Milestone posts: a celebratory Telegram post the moment membership crosses 500 (then 1k, 2.5k, 5k, 10k), once per mark
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+37
-1
@@ -81,6 +81,7 @@ async function post() {
|
|||||||
|
|
||||||
// every 10 minutes: post once a day at or after snapshotHourUtc (a restart never double-posts)
|
// every 10 minutes: post once a day at or after snapshotHourUtc (a restart never double-posts)
|
||||||
async function tick() {
|
async function tick() {
|
||||||
|
try { await milestoneTick(); } catch (e) { console.error('milestone', e.message); }
|
||||||
const sc = X.siteConfig();
|
const sc = X.siteConfig();
|
||||||
if (String(sc.snapshotEnabled || '1') !== '1' || !sc.telegramBotToken) return;
|
if (String(sc.snapshotEnabled || '1') !== '1' || !sc.telegramBotToken) return;
|
||||||
const hour = Number(sc.snapshotHourUtc == null || sc.snapshotHourUtc === '' ? 14 : sc.snapshotHourUtc);
|
const hour = Number(sc.snapshotHourUtc == null || sc.snapshotHourUtc === '' ? 14 : sc.snapshotHourUtc);
|
||||||
@@ -92,4 +93,39 @@ async function tick() {
|
|||||||
|
|
||||||
async function preview() { const sc = X.siteConfig(); return compose(await gather(), sc.telegramCtaUrl); }
|
async function preview() { const sc = X.siteConfig(); return compose(await gather(), sc.telegramCtaUrl); }
|
||||||
|
|
||||||
module.exports = { init, gather, compose, post, tick, preview };
|
// ---- membership milestones (Marty, 2026-09-19): one celebratory post per mark, the moment it is crossed
|
||||||
|
const MILESTONES = [500, 1000, 2500, 5000, 10000];
|
||||||
|
function composeMilestone(mark, s, cta) {
|
||||||
|
const L = [];
|
||||||
|
L.push('\u{1F389} <b>' + n(mark) + ' members on InstantAdPay.</b>');
|
||||||
|
L.push(n(mark) + ' people have joined, and here is what that looks like right now: <b>' + n(s.wallets) + '</b> wallets linked, <b>' + n(s.payoutsOn) + '</b> with payouts switched on, <b>' + n(s.lifeBuys) + '</b> purchases, and <b>' + pol(s.lifePaidWei) + ' POL</b> paid to members in the same transactions the purchases came from. Every one of those payments is on the public ledger.');
|
||||||
|
L.push('Thank you to every member who brought someone in. That is the whole engine, and it is working.');
|
||||||
|
L.push('The next ' + n(mark) + ' start today.');
|
||||||
|
L.push('<a href="https://instantadpay.com/ledger">Live ledger</a>' + (cta ? ' \u00b7 <a href="' + cta + '">Join free</a>' : ''));
|
||||||
|
return L.join('\n\n');
|
||||||
|
}
|
||||||
|
async function memberCount() {
|
||||||
|
if (!(X.db && X.db.enabled())) return 0;
|
||||||
|
const r = await X.db.q('SELECT COUNT(*) n FROM accounts'); return Number((r[0] || {}).n || 0);
|
||||||
|
}
|
||||||
|
// runs from tick(): announce the highest newly crossed mark, once, whatever snapshotEnabled says
|
||||||
|
async function milestoneTick() {
|
||||||
|
const sc = X.siteConfig(); if (!sc.telegramBotToken) return null;
|
||||||
|
const st = state(); const done = st.milestones || {};
|
||||||
|
const count = await memberCount();
|
||||||
|
const due = MILESTONES.filter(m => count >= m && !done[m]);
|
||||||
|
if (!due.length) return null;
|
||||||
|
const mark = due[due.length - 1];
|
||||||
|
const text = composeMilestone(mark, await gather(), sc.telegramCtaUrl);
|
||||||
|
const targets = String(sc.snapshotTargets || 'feed,echo').split(',').map(x => x.trim());
|
||||||
|
let sent = 0;
|
||||||
|
if (targets.includes('feed') && sc.telegramChatId) { if (await X.send(sc.telegramChatId, text, sc.telegramTopicId)) sent++; }
|
||||||
|
if (targets.includes('echo') && sc.telegramEchoChatId) { if (await X.send(sc.telegramEchoChatId, text, sc.telegramEchoTopicId)) sent++; }
|
||||||
|
for (const m of due) done[m] = Date.now(); // lower marks crossed in the same jump are marked too, so they never post late
|
||||||
|
st.milestones = done; setState(st);
|
||||||
|
console.log('milestone posted', mark, 'members', count, 'sent', sent);
|
||||||
|
return { ok: true, mark, count, sent, text };
|
||||||
|
}
|
||||||
|
async function previewMilestone(mark) { const sc = X.siteConfig(); return composeMilestone(Number(mark) || 500, await gather(), sc.telegramCtaUrl); }
|
||||||
|
|
||||||
|
module.exports = { init, gather, compose, post, tick, preview, milestoneTick, previewMilestone, memberCount, MILESTONES };
|
||||||
|
|||||||
Reference in New Issue
Block a user