@sentry/wizard 3.23.3 → 3.24.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 +10 -2
- package/dist/package.json +2 -2
- package/dist/src/react-native/glob.js +24 -4
- package/dist/src/react-native/glob.js.map +1 -1
- package/dist/src/remix/codemods/express-server.d.ts +0 -4
- package/dist/src/remix/codemods/express-server.js +1 -80
- package/dist/src/remix/codemods/express-server.js.map +1 -1
- package/dist/src/remix/codemods/handle-error.js +2 -2
- package/dist/src/remix/codemods/handle-error.js.map +1 -1
- package/dist/src/remix/remix-wizard.js +62 -19
- package/dist/src/remix/remix-wizard.js.map +1 -1
- package/dist/src/remix/sdk-example.js +1 -1
- package/dist/src/remix/sdk-example.js.map +1 -1
- package/dist/src/remix/sdk-setup.d.ts +5 -3
- package/dist/src/remix/sdk-setup.js +98 -38
- package/dist/src/remix/sdk-setup.js.map +1 -1
- package/dist/src/remix/templates.d.ts +1 -1
- package/dist/src/remix/templates.js +1 -1
- package/dist/src/remix/templates.js.map +1 -1
- package/dist/src/remix/utils.d.ts +9 -3
- package/dist/src/remix/utils.js +39 -10
- package/dist/src/remix/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/react-native/glob.ts +1 -1
- package/src/remix/codemods/express-server.ts +0 -121
- package/src/remix/codemods/handle-error.ts +3 -2
- package/src/remix/remix-wizard.ts +45 -17
- package/src/remix/sdk-example.ts +0 -2
- package/src/remix/sdk-setup.ts +125 -33
- package/src/remix/templates.ts +1 -1
- package/src/remix/utils.ts +57 -7
|
@@ -63,7 +63,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
63
63
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
64
64
|
};
|
|
65
65
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
66
|
-
exports.
|
|
66
|
+
exports.instrumentSentryOnEntryServer = exports.updateStartScript = exports.initializeSentryOnEntryClient = exports.updateBuildScript = exports.instrumentRootRoute = exports.loadRemixConfig = exports.isRemixV2 = exports.insertServerInstrumentationFile = exports.createServerInstrumentationFile = exports.runRemixReveal = void 0;
|
|
67
67
|
var fs = __importStar(require("fs"));
|
|
68
68
|
var path = __importStar(require("path"));
|
|
69
69
|
var url = __importStar(require("url"));
|
|
@@ -72,15 +72,14 @@ var childProcess = __importStar(require("child_process"));
|
|
|
72
72
|
var prompts_1 = __importDefault(require("@clack/prompts"));
|
|
73
73
|
var chalk_1 = __importDefault(require("chalk"));
|
|
74
74
|
var semver_1 = require("semver");
|
|
75
|
-
// @ts-expect-error - magicast is ESM and TS complains about that. It works though
|
|
76
75
|
var magicast_1 = require("magicast");
|
|
77
76
|
var package_json_1 = require("../utils/package-json");
|
|
78
77
|
var utils_1 = require("./utils");
|
|
79
78
|
var root_v1_1 = require("./codemods/root-v1");
|
|
80
79
|
var root_v2_1 = require("./codemods/root-v2");
|
|
81
80
|
var handle_error_1 = require("./codemods/handle-error");
|
|
82
|
-
var express_server_1 = require("./codemods/express-server");
|
|
83
81
|
var clack_utils_1 = require("../utils/clack-utils");
|
|
82
|
+
var express_server_1 = require("./codemods/express-server");
|
|
84
83
|
var REMIX_CONFIG_FILE = 'remix.config.js';
|
|
85
84
|
var REMIX_REVEAL_COMMAND = 'npx remix reveal';
|
|
86
85
|
function runRemixReveal(isTS) {
|
|
@@ -110,24 +109,74 @@ function insertClientInitCall(dsn, originalHooksMod) {
|
|
|
110
109
|
],
|
|
111
110
|
});
|
|
112
111
|
var originalHooksModAST = originalHooksMod.$ast;
|
|
113
|
-
var initCallInsertionIndex = (0, utils_1.
|
|
112
|
+
var initCallInsertionIndex = (0, utils_1.getAfterImportsInsertionIndex)(originalHooksModAST);
|
|
114
113
|
originalHooksModAST.body.splice(initCallInsertionIndex, 0,
|
|
115
114
|
// @ts-expect-error - string works here because the AST is proxified by magicast
|
|
116
115
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
117
116
|
(0, magicast_1.generateCode)(initCall).code);
|
|
118
117
|
}
|
|
119
|
-
function
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
118
|
+
function createServerInstrumentationFile(dsn) {
|
|
119
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
120
|
+
var instrumentationFile, instrumentationFileMod, initCall, instrumentationFileModAST, initCallInsertionIndex;
|
|
121
|
+
return __generator(this, function (_a) {
|
|
122
|
+
switch (_a.label) {
|
|
123
|
+
case 0:
|
|
124
|
+
instrumentationFile = 'instrumentation.server.mjs';
|
|
125
|
+
instrumentationFileMod = (0, magicast_1.parseModule)('');
|
|
126
|
+
instrumentationFileMod.imports.$add({
|
|
127
|
+
from: '@sentry/remix',
|
|
128
|
+
imported: '*',
|
|
129
|
+
local: 'Sentry',
|
|
130
|
+
});
|
|
131
|
+
initCall = magicast_1.builders.functionCall('Sentry.init', {
|
|
132
|
+
dsn: dsn,
|
|
133
|
+
tracesSampleRate: 1.0,
|
|
134
|
+
autoInstrumentRemix: true,
|
|
135
|
+
});
|
|
136
|
+
instrumentationFileModAST = instrumentationFileMod.$ast;
|
|
137
|
+
initCallInsertionIndex = (0, utils_1.getAfterImportsInsertionIndex)(instrumentationFileModAST);
|
|
138
|
+
instrumentationFileModAST.body.splice(initCallInsertionIndex, 0,
|
|
139
|
+
// @ts-expect-error - string works here because the AST is proxified by magicast
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
141
|
+
(0, magicast_1.generateCode)(initCall).code);
|
|
142
|
+
return [4 /*yield*/, (0, magicast_1.writeFile)(instrumentationFileModAST, instrumentationFile)];
|
|
143
|
+
case 1:
|
|
144
|
+
_a.sent();
|
|
145
|
+
return [2 /*return*/, instrumentationFile];
|
|
146
|
+
}
|
|
147
|
+
});
|
|
123
148
|
});
|
|
124
|
-
var originalHooksModAST = originalHooksMod.$ast;
|
|
125
|
-
var initCallInsertionIndex = (0, utils_1.getInitCallInsertionIndex)(originalHooksModAST);
|
|
126
|
-
originalHooksModAST.body.splice(initCallInsertionIndex, 0,
|
|
127
|
-
// @ts-expect-error - string works here because the AST is proxified by magicast
|
|
128
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
129
|
-
(0, magicast_1.generateCode)(initCall).code);
|
|
130
149
|
}
|
|
150
|
+
exports.createServerInstrumentationFile = createServerInstrumentationFile;
|
|
151
|
+
function insertServerInstrumentationFile(dsn) {
|
|
152
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
153
|
+
var instrumentationFile, expressServerPath, originalExpressServerMod;
|
|
154
|
+
return __generator(this, function (_a) {
|
|
155
|
+
switch (_a.label) {
|
|
156
|
+
case 0: return [4 /*yield*/, createServerInstrumentationFile(dsn)];
|
|
157
|
+
case 1:
|
|
158
|
+
instrumentationFile = _a.sent();
|
|
159
|
+
return [4 /*yield*/, (0, express_server_1.findCustomExpressServerImplementation)()];
|
|
160
|
+
case 2:
|
|
161
|
+
expressServerPath = _a.sent();
|
|
162
|
+
if (!expressServerPath) {
|
|
163
|
+
return [2 /*return*/, false];
|
|
164
|
+
}
|
|
165
|
+
return [4 /*yield*/, (0, magicast_1.loadFile)(expressServerPath)];
|
|
166
|
+
case 3:
|
|
167
|
+
originalExpressServerMod = _a.sent();
|
|
168
|
+
if ((0, utils_1.serverHasInstrumentationImport)(expressServerPath, originalExpressServerMod.$code)) {
|
|
169
|
+
prompts_1.default.log.warn("File ".concat(chalk_1.default.cyan(path.basename(expressServerPath)), " already contains instrumentation import.\nSkipping adding instrumentation functionality to ").concat(chalk_1.default.cyan(path.basename(expressServerPath)), "."));
|
|
170
|
+
return [2 /*return*/, true];
|
|
171
|
+
}
|
|
172
|
+
originalExpressServerMod.$code = "import './".concat(instrumentationFile, "';\n").concat(originalExpressServerMod.$code);
|
|
173
|
+
fs.writeFileSync(expressServerPath, originalExpressServerMod.$code);
|
|
174
|
+
return [2 /*return*/, true];
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
exports.insertServerInstrumentationFile = insertServerInstrumentationFile;
|
|
131
180
|
function isRemixV2(remixConfig, packageJson) {
|
|
132
181
|
var _a;
|
|
133
182
|
var remixVersion = (0, package_json_1.getPackageVersion)('@remix-run/react', packageJson);
|
|
@@ -282,7 +331,40 @@ function initializeSentryOnEntryClient(dsn, isTS) {
|
|
|
282
331
|
});
|
|
283
332
|
}
|
|
284
333
|
exports.initializeSentryOnEntryClient = initializeSentryOnEntryClient;
|
|
285
|
-
function
|
|
334
|
+
function updateStartScript(instrumentationFile) {
|
|
335
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
336
|
+
var packageJson, startCommand;
|
|
337
|
+
return __generator(this, function (_a) {
|
|
338
|
+
switch (_a.label) {
|
|
339
|
+
case 0: return [4 /*yield*/, (0, clack_utils_1.getPackageDotJson)()];
|
|
340
|
+
case 1:
|
|
341
|
+
packageJson = _a.sent();
|
|
342
|
+
if (!packageJson.scripts || !packageJson.scripts.start) {
|
|
343
|
+
throw new Error("Couldn't find a `start` script in your package.json. Please add one manually.");
|
|
344
|
+
}
|
|
345
|
+
if (packageJson.scripts.start.includes('NODE_OPTIONS')) {
|
|
346
|
+
prompts_1.default.log.warn("Found existing NODE_OPTIONS in ".concat(chalk_1.default.cyan('start'), " script. Skipping adding Sentry initialization."));
|
|
347
|
+
return [2 /*return*/];
|
|
348
|
+
}
|
|
349
|
+
if (!packageJson.scripts.start.includes('remix-serve') &&
|
|
350
|
+
// Adding a following empty space not to match a path that includes `node`
|
|
351
|
+
!packageJson.scripts.start.includes('node ')) {
|
|
352
|
+
prompts_1.default.log.warn("Found a ".concat(chalk_1.default.cyan('start'), " script that doesn't use ").concat(chalk_1.default.cyan('remix-serve'), " or ").concat(chalk_1.default.cyan('node'), ". Skipping adding Sentry initialization."));
|
|
353
|
+
return [2 /*return*/];
|
|
354
|
+
}
|
|
355
|
+
startCommand = packageJson.scripts.start;
|
|
356
|
+
packageJson.scripts.start = "NODE_OPTIONS='--import ./".concat(instrumentationFile, "' ").concat(startCommand);
|
|
357
|
+
return [4 /*yield*/, fs.promises.writeFile(path.join(process.cwd(), 'package.json'), JSON.stringify(packageJson, null, 2))];
|
|
358
|
+
case 2:
|
|
359
|
+
_a.sent();
|
|
360
|
+
prompts_1.default.log.success("Successfully updated ".concat(chalk_1.default.cyan('start'), " script in ").concat(chalk_1.default.cyan('package.json'), " to include Sentry initialization on start."));
|
|
361
|
+
return [2 /*return*/];
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
exports.updateStartScript = updateStartScript;
|
|
367
|
+
function instrumentSentryOnEntryServer(isV2, isTS) {
|
|
286
368
|
return __awaiter(this, void 0, void 0, function () {
|
|
287
369
|
var serverEntryFilename, originalEntryServer, originalEntryServerMod, handleErrorInstrumented;
|
|
288
370
|
return __generator(this, function (_a) {
|
|
@@ -301,7 +383,6 @@ function initializeSentryOnEntryServer(dsn, isV2, isTS) {
|
|
|
301
383
|
imported: '*',
|
|
302
384
|
local: 'Sentry',
|
|
303
385
|
});
|
|
304
|
-
insertServerInitCall(dsn, originalEntryServerMod);
|
|
305
386
|
if (isV2) {
|
|
306
387
|
handleErrorInstrumented = (0, handle_error_1.instrumentHandleError)(originalEntryServerMod, serverEntryFilename);
|
|
307
388
|
if (handleErrorInstrumented) {
|
|
@@ -317,26 +398,5 @@ function initializeSentryOnEntryServer(dsn, isV2, isTS) {
|
|
|
317
398
|
});
|
|
318
399
|
});
|
|
319
400
|
}
|
|
320
|
-
exports.
|
|
321
|
-
function instrumentExpressServer() {
|
|
322
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
323
|
-
var expressServerPath;
|
|
324
|
-
return __generator(this, function (_a) {
|
|
325
|
-
switch (_a.label) {
|
|
326
|
-
case 0: return [4 /*yield*/, (0, express_server_1.findCustomExpressServerImplementation)()];
|
|
327
|
-
case 1:
|
|
328
|
-
expressServerPath = _a.sent();
|
|
329
|
-
if (!expressServerPath) {
|
|
330
|
-
prompts_1.default.log.warn("Could not find custom Express server implementation. Please instrument it manually.");
|
|
331
|
-
return [2 /*return*/];
|
|
332
|
-
}
|
|
333
|
-
return [4 /*yield*/, (0, express_server_1.instrumentExpressCreateRequestHandler)(expressServerPath)];
|
|
334
|
-
case 2:
|
|
335
|
-
_a.sent();
|
|
336
|
-
return [2 /*return*/];
|
|
337
|
-
}
|
|
338
|
-
});
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
exports.instrumentExpressServer = instrumentExpressServer;
|
|
401
|
+
exports.instrumentSentryOnEntryServer = instrumentSentryOnEntryServer;
|
|
342
402
|
//# sourceMappingURL=sdk-setup.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk-setup.js","sourceRoot":"","sources":["../../../src/remix/sdk-setup.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n\nimport type { Program } from '@babel/types';\n\n// @ts-expect-error - magicast is ESM and TS complains about that. It works though\nimport type { ProxifiedModule } from 'magicast';\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as url from 'url';\nimport * as childProcess from 'child_process';\n\n// @ts-expect-error - clack is ESM and TS complains about that. It works though\nimport clack from '@clack/prompts';\nimport chalk from 'chalk';\nimport { gte, minVersion } from 'semver';\n\n// @ts-expect-error - magicast is ESM and TS complains about that. It works though\nimport { builders, generateCode, loadFile, writeFile } from 'magicast';\nimport { PackageDotJson, getPackageVersion } from '../utils/package-json';\nimport { getInitCallInsertionIndex, hasSentryContent } from './utils';\nimport { instrumentRootRouteV1 } from './codemods/root-v1';\nimport { instrumentRootRouteV2 } from './codemods/root-v2';\nimport { instrumentHandleError } from './codemods/handle-error';\nimport {\n findCustomExpressServerImplementation,\n instrumentExpressCreateRequestHandler,\n} from './codemods/express-server';\nimport { getPackageDotJson } from '../utils/clack-utils';\n\nexport type PartialRemixConfig = {\n unstable_dev?: boolean;\n future?: {\n v2_dev?: boolean;\n v2_errorBoundary?: boolean;\n v2_headers?: boolean;\n v2_meta?: boolean;\n v2_normalizeFormMethod?: boolean;\n v2_routeConvention?: boolean;\n };\n};\n\nconst REMIX_CONFIG_FILE = 'remix.config.js';\nconst REMIX_REVEAL_COMMAND = 'npx remix reveal';\n\nexport function runRemixReveal(isTS: boolean): void {\n // Check if entry files already exist\n const clientEntryFilename = `entry.client.${isTS ? 'tsx' : 'jsx'}`;\n const serverEntryFilename = `entry.server.${isTS ? 'tsx' : 'jsx'}`;\n\n const clientEntryPath = path.join(process.cwd(), 'app', clientEntryFilename);\n const serverEntryPath = path.join(process.cwd(), 'app', serverEntryFilename);\n\n if (fs.existsSync(clientEntryPath) && fs.existsSync(serverEntryPath)) {\n clack.log.info(\n `Found entry files ${chalk.cyan(clientEntryFilename)} and ${chalk.cyan(\n serverEntryFilename,\n )}.`,\n );\n } else {\n clack.log.info(\n `Couldn't find entry files in your project. Trying to run ${chalk.cyan(\n REMIX_REVEAL_COMMAND,\n )}...`,\n );\n\n clack.log.info(childProcess.execSync(REMIX_REVEAL_COMMAND).toString());\n }\n}\n\nfunction insertClientInitCall(\n dsn: string,\n originalHooksMod: ProxifiedModule<any>,\n): void {\n const initCall = builders.functionCall('Sentry.init', {\n dsn,\n tracesSampleRate: 1.0,\n replaysSessionSampleRate: 0.1,\n replaysOnErrorSampleRate: 1.0,\n integrations: [\n builders.functionCall(\n 'Sentry.browserTracingIntegration',\n builders.raw('{ useEffect, useLocation, useMatches }'),\n ),\n builders.functionCall('Sentry.replayIntegration'),\n ],\n });\n\n const originalHooksModAST = originalHooksMod.$ast as Program;\n const initCallInsertionIndex = getInitCallInsertionIndex(originalHooksModAST);\n\n originalHooksModAST.body.splice(\n initCallInsertionIndex,\n 0,\n // @ts-expect-error - string works here because the AST is proxified by magicast\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n generateCode(initCall).code,\n );\n}\n\nfunction insertServerInitCall(\n dsn: string,\n originalHooksMod: ProxifiedModule<any>,\n) {\n const initCall = builders.functionCall('Sentry.init', {\n dsn,\n tracesSampleRate: 1.0,\n });\n\n const originalHooksModAST = originalHooksMod.$ast as Program;\n\n const initCallInsertionIndex = getInitCallInsertionIndex(originalHooksModAST);\n\n originalHooksModAST.body.splice(\n initCallInsertionIndex,\n 0,\n // @ts-expect-error - string works here because the AST is proxified by magicast\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n generateCode(initCall).code,\n );\n}\n\nexport function isRemixV2(\n remixConfig: PartialRemixConfig,\n packageJson: PackageDotJson,\n): boolean {\n const remixVersion = getPackageVersion('@remix-run/react', packageJson);\n if (!remixVersion) {\n return false;\n }\n\n const minVer = minVersion(remixVersion);\n\n if (!minVer) {\n return false;\n }\n\n const isV2Remix = gte(minVer, '2.0.0');\n\n return isV2Remix || remixConfig?.future?.v2_errorBoundary || false;\n}\n\nexport async function loadRemixConfig(): Promise<PartialRemixConfig> {\n const configFilePath = path.join(process.cwd(), REMIX_CONFIG_FILE);\n\n try {\n if (!fs.existsSync(configFilePath)) {\n return {};\n }\n\n const configUrl = url.pathToFileURL(configFilePath).href;\n const remixConfigModule = (await import(configUrl)) as {\n default: PartialRemixConfig;\n };\n\n return remixConfigModule?.default || {};\n } catch (e: unknown) {\n clack.log.error(`Couldn't load ${REMIX_CONFIG_FILE}.`);\n clack.log.info(\n chalk.dim(\n typeof e === 'object' && e != null && 'toString' in e\n ? e.toString()\n : typeof e === 'string'\n ? e\n : 'Unknown error',\n ),\n );\n\n return {};\n }\n}\n\nexport async function instrumentRootRoute(\n isV2?: boolean,\n isTS?: boolean,\n): Promise<void> {\n const rootFilename = `root.${isTS ? 'tsx' : 'jsx'}`;\n\n if (isV2) {\n await instrumentRootRouteV2(rootFilename);\n } else {\n await instrumentRootRouteV1(rootFilename);\n }\n\n clack.log.success(\n `Successfully instrumented root route ${chalk.cyan(rootFilename)}.`,\n );\n /* eslint-enable @typescript-eslint/no-unsafe-member-access */\n}\n\nexport async function updateBuildScript(args: {\n org: string;\n project: string;\n url?: string;\n isHydrogen: boolean;\n}): Promise<void> {\n const packageJson = await getPackageDotJson();\n\n if (!packageJson.scripts) {\n packageJson.scripts = {};\n }\n\n const buildCommand = args.isHydrogen\n ? 'shopify hydrogen build'\n : 'remix build';\n\n const instrumentedBuildCommand =\n `${buildCommand} --sourcemap && sentry-upload-sourcemaps --org ${args.org} --project ${args.project}` +\n (args.url ? ` --url ${args.url}` : '') +\n (args.isHydrogen ? ' --buildPath ./dist' : '');\n\n if (!packageJson.scripts.build) {\n packageJson.scripts.build = instrumentedBuildCommand;\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n } else if (packageJson.scripts.build.includes(buildCommand)) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n packageJson.scripts.build = packageJson.scripts.build.replace(\n buildCommand,\n instrumentedBuildCommand,\n );\n } else {\n throw new Error(\n \"`build` script doesn't contain a known build command. Please update it manually.\",\n );\n }\n\n await fs.promises.writeFile(\n path.join(process.cwd(), 'package.json'),\n JSON.stringify(packageJson, null, 2),\n );\n\n clack.log.success(\n `Successfully updated ${chalk.cyan('build')} script in ${chalk.cyan(\n 'package.json',\n )} to generate and upload sourcemaps.`,\n );\n /* eslint-enable @typescript-eslint/no-unsafe-member-access */\n}\n\nexport async function initializeSentryOnEntryClient(\n dsn: string,\n isTS: boolean,\n): Promise<void> {\n const clientEntryFilename = `entry.client.${isTS ? 'tsx' : 'jsx'}`;\n\n const originalEntryClient = path.join(\n process.cwd(),\n 'app',\n clientEntryFilename,\n );\n\n const originalEntryClientMod = await loadFile(originalEntryClient);\n\n if (hasSentryContent(originalEntryClient, originalEntryClientMod.$code)) {\n return;\n }\n\n originalEntryClientMod.imports.$add({\n from: '@sentry/remix',\n imported: '*',\n local: 'Sentry',\n });\n\n originalEntryClientMod.imports.$add({\n from: 'react',\n imported: 'useEffect',\n local: 'useEffect',\n });\n\n originalEntryClientMod.imports.$add({\n from: '@remix-run/react',\n imported: 'useLocation',\n local: 'useLocation',\n });\n\n originalEntryClientMod.imports.$add({\n from: '@remix-run/react',\n imported: 'useMatches',\n local: 'useMatches',\n });\n\n insertClientInitCall(dsn, originalEntryClientMod);\n\n await writeFile(\n originalEntryClientMod.$ast,\n path.join(process.cwd(), 'app', clientEntryFilename),\n );\n\n clack.log.success(\n `Successfully initialized Sentry on client entry point ${chalk.cyan(\n clientEntryFilename,\n )}`,\n );\n}\n\nexport async function initializeSentryOnEntryServer(\n dsn: string,\n isV2: boolean,\n isTS: boolean,\n): Promise<void> {\n const serverEntryFilename = `entry.server.${isTS ? 'tsx' : 'jsx'}`;\n\n const originalEntryServer = path.join(\n process.cwd(),\n 'app',\n serverEntryFilename,\n );\n\n const originalEntryServerMod = await loadFile(originalEntryServer);\n\n if (hasSentryContent(originalEntryServer, originalEntryServerMod.$code)) {\n return;\n }\n\n originalEntryServerMod.imports.$add({\n from: '@sentry/remix',\n imported: '*',\n local: 'Sentry',\n });\n\n insertServerInitCall(dsn, originalEntryServerMod);\n\n if (isV2) {\n const handleErrorInstrumented = instrumentHandleError(\n originalEntryServerMod,\n serverEntryFilename,\n );\n\n if (handleErrorInstrumented) {\n clack.log.success(\n `Instrumented ${chalk.cyan('handleError')} in ${chalk.cyan(\n `${serverEntryFilename}`,\n )}`,\n );\n }\n }\n\n await writeFile(\n originalEntryServerMod.$ast,\n path.join(process.cwd(), 'app', serverEntryFilename),\n );\n\n clack.log.success(\n `Successfully initialized Sentry on server entry point ${chalk.cyan(\n serverEntryFilename,\n )}.`,\n );\n}\n\nexport async function instrumentExpressServer() {\n const expressServerPath = await findCustomExpressServerImplementation();\n\n if (!expressServerPath) {\n clack.log.warn(\n `Could not find custom Express server implementation. Please instrument it manually.`,\n );\n return;\n }\n\n await instrumentExpressCreateRequestHandler(expressServerPath);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sdk-setup.js","sourceRoot":"","sources":["../../../src/remix/sdk-setup.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n\nimport type { Program } from '@babel/types';\n\n// @ts-expect-error - magicast is ESM and TS complains about that. It works though\nimport type { ProxifiedModule } from 'magicast';\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as url from 'url';\nimport * as childProcess from 'child_process';\n\n// @ts-expect-error - clack is ESM and TS complains about that. It works though\nimport clack from '@clack/prompts';\nimport chalk from 'chalk';\nimport { gte, minVersion } from 'semver';\n\nimport {\n builders,\n generateCode,\n loadFile,\n parseModule,\n writeFile,\n // @ts-expect-error - magicast is ESM and TS complains about that. It works though\n} from 'magicast';\nimport type { PackageDotJson } from '../utils/package-json';\nimport { getPackageVersion } from '../utils/package-json';\nimport {\n getAfterImportsInsertionIndex,\n hasSentryContent,\n serverHasInstrumentationImport,\n} from './utils';\nimport { instrumentRootRouteV1 } from './codemods/root-v1';\nimport { instrumentRootRouteV2 } from './codemods/root-v2';\nimport { instrumentHandleError } from './codemods/handle-error';\nimport { getPackageDotJson } from '../utils/clack-utils';\nimport { findCustomExpressServerImplementation } from './codemods/express-server';\n\nexport type PartialRemixConfig = {\n unstable_dev?: boolean;\n future?: {\n v2_dev?: boolean;\n v2_errorBoundary?: boolean;\n v2_headers?: boolean;\n v2_meta?: boolean;\n v2_normalizeFormMethod?: boolean;\n v2_routeConvention?: boolean;\n };\n};\n\nconst REMIX_CONFIG_FILE = 'remix.config.js';\nconst REMIX_REVEAL_COMMAND = 'npx remix reveal';\n\nexport function runRemixReveal(isTS: boolean): void {\n // Check if entry files already exist\n const clientEntryFilename = `entry.client.${isTS ? 'tsx' : 'jsx'}`;\n const serverEntryFilename = `entry.server.${isTS ? 'tsx' : 'jsx'}`;\n\n const clientEntryPath = path.join(process.cwd(), 'app', clientEntryFilename);\n const serverEntryPath = path.join(process.cwd(), 'app', serverEntryFilename);\n\n if (fs.existsSync(clientEntryPath) && fs.existsSync(serverEntryPath)) {\n clack.log.info(\n `Found entry files ${chalk.cyan(clientEntryFilename)} and ${chalk.cyan(\n serverEntryFilename,\n )}.`,\n );\n } else {\n clack.log.info(\n `Couldn't find entry files in your project. Trying to run ${chalk.cyan(\n REMIX_REVEAL_COMMAND,\n )}...`,\n );\n\n clack.log.info(childProcess.execSync(REMIX_REVEAL_COMMAND).toString());\n }\n}\n\nfunction insertClientInitCall(\n dsn: string,\n originalHooksMod: ProxifiedModule<any>,\n): void {\n const initCall = builders.functionCall('Sentry.init', {\n dsn,\n tracesSampleRate: 1.0,\n replaysSessionSampleRate: 0.1,\n replaysOnErrorSampleRate: 1.0,\n integrations: [\n builders.functionCall(\n 'Sentry.browserTracingIntegration',\n builders.raw('{ useEffect, useLocation, useMatches }'),\n ),\n builders.functionCall('Sentry.replayIntegration'),\n ],\n });\n\n const originalHooksModAST = originalHooksMod.$ast as Program;\n const initCallInsertionIndex =\n getAfterImportsInsertionIndex(originalHooksModAST);\n\n originalHooksModAST.body.splice(\n initCallInsertionIndex,\n 0,\n // @ts-expect-error - string works here because the AST is proxified by magicast\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n generateCode(initCall).code,\n );\n}\n\nexport async function createServerInstrumentationFile(dsn: string) {\n // create an empty file named `instrument.server.mjs`\n const instrumentationFile = 'instrumentation.server.mjs';\n const instrumentationFileMod = parseModule('');\n\n instrumentationFileMod.imports.$add({\n from: '@sentry/remix',\n imported: '*',\n local: 'Sentry',\n });\n\n const initCall = builders.functionCall('Sentry.init', {\n dsn,\n tracesSampleRate: 1.0,\n autoInstrumentRemix: true,\n });\n\n const instrumentationFileModAST = instrumentationFileMod.$ast as Program;\n\n const initCallInsertionIndex = getAfterImportsInsertionIndex(\n instrumentationFileModAST,\n );\n\n instrumentationFileModAST.body.splice(\n initCallInsertionIndex,\n 0,\n // @ts-expect-error - string works here because the AST is proxified by magicast\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n generateCode(initCall).code,\n );\n\n await writeFile(instrumentationFileModAST, instrumentationFile);\n\n return instrumentationFile;\n}\n\nexport async function insertServerInstrumentationFile(dsn: string) {\n const instrumentationFile = await createServerInstrumentationFile(dsn);\n\n const expressServerPath = await findCustomExpressServerImplementation();\n\n if (!expressServerPath) {\n return false;\n }\n\n const originalExpressServerMod = await loadFile(expressServerPath);\n\n if (\n serverHasInstrumentationImport(\n expressServerPath,\n originalExpressServerMod.$code,\n )\n ) {\n clack.log.warn(\n `File ${chalk.cyan(\n path.basename(expressServerPath),\n )} already contains instrumentation import.\nSkipping adding instrumentation functionality to ${chalk.cyan(\n path.basename(expressServerPath),\n )}.`,\n );\n\n return true;\n }\n\n originalExpressServerMod.$code = `import './${instrumentationFile}';\\n${originalExpressServerMod.$code}`;\n\n fs.writeFileSync(expressServerPath, originalExpressServerMod.$code);\n\n return true;\n}\n\nexport function isRemixV2(\n remixConfig: PartialRemixConfig,\n packageJson: PackageDotJson,\n): boolean {\n const remixVersion = getPackageVersion('@remix-run/react', packageJson);\n if (!remixVersion) {\n return false;\n }\n\n const minVer = minVersion(remixVersion);\n\n if (!minVer) {\n return false;\n }\n\n const isV2Remix = gte(minVer, '2.0.0');\n\n return isV2Remix || remixConfig?.future?.v2_errorBoundary || false;\n}\n\nexport async function loadRemixConfig(): Promise<PartialRemixConfig> {\n const configFilePath = path.join(process.cwd(), REMIX_CONFIG_FILE);\n\n try {\n if (!fs.existsSync(configFilePath)) {\n return {};\n }\n\n const configUrl = url.pathToFileURL(configFilePath).href;\n const remixConfigModule = (await import(configUrl)) as {\n default: PartialRemixConfig;\n };\n\n return remixConfigModule?.default || {};\n } catch (e: unknown) {\n clack.log.error(`Couldn't load ${REMIX_CONFIG_FILE}.`);\n clack.log.info(\n chalk.dim(\n typeof e === 'object' && e != null && 'toString' in e\n ? e.toString()\n : typeof e === 'string'\n ? e\n : 'Unknown error',\n ),\n );\n\n return {};\n }\n}\n\nexport async function instrumentRootRoute(\n isV2?: boolean,\n isTS?: boolean,\n): Promise<void> {\n const rootFilename = `root.${isTS ? 'tsx' : 'jsx'}`;\n\n if (isV2) {\n await instrumentRootRouteV2(rootFilename);\n } else {\n await instrumentRootRouteV1(rootFilename);\n }\n\n clack.log.success(\n `Successfully instrumented root route ${chalk.cyan(rootFilename)}.`,\n );\n /* eslint-enable @typescript-eslint/no-unsafe-member-access */\n}\n\nexport async function updateBuildScript(args: {\n org: string;\n project: string;\n url?: string;\n isHydrogen: boolean;\n}): Promise<void> {\n const packageJson = await getPackageDotJson();\n\n if (!packageJson.scripts) {\n packageJson.scripts = {};\n }\n\n const buildCommand = args.isHydrogen\n ? 'shopify hydrogen build'\n : 'remix build';\n\n const instrumentedBuildCommand =\n `${buildCommand} --sourcemap && sentry-upload-sourcemaps --org ${args.org} --project ${args.project}` +\n (args.url ? ` --url ${args.url}` : '') +\n (args.isHydrogen ? ' --buildPath ./dist' : '');\n\n if (!packageJson.scripts.build) {\n packageJson.scripts.build = instrumentedBuildCommand;\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n } else if (packageJson.scripts.build.includes(buildCommand)) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n packageJson.scripts.build = packageJson.scripts.build.replace(\n buildCommand,\n instrumentedBuildCommand,\n );\n } else {\n throw new Error(\n \"`build` script doesn't contain a known build command. Please update it manually.\",\n );\n }\n\n await fs.promises.writeFile(\n path.join(process.cwd(), 'package.json'),\n JSON.stringify(packageJson, null, 2),\n );\n\n clack.log.success(\n `Successfully updated ${chalk.cyan('build')} script in ${chalk.cyan(\n 'package.json',\n )} to generate and upload sourcemaps.`,\n );\n /* eslint-enable @typescript-eslint/no-unsafe-member-access */\n}\n\nexport async function initializeSentryOnEntryClient(\n dsn: string,\n isTS: boolean,\n): Promise<void> {\n const clientEntryFilename = `entry.client.${isTS ? 'tsx' : 'jsx'}`;\n\n const originalEntryClient = path.join(\n process.cwd(),\n 'app',\n clientEntryFilename,\n );\n\n const originalEntryClientMod = await loadFile(originalEntryClient);\n\n if (hasSentryContent(originalEntryClient, originalEntryClientMod.$code)) {\n return;\n }\n\n originalEntryClientMod.imports.$add({\n from: '@sentry/remix',\n imported: '*',\n local: 'Sentry',\n });\n\n originalEntryClientMod.imports.$add({\n from: 'react',\n imported: 'useEffect',\n local: 'useEffect',\n });\n\n originalEntryClientMod.imports.$add({\n from: '@remix-run/react',\n imported: 'useLocation',\n local: 'useLocation',\n });\n\n originalEntryClientMod.imports.$add({\n from: '@remix-run/react',\n imported: 'useMatches',\n local: 'useMatches',\n });\n\n insertClientInitCall(dsn, originalEntryClientMod);\n\n await writeFile(\n originalEntryClientMod.$ast,\n path.join(process.cwd(), 'app', clientEntryFilename),\n );\n\n clack.log.success(\n `Successfully initialized Sentry on client entry point ${chalk.cyan(\n clientEntryFilename,\n )}`,\n );\n}\n\nexport async function updateStartScript(instrumentationFile: string) {\n const packageJson = await getPackageDotJson();\n\n if (!packageJson.scripts || !packageJson.scripts.start) {\n throw new Error(\n \"Couldn't find a `start` script in your package.json. Please add one manually.\",\n );\n }\n\n if (packageJson.scripts.start.includes('NODE_OPTIONS')) {\n clack.log.warn(\n `Found existing NODE_OPTIONS in ${chalk.cyan(\n 'start',\n )} script. Skipping adding Sentry initialization.`,\n );\n\n return;\n }\n\n if (\n !packageJson.scripts.start.includes('remix-serve') &&\n // Adding a following empty space not to match a path that includes `node`\n !packageJson.scripts.start.includes('node ')\n ) {\n clack.log.warn(\n `Found a ${chalk.cyan('start')} script that doesn't use ${chalk.cyan(\n 'remix-serve',\n )} or ${chalk.cyan('node')}. Skipping adding Sentry initialization.`,\n );\n\n return;\n }\n\n const startCommand = packageJson.scripts.start;\n\n packageJson.scripts.start = `NODE_OPTIONS='--import ./${instrumentationFile}' ${startCommand}`;\n\n await fs.promises.writeFile(\n path.join(process.cwd(), 'package.json'),\n JSON.stringify(packageJson, null, 2),\n );\n\n clack.log.success(\n `Successfully updated ${chalk.cyan('start')} script in ${chalk.cyan(\n 'package.json',\n )} to include Sentry initialization on start.`,\n );\n}\n\nexport async function instrumentSentryOnEntryServer(\n isV2: boolean,\n isTS: boolean,\n): Promise<void> {\n const serverEntryFilename = `entry.server.${isTS ? 'tsx' : 'jsx'}`;\n\n const originalEntryServer = path.join(\n process.cwd(),\n 'app',\n serverEntryFilename,\n );\n\n const originalEntryServerMod = await loadFile(originalEntryServer);\n\n if (hasSentryContent(originalEntryServer, originalEntryServerMod.$code)) {\n return;\n }\n\n originalEntryServerMod.imports.$add({\n from: '@sentry/remix',\n imported: '*',\n local: 'Sentry',\n });\n\n if (isV2) {\n const handleErrorInstrumented = instrumentHandleError(\n originalEntryServerMod,\n serverEntryFilename,\n );\n\n if (handleErrorInstrumented) {\n clack.log.success(\n `Instrumented ${chalk.cyan('handleError')} in ${chalk.cyan(\n `${serverEntryFilename}`,\n )}`,\n );\n }\n }\n\n await writeFile(\n originalEntryServerMod.$ast,\n path.join(process.cwd(), 'app', serverEntryFilename),\n );\n\n clack.log.success(\n `Successfully initialized Sentry on server entry point ${chalk.cyan(\n serverEntryFilename,\n )}.`,\n );\n}\n"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare const ERROR_BOUNDARY_TEMPLATE_V2 = "const ErrorBoundary = () => {\n const error = useRouteError();\n captureRemixErrorBoundaryError(error);\n return <div>Something went wrong</div>;\n};\n";
|
|
2
|
-
export declare const HANDLE_ERROR_TEMPLATE_V2 = "function handleError(error, { request }) {\n Sentry.captureRemixServerException(error, 'remix.server', request);\n}\n";
|
|
2
|
+
export declare const HANDLE_ERROR_TEMPLATE_V2 = "function handleError(error, { request }) {\n Sentry.captureRemixServerException(error, 'remix.server', request, true);\n}\n";
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.HANDLE_ERROR_TEMPLATE_V2 = exports.ERROR_BOUNDARY_TEMPLATE_V2 = void 0;
|
|
4
4
|
exports.ERROR_BOUNDARY_TEMPLATE_V2 = "const ErrorBoundary = () => {\n const error = useRouteError();\n captureRemixErrorBoundaryError(error);\n return <div>Something went wrong</div>;\n};\n";
|
|
5
|
-
exports.HANDLE_ERROR_TEMPLATE_V2 = "function handleError(error, { request }) {\n Sentry.captureRemixServerException(error, 'remix.server', request);\n}\n";
|
|
5
|
+
exports.HANDLE_ERROR_TEMPLATE_V2 = "function handleError(error, { request }) {\n Sentry.captureRemixServerException(error, 'remix.server', request, true);\n}\n";
|
|
6
6
|
//# sourceMappingURL=templates.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../../src/remix/templates.ts"],"names":[],"mappings":";;;AAAa,QAAA,0BAA0B,GAAG,4JAKzC,CAAC;AAEW,QAAA,wBAAwB,GAAG,
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../../src/remix/templates.ts"],"names":[],"mappings":";;;AAAa,QAAA,0BAA0B,GAAG,4JAKzC,CAAC;AAEW,QAAA,wBAAwB,GAAG,8HAGvC,CAAC","sourcesContent":["export const ERROR_BOUNDARY_TEMPLATE_V2 = `const ErrorBoundary = () => {\n const error = useRouteError();\n captureRemixErrorBoundaryError(error);\n return <div>Something went wrong</div>;\n};\n`;\n\nexport const HANDLE_ERROR_TEMPLATE_V2 = `function handleError(error, { request }) {\n Sentry.captureRemixServerException(error, 'remix.server', request, true);\n}\n`;\n"]}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import type { Program } from '@babel/types';
|
|
2
2
|
import { PackageDotJson } from '../utils/package-json';
|
|
3
|
-
export declare
|
|
3
|
+
export declare const POSSIBLE_SERVER_INSTRUMENTATION_PATHS: string[];
|
|
4
|
+
export declare function hasSentryContent(fileName: string, fileContent: string, expectedContent?: string): boolean;
|
|
5
|
+
export declare function serverHasInstrumentationImport(serverFileName: string, serverFileContent: string): boolean;
|
|
4
6
|
/**
|
|
5
|
-
* We want to insert the init call on top of the file
|
|
7
|
+
* We want to insert the init call on top of the file, before any other imports.
|
|
6
8
|
*/
|
|
7
|
-
export declare function
|
|
9
|
+
export declare function getBeforeImportsInsertionIndex(originalHooksModAST: Program): number;
|
|
10
|
+
/**
|
|
11
|
+
* We want to insert the handleError function just after all imports
|
|
12
|
+
*/
|
|
13
|
+
export declare function getAfterImportsInsertionIndex(originalEntryServerModAST: Program): number;
|
|
8
14
|
export declare function isHydrogenApp(packageJson: PackageDotJson): boolean;
|
package/dist/src/remix/utils.js
CHANGED
|
@@ -26,33 +26,62 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.isHydrogenApp = exports.
|
|
29
|
+
exports.isHydrogenApp = exports.getAfterImportsInsertionIndex = exports.getBeforeImportsInsertionIndex = exports.serverHasInstrumentationImport = exports.hasSentryContent = exports.POSSIBLE_SERVER_INSTRUMENTATION_PATHS = void 0;
|
|
30
30
|
var path = __importStar(require("path"));
|
|
31
31
|
// @ts-expect-error - clack is ESM and TS complains about that. It works though
|
|
32
32
|
var prompts_1 = __importDefault(require("@clack/prompts"));
|
|
33
33
|
var chalk_1 = __importDefault(require("chalk"));
|
|
34
34
|
var package_json_1 = require("../utils/package-json");
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
exports.POSSIBLE_SERVER_INSTRUMENTATION_PATHS = [
|
|
36
|
+
'./instrumentation',
|
|
37
|
+
'./instrumentation.server',
|
|
38
|
+
];
|
|
39
|
+
function hasSentryContent(fileName, fileContent, expectedContent) {
|
|
40
|
+
if (expectedContent === void 0) { expectedContent = '@sentry/remix'; }
|
|
41
|
+
var includesContent = fileContent.includes(expectedContent);
|
|
38
42
|
if (includesContent) {
|
|
39
|
-
prompts_1.default.log.warn("File ".concat(chalk_1.default.cyan(path.basename(fileName)), " already contains
|
|
43
|
+
prompts_1.default.log.warn("File ".concat(chalk_1.default.cyan(path.basename(fileName)), " already contains ").concat(expectedContent, ".\nSkipping adding Sentry functionality to ").concat(chalk_1.default.cyan(path.basename(fileName)), "."));
|
|
40
44
|
}
|
|
41
45
|
return includesContent;
|
|
42
46
|
}
|
|
43
47
|
exports.hasSentryContent = hasSentryContent;
|
|
48
|
+
function serverHasInstrumentationImport(serverFileName, serverFileContent) {
|
|
49
|
+
var includesServerInstrumentationImport = exports.POSSIBLE_SERVER_INSTRUMENTATION_PATHS.some(function (path) {
|
|
50
|
+
return serverFileContent.includes(path);
|
|
51
|
+
});
|
|
52
|
+
if (includesServerInstrumentationImport) {
|
|
53
|
+
prompts_1.default.log.warn("File ".concat(chalk_1.default.cyan(path.basename(serverFileName)), " already contains instrumentation import.\nSkipping adding instrumentation functionality to ").concat(chalk_1.default.cyan(path.basename(serverFileName)), "."));
|
|
54
|
+
}
|
|
55
|
+
return includesServerInstrumentationImport;
|
|
56
|
+
}
|
|
57
|
+
exports.serverHasInstrumentationImport = serverHasInstrumentationImport;
|
|
58
|
+
/**
|
|
59
|
+
* We want to insert the init call on top of the file, before any other imports.
|
|
60
|
+
*/
|
|
61
|
+
function getBeforeImportsInsertionIndex(originalHooksModAST) {
|
|
62
|
+
for (var x = 0; x < originalHooksModAST.body.length - 1; x++) {
|
|
63
|
+
if (originalHooksModAST.body[x].type === 'ImportDeclaration' &&
|
|
64
|
+
// @ts-expect-error - source is available in body
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
66
|
+
originalHooksModAST.body[x].source.value === '@sentry/remix') {
|
|
67
|
+
return x + 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
exports.getBeforeImportsInsertionIndex = getBeforeImportsInsertionIndex;
|
|
44
73
|
/**
|
|
45
|
-
* We want to insert the
|
|
74
|
+
* We want to insert the handleError function just after all imports
|
|
46
75
|
*/
|
|
47
|
-
function
|
|
48
|
-
for (var x =
|
|
49
|
-
if (
|
|
76
|
+
function getAfterImportsInsertionIndex(originalEntryServerModAST) {
|
|
77
|
+
for (var x = originalEntryServerModAST.body.length - 1; x >= 0; x--) {
|
|
78
|
+
if (originalEntryServerModAST.body[x].type === 'ImportDeclaration') {
|
|
50
79
|
return x + 1;
|
|
51
80
|
}
|
|
52
81
|
}
|
|
53
82
|
return 0;
|
|
54
83
|
}
|
|
55
|
-
exports.
|
|
84
|
+
exports.getAfterImportsInsertionIndex = getAfterImportsInsertionIndex;
|
|
56
85
|
function isHydrogenApp(packageJson) {
|
|
57
86
|
return (0, package_json_1.hasPackageInstalled)('@shopify/hydrogen', packageJson);
|
|
58
87
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/remix/utils.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,yCAA6B;AAE7B,+EAA+E;AAC/E,2DAAmC;AACnC,gDAA0B;AAC1B,sDAA4E;
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/remix/utils.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,yCAA6B;AAE7B,+EAA+E;AAC/E,2DAAmC;AACnC,gDAA0B;AAC1B,sDAA4E;AAE/D,QAAA,qCAAqC,GAAG;IACnD,mBAAmB;IACnB,0BAA0B;CAC3B,CAAC;AAEF,SAAgB,gBAAgB,CAC9B,QAAgB,EAChB,WAAmB,EACnB,eAAiC;IAAjC,gCAAA,EAAA,iCAAiC;IAEjC,IAAM,eAAe,GAAG,WAAW,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IAE9D,IAAI,eAAe,EAAE;QACnB,iBAAK,CAAC,GAAG,CAAC,IAAI,CACZ,eAAQ,eAAK,CAAC,IAAI,CAChB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CACxB,+BAAqB,eAAe,wDACD,eAAK,CAAC,IAAI,CAC5C,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CACxB,MAAG,CACL,CAAC;KACH;IAED,OAAO,eAAe,CAAC;AACzB,CAAC;AAnBD,4CAmBC;AAED,SAAgB,8BAA8B,CAC5C,cAAsB,EACtB,iBAAyB;IAEzB,IAAM,mCAAmC,GACvC,6CAAqC,CAAC,IAAI,CAAC,UAAC,IAAI;QAC9C,OAAA,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC;IAAhC,CAAgC,CACjC,CAAC;IAEJ,IAAI,mCAAmC,EAAE;QACvC,iBAAK,CAAC,GAAG,CAAC,IAAI,CACZ,eAAQ,eAAK,CAAC,IAAI,CAChB,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAC9B,yGAC4C,eAAK,CAAC,IAAI,CACrD,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAC9B,MAAG,CACL,CAAC;KACH;IAED,OAAO,mCAAmC,CAAC;AAC7C,CAAC;AArBD,wEAqBC;AAED;;GAEG;AACH,SAAgB,8BAA8B,CAC5C,mBAA4B;IAE5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,mBAAmB,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;QAC5D,IACE,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,mBAAmB;YACxD,iDAAiD;YACjD,sEAAsE;YACtE,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,KAAK,eAAe,EAC5D;YACA,OAAO,CAAC,GAAG,CAAC,CAAC;SACd;KACF;IAED,OAAO,CAAC,CAAC;AACX,CAAC;AAfD,wEAeC;AAED;;GAEG;AACH,SAAgB,6BAA6B,CAC3C,yBAAkC;IAElC,KAAK,IAAI,CAAC,GAAG,yBAAyB,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;QACnE,IAAI,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,mBAAmB,EAAE;YAClE,OAAO,CAAC,GAAG,CAAC,CAAC;SACd;KACF;IAED,OAAO,CAAC,CAAC;AACX,CAAC;AAVD,sEAUC;AAED,SAAgB,aAAa,CAAC,WAA2B;IACvD,OAAO,IAAA,kCAAmB,EAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;AAC/D,CAAC;AAFD,sCAEC","sourcesContent":["import type { Program } from '@babel/types';\n\nimport * as path from 'path';\n\n// @ts-expect-error - clack is ESM and TS complains about that. It works though\nimport clack from '@clack/prompts';\nimport chalk from 'chalk';\nimport { PackageDotJson, hasPackageInstalled } from '../utils/package-json';\n\nexport const POSSIBLE_SERVER_INSTRUMENTATION_PATHS = [\n './instrumentation',\n './instrumentation.server',\n];\n\nexport function hasSentryContent(\n fileName: string,\n fileContent: string,\n expectedContent = '@sentry/remix',\n): boolean {\n const includesContent = fileContent.includes(expectedContent);\n\n if (includesContent) {\n clack.log.warn(\n `File ${chalk.cyan(\n path.basename(fileName),\n )} already contains ${expectedContent}.\nSkipping adding Sentry functionality to ${chalk.cyan(\n path.basename(fileName),\n )}.`,\n );\n }\n\n return includesContent;\n}\n\nexport function serverHasInstrumentationImport(\n serverFileName: string,\n serverFileContent: string,\n): boolean {\n const includesServerInstrumentationImport =\n POSSIBLE_SERVER_INSTRUMENTATION_PATHS.some((path) =>\n serverFileContent.includes(path),\n );\n\n if (includesServerInstrumentationImport) {\n clack.log.warn(\n `File ${chalk.cyan(\n path.basename(serverFileName),\n )} already contains instrumentation import.\nSkipping adding instrumentation functionality to ${chalk.cyan(\n path.basename(serverFileName),\n )}.`,\n );\n }\n\n return includesServerInstrumentationImport;\n}\n\n/**\n * We want to insert the init call on top of the file, before any other imports.\n */\nexport function getBeforeImportsInsertionIndex(\n originalHooksModAST: Program,\n): number {\n for (let x = 0; x < originalHooksModAST.body.length - 1; x++) {\n if (\n originalHooksModAST.body[x].type === 'ImportDeclaration' &&\n // @ts-expect-error - source is available in body\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n originalHooksModAST.body[x].source.value === '@sentry/remix'\n ) {\n return x + 1;\n }\n }\n\n return 0;\n}\n\n/**\n * We want to insert the handleError function just after all imports\n */\nexport function getAfterImportsInsertionIndex(\n originalEntryServerModAST: Program,\n): number {\n for (let x = originalEntryServerModAST.body.length - 1; x >= 0; x--) {\n if (originalEntryServerModAST.body[x].type === 'ImportDeclaration') {\n return x + 1;\n }\n }\n\n return 0;\n}\n\nexport function isHydrogenApp(packageJson: PackageDotJson): boolean {\n return hasPackageInstalled('@shopify/hydrogen', packageJson);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/wizard",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.24.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",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@sentry/node": "^7.69.0",
|
|
30
30
|
"axios": "1.6.0",
|
|
31
31
|
"chalk": "^2.4.1",
|
|
32
|
-
"glob": "^
|
|
32
|
+
"glob": "^8.1.0",
|
|
33
33
|
"inquirer": "^6.2.0",
|
|
34
34
|
"lodash": "^4.17.15",
|
|
35
35
|
"magicast": "^0.2.10",
|
package/src/react-native/glob.ts
CHANGED
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
// @ts-expect-error - clack is ESM and TS complains about that. It works though
|
|
2
|
-
import clack from '@clack/prompts';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import * as recast from 'recast';
|
|
5
|
-
import { visit } from 'ast-types';
|
|
6
1
|
import {
|
|
7
|
-
ProxifiedImportItem,
|
|
8
|
-
generateCode,
|
|
9
2
|
loadFile,
|
|
10
|
-
writeFile,
|
|
11
3
|
// @ts-expect-error - magicast is ESM and TS complains about that. It works though
|
|
12
4
|
} from 'magicast';
|
|
13
|
-
import type { Program } from '@babel/types';
|
|
14
5
|
import * as fs from 'fs';
|
|
15
6
|
|
|
16
|
-
import { getInitCallInsertionIndex, hasSentryContent } from '../utils';
|
|
17
7
|
import { findFile } from '../../utils/ast-utils';
|
|
18
8
|
|
|
19
9
|
// Try to find the Express server implementation that contains `createRequestHandler` from `@remix-run/express`
|
|
@@ -52,114 +42,3 @@ export async function findCustomExpressServerImplementation() {
|
|
|
52
42
|
|
|
53
43
|
return null;
|
|
54
44
|
}
|
|
55
|
-
|
|
56
|
-
// Wrap createRequestHandler with `wrapExpressCreateRequestHandler` from `@sentry/remix`
|
|
57
|
-
export async function instrumentExpressCreateRequestHandler(
|
|
58
|
-
expressServerPath: string,
|
|
59
|
-
): Promise<boolean> {
|
|
60
|
-
const originalExpressServerMod = await loadFile(expressServerPath);
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
hasSentryContent(
|
|
64
|
-
generateCode(originalExpressServerMod.$ast).code,
|
|
65
|
-
originalExpressServerMod.$code,
|
|
66
|
-
)
|
|
67
|
-
) {
|
|
68
|
-
clack.log.warn(
|
|
69
|
-
`Express server in ${chalk.cyan(
|
|
70
|
-
expressServerPath,
|
|
71
|
-
)} already has Sentry instrumentation. Skipping.`,
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
originalExpressServerMod.imports.$add({
|
|
78
|
-
from: '@sentry/remix',
|
|
79
|
-
imported: 'wrapExpressCreateRequestHandler',
|
|
80
|
-
local: 'wrapExpressCreateRequestHandler',
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
const createRequestHandlerImport =
|
|
84
|
-
originalExpressServerMod.imports.$items.find(
|
|
85
|
-
(imp) =>
|
|
86
|
-
imp.from === '@remix-run/express' &&
|
|
87
|
-
imp.imported === 'createRequestHandler',
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
visit(originalExpressServerMod.$ast, {
|
|
91
|
-
visitIdentifier(path) {
|
|
92
|
-
if (
|
|
93
|
-
path.value.name === 'createRequestHandler' &&
|
|
94
|
-
path.parentPath.value.type === 'CallExpression'
|
|
95
|
-
) {
|
|
96
|
-
path.value.name = 'sentryCreateRequestHandler';
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
this.traverse(path);
|
|
100
|
-
},
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
// Insert the const declaration right after the imports
|
|
104
|
-
// Where we want to insert the const declaration is the same as where we would want to insert the init call.
|
|
105
|
-
const insertionIndex = getInitCallInsertionIndex(
|
|
106
|
-
originalExpressServerMod.$ast as Program,
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
const createRequestHandlerConst = wrapCreateRequestHandlerWithSentry(
|
|
110
|
-
createRequestHandlerImport,
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
if (!createRequestHandlerConst) {
|
|
114
|
-
// Todo: throw error
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
(originalExpressServerMod.$ast as Program).body.splice(
|
|
118
|
-
insertionIndex,
|
|
119
|
-
0,
|
|
120
|
-
// @ts-expect-error - string works here because the AST is proxified by magicast
|
|
121
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
122
|
-
createRequestHandlerConst,
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
await writeFile(originalExpressServerMod.$ast, expressServerPath);
|
|
127
|
-
|
|
128
|
-
clack.log.info(
|
|
129
|
-
`Successfully instrumented Express server in ${chalk.cyan(
|
|
130
|
-
expressServerPath,
|
|
131
|
-
)}.`,
|
|
132
|
-
);
|
|
133
|
-
} catch (e) {
|
|
134
|
-
clack.log.warn(
|
|
135
|
-
`Could not write to Express server in ${chalk.cyan(expressServerPath)}.`,
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
throw e;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Wrap `createRequestHandler` with `wrapExpressCreateRequestHandler` and set const name to `sentryCreateRequestHandler`
|
|
145
|
-
export function wrapCreateRequestHandlerWithSentry(
|
|
146
|
-
createRequestHandlerImport: ProxifiedImportItem | undefined,
|
|
147
|
-
) {
|
|
148
|
-
if (!createRequestHandlerImport) {
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const createRequestHandler = createRequestHandlerImport.local;
|
|
153
|
-
|
|
154
|
-
const wrapCreateRequestHandler = recast.types.builders.callExpression(
|
|
155
|
-
recast.types.builders.identifier('wrapExpressCreateRequestHandler'),
|
|
156
|
-
[recast.types.builders.identifier(createRequestHandler)],
|
|
157
|
-
);
|
|
158
|
-
|
|
159
|
-
return recast.types.builders.variableDeclaration('const', [
|
|
160
|
-
recast.types.builders.variableDeclarator(
|
|
161
|
-
recast.types.builders.identifier('sentryCreateRequestHandler'),
|
|
162
|
-
wrapCreateRequestHandler,
|
|
163
|
-
),
|
|
164
|
-
]);
|
|
165
|
-
}
|
|
@@ -7,7 +7,7 @@ import type { Program } from '@babel/types';
|
|
|
7
7
|
import * as recast from 'recast';
|
|
8
8
|
|
|
9
9
|
import { HANDLE_ERROR_TEMPLATE_V2 } from '../templates';
|
|
10
|
-
import {
|
|
10
|
+
import { getAfterImportsInsertionIndex, hasSentryContent } from '../utils';
|
|
11
11
|
|
|
12
12
|
// @ts-expect-error - clack is ESM and TS complains about that. It works though
|
|
13
13
|
import clack from '@clack/prompts';
|
|
@@ -41,7 +41,7 @@ export function instrumentHandleError(
|
|
|
41
41
|
.body[0];
|
|
42
42
|
|
|
43
43
|
originalEntryServerModAST.body.splice(
|
|
44
|
-
|
|
44
|
+
getAfterImportsInsertionIndex(originalEntryServerModAST),
|
|
45
45
|
0,
|
|
46
46
|
// @ts-expect-error - string works here because the AST is proxified by magicast
|
|
47
47
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
@@ -51,6 +51,7 @@ export function instrumentHandleError(
|
|
|
51
51
|
hasSentryContent(
|
|
52
52
|
generateCode(handleErrorFunction).code,
|
|
53
53
|
originalEntryServerMod.$code,
|
|
54
|
+
'captureRemixServerException',
|
|
54
55
|
)
|
|
55
56
|
) {
|
|
56
57
|
return false;
|