AppView in a box as a Vite plugin thing hatk.dev
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: export auth helpers and parseViewer from generated client

Move login, logout, viewerDid, and parseViewer into the generated
client file so templates don't need a local auth.ts. Layout server
load reduces to a single parseViewer(cookies) call.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+39
+39
packages/hatk/src/cli.ts
··· 1859 1859 clientOut += ` return (globalThis as any).__hatk_viewer ?? null\n` 1860 1860 clientOut += `}\n` 1861 1861 1862 + // Auth helpers — login, logout, viewerDid 1863 + clientOut += `\n// ─── Auth Helpers ────────────────────────────────────────────────────\n\n` 1864 + clientOut += `export async function login(handle: string): Promise<void> {\n` 1865 + clientOut += ` const res = await fetch(\`/oauth/login?handle=\${encodeURIComponent(handle)}\`, { redirect: 'manual' })\n` 1866 + clientOut += ` if (res.type === 'opaqueredirect') {\n` 1867 + clientOut += ` window.location.href = \`/oauth/login?handle=\${encodeURIComponent(handle)}\`\n` 1868 + clientOut += ` return\n` 1869 + clientOut += ` }\n` 1870 + clientOut += ` if (res.ok) return\n` 1871 + clientOut += ` const body = await res.json().catch(() => ({ error: 'Login failed' }))\n` 1872 + clientOut += ` throw new Error(body.error || 'Login failed')\n` 1873 + clientOut += `}\n\n` 1874 + clientOut += `export async function logout(): Promise<void> {\n` 1875 + clientOut += ` ;(globalThis as any).__hatk_viewer = null\n` 1876 + clientOut += ` await fetch('/auth/logout', { method: 'POST' }).catch(() => {})\n` 1877 + clientOut += `}\n\n` 1878 + clientOut += `export function viewerDid(): string | null {\n` 1879 + clientOut += ` if (typeof window === 'undefined') return null\n` 1880 + clientOut += ` const viewer = (globalThis as any).__hatk_viewer\n` 1881 + clientOut += ` return viewer?.did ?? null\n` 1882 + clientOut += `}\n\n` 1883 + clientOut += `// Expose viewer for getViewer() bridge\n` 1884 + clientOut += `;(globalThis as any).__hatk_auth = { viewerDid }\n` 1885 + 1886 + // parseViewer — server-side session cookie resolution for +layout.server.ts 1887 + clientOut += `\n// ─── Server Helpers ──────────────────────────────────────────────────\n\n` 1888 + clientOut += `export async function parseViewer(cookies: { get(name: string): string | undefined }): Promise<{ did: string; handle?: string } | null> {\n` 1889 + clientOut += ` const parseSessionCookie = (globalThis as any).__hatk_parseSessionCookie\n` 1890 + clientOut += ` if (!parseSessionCookie) return null\n` 1891 + clientOut += ` const cookieValue = cookies.get('__hatk_session')\n` 1892 + clientOut += ` if (!cookieValue) return null\n` 1893 + clientOut += ` try {\n` 1894 + clientOut += ` const request = new Request('http://localhost', { headers: { cookie: \`__hatk_session=\${cookieValue}\` } })\n` 1895 + clientOut += ` const viewer = await parseSessionCookie(request)\n` 1896 + clientOut += ` if (viewer) (globalThis as any).__hatk_viewer = viewer\n` 1897 + clientOut += ` return viewer\n` 1898 + clientOut += ` } catch { return null }\n` 1899 + clientOut += `}\n` 1900 + 1862 1901 writeFileSync('./hatk.generated.client.ts', clientOut) 1863 1902 1864 1903 console.log(