diff options
| author | Adam Soltys <[email protected]> | 2026-10-01 06:55:14 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-10-01 06:55:14 -0700 |
| commit | 5d441ebbce6066c3636168ec5332ae9c2bdb8607 (patch) | |
| tree | 7e70c783fc0be40eccb09af7499db586c5410526 /tools/public-feed-cache-test.js | |
| parent | 981ff1c7f89b27ff3d7c2957e211365baff0a359 (diff) | |
| download | coinosv3-5d441ebbce6066c3636168ec5332ae9c2bdb8607.tar.gz coinosv3-5d441ebbce6066c3636168ec5332ae9c2bdb8607.zip | |
Serve a shared snapshot for the public feed
Build the default Popular feed once on the server and let browsers verify and paint its signed events before slow media finishes. Keep custom relays, pagination, filtering, and relay fallback on their existing paths.\n\nAdd stale-while-refresh persistence, service-worker bypass, development integration, and unit/browser coverage.
Diffstat (limited to 'tools/public-feed-cache-test.js')
| -rw-r--r-- | tools/public-feed-cache-test.js | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/tools/public-feed-cache-test.js b/tools/public-feed-cache-test.js new file mode 100644 index 0000000..77f833a --- /dev/null +++ b/tools/public-feed-cache-test.js @@ -0,0 +1,50 @@ +import assert from 'node:assert/strict'; +import { buildSnapshot, createSnapshotCache, snapshotResponse } from '../feed/cache.js'; +import { popularCandidates } from '../src/popular-feed.js'; +const id = 'a'.repeat(64), author = 'b'.repeat(64); +const reaction = (pk, kind = 7, tags = []) => ({ kind, pubkey: pk, created_at: 100, tags: [['e', id], ...tags] }); +const post = { kind: 1, id, pubkey: author, created_at: 90, content: 'This is a post about the things we build together.', tags: [] }; +assert.equal(popularCandidates([reaction('c'), reaction('c')]).ids.length, 0); +assert.equal(popularCandidates([reaction(author), reaction('c')]).qualifies(post), false); +assert.equal(popularCandidates([reaction('c'), reaction('d')]).qualifies(post), true); +assert.equal(popularCandidates([reaction('zap-service', 9735, [['P', 'c']]), reaction('c')]).ids.length, 0); +const snapshot = await buildSnapshot(async (filter) => { + if (filter.ids) return [post, post]; + if (filter.kinds[0] === 0) return [{ kind: 0, pubkey: author, created_at: 1, content: '{}' }, { kind: 0, pubkey: author, created_at: 2, content: '{}' }]; + return [reaction('c'), reaction('d')]; +}, () => 1000); +assert.equal(snapshot.notes.length, 1); +assert.equal(snapshot.profiles[0].created_at, 2); +assert.equal(snapshot.popUntil, 100); +await assert.rejects(buildSnapshot(async () => []), /No public posts/); +let time = 1000, builds = 0, finish; +const cache = createSnapshotCache({ now: () => time, build: () => { builds++; return new Promise((resolve) => { finish = resolve; }); } }); +const request = new Request('http://localhost/api/feed'); +assert.equal(snapshotResponse(cache, request).status, 503); +for (let i = 0; i < 100; i++) assert.equal(cache.read(), null); +await Promise.resolve(); +assert.equal(builds, 1, 'cold visitors share one build'); +finish(snapshot); +await cache.refresh(); +assert.equal(cache.read(), snapshot); +assert.equal(snapshotResponse(cache, request).status, 200); +assert.equal(snapshotResponse(cache, new Request(request, { method: 'POST' })).status, 405); +assert.equal(await snapshotResponse(cache, new Request(request, { method: 'HEAD' })).text(), ''); +time += 61_000; +for (let i = 0; i < 100; i++) assert.equal(cache.read(), snapshot); +await Promise.resolve(); +assert.equal(builds, 2, 'stale visitors share one background build'); +finish({ ...snapshot, generatedAt: time }); +await cache.refresh(); +assert.equal(cache.read().generatedAt, time); +let failures = 0; +const failing = createSnapshotCache({ initial: snapshot, now: () => time, build: async () => { failures++; throw Error('offline'); }, onError: () => {} }); +assert.equal(failing.read(), snapshot); +await failing.refresh(); +assert.equal(failing.read(), snapshot); +await failing.refresh(); +assert.equal(failures, 1, 'failed refreshes are throttled and preserve stale data'); +time += 86400_000; +assert.equal(failing.read(), null, 'expired snapshots are not served'); +await failing.refresh(); +console.log('✓ public feed selection, profiles, single flight, stale refresh, failure recovery, expiry and HTTP behavior'); |
