Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });

const core = require('@sentry/core');
const debugBuild = require('../debug-build.js');
const eventbuilder = require('../eventbuilder.js');
const helpers = require('../helpers.js');
const globalhandlers = require('./globalhandlers.js');

const INTEGRATION_NAME = 'WebWorker';

/**
 * Use this integration to set up Sentry with web workers.
 *
 * IMPORTANT: This integration must be added **before** you start listening to
 * any messages from the worker. Otherwise, your message handlers will receive
 * messages from the Sentry SDK which you need to ignore.
 *
 * This integration only has an effect, if you call `Sentry.registerWebWorker(self)`
 * from within the worker(s) you're adding to the integration.
 *
 * Given that you want to initialize the SDK as early as possible, you most likely
 * want to add this integration **after** initializing the SDK:
 *
 * @example:
 * ```ts filename={main.js}
 * import * as Sentry from '@sentry/<your-sdk>';
 *
 * // some time earlier:
 * Sentry.init(...)
 *
 * // 1. Initialize the worker
 * const worker = new Worker(new URL('./worker.ts', import.meta.url));
 *
 * // 2. Add the integration
 * const webWorkerIntegration = Sentry.webWorkerIntegration({ worker });
 * Sentry.addIntegration(webWorkerIntegration);
 *
 * // 3. Register message listeners on the worker
 * worker.addEventListener('message', event => {
 *  // ...
 * });
 * ```
 *
 * If you initialize multiple workers at the same time, you can also pass an array of workers
 * to the integration:
 *
 * ```ts filename={main.js}
 * const webWorkerIntegration = Sentry.webWorkerIntegration({ worker: [worker1, worker2] });
 * Sentry.addIntegration(webWorkerIntegration);
 * ```
 *
 * If you have any additional workers that you initialize at a later point,
 * you can add them to the integration as follows:
 *
 * ```ts filename={main.js}
 * const webWorkerIntegration = Sentry.webWorkerIntegration({ worker: worker1 });
 * Sentry.addIntegration(webWorkerIntegration);
 *
 * // sometime later:
 * webWorkerIntegration.addWorker(worker2);
 * ```
 *
 * Of course, you can also directly add the integration in Sentry.init:
 * ```ts filename={main.js}
 * import * as Sentry from '@sentry/<your-sdk>';
 *
 * // 1. Initialize the worker
 * const worker = new Worker(new URL('./worker.ts', import.meta.url));
 *
 * // 2. Initialize the SDK
 * Sentry.init({
 *  integrations: [Sentry.webWorkerIntegration({ worker })]
 * });
 *
 * // 3. Register message listeners on the worker
 * worker.addEventListener('message', event => {
 *  // ...
 * });
 * ```
 *
 * @param options {WebWorkerIntegrationOptions} Integration options:
 *   - `worker`: The worker instance.
 */
const webWorkerIntegration = core.defineIntegration(({ worker }) => ({
  name: INTEGRATION_NAME,
  setupOnce: () => {
    (Array.isArray(worker) ? worker : [worker]).forEach(w => listenForSentryMessages(w));
  },
  addWorker: (worker) => listenForSentryMessages(worker),
})) ;

function listenForSentryMessages(worker) {
  worker.addEventListener('message', event => {
    if (isSentryMessage(event.data)) {
      event.stopImmediatePropagation(); // other listeners should not receive this message

      // Handle debug IDs
      if (event.data._sentryDebugIds) {
        debugBuild.DEBUG_BUILD && core.debug.log('Sentry debugId web worker message received', event.data);
        helpers.WINDOW._sentryDebugIds = {
          ...event.data._sentryDebugIds,
          // debugIds of the main thread have precedence over the worker's in case of a collision.
          ...helpers.WINDOW._sentryDebugIds,
        };
      }

      // Handle unhandled rejections forwarded from worker
      if (event.data._sentryWorkerError) {
        debugBuild.DEBUG_BUILD && core.debug.log('Sentry worker rejection message received', event.data._sentryWorkerError);
        handleForwardedWorkerRejection(event.data._sentryWorkerError);
      }
    }
  });
}

function handleForwardedWorkerRejection(workerError) {
  const client = core.getClient();
  if (!client) {
    return;
  }

  const stackParser = client.getOptions().stackParser;
  const attachStacktrace = client.getOptions().attachStacktrace;

  const error = workerError.reason;

  // Follow same pattern as globalHandlers for unhandledrejection
  // Handle both primitives and errors the same way
  const event = core.isPrimitive(error)
    ? globalhandlers._eventFromRejectionWithPrimitive(error)
    : eventbuilder.eventFromUnknownInput(stackParser, error, undefined, attachStacktrace, true);

  event.level = 'error';

  // Add worker-specific context
  if (workerError.filename) {
    event.contexts = {
      ...event.contexts,
      worker: {
        filename: workerError.filename,
      },
    };
  }

  core.captureEvent(event, {
    originalException: error,
    mechanism: {
      handled: false,
      type: 'auto.browser.web_worker.onunhandledrejection',
    },
  });

  debugBuild.DEBUG_BUILD && core.debug.log('Captured worker unhandled rejection', error);
}

/**
 * Minimal interface for DedicatedWorkerGlobalScope, only requiring the postMessage method.
 * (which is the only thing we need from the worker's global object)
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/API/DedicatedWorkerGlobalScope
 *
 * We can't use the actual type because it breaks everyone who doesn't have {"lib": ["WebWorker"]}
 * but uses {"skipLibCheck": true} in their tsconfig.json.
 */

/**
 * Use this function to register the worker with the Sentry SDK.
 *
 * This function will:
 * - Send debug IDs to the parent thread
 * - Set up a handler for unhandled rejections in the worker
 * - Forward unhandled rejections to the parent thread for capture
 *
 * Note: Synchronous errors in workers are already captured by globalHandlers.
 * This only handles unhandled promise rejections which don't bubble to the parent.
 *
 * @example
 * ```ts filename={worker.js}
 * import * as Sentry from '@sentry/<your-sdk>';
 *
 * // Do this as early as possible in your worker.
 * Sentry.registerWebWorker({ self });
 *
 * // continue setting up your worker
 * self.postMessage(...)
 * ```
 * @param options {RegisterWebWorkerOptions} Integration options:
 *   - `self`: The worker instance you're calling this function from (self).
 */
function registerWebWorker({ self }) {
  // Send debug IDs to parent thread
  self.postMessage({
    _sentryMessage: true,
    _sentryDebugIds: self._sentryDebugIds ?? undefined,
  });

  // Set up unhandledrejection handler inside the worker
  // Following the same pattern as globalHandlers
  // unhandled rejections don't bubble to the parent thread, so we need to handle them here
  self.addEventListener('unhandledrejection', (event) => {
    const reason = globalhandlers._getUnhandledRejectionError(event);

    // Forward the raw reason to parent thread
    // The parent will handle primitives vs errors the same way globalHandlers does
    const serializedError = {
      reason: reason,
      filename: self.location?.href,
    };

    // Forward to parent thread
    self.postMessage({
      _sentryMessage: true,
      _sentryWorkerError: serializedError,
    });

    debugBuild.DEBUG_BUILD && core.debug.log('[Sentry Worker] Forwarding unhandled rejection to parent', serializedError);
  });

  debugBuild.DEBUG_BUILD && core.debug.log('[Sentry Worker] Registered worker with unhandled rejection handling');
}

function isSentryMessage(eventData) {
  if (!core.isPlainObject(eventData) || eventData._sentryMessage !== true) {
    return false;
  }

  // Must have at least one of: debug IDs or worker error
  const hasDebugIds = '_sentryDebugIds' in eventData;
  const hasWorkerError = '_sentryWorkerError' in eventData;

  if (!hasDebugIds && !hasWorkerError) {
    return false;
  }

  // Validate debug IDs if present
  if (hasDebugIds && !(core.isPlainObject(eventData._sentryDebugIds) || eventData._sentryDebugIds === undefined)) {
    return false;
  }

  // Validate worker error if present
  if (hasWorkerError && !core.isPlainObject(eventData._sentryWorkerError)) {
    return false;
  }

  return true;
}

exports.INTEGRATION_NAME = INTEGRATION_NAME;
exports.registerWebWorker = registerWebWorker;
exports.webWorkerIntegration = webWorkerIntegration;//# sourceMappingURL=http://go/sourcemap/sourcemaps/cd1c87ff9b66021918fb9731605f8d1d5fd2f0b0/node_modules/@sentry/browser/build/npm/cjs/prod/integrations/webWorker.js.map
