with-trace.js 1.03 KB
import { createRequestContext } from './context.js'

/**
 * 判断一个值是否已是 RequestContext(鸭子类型:有 string traceId 与 child 方法)。
 * @param {any} v
 * @returns {boolean}
 */
function isRequestContext(v) {
  return (
    !!v &&
    typeof v === 'object' &&
    typeof v.traceId === 'string' &&
    typeof v.child === 'function'
  )
}

/**
 * 把「`(ctx, ...args) => ...`」的函数包成自动注入 ctx 的函数。
 * 调用时若首参不是 `RequestContext`,则 `createRequestContext()` 注入为首参(自动生成 traceId);
 * 已传则透传同一 ctx(同一 trace)。
 *
 * @template {(...args: any[]) => any} F
 * @param {F} fn
 * @returns {F}
 */
export function withTrace(fn) {
  /** @type {any} */
  const wrapped = function (/** @type {any[]} */ ...args) {
    // @ts-ignore — 透传调用方 this,保留任意可调用形态。
    if (isRequestContext(args[0])) return fn.apply(this, args)
    // @ts-ignore
    return fn.apply(this, [createRequestContext(), ...args])
  }
  return wrapped
}