import { ClientResponseError, ok } from "@atcute/client"; import { mainSchema as createReportSchema } from "@atcute/atproto/types/moderation/createReport"; import type * as ComAtprotoModerationCreateReport from "@atcute/atproto/types/moderation/createReport"; import type * as ComAtprotoModerationDefs from "@atcute/atproto/types/moderation/defs"; import type { AtprotoAudience, Cid, Did, ResourceUri } from "@atcute/lexicons/syntax"; import type { OAuthUserAgent } from "@atcute/oauth-browser-client"; import { createClient } from "$lib/auth/agent"; export type ReasonType = ComAtprotoModerationDefs.ReasonType; export type ReportOutput = ComAtprotoModerationCreateReport.$output; type KnownOf = T extends string ? (string extends T ? never : T) : never; export type KnownReasonType = KnownOf; export type ReportSubject = { kind: "account"; did: string } | { kind: "record"; uri: string; cid: string }; export interface ReportInput { subject: ReportSubject; reasonType: ReasonType; reason?: string; } type SubjectRef = ComAtprotoModerationCreateReport.$input["subject"]; const subjectRef = (subject: ReportSubject): SubjectRef => subject.kind === "account" ? { $type: "com.atproto.admin.defs#repoRef", did: subject.did as Did } : { $type: "com.atproto.repo.strongRef", uri: subject.uri as ResourceUri, cid: subject.cid as Cid }; export const createReport = async ( agent: OAuthUserAgent, labelerDid: string, { subject, reasonType, reason }: ReportInput ): Promise => { const rpc = createClient(agent, `${labelerDid}#atproto_labeler` as AtprotoAudience); return ok( rpc.call(createReportSchema, { input: { reasonType, reason: reason?.trim() || undefined, subject: subjectRef(subject), modTool: { name: "tangled-web" } } }) ); }; const isMissingScope = (cause: ClientResponseError): boolean => { if (cause.status !== 401 && cause.status !== 403) return false; const text = `${cause.error} ${cause.description ?? ""}`.toLowerCase(); return text.includes("scope") || text.includes("invalidtoken") || text.includes("permission"); }; export const reportErrorMessage = (cause: unknown): string => { if (cause instanceof ClientResponseError) { if (isMissingScope(cause)) { return "Reporting was added after you signed in. Sign out and back in to enable it."; } return cause.description || cause.error || "Failed to send the report."; } return cause instanceof Error ? cause.message : "Failed to send the report."; };