@sentry/wizard 3.34.4 → 3.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -1
- package/dist/e2e-tests/tests/nuxt-3.test.d.ts +1 -0
- package/dist/e2e-tests/tests/nuxt-3.test.js +257 -0
- package/dist/e2e-tests/tests/nuxt-3.test.js.map +1 -0
- package/dist/e2e-tests/tests/nuxt-4.test.d.ts +1 -0
- package/dist/e2e-tests/tests/nuxt-4.test.js +258 -0
- package/dist/e2e-tests/tests/nuxt-4.test.js.map +1 -0
- package/dist/e2e-tests/tests/remix.test.js +92 -27
- package/dist/e2e-tests/tests/remix.test.js.map +1 -1
- package/dist/e2e-tests/tests/sveltekit.test.js +102 -42
- package/dist/e2e-tests/tests/sveltekit.test.js.map +1 -1
- package/dist/e2e-tests/utils/index.d.ts +18 -1
- package/dist/e2e-tests/utils/index.js +31 -2
- package/dist/e2e-tests/utils/index.js.map +1 -1
- package/dist/lib/Constants.d.ts +1 -0
- package/dist/lib/Constants.js +1 -0
- package/dist/lib/Constants.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/src/android/templates.js +1 -1
- package/dist/src/android/templates.js.map +1 -1
- package/dist/src/apple/templates.js +2 -2
- package/dist/src/apple/templates.js.map +1 -1
- package/dist/src/nextjs/nextjs-wizard.js +1 -0
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/nuxt/nuxt-wizard.d.ts +3 -0
- package/dist/src/nuxt/nuxt-wizard.js +227 -0
- package/dist/src/nuxt/nuxt-wizard.js.map +1 -0
- package/dist/src/nuxt/sdk-example.d.ts +8 -0
- package/dist/src/nuxt/sdk-example.js +179 -0
- package/dist/src/nuxt/sdk-example.js.map +1 -0
- package/dist/src/nuxt/sdk-setup.d.ts +11 -0
- package/dist/src/nuxt/sdk-setup.js +326 -0
- package/dist/src/nuxt/sdk-setup.js.map +1 -0
- package/dist/src/nuxt/templates.d.ts +22 -0
- package/dist/src/nuxt/templates.js +84 -0
- package/dist/src/nuxt/templates.js.map +1 -0
- package/dist/src/nuxt/utils.d.ts +1 -0
- package/dist/src/nuxt/utils.js +71 -0
- package/dist/src/nuxt/utils.js.map +1 -0
- package/dist/src/remix/remix-wizard.js +2 -1
- package/dist/src/remix/remix-wizard.js.map +1 -1
- package/dist/src/run.d.ts +1 -1
- package/dist/src/run.js +30 -23
- package/dist/src/run.js.map +1 -1
- package/dist/src/sourcemaps/tools/rollup.js +1 -1
- package/dist/src/sourcemaps/tools/rollup.js.map +1 -1
- package/dist/src/sveltekit/sveltekit-wizard.js +2 -1
- package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
- package/dist/src/utils/clack-utils.d.ts +9 -2
- package/dist/src/utils/clack-utils.js +93 -27
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/dist/src/utils/package-json.d.ts +5 -0
- package/dist/src/utils/package-json.js.map +1 -1
- package/dist/src/utils/package-manager.d.ts +1 -0
- package/dist/src/utils/package-manager.js +129 -0
- package/dist/src/utils/package-manager.js.map +1 -1
- package/dist/test/nuxt/templates.test.d.ts +1 -0
- package/dist/test/nuxt/templates.test.js +70 -0
- package/dist/test/nuxt/templates.test.js.map +1 -0
- package/e2e-tests/README.md +59 -0
- package/e2e-tests/test-applications/nuxt-3-test-app/README.md +75 -0
- package/e2e-tests/test-applications/nuxt-3-test-app/nuxt.config.ts +5 -0
- package/e2e-tests/test-applications/nuxt-3-test-app/package.json +18 -0
- package/e2e-tests/test-applications/nuxt-3-test-app/public/favicon.ico +0 -0
- package/e2e-tests/test-applications/nuxt-3-test-app/public/robots.txt +1 -0
- package/e2e-tests/tests/nuxt-3.test.ts +192 -0
- package/e2e-tests/tests/nuxt-4.test.ts +191 -0
- package/e2e-tests/tests/remix.test.ts +163 -50
- package/e2e-tests/tests/sveltekit.test.ts +180 -79
- package/e2e-tests/utils/index.ts +34 -1
- package/lib/Constants.ts +1 -0
- package/package.json +1 -1
- package/src/android/templates.ts +0 -2
- package/src/apple/templates.ts +14 -2
- package/src/nextjs/nextjs-wizard.ts +1 -0
- package/src/nuxt/nuxt-wizard.ts +177 -0
- package/src/nuxt/sdk-example.ts +135 -0
- package/src/nuxt/sdk-setup.ts +248 -0
- package/src/nuxt/templates.ts +296 -0
- package/src/nuxt/utils.ts +32 -0
- package/src/remix/remix-wizard.ts +2 -1
- package/src/run.ts +7 -0
- package/src/sourcemaps/tools/rollup.ts +1 -1
- package/src/sveltekit/sveltekit-wizard.ts +2 -1
- package/src/utils/clack-utils.ts +74 -13
- package/src/utils/package-json.ts +5 -0
- package/src/utils/package-manager.ts +66 -0
- package/test/nuxt/templates.test.ts +228 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { getIssueStreamUrl } from '../utils/url';
|
|
2
|
+
|
|
3
|
+
type SelectedSentryFeatures = {
|
|
4
|
+
performance: boolean;
|
|
5
|
+
replay: boolean;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export function getDefaultNuxtConfig(): string {
|
|
9
|
+
return `// https://nuxt.com/docs/api/configuration/nuxt-config
|
|
10
|
+
export default defineNuxtConfig({
|
|
11
|
+
compatibilityDate: '2024-04-03',
|
|
12
|
+
devtools: { enabled: true }
|
|
13
|
+
})
|
|
14
|
+
`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function getNuxtModuleFallbackTemplate(options: {
|
|
18
|
+
org: string;
|
|
19
|
+
project: string;
|
|
20
|
+
url: string;
|
|
21
|
+
selfHosted: boolean;
|
|
22
|
+
}): string {
|
|
23
|
+
return ` modules: ["@sentry/nuxt/module"],
|
|
24
|
+
sentry: {
|
|
25
|
+
sourceMapsUploadOptions: {
|
|
26
|
+
org: "${options.org}",
|
|
27
|
+
project: "${options.project}",${
|
|
28
|
+
options.selfHosted ? `\n url: "${options.url}",` : ''
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
sourcemap: { client: "hidden" },`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function getSentryConfigContents(
|
|
36
|
+
dsn: string,
|
|
37
|
+
config: 'client' | 'server',
|
|
38
|
+
selectedFeatures: SelectedSentryFeatures,
|
|
39
|
+
): string {
|
|
40
|
+
if (config === 'client') {
|
|
41
|
+
return getSentryClientConfigContents(dsn, selectedFeatures);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return getSentryServerConfigContents(dsn, selectedFeatures);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const featuresConfigMap: Record<keyof SelectedSentryFeatures, string> = {
|
|
48
|
+
performance: [
|
|
49
|
+
' // We recommend adjusting this value in production, or using tracesSampler',
|
|
50
|
+
' // for finer control',
|
|
51
|
+
' tracesSampleRate: 1.0,',
|
|
52
|
+
].join('\n'),
|
|
53
|
+
replay: [
|
|
54
|
+
' // This sets the sample rate to be 10%. You may want this to be 100% while',
|
|
55
|
+
' // in development and sample at a lower rate in production',
|
|
56
|
+
' replaysSessionSampleRate: 0.1,',
|
|
57
|
+
' ',
|
|
58
|
+
' // If the entire session is not sampled, use the below sample rate to sample',
|
|
59
|
+
' // sessions when an error occurs.',
|
|
60
|
+
' replaysOnErrorSampleRate: 1.0,',
|
|
61
|
+
' ',
|
|
62
|
+
" // If you don't want to use Session Replay, just remove the line below:",
|
|
63
|
+
' integrations: [Sentry.replayIntegration()],',
|
|
64
|
+
].join('\n'),
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const featuresMap: Record<
|
|
68
|
+
'client' | 'server',
|
|
69
|
+
Array<keyof SelectedSentryFeatures>
|
|
70
|
+
> = {
|
|
71
|
+
client: ['performance', 'replay'],
|
|
72
|
+
server: ['performance'],
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export function getConfigBody(
|
|
76
|
+
dsn: string,
|
|
77
|
+
variant: 'client' | 'server',
|
|
78
|
+
selectedFeatures: SelectedSentryFeatures,
|
|
79
|
+
) {
|
|
80
|
+
return [
|
|
81
|
+
`dsn: "${dsn}",`,
|
|
82
|
+
Object.entries(selectedFeatures)
|
|
83
|
+
.map(([feature, activated]: [keyof SelectedSentryFeatures, boolean]) => {
|
|
84
|
+
return featuresMap[variant].includes(feature) && activated
|
|
85
|
+
? featuresConfigMap[feature]
|
|
86
|
+
: null;
|
|
87
|
+
})
|
|
88
|
+
.filter(Boolean)
|
|
89
|
+
.join('\n\n'),
|
|
90
|
+
]
|
|
91
|
+
.filter(Boolean)
|
|
92
|
+
.join('\n\n');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function getSentryClientConfigContents(
|
|
96
|
+
dsn: string,
|
|
97
|
+
selectedFeatures: SelectedSentryFeatures,
|
|
98
|
+
): string {
|
|
99
|
+
return `import * as Sentry from "@sentry/nuxt";
|
|
100
|
+
|
|
101
|
+
Sentry.init({
|
|
102
|
+
// If set up, you can use your runtime config here
|
|
103
|
+
// dsn: useRuntimeConfig().public.sentry.dsn,
|
|
104
|
+
${getConfigBody(dsn, 'client', selectedFeatures)}
|
|
105
|
+
|
|
106
|
+
// Setting this option to true will print useful information to the console while you're setting up Sentry.
|
|
107
|
+
debug: false,
|
|
108
|
+
});
|
|
109
|
+
`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function getSentryServerConfigContents(
|
|
113
|
+
dsn: string,
|
|
114
|
+
selectedFeatures: SelectedSentryFeatures,
|
|
115
|
+
): string {
|
|
116
|
+
return `import * as Sentry from "@sentry/nuxt";
|
|
117
|
+
|
|
118
|
+
Sentry.init({
|
|
119
|
+
${getConfigBody(dsn, 'server', selectedFeatures)}
|
|
120
|
+
|
|
121
|
+
// Setting this option to true will print useful information to the console while you're setting up Sentry.
|
|
122
|
+
debug: false,
|
|
123
|
+
});
|
|
124
|
+
`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function getIndexRouteTemplate(): string {
|
|
128
|
+
return `<!--
|
|
129
|
+
This is just to verify the sentry-example-page.
|
|
130
|
+
Feel free to delete this file.
|
|
131
|
+
-->
|
|
132
|
+
|
|
133
|
+
<template></template>`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function getSentryExamplePageTemplate(options: {
|
|
137
|
+
url: string;
|
|
138
|
+
org: string;
|
|
139
|
+
projectId: string;
|
|
140
|
+
}): string {
|
|
141
|
+
const { url, org, projectId } = options;
|
|
142
|
+
const issuesPageLink = getIssueStreamUrl({ url, orgSlug: org, projectId });
|
|
143
|
+
|
|
144
|
+
return `<!--
|
|
145
|
+
This is just a very simple page with a button to throw an example error.
|
|
146
|
+
Feel free to delete this file.
|
|
147
|
+
-->
|
|
148
|
+
|
|
149
|
+
<script setup>
|
|
150
|
+
import * as Sentry from '@sentry/nuxt';
|
|
151
|
+
import { useFetch} from '#imports'
|
|
152
|
+
|
|
153
|
+
function getSentryData() {
|
|
154
|
+
Sentry.startSpan(
|
|
155
|
+
{
|
|
156
|
+
name: 'Example Frontend Span',
|
|
157
|
+
op: 'test'
|
|
158
|
+
},
|
|
159
|
+
async () => {
|
|
160
|
+
const { error } = await useFetch('/api/sentry-example-api');
|
|
161
|
+
if (error.value) {
|
|
162
|
+
throw new Error('Sentry Example Frontend Error');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
</script>
|
|
168
|
+
|
|
169
|
+
<template>
|
|
170
|
+
<title>Sentry Onboarding</title>
|
|
171
|
+
<div>
|
|
172
|
+
<main>
|
|
173
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 44">
|
|
174
|
+
<path
|
|
175
|
+
fill="currentColor"
|
|
176
|
+
d="M124.32,28.28,109.56,9.22h-3.68V34.77h3.73V15.19l15.18,19.58h3.26V9.22h-3.73ZM87.15,23.54h13.23V20.22H87.14V12.53h14.93V9.21H83.34V34.77h18.92V31.45H87.14ZM71.59,20.3h0C66.44,19.06,65,18.08,65,15.7c0-2.14,1.89-3.59,4.71-3.59a12.06,12.06,0,0,1,7.07,2.55l2-2.83a14.1,14.1,0,0,0-9-3c-5.06,0-8.59,3-8.59,7.27,0,4.6,3,6.19,8.46,7.52C74.51,24.74,76,25.78,76,28.11s-2,3.77-5.09,3.77a12.34,12.34,0,0,1-8.3-3.26l-2.25,2.69a15.94,15.94,0,0,0,10.42,3.85c5.48,0,9-2.95,9-7.51C79.75,23.79,77.47,21.72,71.59,20.3ZM195.7,9.22l-7.69,12-7.64-12h-4.46L186,24.67V34.78h3.84V24.55L200,9.22Zm-64.63,3.46h8.37v22.1h3.84V12.68h8.37V9.22H131.08ZM169.41,24.8c3.86-1.07,6-3.77,6-7.63,0-4.91-3.59-8-9.38-8H154.67V34.76h3.8V25.58h6.45l6.48,9.2h4.44l-7-9.82Zm-10.95-2.5V12.6h7.17c3.74,0,5.88,1.77,5.88,4.84s-2.29,4.86-5.84,4.86Z M29,2.26a4.67,4.67,0,0,0-8,0L14.42,13.53A32.21,32.21,0,0,1,32.17,40.19H27.55A27.68,27.68,0,0,0,12.09,17.47L6,28a15.92,15.92,0,0,1,9.23,12.17H4.62A.76.76,0,0,1,4,39.06l2.94-5a10.74,10.74,0,0,0-3.36-1.9l-2.91,5a4.54,4.54,0,0,0,1.69,6.24A4.66,4.66,0,0,0,4.62,44H19.15a19.4,19.4,0,0,0-8-17.31l2.31-4A23.87,23.87,0,0,1,23.76,44H36.07a35.88,35.88,0,0,0-16.41-31.8l4.67-8a.77.77,0,0,1,1.05-.27c.53.29,20.29,34.77,20.66,35.17a.76.76,0,0,1-.68,1.13H40.6q.09,1.91,0,3.81h4.78A4.59,4.59,0,0,0,50,39.43a4.49,4.49,0,0,0-.62-2.28Z"
|
|
177
|
+
/>
|
|
178
|
+
</svg>
|
|
179
|
+
<p>
|
|
180
|
+
Get Started with this <strong>simple Example:</strong>
|
|
181
|
+
</p>
|
|
182
|
+
|
|
183
|
+
<p>1. Send us a sample error:</p>
|
|
184
|
+
<button type="button" @click="getSentryData"> Throw error! </button>
|
|
185
|
+
|
|
186
|
+
<p>
|
|
187
|
+
2. Look for the error on the
|
|
188
|
+
<a href="${issuesPageLink}">Issues Page</a>.
|
|
189
|
+
</p>
|
|
190
|
+
<p style="margin-top: 24px;">
|
|
191
|
+
For more information, take a look at the
|
|
192
|
+
<a href="https://docs.sentry.io/platforms/javascript/guides/nuxt/">
|
|
193
|
+
Sentry Nuxt Documentation
|
|
194
|
+
</a>
|
|
195
|
+
</p>
|
|
196
|
+
</main>
|
|
197
|
+
</div>
|
|
198
|
+
</template>
|
|
199
|
+
|
|
200
|
+
<style scoped>
|
|
201
|
+
main {
|
|
202
|
+
display: flex;
|
|
203
|
+
flex-direction: column;
|
|
204
|
+
justify-content: center;
|
|
205
|
+
align-items: center;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
svg {
|
|
209
|
+
font-size: 4rem;
|
|
210
|
+
margin: 14px 0;
|
|
211
|
+
height: 1em;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
button {
|
|
215
|
+
padding: 12px;
|
|
216
|
+
cursor: pointer;
|
|
217
|
+
background-color: rgb(54, 45, 89);
|
|
218
|
+
border-radius: 4px;
|
|
219
|
+
border: none;
|
|
220
|
+
color: white;
|
|
221
|
+
font-size: 1em;
|
|
222
|
+
margin: 1em;
|
|
223
|
+
transition: all 0.25s ease-in-out;
|
|
224
|
+
}
|
|
225
|
+
button:hover {
|
|
226
|
+
background-color: #8c5393;
|
|
227
|
+
box-shadow: 4px;
|
|
228
|
+
box-shadow: 0px 0px 15px 2px rgba(140, 83, 147, 0.5);
|
|
229
|
+
}
|
|
230
|
+
button:active {
|
|
231
|
+
background-color: #c73852;
|
|
232
|
+
}
|
|
233
|
+
</style>
|
|
234
|
+
`;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export function getSentryExampleApiTemplate() {
|
|
238
|
+
return `// This is just a very simple API route that throws an example error.
|
|
239
|
+
// Feel free to delete this file.
|
|
240
|
+
import { defineEventHandler } from '#imports';
|
|
241
|
+
|
|
242
|
+
export default defineEventHandler(event => {
|
|
243
|
+
throw new Error("Sentry Example API Route Error");
|
|
244
|
+
});
|
|
245
|
+
`;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function getSentryErrorButtonTemplate() {
|
|
249
|
+
return `<!--
|
|
250
|
+
This is just a very simple component that throws an example error.
|
|
251
|
+
Feel free to delete this file.
|
|
252
|
+
-->
|
|
253
|
+
|
|
254
|
+
<script setup>
|
|
255
|
+
import * as Sentry from '@sentry/nuxt';
|
|
256
|
+
|
|
257
|
+
const throwError = () => {
|
|
258
|
+
Sentry.startSpan(
|
|
259
|
+
{
|
|
260
|
+
name: 'Example Frontend Span',
|
|
261
|
+
op: 'test'
|
|
262
|
+
},
|
|
263
|
+
() => {
|
|
264
|
+
throw new Error('Sentry Example Error');
|
|
265
|
+
}
|
|
266
|
+
)
|
|
267
|
+
};
|
|
268
|
+
</script>
|
|
269
|
+
|
|
270
|
+
<template>
|
|
271
|
+
<button id="errorBtn" @click="throwError"> Throw Error! </button>
|
|
272
|
+
</template>
|
|
273
|
+
|
|
274
|
+
<style scoped>
|
|
275
|
+
button {
|
|
276
|
+
padding: 12px;
|
|
277
|
+
cursor: pointer;
|
|
278
|
+
background-color: rgb(54, 45, 89);
|
|
279
|
+
border-radius: 4px;
|
|
280
|
+
border: none;
|
|
281
|
+
color: white;
|
|
282
|
+
font-size: 1em;
|
|
283
|
+
margin: 1em;
|
|
284
|
+
transition: all 0.25s ease-in-out;
|
|
285
|
+
}
|
|
286
|
+
button:hover {
|
|
287
|
+
background-color: #8c5393;
|
|
288
|
+
box-shadow: 4px;
|
|
289
|
+
box-shadow: 0px 0px 15px 2px rgba(140, 83, 147, 0.5);
|
|
290
|
+
}
|
|
291
|
+
button:active {
|
|
292
|
+
background-color: #c73852;
|
|
293
|
+
}
|
|
294
|
+
</style>
|
|
295
|
+
`;
|
|
296
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { gte, minVersion } from 'semver';
|
|
2
|
+
// @ts-expect-error - magicast is ESM and TS complains about that. It works though
|
|
3
|
+
import { loadFile } from 'magicast';
|
|
4
|
+
|
|
5
|
+
export async function isNuxtV4(
|
|
6
|
+
nuxtConfig: string,
|
|
7
|
+
packageVersion: string | undefined,
|
|
8
|
+
) {
|
|
9
|
+
if (!packageVersion) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const minVer = minVersion(packageVersion);
|
|
14
|
+
if (minVer && gte(minVer, '4.0.0')) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// At the time of writing, nuxt 4 is not on its own
|
|
19
|
+
// major yet. We must read the `compatibilityVersion`
|
|
20
|
+
// from the nuxt config.
|
|
21
|
+
const mod = await loadFile(nuxtConfig);
|
|
22
|
+
const config =
|
|
23
|
+
mod.exports.default.$type === 'function-call'
|
|
24
|
+
? mod.exports.default.$args[0]
|
|
25
|
+
: mod.exports.default;
|
|
26
|
+
|
|
27
|
+
if (config && config.future && config.future.compatibilityVersion === 4) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
@@ -70,7 +70,8 @@ async function runRemixWizardWithTelemetry(
|
|
|
70
70
|
await getOrAskForProjectData(options, 'javascript-remix');
|
|
71
71
|
|
|
72
72
|
await installPackage({
|
|
73
|
-
packageName: '@sentry/remix',
|
|
73
|
+
packageName: '@sentry/remix@^8',
|
|
74
|
+
packageNameDisplayLabel: '@sentry/remix',
|
|
74
75
|
alreadyInstalled: hasPackageInstalled('@sentry/remix', packageJson),
|
|
75
76
|
});
|
|
76
77
|
|
package/src/run.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { PreselectedProject, WizardOptions } from './utils/types';
|
|
|
8
8
|
import { runAndroidWizard } from './android/android-wizard';
|
|
9
9
|
import { runAppleWizard } from './apple/apple-wizard';
|
|
10
10
|
import { runNextjsWizard } from './nextjs/nextjs-wizard';
|
|
11
|
+
import { runNuxtWizard } from './nuxt/nuxt-wizard';
|
|
11
12
|
import { runRemixWizard } from './remix/remix-wizard';
|
|
12
13
|
import { runSvelteKitWizard } from './sveltekit/sveltekit-wizard';
|
|
13
14
|
import { runSourcemapsWizard } from './sourcemaps/sourcemaps-wizard';
|
|
@@ -22,6 +23,7 @@ type WizardIntegration =
|
|
|
22
23
|
| 'cordova'
|
|
23
24
|
| 'electron'
|
|
24
25
|
| 'nextjs'
|
|
26
|
+
| 'nuxt'
|
|
25
27
|
| 'remix'
|
|
26
28
|
| 'sveltekit'
|
|
27
29
|
| 'sourcemaps';
|
|
@@ -103,6 +105,7 @@ export async function run(argv: Args) {
|
|
|
103
105
|
{ value: 'cordova', label: 'Cordova' },
|
|
104
106
|
{ value: 'electron', label: 'Electron' },
|
|
105
107
|
{ value: 'nextjs', label: 'Next.js' },
|
|
108
|
+
{ value: 'nuxt', label: 'Nuxt' },
|
|
106
109
|
{ value: 'remix', label: 'Remix' },
|
|
107
110
|
{ value: 'sveltekit', label: 'SvelteKit' },
|
|
108
111
|
{ value: 'sourcemaps', label: 'Configure Source Maps Upload' },
|
|
@@ -148,6 +151,10 @@ export async function run(argv: Args) {
|
|
|
148
151
|
await runNextjsWizard(wizardOptions);
|
|
149
152
|
break;
|
|
150
153
|
|
|
154
|
+
case 'nuxt':
|
|
155
|
+
await runNuxtWizard(wizardOptions);
|
|
156
|
+
break;
|
|
157
|
+
|
|
151
158
|
case 'remix':
|
|
152
159
|
await runRemixWizard(wizardOptions);
|
|
153
160
|
break;
|
|
@@ -51,7 +51,7 @@ export const configureRollupPlugin: SourceMapUploadToolConfigurationFunction =
|
|
|
51
51
|
|
|
52
52
|
clack.log.step(`Add the following code to your rollup config:`);
|
|
53
53
|
|
|
54
|
-
//
|
|
54
|
+
// Intentionally logging directly to console here so that the code can be copied/pasted directly
|
|
55
55
|
// eslint-disable-next-line no-console
|
|
56
56
|
console.log(getCodeSnippet(options));
|
|
57
57
|
|
|
@@ -95,7 +95,8 @@ export async function runSvelteKitWizardWithTelemetry(
|
|
|
95
95
|
Sentry.setTag('sdk-already-installed', sdkAlreadyInstalled);
|
|
96
96
|
|
|
97
97
|
await installPackage({
|
|
98
|
-
packageName: '@sentry/sveltekit',
|
|
98
|
+
packageName: '@sentry/sveltekit@^8',
|
|
99
|
+
packageNameDisplayLabel: '@sentry/sveltekit',
|
|
99
100
|
alreadyInstalled: sdkAlreadyInstalled,
|
|
100
101
|
});
|
|
101
102
|
|
package/src/utils/clack-utils.ts
CHANGED
|
@@ -354,17 +354,23 @@ export async function installPackage({
|
|
|
354
354
|
packageName,
|
|
355
355
|
alreadyInstalled,
|
|
356
356
|
askBeforeUpdating = true,
|
|
357
|
+
packageNameDisplayLabel,
|
|
358
|
+
packageManager,
|
|
357
359
|
}: {
|
|
360
|
+
/** The string that is passed to the package manager CLI as identifier to install (e.g. `@sentry/nextjs`, or `@sentry/nextjs@^8`) */
|
|
358
361
|
packageName: string;
|
|
359
362
|
alreadyInstalled: boolean;
|
|
360
363
|
askBeforeUpdating?: boolean;
|
|
364
|
+
/** Overrides what is shown in the installation logs in place of the `packageName` option. Useful if the `packageName` is ugly (e.g. `@sentry/nextjs@^8`) */
|
|
365
|
+
packageNameDisplayLabel?: string;
|
|
366
|
+
packageManager?: PackageManager;
|
|
361
367
|
}): Promise<{ packageManager?: PackageManager }> {
|
|
362
368
|
return traceStep('install-package', async () => {
|
|
363
369
|
if (alreadyInstalled && askBeforeUpdating) {
|
|
364
370
|
const shouldUpdatePackage = await abortIfCancelled(
|
|
365
371
|
clack.confirm({
|
|
366
372
|
message: `The ${chalk.bold.cyan(
|
|
367
|
-
packageName,
|
|
373
|
+
packageNameDisplayLabel ?? packageName,
|
|
368
374
|
)} package is already installed. Do you want to update it to the latest version?`,
|
|
369
375
|
}),
|
|
370
376
|
);
|
|
@@ -376,18 +382,18 @@ export async function installPackage({
|
|
|
376
382
|
|
|
377
383
|
const sdkInstallSpinner = clack.spinner();
|
|
378
384
|
|
|
379
|
-
const
|
|
385
|
+
const pkgManager = packageManager || (await getPackageManager());
|
|
380
386
|
|
|
381
387
|
sdkInstallSpinner.start(
|
|
382
388
|
`${alreadyInstalled ? 'Updating' : 'Installing'} ${chalk.bold.cyan(
|
|
383
|
-
packageName,
|
|
384
|
-
)} with ${chalk.bold(
|
|
389
|
+
packageNameDisplayLabel ?? packageName,
|
|
390
|
+
)} with ${chalk.bold(pkgManager.label)}.`,
|
|
385
391
|
);
|
|
386
392
|
|
|
387
393
|
try {
|
|
388
394
|
await new Promise<void>((resolve, reject) => {
|
|
389
395
|
childProcess.exec(
|
|
390
|
-
`${
|
|
396
|
+
`${pkgManager.installCommand} ${packageName} ${pkgManager.flags}`,
|
|
391
397
|
(err, stdout, stderr) => {
|
|
392
398
|
if (err) {
|
|
393
399
|
// Write a log file so we can better troubleshoot issues
|
|
@@ -425,11 +431,11 @@ export async function installPackage({
|
|
|
425
431
|
|
|
426
432
|
sdkInstallSpinner.stop(
|
|
427
433
|
`${alreadyInstalled ? 'Updated' : 'Installed'} ${chalk.bold.cyan(
|
|
428
|
-
packageName,
|
|
429
|
-
)} with ${chalk.bold(
|
|
434
|
+
packageNameDisplayLabel ?? packageName,
|
|
435
|
+
)} with ${chalk.bold(pkgManager.label)}.`,
|
|
430
436
|
);
|
|
431
437
|
|
|
432
|
-
return { packageManager };
|
|
438
|
+
return { packageManager: pkgManager };
|
|
433
439
|
});
|
|
434
440
|
}
|
|
435
441
|
|
|
@@ -593,7 +599,7 @@ SENTRY_AUTH_TOKEN=${authToken}
|
|
|
593
599
|
|
|
594
600
|
if (hasAuthToken) {
|
|
595
601
|
clack.log.warn(
|
|
596
|
-
`${chalk.bold(
|
|
602
|
+
`${chalk.bold.cyan(
|
|
597
603
|
SENTRY_DOT_ENV_FILE,
|
|
598
604
|
)} already has auth token. Will not add one.`,
|
|
599
605
|
);
|
|
@@ -608,11 +614,11 @@ SENTRY_AUTH_TOKEN=${authToken}
|
|
|
608
614
|
},
|
|
609
615
|
);
|
|
610
616
|
clack.log.success(
|
|
611
|
-
`Added auth token to ${chalk.bold(SENTRY_DOT_ENV_FILE)}`,
|
|
617
|
+
`Added auth token to ${chalk.bold.cyan(SENTRY_DOT_ENV_FILE)}`,
|
|
612
618
|
);
|
|
613
619
|
} catch {
|
|
614
620
|
clack.log.warning(
|
|
615
|
-
`Failed to add auth token to ${chalk.bold(
|
|
621
|
+
`Failed to add auth token to ${chalk.bold.cyan(
|
|
616
622
|
SENTRY_DOT_ENV_FILE,
|
|
617
623
|
)}. Uploading source maps during build will likely not work locally.`,
|
|
618
624
|
);
|
|
@@ -625,13 +631,13 @@ SENTRY_AUTH_TOKEN=${authToken}
|
|
|
625
631
|
flag: 'w',
|
|
626
632
|
});
|
|
627
633
|
clack.log.success(
|
|
628
|
-
`Created ${chalk.bold(
|
|
634
|
+
`Created ${chalk.bold.cyan(
|
|
629
635
|
SENTRY_DOT_ENV_FILE,
|
|
630
636
|
)} with auth token for you to test source map uploading locally.`,
|
|
631
637
|
);
|
|
632
638
|
} catch {
|
|
633
639
|
clack.log.warning(
|
|
634
|
-
`Failed to create ${chalk.bold(
|
|
640
|
+
`Failed to create ${chalk.bold.cyan(
|
|
635
641
|
SENTRY_DOT_ENV_FILE,
|
|
636
642
|
)} with auth token. Uploading source maps during build will likely not work locally.`,
|
|
637
643
|
);
|
|
@@ -804,6 +810,26 @@ export async function getPackageDotJson(): Promise<PackageDotJson> {
|
|
|
804
810
|
return packageJson || {};
|
|
805
811
|
}
|
|
806
812
|
|
|
813
|
+
export async function updatePackageDotJson(
|
|
814
|
+
packageDotJson: PackageDotJson,
|
|
815
|
+
): Promise<void> {
|
|
816
|
+
try {
|
|
817
|
+
await fs.promises.writeFile(
|
|
818
|
+
path.join(process.cwd(), 'package.json'),
|
|
819
|
+
// TODO: maybe figure out the original indentation
|
|
820
|
+
JSON.stringify(packageDotJson, null, 2),
|
|
821
|
+
{
|
|
822
|
+
encoding: 'utf8',
|
|
823
|
+
flag: 'w',
|
|
824
|
+
},
|
|
825
|
+
);
|
|
826
|
+
} catch {
|
|
827
|
+
clack.log.error(`Unable to update your ${chalk.cyan('package.json')}.`);
|
|
828
|
+
|
|
829
|
+
await abort();
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
807
833
|
export async function getPackageManager(): Promise<PackageManager> {
|
|
808
834
|
const detectedPackageManager = detectPackageManger();
|
|
809
835
|
|
|
@@ -850,6 +876,7 @@ export async function getOrAskForProjectData(
|
|
|
850
876
|
options: WizardOptions,
|
|
851
877
|
platform?:
|
|
852
878
|
| 'javascript-nextjs'
|
|
879
|
+
| 'javascript-nuxt'
|
|
853
880
|
| 'javascript-remix'
|
|
854
881
|
| 'javascript-sveltekit'
|
|
855
882
|
| 'apple-ios'
|
|
@@ -1011,6 +1038,7 @@ async function askForWizardLogin(options: {
|
|
|
1011
1038
|
promoCode?: string;
|
|
1012
1039
|
platform?:
|
|
1013
1040
|
| 'javascript-nextjs'
|
|
1041
|
+
| 'javascript-nuxt'
|
|
1014
1042
|
| 'javascript-remix'
|
|
1015
1043
|
| 'javascript-sveltekit'
|
|
1016
1044
|
| 'apple-ios'
|
|
@@ -1413,6 +1441,24 @@ export async function askShouldCreateExamplePage(
|
|
|
1413
1441
|
);
|
|
1414
1442
|
}
|
|
1415
1443
|
|
|
1444
|
+
export async function askShouldCreateExampleComponent(): Promise<boolean> {
|
|
1445
|
+
return traceStep('ask-create-example-component', () =>
|
|
1446
|
+
abortIfCancelled(
|
|
1447
|
+
clack.select({
|
|
1448
|
+
message: `Do you want to create an example component to test your Sentry setup?`,
|
|
1449
|
+
options: [
|
|
1450
|
+
{
|
|
1451
|
+
value: true,
|
|
1452
|
+
label: 'Yes',
|
|
1453
|
+
hint: 'Recommended - Check your git status before committing!',
|
|
1454
|
+
},
|
|
1455
|
+
{ value: false, label: 'No' },
|
|
1456
|
+
],
|
|
1457
|
+
}),
|
|
1458
|
+
),
|
|
1459
|
+
);
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1416
1462
|
export async function featureSelectionPrompt<F extends ReadonlyArray<Feature>>(
|
|
1417
1463
|
features: F,
|
|
1418
1464
|
): Promise<{ [key in F[number]['id']]: boolean }> {
|
|
@@ -1445,3 +1491,18 @@ export async function featureSelectionPrompt<F extends ReadonlyArray<Feature>>(
|
|
|
1445
1491
|
return selectedFeatures as { [key in F[number]['id']]: boolean };
|
|
1446
1492
|
});
|
|
1447
1493
|
}
|
|
1494
|
+
|
|
1495
|
+
export async function askShouldAddPackageOverride(
|
|
1496
|
+
pkgName: string,
|
|
1497
|
+
pkgVersion: string,
|
|
1498
|
+
): Promise<boolean> {
|
|
1499
|
+
return traceStep(`ask-add-package-override`, () =>
|
|
1500
|
+
abortIfCancelled(
|
|
1501
|
+
clack.confirm({
|
|
1502
|
+
message: `Do you want to add an override for ${chalk.cyan(
|
|
1503
|
+
pkgName,
|
|
1504
|
+
)} version ${chalk.cyan(pkgVersion)}?`,
|
|
1505
|
+
}),
|
|
1506
|
+
),
|
|
1507
|
+
);
|
|
1508
|
+
}
|
|
@@ -3,6 +3,11 @@ export type PackageDotJson = {
|
|
|
3
3
|
scripts?: Record<string, string | undefined>;
|
|
4
4
|
dependencies?: Record<string, string>;
|
|
5
5
|
devDependencies?: Record<string, string>;
|
|
6
|
+
resolutions?: Record<string, string>;
|
|
7
|
+
overrides?: Record<string, string>;
|
|
8
|
+
pnpm?: {
|
|
9
|
+
overrides?: Record<string, string>;
|
|
10
|
+
};
|
|
6
11
|
};
|
|
7
12
|
|
|
8
13
|
type NpmPackage = {
|