@sentry/wizard
Version:
Sentry wizard helping you to configure your project
219 lines (217 loc) • 10.3 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.runRemixWizard = void 0;
// @ts-expect-error - clack is ESM and TS complains about that. It works though
const prompts_1 = __importDefault(require("@clack/prompts"));
const chalk_1 = __importDefault(require("chalk"));
const Constants_1 = require("../../lib/Constants");
const vite_1 = require("../sourcemaps/tools/vite");
const telemetry_1 = require("../telemetry");
const ast_utils_1 = require("../utils/ast-utils");
const clack_1 = require("../utils/clack");
const debug_1 = require("../utils/debug");
const package_json_1 = require("../utils/package-json");
const mcp_config_1 = require("../utils/clack/mcp-config");
const sdk_example_1 = require("./sdk-example");
const sdk_setup_1 = require("./sdk-setup");
const utils_1 = require("./utils");
async function runRemixWizard(options) {
return (0, telemetry_1.withTelemetry)({
enabled: options.telemetryEnabled,
integration: 'remix',
wizardOptions: options,
}, () => runRemixWizardWithTelemetry(options));
}
exports.runRemixWizard = runRemixWizard;
async function runRemixWizardWithTelemetry(options) {
const { promoCode, telemetryEnabled, forceInstall } = options;
(0, clack_1.printWelcome)({
wizardName: 'Sentry Remix Wizard',
promoCode,
telemetryEnabled,
});
const packageJson = await (0, clack_1.getPackageDotJson)();
if (!(0, sdk_setup_1.isRemixV2)(packageJson)) {
prompts_1.default.log.error(`Sentry only supports Remix v2 and above. Please upgrade your Remix version to use Sentry.`);
return;
}
await (0, clack_1.confirmContinueIfNoOrDirtyGitRepo)({
ignoreGitChanges: options.ignoreGitChanges,
cwd: undefined,
});
// We expect `@remix-run/dev` to be installed for every Remix project
await (0, clack_1.ensurePackageIsInstalled)(packageJson, '@remix-run/dev', 'Remix');
const projectData = await (0, clack_1.getOrAskForProjectData)(options, 'javascript-remix');
if (projectData.spotlight) {
prompts_1.default.log.warn('Spotlight mode is not yet supported for Remix.');
prompts_1.default.log.info('Spotlight is currently only available for Next.js.');
await (0, clack_1.abort)('Exiting wizard', 0);
return;
}
const { selectedProject, authToken, sentryUrl, selfHosted } = projectData;
await (0, clack_1.installPackage)({
packageName: '@sentry/remix@^10',
packageNameDisplayLabel: '@sentry/remix',
alreadyInstalled: (0, package_json_1.hasPackageInstalled)('@sentry/remix', packageJson),
forceInstall,
});
const dsn = selectedProject.keys[0].dsn.public;
const isTS = (0, clack_1.isUsingTypeScript)();
const viteConfig = (0, ast_utils_1.findFile)('vite.config');
const selectedFeatures = await (0, clack_1.featureSelectionPrompt)([
{
id: 'performance',
prompt: `Do you want to enable ${chalk_1.default.bold('Tracing')} to track the performance of your application?`,
enabledHint: 'recommended',
},
{
id: 'replay',
prompt: `Do you want to enable ${chalk_1.default.bold('Session Replay')} to get a video-like reproduction of errors during a user session?`,
enabledHint: 'recommended, but increases bundle size',
},
{
id: 'logs',
prompt: `Do you want to enable ${chalk_1.default.bold('Logs')} to send your application logs to Sentry?`,
enabledHint: 'recommended',
},
]);
if (viteConfig) {
await (0, telemetry_1.traceStep)('Update vite configuration for sourcemap uploads', async () => {
try {
await (0, vite_1.configureVitePlugin)({
orgSlug: selectedProject.organization.slug,
projectSlug: selectedProject.slug,
url: sentryUrl,
selfHosted,
authToken,
});
}
catch (e) {
prompts_1.default.log
.warn(`Could not update vite configuration to generate and upload sourcemaps.
Please update your vite configuration manually using instructions from https://docs.sentry.io/platforms/javascript/guides/remix/sourcemaps/`);
(0, debug_1.debug)(e);
}
});
}
else {
await (0, telemetry_1.traceStep)('Update build script for sourcemap uploads', async () => {
try {
await (0, sdk_setup_1.updateBuildScript)({
org: selectedProject.organization.slug,
project: selectedProject.slug,
url: sentryUrl === Constants_1.DEFAULT_URL ? undefined : sentryUrl,
isHydrogen: (0, utils_1.isHydrogenApp)(packageJson),
});
await (0, clack_1.addSentryCliConfig)({ authToken }, clack_1.rcCliSetupConfig);
}
catch (e) {
prompts_1.default.log
.warn(`Could not update build script to generate and upload sourcemaps.
Please update your build script manually using instructions from https://docs.sentry.io/platforms/javascript/guides/remix/sourcemaps/`);
(0, debug_1.debug)(e);
}
});
}
await (0, telemetry_1.traceStep)('Instrument root route', async () => {
try {
await (0, sdk_setup_1.instrumentRootRoute)(isTS);
}
catch (e) {
prompts_1.default.log.warn(`Could not instrument root route.
Please do it manually using instructions from https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/`);
(0, debug_1.debug)(e);
}
});
(0, telemetry_1.traceStep)('Reveal missing entry files', () => {
try {
(0, sdk_setup_1.runRemixReveal)(isTS);
}
catch (e) {
prompts_1.default.log.warn(`Could not run 'npx remix reveal'.
Please create your entry files manually`);
(0, debug_1.debug)(e);
}
});
await (0, telemetry_1.traceStep)('Initialize Sentry on client entry', async () => {
try {
await (0, sdk_setup_1.initializeSentryOnEntryClient)(dsn, isTS, selectedFeatures);
}
catch (e) {
prompts_1.default.log.warn(`Could not initialize Sentry on client entry.
Please do it manually using instructions from https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/`);
(0, debug_1.debug)(e);
}
});
let instrumentationFile = '';
await (0, telemetry_1.traceStep)('Create server instrumentation file', async () => {
try {
instrumentationFile = await (0, sdk_setup_1.createServerInstrumentationFile)(dsn, selectedFeatures);
}
catch (e) {
prompts_1.default.log.warn('Could not create a server instrumentation file. Please do it manually using instructions from https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/');
(0, debug_1.debug)(e);
}
});
let serverFileInstrumented = false;
await (0, telemetry_1.traceStep)('Create server instrumentation file and import it', async () => {
try {
serverFileInstrumented = await (0, sdk_setup_1.insertServerInstrumentationFile)(dsn, selectedFeatures);
}
catch (e) {
prompts_1.default.log.warn('Could not create a server instrumentation file. Please do it manually using instructions from https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/');
(0, debug_1.debug)(e);
}
});
if (!serverFileInstrumented && instrumentationFile) {
await (0, telemetry_1.traceStep)('Update `start` script to import instrumentation file.', async () => {
try {
await (0, sdk_setup_1.updateStartScript)(instrumentationFile);
}
catch (e) {
prompts_1.default.log
.warn(`Could not automatically add Sentry initialization to server entry.
Please do it manually using instructions from https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/`);
(0, debug_1.debug)(e);
}
});
}
await (0, telemetry_1.traceStep)('Instrument server `handleError`', async () => {
try {
await (0, sdk_setup_1.instrumentSentryOnEntryServer)(isTS);
}
catch (e) {
prompts_1.default.log.warn(`Could not initialize Sentry on server entry.
Please do it manually using instructions from https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/`);
(0, debug_1.debug)(e);
}
});
const shouldCreateExamplePage = await (0, clack_1.askShouldCreateExamplePage)();
if (shouldCreateExamplePage) {
await (0, telemetry_1.traceStep)('Create example page', async () => {
await (0, sdk_example_1.createExamplePage)({
isTS,
selfHosted,
orgSlug: selectedProject.organization.slug,
projectId: selectedProject.id,
url: sentryUrl,
});
});
}
await (0, clack_1.runPrettierIfInstalled)({ cwd: undefined });
// Offer optional project-scoped MCP config for Sentry with org and project scope
await (0, mcp_config_1.offerProjectScopedMcpConfig)(selectedProject.organization.slug, selectedProject.slug);
prompts_1.default.outro(`
${chalk_1.default.green('Sentry has been successfully configured for your Remix project.')}
${chalk_1.default.cyan('You can now deploy your project to see Sentry in action.')}
${chalk_1.default.cyan(`To learn more about how to use Sentry with Remix, visit our documentation:
https://docs.sentry.io/platforms/javascript/guides/remix/`)}`);
}
/**
* Offers to add a project-scoped MCP server configuration for the Sentry MCP.
* Supports Cursor, VS Code, and Claude Code.
*/
//# sourceMappingURL=remix-wizard.js.map