docs: serve uncached random readme badge

This commit is contained in:
xmanrui 2026-08-18 20:35:08 +08:00
parent c2fa93a604
commit 23c976ab07
6 changed files with 127 additions and 2 deletions

1
.gitignore vendored
View file

@ -1,4 +1,5 @@
node_modules/
.wrangler/
coverage/
.env
.env.*

View file

@ -8,7 +8,7 @@
<p>
<a href="LICENSE"><img src="https://img.shields.io/github/license/xmanrui/dsh-im" alt="MIT license"></a>
<img src="https://img.shields.io/badge/agent-DeepSeek%20Harness-5865f2" alt="DeepSeek Harness">
<img src="https://redirectwizard.com/redirect/MD1G1" alt="滑动变祖器:今天是梁子或今天是梁圣(随机)">
<img src="https://dsh-im-random-badge.xmanrui-dsh-im.workers.dev" alt="滑动变祖器:今天是梁子或今天是梁圣(随机)">
</p>
<p><a href="README.md">简体中文</a> · <strong>English</strong></p>

View file

@ -9,7 +9,7 @@
<p>
<a href="LICENSE"><img src="https://img.shields.io/github/license/xmanrui/dsh-im" alt="MIT 许可证"></a>
<img src="https://img.shields.io/badge/agent-DeepSeek%20Harness-5865f2" alt="DeepSeek Harness">
<img src="https://redirectwizard.com/redirect/MD1G1" alt="滑动变祖器:今天是梁子或今天是梁圣(随机)">
<img src="https://dsh-im-random-badge.xmanrui-dsh-im.workers.dev" alt="滑动变祖器:今天是梁子或今天是梁圣(随机)">
</p>
<p><strong>简体中文</strong> · <a href="README.en.md">English</a></p>

View file

@ -0,0 +1,55 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import worker, {
createBadgeResponse,
pickBadgeValue,
renderBadge,
} from '../worker/random-badge.mjs';
test('random badge selects both supported values at the sample boundary', () => {
assert.equal(pickBadgeValue(() => 0), '今天是梁子');
assert.equal(pickBadgeValue(() => 0.499999), '今天是梁子');
assert.equal(pickBadgeValue(() => 0.5), '今天是梁圣');
assert.equal(pickBadgeValue(() => 0.999999), '今天是梁圣');
});
test('random badge rejects invalid random samples and badge values', () => {
assert.throws(() => pickBadgeValue(() => -0.1), RangeError);
assert.throws(() => pickBadgeValue(() => 1), RangeError);
assert.throws(() => renderBadge('今天是别人'), RangeError);
});
test('random badge reproduces the Shields layout for either value', () => {
for (const value of ['今天是梁子', '今天是梁圣']) {
const svg = renderBadge(value);
assert.match(svg, /width="130" height="20"/);
assert.match(svg, /<rect width="65" height="20" fill="#555"\/>/);
assert.match(svg, /<rect x="65" width="65" height="20" fill="#f39c12"\/>/);
assert.match(svg, new RegExp(`<title>滑动变祖器: ${value}</title>`));
}
});
test('worker returns a fresh SVG and explicitly disables every cache layer', async () => {
const response = await worker.fetch(new Request('https://badge.example/'));
const svg = await response.text();
assert.equal(response.status, 200);
assert.equal(response.headers.get('content-type'), 'image/svg+xml; charset=utf-8');
assert.equal(response.headers.get('cache-control'), 'no-store, no-cache, must-revalidate, max-age=0');
assert.equal(response.headers.get('cdn-cache-control'), 'no-store');
assert.equal(response.headers.get('cloudflare-cdn-cache-control'), 'no-store');
assert.equal(response.headers.get('surrogate-control'), 'no-store');
assert.match(svg, /今天是梁(?:子|圣)/);
});
test('worker supports HEAD and rejects state-changing methods', async () => {
const headResponse = createBadgeResponse('HEAD');
const postResponse = createBadgeResponse('POST');
assert.equal(headResponse.status, 200);
assert.equal(await headResponse.text(), '');
assert.equal(postResponse.status, 405);
assert.equal(postResponse.headers.get('allow'), 'GET, HEAD');
});

61
worker/random-badge.mjs Normal file
View file

@ -0,0 +1,61 @@
const BADGE_LABEL = '滑动变祖器';
const BADGE_VALUES = Object.freeze(['今天是梁子', '今天是梁圣']);
function secureRandom() {
const sample = new Uint32Array(1);
crypto.getRandomValues(sample);
return sample[0] / 0x1_0000_0000;
}
export function pickBadgeValue(random = secureRandom) {
const sample = random();
if (!Number.isFinite(sample) || sample < 0 || sample >= 1) {
throw new RangeError('Random samples must be finite numbers from 0 (inclusive) to 1 (exclusive).');
}
return BADGE_VALUES[Math.floor(sample * BADGE_VALUES.length)];
}
export function renderBadge(value) {
if (!BADGE_VALUES.includes(value)) {
throw new RangeError(`Unsupported badge value: ${value}`);
}
const accessibleLabel = `${BADGE_LABEL}: ${value}`;
return `<svg xmlns="http://www.w3.org/2000/svg" width="130" height="20" role="img" aria-label="${accessibleLabel}"><title>${accessibleLabel}</title><filter id="blur"><feGaussianBlur stdDeviation="16"/></filter><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="130" height="20" rx="3"/></clipPath><g clip-path="url(#r)"><rect width="65" height="20" fill="#555"/><rect x="65" width="65" height="20" fill="#f39c12"/><rect width="130" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><g transform="scale(.1)"><g aria-hidden="true" fill="#010101"><text x="335" y="150" fill-opacity=".8" filter="url(#blur)" textLength="550">${BADGE_LABEL}</text><text x="335" y="150" fill-opacity=".3" textLength="550">${BADGE_LABEL}</text></g><text x="335" y="140" textLength="550">${BADGE_LABEL}</text></g><g transform="scale(.1)"><g aria-hidden="true" fill="#010101"><text x="965" y="150" fill-opacity=".8" filter="url(#blur)" textLength="550">${value}</text><text x="965" y="150" fill-opacity=".3" textLength="550">${value}</text></g><text x="965" y="140" textLength="550">${value}</text></g></g></svg>`;
}
const NO_CACHE_HEADERS = {
'Cache-Control': 'no-store, no-cache, must-revalidate, max-age=0',
'CDN-Cache-Control': 'no-store',
'Cloudflare-CDN-Cache-Control': 'no-store',
'Content-Type': 'image/svg+xml; charset=utf-8',
Expires: '0',
Pragma: 'no-cache',
'Surrogate-Control': 'no-store',
'X-Content-Type-Options': 'nosniff',
};
export function createBadgeResponse(method = 'GET') {
if (method !== 'GET' && method !== 'HEAD') {
return new Response('Method Not Allowed', {
status: 405,
headers: {
...NO_CACHE_HEADERS,
Allow: 'GET, HEAD',
'Content-Type': 'text/plain; charset=utf-8',
},
});
}
const body = method === 'HEAD' ? null : renderBadge(pickBadgeValue());
return new Response(body, { headers: NO_CACHE_HEADERS });
}
export default {
fetch(request) {
return createBadgeResponse(request.method);
},
};

8
wrangler.jsonc Normal file
View file

@ -0,0 +1,8 @@
{
"$schema": "https://raw.githubusercontent.com/cloudflare/workers-sdk/main/packages/wrangler/config-schema.json",
"name": "dsh-im-random-badge",
"main": "worker/random-badge.mjs",
"compatibility_date": "2026-08-18",
"workers_dev": true,
"preview_urls": false
}