Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions apps/website/qa/traffic-arrival-contract.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// once, untagged visits never, and a failure never reaches the page.
// Run: node --experimental-strip-types qa/traffic-arrival-contract.mjs
import assert from 'node:assert/strict'
import { arrivalFromSearch, reportArrival, ARRIVAL_URL } from '../src/lib/trafficArrival.ts'
import { arrivalFromSearch, reportArrival, ARRIVAL_URL, carrySource, SOURCE_KEY } from '../src/lib/trafficArrival.ts'

// The form the agents publish: the query BEFORE the hash route.
const blog = new URL('https://t27.ai/?utm_source=x&utm_medium=social&utm_campaign=blog&utm_content=gf-t#/blog/gf-t')
Expand All @@ -26,4 +26,16 @@ assert.deepEqual(calls, [[ARRIVAL_URL, { source: 'reddit' }]])
const failing = async () => { throw new Error('offline') }
assert.equal(await reportArrival('?utm_source=threads', failing, { getItem: () => null, setItem: () => {} }), false)

console.log('traffic-arrival contract: 9 checks passed')
// The channel rides on into the bot: remembered at the arrival...
assert.equal(store.get(SOURCE_KEY), 'reddit', 'the visit remembers its channel')
// ...and put at the end of OUR bot's /start payload, the way the bot reads it.
assert.equal(carrySource('https://t.me/t27ai_bot?start=website', 'x'), 'https://t.me/t27ai_bot?start=website__x')
assert.equal(carrySource('https://t.me/t27ai_bot?start=foundry', 'Reddit'), 'https://t.me/t27ai_bot?start=foundry__reddit')
assert.equal(carrySource('https://t.me/other_bot?start=website', 'x'), 'https://t.me/other_bot?start=website', 'never somebody else\'s bot')
assert.equal(carrySource('https://t.me/t27_lang', 'x'), 'https://t.me/t27_lang', 'a channel link is not a bot start')
assert.equal(carrySource('https://t.me/t27ai_bot?start=website__x', 'reddit'), 'https://t.me/t27ai_bot?start=website__x', 'a channel already there stays')
assert.equal(carrySource('https://t.me/t27ai_bot?start=website', null), 'https://t.me/t27ai_bot?start=website', 'no channel, no tag')
const long = 'a'.repeat(62) // + '__x' = 65 > 64
assert.equal(carrySource(`https://t.me/t27ai_bot?start=${long}`, 'x'), `https://t.me/t27ai_bot?start=${long}`, 'never past 64 characters')

console.log('traffic-arrival contract: 16 checks passed')
2 changes: 1 addition & 1 deletion apps/website/src/components/QueenLanes.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
min-height: 0;
height: 100%;
border: 1px solid var(--hud-line, rgba(0, 255, 136, 0.22));
background: var(--hud-panel, rgba(2, 8, 6, 0.86));
background: var(--hud-panel, rgba(2, 8, 6, 0.88));
clip-path: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
}

Expand Down
68 changes: 68 additions & 0 deletions apps/website/src/lib/trafficArrival.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ export async function reportArrival(
): Promise<boolean> {
const tags = arrivalFromSearch(search)
if (!tags) return false
try {
// The channel of this visit, for the links into our bot (carrySource).
if (!storage?.getItem(SOURCE_KEY)) storage?.setItem(SOURCE_KEY, tags.source)
} catch {
/* no storage: the bot link goes untagged */
}
try {
if (storage?.getItem(ONCE_KEY)) return false
storage?.setItem(ONCE_KEY, '1')
Expand All @@ -69,3 +75,65 @@ export async function reportArrival(
return false
}
}

/*
* THE CHANNEL RIDES ON INTO THE BOT (owner, 2026-09-26: "end-to-end
* conversion from t27.ai").
*
* A visitor from X who presses "open in Telegram" used to reach the bot as
* nobody from nowhere: the visit was counted, the start was not tied to it.
* The bot reads the channel at the end of its /start payload after `__`
* (999-multibots-telegraf src/navigation/helpers/appLinks.ts
* splitStartSource) and counts the start by channel; this puts it there, at
* the moment of the click, for OUR bot's links only, never past Telegram's
* 64 characters, never over a channel already in the link.
*/
export const SOURCE_KEY = 'traffic:source'
export const OUR_BOTS = ['t27ai_bot']
const START_MAX = 64

/** The bot link carrying this visit's channel; anything else as given. Pure. */
export function carrySource(href: string, source: string | null): string {
const tag = String(source ?? '')
.toLowerCase()
.replace(/[^a-z0-9-]+/g, '-')
.replace(/^-+|-+$/g, '')
.slice(0, 32)
if (!tag) return href
let u: URL
try {
u = new URL(href)
} catch {
return href
}
if (!['t.me', 'telegram.me'].includes(u.hostname.toLowerCase())) return href
if (!OUR_BOTS.includes(u.pathname.replace(/^\//, '').toLowerCase())) return href
const start = u.searchParams.get('start')
if (!start || start.includes('__')) return href
const next = `${start}__${tag}`
if (next.length > START_MAX || !/^[A-Za-z0-9_-]+$/.test(next)) return href
u.searchParams.set('start', next)
return u.toString()
}

/** Tag our bot links as they are pressed. Never throws, never blocks a click. */
export function installBotLinkCarry(
doc: Pick<Document, 'addEventListener'> | null = typeof document !== 'undefined' ? document : null,
storage: Pick<Storage, 'getItem'> | null = typeof sessionStorage !== 'undefined'
? sessionStorage
: null
): void {
if (!doc) return
const tag = (e: Event) => {
try {
const a = (e.target as Element | null)?.closest?.('a[href]') as HTMLAnchorElement | null
if (!a) return
const next = carrySource(a.href, storage?.getItem(SOURCE_KEY) ?? null)
if (next !== a.href) a.href = next
} catch {
/* a link stays as it was */
}
}
doc.addEventListener('click', tag, true)
doc.addEventListener('auxclick', tag, true)
}
7 changes: 5 additions & 2 deletions apps/website/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import GlobalStarfield from './components/GlobalStarfield.tsx'
import { handExplorerLinksToQueen } from './lib/queenFrame'
import { redirectLegacyQueen } from './lib/legacyQueenRedirect'
import { triIdentity } from './lib/triIdentity'
import { reportArrival } from './lib/trafficArrival'
import { installBotLinkCarry, reportArrival } from './lib/trafficArrival'

// THE QUEEN MOVED to https://app.t27.ai/queen/, which now builds this same
// bundle and serves the board on the app's own origin. #/queen here is the old
Expand All @@ -31,7 +31,10 @@ const leaving = redirectLegacyQueen()
// A visitor from a tagged link (utm_source=x, reddit, threads...) is counted
// once, by channel, where the agents' links land. Not for a page that is on
// its way to another address. See src/lib/trafficArrival.ts.
if (!leaving) void reportArrival()
if (!leaving) {
void reportArrival()
installBotLinkCarry()
}

// In a Queen tab's frame, a link to another Explorer switches the Queen's tab instead
// of navigating the frame under a rail that names a different one.
Expand Down
Loading