tangled
alpha
login
or
join now
socksthewolf.com
/
skyscheduler
1
fork
atom
Schedule posts to Bluesky with Cloudflare workers.
skyscheduler.work
cf
tool
bsky-tool
cloudflare
bluesky
schedule
bsky
service
social-media
cloudflare-workers
1
fork
atom
overview
issues
pulls
pipelines
up some values yeah
SocksTheWolf
2 weeks ago
bc385e22
7b881298
+15
-7
5 changed files
expand all
collapse all
unified
split
src
endpoints
account.tsx
middleware
rateLimit.ts
types.ts
wrangler.d.ts
wrangler.toml
+3
-3
src/endpoints/account.tsx
···
44
44
}
45
45
46
46
// wrapper to login
47
47
-
account.post("/login", async (c) => {
47
47
+
account.post("/login", rateLimit({limiter: "ACCOUNT_LIMITER"}), async (c) => {
48
48
const body = await c.req.json();
49
49
const auth = c.get("auth");
50
50
const validation = LoginSchema.safeParse(body);
···
137
137
return c.text("");
138
138
});
139
139
140
140
-
account.post("/signup", verifyTurnstile, async (c: Context) => {
140
140
+
account.post("/signup", verifyTurnstile, rateLimit({limiter: "ACCOUNT_LIMITER"}), async (c: Context) => {
141
141
const body = await c.req.json();
142
142
const validation = SignupSchema.safeParse(body);
143
143
if (!validation.success) {
···
253
253
return c.json({ok: true, msg: "request processed"});
254
254
});
255
255
256
256
-
account.post("/reset", async (c: Context) => {
256
256
+
account.post("/reset", rateLimit({limiter: "ACCOUNT_LIMITER"}), async (c: Context) => {
257
257
const body = await c.req.json();
258
258
259
259
const validation = AccountResetSchema.safeParse(body);
+4
-2
src/middleware/rateLimit.ts
···
7
7
type RateLimitProps = {
8
8
limiter: string;
9
9
html?: boolean;
10
10
+
message?: string;
10
11
};
11
12
12
13
export const rateLimit = (prop: RateLimitProps) => {
···
22
23
if (success) {
23
24
await next();
24
25
} else {
26
26
+
const str: string = prop.message || "You are currently rate limited, try again later";
25
27
if (prop.html) {
26
26
-
return c.html(html`<b class="btn-error">You are currently rate limited, try again later</b>`);
28
28
+
return c.html(html`<b class="btn-error">${str}</b>`);
27
29
} else {
28
28
-
return c.json({ok: false, msg: "You are currently rate limited, try again later"}, 429);
30
30
+
return c.json({ok: false, msg: str}, 429);
29
31
}
30
32
}
31
33
});
+1
src/types.ts
···
65
65
POST_LIMITER: RateLimit;
66
66
REPOST_LIMITER: RateLimit;
67
67
UPDATE_LIMITER: RateLimit;
68
68
+
ACCOUNT_LIMITER: RateLimit;
68
69
DEFAULT_ADMIN_USER: string;
69
70
DEFAULT_ADMIN_PASS: string;
70
71
DEFAULT_ADMIN_BSKY_PASS: string;
+2
-1
src/wrangler.d.ts
···
1
1
/* eslint-disable */
2
2
-
// Generated by Wrangler by running `wrangler types src/wrangler.d.ts` (hash: ede590ad561b49f51ae6fcdf7fe7f2a3)
2
2
+
// Generated by Wrangler by running `wrangler types src/wrangler.d.ts` (hash: e2b1e0c3605cf1bbdd0ecf0cdf57036b)
3
3
// Runtime types generated with workerd@1.20260305.0 2025-11-18 disable_ctx_exports,disable_nodejs_http_server_modules,nodejs_compat,nodejs_compat_do_not_populate_process_env
4
4
declare namespace Cloudflare {
5
5
interface GlobalProps {
···
16
16
REPOST_LIMITER: RateLimit;
17
17
POST_LIMITER: RateLimit;
18
18
UPDATE_LIMITER: RateLimit;
19
19
+
ACCOUNT_LIMITER: RateLimit;
19
20
IMAGES: ImagesBinding;
20
21
ASSETS: Fetcher;
21
22
IMAGE_SETTINGS: {"enabled":true,"steps":[95,85,75],"bucket_url":"https://resize.skyscheduler.work/","max_width":3000};
+5
-1
wrangler.toml
···
46
46
[[ratelimits]]
47
47
name = "POST_LIMITER"
48
48
namespace_id = "1002"
49
49
-
simple = { limit = 3, period = 10 }
49
49
+
simple = { limit = 5, period = 10 }
50
50
[[ratelimits]]
51
51
name = "UPDATE_LIMITER"
52
52
namespace_id = "1003"
53
53
simple = { limit = 7, period = 60 }
54
54
+
[[ratelimits]]
55
55
+
name = "ACCOUNT_LIMITER"
56
56
+
namespace_id = "1004"
57
57
+
simple = { limit = 10, period = 60 }
54
58
55
59
[triggers]
56
60
# Schedule cron triggers at the start of every hour and ~5:30pm on sunday for big cleanups: