export type JsonRecord = Record export type QueryValue = string | number | boolean | null | undefined export type QueryInput = Record export type ListingSort = 'best' | 'hot' | 'new' | 'top' | 'rising' | 'controversial' export type SearchSort = 'relevance' | 'hot' | 'top' | 'new' | 'comments' export type TimeFilter = 'hour' | 'day' | 'week' | 'month' | 'year' | 'all' export type UserListing = 'about' | 'submitted' | 'comments' | 'overview' export type SubmitKind = 'self' | 'link' export type VoteDirection = 1 | 0 | -1 export type AccountInput = { /** Exact integration name, e.g. `reddit-work`. Wins over `account`. */ integration?: string /** Purpose suffix. `work` → `reddit-work`. `default` / `reddit` / omitted → `reddit`. */ account?: string } export type RedditRequestInput = AccountInput & { path: string method?: string query?: QueryInput headers?: Record body?: unknown dryRun?: boolean confirm?: boolean } export type RedditRequestResult = { ok: boolean status: number statusText: string headers: Record body: unknown integration: string } export type GetListingInput = AccountInput & { subreddit?: string sort?: ListingSort t?: TimeFilter limit?: number after?: string before?: string } export type GetSubredditInput = AccountInput & { subreddit: string } export type SearchInput = AccountInput & { query: string subreddit?: string sort?: SearchSort t?: TimeFilter limit?: number after?: string restrictToSubreddit?: boolean } export type GetUserInput = AccountInput & { username: string listing?: UserListing sort?: ListingSort t?: TimeFilter limit?: number after?: string } export type GetPostInput = AccountInput & { id: string subreddit?: string commentLimit?: number commentSort?: SearchSort | ListingSort } export type SubmitPostInput = AccountInput & { subreddit: string title: string kind?: SubmitKind text?: string url?: string nsfw?: boolean spoiler?: boolean sendreplies?: boolean flairId?: string flairText?: string dryRun?: boolean confirm?: boolean } export type SubmitCommentInput = AccountInput & { parentId: string text: string dryRun?: boolean confirm?: boolean } export type VoteInput = AccountInput & { id: string direction: VoteDirection | 'up' | 'down' | 'clear' dryRun?: boolean confirm?: boolean } export type ShapedPost = { id: string name: string title: string author: string subreddit: string score: number | null upvoteRatio: number | null numComments: number | null url: string | null permalink: string | null createdUtc: number | null over18: boolean stickied: boolean isSelf: boolean selftext: string | null selftextTruncated: boolean linkFlairText: string | null } export type ShapedComment = { id: string name: string author: string body: string | null bodyTruncated: boolean score: number | null permalink: string | null createdUtc: number | null parentId: string | null } export type ShapedListing = { kind: 'listing' after: string | null before: string | null posts: ShapedPost[] } export type ShapedSubreddit = { id: string | null name: string | null displayName: string | null title: string | null publicDescription: string | null subscribers: number | null accountsActive: number | null over18: boolean url: string | null createdUtc: number | null submissionType: string | null } export type ShapedUser = { id: string | null name: string | null createdUtc: number | null commentKarma: number | null linkKarma: number | null totalKarma: number | null isGold: boolean isMod: boolean verified: boolean hasVerifiedEmail: boolean | null } export function requireRecord(value: unknown, utilityName: string): JsonRecord { if (value && typeof value === 'object' && !Array.isArray(value)) { return value as JsonRecord } throw new Error(utilityName + ' requires an object params value.') } export function requireStringField(record: JsonRecord, key: string, utilityName: string): string { const value = record[key] if (typeof value !== 'string' || value.length === 0) { throw new Error(utilityName + ' requires params.' + key + '.') } return value } export function asRecord(value: unknown): JsonRecord | null { if (value && typeof value === 'object' && !Array.isArray(value)) { return value as JsonRecord } return null } export function stringValue(value: unknown): string | undefined { return typeof value === 'string' && value.length > 0 ? value : undefined } export function numberValue(value: unknown): number | null { return typeof value === 'number' && Number.isFinite(value) ? value : null } export function booleanValue(value: unknown, fallback = false): boolean { return typeof value === 'boolean' ? value : fallback }