Feat: Homepage reads daily limits from rate-limit.js

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-06 16:35:46 -07:00
co-authored by Claude Opus 5.5
parent 826e0cd2dd
commit c76b1ba5f7
3 changed files with 21 additions and 6 deletions
+18 -3
View File
@@ -2,7 +2,7 @@ import { braveImageSearch } from "./_utils/brave.js";
import { bingImageSearchFallback } from "./_utils/bing.js";
import { freeImageUrls, parseFreeSource, FREE_UA } from "./_utils/free.js";
import { isFlickrPlaceholder } from "./_utils/flickr.js";
import { DAILY_LIMIT, FREE_DAILY_LIMIT } from "./_utils/rate-limit.js";
import * as LIMITS from "./_utils/rate-limit.js";
const TTL_SECONDS = 90 * 24 * 60 * 60;
const MAX_INDEX = 20;
@@ -13,7 +13,8 @@ export async function onRequest(context) {
const path = params.path?.join("/") || "";
const asset = f => env.ASSETS.fetch(new Request(new URL(`/assets/${f}`, url.origin)));
if (!path || path === "index.html" || path === "robots.txt" || path.startsWith("assets/")) {
if (!path || path === "index.html") return homepage(env, url);
if (path === "robots.txt" || path.startsWith("assets/")) {
return env.ASSETS.fetch(request);
}
if (path === "favicon.ico") return asset("favicon.ico");
@@ -57,7 +58,7 @@ export async function onRequest(context) {
const today = new Date().toISOString().slice(0, 10);
// free.* gets its own counter (prefixed so main-site ids stay unchanged) since it never spends Brave credits
const rateId = await sha256(`${free ? "free:" : ""}${ip}:${today}`);
const limit = free ? FREE_DAILY_LIMIT : DAILY_LIMIT;
const limit = free ? LIMITS.FREE_DAILY_LIMIT : LIMITS.DAILY_LIMIT;
let count = 1;
if (env.SURREAL_URL && env.SURREAL_USER && env.SURREAL_PASS) {
@@ -206,6 +207,20 @@ async function* webImageUrls(context, query) {
yield* (await bingImageSearchFallback(query)) || [];
}
// Fills each <span data-limit="NAME"> with that export of rate-limit.js, so the page never shows stale limits.
// Fetched without the browser's If-None-Match and served without an ETag, so a cached copy can't either.
async function homepage(env, url) {
const res = await env.ASSETS.fetch(new Request(url));
const headers = new Headers(res.headers);
headers.delete("etag");
return new HTMLRewriter().on("[data-limit]", {
element: e => {
const v = LIMITS[e.getAttribute("data-limit")];
if (v != null) e.setInnerContent(`${v}`);
}
}).transform(new Response(res.body, { status: res.status, headers }));
}
async function setupSurreal(env) {
if (!env.SURREAL_URL || !env.SURREAL_USER || !env.SURREAL_PASS) return jsonResponse(500, { error: "SurrealDB env vars missing" });
const sql = `DEFINE NAMESPACE IF NOT EXISTS direct_img;
+1 -1
View File
@@ -1,5 +1,5 @@
// New searches (cache misses) allowed per IP per day, reset at 00:00 UTC. Cache hits never count.
// Safe to edit by hand; also update the numbers in README.md and index.html.
// Safe to edit by hand. The homepage reads these automatically; README.md needs a manual update.
// The burst limit (~10 req/10s) is a Cloudflare WAF rule, not set here.
export const DAILY_LIMIT = 35;
export const FREE_DAILY_LIMIT = 100;
+2 -2
View File
@@ -99,8 +99,8 @@ Use images to complement your responses, powered by Brave.</code></pre>
</thead>
<tbody>
<tr><td>Burst</td><td>~10 req/10s per IP</td><td>HTTP 429 (~10s)</td></tr>
<tr><td>New Searches</td><td>35 per day per IP</td><td>Limit image served</td></tr>
<tr><td>New Free Searches</td><td>100 per day per IP</td><td>Limit image served</td></tr>
<tr><td>New Searches</td><td><span data-limit="DAILY_LIMIT">35</span> per day per IP</td><td>Limit image served</td></tr>
<tr><td>New Free Searches</td><td><span data-limit="FREE_DAILY_LIMIT">100</span> per day per IP</td><td>Limit image served</td></tr>
</tbody>
</table>
<p style="font-size:0.85rem;color:var(--text-muted);">* free.direct-img.link has its own daily limit, separate from the main site's. Cached images don't count toward it and keep loading after you hit it. The burst limit applies to all image requests and is enforced approximately. The daily limit resets at 00:00 UTC.</p>