import { z } from 'zod'; export const RedditSessionStateSchema = z.union([ z.literal('unknown'), z.literal('authenticated'), z.literal('login-required'), z.literal('unreachable'), ]); export const AccountEstablishmentStateSchema = z.union([ z.literal('unknown'), z.literal('established'), z.literal('unestablished'), ]); export const AccountEstablishmentSummarySchema = z.strictObject({ state: AccountEstablishmentStateSchema, /** True only when Reddit rejected an invitation; profile shortfalls do not hold sending. */ sendingHeld: z.boolean(), reasons: z.array(z.string()), accountAgeDays: z.number().nullable(), linkKarma: z.number().nullable(), commentKarma: z.number().nullable(), totalKarma: z.number().nullable(), hasVerifiedEmail: z.boolean().nullable(), profileCheckedAt: z.number().nullable(), lastProbeAt: z.number().nullable(), lastProbeFailure: z.string().nullable(), retryAt: z.number().nullable(), }); export const RedditAccountSummarySchema = z.strictObject({ accountId: z.string().min(1), redditUsername: z.string().min(1), matrixUserId: z.string().min(1), isRunning: z.boolean(), status: z.union([ z.literal('authenticated'), z.literal('login-required'), z.literal('suspended'), z.literal('removed'), ]), createdAt: z.number(), updatedAt: z.number(), lastImportedAt: z.number(), /** Set when the operator retired the account; its content is kept read-only. */ removedAt: z.number().nullable().optional(), /** Absent on responses from a build that predates establishment tracking. */ establishment: AccountEstablishmentSummarySchema.nullable().optional(), }); export const RedditAccountOwnerSchema = RedditAccountSummarySchema.pick({ accountId: true, redditUsername: true, }); export const RedditAccountsResponseSchema = z.array(RedditAccountSummarySchema); export const LoginStatusResponseSchema = z.union([ z.strictObject({ ready: z.literal(false), error: z.string() }), z.strictObject({ ready: z.literal(true), loggedIn: z.boolean(), status: RedditSessionStateSchema, accountId: z.string().min(1).nullable().optional(), username: z.string().min(1).nullable().optional(), }), z.strictObject({ ready: z.literal(true), loggedIn: z.literal(false), error: z.string(), }), ]); export const RedditCookieImportRequestSchema = z.strictObject({ cookies: z.array(z.strictObject({ name: z.string().min(1).max(256), value: z.string().max(16_384), domain: z.string().min(1).max(253), path: z.string().min(1).max(4_096).default('/'), expires: z.number().finite().optional(), httpOnly: z.boolean().optional(), secure: z.boolean().optional(), sameSite: z.enum(['strict', 'lax', 'none', 'no_restriction', 'unspecified']).optional(), })).min(1).max(100), matrix: z.strictObject({ homeserver: z.string().url(), accessToken: z.string().min(1).max(16_384), userId: z.string().min(1).max(512), capturedAt: z.number().finite(), }), }); export const RedditCookieImportResponseSchema = z.union([ z.strictObject({ ok: z.literal(true), status: z.literal('authenticated'), account: RedditAccountSummarySchema, }), z.strictObject({ ok: z.literal(false), error: z.string() }), ]); export const RedditAccountActivationResponseSchema = z.union([ z.strictObject({ ok: z.literal(true), account: RedditAccountSummarySchema }), z.strictObject({ ok: z.literal(false), error: z.string() }), ]); /** The removed account is echoed back so the caller can name what it deleted. */ export const RedditAccountRemovalResponseSchema = z.union([ z.strictObject({ ok: z.literal(true), account: RedditAccountSummarySchema }), z.strictObject({ ok: z.literal(false), error: z.string() }), ]); export type RedditSessionState = z.infer; export type LoginStatusResponse = z.infer; export type RedditCookieImportRequest = z.infer; export type RedditAccountSummary = z.infer; export type AccountEstablishmentState = z.infer; export type AccountEstablishmentSummary = z.infer; export type RedditAccountOwner = z.infer; export type RedditAccountRemovalResponse = z.infer;