Something went wrong. Try again.
Schedule posts and reposts to Bluesky (and other PDSes) with Cloudflare workers. skyscheduler.work
scheduling social-media cloudflare bsky service cloudflare-workers bsky-tool bluesky
Something went wrong. Try again.
6.0 kB · 276 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277import type { BlobRef } from "@atproto/api";import type { Session } from "better-auth/types";import type { BatchItem } from "drizzle-orm/batch";import type { DrizzleD1Database } from "drizzle-orm/d1";import type { Context } from "hono";import type { SecureHeadersVariables } from "hono/secure-headers";import type { createAuth } from "./auth";import type { ScheduledContext } from "./classes/context";import type { Post } from "./classes/post";import type { Repost } from "./classes/repost";import type { EmbedDataType, TaskType } from "./enums";
/** Types, types, types **/export interface EmbedData { content: string; alt?: string; title?: string; uri?: string; type: EmbedDataType; description?: string; width?: number; height?: number; duration?: number; associatedRefs?: WebAssociatedRef[];}
export interface MentionCache { handle: string; did: string;}
export interface BaseContent { userId: string; content: string; uuid: string; uri: string; cid: string;
getUser(): string;}
/// BSKY RECORDS & TYPESexport interface StrongRecordObject { uri: string; cid: string;}export interface WebAssociatedRef extends StrongRecordObject { $type: "com.atproto.repo.strongRef";};
export interface BskyEmbedRecord { $type: "app.bsky.embed.record"; record: StrongRecordObject;}
export type BskyEmbedWrapper = BskyEmptyEmbed | BskyVideoEmbed | BskyImgEmbed | BskyWebEmbed;
export interface BskyEmptyEmbed { type: EmbedDataType.None | EmbedDataType.Record; data?: undefined;}
export interface BskyVideoEmbed { type: EmbedDataType.Video; data: BskyVideoRecordData;}
export interface BskyImgEmbed { type: EmbedDataType.Image; data?: BskyImageRecordData[];}
export interface BskyWebEmbed { type: EmbedDataType.WebLink; data: BskyWebLinkRecordData;}
export interface BskyRecordWrapper { cid?: string; uri?: string;}
export interface BskyMediaAspectRatio { width: number; height: number;}
export interface BskyImageRecordData { alt: string; image: BlobRef; aspectRatio?: BskyMediaAspectRatio;}
export interface BskyVideoRecordData { blob: BlobRef; ar: BskyMediaAspectRatio; alt?: string;}
export interface BskyWebLinkRecordData { uri: string; title: string; description: string; associatedRefs?: WebAssociatedRef[]; thumb?: BlobRef;}
export interface ResolveHandleResponse { did: string;}
// Bsky response to making postsexport interface PostRecordResponse extends StrongRecordObject { postID: string|null; embeds?: EmbedData[];};
// Keeping track of the statuses of the posts that we made during a task operationexport interface PostStatus { records: PostRecordResponse[]; // number of expected successes expected: number; // number of successes we got got: number;}
/// APP RESPONSESexport interface CreateObjectResponse { ok: boolean; msg: string; postId?: string; rate_limited?: boolean;}
export interface CreatePostQueryResponse extends CreateObjectResponse { postNow?: boolean;};
export interface DeleteResponse { success: boolean; isRepost: boolean; wasThreadRoot?: boolean;}
export interface DeleteScheduleResponse { success: boolean; postData?: Post;}
/// MIDDLEWARESexport interface RequireAuthMiddlewareProps { returnHTML?: boolean; // if specified: logs out immediately // if not: logs out after 5 seconds forceLogout?: boolean;}
/// USER WRAPPED DATAexport interface AccountUpdatePayload { username?: string; updatedSession?: boolean; password?: string;}export interface EditPostChanges { content: string; embedContent?: EmbedData[]; mentionsCache?: MentionCache[];}
export type RepostIntakeData = { hours: number; times: number;} | undefined;
/// R2export interface R2BucketObject { name: string; user: string | null; date: Date;}
/// VIOLATIONSexport interface ViolationRecordChange { userPassInvalid?: boolean; accountSuspended?: boolean; mediaTooBig?: boolean; tosViolation?: boolean; takenDown?: boolean; accountGone?: boolean;}
export interface Violation extends ViolationRecordChange { userId: string; createdAt: string;};
/// INTERNAL SERVICE HANDLINGexport interface DestinationLetter { did: string|null; handle: string;}
/// DATABASEexport type DBProcessor = DrizzleD1Database | null;export type BatchQueryItem = BatchItem<"sqlite">;export type BatchQueryArray = BatchQueryItem[];export type BatchQuery = [BatchQueryItem, ...BatchQueryArray];
// Used for the pruning and database operationsexport interface GetAllPostedBatch { id: string; uri: string | null;}
export interface DBServiceData { user: string | null; pds: string; did: string | null; email?: string;}
export interface DBServiceLogin extends DBServiceData { pass: string;}
// Used for the file upload table so we can keep track of// abandoned files from partial recordsexport interface FileListingRecord { createdAt?: Date; userId?: string;}
/// RUNNERSexport interface QueueTaskData { type: TaskType; data: Post | Repost | null;}
/// Contexts & Renderingexport type NextMiddleware = () => Promise<void>;export type ContextVariables = SecureHeadersVariables & { auth: ReturnType<typeof createAuth>; userId: UserIdType; isAdmin: boolean; session: Session | null; db?: DBProcessor; pds: string; ssg: boolean;};
export interface NoncePropType { nonce?: string;}
export interface HonoBase { Bindings: Env; Variables: ContextVariables;}
export type BaseContext = Context<HonoBase>;export type AllContext = BaseContext | ScheduledContext;export interface BaseElementProps { ctx?: AllContext;}
// handling preloading and injection of dependencies into the layoutexport interface PreloadRules { type: "image" | "style" | "script" | "module"; href: string; defer?: boolean; async?: boolean;}
/// MISCexport type UserIdType = string | null;export type LooseObj = Record<string, unknown>;