@sentry/wizard 3.28.0 → 3.30.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 (42) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/package.json +1 -1
  3. package/dist/src/nextjs/nextjs-wizard.js +9 -4
  4. package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
  5. package/dist/src/nextjs/templates.js +2 -2
  6. package/dist/src/nextjs/templates.js.map +1 -1
  7. package/dist/src/react-native/react-native-wizard.js +4 -1
  8. package/dist/src/react-native/react-native-wizard.js.map +1 -1
  9. package/dist/src/remix/remix-wizard.d.ts +1 -1
  10. package/dist/src/remix/remix-wizard.js +27 -11
  11. package/dist/src/remix/remix-wizard.js.map +1 -1
  12. package/dist/src/remix/sdk-setup.d.ts +24 -3
  13. package/dist/src/remix/sdk-setup.js +95 -61
  14. package/dist/src/remix/sdk-setup.js.map +1 -1
  15. package/dist/src/run.d.ts +2 -0
  16. package/dist/src/run.js +2 -0
  17. package/dist/src/run.js.map +1 -1
  18. package/dist/src/sveltekit/sveltekit-wizard.js +3 -1
  19. package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
  20. package/dist/src/utils/clack-utils.d.ts +3 -0
  21. package/dist/src/utils/clack-utils.js +86 -14
  22. package/dist/src/utils/clack-utils.js.map +1 -1
  23. package/dist/src/utils/types.d.ts +12 -0
  24. package/dist/src/utils/types.js.map +1 -1
  25. package/dist/test/remix/client-entry.test.d.ts +1 -0
  26. package/dist/test/remix/client-entry.test.js +41 -0
  27. package/dist/test/remix/client-entry.test.js.map +1 -0
  28. package/dist/test/remix/server-instrumentation.test.d.ts +1 -0
  29. package/dist/test/remix/server-instrumentation.test.js +22 -0
  30. package/dist/test/remix/server-instrumentation.test.js.map +1 -0
  31. package/package.json +1 -1
  32. package/src/nextjs/nextjs-wizard.ts +9 -5
  33. package/src/nextjs/templates.ts +12 -3
  34. package/src/react-native/react-native-wizard.ts +4 -0
  35. package/src/remix/remix-wizard.ts +32 -6
  36. package/src/remix/sdk-setup.ts +145 -48
  37. package/src/run.ts +4 -0
  38. package/src/sveltekit/sveltekit-wizard.ts +3 -0
  39. package/src/utils/clack-utils.ts +93 -3
  40. package/src/utils/types.ts +14 -0
  41. package/test/remix/client-entry.test.ts +122 -0
  42. package/test/remix/server-instrumentation.test.ts +38 -0
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ // @ts-expect-error - magicast is ESM and TS complains about that. It works though
4
+ var magicast_1 = require("magicast");
5
+ var sdk_setup_1 = require("../../src/remix/sdk-setup");
6
+ describe('initializeSentryOnEntryClient', function () {
7
+ it('should initialize Sentry on client entry with all features enabled', function () {
8
+ // Empty entry.client.tsx file for testing
9
+ var originalEntryClientMod = (0, magicast_1.parseModule)('');
10
+ var dsn = 'https://sentry.io/123';
11
+ var selectedFeatures = {
12
+ performance: true,
13
+ replay: true,
14
+ };
15
+ var result = (0, sdk_setup_1.updateEntryClientMod)(originalEntryClientMod, dsn, selectedFeatures);
16
+ expect(result.generate().code).toMatchInlineSnapshot("\n \"import { useEffect,} from \"react\";\n\n import {\n useLocation,\n useMatches,\n } from \"@remix-run/react\";\n\n import * as Sentry from \"@sentry/remix\";\n\n Sentry.init({\n dsn: \"https://sentry.io/123\",\n tracesSampleRate: 1,\n\n integrations: [Sentry.browserTracingIntegration({\n useEffect,\n useLocation,\n useMatches\n }), Sentry.replayIntegration({\n maskAllText: true,\n blockAllMedia: true\n })],\n\n replaysSessionSampleRate: 0.1,\n replaysOnErrorSampleRate: 1\n })\"\n ");
17
+ });
18
+ it('should initialize Sentry on client entry when performance disabled', function () {
19
+ // Empty entry.client.tsx file for testing
20
+ var originalEntryClientMod = (0, magicast_1.parseModule)('');
21
+ var dsn = 'https://sentry.io/123';
22
+ var selectedFeatures = {
23
+ performance: false,
24
+ replay: true,
25
+ };
26
+ var result = (0, sdk_setup_1.updateEntryClientMod)(originalEntryClientMod, dsn, selectedFeatures);
27
+ expect(result.generate().code).toMatchInlineSnapshot("\n \"import * as Sentry from \"@sentry/remix\";\n\n Sentry.init({\n dsn: \"https://sentry.io/123\",\n\n integrations: [Sentry.replayIntegration({\n maskAllText: true,\n blockAllMedia: true\n })],\n\n replaysSessionSampleRate: 0.1,\n replaysOnErrorSampleRate: 1\n })\"\n ");
28
+ });
29
+ it('should initialize Sentry on client entry when replay disabled', function () {
30
+ // Empty entry.client.tsx file for testing
31
+ var originalEntryClientMod = (0, magicast_1.parseModule)('');
32
+ var dsn = 'https://sentry.io/123';
33
+ var selectedFeatures = {
34
+ performance: true,
35
+ replay: false,
36
+ };
37
+ var result = (0, sdk_setup_1.updateEntryClientMod)(originalEntryClientMod, dsn, selectedFeatures);
38
+ expect(result.generate().code).toMatchInlineSnapshot("\n \"import { useEffect,} from \"react\";\n\n import {\n useLocation,\n useMatches,\n } from \"@remix-run/react\";\n\n import * as Sentry from \"@sentry/remix\";\n\n Sentry.init({\n dsn: \"https://sentry.io/123\",\n tracesSampleRate: 1,\n\n integrations: [Sentry.browserTracingIntegration({\n useEffect,\n useLocation,\n useMatches\n })]\n })\"\n ");
39
+ });
40
+ });
41
+ //# sourceMappingURL=client-entry.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-entry.test.js","sourceRoot":"","sources":["../../../test/remix/client-entry.test.ts"],"names":[],"mappings":";;AAAA,kFAAkF;AAClF,qCAAuC;AACvC,uDAAiE;AAEjE,QAAQ,CAAC,+BAA+B,EAAE;IACxC,EAAE,CAAC,oEAAoE,EAAE;QACvE,0CAA0C;QAC1C,IAAM,sBAAsB,GAAG,IAAA,sBAAW,EAAC,EAAE,CAAC,CAAC;QAE/C,IAAM,GAAG,GAAG,uBAAuB,CAAC;QACpC,IAAM,gBAAgB,GAAG;YACvB,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE,IAAI;SACb,CAAC;QAEF,IAAM,MAAM,GAAG,IAAA,gCAAoB,EACjC,sBAAsB,EACtB,GAAG,EACH,gBAAgB,CACjB,CAAC;QAEF,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,qBAAqB,CAAC,qpBA0BpD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE;QACvE,0CAA0C;QAC1C,IAAM,sBAAsB,GAAG,IAAA,sBAAW,EAAC,EAAE,CAAC,CAAC;QAE/C,IAAM,GAAG,GAAG,uBAAuB,CAAC;QACpC,IAAM,gBAAgB,GAAG;YACvB,WAAW,EAAE,KAAK;YAClB,MAAM,EAAE,IAAI;SACb,CAAC;QAEF,IAAM,MAAM,GAAG,IAAA,gCAAoB,EACjC,sBAAsB,EACtB,GAAG,EACH,gBAAgB,CACjB,CAAC;QAEF,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,qBAAqB,CAAC,yWAcpD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE;QAClE,0CAA0C;QAC1C,IAAM,sBAAsB,GAAG,IAAA,sBAAW,EAAC,EAAE,CAAC,CAAC;QAE/C,IAAM,GAAG,GAAG,uBAAuB,CAAC;QACpC,IAAM,gBAAgB,GAAG;YACvB,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE,KAAK;SACd,CAAC;QAEF,IAAM,MAAM,GAAG,IAAA,gCAAoB,EACjC,sBAAsB,EACtB,GAAG,EACH,gBAAgB,CACjB,CAAC;QAEF,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,qBAAqB,CAAC,kdAoBpD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["// @ts-expect-error - magicast is ESM and TS complains about that. It works though\nimport { parseModule } from 'magicast';\nimport { updateEntryClientMod } from '../../src/remix/sdk-setup';\n\ndescribe('initializeSentryOnEntryClient', () => {\n it('should initialize Sentry on client entry with all features enabled', () => {\n // Empty entry.client.tsx file for testing\n const originalEntryClientMod = parseModule('');\n\n const dsn = 'https://sentry.io/123';\n const selectedFeatures = {\n performance: true,\n replay: true,\n };\n\n const result = updateEntryClientMod(\n originalEntryClientMod,\n dsn,\n selectedFeatures,\n );\n\n expect(result.generate().code).toMatchInlineSnapshot(`\n \"import { useEffect,} from \"react\";\n\n import {\n useLocation,\n useMatches,\n } from \"@remix-run/react\";\n\n import * as Sentry from \"@sentry/remix\";\n\n Sentry.init({\n dsn: \"https://sentry.io/123\",\n tracesSampleRate: 1,\n\n integrations: [Sentry.browserTracingIntegration({\n useEffect,\n useLocation,\n useMatches\n }), Sentry.replayIntegration({\n maskAllText: true,\n blockAllMedia: true\n })],\n\n replaysSessionSampleRate: 0.1,\n replaysOnErrorSampleRate: 1\n })\"\n `);\n });\n\n it('should initialize Sentry on client entry when performance disabled', () => {\n // Empty entry.client.tsx file for testing\n const originalEntryClientMod = parseModule('');\n\n const dsn = 'https://sentry.io/123';\n const selectedFeatures = {\n performance: false,\n replay: true,\n };\n\n const result = updateEntryClientMod(\n originalEntryClientMod,\n dsn,\n selectedFeatures,\n );\n\n expect(result.generate().code).toMatchInlineSnapshot(`\n \"import * as Sentry from \"@sentry/remix\";\n\n Sentry.init({\n dsn: \"https://sentry.io/123\",\n\n integrations: [Sentry.replayIntegration({\n maskAllText: true,\n blockAllMedia: true\n })],\n\n replaysSessionSampleRate: 0.1,\n replaysOnErrorSampleRate: 1\n })\"\n `);\n });\n\n it('should initialize Sentry on client entry when replay disabled', () => {\n // Empty entry.client.tsx file for testing\n const originalEntryClientMod = parseModule('');\n\n const dsn = 'https://sentry.io/123';\n const selectedFeatures = {\n performance: true,\n replay: false,\n };\n\n const result = updateEntryClientMod(\n originalEntryClientMod,\n dsn,\n selectedFeatures,\n );\n\n expect(result.generate().code).toMatchInlineSnapshot(`\n \"import { useEffect,} from \"react\";\n\n import {\n useLocation,\n useMatches,\n } from \"@remix-run/react\";\n\n import * as Sentry from \"@sentry/remix\";\n\n Sentry.init({\n dsn: \"https://sentry.io/123\",\n tracesSampleRate: 1,\n\n integrations: [Sentry.browserTracingIntegration({\n useEffect,\n useLocation,\n useMatches\n })]\n })\"\n `);\n });\n});\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ var sdk_setup_1 = require("../../src/remix/sdk-setup");
4
+ describe('generateServerInstrumentationFile', function () {
5
+ it('should generate server instrumentation file', function () {
6
+ var result = (0, sdk_setup_1.generateServerInstrumentationFile)('https://sentry.io/123', {
7
+ performance: true,
8
+ replay: true,
9
+ });
10
+ expect(result.instrumentationFileMod.generate().code)
11
+ .toMatchInlineSnapshot("\n \"import * as Sentry from \"@sentry/remix\";\n\n Sentry.init({\n dsn: \"https://sentry.io/123\",\n tracesSampleRate: 1,\n autoInstrumentRemix: true\n })\"\n ");
12
+ });
13
+ it('should generate server instrumentation file when performance is disabled', function () {
14
+ var result = (0, sdk_setup_1.generateServerInstrumentationFile)('https://sentry.io/123', {
15
+ performance: false,
16
+ replay: true,
17
+ });
18
+ expect(result.instrumentationFileMod.generate().code)
19
+ .toMatchInlineSnapshot("\n \"import * as Sentry from \"@sentry/remix\";\n\n Sentry.init({\n dsn: \"https://sentry.io/123\",\n autoInstrumentRemix: true\n })\"\n ");
20
+ });
21
+ });
22
+ //# sourceMappingURL=server-instrumentation.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-instrumentation.test.js","sourceRoot":"","sources":["../../../test/remix/server-instrumentation.test.ts"],"names":[],"mappings":";;AAAA,uDAA8E;AAE9E,QAAQ,CAAC,mCAAmC,EAAE;IAC5C,EAAE,CAAC,6CAA6C,EAAE;QAChD,IAAM,MAAM,GAAG,IAAA,6CAAiC,EAAC,uBAAuB,EAAE;YACxE,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC;aAClD,qBAAqB,CAAC,+MAQxB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE;QAC7E,IAAM,MAAM,GAAG,IAAA,6CAAiC,EAAC,uBAAuB,EAAE;YACxE,WAAW,EAAE,KAAK;YAClB,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC;aAClD,qBAAqB,CAAC,+KAOxB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { generateServerInstrumentationFile } from '../../src/remix/sdk-setup';\n\ndescribe('generateServerInstrumentationFile', () => {\n it('should generate server instrumentation file', () => {\n const result = generateServerInstrumentationFile('https://sentry.io/123', {\n performance: true,\n replay: true,\n });\n\n expect(result.instrumentationFileMod.generate().code)\n .toMatchInlineSnapshot(`\n \"import * as Sentry from \"@sentry/remix\";\n\n Sentry.init({\n dsn: \"https://sentry.io/123\",\n tracesSampleRate: 1,\n autoInstrumentRemix: true\n })\"\n `);\n });\n\n it('should generate server instrumentation file when performance is disabled', () => {\n const result = generateServerInstrumentationFile('https://sentry.io/123', {\n performance: false,\n replay: true,\n });\n\n expect(result.instrumentationFileMod.generate().code)\n .toMatchInlineSnapshot(`\n \"import * as Sentry from \"@sentry/remix\";\n\n Sentry.init({\n dsn: \"https://sentry.io/123\",\n autoInstrumentRemix: true\n })\"\n `);\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/wizard",
3
- "version": "3.28.0",
3
+ "version": "3.30.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",
@@ -20,9 +20,11 @@ import {
20
20
  featureSelectionPrompt,
21
21
  getOrAskForProjectData,
22
22
  getPackageDotJson,
23
+ getPackageManager,
23
24
  installPackage,
24
25
  isUsingTypeScript,
25
26
  printWelcome,
27
+ runPrettierIfInstalled,
26
28
  showCopyPasteInstructions,
27
29
  } from '../utils/clack-utils';
28
30
  import type { SentryProjectData, WizardOptions } from '../utils/types';
@@ -328,12 +330,14 @@ export async function runNextjsWizardWithTelemetry(
328
330
  await traceStep('configure-ci', () => configureCI('nextjs', authToken));
329
331
  }
330
332
 
331
- clack.outro(`${chalk.green(
332
- 'Successfully installed the Sentry Next.js SDK!',
333
- )}${
333
+ const pacMan = await getPackageManager();
334
+ await runPrettierIfInstalled();
335
+
336
+ clack.outro(`
337
+ ${chalk.green('Successfully installed the Sentry Next.js SDK!')} ${
334
338
  shouldCreateExamplePage
335
- ? `\n\nYou can validate your setup by (re)starting your dev environment (${chalk.cyan(
336
- `next dev`,
339
+ ? `\n\nYou can validate your setup by (re)starting your dev environment (e.g. ${chalk.cyan(
340
+ `${pacMan.runScriptCommand} dev`,
337
341
  )}) and visiting ${chalk.cyan('"/sentry-example-page"')}`
338
342
  : ''
339
343
  }${
@@ -369,7 +369,9 @@ YourCustomErrorComponent.getInitialProps = async (contextData${
369
369
  export function getInstrumentationHookContent(
370
370
  instrumentationHookLocation: 'src' | 'root',
371
371
  ) {
372
- return `export async function register() {
372
+ return `import * as Sentry from '@sentry/nextjs';
373
+
374
+ export async function register() {
373
375
  if (process.env.NEXT_RUNTIME === 'nodejs') {
374
376
  await import('${
375
377
  instrumentationHookLocation === 'root' ? '.' : '..'
@@ -382,6 +384,8 @@ export function getInstrumentationHookContent(
382
384
  }/sentry.edge.config');
383
385
  }
384
386
  }
387
+
388
+ export const onRequestError = Sentry.captureRequestError;
385
389
  `;
386
390
  }
387
391
 
@@ -389,7 +393,9 @@ export function getInstrumentationHookCopyPasteSnippet(
389
393
  instrumentationHookLocation: 'src' | 'root',
390
394
  ) {
391
395
  return makeCodeSnippet(true, (unchanged, plus) => {
392
- return unchanged(`export ${plus('async')} function register() {
396
+ return unchanged(`${plus("import * as Sentry from '@sentry/nextjs';")}
397
+
398
+ export ${plus('async')} function register() {
393
399
  ${plus(`if (process.env.NEXT_RUNTIME === 'nodejs') {
394
400
  await import('${
395
401
  instrumentationHookLocation === 'root' ? '.' : '..'
@@ -401,7 +407,10 @@ export function getInstrumentationHookCopyPasteSnippet(
401
407
  instrumentationHookLocation === 'root' ? '.' : '..'
402
408
  }/sentry.edge.config');
403
409
  }`)}
404
- }`);
410
+ }
411
+
412
+ ${plus('export const onRequestError = Sentry.captureRequestError;')}
413
+ `);
405
414
  });
406
415
  }
407
416
 
@@ -16,6 +16,7 @@ import {
16
16
  installPackage,
17
17
  printWelcome,
18
18
  propertiesCliSetupConfig,
19
+ runPrettierIfInstalled,
19
20
  } from '../utils/clack-utils';
20
21
  import { getPackageVersion, hasPackageInstalled } from '../utils/package-json';
21
22
  import { podInstall } from '../apple/cocoapod';
@@ -212,11 +213,14 @@ Or setup using ${chalk.cyan(
212
213
  await traceStep('patch-android-files', () => patchAndroidFiles(cliConfig));
213
214
  }
214
215
 
216
+ await runPrettierIfInstalled();
217
+
215
218
  const confirmedFirstException = await confirmFirstSentryException(
216
219
  sentryUrl,
217
220
  orgSlug,
218
221
  projectId,
219
222
  );
223
+
220
224
  Sentry.setTag('user-confirmed-first-error', confirmedFirstException);
221
225
 
222
226
  if (confirmedFirstException) {
@@ -7,15 +7,17 @@ import {
7
7
  askShouldCreateExamplePage,
8
8
  confirmContinueIfNoOrDirtyGitRepo,
9
9
  ensurePackageIsInstalled,
10
+ featureSelectionPrompt,
10
11
  getOrAskForProjectData,
11
12
  getPackageDotJson,
12
13
  installPackage,
13
14
  isUsingTypeScript,
14
15
  printWelcome,
15
16
  rcCliSetupConfig,
17
+ runPrettierIfInstalled,
16
18
  } from '../utils/clack-utils';
17
19
  import { hasPackageInstalled } from '../utils/package-json';
18
- import { WizardOptions } from '../utils/types';
20
+ import type { WizardOptions } from '../utils/types';
19
21
  import {
20
22
  initializeSentryOnEntryClient,
21
23
  instrumentSentryOnEntryServer,
@@ -76,8 +78,22 @@ async function runRemixWizardWithTelemetry(
76
78
  const isTS = isUsingTypeScript();
77
79
  const isV2 = isRemixV2(remixConfig, packageJson);
78
80
  const viteConfig = findFile('vite.config');
79
-
80
- await addSentryCliConfig({ authToken }, rcCliSetupConfig);
81
+ const selectedFeatures = await featureSelectionPrompt([
82
+ {
83
+ id: 'performance',
84
+ prompt: `Do you want to enable ${chalk.bold(
85
+ 'Tracing',
86
+ )} to track the performance of your application?`,
87
+ enabledHint: 'recommended',
88
+ },
89
+ {
90
+ id: 'replay',
91
+ prompt: `Do you want to enable ${chalk.bold(
92
+ 'Sentry Session Replay',
93
+ )} to get a video-like reproduction of errors during a user session?`,
94
+ enabledHint: 'recommended, but increases bundle size',
95
+ },
96
+ ] as const);
81
97
 
82
98
  if (viteConfig) {
83
99
  await traceStep(
@@ -108,6 +124,8 @@ async function runRemixWizardWithTelemetry(
108
124
  url: sentryUrl === DEFAULT_URL ? undefined : sentryUrl,
109
125
  isHydrogen: isHydrogenApp(packageJson),
110
126
  });
127
+
128
+ await addSentryCliConfig({ authToken }, rcCliSetupConfig);
111
129
  } catch (e) {
112
130
  clack.log
113
131
  .warn(`Could not update build script to generate and upload sourcemaps.
@@ -139,7 +157,7 @@ async function runRemixWizardWithTelemetry(
139
157
 
140
158
  await traceStep('Initialize Sentry on client entry', async () => {
141
159
  try {
142
- await initializeSentryOnEntryClient(dsn, isTS);
160
+ await initializeSentryOnEntryClient(dsn, isTS, selectedFeatures);
143
161
  } catch (e) {
144
162
  clack.log.warn(`Could not initialize Sentry on client entry.
145
163
  Please do it manually using instructions from https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/`);
@@ -151,7 +169,10 @@ async function runRemixWizardWithTelemetry(
151
169
 
152
170
  await traceStep('Create server instrumentation file', async () => {
153
171
  try {
154
- instrumentationFile = await createServerInstrumentationFile(dsn);
172
+ instrumentationFile = await createServerInstrumentationFile(
173
+ dsn,
174
+ selectedFeatures,
175
+ );
155
176
  } catch (e) {
156
177
  clack.log.warn(
157
178
  'Could not create a server instrumentation file. Please do it manually using instructions from https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/',
@@ -166,7 +187,10 @@ async function runRemixWizardWithTelemetry(
166
187
  'Create server instrumentation file and import it',
167
188
  async () => {
168
189
  try {
169
- serverFileInstrumented = await insertServerInstrumentationFile(dsn);
190
+ serverFileInstrumented = await insertServerInstrumentationFile(
191
+ dsn,
192
+ selectedFeatures,
193
+ );
170
194
  } catch (e) {
171
195
  clack.log.warn(
172
196
  'Could not create a server instrumentation file. Please do it manually using instructions from https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/',
@@ -216,6 +240,8 @@ async function runRemixWizardWithTelemetry(
216
240
  });
217
241
  }
218
242
 
243
+ await runPrettierIfInstalled();
244
+
219
245
  clack.outro(`
220
246
  ${chalk.green(
221
247
  'Sentry has been successfully configured for your Remix project.',
@@ -76,23 +76,72 @@ export function runRemixReveal(isTS: boolean): void {
76
76
  }
77
77
  }
78
78
 
79
+ function getInitCallArgs(
80
+ dsn: string,
81
+ type: 'client' | 'server',
82
+ selectedFeatures: {
83
+ performance: boolean;
84
+ replay: boolean;
85
+ },
86
+ ) {
87
+ const initCallArgs = {
88
+ dsn,
89
+ } as Record<string, unknown>;
90
+
91
+ // Adding tracing sample rate for both client and server
92
+ if (selectedFeatures.performance) {
93
+ initCallArgs.tracesSampleRate = 1.0;
94
+ }
95
+
96
+ // Adding integrations and replay options only for client
97
+ if (
98
+ type === 'client' &&
99
+ (selectedFeatures.performance || selectedFeatures.replay)
100
+ ) {
101
+ initCallArgs.integrations = [];
102
+
103
+ if (selectedFeatures.performance) {
104
+ // @ts-expect-error - Adding Proxified AST node to the array
105
+ initCallArgs.integrations.push(
106
+ builders.functionCall(
107
+ 'Sentry.browserTracingIntegration',
108
+ builders.raw('{ useEffect, useLocation, useMatches }'),
109
+ ),
110
+ );
111
+ }
112
+
113
+ if (selectedFeatures.replay) {
114
+ // @ts-expect-error - Adding Proxified AST node to the array
115
+ initCallArgs.integrations.push(
116
+ builders.functionCall('Sentry.replayIntegration', {
117
+ maskAllText: true,
118
+ blockAllMedia: true,
119
+ }),
120
+ );
121
+
122
+ initCallArgs.replaysSessionSampleRate = 0.1;
123
+ initCallArgs.replaysOnErrorSampleRate = 1.0;
124
+ }
125
+ }
126
+
127
+ // Adding autoInstrumentRemix option only for server
128
+ if (type === 'server') {
129
+ initCallArgs.autoInstrumentRemix = true;
130
+ }
131
+
132
+ return initCallArgs;
133
+ }
134
+
79
135
  function insertClientInitCall(
80
136
  dsn: string,
81
137
  originalHooksMod: ProxifiedModule<any>,
138
+ selectedFeatures: {
139
+ performance: boolean;
140
+ replay: boolean;
141
+ },
82
142
  ): void {
83
- const initCall = builders.functionCall('Sentry.init', {
84
- dsn,
85
- tracesSampleRate: 1.0,
86
- replaysSessionSampleRate: 0.1,
87
- replaysOnErrorSampleRate: 1.0,
88
- integrations: [
89
- builders.functionCall(
90
- 'Sentry.browserTracingIntegration',
91
- builders.raw('{ useEffect, useLocation, useMatches }'),
92
- ),
93
- builders.functionCall('Sentry.replayIntegration'),
94
- ],
95
- });
143
+ const initCallArgs = getInitCallArgs(dsn, 'client', selectedFeatures);
144
+ const initCall = builders.functionCall('Sentry.init', initCallArgs);
96
145
 
97
146
  const originalHooksModAST = originalHooksMod.$ast as Program;
98
147
  const initCallInsertionIndex =
@@ -107,7 +156,13 @@ function insertClientInitCall(
107
156
  );
108
157
  }
109
158
 
110
- export async function createServerInstrumentationFile(dsn: string) {
159
+ export function generateServerInstrumentationFile(
160
+ dsn: string,
161
+ selectedFeatures: {
162
+ performance: boolean;
163
+ replay: boolean;
164
+ },
165
+ ) {
111
166
  // create an empty file named `instrument.server.mjs`
112
167
  const instrumentationFile = 'instrumentation.server.mjs';
113
168
  const instrumentationFileMod = parseModule('');
@@ -118,11 +173,8 @@ export async function createServerInstrumentationFile(dsn: string) {
118
173
  local: 'Sentry',
119
174
  });
120
175
 
121
- const initCall = builders.functionCall('Sentry.init', {
122
- dsn,
123
- tracesSampleRate: 1.0,
124
- autoInstrumentRemix: true,
125
- });
176
+ const initCallArgs = getInitCallArgs(dsn, 'server', selectedFeatures);
177
+ const initCall = builders.functionCall('Sentry.init', initCallArgs);
126
178
 
127
179
  const instrumentationFileModAST = instrumentationFileMod.$ast as Program;
128
180
 
@@ -138,13 +190,35 @@ export async function createServerInstrumentationFile(dsn: string) {
138
190
  generateCode(initCall).code,
139
191
  );
140
192
 
141
- await writeFile(instrumentationFileModAST, instrumentationFile);
193
+ return { instrumentationFile, instrumentationFileMod };
194
+ }
195
+
196
+ export async function createServerInstrumentationFile(
197
+ dsn: string,
198
+ selectedFeatures: {
199
+ performance: boolean;
200
+ replay: boolean;
201
+ },
202
+ ) {
203
+ const { instrumentationFile, instrumentationFileMod } =
204
+ generateServerInstrumentationFile(dsn, selectedFeatures);
205
+
206
+ await writeFile(instrumentationFileMod.$ast, instrumentationFile);
142
207
 
143
208
  return instrumentationFile;
144
209
  }
145
210
 
146
- export async function insertServerInstrumentationFile(dsn: string) {
147
- const instrumentationFile = await createServerInstrumentationFile(dsn);
211
+ export async function insertServerInstrumentationFile(
212
+ dsn: string,
213
+ selectedFeatures: {
214
+ performance: boolean;
215
+ replay: boolean;
216
+ },
217
+ ) {
218
+ const instrumentationFile = await createServerInstrumentationFile(
219
+ dsn,
220
+ selectedFeatures,
221
+ );
148
222
 
149
223
  const expressServerPath = await findCustomExpressServerImplementation();
150
224
 
@@ -297,9 +371,52 @@ export async function updateBuildScript(args: {
297
371
  /* eslint-enable @typescript-eslint/no-unsafe-member-access */
298
372
  }
299
373
 
374
+ export function updateEntryClientMod(
375
+ originalEntryClientMod: ProxifiedModule<any>,
376
+ dsn: string,
377
+ selectedFeatures: {
378
+ performance: boolean;
379
+ replay: boolean;
380
+ },
381
+ ): ProxifiedModule<any> {
382
+ originalEntryClientMod.imports.$add({
383
+ from: '@sentry/remix',
384
+ imported: '*',
385
+ local: 'Sentry',
386
+ });
387
+
388
+ if (selectedFeatures.performance) {
389
+ originalEntryClientMod.imports.$add({
390
+ from: '@remix-run/react',
391
+ imported: 'useLocation',
392
+ local: 'useLocation',
393
+ });
394
+
395
+ originalEntryClientMod.imports.$add({
396
+ from: '@remix-run/react',
397
+ imported: 'useMatches',
398
+ local: 'useMatches',
399
+ });
400
+
401
+ originalEntryClientMod.imports.$add({
402
+ from: 'react',
403
+ imported: 'useEffect',
404
+ local: 'useEffect',
405
+ });
406
+ }
407
+
408
+ insertClientInitCall(dsn, originalEntryClientMod, selectedFeatures);
409
+
410
+ return originalEntryClientMod;
411
+ }
412
+
300
413
  export async function initializeSentryOnEntryClient(
301
414
  dsn: string,
302
415
  isTS: boolean,
416
+ selectedFeatures: {
417
+ performance: boolean;
418
+ replay: boolean;
419
+ },
303
420
  ): Promise<void> {
304
421
  const clientEntryFilename = `entry.client.${isTS ? 'tsx' : 'jsx'}`;
305
422
 
@@ -315,34 +432,14 @@ export async function initializeSentryOnEntryClient(
315
432
  return;
316
433
  }
317
434
 
318
- originalEntryClientMod.imports.$add({
319
- from: '@sentry/remix',
320
- imported: '*',
321
- local: 'Sentry',
322
- });
323
-
324
- originalEntryClientMod.imports.$add({
325
- from: 'react',
326
- imported: 'useEffect',
327
- local: 'useEffect',
328
- });
329
-
330
- originalEntryClientMod.imports.$add({
331
- from: '@remix-run/react',
332
- imported: 'useLocation',
333
- local: 'useLocation',
334
- });
335
-
336
- originalEntryClientMod.imports.$add({
337
- from: '@remix-run/react',
338
- imported: 'useMatches',
339
- local: 'useMatches',
340
- });
341
-
342
- insertClientInitCall(dsn, originalEntryClientMod);
435
+ const updatedEntryClientMod = updateEntryClientMod(
436
+ originalEntryClientMod,
437
+ dsn,
438
+ selectedFeatures,
439
+ );
343
440
 
344
441
  await writeFile(
345
- originalEntryClientMod.$ast,
442
+ updatedEntryClientMod.$ast,
346
443
  path.join(process.cwd(), 'app', clientEntryFilename),
347
444
  );
348
445
 
package/src/run.ts CHANGED
@@ -39,6 +39,8 @@ type Args = {
39
39
 
40
40
  url?: string;
41
41
  platform?: Platform[];
42
+ org?: string;
43
+ project?: string;
42
44
  };
43
45
 
44
46
  export async function run(argv: Args) {
@@ -80,6 +82,8 @@ export async function run(argv: Args) {
80
82
  telemetryEnabled: !argv.disableTelemetry,
81
83
  promoCode: argv.promoCode,
82
84
  url: argv.url,
85
+ orgSlug: argv.org,
86
+ projectSlug: argv.project,
83
87
  };
84
88
 
85
89
  switch (integration) {
@@ -15,6 +15,7 @@ import {
15
15
  getPackageDotJson,
16
16
  installPackage,
17
17
  printWelcome,
18
+ runPrettierIfInstalled,
18
19
  } from '../utils/clack-utils';
19
20
  import { getPackageVersion, hasPackageInstalled } from '../utils/package-json';
20
21
  import type { WizardOptions } from '../utils/types';
@@ -163,6 +164,8 @@ export async function runSvelteKitWizardWithTelemetry(
163
164
  }
164
165
  }
165
166
 
167
+ await runPrettierIfInstalled();
168
+
166
169
  clack.outro(buildOutroMessage(shouldCreateExamplePage));
167
170
  }
168
171