Schedule posts to Bluesky with Cloudflare workers. skyscheduler.work
cf tool bsky-tool cloudflare bluesky schedule bsky service social-media cloudflare-workers

actually bother with rename

make limits not a .d.ts, it never really should have been this as it kept growing, but w/e

+25 -25
+2 -2
README.md
··· 97 97 98 98 ### Application Variables 99 99 100 - Most of the application can be modified either through the `wrangler.toml` vars section or via `src/limits.d.ts`. These are usually heavily commented to explain what the options control. 100 + Most of the application can be modified either through the `wrangler.toml` vars section or via `src/limits.ts`. These are usually heavily commented to explain what the options control. 101 101 102 102 ### Minimization 103 103 104 - The application by default is configured to use the minified versions of the scripts in `assets/js`. You can either turn off this behavior in `src/limits.d.ts` or run `npm run minify` whenever those files change. 104 + The application by default is configured to use the minified versions of the scripts in `assets/js`. You can either turn off this behavior in `src/limits.ts` or run `npm run minify` whenever those files change. 105 105 106 106 ## Project Structure 107 107
+1 -1
src/auth/index.ts
··· 4 4 import { username } from "better-auth/plugins"; 5 5 import { drizzle } from "drizzle-orm/d1"; 6 6 import { schema } from "../db"; 7 - import { BSKY_MAX_USERNAME_LENGTH, BSKY_MIN_USERNAME_LENGTH } from "../limits.d"; 7 + import { BSKY_MAX_USERNAME_LENGTH, BSKY_MIN_USERNAME_LENGTH } from "../limits"; 8 8 import { Bindings } from "../types"; 9 9 import { lookupBskyHandle } from "../utils/bskyApi"; 10 10 import { createDMWithUser } from "../utils/bskyMsg";
+1 -1
src/endpoints/preview.tsx
··· 2 2 import { secureHeaders } from "hono/secure-headers"; 3 3 import isEmpty from "just-is-empty"; 4 4 import { ContextVariables } from "../auth"; 5 - import { BSKY_IMG_MIME_TYPES } from "../limits.d"; 5 + import { BSKY_IMG_MIME_TYPES } from "../limits"; 6 6 import { authMiddleware } from "../middleware/auth"; 7 7 import { corsHelperMiddleware } from "../middleware/corsHelper"; 8 8 import { Bindings } from "../types.d";
+1 -1
src/layout/altTextModal.tsx
··· 1 - import { MAX_ALT_TEXT } from "../limits.d"; 1 + import { MAX_ALT_TEXT } from "../limits"; 2 2 3 3 export function AltTextDialog() { 4 4 return (
+1 -1
src/layout/editPost.tsx
··· 1 - import { MAX_LENGTH } from "../limits.d"; 1 + import { MAX_LENGTH } from "../limits"; 2 2 import { EmbedDataType, Post } from "../types.d"; 3 3 import { PostContentObject } from "./postList"; 4 4
+1 -1
src/layout/makePost.tsx
··· 8 8 MAX_LENGTH, 9 9 MAX_THUMBNAIL_SIZE, 10 10 R2_FILE_SIZE_LIMIT_IN_MB 11 - } from "../limits.d"; 11 + } from "../limits"; 12 12 import { PreloadRules } from "../types.d"; 13 13 import { ConstScriptPreload } from "../utils/constScriptGen"; 14 14 import { DependencyTags } from "./depTags";
+1 -1
src/layout/passwordFields.tsx
··· 1 1 import { html } from "hono/html"; 2 - import { BSKY_MAX_APP_PASSWORD_LENGTH, MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits.d"; 2 + import { BSKY_MAX_APP_PASSWORD_LENGTH, MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits"; 3 3 import { PWAutoCompleteSettings } from "../types.d"; 4 4 import { appPasswordRegex } from "../validation/regexCases"; 5 5
+1 -1
src/layout/retweetOptions.tsx
··· 1 1 import isEmpty from "just-is-empty"; 2 - import { MAX_REPOST_IN_HOURS, MAX_REPOST_INTERVAL_LIMIT } from "../limits.d"; 2 + import { MAX_REPOST_IN_HOURS, MAX_REPOST_INTERVAL_LIMIT } from "../limits"; 3 3 4 4 type RetweetOptionsProps = { 5 5 id: string;
+1 -1
src/layout/settings.tsx
··· 1 - import { MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits.d"; 1 + import { MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits"; 2 2 import { PWAutoCompleteSettings } from "../types.d"; 3 3 import { settingsScriptStr } from "../utils/appScripts"; 4 4 import { BSkyAppPasswordField, DashboardPasswordField } from "./passwordFields";
+1 -1
src/layout/usernameField.tsx
··· 1 1 import { raw } from "hono/html"; 2 - import { BSKY_MIN_USERNAME_LENGTH } from "../limits.d"; 2 + import { BSKY_MIN_USERNAME_LENGTH } from "../limits"; 3 3 4 4 type UsernameFieldProps = { 5 5 title?: string;
+1 -1
src/limits.d.ts src/limits.ts
··· 12 12 // max length of an animated gif in minutes 13 13 export const MAX_GIF_LENGTH: number = 1; 14 14 // if gifs should be allowed to upload 15 - export const GIF_UPLOAD_ALLOWED: boolean = false; 15 + export const GIF_UPLOAD_ALLOWED: boolean = true; 16 16 17 17 // This is the length of how much we keep in the DB after a post has been made 18 18 export const MAX_POSTED_LENGTH: number = 50;
+1 -1
src/pages/homepage.tsx
··· 1 1 import FooterCopyright from "../layout/footer"; 2 2 import { BaseLayout } from "../layout/main"; 3 3 import NavTags from "../layout/navTags"; 4 - import { MAX_REPOST_DAYS, MAX_REPOST_IN_HOURS, MAX_REPOST_INTERVAL, R2_FILE_SIZE_LIMIT_IN_MB } from "../limits.d"; 4 + import { MAX_REPOST_DAYS, MAX_REPOST_IN_HOURS, MAX_REPOST_INTERVAL, R2_FILE_SIZE_LIMIT_IN_MB } from "../limits"; 5 5 6 6 export default function Home() { 7 7 return (
+1 -1
src/pages/reset.tsx
··· 1 1 import AccountHandler from "../layout/account"; 2 2 import { BaseLayout } from "../layout/main"; 3 3 import NavTags from "../layout/navTags"; 4 - import { MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits.d"; 4 + import { MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits"; 5 5 6 6 export default function ResetPassword() { 7 7 const links = [{title: "Forgot Password", url: "/forgot"}];
+1 -1
src/pages/signup.tsx
··· 6 6 import { BSkyAppPasswordField, DashboardPasswordField } from "../layout/passwordFields"; 7 7 import { TurnstileCaptcha, TurnstileCaptchaPreloads } from "../layout/turnstile"; 8 8 import { UsernameField } from "../layout/usernameField"; 9 - import { MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits.d"; 9 + import { MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits"; 10 10 import { PWAutoCompleteSettings } from "../types.d"; 11 11 import { getInviteThread, isUsingInviteKeys } from "../utils/inviteKeys"; 12 12
+1 -1
src/utils/bskyApi.ts
··· 4 4 import has from 'just-has'; 5 5 import isEmpty from "just-is-empty"; 6 6 import truncate from "just-truncate"; 7 - import { BSKY_IMG_SIZE_LIMIT, MAX_ALT_TEXT, MAX_EMBEDS_PER_POST, MAX_POSTED_LENGTH } from '../limits.d'; 7 + import { BSKY_IMG_SIZE_LIMIT, MAX_ALT_TEXT, MAX_EMBEDS_PER_POST, MAX_POSTED_LENGTH } from '../limits'; 8 8 import { 9 9 Bindings, BskyEmbedWrapper, BskyRecordWrapper, EmbedData, EmbedDataType, 10 10 LooseObj, PlatformLoginResponse, Post, PostLabel,
+1 -1
src/utils/constScriptGen.ts
··· 11 11 MAX_THUMBNAIL_SIZE, 12 12 R2_FILE_SIZE_LIMIT, 13 13 GIF_UPLOAD_ALLOWED 14 - } from "../limits.d"; 14 + } from "../limits"; 15 15 import { PreloadRules } from "../types.d"; 16 16 import { postRecordURI } from "../validation/regexCases"; 17 17
+1 -1
src/utils/dbQuery.ts
··· 13 13 import { v4 as uuidv4, validate as uuidValid } from 'uuid'; 14 14 import { mediaFiles, posts, repostCounts, reposts, violations } from "../db/app.schema"; 15 15 import { accounts, users } from "../db/auth.schema"; 16 - import { MAX_HOLD_DAYS_BEFORE_PURGE, MAX_POSTED_LENGTH, MAX_REPOST_POSTS } from "../limits.d"; 16 + import { MAX_HOLD_DAYS_BEFORE_PURGE, MAX_POSTED_LENGTH, MAX_REPOST_POSTS } from "../limits"; 17 17 import { 18 18 BatchQuery, 19 19 Bindings, BskyAPILoginCreds, CreateObjectResponse, CreatePostQueryResponse,
+1 -1
src/utils/r2Query.ts
··· 13 13 MB_TO_BYTES, 14 14 R2_FILE_SIZE_LIMIT, 15 15 R2_FILE_SIZE_LIMIT_IN_MB 16 - } from "../limits.d"; 16 + } from "../limits"; 17 17 import { Bindings, EmbedData, EmbedDataType, R2BucketObject, ScheduledContext } from '../types.d'; 18 18 import { addFileListing, deleteFileListings } from './dbQueryFile'; 19 19
+1 -1
src/validation/accountResetSchema.ts
··· 1 1 import * as z from "zod/v4"; 2 - import { MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits.d"; 2 + import { MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits"; 3 3 4 4 export const AccountResetSchema = z.object({ 5 5 resetToken: z.string().nonempty("reset token is missing!"),
+1 -1
src/validation/accountUpdateSchema.ts
··· 2 2 import { 3 3 BSKY_MAX_APP_PASSWORD_LENGTH, BSKY_MIN_USERNAME_LENGTH, 4 4 MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS 5 - } from "../limits.d"; 5 + } from "../limits"; 6 6 import { appPasswordRegex } from "./regexCases"; 7 7 8 8 export const AccountUpdateSchema = z.object({
+1 -1
src/validation/embedSchema.ts
··· 1 1 import isEmpty from "just-is-empty"; 2 2 import * as z from "zod/v4"; 3 - import { BSKY_VIDEO_LENGTH_LIMIT } from "../limits.d"; 3 + import { BSKY_VIDEO_LENGTH_LIMIT } from "../limits"; 4 4 import { EmbedDataType } from "../types.d"; 5 5 import { FileContentSchema } from "./mediaSchema"; 6 6 import { atpRecordURI } from "./regexCases";
+1 -1
src/validation/postSchema.ts
··· 1 1 import * as z from "zod/v4"; 2 - import { MAX_LENGTH, MAX_REPOST_INTERVAL_LIMIT, MAX_REPOST_IN_HOURS, MIN_LENGTH } from "../limits.d"; 2 + import { MAX_LENGTH, MAX_REPOST_INTERVAL_LIMIT, MAX_REPOST_IN_HOURS, MIN_LENGTH } from "../limits"; 3 3 import { EmbedDataType, PostLabel } from "../types.d"; 4 4 import { ImageEmbedSchema, LinkEmbedSchema, PostRecordSchema, VideoEmbedSchema } from "./embedSchema"; 5 5 import { FileContentSchema } from "./mediaSchema";
+1 -1
src/validation/repostSchema.ts
··· 1 1 import * as z from "zod/v4"; 2 - import { MAX_REPOST_IN_HOURS, MAX_REPOST_INTERVAL_LIMIT } from "../limits.d"; 2 + import { MAX_REPOST_IN_HOURS, MAX_REPOST_INTERVAL_LIMIT } from "../limits"; 3 3 import { atProtoPostURI, postRecordURI } from "./regexCases"; 4 4 5 5 export const RepostSchema = z.object({
+1 -1
src/validation/sharedValidations.ts
··· 5 5 BSKY_MIN_USERNAME_LENGTH, 6 6 MAX_ALT_TEXT, 7 7 MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS 8 - } from "../limits.d"; 8 + } from "../limits"; 9 9 import { appPasswordRegex } from "./regexCases"; 10 10 11 11 export const UsernameSchema = z.object({