Files
zeekay ca39f476a7 beta: the portal sits on the pane, and every claim is one the server keeps
In the app the portal painted the site's page glow, an opaque slab, over
the pane's own fill, inset by the pane's padding. It takes `framed` now:
no glow, no window height, the pane's fill and scroll.

The dashboard counted points the server does not award (local actions,
+25 for asking for Alpha) and promised rewards nothing pays (48 spots, a
free week, 10% tokens back, +1 per $1, "Linked:" on every account). The
score is the server's `score` once it answers one; until then verified
points plus the referrals it counts. The copy states what scores:
+1 per signup, +20 per referral that pays, +1 per 100K tokens, +10 per
star, +1 per follow.

Claude-Session: https://claude.ai/code/session_017vrVus6PPBgP5YRzKV1iqW
2026-10-26 01:13:24 -07:00

289 lines
10 KiB
TypeScript

import { api } from '@hanzo/app/lib/api'
import { scope } from '@hanzo/app/lib/session'
import type { Program } from '@/components/beta/program'
/**
* Beta records, waitlist standing, ecosystem beta requests, and growth actions
* on hanzoai/cloud apps/marketing/beta.go:
*
* GET /v1/marketing/beta the person's record, requested betas, points, and waitlist rank
* PUT /v1/marketing/beta save program, questionnaire answers, and requested betas
* POST /v1/marketing/beta/request request access to specific feature-flagged ecosystem betas (or alpha)
* POST /v1/marketing/beta/actions record a verified GitHub repo star (+10 pts) or founder follow (+1 pt)
*/
export interface BetaAnswer {
id: string
question: string
answer: string[]
}
export interface BetaAction {
action: 'star' | 'follow'
target: string
points: number
at: string
}
export interface BetaStanding {
applied: boolean
program: Program
answers: BetaAnswer[]
betas: string[]
requested: Record<string, string>
github: string
points: number
/** The waitlist score (points plus referrals and tokens); the server's, absent until it answers one. */
score?: number
place: number
of: number
actions: BetaAction[]
lead: string
since: string
}
export const POINTS = {
star: 10,
follow: 1,
referralSignup: 1,
referralDollar: 1,
} as const
export const HANZO_REPOS = [
{ slug: 'hanzoai/dev', label: 'hanzoai/dev', desc: 'Autonomous coding agent for terminal & IDE' },
{ slug: 'hanzoai/ai', label: 'hanzoai/ai', desc: 'Hanzo AI SDK, router, and agent framework' },
{ slug: 'hanzoai/engine', label: 'hanzoai/engine', desc: 'High-performance CUDA & Metal inference engine' },
{ slug: 'hanzoai/cloud', label: 'hanzoai/cloud', desc: 'Sovereign AI cloud & unified backend' },
{ slug: 'hanzoai/mcp', label: 'hanzoai/mcp', desc: 'Model Context Protocol tools & browser extension' },
{ slug: 'hanzoai/ui', label: 'hanzoai/ui', desc: 'Multi-framework React, GUI & design system' },
] as const
export const HANZO_SOCIALS = [
{ kind: 'discord' as const, label: 'Discord', handle: 'discord.gg/XthHQQj', href: 'https://discord.gg/XthHQQj' },
{ kind: 'x' as const, label: 'X @hanzoai', handle: '@hanzoai', href: 'https://x.com/hanzoai' },
{ kind: 'github' as const, label: 'GitHub @hanzoai', handle: '@hanzoai', href: 'https://github.com/hanzoai' },
{ kind: 'linkedin' as const, label: 'LinkedIn', handle: 'hanzo-ai', href: 'https://linkedin.com/company/hanzo-ai' },
{ kind: 'facebook' as const, label: 'Facebook', handle: '@hanzoinc', href: 'https://facebook.com/hanzoinc' },
{ kind: 'youtube' as const, label: 'YouTube @HanzoAI', handle: '@HanzoAI', href: 'https://youtube.com/@HanzoAI' },
{ kind: 'bluesky' as const, label: 'Bluesky', handle: '@hanzoai.bsky.social', href: 'https://bsky.app/profile/hanzoai.bsky.social' },
{ kind: 'reddit' as const, label: 'Reddit r/HanzoAI', handle: 'r/HanzoAI', href: 'https://www.reddit.com/r/HanzoAI/' },
{ kind: 'tiktok' as const, label: 'TikTok @hanzoinc', handle: '@hanzoinc', href: 'https://www.tiktok.com/@hanzoinc' },
{ kind: 'instagram' as const, label: 'Instagram @hanzoinc', handle: '@hanzoinc', href: 'https://www.instagram.com/hanzoinc' },
] as const
/** The founders, as hanzo.ai/about names them: Antje Worring, CEO; Zach Kelling, founding CTO. */
export const HANZO_FOUNDERS = [
{
id: 'antje' as const,
name: 'Antje Worring',
role: 'CEO',
channels: [
{ kind: 'github' as const, label: 'GitHub @zooqueen', href: 'https://github.com/zooqueen' },
{ kind: 'linkedin' as const, label: 'LinkedIn', href: 'https://www.linkedin.com/in/antje-worring/' },
],
},
{
id: 'zach' as const,
name: 'Zach Kelling',
role: 'Founding CTO',
channels: [
{ kind: 'github' as const, label: 'GitHub @zeekay', href: 'https://github.com/zeekay' },
{ kind: 'x' as const, label: 'X @zeekay', href: 'https://x.com/zeekay' },
{ kind: 'linkedin' as const, label: 'LinkedIn', href: 'https://www.linkedin.com/in/zeekay/' },
],
},
] as const
/**
* Stored with `hz_` prefix (like `hz_ref` in referrals.ts) so `own(subject())`
* does not clear them when an anonymous visitor signs up or logs in.
*/
const LOCAL_BETAS_KEY = 'hz_beta_requested'
const LOCAL_GITHUB_KEY = 'hz_beta_github'
const LOCAL_ACTIONS_KEY = 'hz_beta_actions'
export function getLocalRequestedBetas(): string[] {
if (typeof window === 'undefined') return []
try {
const raw = JSON.parse(window.localStorage.getItem(LOCAL_BETAS_KEY) ?? '[]')
return Array.isArray(raw) ? raw.filter((x): x is string => typeof x === 'string') : []
} catch {
return []
}
}
export function setLocalRequestedBetas(ids: string[]): void {
if (typeof window === 'undefined') return
try {
const unique = Array.from(new Set(ids))
window.localStorage.setItem(LOCAL_BETAS_KEY, JSON.stringify(unique))
} catch {
/* ignore storage errors */
}
}
export function getLocalGithub(): string {
if (typeof window === 'undefined') return ''
try {
return window.localStorage.getItem(LOCAL_GITHUB_KEY) ?? ''
} catch {
return ''
}
}
export function setLocalGithub(gh: string): void {
if (typeof window === 'undefined') return
try {
if (gh) window.localStorage.setItem(LOCAL_GITHUB_KEY, gh)
else window.localStorage.removeItem(LOCAL_GITHUB_KEY)
} catch {
/* ignore */
}
}
export function getLocalActions(): BetaAction[] {
if (typeof window === 'undefined') return []
try {
const raw = JSON.parse(window.localStorage.getItem(LOCAL_ACTIONS_KEY) ?? '[]')
return Array.isArray(raw) ? raw : []
} catch {
return []
}
}
export function setLocalActions(actions: BetaAction[]): void {
if (typeof window === 'undefined') return
try {
window.localStorage.setItem(LOCAL_ACTIONS_KEY, JSON.stringify(actions))
} catch {
/* ignore */
}
}
function normalizeStanding(raw: Partial<BetaStanding>): BetaStanding {
const prog = raw.program === 'research' || raw.program === 'partner' ? raw.program : 'beta'
return {
applied: Boolean(raw.applied || raw.program),
program: prog,
answers: Array.isArray(raw.answers) ? raw.answers : [],
betas: Array.isArray(raw.betas) ? raw.betas : [],
requested: raw.requested && typeof raw.requested === 'object' ? raw.requested : {},
github: typeof raw.github === 'string' ? raw.github : '',
points: typeof raw.points === 'number' ? raw.points : 0,
score: typeof raw.score === 'number' ? raw.score : undefined,
place: typeof raw.place === 'number' ? raw.place : 0,
of: typeof raw.of === 'number' ? raw.of : 0,
actions: Array.isArray(raw.actions) ? raw.actions : [],
lead: typeof raw.lead === 'string' ? raw.lead : '',
since: typeof raw.since === 'string' ? raw.since : '',
}
}
/** Read the authenticated user's beta record and waitlist standing. */
export async function standing(): Promise<BetaStanding | null> {
const headers = scope()
if (!headers.Authorization) return null
try {
const res = await fetch(`${api()}/v1/marketing/beta`, { headers })
if (!res.ok) return null
const body = (await res.json()) as Partial<BetaStanding>
return normalizeStanding(body)
} catch {
return null
}
}
/** Save program, answers, and requested betas on the user's record. */
export async function keep(payload: {
program: Program
answers?: BetaAnswer[]
betas?: string[]
lead?: string
}): Promise<BetaStanding | null> {
const headers = scope()
if (!headers.Authorization) return null
try {
const res = await fetch(`${api()}/v1/marketing/beta`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json', ...headers },
body: JSON.stringify(payload),
})
if (!res.ok) return null
const body = (await res.json()) as Partial<BetaStanding>
return normalizeStanding(body)
} catch {
return null
}
}
/** Request access to one or more ecosystem betas (or 'alpha'). Also persists locally when signed out. */
export async function ask(betas: string[]): Promise<BetaStanding | null> {
const clean = betas.map((b) => b.trim().toLowerCase()).filter(Boolean)
if (!clean.length) return null
const existingLocal = getLocalRequestedBetas()
setLocalRequestedBetas([...existingLocal, ...clean])
const headers = scope()
if (!headers.Authorization) return null
try {
const res = await fetch(`${api()}/v1/marketing/beta/request`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', ...headers },
body: JSON.stringify({ betas: clean }),
})
if (!res.ok) return null
const body = (await res.json()) as Partial<BetaStanding>
return normalizeStanding(body)
} catch {
return null
}
}
/** Record a verified GitHub repo star (+10 pts) or founder follow (+1 pt). */
export async function act(
action: 'star' | 'follow',
target: string,
github?: string,
): Promise<{ ok: boolean; standing?: BetaStanding; error?: string }> {
if (github) setLocalGithub(github)
const headers = scope()
if (!headers.Authorization) {
// Save locally until the user signs in
const current = getLocalActions()
if (!current.some((a) => a.action === action && a.target === target)) {
const pts = action === 'star' ? POINTS.star : POINTS.follow
setLocalActions([...current, { action, target, points: pts, at: new Date().toISOString() }])
}
return { ok: true }
}
try {
const res = await fetch(`${api()}/v1/marketing/beta/actions`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', ...headers },
body: JSON.stringify({ action, target, ...(github ? { github } : {}) }),
})
if (!res.ok) {
let msg = 'Could not verify action right now.'
try {
const errBody = (await res.json()) as { message?: string; error?: string }
msg = errBody.message || errBody.error || msg
} catch {
/* ignore */
}
return { ok: false, error: msg }
}
const body = (await res.json()) as Partial<BetaStanding>
return { ok: true, standing: normalizeStanding(body) }
} catch {
return { ok: false, error: 'Network error while verifying action.' }
}
}
/** Check whether a star or follow action has already been recorded. */
export function did(actions: BetaAction[], action: 'star' | 'follow', target: string): boolean {
return actions.some((a) => a.action === action && a.target === target)
}