import { AsyncLocalStorage } from "node:async_hooks"; import { setHttpRequestHookProvider, type HttpRequestHook } from "@tactical-media-broadcast-hub/connector-sdk"; /** * Per-execution HTTP hook carried through AsyncLocalStorage, so concurrent * publish activities in one process never share a "current job". */ const storage = new AsyncLocalStorage(); let installed = false; function install(): void { if (installed) return; setHttpRequestHookProvider(() => storage.getStore()); installed = true; } /** Run `fn` with `hook` observing every SDK HTTP request it makes. */ export function runWithHttpHook(hook: HttpRequestHook, fn: () => Promise): Promise { install(); return storage.run(hook, fn); } import type { ConnectorConnection } from "@tactical-media-broadcast-hub/core"; export interface PublishingExecutionContext { workspaceId: string; connectionId: string; credentialId: string; credentialGeneration: string; signal?: AbortSignal; } const executionStorage = new AsyncLocalStorage(); export function runWithPublishingContext(context: PublishingExecutionContext, fn: () => Promise): Promise { return executionStorage.run(context, fn); } export function publishingContext(connection: ConnectorConnection): PublishingExecutionContext { const context = executionStorage.getStore(); if (!context || connection.workspaceId !== context.workspaceId || connection.id !== context.connectionId || connection.credentialId.id !== context.connectionId) throw new Error("EXECUTION_CREDENTIAL_FENCE"); context.signal?.throwIfAborted(); return context; } export function executionSignal(): AbortSignal | undefined { return executionStorage.getStore()?.signal; }