import { deleteDocument } from '@documenso/lib/server-only/document/delete-document'; import { getMultipleEnvelopeWhereInput } from '@documenso/lib/server-only/envelope/get-envelopes-by-ids'; import { deleteTemplate } from '@documenso/lib/server-only/template/delete-template'; import { prisma } from '@documenso/prisma'; import { EnvelopeType } from '@prisma/client'; import pMap from 'p-map'; import { authenticatedProcedure } from '../trpc'; import { ZBulkDeleteEnvelopesRequestSchema, ZBulkDeleteEnvelopesResponseSchema } from './bulk-delete-envelopes.types'; export const bulkDeleteEnvelopesRoute = authenticatedProcedure // .meta(bulkDeleteEnvelopesMeta) // Keeping this as a private API for a little while until we're sure it's stable and the request/response schemas are finalized. .input(ZBulkDeleteEnvelopesRequestSchema) .output(ZBulkDeleteEnvelopesResponseSchema) .mutation(async ({ input, ctx }) => { const { teamId, user } = ctx; const { envelopeIds } = input; ctx.logger.info({ input: { envelopeIds, }, }); const { envelopeWhereInput } = await getMultipleEnvelopeWhereInput({ ids: { type: 'envelopeId', ids: envelopeIds, }, userId: user.id, teamId, type: null, }); const envelopes = await prisma.envelope.findMany({ where: envelopeWhereInput, select: { id: true, type: true, }, }); const results = await pMap( envelopes, async (envelope) => { const { id: envelopeId, type: envelopeType } = envelope; try { if (envelopeType === EnvelopeType.DOCUMENT) { await deleteDocument({ id: { type: 'envelopeId', id: envelopeId, }, userId: user.id, teamId, requestMetadata: ctx.metadata, }); } else if (envelopeType === EnvelopeType.TEMPLATE) { await deleteTemplate({ id: { type: 'envelopeId', id: envelopeId, }, userId: user.id, teamId, }); } return { success: true, envelopeId, }; } catch (err) { ctx.logger.warn( { envelopeId, error: err, }, 'Failed to delete envelope during bulk delete', ); return { success: false, envelopeId, }; } }, { concurrency: 10, stopOnError: false, }, ); const deletedCount = results.filter((r) => r.success).length; const failedIds = results.filter((r) => !r.success).map((r) => r.envelopeId); // Include envelope IDs that were not attempted (unauthorized/not found) const attemptedIds = new Set(envelopes.map((e) => e.id)); const unattemptedIds = envelopeIds.filter((id) => !attemptedIds.has(id)); return { deletedCount, failedIds: [...failedIds, ...unattemptedIds], }; });