UNPKG

@sentry/react-native

Version:
342 lines 14.8 kB
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()); }); }; import { debug, getClient, getGlobalScope, getIntegrationsToSetup, getIsolationScope, initAndBind, makeDsn, stackParserFromStackParserOptions, withScope as coreWithScope, } from '@sentry/core'; import { defaultStackParser, makeFetchTransport, Profiler } from '@sentry/react'; import * as React from 'react'; import { ReactNativeClient } from './client'; import { FeedbackFormProvider } from './feedback/FeedbackFormProvider'; import { getDevServer } from './integrations/debugsymbolicatorutils'; import { getDefaultIntegrations } from './integrations/default'; import { shouldEnableNativeNagger } from './options'; import { enableSyncToNative } from './scopeSync'; import { TouchEventBoundary } from './touchevents'; import { ReactNativeProfiler } from './tracing'; import { _appLoaded, _extendAppStart, _finishExtendedAppStart, _getExtendedAppStartSpan, } from './tracing/integrations/appStart'; import { useEncodePolyfill } from './transports/encodePolyfill'; import { DEFAULT_BUFFER_SIZE, makeNativeTransportFactory } from './transports/native'; import { getDefaultEnvironment, isExpoGo, isRunningInMetroDevServer, isWeb } from './utils/environment'; import { registerFeatureMarker } from './utils/featureMarkers'; import { getDefaultRelease } from './utils/release'; import { safeFactory, safeTracesSampler } from './utils/safe'; import { checkSentryJsSdkVersionMismatch } from './utils/sdkVersionCheck'; import { RN_GLOBAL_OBJ } from './utils/worldwide'; import { NATIVE } from './wrapper'; const CAPTURE_APP_START_ERRORS_INTEGRATION_NAME = 'CaptureAppStartErrors'; const DEFAULT_OPTIONS = { enableNativeCrashHandling: true, enableNativeNagger: true, autoInitializeNativeSdk: true, enableAutoPerformanceTracing: true, enableWatchdogTerminationTracking: true, patchGlobalPromise: true, sendClientReports: true, maxQueueSize: DEFAULT_BUFFER_SIZE, attachStacktrace: true, enableCaptureFailedRequests: false, enableNdk: true, enableAppStartTracking: true, enableNativeFramesTracking: true, enableStallTracking: true, enableUserInteractionTracing: false, propagateTraceparent: false, }; /** * Inits the SDK and returns the final options. */ export function init(passedOptions) { var _a, _b, _c, _d, _e, _f; if (isRunningInMetroDevServer()) { return; } const userOptions = Object.assign(Object.assign({}, RN_GLOBAL_OBJ.__SENTRY_OPTIONS__), passedOptions); const maxQueueSize = (_c = (_a = userOptions.maxQueueSize) !== null && _a !== void 0 ? _a : (_b = userOptions.transportOptions) === null || _b === void 0 ? void 0 : _b.bufferSize) !== null && _c !== void 0 ? _c : DEFAULT_OPTIONS.maxQueueSize; const enableNative = userOptions.enableNative === undefined || userOptions.enableNative ? NATIVE.isNativeAvailable() : false; useEncodePolyfill(); if (enableNative) { enableSyncToNative(getGlobalScope()); enableSyncToNative(getIsolationScope()); } const getURLFromDSN = (dsn) => { if (!dsn) { return undefined; } const dsnComponents = makeDsn(dsn); if (!dsnComponents) { debug.error('Failed to extract url from DSN: ', dsn); return undefined; } const port = dsnComponents.port ? `:${dsnComponents.port}` : ''; return `${dsnComponents.protocol}://${dsnComponents.host}${port}`; }; const userBeforeBreadcrumb = safeFactory(userOptions.beforeBreadcrumb, { loggerMessage: 'The beforeBreadcrumb threw an error', }); // Exclude Dev Server and Sentry Dsn request from Breadcrumbs const devServerUrl = (_d = getDevServer()) === null || _d === void 0 ? void 0 : _d.url; const dsn = getURLFromDSN(userOptions.dsn); const defaultBeforeBreadcrumb = (breadcrumb, _hint) => { var _a; const type = breadcrumb.type || ''; const url = typeof ((_a = breadcrumb.data) === null || _a === void 0 ? void 0 : _a.url) === 'string' ? breadcrumb.data.url : ''; if (type === 'http' && ((devServerUrl && url.startsWith(devServerUrl)) || (dsn && url.startsWith(dsn)))) { return null; } return breadcrumb; }; const chainedBeforeBreadcrumb = (breadcrumb, hint) => { let modifiedBreadcrumb = breadcrumb; if (userBeforeBreadcrumb) { const result = userBeforeBreadcrumb(breadcrumb, hint); if (result === null) { return null; } modifiedBreadcrumb = result; } return defaultBeforeBreadcrumb(modifiedBreadcrumb, hint); }; const options = Object.assign(Object.assign(Object.assign({}, DEFAULT_OPTIONS), userOptions), { release: (_e = userOptions.release) !== null && _e !== void 0 ? _e : getDefaultRelease(), enableNative, enableNativeNagger: shouldEnableNativeNagger(userOptions.enableNativeNagger), // If custom transport factory fails the SDK won't initialize transport: userOptions.transport || makeNativeTransportFactory({ enableNative, }) || makeFetchTransport, transportOptions: Object.assign(Object.assign(Object.assign({}, DEFAULT_OPTIONS.transportOptions), ((_f = userOptions.transportOptions) !== null && _f !== void 0 ? _f : {})), { bufferSize: maxQueueSize }), maxQueueSize, integrations: [], stackParser: stackParserFromStackParserOptions(userOptions.stackParser || defaultStackParser), beforeBreadcrumb: chainedBeforeBreadcrumb, initialScope: safeFactory(userOptions.initialScope, { loggerMessage: 'The initialScope threw an error' }) }); if (!('autoInitializeNativeSdk' in userOptions) && RN_GLOBAL_OBJ.__SENTRY_OPTIONS__ && !__DEV__) { // Options file is present in a release build, native SDK is expected to be initialized // before JS from the native app entry point (e.g. AppDelegate, MainApplication). // In dev builds, we always re-initialize from JS to set up the native log bridge // and provide runtime values (devServerUrl, defaultSidecarUrl, etc.). // oxlint-disable-next-line eslint(no-console) console.info('[Sentry] Using options file. Native SDK is expected to be initialized before JS, skipping automatic native initialization from JS.'); options.autoInitializeNativeSdk = false; } if ('tracesSampler' in options) { options.tracesSampler = safeTracesSampler(options.tracesSampler); } if (!('environment' in options)) { options.environment = getDefaultEnvironment(); } const defaultIntegrations = userOptions.defaultIntegrations === undefined ? getDefaultIntegrations(options) : userOptions.defaultIntegrations; options.integrations = getIntegrationsToSetup({ integrations: safeFactory(userOptions.integrations, { loggerMessage: 'The integrations threw an error' }), defaultIntegrations, }); initAndBind(ReactNativeClient, options); if (__DEV__) { checkSentryJsSdkVersionMismatch(); } if (isExpoGo()) { debug.log('Offline caching, native errors features are not available in Expo Go.'); debug.log('Use EAS Build / Native Release Build to test these features.'); } if (RN_GLOBAL_OBJ.__SENTRY_OPTIONS__) { debug.log('Sentry JS initialized with options from the options file.'); // Adoption marker for the "capture app-start errors" feature: shipping // `sentry.options.json` is what opts users in (the Metro serializer bundles // it into JS as `__SENTRY_OPTIONS__`, and native reads it before JS runs). registerFeatureMarker(CAPTURE_APP_START_ERRORS_INTEGRATION_NAME); } } /** * Inits the Sentry React Native SDK with automatic instrumentation and wrapped features. */ export function wrap(RootComponent, options) { var _a; const profilerProps = Object.assign(Object.assign({}, options === null || options === void 0 ? void 0 : options.profilerProps), { name: (_a = RootComponent.displayName) !== null && _a !== void 0 ? _a : 'Root', updateProps: {} }); const ProfilerComponent = isWeb() ? Profiler : ReactNativeProfiler; const RootApp = appProps => { var _a; return (React.createElement(TouchEventBoundary, Object.assign({}, ((_a = options === null || options === void 0 ? void 0 : options.touchEventBoundaryProps) !== null && _a !== void 0 ? _a : {})), React.createElement(ProfilerComponent, Object.assign({}, profilerProps), React.createElement(FeedbackFormProvider, null, React.createElement(RootComponent, Object.assign({}, appProps)))))); }; return RootApp; } /** * If native client is available it will trigger a native crash. * Use this only for testing purposes. */ export function nativeCrash() { NATIVE.nativeCrash(); } /** * Signals that the application has finished loading and is ready for user interaction. * * Call this when your app is truly ready — after async initialization, data loading, * splash screen dismissal, auth session restore, etc. This marks the end of the app start span, * giving you a more accurate measurement of perceived startup time. * * If not called, the SDK falls back to the root component mount time (via `Sentry.wrap()`) * or JS bundle execution start. * * @experimental This API is subject to change in future versions. * * @example * ```ts * await loadRemoteConfig(); * await restoreSession(); * SplashScreen.hide(); * Sentry.appLoaded(); * ``` */ export function appLoaded() { // oxlint-disable-next-line typescript-eslint(no-floating-promises) _appLoaded(); } /** * Extends the app start window so work done after initialization (remote config, session restore, * splash screen dismissal, etc.) is included in the app start measurement. Call * {@link finishExtendedAppStart} when the app is ready, or attach child spans via * {@link getExtendedAppStartSpan} to break the extended work down. * * Requires standalone app start tracing (`_experiments.enableStandaloneAppStartTracing`). No-ops if * the app start transaction was already created, if extend was already called, or if called before * `Sentry.init()`. * * @experimental This API is subject to change in future versions. * * @example * ```ts * Sentry.extendAppStart(); * await initializeRemoteConfig(); * Sentry.finishExtendedAppStart(); * ``` */ export function extendAppStart() { _extendAppStart(); } /** * Returns the extended app start span for attaching child spans, or a no-op span when there is no * active extension. Only meaningful between {@link extendAppStart} and {@link finishExtendedAppStart}. * * @experimental This API is subject to change in future versions. * * @example * ```ts * Sentry.extendAppStart(); * const parentSpan = Sentry.getExtendedAppStartSpan(); * const child = Sentry.startInactiveSpan({ parentSpan, op: 'app.init', name: 'fetch remote config' }); * await loadRemoteConfig(); * child.end(); * Sentry.finishExtendedAppStart(); * ``` */ export function getExtendedAppStartSpan() { return _getExtendedAppStartSpan(); } /** * Finishes the app start extension started with {@link extendAppStart}, finalizing the app start * transaction (its duration is trimmed to the last child span). No-ops if there is no active * extension. * * Returns a promise that resolves once the app start transaction has been captured. `await` it * before {@link flush} (e.g. before a code-push/expo update) to make sure the app start data is * queued. * * @experimental This API is subject to change in future versions. */ export function finishExtendedAppStart() { return _finishExtendedAppStart(); } /** * Flushes all pending events in the queue to disk. * Use this before applying any realtime updates such as code-push or expo updates. */ export function flush() { return __awaiter(this, void 0, void 0, function* () { try { const client = getClient(); if (client) { const result = yield client.flush(); return result; } } catch (_) { } debug.error('Failed to flush the event queue.'); return false; }); } /** * Closes the SDK, stops sending events. */ export function close() { return __awaiter(this, void 0, void 0, function* () { try { const client = getClient(); if (client) { yield client.close(); } } catch (e) { debug.error('Failed to close the SDK'); } }); } /** * Creates a new scope with and executes the given operation within. * The scope is automatically removed once the operation * finishes or throws. * * This is essentially a convenience function for: * * pushScope(); * callback(); * popScope(); * * @param callback that will be enclosed into push/popScope. */ export function withScope(callback) { const safeCallback = (scope) => { try { return callback(scope); } catch (e) { debug.error('Error while running withScope callback', e); return undefined; } }; return coreWithScope(safeCallback); } /** * Returns if the app crashed in the last run. */ export function crashedLastRun() { return __awaiter(this, void 0, void 0, function* () { return NATIVE.crashedLastRun(); }); } /** * Pauses app hang tracking on iOS. * * App hang detection will ignore detected app hangs until * `resumeAppHangTracking` is called. * * Use this when showing system dialogs (e.g., permission prompts) * that block the main thread but are not real hangs. * * No-op on Android and when native is not available. * * @platform ios */ export function pauseAppHangTracking() { NATIVE.pauseAppHangTracking(); } /** * Resumes app hang tracking on iOS after it was paused. * * No-op on Android and when native is not available. * * @platform ios */ export function resumeAppHangTracking() { NATIVE.resumeAppHangTracking(); } //# sourceMappingURL=sdk.js.map