import { AsyncLocalStorage } from 'node:async_hooks'; import { Prisma } from '@prisma/client'; import { PrismaService } from '../prisma/prisma.service'; import type { RoutedChannel } from './send-chain.contracts'; export type CompletionContext = { tx: Prisma.TransactionClient; messageRecordId: string; route?: RoutedChannel; routePlanned?: boolean; }; export const completionContext = new AsyncLocalStorage(); // Only send-chain collaborators use this adapter. Nested billing/outbox transactions // join the explicitly established completion transaction, never start a second one. export function completionDatabase(prisma: PrismaService): PrismaService { return new Proxy(prisma, { get(target, key) { const tx = completionContext.getStore()?.tx; if (tx && key === '$transaction') { return (operation: ((client: Prisma.TransactionClient) => unknown) | Promise[]) => typeof operation === 'function' ? operation(tx) : Promise.all(operation); } const owner = tx && key in tx ? tx : target; const value = Reflect.get(owner, key); return typeof value === 'function' ? value.bind(owner) : value; }, }); } export class CompletionRouteRequired extends Error { constructor(readonly select: () => Promise) { super('completion_route_required'); } }