From 12b67b4ba99fd1d0604bc41380add286550fc540 Mon Sep 17 00:00:00 2001 From: vimtor Date: Tue, 19 May 2026 11:08:59 +0200 Subject: [PATCH] core: keep Go referral links crediting new signups --- .../console/app/src/component/go-referral.tsx | 2 +- .../console/app/src/lib/referral-invite.ts | 22 +++++++++---------- packages/console/app/src/middleware.ts | 6 ++--- .../app/src/routes/auth/[...callback].ts | 10 ++++----- packages/console/app/src/routes/go/index.tsx | 9 ++++---- packages/console/core/src/referral.ts | 10 ++++----- 6 files changed, 30 insertions(+), 29 deletions(-) diff --git a/packages/console/app/src/component/go-referral.tsx b/packages/console/app/src/component/go-referral.tsx index 02db2b72da..bd93b6560a 100644 --- a/packages/console/app/src/component/go-referral.tsx +++ b/packages/console/app/src/component/go-referral.tsx @@ -81,7 +81,7 @@ function CopyInviteLink(props: { summary: GoReferralSummary }) { ? window.location.origin : undefined const inviteUrl = createMemo(() => { - const path = `/go?ref=${props.summary.inviteCode}` + const path = `/go?ref=${props.summary.referralCode}` if (!origin) return path return new URL(path, origin).toString() }) diff --git a/packages/console/app/src/lib/referral-invite.ts b/packages/console/app/src/lib/referral-invite.ts index 40ff81af58..b17a0fc3c5 100644 --- a/packages/console/app/src/lib/referral-invite.ts +++ b/packages/console/app/src/lib/referral-invite.ts @@ -1,28 +1,28 @@ import { Referral } from "@opencode-ai/console-core/referral.js" -const INVITE_COOKIE = "oc_referral" -const INVITE_MAX_AGE = 60 * 60 * 24 * 30 +const REFERRAL_COOKIE = "oc_referral" +const REFERRAL_MAX_AGE = 60 * 60 * 24 * 30 -export function normalizeInviteCode(code?: string | null) { +export function normalizeReferralCode(code?: string | null) { return Referral.normalizeCode(code) } -export function inviteCookie(code: string) { - return `${INVITE_COOKIE}=${encodeURIComponent(code)}; Path=/; Max-Age=${INVITE_MAX_AGE}; SameSite=Lax; HttpOnly` +export function referralCookie(code: string) { + return `${REFERRAL_COOKIE}=${encodeURIComponent(code)}; Path=/; Max-Age=${REFERRAL_MAX_AGE}; SameSite=Lax; HttpOnly` } -export function clearInviteCookie() { - return `${INVITE_COOKIE}=; Path=/; Max-Age=0; SameSite=Lax; HttpOnly` +export function clearReferralCookie() { + return `${REFERRAL_COOKIE}=; Path=/; Max-Age=0; SameSite=Lax; HttpOnly` } -export function inviteFromCookieHeader(header: string | null) { +export function referralCodeFromCookieHeader(header: string | null) { if (!header) return undefined - return normalizeInviteCode( + return normalizeReferralCode( header .split(";") .map((x) => x.trim()) - .find((x) => x.startsWith(`${INVITE_COOKIE}=`)) - ?.slice(`${INVITE_COOKIE}=`.length), + .find((x) => x.startsWith(`${REFERRAL_COOKIE}=`)) + ?.slice(`${REFERRAL_COOKIE}=`.length), ) } diff --git a/packages/console/app/src/middleware.ts b/packages/console/app/src/middleware.ts index b04b5f61da..ad5aa09e2a 100644 --- a/packages/console/app/src/middleware.ts +++ b/packages/console/app/src/middleware.ts @@ -1,6 +1,6 @@ import { createMiddleware } from "@solidjs/start/middleware" import { LOCALE_HEADER, cookie, fromPathname, strip } from "~/lib/language" -import { inviteCookie, normalizeInviteCode } from "~/lib/referral-invite" +import { normalizeReferralCode, referralCookie } from "~/lib/referral-invite" export default createMiddleware({ onRequest(event) { @@ -14,7 +14,7 @@ export default createMiddleware({ event.response.headers.append("set-cookie", cookie(locale)) } - const inviteCode = normalizeInviteCode(url.searchParams.get("ref")) - if (inviteCode) event.response.headers.append("set-cookie", inviteCookie(inviteCode)) + const referralCode = normalizeReferralCode(url.searchParams.get("ref")) + if (referralCode) event.response.headers.append("set-cookie", referralCookie(referralCode)) }, }) diff --git a/packages/console/app/src/routes/auth/[...callback].ts b/packages/console/app/src/routes/auth/[...callback].ts index c2f6263242..b1b942ee72 100644 --- a/packages/console/app/src/routes/auth/[...callback].ts +++ b/packages/console/app/src/routes/auth/[...callback].ts @@ -5,7 +5,7 @@ import { AuthClient } from "~/context/auth" import { useAuthSession } from "~/context/auth" import { i18n } from "~/i18n" import { localeFromRequest, route } from "~/lib/language" -import { clearInviteCookie, inviteFromCookieHeader } from "~/lib/referral-invite" +import { clearReferralCookie, referralCodeFromCookieHeader } from "~/lib/referral-invite" export async function GET(input: APIEvent) { const url = new URL(input.request.url) @@ -19,7 +19,7 @@ export async function GET(input: APIEvent) { if (result.err) throw new Error(result.err.message) const decoded = AuthClient.decode(result.tokens.access, {} as any) if (decoded.err) throw new Error(decoded.err.message) - const inviteCode = inviteFromCookieHeader(input.request.headers.get("cookie")) + const referralCode = referralCodeFromCookieHeader(input.request.headers.get("cookie")) const session = await useAuthSession() const id = decoded.subject.properties.accountID await session.update((value) => { @@ -35,14 +35,14 @@ export async function GET(input: APIEvent) { current: id, } }) - if (decoded.subject.properties.newAccount && inviteCode) { - await Referral.createFromAccount({ accountID: id, inviteCode }).catch((error) => { + if (decoded.subject.properties.newAccount && referralCode) { + await Referral.createFromAccount({ accountID: id, referralCode }).catch((error) => { console.error("Referral create failed", error) }) } const next = url.pathname === "/auth/callback" ? "/auth" : url.pathname.replace("/auth/callback", "") const response = redirect(route(locale, next)) - if (inviteCode) response.headers.append("set-cookie", clearInviteCookie()) + if (referralCode) response.headers.append("set-cookie", clearReferralCookie()) return response } catch (e: any) { return new Response( diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index c9359e71ef..373a2b4053 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -226,11 +226,12 @@ function LimitsGraph(props: { href: string }) { export default function Home() { const location = useLocation() const workspaceID = createAsync(() => checkLoggedIn()) - const inviteCode = createMemo(() => new URLSearchParams(location.search).get("ref") ?? undefined) + const referralCode = createMemo(() => new URLSearchParams(location.search).get("ref") ?? undefined) const subscribeUrl = createMemo(() => { - const invite = inviteCode() ? `?ref=${encodeURIComponent(inviteCode()!)}` : "" - if (workspaceID()) return `/workspace/${workspaceID()}/go${invite}` - return `/auth${invite}` + const code = referralCode() + const referral = code ? `?ref=${encodeURIComponent(code)}` : "" + if (workspaceID()) return `/workspace/${workspaceID()}/go${referral}` + return `/auth${referral}` }) const i18n = useI18n() const language = useLanguage() diff --git a/packages/console/core/src/referral.ts b/packages/console/core/src/referral.ts index b3b4c2d778..3d49ae1425 100644 --- a/packages/console/core/src/referral.ts +++ b/packages/console/core/src/referral.ts @@ -153,7 +153,7 @@ export namespace Referral { (a, b) => new Date(b.timeCreated).getTime() - new Date(a.timeCreated).getTime(), ) return { - inviteCode: code.code, + referralCode: code.code, inviteCount: allRewards.length, hasActiveGo: !!rows.lite, rewardAmount: microCentsToCents(REWARD_AMOUNT), @@ -279,16 +279,16 @@ export namespace Referral { export async function createFromAccount(input: { accountID: string - inviteCode?: string + referralCode?: string }) { - const inviteCode = normalizeCode(input.inviteCode) - if (!inviteCode) return { status: "missing-code" as const } + const referralCode = normalizeCode(input.referralCode) + if (!referralCode) return { status: "missing-code" as const } return Database.transaction(async (tx) => { const code = await tx .select({ workspaceID: WorkspaceTable.id }) .from(WorkspaceTable) - .where(and(eq(WorkspaceTable.referralCode, inviteCode), isNull(WorkspaceTable.timeDeleted))) + .where(and(eq(WorkspaceTable.referralCode, referralCode), isNull(WorkspaceTable.timeDeleted))) .then((rows) => rows[0]) if (!code) return { status: "invalid-code" as const }