@sentry/wizard 3.35.0 → 3.37.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 +12 -0
- package/dist/e2e-tests/tests/nuxt-3.test.js +45 -25
- package/dist/e2e-tests/tests/nuxt-3.test.js.map +1 -1
- package/dist/e2e-tests/tests/nuxt-4.test.js +45 -25
- package/dist/e2e-tests/tests/nuxt-4.test.js.map +1 -1
- package/dist/e2e-tests/utils/index.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/nuxt/nuxt-wizard.js +36 -23
- package/dist/src/nuxt/nuxt-wizard.js.map +1 -1
- package/dist/src/nuxt/sdk-setup.d.ts +8 -1
- package/dist/src/nuxt/sdk-setup.js +149 -35
- package/dist/src/nuxt/sdk-setup.js.map +1 -1
- package/dist/src/nuxt/templates.d.ts +1 -1
- package/dist/src/nuxt/templates.js +5 -3
- package/dist/src/nuxt/templates.js.map +1 -1
- package/dist/src/nuxt/types.d.ts +2 -0
- package/dist/src/nuxt/types.js +10 -0
- package/dist/src/nuxt/types.js.map +1 -0
- package/dist/src/nuxt/utils.js +42 -6
- package/dist/src/nuxt/utils.js.map +1 -1
- package/dist/src/utils/clack-utils.d.ts +9 -1
- package/dist/src/utils/clack-utils.js +81 -23
- 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.js +10 -1
- package/dist/test/nuxt/templates.test.js.map +1 -1
- package/e2e-tests/test-applications/nuxt-4-test-app/README.md +75 -0
- package/e2e-tests/test-applications/nuxt-4-test-app/nuxt.config.ts +6 -0
- package/e2e-tests/test-applications/nuxt-4-test-app/package.json +18 -0
- package/e2e-tests/test-applications/nuxt-4-test-app/public/favicon.ico +0 -0
- package/e2e-tests/test-applications/nuxt-4-test-app/public/robots.txt +1 -0
- package/e2e-tests/tests/nuxt-3.test.ts +23 -3
- package/e2e-tests/tests/nuxt-4.test.ts +22 -2
- package/e2e-tests/utils/index.ts +4 -1
- package/package.json +1 -1
- package/src/android/templates.ts +0 -2
- package/src/nuxt/nuxt-wizard.ts +23 -5
- package/src/nuxt/sdk-setup.ts +166 -30
- package/src/nuxt/templates.ts +15 -8
- package/src/nuxt/types.ts +8 -0
- package/src/nuxt/utils.ts +17 -7
- package/src/utils/clack-utils.ts +55 -6
- package/src/utils/package-json.ts +5 -0
- package/src/utils/package-manager.ts +66 -0
- package/test/nuxt/templates.test.ts +33 -6
package/src/nuxt/sdk-setup.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// @ts-expect-error - clack is ESM and TS complains about that. It works though
|
|
2
|
-
import clack from '@clack/prompts';
|
|
2
|
+
import * as clack from '@clack/prompts';
|
|
3
3
|
import * as Sentry from '@sentry/node';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
// @ts-expect-error - magicast is ESM and TS complains about that. It works though
|
|
7
|
-
import { loadFile, generateCode
|
|
7
|
+
import { loadFile, generateCode } from 'magicast';
|
|
8
8
|
// @ts-expect-error - magicast is ESM and TS complains about that. It works though
|
|
9
9
|
import { addNuxtModule } from 'magicast/helpers';
|
|
10
10
|
import path from 'path';
|
|
@@ -15,12 +15,19 @@ import {
|
|
|
15
15
|
getSentryConfigContents,
|
|
16
16
|
} from './templates';
|
|
17
17
|
import {
|
|
18
|
-
abort,
|
|
19
18
|
abortIfCancelled,
|
|
19
|
+
askShouldAddPackageOverride,
|
|
20
|
+
askShouldInstallPackage,
|
|
20
21
|
featureSelectionPrompt,
|
|
22
|
+
installPackage,
|
|
21
23
|
isUsingTypeScript,
|
|
24
|
+
opn,
|
|
22
25
|
} from '../utils/clack-utils';
|
|
23
26
|
import { traceStep } from '../telemetry';
|
|
27
|
+
import { lt, SemVer } from 'semver';
|
|
28
|
+
import { PackageManager, PNPM } from '../utils/package-manager';
|
|
29
|
+
import { hasPackageInstalled, PackageDotJson } from '../utils/package-json';
|
|
30
|
+
import { deploymentPlatforms, DeploymentPlatform } from './types';
|
|
24
31
|
|
|
25
32
|
const possibleNuxtConfig = [
|
|
26
33
|
'nuxt.config.js',
|
|
@@ -54,10 +61,40 @@ export async function getNuxtConfig(): Promise<string> {
|
|
|
54
61
|
return path.join(process.cwd(), configFile);
|
|
55
62
|
}
|
|
56
63
|
|
|
64
|
+
export async function askDeploymentPlatform(): Promise<
|
|
65
|
+
DeploymentPlatform | symbol
|
|
66
|
+
> {
|
|
67
|
+
return await abortIfCancelled(
|
|
68
|
+
clack.select({
|
|
69
|
+
message: 'Please select your deployment platform.',
|
|
70
|
+
options: deploymentPlatforms.map((platform) => ({
|
|
71
|
+
value: platform,
|
|
72
|
+
label: `${platform.charAt(0).toUpperCase()}${platform.slice(1)}`,
|
|
73
|
+
})),
|
|
74
|
+
}),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
57
78
|
export async function addSDKModule(
|
|
58
79
|
config: string,
|
|
59
80
|
options: { org: string; project: string; url: string; selfHosted: boolean },
|
|
81
|
+
deploymentPlatform: DeploymentPlatform | symbol,
|
|
60
82
|
): Promise<void> {
|
|
83
|
+
const shouldTopLevelImport =
|
|
84
|
+
deploymentPlatform === 'vercel' || deploymentPlatform === 'netlify';
|
|
85
|
+
|
|
86
|
+
if (shouldTopLevelImport) {
|
|
87
|
+
clack.log.warn(
|
|
88
|
+
`Sentry needs to be initialized before the application starts. ${chalk.cyan(
|
|
89
|
+
`${deploymentPlatform
|
|
90
|
+
.charAt(0)
|
|
91
|
+
.toUpperCase()}${deploymentPlatform.slice(1)}`,
|
|
92
|
+
)} does not support this yet.\n\nWe will inject the Sentry server-side config at the top of your Nuxt server entry file instead.\n\nThis comes with some restrictions, for more info see:\n\n${chalk.underline(
|
|
93
|
+
'https://docs.sentry.io/platforms/javascript/guides/nuxt/install/top-level-import/',
|
|
94
|
+
)} `,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
61
98
|
try {
|
|
62
99
|
const mod = await loadFile(config);
|
|
63
100
|
|
|
@@ -67,6 +104,9 @@ export async function addSDKModule(
|
|
|
67
104
|
project: options.project,
|
|
68
105
|
...(options.selfHosted && { url: options.url }),
|
|
69
106
|
},
|
|
107
|
+
...(shouldTopLevelImport && {
|
|
108
|
+
autoInjectServerSentry: 'top-level-import',
|
|
109
|
+
}),
|
|
70
110
|
});
|
|
71
111
|
addNuxtModule(mod, '@sentry/nuxt/module', 'sourcemap', {
|
|
72
112
|
client: 'hidden',
|
|
@@ -80,33 +120,31 @@ export async function addSDKModule(
|
|
|
80
120
|
`Added Sentry Nuxt Module to ${chalk.cyan(path.basename(config))}.`,
|
|
81
121
|
);
|
|
82
122
|
} catch (e: unknown) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
await abort('Exiting Wizard');
|
|
109
|
-
}
|
|
123
|
+
clack.log.error(
|
|
124
|
+
'Error while adding the Sentry Nuxt Module to the Nuxt config.',
|
|
125
|
+
);
|
|
126
|
+
clack.log.info(
|
|
127
|
+
chalk.dim(
|
|
128
|
+
typeof e === 'object' && e != null && 'toString' in e
|
|
129
|
+
? e.toString()
|
|
130
|
+
: typeof e === 'string'
|
|
131
|
+
? e
|
|
132
|
+
: 'Unknown error',
|
|
133
|
+
),
|
|
134
|
+
);
|
|
135
|
+
Sentry.captureException(
|
|
136
|
+
'Error while setting up the Nuxt Module in nuxt config',
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
clack.log.warn(
|
|
140
|
+
`Please add the following settings to ${chalk.cyan(
|
|
141
|
+
path.basename(config),
|
|
142
|
+
)}:`,
|
|
143
|
+
);
|
|
144
|
+
// eslint-disable-next-line no-console
|
|
145
|
+
console.log(
|
|
146
|
+
`\n\n${getNuxtModuleFallbackTemplate(options, shouldTopLevelImport)}\n\n`,
|
|
147
|
+
);
|
|
110
148
|
}
|
|
111
149
|
}
|
|
112
150
|
|
|
@@ -207,3 +245,101 @@ export async function createConfigFiles(dsn: string) {
|
|
|
207
245
|
});
|
|
208
246
|
}
|
|
209
247
|
}
|
|
248
|
+
|
|
249
|
+
export async function addNuxtOverrides(
|
|
250
|
+
packageJson: PackageDotJson,
|
|
251
|
+
packageManager: PackageManager,
|
|
252
|
+
nuxtMinVer: SemVer | null,
|
|
253
|
+
) {
|
|
254
|
+
const isPNPM = PNPM.detect();
|
|
255
|
+
|
|
256
|
+
const overrides = [
|
|
257
|
+
{
|
|
258
|
+
pkgName: '@vercel/nft',
|
|
259
|
+
pkgVersion: '^0.27.4',
|
|
260
|
+
},
|
|
261
|
+
...(nuxtMinVer && lt(nuxtMinVer, '3.14.0')
|
|
262
|
+
? [{ pkgName: 'ofetch', pkgVersion: '^1.4.0' }]
|
|
263
|
+
: []),
|
|
264
|
+
];
|
|
265
|
+
|
|
266
|
+
clack.log.warn(
|
|
267
|
+
`To ensure Sentry can properly instrument your code it needs to add version overrides for some Nuxt dependencies${
|
|
268
|
+
isPNPM ? ` and install ${chalk.cyan('import-in-the-middle')}.` : '.'
|
|
269
|
+
}\n\nFor more info see: ${chalk.underline(
|
|
270
|
+
'https://github.com/getsentry/sentry-javascript/issues/14514',
|
|
271
|
+
)}${
|
|
272
|
+
isPNPM
|
|
273
|
+
? `\n\nand ${chalk.underline(
|
|
274
|
+
'https://docs.sentry.io/platforms/javascript/guides/nuxt/troubleshooting/#pnpm-dev-cannot-find-package-import-in-the-middle',
|
|
275
|
+
)}`
|
|
276
|
+
: ''
|
|
277
|
+
}`,
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
for (const { pkgName, pkgVersion } of overrides) {
|
|
281
|
+
const shouldAddOverride = await askShouldAddPackageOverride(
|
|
282
|
+
pkgName,
|
|
283
|
+
pkgVersion,
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
if (shouldAddOverride) {
|
|
287
|
+
await packageManager.addOverride(pkgName, pkgVersion);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (PNPM.detect()) {
|
|
292
|
+
// For pnpm, we want to install iitm
|
|
293
|
+
// See: https://docs.sentry.io/platforms/javascript/guides/nuxt/troubleshooting/#pnpm-dev-cannot-find-package-import-in-the-middle
|
|
294
|
+
const iitmAlreadyInstalled = hasPackageInstalled(
|
|
295
|
+
'import-in-the-middle',
|
|
296
|
+
packageJson,
|
|
297
|
+
);
|
|
298
|
+
Sentry.setTag('iitm-already-installed', iitmAlreadyInstalled);
|
|
299
|
+
|
|
300
|
+
const shouldInstallIitm = await askShouldInstallPackage(
|
|
301
|
+
'import-in-the-middle',
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
if (shouldInstallIitm) {
|
|
305
|
+
await installPackage({
|
|
306
|
+
packageName: 'import-in-the-middle',
|
|
307
|
+
alreadyInstalled: iitmAlreadyInstalled,
|
|
308
|
+
packageManager,
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export async function confirmReadImportDocs(
|
|
315
|
+
deploymentPlatform: DeploymentPlatform | symbol,
|
|
316
|
+
) {
|
|
317
|
+
const canImportSentryServerConfigFile =
|
|
318
|
+
deploymentPlatform !== 'vercel' && deploymentPlatform !== 'netlify';
|
|
319
|
+
|
|
320
|
+
if (!canImportSentryServerConfigFile) {
|
|
321
|
+
// Nothing to do, users have been set up with automatic top-level-import instead
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const docsUrl =
|
|
326
|
+
'https://docs.sentry.io/platforms/javascript/guides/nuxt/install/cli-import/#initializing-sentry-with---import';
|
|
327
|
+
|
|
328
|
+
clack.log.info(
|
|
329
|
+
`After building your Nuxt app, you need to ${chalk.bold(
|
|
330
|
+
'--import',
|
|
331
|
+
)} the Sentry server config file when running your app.\n\nFor more info, see:\n\n${chalk.underline(
|
|
332
|
+
docsUrl,
|
|
333
|
+
)}`,
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
const shouldOpenDocs = await abortIfCancelled(
|
|
337
|
+
clack.confirm({ message: 'Do you want to open the docs?' }),
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
if (shouldOpenDocs) {
|
|
341
|
+
opn(docsUrl, { wait: false }).catch(() => {
|
|
342
|
+
// opn throws in environments that don't have a browser (e.g. remote shells) so we just noop here
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
}
|
package/src/nuxt/templates.ts
CHANGED
|
@@ -14,12 +14,15 @@ export default defineNuxtConfig({
|
|
|
14
14
|
`;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export function getNuxtModuleFallbackTemplate(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
export function getNuxtModuleFallbackTemplate(
|
|
18
|
+
options: {
|
|
19
|
+
org: string;
|
|
20
|
+
project: string;
|
|
21
|
+
url: string;
|
|
22
|
+
selfHosted: boolean;
|
|
23
|
+
},
|
|
24
|
+
shouldTopLevelImport: boolean,
|
|
25
|
+
): string {
|
|
23
26
|
return ` modules: ["@sentry/nuxt/module"],
|
|
24
27
|
sentry: {
|
|
25
28
|
sourceMapsUploadOptions: {
|
|
@@ -27,7 +30,11 @@ export function getNuxtModuleFallbackTemplate(options: {
|
|
|
27
30
|
project: "${options.project}",${
|
|
28
31
|
options.selfHosted ? `\n url: "${options.url}",` : ''
|
|
29
32
|
}
|
|
30
|
-
}
|
|
33
|
+
},${
|
|
34
|
+
shouldTopLevelImport
|
|
35
|
+
? `\n autoInjectServerSentry: "top-level-import",`
|
|
36
|
+
: ''
|
|
37
|
+
}
|
|
31
38
|
},
|
|
32
39
|
sourcemap: { client: "hidden" },`;
|
|
33
40
|
}
|
|
@@ -239,7 +246,7 @@ export function getSentryExampleApiTemplate() {
|
|
|
239
246
|
// Feel free to delete this file.
|
|
240
247
|
import { defineEventHandler } from '#imports';
|
|
241
248
|
|
|
242
|
-
export default defineEventHandler(
|
|
249
|
+
export default defineEventHandler(() => {
|
|
243
250
|
throw new Error("Sentry Example API Route Error");
|
|
244
251
|
});
|
|
245
252
|
`;
|
package/src/nuxt/utils.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
// @ts-ignore - clack is ESM and TS complains about that. It works though
|
|
2
|
+
import * as clack from '@clack/prompts';
|
|
1
3
|
import { gte, minVersion } from 'semver';
|
|
2
4
|
// @ts-expect-error - magicast is ESM and TS complains about that. It works though
|
|
3
5
|
import { loadFile } from 'magicast';
|
|
6
|
+
import { abortIfCancelled } from '../utils/clack-utils';
|
|
4
7
|
|
|
5
8
|
export async function isNuxtV4(
|
|
6
9
|
nuxtConfig: string,
|
|
@@ -18,14 +21,21 @@ export async function isNuxtV4(
|
|
|
18
21
|
// At the time of writing, nuxt 4 is not on its own
|
|
19
22
|
// major yet. We must read the `compatibilityVersion`
|
|
20
23
|
// from the nuxt config.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
try {
|
|
25
|
+
const mod = await loadFile(nuxtConfig);
|
|
26
|
+
const config =
|
|
27
|
+
mod.exports.default.$type === 'function-call'
|
|
28
|
+
? mod.exports.default.$args[0]
|
|
29
|
+
: mod.exports.default;
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
if (config && config.future && config.future.compatibilityVersion === 4) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
} catch {
|
|
35
|
+
// If we cannot parse their config, just ask.
|
|
36
|
+
return await abortIfCancelled(
|
|
37
|
+
clack.confirm({ message: 'Are you using Nuxt version 4?' }),
|
|
38
|
+
);
|
|
29
39
|
}
|
|
30
40
|
|
|
31
41
|
return false;
|
package/src/utils/clack-utils.ts
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
import { debug } from './debug';
|
|
21
21
|
import { fulfillsVersionRange } from './semver';
|
|
22
22
|
|
|
23
|
-
const opn = require('opn') as (
|
|
23
|
+
export const opn = require('opn') as (
|
|
24
24
|
url: string,
|
|
25
25
|
options?: {
|
|
26
26
|
wait?: boolean;
|
|
@@ -355,6 +355,7 @@ export async function installPackage({
|
|
|
355
355
|
alreadyInstalled,
|
|
356
356
|
askBeforeUpdating = true,
|
|
357
357
|
packageNameDisplayLabel,
|
|
358
|
+
packageManager,
|
|
358
359
|
}: {
|
|
359
360
|
/** The string that is passed to the package manager CLI as identifier to install (e.g. `@sentry/nextjs`, or `@sentry/nextjs@^8`) */
|
|
360
361
|
packageName: string;
|
|
@@ -362,6 +363,7 @@ export async function installPackage({
|
|
|
362
363
|
askBeforeUpdating?: boolean;
|
|
363
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`) */
|
|
364
365
|
packageNameDisplayLabel?: string;
|
|
366
|
+
packageManager?: PackageManager;
|
|
365
367
|
}): Promise<{ packageManager?: PackageManager }> {
|
|
366
368
|
return traceStep('install-package', async () => {
|
|
367
369
|
if (alreadyInstalled && askBeforeUpdating) {
|
|
@@ -380,18 +382,18 @@ export async function installPackage({
|
|
|
380
382
|
|
|
381
383
|
const sdkInstallSpinner = clack.spinner();
|
|
382
384
|
|
|
383
|
-
const
|
|
385
|
+
const pkgManager = packageManager || (await getPackageManager());
|
|
384
386
|
|
|
385
387
|
sdkInstallSpinner.start(
|
|
386
388
|
`${alreadyInstalled ? 'Updating' : 'Installing'} ${chalk.bold.cyan(
|
|
387
389
|
packageNameDisplayLabel ?? packageName,
|
|
388
|
-
)} with ${chalk.bold(
|
|
390
|
+
)} with ${chalk.bold(pkgManager.label)}.`,
|
|
389
391
|
);
|
|
390
392
|
|
|
391
393
|
try {
|
|
392
394
|
await new Promise<void>((resolve, reject) => {
|
|
393
395
|
childProcess.exec(
|
|
394
|
-
`${
|
|
396
|
+
`${pkgManager.installCommand} ${packageName} ${pkgManager.flags}`,
|
|
395
397
|
(err, stdout, stderr) => {
|
|
396
398
|
if (err) {
|
|
397
399
|
// Write a log file so we can better troubleshoot issues
|
|
@@ -430,10 +432,10 @@ export async function installPackage({
|
|
|
430
432
|
sdkInstallSpinner.stop(
|
|
431
433
|
`${alreadyInstalled ? 'Updated' : 'Installed'} ${chalk.bold.cyan(
|
|
432
434
|
packageNameDisplayLabel ?? packageName,
|
|
433
|
-
)} with ${chalk.bold(
|
|
435
|
+
)} with ${chalk.bold(pkgManager.label)}.`,
|
|
434
436
|
);
|
|
435
437
|
|
|
436
|
-
return { packageManager };
|
|
438
|
+
return { packageManager: pkgManager };
|
|
437
439
|
});
|
|
438
440
|
}
|
|
439
441
|
|
|
@@ -808,6 +810,26 @@ export async function getPackageDotJson(): Promise<PackageDotJson> {
|
|
|
808
810
|
return packageJson || {};
|
|
809
811
|
}
|
|
810
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
|
+
|
|
811
833
|
export async function getPackageManager(): Promise<PackageManager> {
|
|
812
834
|
const detectedPackageManager = detectPackageManger();
|
|
813
835
|
|
|
@@ -1469,3 +1491,30 @@ export async function featureSelectionPrompt<F extends ReadonlyArray<Feature>>(
|
|
|
1469
1491
|
return selectedFeatures as { [key in F[number]['id']]: boolean };
|
|
1470
1492
|
});
|
|
1471
1493
|
}
|
|
1494
|
+
|
|
1495
|
+
export async function askShouldInstallPackage(
|
|
1496
|
+
pkgName: string,
|
|
1497
|
+
): Promise<boolean> {
|
|
1498
|
+
return traceStep(`ask-install-package`, () =>
|
|
1499
|
+
abortIfCancelled(
|
|
1500
|
+
clack.confirm({
|
|
1501
|
+
message: `Do you want to install ${chalk.cyan(pkgName)}?`,
|
|
1502
|
+
}),
|
|
1503
|
+
),
|
|
1504
|
+
);
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
export async function askShouldAddPackageOverride(
|
|
1508
|
+
pkgName: string,
|
|
1509
|
+
pkgVersion: string,
|
|
1510
|
+
): Promise<boolean> {
|
|
1511
|
+
return traceStep(`ask-add-package-override`, () =>
|
|
1512
|
+
abortIfCancelled(
|
|
1513
|
+
clack.confirm({
|
|
1514
|
+
message: `Do you want to add an override for ${chalk.cyan(
|
|
1515
|
+
pkgName,
|
|
1516
|
+
)} version ${chalk.cyan(pkgVersion)}?`,
|
|
1517
|
+
}),
|
|
1518
|
+
),
|
|
1519
|
+
);
|
|
1520
|
+
}
|
|
@@ -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 = {
|
|
@@ -4,6 +4,7 @@ import * as path from 'path';
|
|
|
4
4
|
|
|
5
5
|
import * as Sentry from '@sentry/node';
|
|
6
6
|
import { traceStep } from '../telemetry';
|
|
7
|
+
import { getPackageDotJson, updatePackageDotJson } from './clack-utils';
|
|
7
8
|
|
|
8
9
|
export interface PackageManager {
|
|
9
10
|
name: string;
|
|
@@ -15,6 +16,7 @@ export interface PackageManager {
|
|
|
15
16
|
runScriptCommand: string;
|
|
16
17
|
flags: string;
|
|
17
18
|
detect: () => boolean;
|
|
19
|
+
addOverride: (pkgName: string, pkgVersion: string) => Promise<void>;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export const BUN: PackageManager = {
|
|
@@ -26,6 +28,18 @@ export const BUN: PackageManager = {
|
|
|
26
28
|
runScriptCommand: 'bun run',
|
|
27
29
|
flags: '',
|
|
28
30
|
detect: () => fs.existsSync(path.join(process.cwd(), BUN.lockFile)),
|
|
31
|
+
addOverride: async (pkgName, pkgVersion): Promise<void> => {
|
|
32
|
+
const packageDotJson = await getPackageDotJson();
|
|
33
|
+
const overrides = packageDotJson.overrides || {};
|
|
34
|
+
|
|
35
|
+
await updatePackageDotJson({
|
|
36
|
+
...packageDotJson,
|
|
37
|
+
overrides: {
|
|
38
|
+
...overrides,
|
|
39
|
+
[pkgName]: pkgVersion,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
},
|
|
29
43
|
};
|
|
30
44
|
export const YARN_V1: PackageManager = {
|
|
31
45
|
name: 'yarn',
|
|
@@ -45,6 +59,18 @@ export const YARN_V1: PackageManager = {
|
|
|
45
59
|
return false;
|
|
46
60
|
}
|
|
47
61
|
},
|
|
62
|
+
addOverride: async (pkgName, pkgVersion): Promise<void> => {
|
|
63
|
+
const packageDotJson = await getPackageDotJson();
|
|
64
|
+
const resolutions = packageDotJson.resolutions || {};
|
|
65
|
+
|
|
66
|
+
await updatePackageDotJson({
|
|
67
|
+
...packageDotJson,
|
|
68
|
+
resolutions: {
|
|
69
|
+
...resolutions,
|
|
70
|
+
[pkgName]: pkgVersion,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
},
|
|
48
74
|
};
|
|
49
75
|
/** YARN V2/3/4 */
|
|
50
76
|
export const YARN_V2: PackageManager = {
|
|
@@ -65,6 +91,18 @@ export const YARN_V2: PackageManager = {
|
|
|
65
91
|
return false;
|
|
66
92
|
}
|
|
67
93
|
},
|
|
94
|
+
addOverride: async (pkgName, pkgVersion): Promise<void> => {
|
|
95
|
+
const packageDotJson = await getPackageDotJson();
|
|
96
|
+
const resolutions = packageDotJson.resolutions || {};
|
|
97
|
+
|
|
98
|
+
await updatePackageDotJson({
|
|
99
|
+
...packageDotJson,
|
|
100
|
+
resolutions: {
|
|
101
|
+
...resolutions,
|
|
102
|
+
[pkgName]: pkgVersion,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
},
|
|
68
106
|
};
|
|
69
107
|
export const PNPM: PackageManager = {
|
|
70
108
|
name: 'pnpm',
|
|
@@ -75,6 +113,22 @@ export const PNPM: PackageManager = {
|
|
|
75
113
|
runScriptCommand: 'pnpm',
|
|
76
114
|
flags: '--ignore-workspace-root-check',
|
|
77
115
|
detect: () => fs.existsSync(path.join(process.cwd(), PNPM.lockFile)),
|
|
116
|
+
addOverride: async (pkgName, pkgVersion): Promise<void> => {
|
|
117
|
+
const packageDotJson = await getPackageDotJson();
|
|
118
|
+
const pnpm = packageDotJson.pnpm || {};
|
|
119
|
+
const overrides = pnpm.overrides || {};
|
|
120
|
+
|
|
121
|
+
await updatePackageDotJson({
|
|
122
|
+
...packageDotJson,
|
|
123
|
+
pnpm: {
|
|
124
|
+
...pnpm,
|
|
125
|
+
overrides: {
|
|
126
|
+
...overrides,
|
|
127
|
+
[pkgName]: pkgVersion,
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
},
|
|
78
132
|
};
|
|
79
133
|
export const NPM: PackageManager = {
|
|
80
134
|
name: 'npm',
|
|
@@ -85,6 +139,18 @@ export const NPM: PackageManager = {
|
|
|
85
139
|
runScriptCommand: 'npm run',
|
|
86
140
|
flags: '',
|
|
87
141
|
detect: () => fs.existsSync(path.join(process.cwd(), NPM.lockFile)),
|
|
142
|
+
addOverride: async (pkgName, pkgVersion): Promise<void> => {
|
|
143
|
+
const packageDotJson = await getPackageDotJson();
|
|
144
|
+
const overrides = packageDotJson.overrides || {};
|
|
145
|
+
|
|
146
|
+
await updatePackageDotJson({
|
|
147
|
+
...packageDotJson,
|
|
148
|
+
overrides: {
|
|
149
|
+
...overrides,
|
|
150
|
+
[pkgName]: pkgVersion,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
},
|
|
88
154
|
};
|
|
89
155
|
|
|
90
156
|
export const packageManagers = [BUN, YARN_V1, YARN_V2, PNPM, NPM];
|
|
@@ -206,12 +206,38 @@ describe('Nuxt code templates', () => {
|
|
|
206
206
|
|
|
207
207
|
describe('getNuxtModuleFallbackTemplate', () => {
|
|
208
208
|
it('generates configuration options for the nuxt config', () => {
|
|
209
|
-
const template = getNuxtModuleFallbackTemplate(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
209
|
+
const template = getNuxtModuleFallbackTemplate(
|
|
210
|
+
{
|
|
211
|
+
org: 'my-org',
|
|
212
|
+
project: 'my-project',
|
|
213
|
+
url: 'https://sentry.io',
|
|
214
|
+
selfHosted: false,
|
|
215
|
+
},
|
|
216
|
+
false,
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
expect(template).toMatchInlineSnapshot(`
|
|
220
|
+
" modules: ["@sentry/nuxt/module"],
|
|
221
|
+
sentry: {
|
|
222
|
+
sourceMapsUploadOptions: {
|
|
223
|
+
org: "my-org",
|
|
224
|
+
project: "my-project",
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
sourcemap: { client: "hidden" },"
|
|
228
|
+
`);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('generates configuration options for the nuxt config with top level import', () => {
|
|
232
|
+
const template = getNuxtModuleFallbackTemplate(
|
|
233
|
+
{
|
|
234
|
+
org: 'my-org',
|
|
235
|
+
project: 'my-project',
|
|
236
|
+
url: 'https://sentry.io',
|
|
237
|
+
selfHosted: false,
|
|
238
|
+
},
|
|
239
|
+
true,
|
|
240
|
+
);
|
|
215
241
|
|
|
216
242
|
expect(template).toMatchInlineSnapshot(`
|
|
217
243
|
" modules: ["@sentry/nuxt/module"],
|
|
@@ -220,6 +246,7 @@ describe('Nuxt code templates', () => {
|
|
|
220
246
|
org: "my-org",
|
|
221
247
|
project: "my-project",
|
|
222
248
|
},
|
|
249
|
+
autoInjectServerSentry: "top-level-import",
|
|
223
250
|
},
|
|
224
251
|
sourcemap: { client: "hidden" },"
|
|
225
252
|
`);
|