{"version":3,"file":"AsyncLocalStorageContextManager.cjs","names":["AsyncLocalStorage","ROOT_CONTEXT","EventEmitter","events"],"sources":["../src/AsyncLocalStorageContextManager.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Context, ContextManager } from '@opentelemetry/api';\nimport { ROOT_CONTEXT } from '@opentelemetry/api';\nimport type { ContextManagementToken } from './types';\nimport { AsyncLocalStorage } from 'async_hooks';\nimport { EventEmitter } from 'events';\n\ntype Func<T> = (...args: unknown[]) => T;\n/**\n * Store a map for each event of all original listeners and their \"patched\"\n * version. So when a listener is removed by the user, the corresponding\n * patched function will be also removed.\n */\ninterface PatchMap {\n  [name: string]: WeakMap<Func<void>, Func<void>>;\n}\n\nconst ADD_LISTENER_METHODS = [\n  'addListener' as const,\n  'on' as const,\n  'once' as const,\n  'prependListener' as const,\n  'prependOnceListener' as const,\n];\n\n/**\n * Wrapper around a token and _asyncLocalStorage to mirror the behavior of\n * a Node.js RunScope\n *\n * @internal not intended for direct public consumption. Will be removed once\n * withScope is available on all supported Node.js versions\n */\nclass DisposeOnceToken implements ContextManagementToken {\n  private _isDisposed = false;\n  private readonly _previousContext: Context;\n  private readonly _asyncLocalStorage: AsyncLocalStorage<Context>;\n\n  constructor(\n    previousContext: Context,\n    asyncLocalStorage: AsyncLocalStorage<Context>\n  ) {\n    this._previousContext = previousContext;\n    this._asyncLocalStorage = asyncLocalStorage;\n  }\n\n  dispose() {\n    if (this._isDisposed) {\n      return;\n    }\n\n    this._asyncLocalStorage.enterWith(this._previousContext);\n    this._isDisposed = true;\n  }\n}\n\nexport class AsyncLocalStorageContextManager implements ContextManager {\n  private readonly _kOtListeners = Symbol('OtListeners');\n  private _wrapped = false;\n  private _asyncLocalStorage: AsyncLocalStorage<Context>;\n\n  constructor() {\n    this._asyncLocalStorage = new AsyncLocalStorage();\n  }\n\n  active(): Context {\n    return this._asyncLocalStorage.getStore() ?? ROOT_CONTEXT;\n  }\n\n  with<A extends unknown[], F extends (...args: A) => ReturnType<F>>(\n    context: Context,\n    fn: F,\n    thisArg?: ThisParameterType<F>,\n    ...args: A\n  ): ReturnType<F> {\n    const cb = thisArg == null ? fn : fn.bind(thisArg);\n    return this._asyncLocalStorage.run(context, cb as never, ...args);\n  }\n\n  /**\n   * Binds a the certain context or the active one to the target function and then returns the target\n   * @param context A context (span) to be bind to target\n   * @param target a function or event emitter. When target or one of its callbacks is called,\n   *  the provided context will be used as the active context for the duration of the call.\n   */\n  bind<T>(context: Context, target: T): T {\n    if (target instanceof EventEmitter) {\n      return this._bindEventEmitter(context, target);\n    }\n\n    if (typeof target === 'function') {\n      return this._bindFunction(context, target);\n    }\n    return target;\n  }\n\n  private _bindFunction<T extends Function>(context: Context, target: T): T {\n    const manager = this;\n    const contextWrapper = function (this: never, ...args: unknown[]) {\n      return manager.with(context, () => target.apply(this, args));\n    };\n    Object.defineProperty(contextWrapper, 'length', {\n      enumerable: false,\n      configurable: true,\n      writable: false,\n      value: target.length,\n    });\n    return contextWrapper as unknown as T;\n  }\n\n  /**\n   * By default, EventEmitter call their callback with their context, which we do\n   * not want, instead we will bind a specific context to all callbacks that\n   * go through it.\n   * @param context the context we want to bind\n   * @param ee EventEmitter an instance of EventEmitter to patch\n   */\n  private _bindEventEmitter<T extends EventEmitter>(\n    context: Context,\n    ee: T\n  ): T {\n    const map = this._getPatchMap(ee);\n    if (map !== undefined) return ee;\n    this._createPatchMap(ee);\n\n    // patch methods that add a listener to propagate context\n    ADD_LISTENER_METHODS.forEach(methodName => {\n      if (ee[methodName] === undefined) return;\n      ee[methodName] = this._patchAddListener(ee, ee[methodName], context);\n    });\n    // patch methods that remove a listener\n    if (typeof ee.removeListener === 'function') {\n      ee.removeListener = this._patchRemoveListener(ee, ee.removeListener);\n    }\n    if (typeof ee.off === 'function') {\n      ee.off = this._patchRemoveListener(ee, ee.off);\n    }\n    // patch method that remove all listeners\n    if (typeof ee.removeAllListeners === 'function') {\n      ee.removeAllListeners = this._patchRemoveAllListeners(\n        ee,\n        ee.removeAllListeners\n      );\n    }\n    return ee;\n  }\n\n  /**\n   * Patch methods that remove a given listener so that we match the \"patched\"\n   * version of that listener (the one that propagate context).\n   * @param ee EventEmitter instance\n   * @param original reference to the patched method\n   */\n  private _patchRemoveListener(ee: EventEmitter, original: Function) {\n    const contextManager = this;\n    return function (this: never, event: string, listener: Func<void>) {\n      const events = contextManager._getPatchMap(ee)?.[event];\n      if (events === undefined) {\n        return original.call(this, event, listener);\n      }\n      const patchedListener = events.get(listener);\n      return original.call(this, event, patchedListener || listener);\n    };\n  }\n\n  /**\n   * Patch methods that remove all listeners so we remove our\n   * internal references for a given event.\n   * @param ee EventEmitter instance\n   * @param original reference to the patched method\n   */\n  private _patchRemoveAllListeners(ee: EventEmitter, original: Function) {\n    const contextManager = this;\n    return function (this: never, event: string) {\n      const map = contextManager._getPatchMap(ee);\n      if (map !== undefined) {\n        if (arguments.length === 0) {\n          contextManager._createPatchMap(ee);\n        } else if (map[event] !== undefined) {\n          delete map[event];\n        }\n      }\n      return original.apply(this, arguments);\n    };\n  }\n\n  /**\n   * Patch methods on an event emitter instance that can add listeners so we\n   * can force them to propagate a given context.\n   * @param ee EventEmitter instance\n   * @param original reference to the patched method\n   * @param [context] context to propagate when calling listeners\n   */\n  private _patchAddListener(\n    ee: EventEmitter,\n    original: Function,\n    context: Context\n  ) {\n    const contextManager = this;\n    return function (this: never, event: string, listener: Func<void>) {\n      /**\n       * This check is required to prevent double-wrapping the listener.\n       * The implementation for ee.once wraps the listener and calls ee.on.\n       * Without this check, we would wrap that wrapped listener.\n       * This causes an issue because ee.removeListener depends on the onceWrapper\n       * to properly remove the listener. If we wrap their wrapper, we break\n       * that detection.\n       */\n      if (contextManager._wrapped) {\n        return original.call(this, event, listener);\n      }\n      let map = contextManager._getPatchMap(ee);\n      if (map === undefined) {\n        map = contextManager._createPatchMap(ee);\n      }\n      let listeners = map[event];\n      if (listeners === undefined) {\n        listeners = new WeakMap();\n        map[event] = listeners;\n      }\n      const patchedListener = contextManager.bind(context, listener);\n      // store a weak reference of the user listener to ours\n      listeners.set(listener, patchedListener);\n\n      /**\n       * See comment at the start of this function for the explanation of this property.\n       */\n      contextManager._wrapped = true;\n      try {\n        return original.call(this, event, patchedListener);\n      } finally {\n        contextManager._wrapped = false;\n      }\n    };\n  }\n\n  private _createPatchMap(ee: EventEmitter): PatchMap {\n    const map = Object.create(null);\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    (ee as any)[this._kOtListeners] = map;\n    return map;\n  }\n  private _getPatchMap(ee: EventEmitter): PatchMap | undefined {\n    return (ee as never)[this._kOtListeners];\n  }\n\n  enable(): this {\n    return this;\n  }\n\n  disable(): this {\n    this._asyncLocalStorage.disable();\n    return this;\n  }\n\n  /**\n   * Imperatively sets `context` as active for the current async execution chain\n   * and operations spawned from it. Returns a {@link ContextManagementToken} whose `dispose()`\n   * restores the previous context (see {@link ContextManager.attach}).\n   *\n   * On Node.js 25.9+, delegates to `AsyncLocalStorage.withScope()` which returns\n   * a native `RunScope`. On older Node.js versions, falls back to `enterWith()` with\n   * a manual token.\n   *\n   * **Caveat for async functions:** Both `withScope()` and `enterWith()` affect the\n   * entire current async execution chain. If `attach()` is called inside an async\n   * function before the first `await`, the context change will leak into the caller's\n   * context and remain active there until something else restores it. Prefer `with()`\n   * for async code.\n   *\n   * @experimental This API is experimental and may change in minor releases without prior notice.\n   */\n  attach(context: Context): ContextManagementToken {\n    // Node.js 25.9+: withScope() returns a RunScope with dispose()\n    const withScope = (\n      this._asyncLocalStorage as AsyncLocalStorage<Context> & {\n        withScope?: (value: Context) => ContextManagementToken;\n      }\n    ).withScope;\n    if (withScope) {\n      return withScope.call(this._asyncLocalStorage, context);\n    }\n\n    // Fallback for older Node.js - this can be dropped when the minimum supported\n    // Node.js version of this package is 25.9 or higher.\n    const previousContext = this.active();\n    this._asyncLocalStorage.enterWith(context);\n    return new DisposeOnceToken(previousContext, this._asyncLocalStorage);\n  }\n}\n"],"mappings":"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"}