@sentry/wizard 3.27.0 → 3.29.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 +13 -0
- package/dist/package.json +1 -1
- package/dist/src/nextjs/nextjs-wizard.js +56 -8
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/nextjs/templates.js +2 -2
- package/dist/src/nextjs/templates.js.map +1 -1
- package/dist/src/react-native/react-native-wizard.js +4 -1
- package/dist/src/react-native/react-native-wizard.js.map +1 -1
- package/dist/src/remix/remix-wizard.d.ts +1 -1
- package/dist/src/remix/remix-wizard.js +27 -11
- package/dist/src/remix/remix-wizard.js.map +1 -1
- package/dist/src/remix/sdk-setup.d.ts +24 -3
- package/dist/src/remix/sdk-setup.js +95 -61
- package/dist/src/remix/sdk-setup.js.map +1 -1
- package/dist/src/sveltekit/sdk-setup.js +64 -43
- package/dist/src/sveltekit/sdk-setup.js.map +1 -1
- package/dist/src/sveltekit/sveltekit-wizard.d.ts +1 -1
- package/dist/src/sveltekit/sveltekit-wizard.js +3 -1
- package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
- package/dist/src/sveltekit/templates.d.ts +8 -2
- package/dist/src/sveltekit/templates.js +11 -5
- package/dist/src/sveltekit/templates.js.map +1 -1
- package/dist/src/utils/clack-utils.d.ts +3 -0
- package/dist/src/utils/clack-utils.js +59 -1
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/dist/test/remix/client-entry.test.d.ts +1 -0
- package/dist/test/remix/client-entry.test.js +41 -0
- package/dist/test/remix/client-entry.test.js.map +1 -0
- package/dist/test/remix/server-instrumentation.test.d.ts +1 -0
- package/dist/test/remix/server-instrumentation.test.js +22 -0
- package/dist/test/remix/server-instrumentation.test.js.map +1 -0
- package/dist/test/sveltekit/templates.test.d.ts +1 -0
- package/dist/test/sveltekit/templates.test.js +43 -0
- package/dist/test/sveltekit/templates.test.js.map +1 -0
- package/package.json +1 -1
- package/src/nextjs/nextjs-wizard.ts +48 -3
- package/src/nextjs/templates.ts +12 -3
- package/src/react-native/react-native-wizard.ts +4 -0
- package/src/remix/remix-wizard.ts +32 -6
- package/src/remix/sdk-setup.ts +145 -48
- package/src/sveltekit/sdk-setup.ts +100 -22
- package/src/sveltekit/sveltekit-wizard.ts +4 -1
- package/src/sveltekit/templates.ts +36 -10
- package/src/utils/clack-utils.ts +47 -1
- package/test/remix/client-entry.test.ts +122 -0
- package/test/remix/server-instrumentation.test.ts +38 -0
- package/test/sveltekit/templates.test.ts +152 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
var sdk_setup_1 = require("../../src/remix/sdk-setup");
|
|
4
|
+
describe('generateServerInstrumentationFile', function () {
|
|
5
|
+
it('should generate server instrumentation file', function () {
|
|
6
|
+
var result = (0, sdk_setup_1.generateServerInstrumentationFile)('https://sentry.io/123', {
|
|
7
|
+
performance: true,
|
|
8
|
+
replay: true,
|
|
9
|
+
});
|
|
10
|
+
expect(result.instrumentationFileMod.generate().code)
|
|
11
|
+
.toMatchInlineSnapshot("\n \"import * as Sentry from \"@sentry/remix\";\n\n Sentry.init({\n dsn: \"https://sentry.io/123\",\n tracesSampleRate: 1,\n autoInstrumentRemix: true\n })\"\n ");
|
|
12
|
+
});
|
|
13
|
+
it('should generate server instrumentation file when performance is disabled', function () {
|
|
14
|
+
var result = (0, sdk_setup_1.generateServerInstrumentationFile)('https://sentry.io/123', {
|
|
15
|
+
performance: false,
|
|
16
|
+
replay: true,
|
|
17
|
+
});
|
|
18
|
+
expect(result.instrumentationFileMod.generate().code)
|
|
19
|
+
.toMatchInlineSnapshot("\n \"import * as Sentry from \"@sentry/remix\";\n\n Sentry.init({\n dsn: \"https://sentry.io/123\",\n autoInstrumentRemix: true\n })\"\n ");
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=server-instrumentation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-instrumentation.test.js","sourceRoot":"","sources":["../../../test/remix/server-instrumentation.test.ts"],"names":[],"mappings":";;AAAA,uDAA8E;AAE9E,QAAQ,CAAC,mCAAmC,EAAE;IAC5C,EAAE,CAAC,6CAA6C,EAAE;QAChD,IAAM,MAAM,GAAG,IAAA,6CAAiC,EAAC,uBAAuB,EAAE;YACxE,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC;aAClD,qBAAqB,CAAC,+MAQxB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE;QAC7E,IAAM,MAAM,GAAG,IAAA,6CAAiC,EAAC,uBAAuB,EAAE;YACxE,WAAW,EAAE,KAAK;YAClB,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC;aAClD,qBAAqB,CAAC,+KAOxB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { generateServerInstrumentationFile } from '../../src/remix/sdk-setup';\n\ndescribe('generateServerInstrumentationFile', () => {\n it('should generate server instrumentation file', () => {\n const result = generateServerInstrumentationFile('https://sentry.io/123', {\n performance: true,\n replay: true,\n });\n\n expect(result.instrumentationFileMod.generate().code)\n .toMatchInlineSnapshot(`\n \"import * as Sentry from \"@sentry/remix\";\n\n Sentry.init({\n dsn: \"https://sentry.io/123\",\n tracesSampleRate: 1,\n autoInstrumentRemix: true\n })\"\n `);\n });\n\n it('should generate server instrumentation file when performance is disabled', () => {\n const result = generateServerInstrumentationFile('https://sentry.io/123', {\n performance: false,\n replay: true,\n });\n\n expect(result.instrumentationFileMod.generate().code)\n .toMatchInlineSnapshot(`\n \"import * as Sentry from \"@sentry/remix\";\n\n Sentry.init({\n dsn: \"https://sentry.io/123\",\n autoInstrumentRemix: true\n })\"\n `);\n });\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
var templates_1 = require("../../src/sveltekit/templates");
|
|
4
|
+
describe('getClientHooksTemplate', function () {
|
|
5
|
+
it('should generate client hooks template with all features enabled', function () {
|
|
6
|
+
var result = (0, templates_1.getClientHooksTemplate)('https://sentry.io/123', {
|
|
7
|
+
performance: true,
|
|
8
|
+
replay: true,
|
|
9
|
+
});
|
|
10
|
+
expect(result).toMatchInlineSnapshot("\n \"import { handleErrorWithSentry, replayIntegration } from \"@sentry/sveltekit\";\n import * as Sentry from '@sentry/sveltekit';\n\n Sentry.init({\n dsn: 'https://sentry.io/123',\n\n tracesSampleRate: 1.0,\n\n // This sets the sample rate to be 10%. You may want this to be 100% while\n // in development and sample at a lower rate in production\n replaysSessionSampleRate: 0.1,\n\n // If the entire session is not sampled, use the below sample rate to sample\n // sessions when an error occurs.\n replaysOnErrorSampleRate: 1.0,\n\n // If you don't want to use Session Replay, just remove the line below:\n integrations: [replayIntegration()],\n });\n\n // If you have a custom error handler, pass it to `handleErrorWithSentry`\n export const handleError = handleErrorWithSentry();\n \"\n ");
|
|
11
|
+
});
|
|
12
|
+
it('should generate client hooks template when performance disabled', function () {
|
|
13
|
+
var result = (0, templates_1.getClientHooksTemplate)('https://sentry.io/123', {
|
|
14
|
+
performance: false,
|
|
15
|
+
replay: true,
|
|
16
|
+
});
|
|
17
|
+
expect(result).toMatchInlineSnapshot("\n \"import { handleErrorWithSentry, replayIntegration } from \"@sentry/sveltekit\";\n import * as Sentry from '@sentry/sveltekit';\n\n Sentry.init({\n dsn: 'https://sentry.io/123',\n\n // This sets the sample rate to be 10%. You may want this to be 100% while\n // in development and sample at a lower rate in production\n replaysSessionSampleRate: 0.1,\n\n // If the entire session is not sampled, use the below sample rate to sample\n // sessions when an error occurs.\n replaysOnErrorSampleRate: 1.0,\n\n // If you don't want to use Session Replay, just remove the line below:\n integrations: [replayIntegration()],\n });\n\n // If you have a custom error handler, pass it to `handleErrorWithSentry`\n export const handleError = handleErrorWithSentry();\n \"\n ");
|
|
18
|
+
});
|
|
19
|
+
it('should generate client hooks template when replay disabled', function () {
|
|
20
|
+
var result = (0, templates_1.getClientHooksTemplate)('https://sentry.io/123', {
|
|
21
|
+
performance: true,
|
|
22
|
+
replay: false,
|
|
23
|
+
});
|
|
24
|
+
expect(result).toMatchInlineSnapshot("\n \"import { handleErrorWithSentry, replayIntegration } from \"@sentry/sveltekit\";\n import * as Sentry from '@sentry/sveltekit';\n\n Sentry.init({\n dsn: 'https://sentry.io/123',\n\n tracesSampleRate: 1.0,\n\n\n });\n\n // If you have a custom error handler, pass it to `handleErrorWithSentry`\n export const handleError = handleErrorWithSentry();\n \"\n ");
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
describe('getServerHooksTemplate', function () {
|
|
28
|
+
it('should generate server hooks template with all features enabled', function () {
|
|
29
|
+
var result = (0, templates_1.getServerHooksTemplate)('https://sentry.io/123', {
|
|
30
|
+
performance: true,
|
|
31
|
+
replay: true,
|
|
32
|
+
});
|
|
33
|
+
expect(result).toMatchInlineSnapshot("\n \"import { sequence } from \"@sveltejs/kit/hooks\";\n import { handleErrorWithSentry, sentryHandle } from \"@sentry/sveltekit\";\n import * as Sentry from '@sentry/sveltekit';\n\n Sentry.init({\n dsn: 'https://sentry.io/123',\n\n tracesSampleRate: 1.0,\n\n // uncomment the line below to enable Spotlight (https://spotlightjs.com)\n // spotlight: import.meta.env.DEV,\n });\n\n // If you have custom handlers, make sure to place them after `sentryHandle()` in the `sequence` function.\n export const handle = sequence(sentryHandle());\n\n // If you have a custom error handler, pass it to `handleErrorWithSentry`\n export const handleError = handleErrorWithSentry();\n \"\n ");
|
|
34
|
+
});
|
|
35
|
+
it('should generate server hooks template when performance disabled', function () {
|
|
36
|
+
var result = (0, templates_1.getServerHooksTemplate)('https://sentry.io/123', {
|
|
37
|
+
performance: false,
|
|
38
|
+
replay: true,
|
|
39
|
+
});
|
|
40
|
+
expect(result).toMatchInlineSnapshot("\n \"import { sequence } from \"@sveltejs/kit/hooks\";\n import { handleErrorWithSentry, sentryHandle } from \"@sentry/sveltekit\";\n import * as Sentry from '@sentry/sveltekit';\n\n Sentry.init({\n dsn: 'https://sentry.io/123',\n\n // uncomment the line below to enable Spotlight (https://spotlightjs.com)\n // spotlight: import.meta.env.DEV,\n });\n\n // If you have custom handlers, make sure to place them after `sentryHandle()` in the `sequence` function.\n export const handle = sequence(sentryHandle());\n\n // If you have a custom error handler, pass it to `handleErrorWithSentry`\n export const handleError = handleErrorWithSentry();\n \"\n ");
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=templates.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.test.js","sourceRoot":"","sources":["../../../test/sveltekit/templates.test.ts"],"names":[],"mappings":";;AAAA,2DAGuC;AAEvC,QAAQ,CAAC,wBAAwB,EAAE;IACjC,EAAE,CAAC,iEAAiE,EAAE;QACpE,IAAM,MAAM,GAAG,IAAA,kCAAsB,EAAC,uBAAuB,EAAE;YAC7D,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,s4BAwBpC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE;QACpE,IAAM,MAAM,GAAG,IAAA,kCAAsB,EAAC,uBAAuB,EAAE;YAC7D,WAAW,EAAE,KAAK;YAClB,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,o2BAsBpC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE;QAC/D,IAAM,MAAM,GAAG,IAAA,kCAAsB,EAAC,uBAAuB,EAAE;YAC7D,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE,KAAK;SACd,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,4ZAepC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,wBAAwB,EAAE;IACjC,EAAE,CAAC,iEAAiE,EAAE;QACpE,IAAM,MAAM,GAAG,IAAA,kCAAsB,EAAC,uBAAuB,EAAE;YAC7D,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,wvBAoBpC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE;QACpE,IAAM,MAAM,GAAG,IAAA,kCAAsB,EAAC,uBAAuB,EAAE;YAC7D,WAAW,EAAE,KAAK;YAClB,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,stBAkBpC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import {\n getClientHooksTemplate,\n getServerHooksTemplate,\n} from '../../src/sveltekit/templates';\n\ndescribe('getClientHooksTemplate', () => {\n it('should generate client hooks template with all features enabled', () => {\n const result = getClientHooksTemplate('https://sentry.io/123', {\n performance: true,\n replay: true,\n });\n\n expect(result).toMatchInlineSnapshot(`\n \"import { handleErrorWithSentry, replayIntegration } from \"@sentry/sveltekit\";\n import * as Sentry from '@sentry/sveltekit';\n\n Sentry.init({\n dsn: 'https://sentry.io/123',\n\n tracesSampleRate: 1.0,\n\n // This sets the sample rate to be 10%. You may want this to be 100% while\n // in development and sample at a lower rate in production\n replaysSessionSampleRate: 0.1,\n\n // If the entire session is not sampled, use the below sample rate to sample\n // sessions when an error occurs.\n replaysOnErrorSampleRate: 1.0,\n\n // If you don't want to use Session Replay, just remove the line below:\n integrations: [replayIntegration()],\n });\n\n // If you have a custom error handler, pass it to \\`handleErrorWithSentry\\`\n export const handleError = handleErrorWithSentry();\n \"\n `);\n });\n\n it('should generate client hooks template when performance disabled', () => {\n const result = getClientHooksTemplate('https://sentry.io/123', {\n performance: false,\n replay: true,\n });\n\n expect(result).toMatchInlineSnapshot(`\n \"import { handleErrorWithSentry, replayIntegration } from \"@sentry/sveltekit\";\n import * as Sentry from '@sentry/sveltekit';\n\n Sentry.init({\n dsn: 'https://sentry.io/123',\n\n // This sets the sample rate to be 10%. You may want this to be 100% while\n // in development and sample at a lower rate in production\n replaysSessionSampleRate: 0.1,\n\n // If the entire session is not sampled, use the below sample rate to sample\n // sessions when an error occurs.\n replaysOnErrorSampleRate: 1.0,\n\n // If you don't want to use Session Replay, just remove the line below:\n integrations: [replayIntegration()],\n });\n\n // If you have a custom error handler, pass it to \\`handleErrorWithSentry\\`\n export const handleError = handleErrorWithSentry();\n \"\n `);\n });\n\n it('should generate client hooks template when replay disabled', () => {\n const result = getClientHooksTemplate('https://sentry.io/123', {\n performance: true,\n replay: false,\n });\n\n expect(result).toMatchInlineSnapshot(`\n \"import { handleErrorWithSentry, replayIntegration } from \"@sentry/sveltekit\";\n import * as Sentry from '@sentry/sveltekit';\n\n Sentry.init({\n dsn: 'https://sentry.io/123',\n\n tracesSampleRate: 1.0,\n\n\n });\n\n // If you have a custom error handler, pass it to \\`handleErrorWithSentry\\`\n export const handleError = handleErrorWithSentry();\n \"\n `);\n });\n});\n\ndescribe('getServerHooksTemplate', () => {\n it('should generate server hooks template with all features enabled', () => {\n const result = getServerHooksTemplate('https://sentry.io/123', {\n performance: true,\n replay: true,\n });\n\n expect(result).toMatchInlineSnapshot(`\n \"import { sequence } from \"@sveltejs/kit/hooks\";\n import { handleErrorWithSentry, sentryHandle } from \"@sentry/sveltekit\";\n import * as Sentry from '@sentry/sveltekit';\n\n Sentry.init({\n dsn: 'https://sentry.io/123',\n\n tracesSampleRate: 1.0,\n\n // uncomment the line below to enable Spotlight (https://spotlightjs.com)\n // spotlight: import.meta.env.DEV,\n });\n\n // If you have custom handlers, make sure to place them after \\`sentryHandle()\\` in the \\`sequence\\` function.\n export const handle = sequence(sentryHandle());\n\n // If you have a custom error handler, pass it to \\`handleErrorWithSentry\\`\n export const handleError = handleErrorWithSentry();\n \"\n `);\n });\n\n it('should generate server hooks template when performance disabled', () => {\n const result = getServerHooksTemplate('https://sentry.io/123', {\n performance: false,\n replay: true,\n });\n\n expect(result).toMatchInlineSnapshot(`\n \"import { sequence } from \"@sveltejs/kit/hooks\";\n import { handleErrorWithSentry, sentryHandle } from \"@sentry/sveltekit\";\n import * as Sentry from '@sentry/sveltekit';\n\n Sentry.init({\n dsn: 'https://sentry.io/123',\n\n // uncomment the line below to enable Spotlight (https://spotlightjs.com)\n // spotlight: import.meta.env.DEV,\n });\n\n // If you have custom handlers, make sure to place them after \\`sentryHandle()\\` in the \\`sequence\\` function.\n export const handle = sequence(sentryHandle());\n\n // If you have a custom error handler, pass it to \\`handleErrorWithSentry\\`\n export const handleError = handleErrorWithSentry();\n \"\n `);\n });\n});\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/wizard",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.29.0",
|
|
4
4
|
"homepage": "https://github.com/getsentry/sentry-wizard",
|
|
5
5
|
"repository": "https://github.com/getsentry/sentry-wizard",
|
|
6
6
|
"description": "Sentry wizard helping you to configure your project",
|
|
@@ -20,9 +20,11 @@ import {
|
|
|
20
20
|
featureSelectionPrompt,
|
|
21
21
|
getOrAskForProjectData,
|
|
22
22
|
getPackageDotJson,
|
|
23
|
+
getPackageManager,
|
|
23
24
|
installPackage,
|
|
24
25
|
isUsingTypeScript,
|
|
25
26
|
printWelcome,
|
|
27
|
+
runPrettierIfInstalled,
|
|
26
28
|
showCopyPasteInstructions,
|
|
27
29
|
} from '../utils/clack-utils';
|
|
28
30
|
import type { SentryProjectData, WizardOptions } from '../utils/types';
|
|
@@ -297,6 +299,25 @@ export async function runNextjsWizardWithTelemetry(
|
|
|
297
299
|
|
|
298
300
|
await addDotEnvSentryBuildPluginFile(authToken);
|
|
299
301
|
|
|
302
|
+
const isLikelyUsingTurbopack = await checkIfLikelyIsUsingTurbopack();
|
|
303
|
+
if (isLikelyUsingTurbopack || isLikelyUsingTurbopack === null) {
|
|
304
|
+
await abortIfCancelled(
|
|
305
|
+
clack.select({
|
|
306
|
+
message: `Warning: The Sentry SDK doesn't yet fully support Turbopack in dev mode. The SDK will not be loaded in the browser, and serverside instrumentation will be inaccurate or incomplete. Production builds will still fully work. ${chalk.bold(
|
|
307
|
+
`To continue this setup, if you are using Turbopack, temporarily remove \`--turbo\` from your dev command until you have verified the SDK is working as expected.`,
|
|
308
|
+
)}`,
|
|
309
|
+
options: [
|
|
310
|
+
{
|
|
311
|
+
label: 'I understand.',
|
|
312
|
+
hint: 'press enter',
|
|
313
|
+
value: true,
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
initialValue: true,
|
|
317
|
+
}),
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
|
|
300
321
|
const mightBeUsingVercel = fs.existsSync(
|
|
301
322
|
path.join(process.cwd(), 'vercel.json'),
|
|
302
323
|
);
|
|
@@ -309,13 +330,20 @@ export async function runNextjsWizardWithTelemetry(
|
|
|
309
330
|
await traceStep('configure-ci', () => configureCI('nextjs', authToken));
|
|
310
331
|
}
|
|
311
332
|
|
|
333
|
+
const pacMan = await getPackageManager();
|
|
334
|
+
await runPrettierIfInstalled();
|
|
335
|
+
|
|
312
336
|
clack.outro(`
|
|
313
337
|
${chalk.green('Successfully installed the Sentry Next.js SDK!')} ${
|
|
314
338
|
shouldCreateExamplePage
|
|
315
|
-
? `\n\nYou can validate your setup by
|
|
316
|
-
|
|
339
|
+
? `\n\nYou can validate your setup by (re)starting your dev environment (e.g. ${chalk.cyan(
|
|
340
|
+
`${pacMan.runScriptCommand} dev`,
|
|
317
341
|
)}) and visiting ${chalk.cyan('"/sentry-example-page"')}`
|
|
318
342
|
: ''
|
|
343
|
+
}${
|
|
344
|
+
shouldCreateExamplePage && isLikelyUsingTurbopack
|
|
345
|
+
? `\nDon't forget to remove \`--turbo\` from your dev command until you have verified the SDK is working. You can safely add it back afterwards.`
|
|
346
|
+
: ''
|
|
319
347
|
}
|
|
320
348
|
|
|
321
349
|
${chalk.dim(
|
|
@@ -346,7 +374,7 @@ async function createOrMergeNextJsFiles(
|
|
|
346
374
|
id: 'replay',
|
|
347
375
|
prompt: `Do you want to enable ${chalk.bold(
|
|
348
376
|
'Sentry Session Replay',
|
|
349
|
-
)} to get reproduction of
|
|
377
|
+
)} to get a video-like reproduction of errors during a user session?`,
|
|
350
378
|
enabledHint: 'recommended, but increases bundle size',
|
|
351
379
|
},
|
|
352
380
|
] as const);
|
|
@@ -925,3 +953,20 @@ async function askShouldEnableReactComponentAnnotation() {
|
|
|
925
953
|
return shouldEnableReactComponentAnnotation;
|
|
926
954
|
});
|
|
927
955
|
}
|
|
956
|
+
|
|
957
|
+
/**
|
|
958
|
+
* Returns true or false depending on whether we think the user is using Turbopack. May return null in case we aren't sure.
|
|
959
|
+
*/
|
|
960
|
+
async function checkIfLikelyIsUsingTurbopack(): Promise<boolean | null> {
|
|
961
|
+
let packageJsonContent: string;
|
|
962
|
+
try {
|
|
963
|
+
packageJsonContent = await fs.promises.readFile(
|
|
964
|
+
path.join(process.cwd(), 'package.json'),
|
|
965
|
+
'utf8',
|
|
966
|
+
);
|
|
967
|
+
} catch {
|
|
968
|
+
return null;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
return packageJsonContent.includes('--turbo');
|
|
972
|
+
}
|
package/src/nextjs/templates.ts
CHANGED
|
@@ -369,7 +369,9 @@ YourCustomErrorComponent.getInitialProps = async (contextData${
|
|
|
369
369
|
export function getInstrumentationHookContent(
|
|
370
370
|
instrumentationHookLocation: 'src' | 'root',
|
|
371
371
|
) {
|
|
372
|
-
return `
|
|
372
|
+
return `import * as Sentry from '@sentry/nextjs';
|
|
373
|
+
|
|
374
|
+
export async function register() {
|
|
373
375
|
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
374
376
|
await import('${
|
|
375
377
|
instrumentationHookLocation === 'root' ? '.' : '..'
|
|
@@ -382,6 +384,8 @@ export function getInstrumentationHookContent(
|
|
|
382
384
|
}/sentry.edge.config');
|
|
383
385
|
}
|
|
384
386
|
}
|
|
387
|
+
|
|
388
|
+
export const onRequestError = Sentry.captureRequestError;
|
|
385
389
|
`;
|
|
386
390
|
}
|
|
387
391
|
|
|
@@ -389,7 +393,9 @@ export function getInstrumentationHookCopyPasteSnippet(
|
|
|
389
393
|
instrumentationHookLocation: 'src' | 'root',
|
|
390
394
|
) {
|
|
391
395
|
return makeCodeSnippet(true, (unchanged, plus) => {
|
|
392
|
-
return unchanged(
|
|
396
|
+
return unchanged(`${plus("import * as Sentry from '@sentry/nextjs';")}
|
|
397
|
+
|
|
398
|
+
export ${plus('async')} function register() {
|
|
393
399
|
${plus(`if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
394
400
|
await import('${
|
|
395
401
|
instrumentationHookLocation === 'root' ? '.' : '..'
|
|
@@ -401,7 +407,10 @@ export function getInstrumentationHookCopyPasteSnippet(
|
|
|
401
407
|
instrumentationHookLocation === 'root' ? '.' : '..'
|
|
402
408
|
}/sentry.edge.config');
|
|
403
409
|
}`)}
|
|
404
|
-
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
${plus('export const onRequestError = Sentry.captureRequestError;')}
|
|
413
|
+
`);
|
|
405
414
|
});
|
|
406
415
|
}
|
|
407
416
|
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
installPackage,
|
|
17
17
|
printWelcome,
|
|
18
18
|
propertiesCliSetupConfig,
|
|
19
|
+
runPrettierIfInstalled,
|
|
19
20
|
} from '../utils/clack-utils';
|
|
20
21
|
import { getPackageVersion, hasPackageInstalled } from '../utils/package-json';
|
|
21
22
|
import { podInstall } from '../apple/cocoapod';
|
|
@@ -212,11 +213,14 @@ Or setup using ${chalk.cyan(
|
|
|
212
213
|
await traceStep('patch-android-files', () => patchAndroidFiles(cliConfig));
|
|
213
214
|
}
|
|
214
215
|
|
|
216
|
+
await runPrettierIfInstalled();
|
|
217
|
+
|
|
215
218
|
const confirmedFirstException = await confirmFirstSentryException(
|
|
216
219
|
sentryUrl,
|
|
217
220
|
orgSlug,
|
|
218
221
|
projectId,
|
|
219
222
|
);
|
|
223
|
+
|
|
220
224
|
Sentry.setTag('user-confirmed-first-error', confirmedFirstException);
|
|
221
225
|
|
|
222
226
|
if (confirmedFirstException) {
|
|
@@ -7,15 +7,17 @@ import {
|
|
|
7
7
|
askShouldCreateExamplePage,
|
|
8
8
|
confirmContinueIfNoOrDirtyGitRepo,
|
|
9
9
|
ensurePackageIsInstalled,
|
|
10
|
+
featureSelectionPrompt,
|
|
10
11
|
getOrAskForProjectData,
|
|
11
12
|
getPackageDotJson,
|
|
12
13
|
installPackage,
|
|
13
14
|
isUsingTypeScript,
|
|
14
15
|
printWelcome,
|
|
15
16
|
rcCliSetupConfig,
|
|
17
|
+
runPrettierIfInstalled,
|
|
16
18
|
} from '../utils/clack-utils';
|
|
17
19
|
import { hasPackageInstalled } from '../utils/package-json';
|
|
18
|
-
import { WizardOptions } from '../utils/types';
|
|
20
|
+
import type { WizardOptions } from '../utils/types';
|
|
19
21
|
import {
|
|
20
22
|
initializeSentryOnEntryClient,
|
|
21
23
|
instrumentSentryOnEntryServer,
|
|
@@ -76,8 +78,22 @@ async function runRemixWizardWithTelemetry(
|
|
|
76
78
|
const isTS = isUsingTypeScript();
|
|
77
79
|
const isV2 = isRemixV2(remixConfig, packageJson);
|
|
78
80
|
const viteConfig = findFile('vite.config');
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
const selectedFeatures = await featureSelectionPrompt([
|
|
82
|
+
{
|
|
83
|
+
id: 'performance',
|
|
84
|
+
prompt: `Do you want to enable ${chalk.bold(
|
|
85
|
+
'Tracing',
|
|
86
|
+
)} to track the performance of your application?`,
|
|
87
|
+
enabledHint: 'recommended',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: 'replay',
|
|
91
|
+
prompt: `Do you want to enable ${chalk.bold(
|
|
92
|
+
'Sentry Session Replay',
|
|
93
|
+
)} to get a video-like reproduction of errors during a user session?`,
|
|
94
|
+
enabledHint: 'recommended, but increases bundle size',
|
|
95
|
+
},
|
|
96
|
+
] as const);
|
|
81
97
|
|
|
82
98
|
if (viteConfig) {
|
|
83
99
|
await traceStep(
|
|
@@ -108,6 +124,8 @@ async function runRemixWizardWithTelemetry(
|
|
|
108
124
|
url: sentryUrl === DEFAULT_URL ? undefined : sentryUrl,
|
|
109
125
|
isHydrogen: isHydrogenApp(packageJson),
|
|
110
126
|
});
|
|
127
|
+
|
|
128
|
+
await addSentryCliConfig({ authToken }, rcCliSetupConfig);
|
|
111
129
|
} catch (e) {
|
|
112
130
|
clack.log
|
|
113
131
|
.warn(`Could not update build script to generate and upload sourcemaps.
|
|
@@ -139,7 +157,7 @@ async function runRemixWizardWithTelemetry(
|
|
|
139
157
|
|
|
140
158
|
await traceStep('Initialize Sentry on client entry', async () => {
|
|
141
159
|
try {
|
|
142
|
-
await initializeSentryOnEntryClient(dsn, isTS);
|
|
160
|
+
await initializeSentryOnEntryClient(dsn, isTS, selectedFeatures);
|
|
143
161
|
} catch (e) {
|
|
144
162
|
clack.log.warn(`Could not initialize Sentry on client entry.
|
|
145
163
|
Please do it manually using instructions from https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/`);
|
|
@@ -151,7 +169,10 @@ async function runRemixWizardWithTelemetry(
|
|
|
151
169
|
|
|
152
170
|
await traceStep('Create server instrumentation file', async () => {
|
|
153
171
|
try {
|
|
154
|
-
instrumentationFile = await createServerInstrumentationFile(
|
|
172
|
+
instrumentationFile = await createServerInstrumentationFile(
|
|
173
|
+
dsn,
|
|
174
|
+
selectedFeatures,
|
|
175
|
+
);
|
|
155
176
|
} catch (e) {
|
|
156
177
|
clack.log.warn(
|
|
157
178
|
'Could not create a server instrumentation file. Please do it manually using instructions from https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/',
|
|
@@ -166,7 +187,10 @@ async function runRemixWizardWithTelemetry(
|
|
|
166
187
|
'Create server instrumentation file and import it',
|
|
167
188
|
async () => {
|
|
168
189
|
try {
|
|
169
|
-
serverFileInstrumented = await insertServerInstrumentationFile(
|
|
190
|
+
serverFileInstrumented = await insertServerInstrumentationFile(
|
|
191
|
+
dsn,
|
|
192
|
+
selectedFeatures,
|
|
193
|
+
);
|
|
170
194
|
} catch (e) {
|
|
171
195
|
clack.log.warn(
|
|
172
196
|
'Could not create a server instrumentation file. Please do it manually using instructions from https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/',
|
|
@@ -216,6 +240,8 @@ async function runRemixWizardWithTelemetry(
|
|
|
216
240
|
});
|
|
217
241
|
}
|
|
218
242
|
|
|
243
|
+
await runPrettierIfInstalled();
|
|
244
|
+
|
|
219
245
|
clack.outro(`
|
|
220
246
|
${chalk.green(
|
|
221
247
|
'Sentry has been successfully configured for your Remix project.',
|
package/src/remix/sdk-setup.ts
CHANGED
|
@@ -76,23 +76,72 @@ export function runRemixReveal(isTS: boolean): void {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
function getInitCallArgs(
|
|
80
|
+
dsn: string,
|
|
81
|
+
type: 'client' | 'server',
|
|
82
|
+
selectedFeatures: {
|
|
83
|
+
performance: boolean;
|
|
84
|
+
replay: boolean;
|
|
85
|
+
},
|
|
86
|
+
) {
|
|
87
|
+
const initCallArgs = {
|
|
88
|
+
dsn,
|
|
89
|
+
} as Record<string, unknown>;
|
|
90
|
+
|
|
91
|
+
// Adding tracing sample rate for both client and server
|
|
92
|
+
if (selectedFeatures.performance) {
|
|
93
|
+
initCallArgs.tracesSampleRate = 1.0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Adding integrations and replay options only for client
|
|
97
|
+
if (
|
|
98
|
+
type === 'client' &&
|
|
99
|
+
(selectedFeatures.performance || selectedFeatures.replay)
|
|
100
|
+
) {
|
|
101
|
+
initCallArgs.integrations = [];
|
|
102
|
+
|
|
103
|
+
if (selectedFeatures.performance) {
|
|
104
|
+
// @ts-expect-error - Adding Proxified AST node to the array
|
|
105
|
+
initCallArgs.integrations.push(
|
|
106
|
+
builders.functionCall(
|
|
107
|
+
'Sentry.browserTracingIntegration',
|
|
108
|
+
builders.raw('{ useEffect, useLocation, useMatches }'),
|
|
109
|
+
),
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (selectedFeatures.replay) {
|
|
114
|
+
// @ts-expect-error - Adding Proxified AST node to the array
|
|
115
|
+
initCallArgs.integrations.push(
|
|
116
|
+
builders.functionCall('Sentry.replayIntegration', {
|
|
117
|
+
maskAllText: true,
|
|
118
|
+
blockAllMedia: true,
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
initCallArgs.replaysSessionSampleRate = 0.1;
|
|
123
|
+
initCallArgs.replaysOnErrorSampleRate = 1.0;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Adding autoInstrumentRemix option only for server
|
|
128
|
+
if (type === 'server') {
|
|
129
|
+
initCallArgs.autoInstrumentRemix = true;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return initCallArgs;
|
|
133
|
+
}
|
|
134
|
+
|
|
79
135
|
function insertClientInitCall(
|
|
80
136
|
dsn: string,
|
|
81
137
|
originalHooksMod: ProxifiedModule<any>,
|
|
138
|
+
selectedFeatures: {
|
|
139
|
+
performance: boolean;
|
|
140
|
+
replay: boolean;
|
|
141
|
+
},
|
|
82
142
|
): void {
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
tracesSampleRate: 1.0,
|
|
86
|
-
replaysSessionSampleRate: 0.1,
|
|
87
|
-
replaysOnErrorSampleRate: 1.0,
|
|
88
|
-
integrations: [
|
|
89
|
-
builders.functionCall(
|
|
90
|
-
'Sentry.browserTracingIntegration',
|
|
91
|
-
builders.raw('{ useEffect, useLocation, useMatches }'),
|
|
92
|
-
),
|
|
93
|
-
builders.functionCall('Sentry.replayIntegration'),
|
|
94
|
-
],
|
|
95
|
-
});
|
|
143
|
+
const initCallArgs = getInitCallArgs(dsn, 'client', selectedFeatures);
|
|
144
|
+
const initCall = builders.functionCall('Sentry.init', initCallArgs);
|
|
96
145
|
|
|
97
146
|
const originalHooksModAST = originalHooksMod.$ast as Program;
|
|
98
147
|
const initCallInsertionIndex =
|
|
@@ -107,7 +156,13 @@ function insertClientInitCall(
|
|
|
107
156
|
);
|
|
108
157
|
}
|
|
109
158
|
|
|
110
|
-
export
|
|
159
|
+
export function generateServerInstrumentationFile(
|
|
160
|
+
dsn: string,
|
|
161
|
+
selectedFeatures: {
|
|
162
|
+
performance: boolean;
|
|
163
|
+
replay: boolean;
|
|
164
|
+
},
|
|
165
|
+
) {
|
|
111
166
|
// create an empty file named `instrument.server.mjs`
|
|
112
167
|
const instrumentationFile = 'instrumentation.server.mjs';
|
|
113
168
|
const instrumentationFileMod = parseModule('');
|
|
@@ -118,11 +173,8 @@ export async function createServerInstrumentationFile(dsn: string) {
|
|
|
118
173
|
local: 'Sentry',
|
|
119
174
|
});
|
|
120
175
|
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
tracesSampleRate: 1.0,
|
|
124
|
-
autoInstrumentRemix: true,
|
|
125
|
-
});
|
|
176
|
+
const initCallArgs = getInitCallArgs(dsn, 'server', selectedFeatures);
|
|
177
|
+
const initCall = builders.functionCall('Sentry.init', initCallArgs);
|
|
126
178
|
|
|
127
179
|
const instrumentationFileModAST = instrumentationFileMod.$ast as Program;
|
|
128
180
|
|
|
@@ -138,13 +190,35 @@ export async function createServerInstrumentationFile(dsn: string) {
|
|
|
138
190
|
generateCode(initCall).code,
|
|
139
191
|
);
|
|
140
192
|
|
|
141
|
-
|
|
193
|
+
return { instrumentationFile, instrumentationFileMod };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export async function createServerInstrumentationFile(
|
|
197
|
+
dsn: string,
|
|
198
|
+
selectedFeatures: {
|
|
199
|
+
performance: boolean;
|
|
200
|
+
replay: boolean;
|
|
201
|
+
},
|
|
202
|
+
) {
|
|
203
|
+
const { instrumentationFile, instrumentationFileMod } =
|
|
204
|
+
generateServerInstrumentationFile(dsn, selectedFeatures);
|
|
205
|
+
|
|
206
|
+
await writeFile(instrumentationFileMod.$ast, instrumentationFile);
|
|
142
207
|
|
|
143
208
|
return instrumentationFile;
|
|
144
209
|
}
|
|
145
210
|
|
|
146
|
-
export async function insertServerInstrumentationFile(
|
|
147
|
-
|
|
211
|
+
export async function insertServerInstrumentationFile(
|
|
212
|
+
dsn: string,
|
|
213
|
+
selectedFeatures: {
|
|
214
|
+
performance: boolean;
|
|
215
|
+
replay: boolean;
|
|
216
|
+
},
|
|
217
|
+
) {
|
|
218
|
+
const instrumentationFile = await createServerInstrumentationFile(
|
|
219
|
+
dsn,
|
|
220
|
+
selectedFeatures,
|
|
221
|
+
);
|
|
148
222
|
|
|
149
223
|
const expressServerPath = await findCustomExpressServerImplementation();
|
|
150
224
|
|
|
@@ -297,9 +371,52 @@ export async function updateBuildScript(args: {
|
|
|
297
371
|
/* eslint-enable @typescript-eslint/no-unsafe-member-access */
|
|
298
372
|
}
|
|
299
373
|
|
|
374
|
+
export function updateEntryClientMod(
|
|
375
|
+
originalEntryClientMod: ProxifiedModule<any>,
|
|
376
|
+
dsn: string,
|
|
377
|
+
selectedFeatures: {
|
|
378
|
+
performance: boolean;
|
|
379
|
+
replay: boolean;
|
|
380
|
+
},
|
|
381
|
+
): ProxifiedModule<any> {
|
|
382
|
+
originalEntryClientMod.imports.$add({
|
|
383
|
+
from: '@sentry/remix',
|
|
384
|
+
imported: '*',
|
|
385
|
+
local: 'Sentry',
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
if (selectedFeatures.performance) {
|
|
389
|
+
originalEntryClientMod.imports.$add({
|
|
390
|
+
from: '@remix-run/react',
|
|
391
|
+
imported: 'useLocation',
|
|
392
|
+
local: 'useLocation',
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
originalEntryClientMod.imports.$add({
|
|
396
|
+
from: '@remix-run/react',
|
|
397
|
+
imported: 'useMatches',
|
|
398
|
+
local: 'useMatches',
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
originalEntryClientMod.imports.$add({
|
|
402
|
+
from: 'react',
|
|
403
|
+
imported: 'useEffect',
|
|
404
|
+
local: 'useEffect',
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
insertClientInitCall(dsn, originalEntryClientMod, selectedFeatures);
|
|
409
|
+
|
|
410
|
+
return originalEntryClientMod;
|
|
411
|
+
}
|
|
412
|
+
|
|
300
413
|
export async function initializeSentryOnEntryClient(
|
|
301
414
|
dsn: string,
|
|
302
415
|
isTS: boolean,
|
|
416
|
+
selectedFeatures: {
|
|
417
|
+
performance: boolean;
|
|
418
|
+
replay: boolean;
|
|
419
|
+
},
|
|
303
420
|
): Promise<void> {
|
|
304
421
|
const clientEntryFilename = `entry.client.${isTS ? 'tsx' : 'jsx'}`;
|
|
305
422
|
|
|
@@ -315,34 +432,14 @@ export async function initializeSentryOnEntryClient(
|
|
|
315
432
|
return;
|
|
316
433
|
}
|
|
317
434
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
originalEntryClientMod.imports.$add({
|
|
325
|
-
from: 'react',
|
|
326
|
-
imported: 'useEffect',
|
|
327
|
-
local: 'useEffect',
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
originalEntryClientMod.imports.$add({
|
|
331
|
-
from: '@remix-run/react',
|
|
332
|
-
imported: 'useLocation',
|
|
333
|
-
local: 'useLocation',
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
originalEntryClientMod.imports.$add({
|
|
337
|
-
from: '@remix-run/react',
|
|
338
|
-
imported: 'useMatches',
|
|
339
|
-
local: 'useMatches',
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
insertClientInitCall(dsn, originalEntryClientMod);
|
|
435
|
+
const updatedEntryClientMod = updateEntryClientMod(
|
|
436
|
+
originalEntryClientMod,
|
|
437
|
+
dsn,
|
|
438
|
+
selectedFeatures,
|
|
439
|
+
);
|
|
343
440
|
|
|
344
441
|
await writeFile(
|
|
345
|
-
|
|
442
|
+
updatedEntryClientMod.$ast,
|
|
346
443
|
path.join(process.cwd(), 'app', clientEntryFilename),
|
|
347
444
|
);
|
|
348
445
|
|