import { AsyncLocalStorage } from "node:async_hooks";
// ── globalThis 单例 key ─────────────────────────────────────
//
// 使用 Symbol.for() 而非普通字符串 key：
//   - Symbol.for() 在整个 V8 isolate（进程）中全局唯一
//   - 即使多个 npm 包版本共存，只要 key 字符串相同就返回同一个 Symbol
//   - 避免与用户代码或其他库的 globalThis 属性意外碰撞
//
const GLOBAL_KEY = Symbol.for("vextjs.requestContext");
/**
 * 获取或创建全局唯一的 requestContext 实例
 *
 * 首次调用时创建 AsyncLocalStorage 实例并挂载到 globalThis[GLOBAL_KEY]，
 * 后续调用（无论来自 ESM 还是 CJS）直接返回已缓存的实例。
 */
function getOrCreateRequestContext() {
    const existing = globalThis[GLOBAL_KEY];
    if (existing instanceof AsyncLocalStorage) {
        return existing;
    }
    const instance = new AsyncLocalStorage();
    globalThis[GLOBAL_KEY] = instance;
    return instance;
}
/**
 * 请求上下文（AsyncLocalStorage 实例）
 *
 * 框架核心基础设施，在中间件链执行前通过 requestContext.run() 创建请求作用域。
 * 后续所有同步/异步代码通过 requestContext.getStore() 访问当前请求的上下文数据。
 *
 * 生命周期：
 *   1. adapter 收到请求，调用 requestContext.run(store, callback)
 *   2. callback 内执行中间件链（requestId 中间件写入 store.requestId）
 *   3. handler 执行，app.throw / app.logger 等读取 store
 *   4. 请求结束，store 自动 GC（无需手动清理）
 *
 * 单例保证：
 *   通过 globalThis + Symbol.for() 缓存，确保 ESM（dist/index.js）和
 *   CJS（dist/index.cjs）加载到同一个 AsyncLocalStorage 实例。
 *   解决了 adapter 在实例 A 上 .run() 而用户路由代码在实例 B 上
 *   .getStore() 返回 null 的双包问题。
 */
export const requestContext = getOrCreateRequestContext();
