@sentry/wizard 1.2.13 → 1.2.17

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.
package/CHANGELOG.md CHANGED
@@ -2,276 +2,294 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 1.2.17
6
+
7
+ - Support Next.js v12 (#152)
8
+
9
+ ## 1.2.16
10
+
11
+ - fix(nextjs): Do not capture 404s as exceptions in `_error` (#146)
12
+
13
+ ## 1.2.15
14
+
15
+ - Check version range rather than minimum version for nextjs (#143)
16
+
17
+ ## 1.2.14
18
+
19
+ - Automatically include `pages/_error.js` when setting up nextjs project (#140)
20
+ - Clarify "Usage" section of `README.md` (#139)
21
+
5
22
  ## 1.2.13
6
23
 
7
- * Fix `.sentryclirc` file formatting (#131)
24
+ - Fix `.sentryclirc` file formatting (#131)
8
25
 
9
26
  ## 1.2.12
10
27
 
11
- * Don't expose auth token in `sentry.properties` (#128)
28
+ - Don't expose auth token in `sentry.properties` (#128)
12
29
 
13
30
  ## 1.2.11
14
31
 
15
- * Parse Next.js version as a string, instead of int (#122)
32
+ - Parse Next.js version as a string, instead of int (#122)
16
33
 
17
34
  ## 1.2.10
18
35
 
19
- * Check new contents before overwriting a file (#117)
36
+ - Check new contents before overwriting a file (#117)
20
37
 
21
38
  ## 1.2.9
22
39
 
23
- * Add performance monitoring support to nextjs scripts (#114)
24
- * Make webpack silent by default in nextjs config (#113)
40
+ - Add performance monitoring support to nextjs scripts (#114)
41
+ - Make webpack silent by default in nextjs config (#113)
25
42
 
26
43
  ## v1.2.8
27
44
 
28
- * Fix React Native JS patching throwing errors due to incorrect argument
45
+ - Fix React Native JS patching throwing errors due to incorrect argument
29
46
 
30
47
  ## v1.2.7
31
48
 
32
- * Fix React Native uninstall script
33
- * Fix platform selection issues and repeated prompts on Mobile Projects.
49
+ - Fix React Native uninstall script
50
+ - Fix platform selection issues and repeated prompts on Mobile Projects.
34
51
 
35
52
  ## v1.2.6
36
53
 
37
- * Get release from environment for the Next.js SDK
54
+ - Get release from environment for the Next.js SDK
38
55
 
39
56
  ## v1.2.5
40
57
 
41
- * Ignore coverage when linting and clarify Next.js messages.
58
+ - Ignore coverage when linting and clarify Next.js messages.
42
59
 
43
60
  ## v1.2.4
44
61
 
45
- * Add Next.js SDK initialization config files.
46
- * Update webpack config file of Next.js.
62
+ - Add Next.js SDK initialization config files.
63
+ - Update webpack config file of Next.js.
47
64
 
48
65
  ## v1.2.3
49
66
 
50
- * Don't use `package` as a varname in the NextJS config
51
- * Enable env variables in the NextJS config
67
+ - Don't use `package` as a varname in the NextJS config
68
+ - Enable env variables in the NextJS config
52
69
 
53
70
  ## v1.2.2
54
71
 
55
- * Add support for `NEXT_PUBLIC_SENTRY_DSN`
72
+ - Add support for `NEXT_PUBLIC_SENTRY_DSN`
56
73
 
57
74
  ## v1.2.1
58
75
 
59
- * Update `next.config.js`, and create mergeable configs when they already exist
76
+ - Update `next.config.js`, and create mergeable configs when they already exist
60
77
 
61
78
  ## v1.2.0
62
79
 
63
- * Add support for Next.js
80
+ - Add support for Next.js
64
81
 
65
82
  ## v1.1.4
66
83
 
67
- * Bump @sentry/cli `1.52.4`
84
+ - Bump @sentry/cli `1.52.4`
68
85
 
69
86
  ## v1.1.3
70
87
 
71
- * Add sourcemap output path to derived data to react native ios script
72
- * Bump @sentry/cli `1.52.3`
88
+ - Add sourcemap output path to derived data to react native ios script
89
+ - Bump @sentry/cli `1.52.3`
73
90
 
74
91
  ## v1.1.2
75
92
 
76
- * Don't `cli/executable` for Android project on react-native
93
+ - Don't `cli/executable` for Android project on react-native
77
94
 
78
95
  ## v1.1.1
79
96
 
80
- * Bump @sentry/cli `1.51.0`
97
+ - Bump @sentry/cli `1.51.0`
81
98
 
82
99
  ## v1.1.0
83
100
 
84
- * Bump @sentry/cli `1.50.0`
101
+ - Bump @sentry/cli `1.50.0`
85
102
 
86
103
  ## v1.0.2
87
104
 
88
- * Several dependeny bumps with related security updates
105
+ - Several dependeny bumps with related security updates
89
106
 
90
107
  ## v1.0.1
91
108
 
92
- * Strip only `Sentry*` frameworks for Cordova
93
- * Guard Xcode project updates for react-native
109
+ - Strip only `Sentry*` frameworks for Cordova
110
+ - Guard Xcode project updates for react-native
94
111
 
95
112
  ## v1.0.0
96
113
 
97
- * Support for new `@sentry/react-native`
114
+ - Support for new `@sentry/react-native`
98
115
 
99
116
  ## v0.13.0
100
117
 
101
- * Bump @sentry/cli `1.43.0`
118
+ - Bump @sentry/cli `1.43.0`
102
119
 
103
120
  ## v0.12.1
104
121
 
105
- * Bump @sentry/cli `1.36.1`
122
+ - Bump @sentry/cli `1.36.1`
106
123
 
107
124
  ## v0.12.0
108
125
 
109
- * Fixed #22
110
- * Bumped dependencies
126
+ - Fixed #22
127
+ - Bumped dependencies
111
128
 
112
129
  ## v0.11.1
113
130
 
114
- * Fixed #16
131
+ - Fixed #16
115
132
 
116
133
  ## v0.11.0
117
134
 
118
- * Update all dependencies, Fix tests on travis
135
+ - Update all dependencies, Fix tests on travis
119
136
 
120
137
  ## v0.10.3
121
138
 
122
- * Use public DSN for react-native
139
+ - Use public DSN for react-native
123
140
 
124
141
  ## v0.10.2
125
142
 
126
- * Remove secret DSN part check for prompt
143
+ - Remove secret DSN part check for prompt
127
144
 
128
145
  ## v0.10.1
129
146
 
130
- * Use opn in favor of open
147
+ - Use opn in favor of open
131
148
 
132
149
  ## v0.10.0
133
150
 
134
- * Change Cordova wizard steps to only run once and create properties file in root
151
+ - Change Cordova wizard steps to only run once and create properties file in
152
+ root
135
153
 
136
154
  ## v0.9.7
137
155
 
138
- * Fix a bug where sentry-wizard will ask for parameters on uninstall
156
+ - Fix a bug where sentry-wizard will ask for parameters on uninstall
139
157
 
140
158
  ## v0.9.6
141
159
 
142
- * Fix electron symbol upload script
160
+ - Fix electron symbol upload script
143
161
 
144
162
  ## v0.9.5
145
163
 
146
- * Update Electron instructions to latest SDK version
164
+ - Update Electron instructions to latest SDK version
147
165
 
148
166
  ## v0.9.4
149
167
 
150
- * Restore Node compatibility
151
- * Add more tests
168
+ - Restore Node compatibility
169
+ - Add more tests
152
170
 
153
171
  ## v0.9.3
154
172
 
155
- * Fix Electron installation code - Fixes #7
173
+ - Fix Electron installation code - Fixes #7
156
174
 
157
175
  ## v0.9.2
158
176
 
159
- * Support Electron prereleases in symbol upload
160
- * Correctly upload Electron dSYMs for macOS
177
+ - Support Electron prereleases in symbol upload
178
+ - Correctly upload Electron dSYMs for macOS
161
179
 
162
180
  ## v0.9.1
163
181
 
164
- * Add strip arch script for cordova
182
+ - Add strip arch script for cordova
165
183
 
166
184
  ## v0.9.0
167
185
 
168
- * Add support for electron projects
186
+ - Add support for electron projects
169
187
 
170
188
  ## v0.8.3
171
189
 
172
- * Fixed an issue where file exsists always returned false
190
+ - Fixed an issue where file exsists always returned false
173
191
 
174
192
  ## v0.8.2
175
193
 
176
- * Move sentry.properties file to plugins folder for Cordova
194
+ - Move sentry.properties file to plugins folder for Cordova
177
195
 
178
196
  ## v0.8.1
179
197
 
180
- * Fix react-native js file patching
181
- * Bump sentry-cli to 1.28.4
198
+ - Fix react-native js file patching
199
+ - Bump sentry-cli to 1.28.4
182
200
 
183
201
  ## v0.8.0
184
202
 
185
- * Fix Cordova sentry-cli upload-dsym command for Xcode
203
+ - Fix Cordova sentry-cli upload-dsym command for Xcode
186
204
 
187
205
  ## v0.7.5
188
206
 
189
- * Bump sentry-cli version to 1.28.1
207
+ - Bump sentry-cli version to 1.28.1
190
208
 
191
209
  ## v0.7.4
192
210
 
193
- * Bump sentry-cli version to 1.27.1
194
- * Fix Cordova integration
195
- * Fix issue in file checker to default to false
211
+ - Bump sentry-cli version to 1.27.1
212
+ - Fix Cordova integration
213
+ - Fix issue in file checker to default to false
196
214
 
197
215
  ## v0.7.3
198
216
 
199
- * Bump sentry-cli version
217
+ - Bump sentry-cli version
200
218
 
201
219
  ## v0.7.2
202
220
 
203
- * Fix quiet mode and default parameter
204
- * Fix version detection for @sentry/cli
221
+ - Fix quiet mode and default parameter
222
+ - Fix version detection for @sentry/cli
205
223
 
206
224
  ## v0.7.1
207
225
 
208
- * Improve function call for wizard and parameter validation/sanitation
226
+ - Improve function call for wizard and parameter validation/sanitation
209
227
 
210
228
  ## v0.7.0
211
229
 
212
- * Use @sentry/cli
230
+ - Use @sentry/cli
213
231
 
214
232
  ## v0.6.1
215
233
 
216
- * Fixed https://github.com/getsentry/react-native-sentry/issues/304
234
+ - Fixed https://github.com/getsentry/react-native-sentry/issues/304
217
235
 
218
236
  ## v0.6.0
219
237
 
220
- * Add quiet mode --quiet
221
- * Fallback to user prompts when not able to connect to Sentry
222
- * Renamed parameter type/protype to integration
238
+ - Add quiet mode --quiet
239
+ - Fallback to user prompts when not able to connect to Sentry
240
+ - Renamed parameter type/protype to integration
223
241
 
224
242
  ## v0.5.3
225
243
 
226
- * Passing answers fixed in file helper
244
+ - Passing answers fixed in file helper
227
245
 
228
246
  ## v0.5.2
229
247
 
230
- * Platform check
248
+ - Platform check
231
249
 
232
250
  ## v0.5.1
233
251
 
234
- * Fix skip connection also for polling
252
+ - Fix skip connection also for polling
235
253
 
236
254
  ## v0.5.0
237
255
 
238
- * Add skip connection option to skip connecting to Sentry
239
- * Add possiblity to overwrite args with ENV vars SENTRY_WIZARD prefixed
256
+ - Add skip connection option to skip connecting to Sentry
257
+ - Add possiblity to overwrite args with ENV vars SENTRY_WIZARD prefixed
240
258
 
241
259
  ## v0.4.0
242
260
 
243
- * Fix uninstall step for react-native
261
+ - Fix uninstall step for react-native
244
262
 
245
263
  ## v0.3.2
246
264
 
247
- * Fix sentry-cli version
265
+ - Fix sentry-cli version
248
266
 
249
267
  ## v0.3.1
250
268
 
251
- * Fix polling and json reponse parsing
269
+ - Fix polling and json reponse parsing
252
270
 
253
271
  ## v0.3.0
254
272
 
255
- * Add support for cordova
256
- * Internal refactorings
257
- * Check if project is already setup
273
+ - Add support for cordova
274
+ - Internal refactorings
275
+ - Check if project is already setup
258
276
 
259
277
  ## v0.2.2
260
278
 
261
- * Fix build process
279
+ - Fix build process
262
280
 
263
281
  ## v0.2.1
264
282
 
265
- * Fix build process
283
+ - Fix build process
266
284
 
267
285
  ## v0.2.0
268
286
 
269
- * Add support for react-native
287
+ - Add support for react-native
270
288
 
271
289
  ## v0.1.1
272
290
 
273
- * Fix build process
291
+ - Fix build process
274
292
 
275
293
  ## v0.1.0
276
294
 
277
- * Inital release
295
+ - Inital release
package/README.md CHANGED
@@ -4,34 +4,51 @@
4
4
  </a>
5
5
  <br/>
6
6
  <h1>Sentry Wizard</h1>
7
- <h4>Helping you to set up your project with Sentry</h4>
7
+ <h4>The Sentry Wizard helps you set up your React Native, Cordova, Electron or Next.js projects with Sentry.</h4>
8
8
  </p>
9
9
 
10
- [![Travis](https://img.shields.io/travis/getsentry/sentry-wizard.svg?maxAge=2592000)](https://travis-ci.org/getsentry/sentry-wizard)
11
10
  [![npm version](https://img.shields.io/npm/v/@sentry/wizard.svg)](https://www.npmjs.com/package/@sentry/wizard)
12
11
  [![npm dm](https://img.shields.io/npm/dm/@sentry/wizard.svg)](https://www.npmjs.com/package/@sentry/wizard)
13
12
  [![npm dt](https://img.shields.io/npm/dt/@sentry/wizard.svg)](https://www.npmjs.com/package/@sentry/wizard)
14
- [![Discord Chat](https://img.shields.io/discord/621778831602221064.svg)](https://discord.gg/Ww9hbqr)
13
+ [![Discord Chat](https://img.shields.io/discord/621778831602221064.svg)](https://discord.gg/Ww9hbqr)
15
14
 
16
15
  [![deps](https://david-dm.org/getsentry/sentry-wizard/status.svg)](https://david-dm.org/getsentry/sentry-wizard?view=list)
17
16
  [![deps dev](https://david-dm.org/getsentry/sentry-wizard/dev-status.svg)](https://david-dm.org/getsentry/sentry-wizard?type=dev&view=list)
18
17
  [![deps peer](https://david-dm.org/getsentry/sentry-wizard/peer-status.svg)](https://david-dm.org/getsentry/sentry-wizard?type=peer&view=list)
19
18
 
20
-
21
19
  ![Wizard in action](https://github.com/getsentry/sentry-wizard/raw/master/assets/wizard.mov.gif)
22
20
 
23
-
24
21
  # Usage
25
22
 
26
- Install it with `npm` or `yarn`
23
+ There are multiple ways to run the Wizard.
24
+
25
+ 1. Install globally and run it anywhere:
26
+
27
+ ```bash
28
+ npm install -g @sentry/wizard
29
+ # or
30
+ yarn global add @sentry/wizard
31
+
32
+ sentry-wizard
33
+ ```
34
+
35
+ 2. Install and run it in your project with `yarn`:
27
36
 
37
+ ```bash
38
+ yarn add @sentry/wizard
39
+ yarn sentry-wizard
28
40
  ```
29
- npm install @sentry/wizard
41
+
42
+ 3. Run it directly without installing:
43
+
44
+ ```bash
45
+ npx @sentry/wizard
30
46
  ```
31
47
 
32
- Call `sentry-wizard` in your project and follow the instructions.
48
+ At the current moment, the wizard is meant to be used for React Native, Cordova, Electron or Next.js. If you have other platforms you would like the wizard to support, please open a [GitHub issue](https://github.com/getsentry/sentry-wizard/issues)!
33
49
 
34
50
  # Options
51
+
35
52
  ```
36
53
  Options:
37
54
  --help Show help [boolean]
@@ -56,7 +73,7 @@ Options:
56
73
 
57
74
  ## Resources
58
75
 
59
- * [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks)
60
- * [![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr)
61
- * [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](http://stackoverflow.com/questions/tagged/sentry)
62
- * [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry)
76
+ - [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks)
77
+ - [![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr)
78
+ - [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](http://stackoverflow.com/questions/tagged/sentry)
79
+ - [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry)
@@ -0,0 +1,65 @@
1
+ import NextErrorComponent from 'next/error';
2
+
3
+ import * as Sentry from '@sentry/nextjs';
4
+
5
+ const MyError = ({ statusCode, hasGetInitialPropsRun, err }) => {
6
+ if (!hasGetInitialPropsRun && err) {
7
+ // getInitialProps is not called in case of
8
+ // https://github.com/vercel/next.js/issues/8592. As a workaround, we pass
9
+ // err via _app.js so it can be captured
10
+ Sentry.captureException(err);
11
+ // Flushing is not required in this case as it only happens on the client
12
+ }
13
+
14
+ return <NextErrorComponent statusCode={statusCode} />;
15
+ };
16
+
17
+ MyError.getInitialProps = async (context) => {
18
+ const errorInitialProps = await NextErrorComponent.getInitialProps(context);
19
+
20
+ const { res, err, asPath } = context;
21
+
22
+ // Workaround for https://github.com/vercel/next.js/issues/8592, mark when
23
+ // getInitialProps has run
24
+ errorInitialProps.hasGetInitialPropsRun = true;
25
+
26
+ // Returning early because we don't want to log 404 errors to Sentry.
27
+ if (res?.statusCode === 404) {
28
+ return errorInitialProps;
29
+ }
30
+
31
+ // Running on the server, the response object (`res`) is available.
32
+ //
33
+ // Next.js will pass an err on the server if a page's data fetching methods
34
+ // threw or returned a Promise that rejected
35
+ //
36
+ // Running on the client (browser), Next.js will provide an err if:
37
+ //
38
+ // - a page's `getInitialProps` threw or returned a Promise that rejected
39
+ // - an exception was thrown somewhere in the React lifecycle (render,
40
+ // componentDidMount, etc) that was caught by Next.js's React Error
41
+ // Boundary. Read more about what types of exceptions are caught by Error
42
+ // Boundaries: https://reactjs.org/docs/error-boundaries.html
43
+
44
+ if (err) {
45
+ Sentry.captureException(err);
46
+
47
+ // Flushing before returning is necessary if deploying to Vercel, see
48
+ // https://vercel.com/docs/platform/limits#streaming-responses
49
+ await Sentry.flush(2000);
50
+
51
+ return errorInitialProps;
52
+ }
53
+
54
+ // If this point is reached, getInitialProps was called without any
55
+ // information about what the error might be. This is unexpected and may
56
+ // indicate a bug introduced in Next.js, so record it in Sentry
57
+ Sentry.captureException(
58
+ new Error(`_error.js getInitialProps missing data at path: ${asPath}`),
59
+ );
60
+ await Sentry.flush(2000);
61
+
62
+ return errorInitialProps;
63
+ };
64
+
65
+ export default MyError;
@@ -9,7 +9,7 @@ const moduleExports = {
9
9
  // Your existing module.exports
10
10
  };
11
11
 
12
- const SentryWebpackPluginOptions = {
12
+ const sentryWebpackPluginOptions = {
13
13
  // Additional config options for the Sentry Webpack plugin. Keep in mind that
14
14
  // the following options are set automatically, and overriding them is not
15
15
  // recommended:
@@ -23,4 +23,4 @@ const SentryWebpackPluginOptions = {
23
23
 
24
24
  // Make sure adding Sentry options is the last code to run before exporting, to
25
25
  // ensure that your source maps include changes from all other Webpack plugins
26
- module.exports = withSentryConfig(moduleExports, SentryWebpackPluginOptions);
26
+ module.exports = withSentryConfig(moduleExports, sentryWebpackPluginOptions);
@@ -10,6 +10,7 @@ export declare class SentryCli {
10
10
  constructor(_argv: Args);
11
11
  setResolveFunction(resolve: (path: string) => string): void;
12
12
  convertAnswersToProperties(answers: Answers): SentryCliProps;
13
+ /** Create the contents of a `sentry.properties` file */
13
14
  dumpProperties(props: SentryCliProps): string;
14
15
  dumpConfig(config: SentryCliConfig): string;
15
16
  }
@@ -29,6 +29,7 @@ var SentryCli = /** @class */ (function () {
29
29
  }
30
30
  return props;
31
31
  };
32
+ /** Create the contents of a `sentry.properties` file */
32
33
  SentryCli.prototype.dumpProperties = function (props) {
33
34
  var rv = [];
34
35
  for (var key in props) {
@@ -37,6 +38,7 @@ var SentryCli = /** @class */ (function () {
37
38
  var value = props[key];
38
39
  key = key.replace(/\//g, '.');
39
40
  if (value === undefined || value === null) {
41
+ // comment that property out since it has no value
40
42
  rv.push("#" + key + "=");
41
43
  }
42
44
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"SentryCli.js","sourceRoot":"","sources":["../../../lib/Helper/SentryCli.ts"],"names":[],"mappings":";;;AACA,0BAA4B;AAC5B,2BAA6B;AAU7B;IAIE,mBAAsB,KAAW;QAAX,UAAK,GAAL,KAAK,CAAM;QAHjC,sDAAsD;QAC9C,aAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAEC,CAAC;IAE9B,sCAAkB,GAAzB,UAA0B,OAAiC;QACzD,IAAI,CAAC,QAAQ,GAAG,OAAc,CAAC;IACjC,CAAC;IAEM,8CAA0B,GAAjC,UAAkC,OAAgB;QAChD,IAAM,KAAK,GAAmB,EAAE,CAAC;QACjC,KAAK,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;QACvC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,0BAA0B,EAAE,IAAI,CAAC,CAAC;QACzE,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,qBAAqB,EAAE,IAAI,CAAC,CAAC;QACxE,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,mBAAmB,EAAE,IAAI,CAAC,CAAC;QAChE,IAAI;YACF,IAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;YAC5D,KAAK,CAAC,gBAAgB,CAAC,GAAG,IAAI;iBAC3B,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC;iBAChC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;SAC3B;QAAC,OAAO,CAAC,EAAE;YACV,6CAA6C;SAC9C;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAEM,kCAAc,GAArB,UAAsB,KAAqB;QACzC,IAAM,EAAE,GAAG,EAAE,CAAC;QACd,KAAK,IAAI,GAAG,IAAI,KAAK,EAAE;YACrB,iDAAiD;YACjD,IAAI,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE;gBAC7B,IAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;gBACzB,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBAC9B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE;oBACzC,EAAE,CAAC,IAAI,CAAC,MAAI,GAAG,MAAG,CAAC,CAAC;iBACrB;qBAAM;oBACL,EAAE,CAAC,IAAI,CAAI,GAAG,SAAI,KAAO,CAAC,CAAC;iBAC5B;aACF;SACF;QACD,2CAA2C;QAC3C,OAAO,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9B,CAAC;IAEM,8BAAU,GAAjB,UAAkB,MAAuB;QACvC,IAAM,cAAc,GAAa,EAAE,CAAC;QACpC,KAAK,IAAM,WAAW,IAAI,MAAM,EAAE;YAChC,iDAAiD;YACjD,IAAI,MAAM,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE;gBACtC,IAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;gBACvD,IAAM,OAAO,GAAG,MAAI,WAAW,WAAM,KAAO,CAAC;gBAC7C,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;aAC9B;SACF;QACD,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IACH,gBAAC;AAAD,CAAC,AAzDD,IAyDC;AAzDY,8BAAS","sourcesContent":["import { Answers } from 'inquirer';\nimport * as _ from 'lodash';\nimport * as path from 'path';\n\nimport { Args } from '../Constants';\n\nexport interface SentryCliProps {\n [s: string]: string;\n}\n\ntype SentryCliConfig = Record<string, SentryCliProps>;\n\nexport class SentryCli {\n // eslint-disable-next-line @typescript-eslint/typedef\n private _resolve = require.resolve;\n\n constructor(protected _argv: Args) {}\n\n public setResolveFunction(resolve: (path: string) => string): void {\n this._resolve = resolve as any;\n }\n\n public convertAnswersToProperties(answers: Answers): SentryCliProps {\n const props: SentryCliProps = {};\n props['defaults/url'] = this._argv.url;\n props['defaults/org'] = _.get(answers, 'config.organization.slug', null);\n props['defaults/project'] = _.get(answers, 'config.project.slug', null);\n props['auth/token'] = _.get(answers, 'config.auth.token', null);\n try {\n const cliPath = this._resolve('@sentry/cli/bin/sentry-cli');\n props['cli/executable'] = path\n .relative(process.cwd(), cliPath)\n .replace(/\\\\/g, '\\\\\\\\');\n } catch (e) {\n // we do nothing and leave everyting as it is\n }\n return props;\n }\n\n public dumpProperties(props: SentryCliProps): string {\n const rv = [];\n for (let key in props) {\n // eslint-disable-next-line no-prototype-builtins\n if (props.hasOwnProperty(key)) {\n const value = props[key];\n key = key.replace(/\\//g, '.');\n if (value === undefined || value === null) {\n rv.push(`#${key}=`);\n } else {\n rv.push(`${key}=${value}`);\n }\n }\n }\n // eslint-disable-next-line prefer-template\n return rv.join('\\n') + '\\n';\n }\n\n public dumpConfig(config: SentryCliConfig): string {\n const dumpedSections: string[] = [];\n for (const sectionName in config) {\n // eslint-disable-next-line no-prototype-builtins\n if (config.hasOwnProperty(sectionName)) {\n const props = this.dumpProperties(config[sectionName]);\n const section = `[${sectionName}]\\n${props}`;\n dumpedSections.push(section);\n }\n }\n return dumpedSections.join('\\n');\n }\n}\n"]}
1
+ {"version":3,"file":"SentryCli.js","sourceRoot":"","sources":["../../../lib/Helper/SentryCli.ts"],"names":[],"mappings":";;;AACA,0BAA4B;AAC5B,2BAA6B;AAU7B;IAIE,mBAAsB,KAAW;QAAX,UAAK,GAAL,KAAK,CAAM;QAHjC,sDAAsD;QAC9C,aAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAEC,CAAC;IAE9B,sCAAkB,GAAzB,UAA0B,OAAiC;QACzD,IAAI,CAAC,QAAQ,GAAG,OAAc,CAAC;IACjC,CAAC;IAEM,8CAA0B,GAAjC,UAAkC,OAAgB;QAChD,IAAM,KAAK,GAAmB,EAAE,CAAC;QACjC,KAAK,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;QACvC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,0BAA0B,EAAE,IAAI,CAAC,CAAC;QACzE,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,qBAAqB,EAAE,IAAI,CAAC,CAAC;QACxE,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,mBAAmB,EAAE,IAAI,CAAC,CAAC;QAChE,IAAI;YACF,IAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;YAC5D,KAAK,CAAC,gBAAgB,CAAC,GAAG,IAAI;iBAC3B,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC;iBAChC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;SAC3B;QAAC,OAAO,CAAC,EAAE;YACV,6CAA6C;SAC9C;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,wDAAwD;IACjD,kCAAc,GAArB,UAAsB,KAAqB;QACzC,IAAM,EAAE,GAAG,EAAE,CAAC;QACd,KAAK,IAAI,GAAG,IAAI,KAAK,EAAE;YACrB,iDAAiD;YACjD,IAAI,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE;gBAC7B,IAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;gBACzB,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBAC9B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE;oBACzC,kDAAkD;oBAClD,EAAE,CAAC,IAAI,CAAC,MAAI,GAAG,MAAG,CAAC,CAAC;iBACrB;qBAAM;oBACL,EAAE,CAAC,IAAI,CAAI,GAAG,SAAI,KAAO,CAAC,CAAC;iBAC5B;aACF;SACF;QACD,2CAA2C;QAC3C,OAAO,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9B,CAAC;IAEM,8BAAU,GAAjB,UAAkB,MAAuB;QACvC,IAAM,cAAc,GAAa,EAAE,CAAC;QACpC,KAAK,IAAM,WAAW,IAAI,MAAM,EAAE;YAChC,iDAAiD;YACjD,IAAI,MAAM,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE;gBACtC,IAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;gBACvD,IAAM,OAAO,GAAG,MAAI,WAAW,WAAM,KAAO,CAAC;gBAC7C,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;aAC9B;SACF;QACD,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IACH,gBAAC;AAAD,CAAC,AA3DD,IA2DC;AA3DY,8BAAS","sourcesContent":["import { Answers } from 'inquirer';\nimport * as _ from 'lodash';\nimport * as path from 'path';\n\nimport { Args } from '../Constants';\n\nexport interface SentryCliProps {\n [s: string]: string;\n}\n\ntype SentryCliConfig = Record<string, SentryCliProps>;\n\nexport class SentryCli {\n // eslint-disable-next-line @typescript-eslint/typedef\n private _resolve = require.resolve;\n\n constructor(protected _argv: Args) {}\n\n public setResolveFunction(resolve: (path: string) => string): void {\n this._resolve = resolve as any;\n }\n\n public convertAnswersToProperties(answers: Answers): SentryCliProps {\n const props: SentryCliProps = {};\n props['defaults/url'] = this._argv.url;\n props['defaults/org'] = _.get(answers, 'config.organization.slug', null);\n props['defaults/project'] = _.get(answers, 'config.project.slug', null);\n props['auth/token'] = _.get(answers, 'config.auth.token', null);\n try {\n const cliPath = this._resolve('@sentry/cli/bin/sentry-cli');\n props['cli/executable'] = path\n .relative(process.cwd(), cliPath)\n .replace(/\\\\/g, '\\\\\\\\');\n } catch (e) {\n // we do nothing and leave everyting as it is\n }\n return props;\n }\n\n /** Create the contents of a `sentry.properties` file */\n public dumpProperties(props: SentryCliProps): string {\n const rv = [];\n for (let key in props) {\n // eslint-disable-next-line no-prototype-builtins\n if (props.hasOwnProperty(key)) {\n const value = props[key];\n key = key.replace(/\\//g, '.');\n if (value === undefined || value === null) {\n // comment that property out since it has no value\n rv.push(`#${key}=`);\n } else {\n rv.push(`${key}=${value}`);\n }\n }\n }\n // eslint-disable-next-line prefer-template\n return rv.join('\\n') + '\\n';\n }\n\n public dumpConfig(config: SentryCliConfig): string {\n const dumpedSections: string[] = [];\n for (const sectionName in config) {\n // eslint-disable-next-line no-prototype-builtins\n if (config.hasOwnProperty(sectionName)) {\n const props = this.dumpProperties(config[sectionName]);\n const section = `[${sectionName}]\\n${props}`;\n dumpedSections.push(section);\n }\n }\n return dumpedSections.join('\\n');\n }\n}\n"]}
@@ -10,7 +10,7 @@ export declare abstract class BaseIntegration extends BaseStep {
10
10
  /**
11
11
  * This can be used for example for platform:boolean to determine
12
12
  * if we should configure iOS/Android.
13
- * Basically this will be merged into answers so it can be check by a later step.
13
+ * Basically this will be merged into answers so it can be checked by a later step.
14
14
  */
15
15
  shouldConfigure(_answers: Answers): Promise<Answers>;
16
16
  shouldEmit(_answers: Answers): Promise<boolean>;
@@ -71,7 +71,7 @@ var BaseIntegration = /** @class */ (function (_super) {
71
71
  /**
72
72
  * This can be used for example for platform:boolean to determine
73
73
  * if we should configure iOS/Android.
74
- * Basically this will be merged into answers so it can be check by a later step.
74
+ * Basically this will be merged into answers so it can be checked by a later step.
75
75
  */
76
76
  BaseIntegration.prototype.shouldConfigure = function (_answers) {
77
77
  return __awaiter(this, void 0, void 0, function () {
@@ -93,7 +93,8 @@ var BaseIntegration = /** @class */ (function (_super) {
93
93
  _b = (_a = _).keys;
94
94
  _d = (_c = _).pickBy;
95
95
  return [4 /*yield*/, this.shouldConfigure(_answers)];
96
- case 1: return [2 /*return*/, (_b.apply(_a, [_d.apply(_c, [_e.sent(), function (active) { return active; }])]).length > 0)];
96
+ case 1: return [2 /*return*/, (_b.apply(_a, [_d.apply(_c, [_e.sent(),
97
+ function (active) { return active; }])]).length > 0)];
97
98
  }
98
99
  });
99
100
  });
@@ -1 +1 @@
1
- {"version":3,"file":"BaseIntegration.js","sourceRoot":"","sources":["../../../../lib/Steps/Integrations/BaseIntegration.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,0BAA4B;AAG5B,wCAAuC;AAEvC;IAA8C,mCAAQ;IAIpD,yBAAsB,KAAW;QAAjC,YACE,kBAAM,KAAK,CAAC,SAGb;QAJqB,WAAK,GAAL,KAAK,CAAM;QAE/B,kEAAkE;QAClE,KAAI,CAAC,IAAI,GAAG,KAAI,CAAC,SAAS,CAAC;;IAC7B,CAAC;IAEY,mCAAS,GAAtB,UAAuB,QAAiB;;;gBACtC,sBAAO,EAAE,EAAC;;;KACX;IAED;;;;OAIG;IACU,yCAAe,GAA5B,UAA6B,QAAiB;;;gBAC5C,IAAI,IAAI,CAAC,gBAAgB,EAAE;oBACzB,sBAAO,IAAI,CAAC,gBAAgB,EAAC;iBAC9B;gBACD,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC5D,sBAAO,IAAI,CAAC,gBAAgB,EAAC;;;KAC9B;IAEY,oCAAU,GAAvB,UAAwB,QAAiB;;;;;;wBAErC,KAAA,CAAA,KAAA,CAAC,CAAA,CAAC,IAAI,CAAA;wBACJ,KAAA,CAAA,KAAA,CAAC,CAAA,CAAC,MAAM,CAAA;wBAAC,qBAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAA;4BAFjD,sBAAO,CACL,cACE,cAAS,SAAoC,EAAE,UAAC,MAAe,IAAK,OAAA,MAAM,EAAN,CAAM,EAAC,EAC5E,CAAC,MAAM,GAAG,CAAC,CACb,EAAC;;;;KACH;IAGH,sBAAC;AAAD,CAAC,AApCD,CAA8C,mBAAQ,GAoCrD;AApCqB,0CAAe","sourcesContent":["import { Answers } from 'inquirer';\nimport * as _ from 'lodash';\n\nimport { Args } from '../../Constants';\nimport { BaseStep } from '../BaseStep';\n\nexport abstract class BaseIntegration extends BaseStep {\n public type: string;\n protected _shouldConfigure: Promise<Answers>;\n\n constructor(protected _argv: Args) {\n super(_argv);\n // @ts-ignore property construct does not exist on BaseIntegration\n this.type = this.construct;\n }\n\n public async uninstall(_answers: Answers): Promise<Answers> {\n return {};\n }\n\n /**\n * This can be used for example for platform:boolean to determine\n * if we should configure iOS/Android.\n * Basically this will be merged into answers so it can be check by a later step.\n */\n public async shouldConfigure(_answers: Answers): Promise<Answers> {\n if (this._shouldConfigure) {\n return this._shouldConfigure;\n }\n this._shouldConfigure = Promise.resolve({ platform: true });\n return this._shouldConfigure;\n }\n\n public async shouldEmit(_answers: Answers): Promise<boolean> {\n return (\n _.keys(\n _.pickBy(await this.shouldConfigure(_answers), (active: boolean) => active),\n ).length > 0\n );\n }\n\n public abstract emit(answers: Answers): Promise<Answers>;\n}\n"]}
1
+ {"version":3,"file":"BaseIntegration.js","sourceRoot":"","sources":["../../../../lib/Steps/Integrations/BaseIntegration.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,0BAA4B;AAG5B,wCAAuC;AAEvC;IAA8C,mCAAQ;IAIpD,yBAAsB,KAAW;QAAjC,YACE,kBAAM,KAAK,CAAC,SAGb;QAJqB,WAAK,GAAL,KAAK,CAAM;QAE/B,kEAAkE;QAClE,KAAI,CAAC,IAAI,GAAG,KAAI,CAAC,SAAS,CAAC;;IAC7B,CAAC;IAEY,mCAAS,GAAtB,UAAuB,QAAiB;;;gBACtC,sBAAO,EAAE,EAAC;;;KACX;IAED;;;;OAIG;IACU,yCAAe,GAA5B,UAA6B,QAAiB;;;gBAC5C,IAAI,IAAI,CAAC,gBAAgB,EAAE;oBACzB,sBAAO,IAAI,CAAC,gBAAgB,EAAC;iBAC9B;gBACD,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC5D,sBAAO,IAAI,CAAC,gBAAgB,EAAC;;;KAC9B;IAEY,oCAAU,GAAvB,UAAwB,QAAiB;;;;;;wBAErC,KAAA,CAAA,KAAA,CAAC,CAAA,CAAC,IAAI,CAAA;wBACJ,KAAA,CAAA,KAAA,CAAC,CAAA,CAAC,MAAM,CAAA;wBACN,qBAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAA;4BAH1C,sBAAO,CACL,cACE,cACE,SAAoC;gCACpC,UAAC,MAAe,IAAK,OAAA,MAAM,EAAN,CAAM,EAC5B,EACF,CAAC,MAAM,GAAG,CAAC,CACb,EAAC;;;;KACH;IAGH,sBAAC;AAAD,CAAC,AAvCD,CAA8C,mBAAQ,GAuCrD;AAvCqB,0CAAe","sourcesContent":["import { Answers } from 'inquirer';\nimport * as _ from 'lodash';\n\nimport { Args } from '../../Constants';\nimport { BaseStep } from '../BaseStep';\n\nexport abstract class BaseIntegration extends BaseStep {\n public type: string;\n protected _shouldConfigure: Promise<Answers>;\n\n constructor(protected _argv: Args) {\n super(_argv);\n // @ts-ignore property construct does not exist on BaseIntegration\n this.type = this.construct;\n }\n\n public async uninstall(_answers: Answers): Promise<Answers> {\n return {};\n }\n\n /**\n * This can be used for example for platform:boolean to determine\n * if we should configure iOS/Android.\n * Basically this will be merged into answers so it can be checked by a later step.\n */\n public async shouldConfigure(_answers: Answers): Promise<Answers> {\n if (this._shouldConfigure) {\n return this._shouldConfigure;\n }\n this._shouldConfigure = Promise.resolve({ platform: true });\n return this._shouldConfigure;\n }\n\n public async shouldEmit(_answers: Answers): Promise<boolean> {\n return (\n _.keys(\n _.pickBy(\n await this.shouldConfigure(_answers),\n (active: boolean) => active,\n ),\n ).length > 0\n );\n }\n\n public abstract emit(answers: Answers): Promise<Answers>;\n}\n"]}
@@ -13,6 +13,7 @@ export declare class NextJs extends BaseIntegration {
13
13
  private _createNextConfig;
14
14
  private _setTemplate;
15
15
  private _fillAndCopyTemplate;
16
- private _checkDep;
17
- private _fulfillsMinVersion;
16
+ private _checkUserNextVersion;
17
+ private _fulfillsVersionRange;
18
+ private _spliceInPlace;
18
19
  }
@@ -59,8 +59,16 @@ var __rest = (this && this.__rest) || function (s, e) {
59
59
  }
60
60
  return t;
61
61
  };
62
+ var __spreadArrays = (this && this.__spreadArrays) || function () {
63
+ for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
64
+ for (var r = Array(s), k = 0, i = 0; i < il; i++)
65
+ for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
66
+ r[k] = a[j];
67
+ return r;
68
+ };
62
69
  Object.defineProperty(exports, "__esModule", { value: true });
63
70
  exports.NextJs = void 0;
71
+ /* eslint-disable max-lines */
64
72
  var fs = require("fs");
65
73
  var inquirer_1 = require("inquirer");
66
74
  var _ = require("lodash");
@@ -69,12 +77,20 @@ var semver_1 = require("semver");
69
77
  var Logging_1 = require("../../Helper/Logging");
70
78
  var SentryCli_1 = require("../../Helper/SentryCli");
71
79
  var BaseIntegration_1 = require("./BaseIntegration");
72
- var MIN_NEXTJS_VERSION = '10.0.8'; // Must be a fixed version: `X.Y.Z`
80
+ var COMPATIBLE_NEXTJS_VERSIONS = '>=10.0.8 <13.0.0';
73
81
  var PROPERTIES_FILENAME = 'sentry.properties';
74
82
  var SENTRYCLIRC_FILENAME = '.sentryclirc';
75
83
  var GITIGNORE_FILENAME = '.gitignore';
76
84
  var CONFIG_DIR = 'configs/';
77
- var MERGEABLE_CONFIG_PREFIX = '_';
85
+ var MERGEABLE_CONFIG_INFIX = 'wizardcopy';
86
+ // for those files which can go in more than one place, the list of places they
87
+ // could go (the first one which works will be used)
88
+ var TEMPLATE_DESTINATIONS = {
89
+ '_error.js': ['pages', 'src/pages'],
90
+ 'next.config.js': ['.'],
91
+ 'sentry.server.config.js': ['.'],
92
+ 'sentry.client.config.js': ['.'],
93
+ };
78
94
  var appPackage = {};
79
95
  try {
80
96
  appPackage = require(path.join(process.cwd(), 'package.json'));
@@ -107,7 +123,7 @@ var NextJs = /** @class */ (function (_super) {
107
123
  this._createNextConfig(configDirectory, dsn);
108
124
  }
109
125
  else {
110
- Logging_1.debug("Couldn't find " + configDirectory + ", probably because you run from src");
126
+ Logging_1.debug("Couldn't find " + configDirectory + ", probably because you ran this from inside of `/lib` rather than `/dist`");
111
127
  Logging_1.nl();
112
128
  }
113
129
  Logging_1.l('For more information, see https://docs.sentry.io/platforms/javascript/guides/nextjs/');
@@ -128,7 +144,7 @@ var NextJs = /** @class */ (function (_super) {
128
144
  }
129
145
  Logging_1.nl();
130
146
  userAnswers = { continue: true };
131
- if (!(!this._checkDep('next', true) && !this._argv.quiet)) return [3 /*break*/, 2];
147
+ if (!(!this._checkUserNextVersion('next') && !this._argv.quiet)) return [3 /*break*/, 2];
132
148
  return [4 /*yield*/, inquirer_1.prompt({
133
149
  message: 'There were errors during your project checkup, do you still want to continue?',
134
150
  name: 'continue',
@@ -228,78 +244,92 @@ var NextJs = /** @class */ (function (_super) {
228
244
  var templates = fs.readdirSync(configDirectory);
229
245
  for (var _i = 0, templates_1 = templates; _i < templates_1.length; _i++) {
230
246
  var template = templates_1[_i];
231
- this._setTemplate(configDirectory, template, dsn);
247
+ this._setTemplate(configDirectory, template, TEMPLATE_DESTINATIONS[template], dsn);
232
248
  }
233
249
  Logging_1.red('⚠ Performance monitoring is enabled capturing 100% of transactions.\n' +
234
250
  ' Learn more in https://docs.sentry.io/product/performance/');
235
251
  Logging_1.nl();
236
252
  };
237
- NextJs.prototype._setTemplate = function (configDirectory, template, dsn) {
238
- var templatePath = path.join(configDirectory, template);
239
- var mergeableFile = MERGEABLE_CONFIG_PREFIX + template;
240
- if (!fs.existsSync(template)) {
241
- this._fillAndCopyTemplate(templatePath, template, dsn);
242
- }
243
- else if (!fs.existsSync(mergeableFile)) {
244
- this._fillAndCopyTemplate(templatePath, mergeableFile, dsn);
245
- Logging_1.red("File " + template + " already exists, so created " + mergeableFile + ".\n" +
246
- "Please, merge those files.");
247
- Logging_1.nl();
248
- }
249
- else {
250
- Logging_1.red("File " + template + " already exists, and " + mergeableFile + " also exists.\n" +
251
- 'Please, merge those files.');
252
- Logging_1.nl();
253
+ NextJs.prototype._setTemplate = function (configDirectory, templateFile, destinationOptions, dsn) {
254
+ var templatePath = path.join(configDirectory, templateFile);
255
+ for (var _i = 0, destinationOptions_1 = destinationOptions; _i < destinationOptions_1.length; _i++) {
256
+ var destinationDir = destinationOptions_1[_i];
257
+ if (!fs.existsSync(destinationDir)) {
258
+ continue;
259
+ }
260
+ var destinationPath = path.join(destinationDir, templateFile);
261
+ // in case the file in question already exists, we'll make a copy with
262
+ // `MERGEABLE_CONFIG_INFIX` inserted just before the extension, so as not
263
+ // to overwrite the existing file
264
+ var mergeableFilePath = path.join(destinationDir, this._spliceInPlace(templateFile.split('.'), -1, 0, MERGEABLE_CONFIG_INFIX).join('.'));
265
+ if (!fs.existsSync(destinationPath)) {
266
+ this._fillAndCopyTemplate(templatePath, destinationPath, dsn);
267
+ }
268
+ else if (!fs.existsSync(mergeableFilePath)) {
269
+ this._fillAndCopyTemplate(templatePath, mergeableFilePath, dsn);
270
+ Logging_1.red("File `" + templateFile + "` already exists, so created `" + mergeableFilePath + "`.\n" +
271
+ 'Please merge those files.');
272
+ Logging_1.nl();
273
+ }
274
+ else {
275
+ Logging_1.red("Both `" + templateFile + "` and `" + mergeableFilePath + "` already exist.\n" +
276
+ 'Please merge those files.');
277
+ Logging_1.nl();
278
+ }
279
+ return;
253
280
  }
281
+ Logging_1.red("Could not find appropriate destination for `" + templateFile + "`. Tried: " + destinationOptions + ".");
282
+ Logging_1.nl();
254
283
  };
255
284
  NextJs.prototype._fillAndCopyTemplate = function (sourcePath, targetPath, dsn) {
256
285
  var templateContent = fs.readFileSync(sourcePath).toString();
257
286
  var filledTemplate = templateContent.replace('___DSN___', dsn);
258
287
  fs.writeFileSync(targetPath, filledTemplate);
259
288
  };
260
- NextJs.prototype._checkDep = function (packageName, minVersion) {
261
- var depVersion = _.get(appPackage, ['dependencies', packageName], '0.0.0');
262
- var devDepVersion = _.get(appPackage, ['devDependencies', packageName], '0.0.0');
263
- if (!_.get(appPackage, "dependencies." + packageName, false) &&
264
- !_.get(appPackage, "devDependencies." + packageName, false)) {
265
- Logging_1.red("\u2717 " + packageName + " isn't in your dependencies");
266
- Logging_1.red(" please install it with yarn/npm");
289
+ NextJs.prototype._checkUserNextVersion = function (packageName) {
290
+ var depsVersion = _.get(appPackage, ['dependencies', packageName]);
291
+ var devDepsVersion = _.get(appPackage, ['devDependencies', packageName]);
292
+ if (!depsVersion && !devDepsVersion) {
293
+ Logging_1.red("\u2717 " + packageName + " isn't in your dependencies.");
294
+ Logging_1.red(' Please install it with yarn/npm.');
267
295
  return false;
268
296
  }
269
- else if (!this._fulfillsMinVersion(depVersion) &&
270
- !this._fulfillsMinVersion(devDepVersion)) {
271
- Logging_1.red("\u2717 Your installed version of `" + packageName + "` is not supported, >=" + MIN_NEXTJS_VERSION + " needed.");
297
+ else if (!this._fulfillsVersionRange(depsVersion) &&
298
+ !this._fulfillsVersionRange(devDepsVersion)) {
299
+ Logging_1.red("\u2717 Your `package.json` specifies a version of `" + packageName + "` outside of the compatible version range " + COMPATIBLE_NEXTJS_VERSIONS + ".\n");
272
300
  return false;
273
301
  }
274
302
  else {
275
- if (minVersion) {
276
- Logging_1.green("\u2713 " + packageName + " >= " + MIN_NEXTJS_VERSION + " is installed");
277
- }
278
- else {
279
- Logging_1.green("\u2713 " + packageName + " is installed");
280
- }
303
+ Logging_1.green("\u2713 A compatible version of `" + packageName + "` is specified in `package.json`.");
281
304
  return true;
282
305
  }
283
306
  };
284
- NextJs.prototype._fulfillsMinVersion = function (version) {
285
- // The latest version, which at the moment is greater than the minimum
286
- // version, shouldn't be a blocker in the wizard.
307
+ NextJs.prototype._fulfillsVersionRange = function (version) {
308
+ // The latest version is currently 12.x, which is not yet supported.
287
309
  if (version === 'latest') {
288
- return true;
310
+ return false;
289
311
  }
290
- var cleanedVersion = semver_1.clean(version);
291
- if (cleanedVersion) {
292
- // gte(x, y) : true if x >= y
293
- return semver_1.gte(cleanedVersion, MIN_NEXTJS_VERSION);
312
+ var cleanedUserVersion, isRange;
313
+ if (semver_1.valid(version)) {
314
+ cleanedUserVersion = semver_1.valid(version);
315
+ isRange = false;
294
316
  }
295
- var minVersionRange = ">=" + MIN_NEXTJS_VERSION;
296
- var userVersionRange = semver_1.validRange(version);
297
- var minUserVersion = semver_1.minVersion(userVersionRange);
298
- if (minUserVersion == null) {
299
- // This should never happen
300
- return false;
317
+ else if (semver_1.validRange(version)) {
318
+ cleanedUserVersion = semver_1.validRange(version);
319
+ isRange = true;
320
+ }
321
+ return (!!cleanedUserVersion &&
322
+ (isRange
323
+ ? semver_1.subset(cleanedUserVersion, COMPATIBLE_NEXTJS_VERSIONS)
324
+ : semver_1.satisfies(cleanedUserVersion, COMPATIBLE_NEXTJS_VERSIONS)));
325
+ };
326
+ NextJs.prototype._spliceInPlace = function (arr, start, deleteCount) {
327
+ var inserts = [];
328
+ for (var _i = 3; _i < arguments.length; _i++) {
329
+ inserts[_i - 3] = arguments[_i];
301
330
  }
302
- return semver_1.satisfies(minUserVersion, minVersionRange);
331
+ arr.splice.apply(arr, __spreadArrays([start, deleteCount], inserts));
332
+ return arr;
303
333
  };
304
334
  return NextJs;
305
335
  }(BaseIntegration_1.BaseIntegration));
@@ -1 +1 @@
1
- {"version":3,"file":"NextJs.js","sourceRoot":"","sources":["../../../../lib/Steps/Integrations/NextJs.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport { Answers, prompt } from 'inquirer';\nimport * as _ from 'lodash';\nimport * as path from 'path';\nimport { clean, gte, minVersion, satisfies, validRange } from 'semver';\n\nimport { Args } from '../../Constants';\nimport { debug, green, l, nl, red } from '../../Helper/Logging';\nimport { SentryCli, SentryCliProps } from '../../Helper/SentryCli';\nimport { BaseIntegration } from './BaseIntegration';\n\nconst MIN_NEXTJS_VERSION = '10.0.8'; // Must be a fixed version: `X.Y.Z`\nconst PROPERTIES_FILENAME = 'sentry.properties';\nconst SENTRYCLIRC_FILENAME = '.sentryclirc';\nconst GITIGNORE_FILENAME = '.gitignore';\nconst CONFIG_DIR = 'configs/';\nconst MERGEABLE_CONFIG_PREFIX = '_';\n\nlet appPackage: any = {};\n\ntry {\n appPackage = require(path.join(process.cwd(), 'package.json'));\n} catch {\n // We don't need to have this\n}\n\nexport class NextJs extends BaseIntegration {\n protected _sentryCli: SentryCli;\n\n constructor(protected _argv: Args) {\n super(_argv);\n this._sentryCli = new SentryCli(this._argv);\n }\n\n public async emit(answers: Answers): Promise<Answers> {\n const dsn = _.get(answers, ['config', 'dsn', 'public'], null);\n nl();\n\n const sentryCliProps = this._sentryCli.convertAnswersToProperties(answers);\n await this._createSentryCliConfig(sentryCliProps);\n\n const configDirectory = path.join(\n __dirname,\n '..',\n '..',\n '..',\n 'NextJs',\n CONFIG_DIR,\n );\n\n if (fs.existsSync(configDirectory)) {\n this._createNextConfig(configDirectory, dsn);\n } else {\n debug(\n `Couldn't find ${configDirectory}, probably because you run from src`,\n );\n nl();\n }\n\n l(\n 'For more information, see https://docs.sentry.io/platforms/javascript/guides/nextjs/',\n );\n nl();\n\n return {};\n }\n\n public async shouldConfigure(_answers: Answers): Promise<Answers> {\n if (this._shouldConfigure) {\n return this._shouldConfigure;\n }\n\n nl();\n\n let userAnswers: Answers = { continue: true };\n if (!this._checkDep('next', true) && !this._argv.quiet) {\n userAnswers = await prompt({\n message:\n 'There were errors during your project checkup, do you still want to continue?',\n name: 'continue',\n default: false,\n type: 'confirm',\n });\n }\n\n nl();\n\n if (!userAnswers['continue']) {\n throw new Error('Please install the required dependencies to continue.');\n }\n\n this._shouldConfigure = Promise.resolve({ nextjs: true });\n // eslint-disable-next-line @typescript-eslint/unbound-method\n return this.shouldConfigure;\n }\n\n private async _createSentryCliConfig(\n cliProps: SentryCliProps,\n ): Promise<void> {\n const { 'auth/token': authToken, ...cliPropsToWrite } = cliProps;\n\n /**\n * To not commit the auth token to the VCS, instead of adding it to the\n * properties file (like the rest of props), it's added to the Sentry CLI\n * config, which is added to the gitignore. This way makes the properties\n * file safe to commit without exposing any auth tokens.\n */\n if (authToken) {\n try {\n await fs.promises.appendFile(\n SENTRYCLIRC_FILENAME,\n this._sentryCli.dumpConfig({ auth: { token: authToken } }),\n );\n green(`✓ Successfully added the auth token to ${SENTRYCLIRC_FILENAME}`);\n } catch {\n red(\n `⚠ Could not add the auth token to ${SENTRYCLIRC_FILENAME}, ` +\n `please add it to identify your user account:\\n${authToken}`,\n );\n nl();\n }\n } else {\n red(\n `⚠ Did not find an auth token, please add your token to ${SENTRYCLIRC_FILENAME}`,\n );\n l(\n 'To generate an auth token, visit https://sentry.io/settings/account/api/auth-tokens/',\n );\n l(\n 'To learn how to configure Sentry CLI, visit ' +\n 'https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#configure-sentry-cli',\n );\n }\n\n await this._addToGitignore(\n SENTRYCLIRC_FILENAME,\n `⚠ Could not add ${SENTRYCLIRC_FILENAME} to ${GITIGNORE_FILENAME}, ` +\n 'please add it to not commit your auth key.',\n );\n\n try {\n await fs.promises.writeFile(\n `./${PROPERTIES_FILENAME}`,\n this._sentryCli.dumpProperties(cliPropsToWrite),\n );\n green(`✓ Successfully created sentry.properties`);\n } catch {\n red(`⚠ Could not add org and project data to ${PROPERTIES_FILENAME}`);\n l(\n 'See docs for a manual setup: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#configure-sentry-cli',\n );\n }\n nl();\n }\n\n private async _addToGitignore(\n filepath: string,\n errorMsg: string,\n ): Promise<void> {\n /**\n * Don't check whether the given file is ignored because:\n * 1. It's tricky to check it without git.\n * 2. Git might not be installed or accessible.\n * 3. It's convenient to use a module to interact with git, but it would\n * increase the size x2 approximately. Docs say to run the Wizard without\n * installing it, and duplicating the size would slow the set-up down.\n * 4. The Wizard is meant to be run once.\n * 5. A message is logged informing users it's been added to the gitignore.\n * 6. It will be added to the gitignore as many times as it runs - not a big\n * deal.\n * 7. It's straightforward to remove it from the gitignore.\n */\n try {\n await fs.promises.appendFile(\n GITIGNORE_FILENAME,\n `\\n# Sentry\\n${filepath}\\n`,\n );\n green(`✓ ${filepath} added to ${GITIGNORE_FILENAME}`);\n } catch {\n red(errorMsg);\n }\n }\n\n private _createNextConfig(configDirectory: string, dsn: any): void {\n const templates = fs.readdirSync(configDirectory);\n for (const template of templates) {\n this._setTemplate(configDirectory, template, dsn);\n }\n red(\n '⚠ Performance monitoring is enabled capturing 100% of transactions.\\n' +\n ' Learn more in https://docs.sentry.io/product/performance/',\n );\n nl();\n }\n\n private _setTemplate(\n configDirectory: string,\n template: string,\n dsn: string,\n ): void {\n const templatePath = path.join(configDirectory, template);\n const mergeableFile = MERGEABLE_CONFIG_PREFIX + template;\n if (!fs.existsSync(template)) {\n this._fillAndCopyTemplate(templatePath, template, dsn);\n } else if (!fs.existsSync(mergeableFile)) {\n this._fillAndCopyTemplate(templatePath, mergeableFile, dsn);\n red(\n `File ${template} already exists, so created ${mergeableFile}.\\n` +\n `Please, merge those files.`,\n );\n nl();\n } else {\n red(\n `File ${template} already exists, and ${mergeableFile} also exists.\\n` +\n 'Please, merge those files.',\n );\n nl();\n }\n }\n\n private _fillAndCopyTemplate(\n sourcePath: string,\n targetPath: string,\n dsn: string,\n ): void {\n const templateContent = fs.readFileSync(sourcePath).toString();\n const filledTemplate = templateContent.replace('___DSN___', dsn);\n fs.writeFileSync(targetPath, filledTemplate);\n }\n\n private _checkDep(packageName: string, minVersion?: boolean): boolean {\n const depVersion = _.get(\n appPackage,\n ['dependencies', packageName],\n '0.0.0',\n );\n const devDepVersion = _.get(\n appPackage,\n ['devDependencies', packageName],\n '0.0.0',\n );\n\n if (\n !_.get(appPackage, `dependencies.${packageName}`, false) &&\n !_.get(appPackage, `devDependencies.${packageName}`, false)\n ) {\n red(`✗ ${packageName} isn't in your dependencies`);\n red(` please install it with yarn/npm`);\n return false;\n } else if (\n !this._fulfillsMinVersion(depVersion) &&\n !this._fulfillsMinVersion(devDepVersion)\n ) {\n red(\n `✗ Your installed version of \\`${packageName}\\` is not supported, >=${MIN_NEXTJS_VERSION} needed.`,\n );\n return false;\n } else {\n if (minVersion) {\n green(`✓ ${packageName} >= ${MIN_NEXTJS_VERSION} is installed`);\n } else {\n green(`✓ ${packageName} is installed`);\n }\n return true;\n }\n }\n\n private _fulfillsMinVersion(version: string): boolean {\n // The latest version, which at the moment is greater than the minimum\n // version, shouldn't be a blocker in the wizard.\n if (version === 'latest') {\n return true;\n }\n\n const cleanedVersion = clean(version);\n if (cleanedVersion) {\n // gte(x, y) : true if x >= y\n return gte(cleanedVersion, MIN_NEXTJS_VERSION);\n }\n\n const minVersionRange = `>=${MIN_NEXTJS_VERSION}`;\n const userVersionRange = validRange(version);\n const minUserVersion = minVersion(userVersionRange);\n if (minUserVersion == null) {\n // This should never happen\n return false;\n }\n return satisfies(minUserVersion, minVersionRange);\n }\n}\n"]}
1
+ {"version":3,"file":"NextJs.js","sourceRoot":"","sources":["../../../../lib/Steps/Integrations/NextJs.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable max-lines */\nimport * as fs from 'fs';\nimport { Answers, prompt } from 'inquirer';\nimport * as _ from 'lodash';\nimport * as path from 'path';\nimport { satisfies, subset, valid, validRange } from 'semver';\n\nimport { Args } from '../../Constants';\nimport { debug, green, l, nl, red } from '../../Helper/Logging';\nimport { SentryCli, SentryCliProps } from '../../Helper/SentryCli';\nimport { BaseIntegration } from './BaseIntegration';\n\nconst COMPATIBLE_NEXTJS_VERSIONS = '>=10.0.8 <13.0.0';\nconst PROPERTIES_FILENAME = 'sentry.properties';\nconst SENTRYCLIRC_FILENAME = '.sentryclirc';\nconst GITIGNORE_FILENAME = '.gitignore';\nconst CONFIG_DIR = 'configs/';\nconst MERGEABLE_CONFIG_INFIX = 'wizardcopy';\n\n// for those files which can go in more than one place, the list of places they\n// could go (the first one which works will be used)\nconst TEMPLATE_DESTINATIONS: { [key: string]: string[] } = {\n '_error.js': ['pages', 'src/pages'],\n 'next.config.js': ['.'],\n 'sentry.server.config.js': ['.'],\n 'sentry.client.config.js': ['.'],\n};\n\nlet appPackage: any = {};\n\ntry {\n appPackage = require(path.join(process.cwd(), 'package.json'));\n} catch {\n // We don't need to have this\n}\n\nexport class NextJs extends BaseIntegration {\n protected _sentryCli: SentryCli;\n\n constructor(protected _argv: Args) {\n super(_argv);\n this._sentryCli = new SentryCli(this._argv);\n }\n\n public async emit(answers: Answers): Promise<Answers> {\n const dsn = _.get(answers, ['config', 'dsn', 'public'], null);\n nl();\n\n const sentryCliProps = this._sentryCli.convertAnswersToProperties(answers);\n await this._createSentryCliConfig(sentryCliProps);\n\n const configDirectory = path.join(\n __dirname,\n '..',\n '..',\n '..',\n 'NextJs',\n CONFIG_DIR,\n );\n\n if (fs.existsSync(configDirectory)) {\n this._createNextConfig(configDirectory, dsn);\n } else {\n debug(\n `Couldn't find ${configDirectory}, probably because you ran this from inside of \\`/lib\\` rather than \\`/dist\\``,\n );\n nl();\n }\n\n l(\n 'For more information, see https://docs.sentry.io/platforms/javascript/guides/nextjs/',\n );\n nl();\n\n return {};\n }\n\n public async shouldConfigure(_answers: Answers): Promise<Answers> {\n if (this._shouldConfigure) {\n return this._shouldConfigure;\n }\n\n nl();\n\n let userAnswers: Answers = { continue: true };\n if (!this._checkUserNextVersion('next') && !this._argv.quiet) {\n userAnswers = await prompt({\n message:\n 'There were errors during your project checkup, do you still want to continue?',\n name: 'continue',\n default: false,\n type: 'confirm',\n });\n }\n\n nl();\n\n if (!userAnswers['continue']) {\n throw new Error('Please install the required dependencies to continue.');\n }\n\n this._shouldConfigure = Promise.resolve({ nextjs: true });\n // eslint-disable-next-line @typescript-eslint/unbound-method\n return this.shouldConfigure;\n }\n\n private async _createSentryCliConfig(\n cliProps: SentryCliProps,\n ): Promise<void> {\n const { 'auth/token': authToken, ...cliPropsToWrite } = cliProps;\n\n /**\n * To not commit the auth token to the VCS, instead of adding it to the\n * properties file (like the rest of props), it's added to the Sentry CLI\n * config, which is added to the gitignore. This way makes the properties\n * file safe to commit without exposing any auth tokens.\n */\n if (authToken) {\n try {\n await fs.promises.appendFile(\n SENTRYCLIRC_FILENAME,\n this._sentryCli.dumpConfig({ auth: { token: authToken } }),\n );\n green(`✓ Successfully added the auth token to ${SENTRYCLIRC_FILENAME}`);\n } catch {\n red(\n `⚠ Could not add the auth token to ${SENTRYCLIRC_FILENAME}, ` +\n `please add it to identify your user account:\\n${authToken}`,\n );\n nl();\n }\n } else {\n red(\n `⚠ Did not find an auth token, please add your token to ${SENTRYCLIRC_FILENAME}`,\n );\n l(\n 'To generate an auth token, visit https://sentry.io/settings/account/api/auth-tokens/',\n );\n l(\n 'To learn how to configure Sentry CLI, visit ' +\n 'https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#configure-sentry-cli',\n );\n }\n\n await this._addToGitignore(\n SENTRYCLIRC_FILENAME,\n `⚠ Could not add ${SENTRYCLIRC_FILENAME} to ${GITIGNORE_FILENAME}, ` +\n 'please add it to not commit your auth key.',\n );\n\n try {\n await fs.promises.writeFile(\n `./${PROPERTIES_FILENAME}`,\n this._sentryCli.dumpProperties(cliPropsToWrite),\n );\n green(`✓ Successfully created sentry.properties`);\n } catch {\n red(`⚠ Could not add org and project data to ${PROPERTIES_FILENAME}`);\n l(\n 'See docs for a manual setup: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#configure-sentry-cli',\n );\n }\n nl();\n }\n\n private async _addToGitignore(\n filepath: string,\n errorMsg: string,\n ): Promise<void> {\n /**\n * Don't check whether the given file is ignored because:\n * 1. It's tricky to check it without git.\n * 2. Git might not be installed or accessible.\n * 3. It's convenient to use a module to interact with git, but it would\n * increase the size x2 approximately. Docs say to run the Wizard without\n * installing it, and duplicating the size would slow the set-up down.\n * 4. The Wizard is meant to be run once.\n * 5. A message is logged informing users it's been added to the gitignore.\n * 6. It will be added to the gitignore as many times as it runs - not a big\n * deal.\n * 7. It's straightforward to remove it from the gitignore.\n */\n try {\n await fs.promises.appendFile(\n GITIGNORE_FILENAME,\n `\\n# Sentry\\n${filepath}\\n`,\n );\n green(`✓ ${filepath} added to ${GITIGNORE_FILENAME}`);\n } catch {\n red(errorMsg);\n }\n }\n\n private _createNextConfig(configDirectory: string, dsn: any): void {\n const templates = fs.readdirSync(configDirectory);\n for (const template of templates) {\n this._setTemplate(\n configDirectory,\n template,\n TEMPLATE_DESTINATIONS[template],\n dsn,\n );\n }\n red(\n '⚠ Performance monitoring is enabled capturing 100% of transactions.\\n' +\n ' Learn more in https://docs.sentry.io/product/performance/',\n );\n nl();\n }\n\n private _setTemplate(\n configDirectory: string,\n templateFile: string,\n destinationOptions: string[],\n dsn: string,\n ): void {\n const templatePath = path.join(configDirectory, templateFile);\n\n for (const destinationDir of destinationOptions) {\n if (!fs.existsSync(destinationDir)) {\n continue;\n }\n\n const destinationPath = path.join(destinationDir, templateFile);\n // in case the file in question already exists, we'll make a copy with\n // `MERGEABLE_CONFIG_INFIX` inserted just before the extension, so as not\n // to overwrite the existing file\n const mergeableFilePath = path.join(\n destinationDir,\n this._spliceInPlace(\n templateFile.split('.'),\n -1,\n 0,\n MERGEABLE_CONFIG_INFIX,\n ).join('.'),\n );\n\n if (!fs.existsSync(destinationPath)) {\n this._fillAndCopyTemplate(templatePath, destinationPath, dsn);\n } else if (!fs.existsSync(mergeableFilePath)) {\n this._fillAndCopyTemplate(templatePath, mergeableFilePath, dsn);\n red(\n `File \\`${templateFile}\\` already exists, so created \\`${mergeableFilePath}\\`.\\n` +\n 'Please merge those files.',\n );\n nl();\n } else {\n red(\n `Both \\`${templateFile}\\` and \\`${mergeableFilePath}\\` already exist.\\n` +\n 'Please merge those files.',\n );\n nl();\n }\n return;\n }\n\n red(\n `Could not find appropriate destination for \\`${templateFile}\\`. Tried: ${destinationOptions}.`,\n );\n nl();\n }\n\n private _fillAndCopyTemplate(\n sourcePath: string,\n targetPath: string,\n dsn: string,\n ): void {\n const templateContent = fs.readFileSync(sourcePath).toString();\n const filledTemplate = templateContent.replace('___DSN___', dsn);\n fs.writeFileSync(targetPath, filledTemplate);\n }\n\n private _checkUserNextVersion(packageName: string): boolean {\n const depsVersion = _.get(appPackage, ['dependencies', packageName]);\n const devDepsVersion = _.get(appPackage, ['devDependencies', packageName]);\n\n if (!depsVersion && !devDepsVersion) {\n red(`✗ ${packageName} isn't in your dependencies.`);\n red(' Please install it with yarn/npm.');\n return false;\n } else if (\n !this._fulfillsVersionRange(depsVersion) &&\n !this._fulfillsVersionRange(devDepsVersion)\n ) {\n red(\n `✗ Your \\`package.json\\` specifies a version of \\`${packageName}\\` outside of the compatible version range ${COMPATIBLE_NEXTJS_VERSIONS}.\\n`,\n );\n return false;\n } else {\n green(\n `✓ A compatible version of \\`${packageName}\\` is specified in \\`package.json\\`.`,\n );\n return true;\n }\n }\n\n private _fulfillsVersionRange(version: string): boolean {\n // The latest version is currently 12.x, which is not yet supported.\n if (version === 'latest') {\n return false;\n }\n\n let cleanedUserVersion, isRange;\n\n if (valid(version)) {\n cleanedUserVersion = valid(version);\n isRange = false;\n } else if (validRange(version)) {\n cleanedUserVersion = validRange(version);\n isRange = true;\n }\n\n return (\n !!cleanedUserVersion &&\n (isRange\n ? subset(cleanedUserVersion, COMPATIBLE_NEXTJS_VERSIONS)\n : satisfies(cleanedUserVersion, COMPATIBLE_NEXTJS_VERSIONS))\n );\n }\n\n private _spliceInPlace(\n arr: Array<any>,\n start: number,\n deleteCount: number,\n ...inserts: any[]\n ): Array<any> {\n arr.splice(start, deleteCount, ...inserts);\n return arr;\n }\n}\n"]}
@@ -37,6 +37,7 @@ export class SentryCli {
37
37
  return props;
38
38
  }
39
39
 
40
+ /** Create the contents of a `sentry.properties` file */
40
41
  public dumpProperties(props: SentryCliProps): string {
41
42
  const rv = [];
42
43
  for (let key in props) {
@@ -45,6 +46,7 @@ export class SentryCli {
45
46
  const value = props[key];
46
47
  key = key.replace(/\//g, '.');
47
48
  if (value === undefined || value === null) {
49
+ // comment that property out since it has no value
48
50
  rv.push(`#${key}=`);
49
51
  } else {
50
52
  rv.push(`${key}=${value}`);
@@ -21,7 +21,7 @@ export abstract class BaseIntegration extends BaseStep {
21
21
  /**
22
22
  * This can be used for example for platform:boolean to determine
23
23
  * if we should configure iOS/Android.
24
- * Basically this will be merged into answers so it can be check by a later step.
24
+ * Basically this will be merged into answers so it can be checked by a later step.
25
25
  */
26
26
  public async shouldConfigure(_answers: Answers): Promise<Answers> {
27
27
  if (this._shouldConfigure) {
@@ -34,7 +34,10 @@ export abstract class BaseIntegration extends BaseStep {
34
34
  public async shouldEmit(_answers: Answers): Promise<boolean> {
35
35
  return (
36
36
  _.keys(
37
- _.pickBy(await this.shouldConfigure(_answers), (active: boolean) => active),
37
+ _.pickBy(
38
+ await this.shouldConfigure(_answers),
39
+ (active: boolean) => active,
40
+ ),
38
41
  ).length > 0
39
42
  );
40
43
  }
@@ -1,20 +1,30 @@
1
+ /* eslint-disable max-lines */
1
2
  import * as fs from 'fs';
2
3
  import { Answers, prompt } from 'inquirer';
3
4
  import * as _ from 'lodash';
4
5
  import * as path from 'path';
5
- import { clean, gte, minVersion, satisfies, validRange } from 'semver';
6
+ import { satisfies, subset, valid, validRange } from 'semver';
6
7
 
7
8
  import { Args } from '../../Constants';
8
9
  import { debug, green, l, nl, red } from '../../Helper/Logging';
9
10
  import { SentryCli, SentryCliProps } from '../../Helper/SentryCli';
10
11
  import { BaseIntegration } from './BaseIntegration';
11
12
 
12
- const MIN_NEXTJS_VERSION = '10.0.8'; // Must be a fixed version: `X.Y.Z`
13
+ const COMPATIBLE_NEXTJS_VERSIONS = '>=10.0.8 <13.0.0';
13
14
  const PROPERTIES_FILENAME = 'sentry.properties';
14
15
  const SENTRYCLIRC_FILENAME = '.sentryclirc';
15
16
  const GITIGNORE_FILENAME = '.gitignore';
16
17
  const CONFIG_DIR = 'configs/';
17
- const MERGEABLE_CONFIG_PREFIX = '_';
18
+ const MERGEABLE_CONFIG_INFIX = 'wizardcopy';
19
+
20
+ // for those files which can go in more than one place, the list of places they
21
+ // could go (the first one which works will be used)
22
+ const TEMPLATE_DESTINATIONS: { [key: string]: string[] } = {
23
+ '_error.js': ['pages', 'src/pages'],
24
+ 'next.config.js': ['.'],
25
+ 'sentry.server.config.js': ['.'],
26
+ 'sentry.client.config.js': ['.'],
27
+ };
18
28
 
19
29
  let appPackage: any = {};
20
30
 
@@ -52,7 +62,7 @@ export class NextJs extends BaseIntegration {
52
62
  this._createNextConfig(configDirectory, dsn);
53
63
  } else {
54
64
  debug(
55
- `Couldn't find ${configDirectory}, probably because you run from src`,
65
+ `Couldn't find ${configDirectory}, probably because you ran this from inside of \`/lib\` rather than \`/dist\``,
56
66
  );
57
67
  nl();
58
68
  }
@@ -73,7 +83,7 @@ export class NextJs extends BaseIntegration {
73
83
  nl();
74
84
 
75
85
  let userAnswers: Answers = { continue: true };
76
- if (!this._checkDep('next', true) && !this._argv.quiet) {
86
+ if (!this._checkUserNextVersion('next') && !this._argv.quiet) {
77
87
  userAnswers = await prompt({
78
88
  message:
79
89
  'There were errors during your project checkup, do you still want to continue?',
@@ -184,7 +194,12 @@ export class NextJs extends BaseIntegration {
184
194
  private _createNextConfig(configDirectory: string, dsn: any): void {
185
195
  const templates = fs.readdirSync(configDirectory);
186
196
  for (const template of templates) {
187
- this._setTemplate(configDirectory, template, dsn);
197
+ this._setTemplate(
198
+ configDirectory,
199
+ template,
200
+ TEMPLATE_DESTINATIONS[template],
201
+ dsn,
202
+ );
188
203
  }
189
204
  red(
190
205
  '⚠ Performance monitoring is enabled capturing 100% of transactions.\n' +
@@ -195,27 +210,54 @@ export class NextJs extends BaseIntegration {
195
210
 
196
211
  private _setTemplate(
197
212
  configDirectory: string,
198
- template: string,
213
+ templateFile: string,
214
+ destinationOptions: string[],
199
215
  dsn: string,
200
216
  ): void {
201
- const templatePath = path.join(configDirectory, template);
202
- const mergeableFile = MERGEABLE_CONFIG_PREFIX + template;
203
- if (!fs.existsSync(template)) {
204
- this._fillAndCopyTemplate(templatePath, template, dsn);
205
- } else if (!fs.existsSync(mergeableFile)) {
206
- this._fillAndCopyTemplate(templatePath, mergeableFile, dsn);
207
- red(
208
- `File ${template} already exists, so created ${mergeableFile}.\n` +
209
- `Please, merge those files.`,
210
- );
211
- nl();
212
- } else {
213
- red(
214
- `File ${template} already exists, and ${mergeableFile} also exists.\n` +
215
- 'Please, merge those files.',
217
+ const templatePath = path.join(configDirectory, templateFile);
218
+
219
+ for (const destinationDir of destinationOptions) {
220
+ if (!fs.existsSync(destinationDir)) {
221
+ continue;
222
+ }
223
+
224
+ const destinationPath = path.join(destinationDir, templateFile);
225
+ // in case the file in question already exists, we'll make a copy with
226
+ // `MERGEABLE_CONFIG_INFIX` inserted just before the extension, so as not
227
+ // to overwrite the existing file
228
+ const mergeableFilePath = path.join(
229
+ destinationDir,
230
+ this._spliceInPlace(
231
+ templateFile.split('.'),
232
+ -1,
233
+ 0,
234
+ MERGEABLE_CONFIG_INFIX,
235
+ ).join('.'),
216
236
  );
217
- nl();
237
+
238
+ if (!fs.existsSync(destinationPath)) {
239
+ this._fillAndCopyTemplate(templatePath, destinationPath, dsn);
240
+ } else if (!fs.existsSync(mergeableFilePath)) {
241
+ this._fillAndCopyTemplate(templatePath, mergeableFilePath, dsn);
242
+ red(
243
+ `File \`${templateFile}\` already exists, so created \`${mergeableFilePath}\`.\n` +
244
+ 'Please merge those files.',
245
+ );
246
+ nl();
247
+ } else {
248
+ red(
249
+ `Both \`${templateFile}\` and \`${mergeableFilePath}\` already exist.\n` +
250
+ 'Please merge those files.',
251
+ );
252
+ nl();
253
+ }
254
+ return;
218
255
  }
256
+
257
+ red(
258
+ `Could not find appropriate destination for \`${templateFile}\`. Tried: ${destinationOptions}.`,
259
+ );
260
+ nl();
219
261
  }
220
262
 
221
263
  private _fillAndCopyTemplate(
@@ -228,63 +270,61 @@ export class NextJs extends BaseIntegration {
228
270
  fs.writeFileSync(targetPath, filledTemplate);
229
271
  }
230
272
 
231
- private _checkDep(packageName: string, minVersion?: boolean): boolean {
232
- const depVersion = _.get(
233
- appPackage,
234
- ['dependencies', packageName],
235
- '0.0.0',
236
- );
237
- const devDepVersion = _.get(
238
- appPackage,
239
- ['devDependencies', packageName],
240
- '0.0.0',
241
- );
273
+ private _checkUserNextVersion(packageName: string): boolean {
274
+ const depsVersion = _.get(appPackage, ['dependencies', packageName]);
275
+ const devDepsVersion = _.get(appPackage, ['devDependencies', packageName]);
242
276
 
243
- if (
244
- !_.get(appPackage, `dependencies.${packageName}`, false) &&
245
- !_.get(appPackage, `devDependencies.${packageName}`, false)
246
- ) {
247
- red(`✗ ${packageName} isn't in your dependencies`);
248
- red(` please install it with yarn/npm`);
277
+ if (!depsVersion && !devDepsVersion) {
278
+ red(`✗ ${packageName} isn't in your dependencies.`);
279
+ red(' Please install it with yarn/npm.');
249
280
  return false;
250
281
  } else if (
251
- !this._fulfillsMinVersion(depVersion) &&
252
- !this._fulfillsMinVersion(devDepVersion)
282
+ !this._fulfillsVersionRange(depsVersion) &&
283
+ !this._fulfillsVersionRange(devDepsVersion)
253
284
  ) {
254
285
  red(
255
- `✗ Your installed version of \`${packageName}\` is not supported, >=${MIN_NEXTJS_VERSION} needed.`,
286
+ `✗ Your \`package.json\` specifies a version of \`${packageName}\` outside of the compatible version range ${COMPATIBLE_NEXTJS_VERSIONS}.\n`,
256
287
  );
257
288
  return false;
258
289
  } else {
259
- if (minVersion) {
260
- green(`✓ ${packageName} >= ${MIN_NEXTJS_VERSION} is installed`);
261
- } else {
262
- green(`✓ ${packageName} is installed`);
263
- }
290
+ green(
291
+ `✓ A compatible version of \`${packageName}\` is specified in \`package.json\`.`,
292
+ );
264
293
  return true;
265
294
  }
266
295
  }
267
296
 
268
- private _fulfillsMinVersion(version: string): boolean {
269
- // The latest version, which at the moment is greater than the minimum
270
- // version, shouldn't be a blocker in the wizard.
297
+ private _fulfillsVersionRange(version: string): boolean {
298
+ // The latest version is currently 12.x, which is not yet supported.
271
299
  if (version === 'latest') {
272
- return true;
300
+ return false;
273
301
  }
274
302
 
275
- const cleanedVersion = clean(version);
276
- if (cleanedVersion) {
277
- // gte(x, y) : true if x >= y
278
- return gte(cleanedVersion, MIN_NEXTJS_VERSION);
279
- }
303
+ let cleanedUserVersion, isRange;
280
304
 
281
- const minVersionRange = `>=${MIN_NEXTJS_VERSION}`;
282
- const userVersionRange = validRange(version);
283
- const minUserVersion = minVersion(userVersionRange);
284
- if (minUserVersion == null) {
285
- // This should never happen
286
- return false;
305
+ if (valid(version)) {
306
+ cleanedUserVersion = valid(version);
307
+ isRange = false;
308
+ } else if (validRange(version)) {
309
+ cleanedUserVersion = validRange(version);
310
+ isRange = true;
287
311
  }
288
- return satisfies(minUserVersion, minVersionRange);
312
+
313
+ return (
314
+ !!cleanedUserVersion &&
315
+ (isRange
316
+ ? subset(cleanedUserVersion, COMPATIBLE_NEXTJS_VERSIONS)
317
+ : satisfies(cleanedUserVersion, COMPATIBLE_NEXTJS_VERSIONS))
318
+ );
319
+ }
320
+
321
+ private _spliceInPlace(
322
+ arr: Array<any>,
323
+ start: number,
324
+ deleteCount: number,
325
+ ...inserts: any[]
326
+ ): Array<any> {
327
+ arr.splice(start, deleteCount, ...inserts);
328
+ return arr;
289
329
  }
290
330
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/wizard",
3
- "version": "1.2.13",
3
+ "version": "1.2.17",
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",
@@ -0,0 +1,65 @@
1
+ import NextErrorComponent from 'next/error';
2
+
3
+ import * as Sentry from '@sentry/nextjs';
4
+
5
+ const MyError = ({ statusCode, hasGetInitialPropsRun, err }) => {
6
+ if (!hasGetInitialPropsRun && err) {
7
+ // getInitialProps is not called in case of
8
+ // https://github.com/vercel/next.js/issues/8592. As a workaround, we pass
9
+ // err via _app.js so it can be captured
10
+ Sentry.captureException(err);
11
+ // Flushing is not required in this case as it only happens on the client
12
+ }
13
+
14
+ return <NextErrorComponent statusCode={statusCode} />;
15
+ };
16
+
17
+ MyError.getInitialProps = async (context) => {
18
+ const errorInitialProps = await NextErrorComponent.getInitialProps(context);
19
+
20
+ const { res, err, asPath } = context;
21
+
22
+ // Workaround for https://github.com/vercel/next.js/issues/8592, mark when
23
+ // getInitialProps has run
24
+ errorInitialProps.hasGetInitialPropsRun = true;
25
+
26
+ // Returning early because we don't want to log 404 errors to Sentry.
27
+ if (res?.statusCode === 404) {
28
+ return errorInitialProps;
29
+ }
30
+
31
+ // Running on the server, the response object (`res`) is available.
32
+ //
33
+ // Next.js will pass an err on the server if a page's data fetching methods
34
+ // threw or returned a Promise that rejected
35
+ //
36
+ // Running on the client (browser), Next.js will provide an err if:
37
+ //
38
+ // - a page's `getInitialProps` threw or returned a Promise that rejected
39
+ // - an exception was thrown somewhere in the React lifecycle (render,
40
+ // componentDidMount, etc) that was caught by Next.js's React Error
41
+ // Boundary. Read more about what types of exceptions are caught by Error
42
+ // Boundaries: https://reactjs.org/docs/error-boundaries.html
43
+
44
+ if (err) {
45
+ Sentry.captureException(err);
46
+
47
+ // Flushing before returning is necessary if deploying to Vercel, see
48
+ // https://vercel.com/docs/platform/limits#streaming-responses
49
+ await Sentry.flush(2000);
50
+
51
+ return errorInitialProps;
52
+ }
53
+
54
+ // If this point is reached, getInitialProps was called without any
55
+ // information about what the error might be. This is unexpected and may
56
+ // indicate a bug introduced in Next.js, so record it in Sentry
57
+ Sentry.captureException(
58
+ new Error(`_error.js getInitialProps missing data at path: ${asPath}`),
59
+ );
60
+ await Sentry.flush(2000);
61
+
62
+ return errorInitialProps;
63
+ };
64
+
65
+ export default MyError;
@@ -9,7 +9,7 @@ const moduleExports = {
9
9
  // Your existing module.exports
10
10
  };
11
11
 
12
- const SentryWebpackPluginOptions = {
12
+ const sentryWebpackPluginOptions = {
13
13
  // Additional config options for the Sentry Webpack plugin. Keep in mind that
14
14
  // the following options are set automatically, and overriding them is not
15
15
  // recommended:
@@ -23,4 +23,4 @@ const SentryWebpackPluginOptions = {
23
23
 
24
24
  // Make sure adding Sentry options is the last code to run before exporting, to
25
25
  // ensure that your source maps include changes from all other Webpack plugins
26
- module.exports = withSentryConfig(moduleExports, SentryWebpackPluginOptions);
26
+ module.exports = withSentryConfig(moduleExports, sentryWebpackPluginOptions);