{"version":3,"file":"index.cjs","names":["AsyncLocalStorage"],"sources":["../../../../../../@warlock.js/context/src/base-context.ts","../../../../../../@warlock.js/context/src/context-manager.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"async_hooks\";\n\n/**\n * Base class for all AsyncLocalStorage-based contexts\n *\n * Provides a consistent API for managing context across async operations.\n * All framework contexts (request, storage, database) extend this class.\n *\n * @template TStore - The type of data stored in context\n *\n * @example\n * ```typescript\n * interface MyContextStore {\n *   userId: string;\n *   tenant: string;\n * }\n *\n * class MyContext extends Context<MyContextStore> {}\n * const myContext = new MyContext();\n *\n * // Use it\n * await myContext.run({ userId: '123', tenant: 'acme' }, async () => {\n *   const userId = myContext.get('userId'); // '123'\n * });\n * ```\n */\nexport abstract class Context<TStore extends Record<string, any>> {\n  protected readonly storage: AsyncLocalStorage<TStore> = new AsyncLocalStorage<TStore>();\n\n  /**\n   * Run a callback within a new context\n   *\n   * Creates a new async context with the provided store data.\n   * All operations within the callback will have access to this context.\n   *\n   * @param store - Initial context data\n   * @param callback - Async function to execute\n   * @returns Result of the callback\n   */\n  public run<T>(store: TStore, callback: () => Promise<T>): Promise<T> {\n    return this.storage.run(store, callback);\n  }\n\n  /**\n   * Enter a new context without a callback\n   *\n   * Useful for middleware where you want to set context for the rest of the request.\n   * Unlike `run()`, this doesn't require a callback.\n   *\n   * @param store - Context data to set\n   */\n  public enter(store: TStore): void {\n    this.storage.enterWith(store);\n  }\n\n  /**\n   * Update the current context\n   *\n   * Merges new data into existing context, or enters new context if none exists.\n   *\n   * @param updates - Partial context data to merge\n   */\n  public update(updates: Partial<TStore>): void {\n    const current = this.storage.getStore();\n\n    if (current) {\n      Object.assign(current, updates);\n    } else {\n      this.enter(updates as TStore);\n    }\n  }\n\n  /**\n   * Get the current context store\n   *\n   * @returns Current context or undefined if not in context\n   */\n  public getStore(): TStore | undefined {\n    return this.storage.getStore();\n  }\n\n  /**\n   * Get a specific value from context\n   *\n   * @param key - Key to retrieve\n   * @returns Value or undefined\n   */\n  public get<K extends keyof TStore>(key: K): TStore[K] | undefined {\n    return this.storage.getStore()?.[key];\n  }\n\n  /**\n   * Set a specific value in context\n   *\n   * @param key - Key to set\n   * @param value - Value to store\n   */\n  public set<K extends keyof TStore>(key: K, value: TStore[K]): void {\n    this.update({ [key]: value } as any);\n  }\n\n  /**\n   * Clear the context\n   */\n  public clear(): void {\n    this.storage.enterWith({} as TStore);\n  }\n\n  /**\n   * Check if currently in a context\n   */\n  public hasContext(): boolean {\n    return this.storage.getStore() !== undefined;\n  }\n\n  /**\n   * Build the initial store for this context\n   *\n   * Override this method to provide custom initialization logic.\n   * Called by ContextManager.buildStores() for each registered context.\n   *\n   * @param payload - Generic payload (e.g., { request, response } for HTTP contexts)\n   * @returns Initial store data\n   */\n  public abstract buildStore(payload?: Record<string, any>): TStore;\n}\n","import type { Context } from \"./base-context\";\n\n/**\n * Context Manager - Orchestrates multiple contexts together\n *\n * Allows running multiple AsyncLocalStorage contexts in a single operation,\n * making it easy to link request, storage, database, and other contexts.\n *\n * @example\n * ```typescript\n * // Register contexts\n * contextManager\n *   .register('request', requestContext)\n *   .register('storage', storageDriverContext)\n *   .register('database', databaseDataSourceContext);\n *\n * // Run all contexts together\n * await contextManager.runAll({\n *   request: { request, response, user },\n *   storage: { driver, metadata: { tenantId: '123' } },\n *   database: { dataSource: 'primary' },\n * }, async () => {\n *   // All contexts active!\n *   await handleRequest();\n * });\n * ```\n */\nexport class ContextManager {\n  private contexts = new Map<string, Context<any>>();\n\n  /**\n   * Register a context\n   *\n   * @param name - Unique context name\n   * @param context - Context instance\n   * @returns This instance for chaining\n   */\n  public register(name: string, context: Context<any>): this {\n    this.contexts.set(name, context);\n    return this;\n  }\n\n  /**\n   * Run all registered contexts together\n   *\n   * Nests all context.run() calls, ensuring all contexts are active\n   * for the duration of the callback.\n   *\n   * @param stores - Context stores keyed by context name\n   * @param callback - Async function to execute\n   * @returns Result of the callback\n   */\n  public async runAll<T>(stores: Record<string, any>, callback: () => Promise<T>): Promise<T> {\n    const entries = Array.from(this.contexts.entries());\n\n    // Build nested context runners\n    const runner = entries.reduceRight((next, [name, context]) => {\n      return () => context.run(stores[name] || {}, next);\n    }, callback);\n\n    return runner();\n  }\n\n  /**\n   * Enter all contexts at once (for middleware)\n   *\n   * @param stores - Context stores keyed by context name\n   */\n  public enterAll(stores: Record<string, any>): void {\n    for (const [name, context] of this.contexts.entries()) {\n      if (stores[name]) {\n        context.enter(stores[name]);\n      }\n    }\n  }\n\n  /**\n   * Clear all contexts\n   */\n  public clearAll(): void {\n    for (const context of this.contexts.values()) {\n      context.clear();\n    }\n  }\n\n  /**\n   * Get a specific registered context\n   *\n   * @param name - Context name\n   * @returns Context instance or undefined\n   */\n  public getContext<T extends Context<any>>(name: string): T | undefined {\n    return this.contexts.get(name) as T | undefined;\n  }\n\n  /**\n   * Check if a context is registered\n   *\n   * @param name - Context name\n   * @returns True if context is registered\n   */\n  public hasContext(name: string): boolean {\n    return this.contexts.has(name);\n  }\n\n  /**\n   * Build all context stores by calling each context's buildStore() method\n   *\n   * This is the immutable pattern - returns a new record of stores.\n   * Each context defines its own initialization logic.\n   *\n   * @param payload - Payload passed to each buildStore() (e.g., { request, response })\n   * @returns Record of context name -> store data\n   *\n   * @example\n   * ```typescript\n   * const httpContextStore = contextManager.buildStores({ request, response });\n   * await contextManager.runAll(httpContextStore, async () => { ... });\n   * ```\n   */\n  public buildStores(payload?: Record<string, any>): Record<string, any> {\n    const stores: Record<string, any> = {};\n\n    for (const [name, context] of this.contexts.entries()) {\n      stores[name] = context.buildStore(payload) ?? {};\n    }\n\n    return stores;\n  }\n\n  /**\n   * Unregister a context\n   *\n   * @param name - Context name to remove\n   * @returns True if context was removed\n   */\n  public unregister(name: string): boolean {\n    return this.contexts.delete(name);\n  }\n}\n\n/**\n * Global context manager instance\n *\n * Use this singleton to register and manage all framework contexts.\n */\nexport const contextManager = new ContextManager();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,IAAsB,UAAtB,MAAkE;;iBACR,IAAIA,8BAA0B;;;;;;;;;;;;CAYtF,AAAO,IAAO,OAAe,UAAwC;EACnE,OAAO,KAAK,QAAQ,IAAI,OAAO,QAAQ;CACzC;;;;;;;;;CAUA,AAAO,MAAM,OAAqB;EAChC,KAAK,QAAQ,UAAU,KAAK;CAC9B;;;;;;;;CASA,AAAO,OAAO,SAAgC;EAC5C,MAAM,UAAU,KAAK,QAAQ,SAAS;EAEtC,IAAI,SACF,OAAO,OAAO,SAAS,OAAO;OAE9B,KAAK,MAAM,OAAiB;CAEhC;;;;;;CAOA,AAAO,WAA+B;EACpC,OAAO,KAAK,QAAQ,SAAS;CAC/B;;;;;;;CAQA,AAAO,IAA4B,KAA+B;EAChE,OAAO,KAAK,QAAQ,SAAS,CAAC,GAAG;CACnC;;;;;;;CAQA,AAAO,IAA4B,KAAQ,OAAwB;EACjE,KAAK,OAAO,GAAG,MAAM,MAAM,CAAQ;CACrC;;;;CAKA,AAAO,QAAc;EACnB,KAAK,QAAQ,UAAU,CAAC,CAAW;CACrC;;;;CAKA,AAAO,aAAsB;EAC3B,OAAO,KAAK,QAAQ,SAAS,MAAM;CACrC;AAYF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClGA,IAAa,iBAAb,MAA4B;;kCACP,IAAI,IAA0B;;;;;;;;;CASjD,AAAO,SAAS,MAAc,SAA6B;EACzD,KAAK,SAAS,IAAI,MAAM,OAAO;EAC/B,OAAO;CACT;;;;;;;;;;;CAYA,MAAa,OAAU,QAA6B,UAAwC;EAQ1F,OAPgB,MAAM,KAAK,KAAK,SAAS,QAAQ,CAG5B,CAAC,CAAC,aAAa,MAAM,CAAC,MAAM,aAAa;GAC5D,aAAa,QAAQ,IAAI,OAAO,SAAS,CAAC,GAAG,IAAI;EACnD,GAAG,QAES,CAAC,CAAC;CAChB;;;;;;CAOA,AAAO,SAAS,QAAmC;EACjD,KAAK,MAAM,CAAC,MAAM,YAAY,KAAK,SAAS,QAAQ,GAClD,IAAI,OAAO,OACT,QAAQ,MAAM,OAAO,KAAK;CAGhC;;;;CAKA,AAAO,WAAiB;EACtB,KAAK,MAAM,WAAW,KAAK,SAAS,OAAO,GACzC,QAAQ,MAAM;CAElB;;;;;;;CAQA,AAAO,WAAmC,MAA6B;EACrE,OAAO,KAAK,SAAS,IAAI,IAAI;CAC/B;;;;;;;CAQA,AAAO,WAAW,MAAuB;EACvC,OAAO,KAAK,SAAS,IAAI,IAAI;CAC/B;;;;;;;;;;;;;;;;CAiBA,AAAO,YAAY,SAAoD;EACrE,MAAM,SAA8B,CAAC;EAErC,KAAK,MAAM,CAAC,MAAM,YAAY,KAAK,SAAS,QAAQ,GAClD,OAAO,QAAQ,QAAQ,WAAW,OAAO,KAAK,CAAC;EAGjD,OAAO;CACT;;;;;;;CAQA,AAAO,WAAW,MAAuB;EACvC,OAAO,KAAK,SAAS,OAAO,IAAI;CAClC;AACF;;;;;;AAOA,MAAa,iBAAiB,IAAI,eAAe"}