Schedule posts to Bluesky with Cloudflare workers. skyscheduler.work
cf tool bsky-tool cloudflare bluesky schedule bsky service social-media cloudflare-workers
at main 125 lines 3.7 kB view raw
1"$schema" = "./node_modules/wrangler/config-schema.json" 2name = "skyscheduler" 3main = "src/index.tsx" 4compatibility_date = "2025-11-18" 5compatibility_flags = [ "nodejs_compat", "nodejs_compat_do_not_populate_process_env", "disable_ctx_exports", "disable_nodejs_http_server_modules" ] 6send_metrics = false 7minify = true 8upload_source_maps = true 9preview_urls = false 10 11assets = { binding = "ASSETS", run_worker_first = ["/robots.txt"], directory = "./assets/", not_found_handling = "single-page-application" } 12routes = [{ pattern = "skyscheduler.work", custom_domain = true }] 13 14# Redis for sessions 15[[kv_namespaces]] 16binding = "KV" 17id = "0ecd892014ac47eea38c72be94586e7b" 18 19# Invite key pool 20[[kv_namespaces]] 21binding = "INVITE_POOL" 22id = "45e1cff45cad45c28b22c4fbcd30db00" 23 24[[d1_databases]] 25binding = "DB" 26database_name = "skyposts" 27database_id = "5553e724-4dfb-4771-9c08-3584da5855d1" 28migrations_table = "migrations" 29migrations_dir = "migrations" 30 31# media storage 32[[r2_buckets]] 33binding = "R2" 34bucket_name = "skyembeds" 35 36# temporary storage to get CF Images working, this bucket should be WAF'd so no one but the worker can access it. 37[[r2_buckets]] 38binding = "R2RESIZE" 39bucket_name = "skyscheduler-resize" 40 41# rate limits to help combat abuse 42[[ratelimits]] 43name = "REPOST_LIMITER" 44namespace_id = "5471001" 45simple = { limit = 4, period = 60 } 46[[ratelimits]] 47name = "POST_LIMITER" 48namespace_id = "5471002" 49simple = { limit = 5, period = 10 } 50[[ratelimits]] 51name = "UPDATE_LIMITER" 52namespace_id = "5471003" 53simple = { limit = 7, period = 60 } 54[[ratelimits]] 55name = "ACCOUNT_LIMITER" 56namespace_id = "5471004" 57simple = { limit = 10, period = 60 } 58 59[triggers] 60# Schedule cron triggers at the start of every hour and ~5:30pm on sunday for big cleanups: 61crons = [ "0 * * * *", "30 17 * * sun" ] 62 63# flags required to run wrangler in linux 64[dev] 65ip = "127.0.0.1" 66 67[observability] 68enabled = true 69head_sampling_rate = 1 70[observability.traces] 71enabled = true 72head_sampling_rate = 0.5 73persist = true 74 75[[queues.producers]] 76queue = "skyscheduler-post-queue" 77binding = "POST_QUEUE" 78 79[[queues.producers]] 80queue = "skyscheduler-repost-queue" 81binding = "REPOST_QUEUE" 82 83[[queues.consumers]] 84queue = "skyscheduler-post-queue" 85max_batch_size = 3 86max_batch_timeout = 5 87max_retries = 3 88 89[[queues.consumers]] 90queue = "skyscheduler-repost-queue" 91max_batch_size = 15 92max_batch_timeout = 10 93max_retries = 3 94 95# used for resizing the thumbnails for link posts 96[images] 97binding = "IMAGES" 98 99[build] 100command = "npm run minify" 101 102[vars] 103# the domain and protocol that this application is hosted on. note this value is also used for CORS 104BETTER_AUTH_URL="https://skyscheduler.work" 105 106# If we should use cf image transforms & how much of a quality percentage should we try and the public location of the resize bucket. 107IMAGE_SETTINGS={enabled=true, steps=[95, 85, 75], bucket_url="https://resize.skyscheduler.work/", max_width=3000} 108 109# Signup options and if keys should be used 110SIGNUP_SETTINGS = {use_captcha=true, invite_only=false, invite_thread="", invite_uses=10} 111 112# queue handling, pushing information. 113QUEUE_SETTINGS = {enabled=true, repostsEnabled=true, postNowEnabled=false, threadEnabled=true, pressure_retries=true, delay_val=100, max_retries=3, post_queues=["POST_QUEUE"], repost_queues=["REPOST_QUEUE"]} 114 115# redirect links 116REDIRECTS = {contact="https://bsky.app/profile/skyscheduler.work", tip="https://ko-fi.com/socksthewolf/tip"} 117 118# if we should be removing abandoned files from R2 storage 119R2_SETTINGS={auto_prune=true, prune_days=3} 120 121# settings about tasks 122TASK_SETTINGS={use_posts=true, use_reposts=true} 123 124# set this to true in your .dev.vars to turn off turnstile 125IN_DEV=false