import "reflect-metadata"; import { injectable } from "inversify"; import { getPayload } from "payload"; import type { SanitizedConfig } from "payload"; import { NoopTracer, NoopLogger, type ITracer, type ILogger, } from "@repo/core-shared/instrumentation"; import type { IMediaRepository } from "../../application/repositories/media.repository.interface"; import type { Media } from "../../entities/models/media"; type PayloadMediaDoc = { id: string | number; alt?: string | null; url?: string | null; filename?: string | null; mimeType?: string | null; filesize?: number | null; width?: number | null; height?: number | null; }; function mapDoc(doc: PayloadMediaDoc): Media { return { id: String(doc.id), alt: doc.alt ?? "", url: doc.url ?? "", filename: doc.filename ?? "", mimeType: doc.mimeType ?? "", filesize: doc.filesize ?? 0, ...(doc.width != null && { width: doc.width }), ...(doc.height != null && { height: doc.height }), }; } const FEATURE = "media" as const; const REPO = "media" as const; @injectable() export class MediaRepository implements IMediaRepository { private config: SanitizedConfig; private tracer: ITracer; private logger: ILogger; constructor( config: SanitizedConfig, tracer: ITracer = new NoopTracer(), logger: ILogger = new NoopLogger(), ) { this.config = config; this.tracer = tracer; this.logger = logger; } async getMedia(id: string): Promise { return this.tracer.startSpan( { name: "media.getMedia", op: "repository", attributes: { id } }, async (span) => { try { const payload = await getPayload({ config: this.config }); const doc = await payload.findByID({ collection: "media", id, overrideAccess: true, }); span.setAttribute("found", true); return mapDoc(doc as PayloadMediaDoc); } catch (err) { if ( err && typeof err === "object" && "status" in err && (err as { status: unknown }).status === 404 ) { span.setAttribute("found", false); return undefined; } this.logger.captureException(err, { tags: { feature: FEATURE, repo: REPO, method: "getMedia" }, }); span.setStatus("error", err instanceof Error ? err.message : String(err)); throw err; } }, ); } async listMedia(opts?: { limit?: number; offset?: number }): Promise { return this.tracer.startSpan( { name: "media.listMedia", op: "repository", attributes: { limit: opts?.limit ?? null, offset: opts?.offset ?? null, }, }, async (span) => { try { const payload = await getPayload({ config: this.config }); const result = await payload.find({ collection: "media", limit: opts?.limit ?? 50, page: opts?.offset ? Math.floor(opts.offset / (opts.limit ?? 50)) + 1 : 1, overrideAccess: true, }); const items = result.docs.map((d) => mapDoc(d as PayloadMediaDoc)); span.setAttribute("count", items.length); return items; } catch (err) { this.logger.captureException(err, { tags: { feature: FEATURE, repo: REPO, method: "listMedia" }, }); span.setStatus("error", err instanceof Error ? err.message : String(err)); throw err; } }, ); } async deleteMedia(id: string): Promise { return this.tracer.startSpan( { name: "media.deleteMedia", op: "repository", attributes: { id } }, async (span) => { try { const payload = await getPayload({ config: this.config }); await payload.delete({ collection: "media", id, overrideAccess: true, }); span.setAttribute("deleted", true); } catch (err) { span.setAttribute("deleted", false); this.logger.captureException(err, { tags: { feature: FEATURE, repo: REPO, method: "deleteMedia" }, }); span.setStatus("error", err instanceof Error ? err.message : String(err)); throw err; } }, ); } }