Verified visits (7th ad format): guaranteed unique human-visit packs
- Buy N verified visits flat up-front; each is a distinct member, dwell + captcha verified - Verified visits earn sub-tab: open site (new tab), dwell, human-check, earn - Per-viewer dedup (visit_seen unique), daily cap, completes at N; single-use tokens Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -35,6 +35,7 @@ fs.mkdirSync(UPLOADS_DIR, { recursive: true });
|
||||
const uploadCounts = new Map(); // email:day -> uploads today
|
||||
const gauntletTokens = new Map(); // email -> welcome-tour token (server-clock dwell floor)
|
||||
const videoTokens = new Map(); // email -> watch-to-earn video token (server-clock watch floor)
|
||||
const visitTokens = new Map(); // email -> verified-visit token (dwell + captcha floor)
|
||||
// walk the referral chain upward via sponsorRef (code/username/member id)
|
||||
async function uplineSlides(email, depth = 3) {
|
||||
const out = [];
|
||||
@@ -767,6 +768,48 @@ const server = http.createServer(async (req, res) => {
|
||||
const status = await ads.recordVideoWatch(s.email);
|
||||
return json(res, 200, { ok: true, credited: tier.reward, status });
|
||||
}
|
||||
// -- verified visits: view a member's site (new tab) for the dwell, pass a
|
||||
// human check, and it counts as one guaranteed unique visit for the pack
|
||||
if (p === '/api/my/visits' && req.method === 'GET') {
|
||||
const s = await auth.fromRequest(req);
|
||||
if (!s || !s.email) return json(res, 401, { error: 'Sign in first.' });
|
||||
const status = await ads.visitStatus(s.email);
|
||||
if (status.count >= status.cap) return json(res, 200, { ad: null, status });
|
||||
const ad = await ads.serveVisit(s.email);
|
||||
if (!ad) return json(res, 200, { ad: null, status });
|
||||
const token = crypto.randomBytes(16).toString('hex');
|
||||
visitTokens.set(s.email, { token, ts: Date.now(), id: ad.id });
|
||||
return json(res, 200, { ad, token, status });
|
||||
}
|
||||
if (p === '/api/my/visitchallenge' && req.method === 'GET') {
|
||||
const s = await auth.fromRequest(req);
|
||||
if (!s || !s.email) return json(res, 401, { error: 'Sign in first.' });
|
||||
const t = visitTokens.get(s.email);
|
||||
if (!t || t.token !== String(u.searchParams.get('token') || '')) return json(res, 400, { error: 'That visit is no longer open.' });
|
||||
const dwellMs = (ads.rates().visitDwellSeconds || 8) * 1000;
|
||||
const age = Date.now() - t.ts;
|
||||
if (age < dwellMs - 400) return json(res, 200, { early: true, wait: Math.ceil((dwellMs - age) / 1000) });
|
||||
if (age > 5 * 60 * 1000) { visitTokens.delete(s.email); return json(res, 400, { error: 'That visit went stale. Load a fresh one.' }); }
|
||||
const pick = CAPTCHA.slice().sort(() => Math.random() - 0.5).slice(0, 5);
|
||||
const answer = Math.floor(Math.random() * pick.length);
|
||||
t.challenge = { answer };
|
||||
return json(res, 200, { prompt: pick[answer][1], options: pick.map(x => x[0]) });
|
||||
}
|
||||
if (p === '/api/my/visitdone' && req.method === 'POST') {
|
||||
const s = await auth.fromRequest(req);
|
||||
if (!s || !s.email) return json(res, 401, { error: 'Sign in first.' });
|
||||
const b = await readBody(req);
|
||||
const t = visitTokens.get(s.email);
|
||||
if (!t || t.token !== String(b.token || '')) return json(res, 400, { error: 'That visit did not check out. Load the next one.' });
|
||||
const dwellMs = (ads.rates().visitDwellSeconds || 8) * 1000;
|
||||
if (Date.now() - t.ts < dwellMs - 400) return json(res, 400, { error: 'Give the site the full visit first.' });
|
||||
if (!t.challenge) return json(res, 400, { error: 'Finish the quick check first.', retry: true });
|
||||
if (Number(b.answer) !== t.challenge.answer) { t.challenge = null; return json(res, 400, { error: 'Wrong pick.', retry: true }); }
|
||||
visitTokens.delete(s.email);
|
||||
const r = await ads.completeVisit(s.email, t.id);
|
||||
if (r.error) return json(res, 400, r);
|
||||
return json(res, 200, Object.assign(r, { status: await ads.visitStatus(s.email) }));
|
||||
}
|
||||
// -- onsite solo ads: member inbox with read rewards
|
||||
if (p === '/api/my/inbox' && req.method === 'GET') {
|
||||
const s = await auth.fromRequest(req);
|
||||
|
||||
Reference in New Issue
Block a user