import { Injectable } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { QueryFailedError, Repository } from "typeorm"; import { BaseRepository } from "@edr/api-common"; import { PaymentWebhookEvent } from "./entities/payment-webhook-event.entity"; const PG_UNIQUE_VIOLATION = "23505"; @Injectable() export class WebhookEventsRepository extends BaseRepository { constructor( @InjectRepository(PaymentWebhookEvent) repository: Repository, ) { super(repository); } /** * Insert the event, relying on the unique (provider, external_event_id) index for dedupe. * Returns null when the event was already recorded (duplicate delivery / provider replay). */ async createDeduped( data: Partial, ): Promise { try { return await this.create(data); } catch (err) { if ( err instanceof QueryFailedError && (err.driverError as { code?: string })?.code === PG_UNIQUE_VIOLATION ) { return null; } throw err; } } async markProcessed(id: string, processingError?: string): Promise { await this.update(id, { processedAt: new Date(), processingError: processingError ?? null, }); } }