@sentry/react-native
Version:
Official Sentry SDK for react-native
145 lines • 7.57 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSentryMetroSerializer = exports.unstableBeforeAssetSerializationDebugIdPlugin = void 0;
const crypto = require("crypto");
const utils_1 = require("./utils");
const utils_2 = require("./vendor/metro/utils");
const DEBUG_ID_PLACE_HOLDER = '__debug_id_place_holder__';
const DEBUG_ID_MODULE_PATH = '__debugid__';
const SOURCE_MAP_COMMENT = '//# sourceMappingURL=';
const DEBUG_ID_COMMENT = '//# debugId=';
/**
* Adds Sentry Debug ID polyfill module to the bundle.
*/
function unstableBeforeAssetSerializationDebugIdPlugin({ premodules, debugId, }) {
if (!debugId) {
return premodules;
}
const debugIdModuleExists = premodules.findIndex(module => module.path === DEBUG_ID_MODULE_PATH) != -1;
if (debugIdModuleExists) {
// eslint-disable-next-line no-console
console.warn('\n\nDebug ID module found. Skipping Sentry Debug ID module...\n\n');
return premodules;
}
const debugIdModule = createDebugIdModule(debugId);
return (0, utils_1.prependModule)(premodules, debugIdModule);
}
exports.unstableBeforeAssetSerializationDebugIdPlugin = unstableBeforeAssetSerializationDebugIdPlugin;
/**
* Creates a Metro serializer that adds Debug ID module to the plain bundle.
* The Debug ID module is a virtual module that provides a debug ID in runtime.
*
* RAM Bundles do not support custom serializers.
*/
const createSentryMetroSerializer = (customSerializer) => {
const serializer = customSerializer || (0, utils_2.createDefaultMetroSerializer)();
return function (entryPoint, preModules, graph, options) {
return __awaiter(this, void 0, void 0, function* () {
if (graph.transformOptions.hot) {
return serializer(entryPoint, preModules, graph, options);
}
const debugIdModuleExists = preModules.findIndex(module => module.path === DEBUG_ID_MODULE_PATH) != -1;
if (debugIdModuleExists) {
// eslint-disable-next-line no-console
console.warn('Debug ID module found. Skipping Sentry Debug ID module...');
return serializer(entryPoint, preModules, graph, options);
}
const debugIdModule = createDebugIdModule(DEBUG_ID_PLACE_HOLDER);
options.sentryBundleCallback = createSentryBundleCallback(debugIdModule);
const modifiedPreModules = (0, utils_1.prependModule)(preModules, debugIdModule);
// Run wrapped serializer
const serializerResult = serializer(entryPoint, modifiedPreModules, graph, options);
const { code: bundleCode, map: bundleMapString } = yield extractSerializerResult(serializerResult);
// Add debug id comment to the bundle
let debugId = (0, utils_1.determineDebugIdFromBundleSource)(bundleCode);
if (!debugId) {
// For lazy-loaded chunks or bundles without the debug ID module,
// calculate the debug ID from the bundle content.
// This ensures Metro 0.83.2+ code-split bundles get debug IDs.
// That needs to be done because when Metro 0.83.2 stopped importing `BabelSourceMapSegment`
// from `@babel/generator` and defined it locally, it subtly changed the source map output format.
// https://github.com/facebook/metro/blob/main/packages/metro-source-map/src/source-map.js#L47
debugId = calculateDebugId(bundleCode);
// eslint-disable-next-line no-console
console.log('info ' + `Bundle Debug ID (calculated): ${debugId}`);
}
// Only print debug id for command line builds => not hot reload from dev server
// eslint-disable-next-line no-console
console.log('info ' + `Bundle Debug ID: ${debugId}`);
const debugIdComment = `${DEBUG_ID_COMMENT}${debugId}`;
const indexOfSourceMapComment = bundleCode.lastIndexOf(SOURCE_MAP_COMMENT);
const bundleCodeWithDebugId = indexOfSourceMapComment === -1
? // If source map comment is missing lets just add the debug id comment
`${bundleCode}\n${debugIdComment}`
: // If source map comment is present lets add the debug id comment before it
`${bundleCode.substring(0, indexOfSourceMapComment) + debugIdComment}\n${bundleCode.substring(indexOfSourceMapComment)}`;
const bundleMap = JSON.parse(bundleMapString);
// For now we write both fields until we know what will become the standard - if ever.
bundleMap['debug_id'] = debugId;
bundleMap['debugId'] = debugId;
return {
code: bundleCodeWithDebugId,
map: JSON.stringify(bundleMap),
};
});
};
};
exports.createSentryMetroSerializer = createSentryMetroSerializer;
/**
* This function is expected to be called after serializer creates the final bundle object
* and before the source maps are generated.
*
* It injects a debug ID into the bundle and returns the modified bundle.
*
* Access it via `options.sentryBundleCallback` in your custom serializer.
*/
function createSentryBundleCallback(debugIdModule) {
return (bundle) => {
const debugId = calculateDebugId(bundle.pre, bundle.modules);
debugIdModule.setSource(injectDebugId(debugIdModule.getSource().toString(), debugId));
bundle.pre = injectDebugId(bundle.pre, debugId);
return bundle;
};
}
function extractSerializerResult(serializerResult) {
return __awaiter(this, void 0, void 0, function* () {
if (typeof serializerResult === 'string') {
return { code: serializerResult, map: '{}' };
}
if ('map' in serializerResult) {
return { code: serializerResult.code, map: serializerResult.map };
}
const awaitedResult = yield serializerResult;
if (typeof awaitedResult === 'string') {
return { code: awaitedResult, map: '{}' };
}
return { code: awaitedResult.code, map: awaitedResult.map };
});
}
function createDebugIdModule(debugId) {
return (0, utils_1.createVirtualJSModule)(DEBUG_ID_MODULE_PATH, (0, utils_1.createDebugIdSnippet)(debugId));
}
function calculateDebugId(bundleCode, modules) {
const hash = crypto.createHash('md5');
hash.update(bundleCode);
if (modules) {
for (const [, code] of modules) {
hash.update(code);
}
}
return (0, utils_1.stringToUUID)(hash.digest('hex'));
}
function injectDebugId(code, debugId) {
// eslint-disable-next-line @sentry-internal/sdk/no-regexp-constructor
return code.replace(new RegExp(DEBUG_ID_PLACE_HOLDER, 'g'), debugId);
}
//# sourceMappingURL=sentryMetroSerializer.js.map