Sponsor pre-check alert: only the checkout call may alert (the dashboard's display-only call never does), and the alert says what it is: a heads-up before the sale, nothing paid yet
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+2
-2
@@ -14,7 +14,7 @@
|
|||||||
// if they arrived through a sponsor's link, show who they're joining under
|
// if they arrived through a sponsor's link, show who they're joining under
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
const sp = await (await fetch('/api/sponsor')).json();
|
const sp = await (await fetch('/api/sponsor?intent=view')).json(); // display only: never an alert
|
||||||
if (sp && sp.invited && sp.name && $('sponsorNote')) { $('sponsorNoteName').textContent = sp.name; $('sponsorNote').hidden = false; }
|
if (sp && sp.invited && sp.name && $('sponsorNote')) { $('sponsorNoteName').textContent = sp.name; $('sponsorNote').hidden = false; }
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
})();
|
})();
|
||||||
@@ -2217,7 +2217,7 @@
|
|||||||
}
|
}
|
||||||
if (cur !== wantAddr) throw new Error('Your wallet connected as ' + cur.slice(0, 6) + '…' + cur.slice(-4) + ' but you chose ' + wantAddr.slice(0, 6) + '…' + wantAddr.slice(-4) + '. Switch accounts in your wallet app and try again.');
|
if (cur !== wantAddr) throw new Error('Your wallet connected as ' + cur.slice(0, 6) + '…' + cur.slice(-4) + ' but you chose ' + wantAddr.slice(0, 6) + '…' + wantAddr.slice(-4) + '. Switch accounts in your wallet app and try again.');
|
||||||
}
|
}
|
||||||
const spNow = fromPos ? { sponsorId: meNow.memberId } : await jretry('/api/sponsor');
|
const spNow = fromPos ? { sponsorId: meNow.memberId } : await jretry('/api/sponsor?intent=buy');
|
||||||
if (!fromPos && !meNow.memberId && spNow.sponsorBlocked) { IAP.status(sponsorHoldText(spNow), 'bad'); return; } // first activation must not hand a sponsored member to the company
|
if (!fromPos && !meNow.memberId && spNow.sponsorBlocked) { IAP.status(sponsorHoldText(spNow), 'bad'); return; } // first activation must not hand a sponsored member to the company
|
||||||
if (!fromPos && !meNow.memberId && spNow.sponsorRouted) IAP.status((spNow.sponsorRouted.from || 'Your sponsor') + ' has not switched on payouts, so this purchase credits ' + spNow.sponsorRouted.to + ' instead. You are not held up; carrying on.', 'ok');
|
if (!fromPos && !meNow.memberId && spNow.sponsorRouted) IAP.status((spNow.sponsorRouted.from || 'Your sponsor') + ' has not switched on payouts, so this purchase credits ' + spNow.sponsorRouted.to + ' instead. You are not held up; carrying on.', 'ok');
|
||||||
// pre-flight: stop early if the POL is not there. Trust Wallet also hard-blocks any
|
// pre-flight: stop early if the POL is not there. Trust Wallet also hard-blocks any
|
||||||
|
|||||||
+1
-1
@@ -1070,7 +1070,7 @@
|
|||||||
<script src="/assets/common.js?v=20260916a"></script>
|
<script src="/assets/common.js?v=20260916a"></script>
|
||||||
<script src="/assets/wallet.js?v=20260911a"></script>
|
<script src="/assets/wallet.js?v=20260911a"></script>
|
||||||
<script src="/assets/promo.js?v=20260921d"></script>
|
<script src="/assets/promo.js?v=20260921d"></script>
|
||||||
<script src="/assets/my.js?v=20260924c"></script>
|
<script src="/assets/my.js?v=20260924d"></script>
|
||||||
<script src="/assets/chat.js?v=20260907l"></script>
|
<script src="/assets/chat.js?v=20260907l"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -760,11 +760,12 @@ function fraudAlert(email, fc, spAcct, blocked) {
|
|||||||
const sponsorRoutedLast = new Map(); // buyer email -> ts (one alert per buyer per hour)
|
const sponsorRoutedLast = new Map(); // buyer email -> ts (one alert per buyer per hour)
|
||||||
function sponsorRoutedAlert(who, spd, routed, skipped) {
|
function sponsorRoutedAlert(who, spd, routed, skipped) {
|
||||||
const k = String(who || '?'); if (Date.now() - (sponsorRoutedLast.get(k) || 0) < 3600000) return; sponsorRoutedLast.set(k, Date.now());
|
const k = String(who || '?'); if (Date.now() - (sponsorRoutedLast.get(k) || 0) < 3600000) return; sponsorRoutedLast.set(k, Date.now());
|
||||||
const text = '\u2934\uFE0F InstantAdPay: purchase by ' + k.replace(/^(.{2}).*(@.*)$/, '$1***$2') + ' routed past ' + (spd.name || '?')
|
const text = '\u2934\uFE0F InstantAdPay heads-up: ' + k.replace(/^(.{2}).*(@.*)$/, '$1***$2') + ' is at checkout. Their sponsor ' + (spd.name || '?')
|
||||||
+ ' (payouts not switched on) to ' + routed.to + '. The buyer was not held up.' + (skipped.length > 1 ? ' Skipped: ' + skipped.map(x => x.name).join(', ') + '.' : '');
|
+ ' has not switched on payouts, so if this purchase goes through it pays ' + routed.to + ' instead.' + (skipped.length > 1 ? ' Also skipped: ' + skipped.map(x => x.name).join(', ') + '.' : '')
|
||||||
|
+ ' Nothing has been paid yet; the on-chain result posts to Telegram when the sale settles.';
|
||||||
const sc = siteConfig();
|
const sc = siteConfig();
|
||||||
if (sc.telegramBotToken && sc.telegramAdminChatId) telegramSend(sc.telegramAdminChatId, text).catch(() => {});
|
if (sc.telegramBotToken && sc.telegramAdminChatId) telegramSend(sc.telegramAdminChatId, text).catch(() => {});
|
||||||
else if (ADMIN_EMAIL && mailer.hasKey()) mailer.send(ADMIN_EMAIL, 'InstantAdPay: purchase routed past an unactivated sponsor', text).catch(() => {});
|
else if (ADMIN_EMAIL && mailer.hasKey()) mailer.send(ADMIN_EMAIL, 'InstantAdPay heads-up: a checkout will route past an unactivated sponsor', text).catch(() => {});
|
||||||
// the skipped sponsor and the one who gains are told by sponsorSyncOnEvent, once the position exists on the chain
|
// the skipped sponsor and the one who gains are told by sponsorSyncOnEvent, once the position exists on the chain
|
||||||
}
|
}
|
||||||
const sponsorAlertLast = new Map(); // email -> ts (one alert per member per hour)
|
const sponsorAlertLast = new Map(); // email -> ts (one alert per member per hour)
|
||||||
@@ -1267,9 +1268,9 @@ const server = http.createServer(async (req, res) => {
|
|||||||
const catchId = Number(siteConfig().defaultSponsorId) || 1;
|
const catchId = Number(siteConfig().defaultSponsorId) || 1;
|
||||||
sponsorId = w.id;
|
sponsorId = w.id;
|
||||||
sponsorRouted = { from: spd.name || null, to: w.id ? w.name : 'the company (#' + catchId + ')', toId: w.id || catchId, skipped: w.skipped.map(x => x.name) };
|
sponsorRouted = { from: spd.name || null, to: w.id ? w.name : 'the company (#' + catchId + ')', toId: w.id || catchId, skipped: w.skipped.map(x => x.name) };
|
||||||
sponsorRoutedAlert(acct.email, spd, sponsorRouted, w.skipped);
|
if (u.searchParams.get('intent') === 'buy') sponsorRoutedAlert(acct.email, spd, sponsorRouted, w.skipped); // the dashboard's display-only pre-check never alerts (Marty, 2026-09-21)
|
||||||
}
|
}
|
||||||
} else if (acct && acct.sponsorRef && !sponsorId && spd.reason !== 'none') { sponsorBlocked = spd.reason; sponsorBlockedAlert(acct.email, Object.assign({ tok }, spd)); }
|
} else if (acct && acct.sponsorRef && !sponsorId && spd.reason !== 'none') { sponsorBlocked = spd.reason; if (u.searchParams.get('intent') === 'buy') sponsorBlockedAlert(acct.email, Object.assign({ tok }, spd)); }
|
||||||
if (sponsorId && await payoutChainBlocked(sponsorId, 2)) { console.log('sponsor routed away from no-payout chain', sponsorId); sponsorId = 0; }
|
if (sponsorId && await payoutChainBlocked(sponsorId, 2)) { console.log('sponsor routed away from no-payout chain', sponsorId); sponsorId = 0; }
|
||||||
// orphan fallback: an unresolvable/absent sponsor (dead link, no link) lands
|
// orphan fallback: an unresolvable/absent sponsor (dead link, no link) lands
|
||||||
// the new member under the configured catch position (#1) instead of root
|
// the new member under the configured catch position (#1) instead of root
|
||||||
|
|||||||
Reference in New Issue
Block a user