Schedule posts to Bluesky with Cloudflare workers.
skyscheduler.work
cf
tool
bsky-tool
cloudflare
bluesky
schedule
bsky
service
social-media
cloudflare-workers
1import { BatchItem } from "drizzle-orm/batch";
2import { Context } from "hono";
3import { ScheduledContext } from "./classes/context";
4import { Post } from "./classes/post";
5import { Repost } from "./classes/repost";
6
7/*** Settings config wrappers for bindings ***/
8type ImageConfigSettings = {
9 enabled: boolean;
10 steps?: number[];
11 bucket_url?: string;
12 max_width?: number;
13};
14
15type SignupConfigSettings = {
16 use_captcha: boolean;
17 invite_only: boolean;
18 invite_thread?: string;
19 invite_uses: number;
20}
21
22type RedirectConfigSettings = {
23 contact: string;
24 tip: string;
25}
26
27type R2ConfigSettings = {
28 auto_prune: boolean;
29 prune_days?: number;
30}
31
32type QueueConfigSettings = {
33 enabled: boolean;
34 repostsEnabled: boolean;
35 threadEnabled: boolean;
36 postNowEnabled?: boolean;
37 pressure_retries?: boolean;
38 delay_val: number;
39 max_retries: number;
40 post_queues: string[];
41 repost_queues: string[];
42}
43
44export type AgentConfigSettings = {
45 use_posts: boolean;
46 use_reposts: boolean;
47}
48
49/** Types, types, types **/
50export interface Bindings {
51 DB: D1Database;
52 R2: R2Bucket;
53 R2RESIZE: R2Bucket;
54 KV: KVNamespace;
55 IMAGES: ImagesBinding;
56 ASSETS?: Fetcher;
57 POST_QUEUE: Queue;
58 REPOST_QUEUE: Queue;
59 QUEUE_SETTINGS: QueueConfigSettings;
60 INVITE_POOL?: KVNamespace;
61 IMAGE_SETTINGS: ImageConfigSettings;
62 SIGNUP_SETTINGS: SignupConfigSettings;
63 TASK_SETTINGS: AgentConfigSettings;
64 R2_SETTINGS: R2ConfigSettings;
65 POST_LIMITER: RateLimit;
66 REPOST_LIMITER: RateLimit;
67 UPDATE_LIMITER: RateLimit;
68 ACCOUNT_LIMITER: RateLimit;
69 DEFAULT_ADMIN_USER: string;
70 DEFAULT_ADMIN_PASS: string;
71 DEFAULT_ADMIN_BSKY_PASS: string;
72 BETTER_AUTH_SECRET: string;
73 BETTER_AUTH_URL: string;
74 TURNSTILE_PUBLIC_KEY: string;
75 TURNSTILE_SECRET_KEY: string;
76 RESIZE_SECRET_HEADER: string;
77 RESET_BOT_USERNAME: string;
78 RESET_BOT_APP_PASS: string;
79 ENCRYPTED_PASS_KEY: string;
80 IN_DEV: boolean;
81 REDIRECTS: RedirectConfigSettings;
82};
83
84export enum EmbedDataType {
85 None = 0,
86 Image = 1,
87 WebLink = 2,
88 Video = 3,
89 Record = 4,
90};
91
92export type EmbedData = {
93 content: string;
94 alt?: string;
95 title?: string;
96 uri?: string;
97 type: EmbedDataType;
98 description?: string;
99 width?: number;
100 height?: number;
101 duration?: number;
102};
103
104export enum PostLabel {
105 None = "None",
106 Suggestive = "Suggestive",
107 Nudity = "Nudity",
108 Adult = "Adult",
109 Graphic = "Graphic",
110 GraphicAdult = "GraphicAdult"
111};
112
113export enum TaskType {
114 None,
115 Blast,
116 Post,
117 Repost,
118};
119
120export type Violation = {
121 userId: string;
122 tosViolation: boolean;
123 userPassInvalid: boolean;
124 accountSuspended: boolean;
125 accountGone: boolean;
126 mediaTooBig: boolean;
127 createdAt: string;
128};
129
130export type PostResponseObject = {
131 uri: string;
132 cid: string;
133};
134
135export type PostRecordResponse = PostResponseObject & {
136 postID: string|null;
137 embeds?: EmbedData[];
138};
139
140export type PostStatus = {
141 records: PostRecordResponse[];
142 // number of expected successes
143 expected: number;
144 // number of successes we got
145 got: number;
146};
147
148export type DeleteResponse = {
149 success: boolean;
150 isRepost: boolean;
151 needsRefresh?: boolean;
152}
153
154export interface LooseObj {
155 [key: string]: any;
156};
157
158export enum AccountStatus {
159 None = 0,
160 Ok,
161 Suspended,
162 Deactivated,
163 TakenDown,
164 InvalidAccount,
165 PlatformOutage,
166 MediaTooBig,
167 UnhandledError,
168 TOSViolation,
169};
170
171export enum PWAutoCompleteSettings {
172 Off,
173 NewPass,
174 CurrentPass
175};
176
177export type BskyEmbedWrapper = {
178 type: EmbedDataType;
179 data?: any;
180};
181
182export type BskyRecordWrapper = {
183 cid?: string;
184 uri?: string;
185};
186
187export type CreateObjectResponse = {
188 ok: boolean;
189 msg: string;
190 postId?: string;
191};
192
193export type CreatePostQueryResponse = CreateObjectResponse & {
194 postNow?: boolean;
195};
196
197export type QueueTaskData = {
198 type: TaskType;
199 data: Post|Repost|null;
200};
201
202// Used for the pruning and database operations
203export type GetAllPostedBatch = {
204 id: string;
205 uri: string|null;
206};
207
208export type R2BucketObject = {
209 name: string;
210 user: string|null;
211 date: Date
212}
213
214export type AllContext = Context|ScheduledContext;
215export type BatchQuery = [BatchItem<'sqlite'>, ...BatchItem<'sqlite'>[]];