36 lines
1.3 KiB
TypeScript
36 lines
1.3 KiB
TypeScript
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<CompletionContext>();
|
|
|
|
// 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<unknown>[]) =>
|
|
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<RoutedChannel>) {
|
|
super('completion_route_required');
|
|
}
|
|
}
|