import { AsyncLocalStorage } from "node:async_hooks"; import type { GatewayRequestContext, GatewayRequestOptions, } from "../../gateway/server-methods/types.js"; export type PluginRuntimeGatewayRequestScope = { context?: GatewayRequestContext; client?: GatewayRequestOptions["client"]; isWebchatConnect: GatewayRequestOptions["isWebchatConnect"]; pluginId?: string; }; const PLUGIN_RUNTIME_GATEWAY_REQUEST_SCOPE_KEY: unique symbol = Symbol.for( "openclaw.pluginRuntimeGatewayRequestScope", ); const pluginRuntimeGatewayRequestScope = (() => { const globalState = globalThis as typeof globalThis & { [PLUGIN_RUNTIME_GATEWAY_REQUEST_SCOPE_KEY]?: AsyncLocalStorage; }; const existing = globalState[PLUGIN_RUNTIME_GATEWAY_REQUEST_SCOPE_KEY]; if (existing) { return existing; } const created = new AsyncLocalStorage(); globalState[PLUGIN_RUNTIME_GATEWAY_REQUEST_SCOPE_KEY] = created; return created; })(); /** * Runs plugin gateway handlers with request-scoped context that runtime helpers can read. */ export function withPluginRuntimeGatewayRequestScope( scope: PluginRuntimeGatewayRequestScope, run: () => T, ): T { return pluginRuntimeGatewayRequestScope.run(scope, run); } /** * Runs work under the current gateway request scope while attaching plugin identity. */ export function withPluginRuntimePluginIdScope(pluginId: string, run: () => T): T { const current = pluginRuntimeGatewayRequestScope.getStore(); const scoped: PluginRuntimeGatewayRequestScope = current ? { ...current, pluginId } : { pluginId, isWebchatConnect: () => false, }; return pluginRuntimeGatewayRequestScope.run(scoped, run); } /** * Returns the current plugin gateway request scope when called from a plugin request handler. */ export function getPluginRuntimeGatewayRequestScope(): | PluginRuntimeGatewayRequestScope | undefined { return pluginRuntimeGatewayRequestScope.getStore(); }