Files
climperor/web/frontend/functions/api/mobile-demand.js
T
vosonandCursor b01552ee6e v0.5.84: matches origin filter, mobile gate, refresh reliability.
Ship Web refresh cache/lock, mobile demand gate, matches 职业/国服 filter, and related site updates through 0.5.84.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-29 18:31:55 +08:00

71 lines
1.9 KiB
JavaScript

/**
* Pages Function: GET|POST /api/mobile-demand
*
* Best-effort edge counter for "please add mobile support" demand.
* Stored via the Cache API (no KV / wrangler binding), same pattern as
* live-status. Counts may undercount under concurrent colo races and can
* reset if the edge entry is evicted; good enough as a demand signal.
*
* GET -> { count }
* POST -> increment once, return { count, voted: true }
*/
const CACHE_KEY = "https://mobile-demand.internal/v1";
// Long store TTL so eviction is rare; freshness is not time-gated.
const CACHE_STORE_MAX_AGE_S = 365 * 24 * 60 * 60;
function jsonResponse(body, status = 200) {
return new Response(JSON.stringify(body), {
status,
headers: {
"Content-Type": "application/json; charset=utf-8",
"Cache-Control": "no-store",
},
});
}
async function readCount() {
try {
const cached = await caches.default.match(CACHE_KEY);
if (!cached) return 0;
const data = await cached.json();
const n = Number(data && data.count);
return Number.isFinite(n) && n >= 0 ? Math.floor(n) : 0;
} catch {
return 0;
}
}
async function writeCount(count) {
const body = {
count,
updated_at: new Date().toISOString(),
};
const cached = new Response(JSON.stringify(body), {
headers: {
"Content-Type": "application/json; charset=utf-8",
"Cache-Control": `max-age=${CACHE_STORE_MAX_AGE_S}`,
},
});
await caches.default.put(CACHE_KEY, cached);
}
export async function onRequestGet() {
try {
const count = await readCount();
return jsonResponse({ count });
} catch {
return jsonResponse({ count: 0 });
}
}
export async function onRequestPost() {
try {
const next = (await readCount()) + 1;
await writeCount(next);
return jsonResponse({ count: next, voted: true });
} catch {
return jsonResponse({ error: "increment_failed" }, 503);
}
}