@sentry/react-native
Version:
Official Sentry SDK for react-native
127 lines • 5.65 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.withSentryOptionsFromFile = withSentryOptionsFromFile;
const core_1 = require("@sentry/core");
const fs = require("fs");
const path = require("path");
const utils_1 = require("./utils");
const countLines_1 = require("./vendor/metro/countLines");
const DEFAULT_OPTIONS_FILE_NAME = 'sentry.options.json';
/**
* Loads Sentry options from a file in
*/
function withSentryOptionsFromFile(config, optionsFile) {
var _a;
if (optionsFile === false) {
return config;
}
const { projectRoot } = config;
if (!projectRoot) {
// oxlint-disable-next-line eslint(no-console)
console.error('[@sentry/react-native/metro] Project root is required to load Sentry options from a file');
return config;
}
let optionsPath = path.join(projectRoot, DEFAULT_OPTIONS_FILE_NAME);
if (typeof optionsFile === 'string' && path.isAbsolute(optionsFile)) {
optionsPath = optionsFile;
}
else if (typeof optionsFile === 'string') {
optionsPath = path.join(projectRoot, optionsFile);
}
const originalSerializer = (_a = config.serializer) === null || _a === void 0 ? void 0 : _a.customSerializer;
if (!originalSerializer) {
// It's okay to bail here because we don't expose this for direct usage, but as part of `withSentryConfig`
// If used directly in RN, the user is responsible for providing a custom serializer first, Expo provides serializer in default config
// oxlint-disable-next-line eslint(no-console)
console.error('[@sentry/react-native/metro] `config.serializer.customSerializer` is required to load Sentry options from a file');
return config;
}
const sentryOptionsSerializer = (entryPoint, preModules, graph, options) => {
const sentryOptionsModule = createSentryOptionsModule(optionsPath);
if (sentryOptionsModule) {
preModules.push(sentryOptionsModule);
}
return originalSerializer(entryPoint, preModules, graph, options);
};
// Preserve Expo's __originalSerializer marker so Expo can detect user-provided serializers
if ('__originalSerializer' in originalSerializer) {
Object.assign(sentryOptionsSerializer, {
__originalSerializer: originalSerializer.__originalSerializer,
});
}
// @ts-expect-error customSerializer is typed read only in metro 0.84+
config.serializer.customSerializer = sentryOptionsSerializer;
return config;
}
function createSentryOptionsModule(filePath) {
let content;
try {
content = fs.readFileSync(filePath, 'utf8');
}
catch (error) {
if (error.code === 'ENOENT') {
core_1.logger.debug(`[@sentry/react-native/metro] Sentry options file does not exist at ${filePath}`);
}
else {
core_1.logger.error(`[@sentry/react-native/metro] Failed to read Sentry options file at ${filePath}`);
}
return null;
}
let parsedContent;
try {
parsedContent = JSON.parse(content);
}
catch (error) {
core_1.logger.error(`[@sentry/react-native/metro] Failed to parse Sentry options file at ${filePath}`);
return null;
}
applySentryOptionsEnvOverrides(parsedContent);
const minifiedContent = JSON.stringify(parsedContent);
const optionsCode = `var __SENTRY_OPTIONS__=${minifiedContent};`;
core_1.logger.debug(`[@sentry/react-native/metro] Sentry options added to the bundle from file at ${filePath}`);
return {
dependencies: new Map(),
getSource: () => Buffer.from(optionsCode),
inverseDependencies: (0, utils_1.createSet)(),
path: '__sentry-options__',
output: [
{
type: 'js/script/virtual',
data: {
code: optionsCode,
lineCount: (0, countLines_1.default)(optionsCode),
map: [],
},
},
],
};
}
/**
* Applies the `SENTRY_ENVIRONMENT`, `SENTRY_RELEASE` and `SENTRY_DIST` build-time overrides to the
* options bundled into the JS (`__SENTRY_OPTIONS__`).
*
* The native build steps (`sentry-xcode.sh`, `sentry.gradle.kts`) already apply these env variables
* to the native copy of `sentry.options.json`. Without mirroring them here, the native SDK (which owns
* release health sessions on mobile) and the JS layer can end up with a different `environment`,
* `release` or `dist`, splitting session and event data across releases/environments.
*/
function applySentryOptionsEnvOverrides(options) {
// The options file is expected to contain a JSON object. Guard against valid-but-unexpected JSON
// (e.g. a primitive or `null`), where assigning a property would throw in strict mode.
if (typeof options !== 'object' || options === null) {
return;
}
if (process.env.SENTRY_ENVIRONMENT) {
options.environment = process.env.SENTRY_ENVIRONMENT;
core_1.logger.debug(`[@sentry/react-native/metro] Overriding 'environment' from SENTRY_ENVIRONMENT environment variable`);
}
if (process.env.SENTRY_RELEASE) {
options.release = process.env.SENTRY_RELEASE;
core_1.logger.debug(`[@sentry/react-native/metro] Overriding 'release' from SENTRY_RELEASE environment variable`);
}
if (process.env.SENTRY_DIST) {
options.dist = process.env.SENTRY_DIST;
core_1.logger.debug(`[@sentry/react-native/metro] Overriding 'dist' from SENTRY_DIST environment variable`);
}
}
//# sourceMappingURL=sentryOptionsSerializer.js.map