Social layer: leaderboard (week/month/all) + six badges, /leaders and /promo pages, share panel and rank on the board, ?r= referral cookie -> member's IAP join link, OG tags, banner set served through the curtain

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-19 19:40:50 -05:00
parent cdded9d4ed
commit dd6a3a3bfa
19 changed files with 304 additions and 11 deletions
+10
View File
@@ -77,6 +77,16 @@ const sleep = ms => new Promise(r => setTimeout(r, ms));
const rewards = require('../lib/rewards'); const draws = Array.from({ length: 4000 }, () => rewards.draw(0.05, 1));
const median = draws.sort((x, y) => x - y)[2000]; eq([draws.every(d => d >= 0.05 && d <= 1), median < 0.35], [true, true], 'the draw stays in range and its median sits low (' + median + ')');
// social: the find is on the leaderboard with a badge, the board carries rank and a share link,
// and a share link visit sets the referral cookie that turns sign-ups into that member's IAP join link
const lb = await call('/api/leaders?period=all'); eq([lb.status, lb.body.rows.length >= 1, lb.body.rows[0].memberId, lb.body.rows[0].finds >= 1, lb.body.rows[0].badges.length >= 1], [200, true, 42, true, true], 'leaderboard: hunter 42 leads all time with a badge');
const bd = await call('/api/badges'); eq(bd.body.badges.length, 6, 'six badges are defined');
const b3 = await call('/api/my/board'); eq([b3.body.badges.some(b => b.id === 'first'), b3.body.rank.all.rank, b3.body.share.link], [true, 1, B + '/?r=hunter42'], 'board: First Find badge, rank #1, share link carries the username');
const rv = await fetch(B + '/?r=hunter42', { redirect: 'manual' }); eq([rv.status, /ph\.ref=hunter42/.test(rv.headers.get('set-cookie') || ''), rv.headers.get('location')], [302, true, '/'], 'a share-link visit sets the referral cookie and lands on the landing');
const cf = await (await fetch(B + '/api/config', { headers: { Cookie: 'ph.ref=hunter42' } })).json(); eq([cf.ref, cf.joinUrl], ['hunter42', 'https://instantadpay.com/join/hunter42?from=polhunter'], 'with the cookie, sign-ups go to that member\u2019s IAP join link');
const badRef = await fetch(B + '/?r=<script>', { redirect: 'manual' }); eq(/ph\.ref/.test(badRef.headers.get('set-cookie') || ''), false, 'a malformed ref sets no cookie');
for (const pg of ['/leaders', '/promo']) { const r = await fetch(B + pg); eq([r.status, /<title>/.test(await r.text())], [200, true], pg + ' serves'); }
// nothing outward: no telegram env, no faucet env
const led = await call('/api/ledger'); eq(led.body.totals.paid, 0, 'nothing has been paid, because no faucet is configured');