@sentry/wizard 3.10.0 → 3.12.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 (150) hide show
  1. package/CHANGELOG.md +54 -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 +225 -0
  19. package/dist/src/android/android-wizard.js.map +1 -0
  20. package/dist/src/android/code-tools.d.ts +47 -0
  21. package/dist/src/android/code-tools.js +173 -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 +286 -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 +123 -111
  63. package/dist/src/sourcemaps/tools/vite.js.map +1 -1
  64. package/dist/src/sourcemaps/tools/webpack.d.ts +6 -1
  65. package/dist/src/sourcemaps/tools/webpack.js +290 -25
  66. package/dist/src/sourcemaps/tools/webpack.js.map +1 -1
  67. package/dist/src/sourcemaps/utils/detect-tool.d.ts +1 -1
  68. package/dist/src/sourcemaps/utils/detect-tool.js.map +1 -1
  69. package/dist/src/sveltekit/sdk-setup.js +5 -5
  70. package/dist/src/sveltekit/sdk-setup.js.map +1 -1
  71. package/dist/src/sveltekit/sveltekit-wizard.js +34 -44
  72. package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
  73. package/dist/src/telemetry.js +1 -0
  74. package/dist/src/telemetry.js.map +1 -1
  75. package/dist/src/utils/ast-utils.d.ts +9 -5
  76. package/dist/src/utils/ast-utils.js +26 -11
  77. package/dist/src/utils/ast-utils.js.map +1 -1
  78. package/dist/src/utils/clack-utils.d.ts +74 -28
  79. package/dist/src/utils/clack-utils.js +427 -264
  80. package/dist/src/utils/clack-utils.js.map +1 -1
  81. package/dist/src/utils/package-manager.d.ts +10 -0
  82. package/dist/{lib/Helper/PackageManager.js → src/utils/package-manager.js} +42 -74
  83. package/dist/src/utils/package-manager.js.map +1 -0
  84. package/dist/src/utils/release-registry.d.ts +1 -0
  85. package/dist/src/utils/release-registry.js +68 -0
  86. package/dist/src/utils/release-registry.js.map +1 -0
  87. package/dist/src/utils/sentrycli-utils.d.ts +4 -0
  88. package/dist/src/utils/sentrycli-utils.js +41 -0
  89. package/dist/src/utils/sentrycli-utils.js.map +1 -0
  90. package/dist/test/android/code-tools.test.d.ts +1 -0
  91. package/dist/test/android/code-tools.test.js +34 -0
  92. package/dist/test/android/code-tools.test.js.map +1 -0
  93. package/dist/test/sourcemaps/tools/vite.test.d.ts +1 -0
  94. package/dist/test/sourcemaps/tools/vite.test.js +132 -0
  95. package/dist/test/sourcemaps/tools/vite.test.js.map +1 -0
  96. package/dist/test/sourcemaps/tools/webpack.test.d.ts +1 -0
  97. package/dist/test/sourcemaps/tools/webpack.test.js +179 -0
  98. package/dist/test/sourcemaps/tools/webpack.test.js.map +1 -0
  99. package/dist/test/utils/ast-utils.test.js +42 -7
  100. package/dist/test/utils/ast-utils.test.js.map +1 -1
  101. package/dist/test/utils/clack-utils.test.d.ts +1 -0
  102. package/dist/test/utils/clack-utils.test.js +200 -0
  103. package/dist/test/utils/clack-utils.test.js.map +1 -0
  104. package/lib/Constants.ts +5 -0
  105. package/lib/Steps/ChooseIntegration.ts +7 -3
  106. package/lib/Steps/Integrations/Android.ts +23 -0
  107. package/lib/Steps/Integrations/ReactNative.ts +9 -3
  108. package/lib/Steps/PromptForParameters.ts +48 -3
  109. package/lib/Steps/SentryProjectSelector.ts +3 -1
  110. package/package.json +4 -3
  111. package/src/android/android-wizard.ts +204 -0
  112. package/src/android/code-tools.ts +170 -0
  113. package/src/android/gradle.ts +250 -0
  114. package/src/android/manifest.ts +180 -0
  115. package/src/android/templates.ts +88 -0
  116. package/src/apple/apple-wizard.ts +113 -35
  117. package/src/apple/cocoapod.ts +6 -3
  118. package/src/apple/code-tools.ts +46 -18
  119. package/src/apple/fastlane.ts +6 -12
  120. package/src/apple/templates.ts +2 -8
  121. package/src/apple/xcode-manager.ts +167 -25
  122. package/src/nextjs/nextjs-wizard.ts +72 -8
  123. package/src/nextjs/templates.ts +16 -2
  124. package/src/remix/remix-wizard.ts +10 -15
  125. package/src/sourcemaps/sourcemaps-wizard.ts +19 -5
  126. package/src/sourcemaps/tools/nextjs.ts +2 -2
  127. package/src/sourcemaps/tools/sentry-cli.ts +8 -7
  128. package/src/sourcemaps/tools/vite.ts +143 -79
  129. package/src/sourcemaps/tools/webpack.ts +369 -30
  130. package/src/sourcemaps/utils/detect-tool.ts +2 -1
  131. package/src/sveltekit/sdk-setup.ts +10 -6
  132. package/src/sveltekit/sveltekit-wizard.ts +5 -14
  133. package/src/telemetry.ts +2 -0
  134. package/src/utils/ast-utils.ts +29 -11
  135. package/src/utils/clack-utils.ts +485 -283
  136. package/src/utils/package-manager.ts +61 -0
  137. package/src/utils/release-registry.ts +19 -0
  138. package/src/utils/sentrycli-utils.ts +22 -0
  139. package/test/android/code-tools.test.ts +49 -0
  140. package/test/sourcemaps/tools/vite.test.ts +149 -0
  141. package/test/sourcemaps/tools/webpack.test.ts +303 -0
  142. package/test/utils/ast-utils.test.ts +28 -9
  143. package/test/utils/clack-utils.test.ts +142 -0
  144. package/dist/lib/Helper/PackageManager.d.ts +0 -22
  145. package/dist/lib/Helper/PackageManager.js.map +0 -1
  146. package/dist/src/utils/vendor/clack-custom-select.d.ts +0 -21
  147. package/dist/src/utils/vendor/clack-custom-select.js +0 -137
  148. package/dist/src/utils/vendor/clack-custom-select.js.map +0 -1
  149. package/lib/Helper/PackageManager.ts +0 -59
  150. package/src/utils/vendor/clack-custom-select.ts +0 -160
@@ -1,11 +1,24 @@
1
+ import * as path from 'path';
2
+ import * as fs from 'fs';
3
+
1
4
  // @ts-ignore - clack is ESM and TS complains about that. It works though
2
- import clack, { select } from '@clack/prompts';
5
+ import * as clack from '@clack/prompts';
3
6
  import chalk from 'chalk';
7
+
8
+ import * as recast from 'recast';
9
+ import x = recast.types;
10
+ import t = x.namedTypes;
11
+
12
+ import * as Sentry from '@sentry/node';
13
+
4
14
  import {
5
15
  abortIfCancelled,
6
16
  addDotEnvSentryBuildPluginFile,
17
+ askForToolConfigPath,
18
+ createNewConfigFile,
7
19
  getPackageDotJson,
8
20
  installPackage,
21
+ showCopyPasteInstructions,
9
22
  } from '../../utils/clack-utils';
10
23
  import { hasPackageInstalled } from '../../utils/package-json';
11
24
 
@@ -14,28 +27,57 @@ import {
14
27
  SourceMapUploadToolConfigurationOptions,
15
28
  } from './types';
16
29
 
17
- const getCodeSnippet = (options: SourceMapUploadToolConfigurationOptions) =>
18
- chalk.gray(`
19
- ${chalk.greenBright(
20
- 'const { sentryWebpackPlugin } = require("@sentry/webpack-plugin");',
21
- )}
30
+ import { findFile, hasSentryContent } from '../../utils/ast-utils';
31
+ import { debug } from '../../utils/debug';
22
32
 
23
- module.exports = {
24
- // ... other config options
25
- ${chalk.greenBright(
26
- 'devtool: "source-map", // Source map generation must be turned on',
27
- )}
28
- plugins: [
29
- ${chalk.greenBright(`sentryWebpackPlugin({
33
+ const getCodeSnippet = (
34
+ options: SourceMapUploadToolConfigurationOptions,
35
+ colors: boolean,
36
+ ) => {
37
+ const rawImportStmt =
38
+ 'const { sentryWebpackPlugin } = require("@sentry/webpack-plugin");';
39
+ const rawGenerateSourceMapsOption =
40
+ 'devtool: "source-map", // Source map generation must be turned on';
41
+ const rawSentryWebpackPluginFunction = `sentryWebpackPlugin({
30
42
  authToken: process.env.SENTRY_AUTH_TOKEN,
31
43
  org: "${options.orgSlug}",
32
44
  project: "${options.projectSlug}",${
33
- options.selfHosted ? `\n url: "${options.url}",` : ''
34
- }
35
- })`)},
36
- ],
45
+ options.selfHosted ? `\n url: "${options.url}",` : ''
46
+ }
47
+ })`;
48
+
49
+ const importStmt = colors ? chalk.greenBright(rawImportStmt) : rawImportStmt;
50
+ const generateSourceMapsOption = colors
51
+ ? chalk.greenBright(rawGenerateSourceMapsOption)
52
+ : rawGenerateSourceMapsOption;
53
+ const sentryWebpackPluginFunction = colors
54
+ ? chalk.greenBright(rawSentryWebpackPluginFunction)
55
+ : rawSentryWebpackPluginFunction;
56
+
57
+ const code = getWebpackConfigContent(
58
+ importStmt,
59
+ generateSourceMapsOption,
60
+ sentryWebpackPluginFunction,
61
+ );
62
+
63
+ return colors ? chalk.gray(code) : code;
37
64
  };
38
- `);
65
+
66
+ const getWebpackConfigContent = (
67
+ importStmt: string,
68
+ generateSourceMapsOption: string,
69
+ sentryWebpackPluginFunction: string,
70
+ ) => `${importStmt}
71
+
72
+ module.exports = {
73
+ // ... other options
74
+ ${generateSourceMapsOption},
75
+ plugins: [
76
+ // Put the Sentry Webpack plugin after all other plugins
77
+ ${sentryWebpackPluginFunction},
78
+ ],
79
+ }
80
+ `;
39
81
 
40
82
  export const configureWebPackPlugin: SourceMapUploadToolConfigurationFunction =
41
83
  async (options) => {
@@ -47,21 +89,318 @@ export const configureWebPackPlugin: SourceMapUploadToolConfigurationFunction =
47
89
  ),
48
90
  });
49
91
 
50
- clack.log.step(
51
- `Add the following code to your ${chalk.bold('webpack.config.js')} file:`,
52
- );
92
+ const webpackConfigPath =
93
+ findFile(path.resolve(process.cwd(), 'webpack.config')) ??
94
+ (await askForToolConfigPath('Webpack', 'webpack.config.js'));
95
+
96
+ let successfullyAdded = false;
97
+ if (webpackConfigPath) {
98
+ successfullyAdded = await modifyWebpackConfig(webpackConfigPath, options);
99
+ } else {
100
+ successfullyAdded = await createNewConfigFile(
101
+ path.join(process.cwd(), 'webpack.config.js'),
102
+ getCodeSnippet(options, false),
103
+ 'More information about Webpack configs: https://vitejs.dev/config/',
104
+ );
105
+ Sentry.setTag(
106
+ 'created-new-config',
107
+ successfullyAdded ? 'success' : 'fail',
108
+ );
109
+ }
110
+
111
+ if (successfullyAdded) {
112
+ clack.log.info(
113
+ `We recommend checking the ${
114
+ webpackConfigPath ? 'modified' : 'added'
115
+ } file after the wizard finished to ensure it works with your build setup.`,
116
+ );
117
+
118
+ Sentry.setTag('ast-mod', 'success');
119
+ } else {
120
+ Sentry.setTag('ast-mod', 'fail');
121
+ await showCopyPasteInstructions(
122
+ path.basename(webpackConfigPath || 'webpack.config.js'),
123
+ getCodeSnippet(options, true),
124
+ );
125
+ }
126
+
127
+ await addDotEnvSentryBuildPluginFile(options.authToken);
128
+ };
129
+
130
+ /**
131
+ * Modifies a webpack config file to enable source map generation and add the Sentry webpack plugin
132
+ * exported only for testing
133
+ */
134
+ export async function modifyWebpackConfig(
135
+ webpackConfigPath: string,
136
+ options: SourceMapUploadToolConfigurationOptions,
137
+ ): Promise<boolean> {
138
+ try {
139
+ const webpackConfig = await fs.promises.readFile(webpackConfigPath, {
140
+ encoding: 'utf-8',
141
+ });
142
+
143
+ const prettyConfigFilename = chalk.cyan(path.basename(webpackConfigPath));
144
+
145
+ // no idea why recast returns any here, this is dumb :/
146
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
147
+ const program = recast.parse(webpackConfig.toString()).program as t.Program;
148
+
149
+ if (!(await shouldModifyWebpackConfig(program, prettyConfigFilename))) {
150
+ // Sentry tag is set in shouldModifyWebpackConfig
151
+ return false;
152
+ }
153
+
154
+ const exportStmt = getCjsModuleExports(program);
155
+ if (!exportStmt) {
156
+ // We only care about CJS at the moment since it's probably the most widely used format for webpack configs.
157
+ debug(`Could not find module.exports = {...} in ${webpackConfigPath}.`);
158
+ Sentry.setTag('ast-mod-fail-reason', 'config-object-not-found');
159
+ return false;
160
+ }
161
+
162
+ const configObject = getWebpackConfigObject(exportStmt, program);
163
+
164
+ if (!configObject) {
165
+ debug(`Couldn't find config object in ${webpackConfigPath}`);
166
+ Sentry.setTag('ast-mod-fail-reason', 'config-object-not-found');
167
+ return false;
168
+ }
53
169
 
54
- // Intentially logging directly to console here so that the code can be copied/pasted directly
55
- // eslint-disable-next-line no-console
56
- console.log(getCodeSnippet(options));
170
+ const enabledSourcemaps = enableSourcemapsGeneration(configObject);
57
171
 
58
- await abortIfCancelled(
59
- select({
60
- message: 'Did you copy the snippet above?',
61
- options: [{ label: 'Yes, continue!', value: true }],
172
+ if (enabledSourcemaps) {
173
+ clack.log.success(
174
+ `Enabled source map generation in ${prettyConfigFilename}.`,
175
+ );
176
+ } else {
177
+ clack.log.warn(
178
+ `Couldn't enable source maps generation in ${prettyConfigFilename} Please follow the instructions below.`,
179
+ );
180
+ Sentry.setTag('ast-mod-fail-reason', 'insertion-fail');
181
+ return false;
182
+ }
183
+
184
+ const addedPlugin = addSentryWebpackPlugin(program, configObject, options);
185
+ if (addedPlugin) {
186
+ clack.log.success(
187
+ `Added Sentry webpack plugin to ${prettyConfigFilename}.`,
188
+ );
189
+ } else {
190
+ clack.log.warn(
191
+ `Couldn't add Sentry webpack plugin to ${prettyConfigFilename}. Please follow the instructions below.`,
192
+ );
193
+ Sentry.setTag('ast-mod-fail-reason', 'insertion-fail');
194
+ return false;
195
+ }
196
+
197
+ const code = recast.print(program).code;
198
+ await fs.promises.writeFile(webpackConfigPath, code);
199
+
200
+ return true;
201
+ } catch (e) {
202
+ Sentry.setTag('ast-mod-fail-reason', 'insertion-fail');
203
+ debug(e);
204
+ return false;
205
+ }
206
+ }
207
+
208
+ async function shouldModifyWebpackConfig(
209
+ program: t.Program,
210
+ prettyConfigFilename: string,
211
+ ) {
212
+ if (hasSentryContent(program)) {
213
+ const shouldContinue = await abortIfCancelled(
214
+ clack.select({
215
+ message: `Seems like ${prettyConfigFilename} already contains Sentry-related code. Should the wizard modify it anyway?`,
216
+ options: [
217
+ {
218
+ label: 'Yes, add the Sentry Webpack plugin',
219
+ value: true,
220
+ },
221
+ {
222
+ label: 'No, show me instructions to manually add the plugin',
223
+ value: false,
224
+ },
225
+ ],
62
226
  initialValue: true,
63
227
  }),
64
228
  );
65
229
 
66
- await addDotEnvSentryBuildPluginFile(options.authToken);
67
- };
230
+ if (!shouldContinue) {
231
+ Sentry.setTag('ast-mod-fail-reason', 'has-sentry-content');
232
+ return false;
233
+ }
234
+ }
235
+
236
+ return true;
237
+ }
238
+
239
+ function addSentryWebpackPlugin(
240
+ program: t.Program,
241
+ configObj: t.ObjectExpression,
242
+ options: SourceMapUploadToolConfigurationOptions,
243
+ ) {
244
+ const b = addSentryWebpackPluginImport(program);
245
+
246
+ const sentryPluginCall = b.callExpression(
247
+ b.identifier('sentryWebpackPlugin'),
248
+ [
249
+ b.objectExpression([
250
+ b.objectProperty(
251
+ b.identifier('authToken'),
252
+ b.identifier('process.env.SENTRY_AUTH_TOKEN'),
253
+ ),
254
+ b.objectProperty(b.identifier('org'), b.stringLiteral(options.orgSlug)),
255
+ b.objectProperty(
256
+ b.identifier('project'),
257
+ b.stringLiteral(options.projectSlug),
258
+ ),
259
+ ...(options.selfHosted
260
+ ? [
261
+ b.objectProperty(
262
+ b.identifier('url'),
263
+ b.stringLiteral(options.url),
264
+ ),
265
+ ]
266
+ : []),
267
+ ]),
268
+ ],
269
+ );
270
+
271
+ const pluginsProp = configObj.properties.find(
272
+ (p): p is t.Property =>
273
+ p.type === 'Property' &&
274
+ p.key.type === 'Identifier' &&
275
+ p.key.name === 'plugins',
276
+ );
277
+
278
+ if (pluginsProp) {
279
+ if (pluginsProp.value.type === 'ArrayExpression') {
280
+ pluginsProp.value.elements.push(sentryPluginCall);
281
+ } else {
282
+ pluginsProp.value = b.arrayExpression([sentryPluginCall]);
283
+ }
284
+ return true;
285
+ }
286
+
287
+ configObj.properties.push(
288
+ b.objectProperty(
289
+ b.identifier('plugins'),
290
+ b.arrayExpression([sentryPluginCall]),
291
+ ),
292
+ );
293
+
294
+ return true;
295
+ }
296
+
297
+ function addSentryWebpackPluginImport(program: t.Program) {
298
+ const b = recast.types.builders;
299
+
300
+ const sentryPluginRequireStmt = b.variableDeclaration('const', [
301
+ b.variableDeclarator(
302
+ b.objectPattern([
303
+ b.objectProperty.from({
304
+ key: b.identifier('sentryWebpackPlugin'),
305
+ value: b.identifier('sentryWebpackPlugin'),
306
+ shorthand: true,
307
+ }),
308
+ ]),
309
+ b.callExpression(b.identifier('require'), [
310
+ b.stringLiteral('@sentry/webpack-plugin'),
311
+ ]),
312
+ ),
313
+ ]);
314
+
315
+ program.body.unshift(sentryPluginRequireStmt);
316
+ return b;
317
+ }
318
+
319
+ function enableSourcemapsGeneration(configObj: t.ObjectExpression): boolean {
320
+ const b = recast.types.builders;
321
+
322
+ const devtoolProp = configObj.properties.find(
323
+ (p): p is t.Property =>
324
+ p.type === 'Property' &&
325
+ p.key.type === 'Identifier' &&
326
+ p.key.name === 'devtool',
327
+ );
328
+
329
+ if (devtoolProp) {
330
+ // devtool can have quite a lot of source maps values.
331
+ // see: https://webpack.js.org/configuration/devtool/#devtool
332
+ // For Sentry to work best, we should set it to "source-map" or "hidden-source-map"
333
+ // Heuristic:
334
+ // - all values that contain "hidden" will be set to "hidden-source-map"
335
+ // - all other values will be set to "source-map"
336
+ if (
337
+ (devtoolProp.value.type === 'Literal' ||
338
+ devtoolProp.value.type === 'StringLiteral') &&
339
+ devtoolProp.value.value?.toString().startsWith('hidden-')
340
+ ) {
341
+ devtoolProp.value = b.stringLiteral('hidden-source-map');
342
+ } else {
343
+ devtoolProp.value = b.stringLiteral('source-map');
344
+ }
345
+ return true;
346
+ }
347
+
348
+ configObj.properties.push(
349
+ b.objectProperty(b.identifier('devtool'), b.stringLiteral('source-map')),
350
+ );
351
+
352
+ return true;
353
+ }
354
+
355
+ function getWebpackConfigObject(
356
+ moduleExports: t.AssignmentExpression,
357
+ program: t.Program,
358
+ ): t.ObjectExpression | undefined {
359
+ const rhs = moduleExports.right;
360
+ if (rhs.type === 'ObjectExpression') {
361
+ return rhs;
362
+ }
363
+ if (rhs.type === 'Identifier') {
364
+ const configId = rhs.name;
365
+
366
+ const configDeclaration = program.body.find(
367
+ (s): s is t.VariableDeclaration =>
368
+ s.type === 'VariableDeclaration' &&
369
+ !!s.declarations.find(
370
+ (d) =>
371
+ d.type === 'VariableDeclarator' &&
372
+ d.id.type === 'Identifier' &&
373
+ d.id.name === configId,
374
+ ),
375
+ );
376
+
377
+ const declarator = configDeclaration?.declarations.find(
378
+ (d): d is t.VariableDeclarator =>
379
+ d.type === 'VariableDeclarator' &&
380
+ d.id.type === 'Identifier' &&
381
+ d.id.name === configId,
382
+ );
383
+
384
+ return declarator?.init?.type === 'ObjectExpression'
385
+ ? declarator.init
386
+ : undefined;
387
+ }
388
+
389
+ return undefined;
390
+ }
391
+
392
+ function getCjsModuleExports(
393
+ program: t.Program,
394
+ ): t.AssignmentExpression | undefined {
395
+ const moduleExports = program.body.find(
396
+ (s): s is t.ExpressionStatement =>
397
+ s.type === 'ExpressionStatement' &&
398
+ s.expression.type === 'AssignmentExpression' &&
399
+ s.expression.left.type === 'MemberExpression' &&
400
+ s.expression.left.object.type === 'Identifier' &&
401
+ s.expression.left.object.name === 'module' &&
402
+ s.expression.left.property.type === 'Identifier' &&
403
+ s.expression.left.property.name === 'exports',
404
+ );
405
+ return moduleExports?.expression as t.AssignmentExpression;
406
+ }
@@ -11,7 +11,8 @@ export type SupportedTools =
11
11
  | 'create-react-app'
12
12
  | 'angular'
13
13
  | 'nextjs'
14
- | 'remix';
14
+ | 'remix'
15
+ | 'no-tool';
15
16
 
16
17
  // A map of package names pointing to the tool slug.
17
18
  // The order is important, because we want to detect the most specific tool first.
@@ -15,7 +15,11 @@ import { addVitePlugin } from 'magicast/helpers';
15
15
  import { getClientHooksTemplate, getServerHooksTemplate } from './templates';
16
16
  import { abortIfCancelled, isUsingTypeScript } from '../utils/clack-utils';
17
17
  import { debug } from '../utils/debug';
18
- import { findScriptFile, hasSentryContent } from '../utils/ast-utils';
18
+ import { findFile, hasSentryContent } from '../utils/ast-utils';
19
+
20
+ import * as recast from 'recast';
21
+ import x = recast.types;
22
+ import t = x.namedTypes;
19
23
 
20
24
  const SVELTE_CONFIG_FILE = 'svelte.config.js';
21
25
 
@@ -46,10 +50,10 @@ export async function createOrMergeSvelteKitFiles(
46
50
  const { clientHooksPath, serverHooksPath } = getHooksConfigDirs(svelteConfig);
47
51
 
48
52
  // full file paths with correct file ending (or undefined if not found)
49
- const originalClientHooksFile = findScriptFile(clientHooksPath);
50
- const originalServerHooksFile = findScriptFile(serverHooksPath);
53
+ const originalClientHooksFile = findFile(clientHooksPath);
54
+ const originalServerHooksFile = findFile(serverHooksPath);
51
55
 
52
- const viteConfig = findScriptFile(path.resolve(process.cwd(), 'vite.config'));
56
+ const viteConfig = findFile(path.resolve(process.cwd(), 'vite.config'));
53
57
 
54
58
  const fileEnding = isUsingTypeScript() ? 'ts' : 'js';
55
59
 
@@ -139,7 +143,7 @@ async function mergeHooksFile(
139
143
  dsn: string,
140
144
  ): Promise<void> {
141
145
  const originalHooksMod = await loadFile(hooksFile);
142
- if (hasSentryContent(originalHooksMod)) {
146
+ if (hasSentryContent(originalHooksMod.$ast as t.Program)) {
143
147
  // We don't want to mess with files that already have Sentry content.
144
148
  // Let's just bail out at this point.
145
149
  clack.log.warn(
@@ -399,7 +403,7 @@ async function modifyViteConfig(
399
403
  try {
400
404
  const viteModule = parseModule(viteConfigContent);
401
405
 
402
- if (hasSentryContent(viteModule)) {
406
+ if (hasSentryContent(viteModule.$ast as t.Program)) {
403
407
  clack.log.warn(
404
408
  `File ${chalk.cyan(
405
409
  path.basename(viteConfigPath),
@@ -4,12 +4,10 @@ import chalk from 'chalk';
4
4
 
5
5
  import {
6
6
  abort,
7
- addSentryCliRc,
8
- askForProjectSelection,
9
- askForSelfHosted,
10
- askForWizardLogin,
7
+ addSentryCliConfig,
11
8
  confirmContinueEvenThoughNoGitRepo,
12
9
  ensurePackageIsInstalled,
10
+ getOrAskForProjectData,
13
11
  getPackageDotJson,
14
12
  installPackage,
15
13
  printWelcome,
@@ -32,22 +30,15 @@ export async function runSvelteKitWizard(
32
30
  const packageJson = await getPackageDotJson();
33
31
  await ensurePackageIsInstalled(packageJson, '@sveltejs/kit', 'Sveltekit');
34
32
 
35
- const { url: sentryUrl, selfHosted } = await askForSelfHosted(options.url);
36
-
37
- const { projects, apiKeys } = await askForWizardLogin({
38
- promoCode: options.promoCode,
39
- url: sentryUrl,
40
- platform: 'javascript-sveltekit',
41
- });
42
-
43
- const selectedProject = await askForProjectSelection(projects);
33
+ const { selectedProject, selfHosted, sentryUrl, authToken } =
34
+ await getOrAskForProjectData(options, 'javascript-sveltekit');
44
35
 
45
36
  await installPackage({
46
37
  packageName: '@sentry/sveltekit',
47
38
  alreadyInstalled: hasPackageInstalled('@sentry/sveltekit', packageJson),
48
39
  });
49
40
 
50
- await addSentryCliRc(apiKeys.token);
41
+ await addSentryCliConfig(authToken);
51
42
 
52
43
  const svelteConfig = await loadSvelteConfig();
53
44
 
package/src/telemetry.ts CHANGED
@@ -52,6 +52,8 @@ function createSentryInstance(enabled: boolean, integration: string) {
52
52
  dsn: 'https://8871d3ff64814ed8960c96d1fcc98a27@o1.ingest.sentry.io/4505425820712960',
53
53
  enabled: enabled,
54
54
 
55
+ environment: `production-${integration}`,
56
+
55
57
  tracesSampleRate: 1,
56
58
  sampleRate: 1,
57
59
 
@@ -1,20 +1,38 @@
1
1
  import * as fs from 'fs';
2
- // @ts-ignore - magicast is ESM and TS complains about that. It works though
3
- import { ProxifiedModule } from 'magicast';
2
+
3
+ import * as recast from 'recast';
4
+ import x = recast.types;
5
+ import t = x.namedTypes;
4
6
 
5
7
  /**
6
- * Checks if a JS/TS file where we don't know its concrete file type yet exists
8
+ * Checks if a file where we don't know its concrete file type yet exists
7
9
  * and returns the full path to the file with the correct file type.
8
10
  */
9
- export function findScriptFile(hooksFile: string): string | undefined {
10
- const possibleFileTypes = ['.js', '.ts', '.mjs'];
11
- return possibleFileTypes
12
- .map((type) => `${hooksFile}${type}`)
11
+ export function findFile(
12
+ filePath: string,
13
+ fileTypes: string[] = ['.js', '.ts', '.mjs', '.cjs'],
14
+ ): string | undefined {
15
+ return fileTypes
16
+ .map((type) => `${filePath}${type}`)
13
17
  .find((file) => fs.existsSync(file));
14
18
  }
15
19
 
16
- /** Checks if a Sentry package is already mentioned in the file */
17
- export function hasSentryContent(mod: ProxifiedModule<object>): boolean {
18
- const imports = mod.imports.$items.map((i) => i.from);
19
- return !!imports.find((i) => i.startsWith('@sentry/'));
20
+ /**
21
+ * checks for require('@sentry/*') syntax
22
+ */
23
+ export function hasSentryContent(program: t.Program): boolean {
24
+ let foundSentry: boolean | undefined = false;
25
+ recast.visit(program, {
26
+ visitStringLiteral(path) {
27
+ foundSentry = foundSentry || path.node.value.startsWith('@sentry/');
28
+ this.traverse(path);
29
+ },
30
+ visitLiteral(path) {
31
+ foundSentry =
32
+ foundSentry || path.node.value?.toString().startsWith('@sentry/');
33
+ this.traverse(path);
34
+ },
35
+ });
36
+
37
+ return !!foundSentry;
20
38
  }