mirror of
https://github.com/direct-img/direct-img.link.git
synced 2026-10-08 22:45:19 +00:00
Perf: Serve homepage and assets without invoking Functions
Add _routes.json so /, /robots.txt and /assets/* skip the worker and don't count against the Functions request quota. rate-limit.js moves to assets/ so the homepage reads it client-side instead of via HTMLRewriter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"version": 1,
|
||||
"include": ["/*"],
|
||||
"exclude": ["/", "/index.html", "/robots.txt", "/assets/*"]
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
// New searches (cache misses) allowed per IP per day, reset at 00:00 UTC. Cache hits never count.
|
||||
// Safe to edit by hand. The homepage reads these automatically; README.md needs a manual update.
|
||||
// Safe to edit by hand. Imported by the worker and by the homepage (as a static file, so no Functions quota);
|
||||
// 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;
|
||||
+3
-17
@@ -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 * as LIMITS from "./_utils/rate-limit.js";
|
||||
import * as LIMITS from "../assets/rate-limit.js";
|
||||
|
||||
const TTL_SECONDS = 90 * 24 * 60 * 60;
|
||||
const MAX_INDEX = 20;
|
||||
@@ -13,8 +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") return homepage(env, url);
|
||||
if (path === "robots.txt" || path.startsWith("assets/")) {
|
||||
// _routes.json serves these statically without invoking this function; kept as a fallback
|
||||
if (!path || path === "index.html" || path === "robots.txt" || path.startsWith("assets/")) {
|
||||
return env.ASSETS.fetch(request);
|
||||
}
|
||||
if (path === "favicon.ico") return asset("favicon.ico");
|
||||
@@ -207,20 +207,6 @@ 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;
|
||||
|
||||
@@ -127,5 +127,9 @@ Use images to complement your responses, powered by Brave.</code></pre>
|
||||
},()=>getSelection().selectAllChildren(p));
|
||||
};
|
||||
</script>
|
||||
<script type="module">
|
||||
import * as L from '/assets/rate-limit.js';
|
||||
for(const e of document.querySelectorAll('[data-limit]'))e.textContent=L[e.dataset.limit]??e.textContent;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user