@sentry/wizard 3.10.0 → 3.11.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 (131) hide show
  1. package/CHANGELOG.md +47 -7
  2. package/dist/lib/Constants.d.ts +1 -0
  3. package/dist/lib/Constants.js +5 -0
  4. package/dist/lib/Constants.js.map +1 -1
  5. package/dist/lib/Steps/ChooseIntegration.js +8 -4
  6. package/dist/lib/Steps/ChooseIntegration.js.map +1 -1
  7. package/dist/lib/Steps/Integrations/Android.d.ts +9 -0
  8. package/dist/lib/Steps/Integrations/Android.js +86 -0
  9. package/dist/lib/Steps/Integrations/Android.js.map +1 -0
  10. package/dist/lib/Steps/Integrations/ReactNative.js +3 -3
  11. package/dist/lib/Steps/Integrations/ReactNative.js.map +1 -1
  12. package/dist/lib/Steps/PromptForParameters.js +36 -3
  13. package/dist/lib/Steps/PromptForParameters.js.map +1 -1
  14. package/dist/lib/Steps/SentryProjectSelector.js +1 -1
  15. package/dist/lib/Steps/SentryProjectSelector.js.map +1 -1
  16. package/dist/package.json +4 -3
  17. package/dist/src/android/android-wizard.d.ts +2 -0
  18. package/dist/src/android/android-wizard.js +217 -0
  19. package/dist/src/android/android-wizard.js.map +1 -0
  20. package/dist/src/android/code-tools.d.ts +39 -0
  21. package/dist/src/android/code-tools.js +161 -0
  22. package/dist/src/android/code-tools.js.map +1 -0
  23. package/dist/src/android/gradle.d.ts +62 -0
  24. package/dist/src/android/gradle.js +281 -0
  25. package/dist/src/android/gradle.js.map +1 -0
  26. package/dist/src/android/manifest.d.ts +57 -0
  27. package/dist/src/android/manifest.js +183 -0
  28. package/dist/src/android/manifest.js.map +1 -0
  29. package/dist/src/android/templates.d.ts +11 -0
  30. package/dist/src/android/templates.js +34 -0
  31. package/dist/src/android/templates.js.map +1 -0
  32. package/dist/src/apple/apple-wizard.js +123 -64
  33. package/dist/src/apple/apple-wizard.js.map +1 -1
  34. package/dist/src/apple/cocoapod.js +4 -3
  35. package/dist/src/apple/cocoapod.js.map +1 -1
  36. package/dist/src/apple/code-tools.d.ts +1 -1
  37. package/dist/src/apple/code-tools.js +43 -19
  38. package/dist/src/apple/code-tools.js.map +1 -1
  39. package/dist/src/apple/fastlane.d.ts +1 -1
  40. package/dist/src/apple/fastlane.js +12 -6
  41. package/dist/src/apple/fastlane.js.map +1 -1
  42. package/dist/src/apple/templates.d.ts +2 -2
  43. package/dist/src/apple/templates.js +4 -4
  44. package/dist/src/apple/templates.js.map +1 -1
  45. package/dist/src/apple/xcode-manager.d.ts +19 -3
  46. package/dist/src/apple/xcode-manager.js +126 -24
  47. package/dist/src/apple/xcode-manager.js.map +1 -1
  48. package/dist/src/nextjs/nextjs-wizard.js +49 -11
  49. package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
  50. package/dist/src/nextjs/templates.d.ts +2 -0
  51. package/dist/src/nextjs/templates.js +6 -2
  52. package/dist/src/nextjs/templates.js.map +1 -1
  53. package/dist/src/remix/remix-wizard.js +10 -20
  54. package/dist/src/remix/remix-wizard.js.map +1 -1
  55. package/dist/src/sourcemaps/sourcemaps-wizard.js +26 -13
  56. package/dist/src/sourcemaps/sourcemaps-wizard.js.map +1 -1
  57. package/dist/src/sourcemaps/tools/nextjs.js +1 -1
  58. package/dist/src/sourcemaps/tools/nextjs.js.map +1 -1
  59. package/dist/src/sourcemaps/tools/sentry-cli.js +19 -16
  60. package/dist/src/sourcemaps/tools/sentry-cli.js.map +1 -1
  61. package/dist/src/sourcemaps/tools/vite.d.ts +2 -1
  62. package/dist/src/sourcemaps/tools/vite.js +99 -12
  63. package/dist/src/sourcemaps/tools/vite.js.map +1 -1
  64. package/dist/src/sourcemaps/utils/detect-tool.d.ts +1 -1
  65. package/dist/src/sourcemaps/utils/detect-tool.js.map +1 -1
  66. package/dist/src/sveltekit/sdk-setup.js +3 -3
  67. package/dist/src/sveltekit/sdk-setup.js.map +1 -1
  68. package/dist/src/sveltekit/sveltekit-wizard.js +34 -44
  69. package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
  70. package/dist/src/telemetry.js +1 -0
  71. package/dist/src/telemetry.js.map +1 -1
  72. package/dist/src/utils/ast-utils.d.ts +2 -2
  73. package/dist/src/utils/ast-utils.js +7 -7
  74. package/dist/src/utils/ast-utils.js.map +1 -1
  75. package/dist/src/utils/clack-utils.d.ts +22 -28
  76. package/dist/src/utils/clack-utils.js +270 -264
  77. package/dist/src/utils/clack-utils.js.map +1 -1
  78. package/dist/src/utils/package-manager.d.ts +10 -0
  79. package/dist/{lib/Helper/PackageManager.js → src/utils/package-manager.js} +42 -74
  80. package/dist/src/utils/package-manager.js.map +1 -0
  81. package/dist/src/utils/release-registry.d.ts +1 -0
  82. package/dist/src/utils/release-registry.js +68 -0
  83. package/dist/src/utils/release-registry.js.map +1 -0
  84. package/dist/src/utils/sentrycli-utils.d.ts +4 -0
  85. package/dist/src/utils/sentrycli-utils.js +41 -0
  86. package/dist/src/utils/sentrycli-utils.js.map +1 -0
  87. package/dist/test/sourcemaps/tools/vite.test.d.ts +1 -0
  88. package/dist/test/sourcemaps/tools/vite.test.js +132 -0
  89. package/dist/test/sourcemaps/tools/vite.test.js.map +1 -0
  90. package/lib/Constants.ts +5 -0
  91. package/lib/Steps/ChooseIntegration.ts +7 -3
  92. package/lib/Steps/Integrations/Android.ts +23 -0
  93. package/lib/Steps/Integrations/ReactNative.ts +9 -3
  94. package/lib/Steps/PromptForParameters.ts +48 -3
  95. package/lib/Steps/SentryProjectSelector.ts +3 -1
  96. package/package.json +4 -3
  97. package/src/android/android-wizard.ts +196 -0
  98. package/src/android/code-tools.ts +156 -0
  99. package/src/android/gradle.ts +245 -0
  100. package/src/android/manifest.ts +180 -0
  101. package/src/android/templates.ts +88 -0
  102. package/src/apple/apple-wizard.ts +113 -35
  103. package/src/apple/cocoapod.ts +6 -3
  104. package/src/apple/code-tools.ts +46 -18
  105. package/src/apple/fastlane.ts +6 -12
  106. package/src/apple/templates.ts +2 -8
  107. package/src/apple/xcode-manager.ts +167 -25
  108. package/src/nextjs/nextjs-wizard.ts +72 -8
  109. package/src/nextjs/templates.ts +16 -2
  110. package/src/remix/remix-wizard.ts +10 -15
  111. package/src/sourcemaps/sourcemaps-wizard.ts +19 -5
  112. package/src/sourcemaps/tools/nextjs.ts +2 -2
  113. package/src/sourcemaps/tools/sentry-cli.ts +8 -7
  114. package/src/sourcemaps/tools/vite.ts +136 -6
  115. package/src/sourcemaps/utils/detect-tool.ts +2 -1
  116. package/src/sveltekit/sdk-setup.ts +4 -4
  117. package/src/sveltekit/sveltekit-wizard.ts +5 -14
  118. package/src/telemetry.ts +2 -0
  119. package/src/utils/ast-utils.ts +7 -5
  120. package/src/utils/clack-utils.ts +337 -283
  121. package/src/utils/package-manager.ts +61 -0
  122. package/src/utils/release-registry.ts +19 -0
  123. package/src/utils/sentrycli-utils.ts +22 -0
  124. package/test/sourcemaps/tools/vite.test.ts +149 -0
  125. package/dist/lib/Helper/PackageManager.d.ts +0 -22
  126. package/dist/lib/Helper/PackageManager.js.map +0 -1
  127. package/dist/src/utils/vendor/clack-custom-select.d.ts +0 -21
  128. package/dist/src/utils/vendor/clack-custom-select.js +0 -137
  129. package/dist/src/utils/vendor/clack-custom-select.js.map +0 -1
  130. package/lib/Helper/PackageManager.ts +0 -59
  131. package/src/utils/vendor/clack-custom-select.ts +0 -160
@@ -2,17 +2,30 @@
2
2
  /* eslint-disable @typescript-eslint/no-unsafe-member-access */
3
3
  /* eslint-disable @typescript-eslint/no-unsafe-assignment */
4
4
  /* eslint-disable @typescript-eslint/no-unsafe-call */
5
- /* eslint-disable @typescript-eslint/no-unused-vars */
5
+ // @ts-ignore - clack is ESM and TS complains about that. It works though
6
+ import clack from '@clack/prompts';
6
7
  import * as fs from 'fs';
7
8
  import { SentryProjectData } from '../utils/types';
8
9
  import * as templates from './templates';
10
+ import * as path from 'path';
9
11
  const xcode = require('xcode');
10
12
 
11
- /* eslint-enable @typescript-eslint/no-unused-vars */
13
+ interface ProjetFile {
14
+ key: string;
15
+ path: string;
16
+ }
12
17
 
13
- function setDebugInformationFormat(proj: any): void {
18
+ function setDebugInformationFormat(proj: any, targetName: string): void {
14
19
  const xcObjects = proj.hash.project.objects;
15
- const target = proj.getFirstTarget().firstTarget;
20
+ const targetKey: string = Object.keys(xcObjects.PBXNativeTarget || {}).filter(
21
+ (key) => {
22
+ return (
23
+ !key.endsWith('_comment') &&
24
+ xcObjects.PBXNativeTarget[key].name === targetName
25
+ );
26
+ },
27
+ )[0];
28
+ const target = xcObjects.PBXNativeTarget[targetKey];
16
29
 
17
30
  xcObjects.XCConfigurationList[
18
31
  target.buildConfigurationList
@@ -23,7 +36,7 @@ function setDebugInformationFormat(proj: any): void {
23
36
  });
24
37
  }
25
38
 
26
- function addSentrySPM(proj: any): void {
39
+ function addSentrySPM(proj: any, targetName: string): void {
27
40
  const xcObjects = proj.hash.project.objects;
28
41
 
29
42
  const sentryFrameworkUUID = proj.generateUuid() as string;
@@ -61,7 +74,16 @@ function addSentrySPM(proj: any): void {
61
74
  }
62
75
  }
63
76
 
64
- const target = proj.getFirstTarget().firstTarget;
77
+ const targetKey: string = Object.keys(xcObjects.PBXNativeTarget || {}).filter(
78
+ (key) => {
79
+ return (
80
+ !key.endsWith('_comment') &&
81
+ xcObjects.PBXNativeTarget[key].name === targetName
82
+ );
83
+ },
84
+ )[0];
85
+ const target = xcObjects.PBXNativeTarget[targetKey];
86
+
65
87
  if (!target.packageProductDependencies) {
66
88
  target.packageProductDependencies = [];
67
89
  }
@@ -106,15 +128,25 @@ function addSentrySPM(proj: any): void {
106
128
  };
107
129
  xcObjects.XCSwiftPackageProductDependency[sentrySPMUUID + '_comment'] =
108
130
  'Sentry';
131
+
132
+ clack.log.step('Added Sentry SPM dependency to your project');
109
133
  }
110
134
 
111
135
  function addUploadSymbolsScript(
112
136
  xcodeProject: any,
113
137
  sentryProject: SentryProjectData,
114
- apiKeys: { token: string },
138
+ targetName: string,
115
139
  uploadSource = true,
116
140
  ): void {
117
141
  const xcObjects = xcodeProject.hash.project.objects;
142
+ const targetKey: string = Object.keys(xcObjects.PBXNativeTarget || {}).filter(
143
+ (key) => {
144
+ return (
145
+ !key.endsWith('_comment') &&
146
+ xcObjects.PBXNativeTarget[key].name === targetName
147
+ );
148
+ },
149
+ )[0];
118
150
 
119
151
  for (const scriptKey in xcObjects.PBXShellScriptBuildPhase || {}) {
120
152
  if (!scriptKey.endsWith('_comment')) {
@@ -132,7 +164,7 @@ function addUploadSymbolsScript(
132
164
  [],
133
165
  'PBXShellScriptBuildPhase',
134
166
  'Upload Debug Symbols to Sentry',
135
- null,
167
+ targetKey,
136
168
  {
137
169
  inputFileListPaths: [],
138
170
  outputFileListPaths: [],
@@ -141,29 +173,139 @@ function addUploadSymbolsScript(
141
173
  shellScript: templates.getRunScriptTemplate(
142
174
  sentryProject.organization.slug,
143
175
  sentryProject.slug,
144
- apiKeys.token,
145
176
  uploadSource,
146
177
  ),
147
178
  },
148
179
  );
180
+ clack.log.step(`Added Sentry upload script to "${targetName}" build phase`);
149
181
  }
150
182
 
151
- export function updateXcodeProject(
152
- projectPath: string,
153
- sentryProject: SentryProjectData,
154
- apiKeys: { token: string },
155
- addSPMReference: boolean,
156
- uploadSource = true,
157
- ): void {
158
- const proj = xcode.project(projectPath);
159
- proj.parseSync();
160
- addUploadSymbolsScript(proj, sentryProject, apiKeys, uploadSource);
161
- if (uploadSource) {
162
- setDebugInformationFormat(proj);
183
+ export class XcodeProject {
184
+ projectPath: string;
185
+ project: any;
186
+ objects: any;
187
+ files: ProjetFile[] | undefined;
188
+
189
+ public constructor(projectPath: string) {
190
+ this.projectPath = projectPath;
191
+ this.project = xcode.project(projectPath);
192
+ this.project.parseSync();
193
+ this.objects = this.project.hash.project.objects;
194
+ }
195
+
196
+ public getAllTargets(): string[] {
197
+ return Object.keys(this.objects.PBXNativeTarget || {})
198
+ .filter((key) => {
199
+ return (
200
+ !key.endsWith('_comment') &&
201
+ this.objects.PBXNativeTarget[key].productType.startsWith(
202
+ '"com.apple.product-type.application',
203
+ )
204
+ );
205
+ })
206
+ .map((key) => {
207
+ return this.objects.PBXNativeTarget[key].name as string;
208
+ });
209
+ }
210
+
211
+ public updateXcodeProject(
212
+ sentryProject: SentryProjectData,
213
+ target: string,
214
+ apiKeys: { token: string },
215
+ addSPMReference: boolean,
216
+ uploadSource = true,
217
+ ): void {
218
+ addUploadSymbolsScript(this.project, sentryProject, target, uploadSource);
219
+ if (uploadSource) {
220
+ setDebugInformationFormat(this.project, target);
221
+ }
222
+ if (addSPMReference) {
223
+ addSentrySPM(this.project, target);
224
+ }
225
+ const newContent = this.project.writeSync();
226
+ fs.writeFileSync(this.projectPath, newContent);
227
+ }
228
+
229
+ public filesForTarget(target: string): string[] | undefined {
230
+ const files = this.projectFiles();
231
+ const fileDictionary: any = {};
232
+ files.forEach((file) => {
233
+ fileDictionary[file.key] = file.path;
234
+ });
235
+
236
+ const nativeTarget = Object.keys(this.objects.PBXNativeTarget || {}).filter(
237
+ (key) => {
238
+ return (
239
+ !key.endsWith('_comment') &&
240
+ this.objects.PBXNativeTarget[key].name === target
241
+ );
242
+ },
243
+ )[0];
244
+
245
+ if (nativeTarget === undefined) {
246
+ return undefined;
247
+ }
248
+
249
+ const buildPhaseKey = this.objects.PBXNativeTarget[
250
+ nativeTarget
251
+ ].buildPhases.filter((phase: any) => {
252
+ return this.objects.PBXSourcesBuildPhase[phase.value] !== undefined;
253
+ })[0];
254
+
255
+ if (buildPhaseKey === undefined) {
256
+ return undefined;
257
+ }
258
+
259
+ const buildPhases = this.objects.PBXSourcesBuildPhase[buildPhaseKey.value];
260
+ if (buildPhases === undefined) {
261
+ return undefined;
262
+ }
263
+
264
+ const baseDir = path.dirname(path.dirname(this.projectPath));
265
+
266
+ return buildPhases.files
267
+ .map((file: any) => {
268
+ const buildFile = fileDictionary[
269
+ this.objects.PBXBuildFile[file.value].fileRef
270
+ ] as string;
271
+ if (!buildFile) {
272
+ return '';
273
+ }
274
+ return path.join(baseDir, buildFile);
275
+ })
276
+ .filter((f: string) => f.length > 0) as string[];
163
277
  }
164
- if (addSPMReference) {
165
- addSentrySPM(proj);
278
+
279
+ projectFiles(): ProjetFile[] {
280
+ if (this.files === undefined) {
281
+ const proj = this.project.getFirstProject();
282
+ const mainGroupKey = proj.firstProject.mainGroup;
283
+ const mainGroup = this.objects.PBXGroup[mainGroupKey];
284
+ this.files = this.buildGroup(mainGroup);
285
+ }
286
+ return this.files;
287
+ }
288
+
289
+ buildGroup(group: any, path = ''): ProjetFile[] {
290
+ const result: ProjetFile[] = [];
291
+ for (const child of group.children) {
292
+ if (this.objects.PBXFileReference[child.value]) {
293
+ const fileReference = this.objects.PBXFileReference[child.value];
294
+ result.push({
295
+ key: child.value,
296
+ path: `${path}${fileReference.path.replace(/"/g, '')}`,
297
+ });
298
+ } else if (this.objects.PBXGroup[child.value]) {
299
+ const groupReference = this.objects.PBXGroup[child.value];
300
+ const groupChildren = this.buildGroup(
301
+ groupReference,
302
+ groupReference.path
303
+ ? `${path}${groupReference.path.replace(/"/g, '')}/`
304
+ : path,
305
+ );
306
+ result.push(...groupChildren);
307
+ }
308
+ }
309
+ return result;
166
310
  }
167
- const newContent = proj.writeSync();
168
- fs.writeFileSync(projectPath, newContent);
169
311
  }
@@ -10,7 +10,7 @@ import * as path from 'path';
10
10
  import {
11
11
  abort,
12
12
  abortIfCancelled,
13
- addSentryCliRc,
13
+ addSentryCliConfig,
14
14
  confirmContinueEvenThoughNoGitRepo,
15
15
  ensurePackageIsInstalled,
16
16
  getOrAskForProjectData,
@@ -28,6 +28,7 @@ import {
28
28
  getNextjsWebpackPluginOptionsTemplate,
29
29
  getSentryConfigContents,
30
30
  getSentryExampleApiRoute,
31
+ getSentryExampleAppDirApiRoute,
31
32
  getSentryExamplePageContents,
32
33
  } from './templates';
33
34
 
@@ -44,7 +45,7 @@ export async function runNextjsWizard(options: WizardOptions): Promise<void> {
44
45
  await ensurePackageIsInstalled(packageJson, 'next', 'Next.js');
45
46
 
46
47
  const { selectedProject, authToken, selfHosted, sentryUrl } =
47
- await getOrAskForProjectData(options);
48
+ await getOrAskForProjectData(options, 'javascript-nextjs');
48
49
 
49
50
  await installPackage({
50
51
  packageName: '@sentry/nextjs',
@@ -279,8 +280,11 @@ export async function runNextjsWizard(options: WizardOptions): Promise<void> {
279
280
  }
280
281
  }
281
282
 
283
+ const srcDir = path.join(process.cwd(), 'src');
282
284
  const maybePagesDirPath = path.join(process.cwd(), 'pages');
283
- const maybeSrcPagesDirPath = path.join(process.cwd(), 'src', 'pages');
285
+ const maybeSrcPagesDirPath = path.join(srcDir, 'pages');
286
+ const maybeAppDirPath = path.join(process.cwd(), 'app');
287
+ const maybeSrcAppDirPath = path.join(srcDir, 'app');
284
288
 
285
289
  let pagesLocation =
286
290
  fs.existsSync(maybePagesDirPath) &&
@@ -291,23 +295,83 @@ export async function runNextjsWizard(options: WizardOptions): Promise<void> {
291
295
  ? ['src', 'pages']
292
296
  : undefined;
293
297
 
294
- if (!pagesLocation) {
295
- pagesLocation = ['pages'];
298
+ const appLocation =
299
+ fs.existsSync(maybeAppDirPath) &&
300
+ fs.lstatSync(maybeAppDirPath).isDirectory()
301
+ ? ['app']
302
+ : fs.existsSync(maybeSrcAppDirPath) &&
303
+ fs.lstatSync(maybeSrcAppDirPath).isDirectory()
304
+ ? ['src', 'app']
305
+ : undefined;
306
+
307
+ if (!pagesLocation && !appLocation) {
308
+ pagesLocation =
309
+ fs.existsSync(srcDir) && fs.lstatSync(srcDir).isDirectory()
310
+ ? ['src', 'pages']
311
+ : ['pages'];
296
312
  fs.mkdirSync(path.join(process.cwd(), ...pagesLocation), {
297
313
  recursive: true,
298
314
  });
299
315
  }
300
316
 
301
- if (pagesLocation) {
317
+ if (appLocation) {
318
+ const examplePageContents = getSentryExamplePageContents({
319
+ selfHosted,
320
+ orgSlug: selectedProject.organization.slug,
321
+ projectId: selectedProject.id,
322
+ url: sentryUrl,
323
+ useClient: true,
324
+ });
325
+
326
+ await fs.promises.writeFile(
327
+ path.join(
328
+ process.cwd(),
329
+ ...appLocation,
330
+ 'sentry-example-page',
331
+ 'page.jsx',
332
+ ),
333
+ examplePageContents,
334
+ { encoding: 'utf8', flag: 'w' },
335
+ );
336
+
337
+ clack.log.success(
338
+ `Created ${chalk.bold(
339
+ path.join(...appLocation, 'sentry-example-page', 'page.jsx'),
340
+ )}.`,
341
+ );
342
+
343
+ fs.mkdirSync(path.join(process.cwd(), ...appLocation, 'api'), {
344
+ recursive: true,
345
+ });
346
+
347
+ await fs.promises.writeFile(
348
+ path.join(
349
+ process.cwd(),
350
+ ...appLocation,
351
+ 'api',
352
+ 'sentry-example-api',
353
+ 'route.js',
354
+ ),
355
+ getSentryExampleAppDirApiRoute(),
356
+ { encoding: 'utf8', flag: 'w' },
357
+ );
358
+
359
+ clack.log.success(
360
+ `Created ${chalk.bold(
361
+ path.join(...appLocation, 'api', 'sentry-example-api', 'route.js'),
362
+ )}.`,
363
+ );
364
+ } else if (pagesLocation) {
302
365
  const examplePageContents = getSentryExamplePageContents({
303
366
  selfHosted,
304
367
  orgSlug: selectedProject.organization.slug,
305
368
  projectId: selectedProject.id,
306
369
  url: sentryUrl,
370
+ useClient: false,
307
371
  });
308
372
 
309
373
  await fs.promises.writeFile(
310
- path.join(process.cwd(), ...pagesLocation, 'sentry-example-page.js'),
374
+ path.join(process.cwd(), ...pagesLocation, 'sentry-example-page.jsx'),
311
375
  examplePageContents,
312
376
  { encoding: 'utf8', flag: 'w' },
313
377
  );
@@ -340,7 +404,7 @@ export async function runNextjsWizard(options: WizardOptions): Promise<void> {
340
404
  );
341
405
  }
342
406
 
343
- await addSentryCliRc(authToken);
407
+ await addSentryCliConfig(authToken);
344
408
 
345
409
  const mightBeUsingVercel = fs.existsSync(
346
410
  path.join(process.cwd(), 'vercel.json'),
@@ -150,15 +150,18 @@ export function getSentryExamplePageContents(options: {
150
150
  url: string;
151
151
  orgSlug: string;
152
152
  projectId: string;
153
+ useClient: boolean;
153
154
  }): string {
154
155
  const issuesPageLink = options.selfHosted
155
156
  ? `${options.url}organizations/${options.orgSlug}/issues/?project=${options.projectId}`
156
157
  : `https://${options.orgSlug}.sentry.io/issues/?project=${options.projectId}`;
157
158
 
158
- return `import Head from "next/head";
159
+ return `${
160
+ options.useClient ? '"use client";\n\n' : ''
161
+ }import Head from "next/head";
159
162
  import * as Sentry from "@sentry/nextjs";
160
163
 
161
- export default function Home() {
164
+ export default function Page() {
162
165
  return (
163
166
  <div>
164
167
  <Head>
@@ -250,3 +253,14 @@ export default function handler(_req, res) {
250
253
  }
251
254
  `;
252
255
  }
256
+
257
+ export function getSentryExampleAppDirApiRoute() {
258
+ return `import { NextResponse } from "next/server";
259
+
260
+ // A faulty API route to test Sentry's error monitoring
261
+ export function GET() {
262
+ throw new Error("Sentry Example API Route Error");
263
+ return NextResponse.json({ data: "Testing Sentry Error..." });
264
+ }
265
+ `;
266
+ }
@@ -3,16 +3,15 @@ import clack from '@clack/prompts';
3
3
  import chalk from 'chalk';
4
4
 
5
5
  import {
6
- addSentryCliRc,
7
- askForProjectSelection,
8
- askForSelfHosted,
9
- askForWizardLogin,
6
+ addSentryCliConfig,
10
7
  confirmContinueEvenThoughNoGitRepo,
11
8
  ensurePackageIsInstalled,
9
+ getOrAskForProjectData,
12
10
  getPackageDotJson,
13
11
  installPackage,
14
12
  isUsingTypeScript,
15
13
  printWelcome,
14
+ sourceMapsCliSetupConfig,
16
15
  } from '../utils/clack-utils';
17
16
  import { hasPackageInstalled } from '../utils/package-json';
18
17
  import { WizardOptions } from '../utils/types';
@@ -54,15 +53,10 @@ async function runRemixWizardWithTelemetry(
54
53
  // We expect `@remix-run/dev` to be installed for every Remix project
55
54
  await ensurePackageIsInstalled(packageJson, '@remix-run/dev', 'Remix');
56
55
 
57
- const { url: sentryUrl } = await askForSelfHosted(options.url);
58
-
59
- const { projects, apiKeys } = await askForWizardLogin({
60
- promoCode: options.promoCode,
61
- url: sentryUrl,
62
- platform: 'javascript-remix',
63
- });
64
-
65
- const selectedProject = await askForProjectSelection(projects);
56
+ const { selectedProject, authToken } = await getOrAskForProjectData(
57
+ options,
58
+ 'javascript-remix',
59
+ );
66
60
 
67
61
  await traceStep('Install Sentry SDK', () =>
68
62
  installPackage({
@@ -76,8 +70,9 @@ async function runRemixWizardWithTelemetry(
76
70
  const isTS = isUsingTypeScript();
77
71
  const isV2 = isRemixV2(remixConfig, packageJson);
78
72
 
79
- await addSentryCliRc(
80
- apiKeys.token,
73
+ await addSentryCliConfig(
74
+ authToken,
75
+ sourceMapsCliSetupConfig,
81
76
  selectedProject.organization.slug,
82
77
  selectedProject.name,
83
78
  );
@@ -4,9 +4,9 @@ import chalk from 'chalk';
4
4
  import * as Sentry from '@sentry/node';
5
5
 
6
6
  import {
7
+ abort,
7
8
  abortIfCancelled,
8
9
  confirmContinueEvenThoughNoGitRepo,
9
- detectPackageManager,
10
10
  SENTRY_DOT_ENV_FILE,
11
11
  printWelcome,
12
12
  SENTRY_CLI_RC_FILE,
@@ -30,6 +30,7 @@ import { configureAngularSourcemapGenerationFlow } from './tools/angular';
30
30
  import { detectUsedTool, SupportedTools } from './utils/detect-tool';
31
31
  import { configureNextJsSourceMapsUpload } from './tools/nextjs';
32
32
  import { configureRemixSourceMapsUpload } from './tools/remix';
33
+ import { detectPackageManger } from '../utils/package-manager';
33
34
 
34
35
  export async function runSourcemapsWizard(
35
36
  options: WizardOptions,
@@ -89,6 +90,14 @@ You can turn this off by running the wizard with the '--disable-telemetry' flag.
89
90
 
90
91
  Sentry.setTag('selected-tool', selectedTool);
91
92
 
93
+ if (selectedTool === 'no-tool') {
94
+ clack.log.info(
95
+ "No Problem! But in this case, there's nothing to configure :)",
96
+ );
97
+ await abort('Exiting, have a great day!', 0);
98
+ return;
99
+ }
100
+
92
101
  await traceStep('tool-setup', () =>
93
102
  startToolSetupFlow(
94
103
  selectedTool,
@@ -115,7 +124,7 @@ You can turn this off by running the wizard with the '--disable-telemetry' flag.
115
124
  }
116
125
 
117
126
  async function askForUsedBundlerTool(): Promise<SupportedTools> {
118
- const selectedTool: SupportedTools | symbol = await abortIfCancelled(
127
+ const selectedTool = await abortIfCancelled(
119
128
  clack.select({
120
129
  message: 'Which framework, bundler or build tool are you using?',
121
130
  options: [
@@ -165,10 +174,15 @@ async function askForUsedBundlerTool(): Promise<SupportedTools> {
165
174
  hint: 'Configure source maps when using tsc as build tool',
166
175
  },
167
176
  {
168
- label: 'None of the above',
177
+ label: 'I use another tool',
169
178
  value: 'sentry-cli',
170
179
  hint: 'This will configure source maps upload for you using sentry-cli',
171
180
  },
181
+ {
182
+ label: "I don't minify, transpile or bundle my code",
183
+ value: 'no-tool',
184
+ hint: 'This will exit the wizard',
185
+ },
172
186
  ],
173
187
  initialValue: await detectUsedTool(),
174
188
  }),
@@ -317,8 +331,8 @@ SENTRY_AUTH_TOKEN=${authToken}
317
331
  }
318
332
 
319
333
  function printOutro(url: string, orgSlug: string, projectId: string) {
320
- const pacMan = detectPackageManager() || 'npm';
321
- const buildCommand = `'${pacMan}${pacMan === 'npm' ? ' run' : ''} build'`;
334
+ const packageManager = detectPackageManger();
335
+ const buildCommand = packageManager?.buildCommand ?? 'npm run build';
322
336
 
323
337
  const urlObject = new URL(url);
324
338
  urlObject.host = `${orgSlug}.${urlObject.host}`;
@@ -3,7 +3,7 @@ import * as clack from '@clack/prompts';
3
3
  import chalk from 'chalk';
4
4
  import { runNextjsWizard } from '../../nextjs/nextjs-wizard';
5
5
  import { traceStep } from '../../telemetry';
6
- import { abortIfCancelled, addSentryCliRc } from '../../utils/clack-utils';
6
+ import { abortIfCancelled, addSentryCliConfig } from '../../utils/clack-utils';
7
7
  import { WizardOptions } from '../../utils/types';
8
8
 
9
9
  import { SourceMapUploadToolConfigurationOptions } from './types';
@@ -99,7 +99,7 @@ In case you already tried the wizard, we can also show you how to configure your
99
99
  );
100
100
 
101
101
  await traceStep('nextjs-manual-sentryclirc', () =>
102
- addSentryCliRc(options.authToken),
102
+ addSentryCliConfig(options.authToken),
103
103
  );
104
104
  }
105
105
 
@@ -6,8 +6,7 @@ import * as path from 'path';
6
6
  import * as fs from 'fs';
7
7
  import {
8
8
  abortIfCancelled,
9
- addSentryCliRc,
10
- detectPackageManager,
9
+ addSentryCliConfig,
11
10
  getPackageDotJson,
12
11
  installPackage,
13
12
  } from '../../utils/clack-utils';
@@ -15,6 +14,7 @@ import {
15
14
  import { SourceMapUploadToolConfigurationOptions } from './types';
16
15
  import { hasPackageInstalled, PackageDotJson } from '../../utils/package-json';
17
16
  import { traceStep } from '../../telemetry';
17
+ import { detectPackageManger } from '../../utils/package-manager';
18
18
 
19
19
  const SENTRY_NPM_SCRIPT_NAME = 'sentry:sourcemaps';
20
20
 
@@ -96,7 +96,7 @@ export async function configureSentryCLI(
96
96
  );
97
97
  }
98
98
 
99
- await addSentryCliRc(options.authToken);
99
+ await addSentryCliConfig(options.authToken);
100
100
  }
101
101
 
102
102
  export async function setupNpmScriptInCI(): Promise<void> {
@@ -205,7 +205,8 @@ async function addSentryCommandToBuildCommand(
205
205
  (s) => s !== SENTRY_NPM_SCRIPT_NAME,
206
206
  );
207
207
 
208
- const pacMan = detectPackageManager() || 'npm';
208
+ const packageManager = detectPackageManger();
209
+ const packageManagerName = packageManager?.name ?? 'npm';
209
210
 
210
211
  // Heuristic to pre-select the build command:
211
212
  // Often, 'build' is the prod build command, so we favour it.
@@ -220,7 +221,7 @@ async function addSentryCommandToBuildCommand(
220
221
  (await abortIfCancelled(
221
222
  clack.confirm({
222
223
  message: `Is ${chalk.cyan(
223
- `${pacMan} run ${buildCommand}`,
224
+ `${packageManagerName} run ${buildCommand}`,
224
225
  )} your production build command?`,
225
226
  }),
226
227
  ));
@@ -228,7 +229,7 @@ async function addSentryCommandToBuildCommand(
228
229
  if (allNpmScripts.length && (!buildCommand || !isProdBuildCommand)) {
229
230
  buildCommand = await abortIfCancelled(
230
231
  clack.select({
231
- message: `Which ${pacMan} command in your ${chalk.cyan(
232
+ message: `Which ${packageManagerName} command in your ${chalk.cyan(
232
233
  'package.json',
233
234
  )} builds your application for production?`,
234
235
  options: allNpmScripts
@@ -254,7 +255,7 @@ Please add it manually to your prod build command.`,
254
255
  packageDotJson.scripts[
255
256
  buildCommand
256
257
  // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
257
- ] = `${packageDotJson.scripts[buildCommand]} && ${pacMan} run ${SENTRY_NPM_SCRIPT_NAME}`;
258
+ ] = `${packageDotJson.scripts[buildCommand]} && ${packageManager} run ${SENTRY_NPM_SCRIPT_NAME}`;
258
259
 
259
260
  await fs.promises.writeFile(
260
261
  path.join(process.cwd(), 'package.json'),