commits
backend: zig 0.15 → 0.16 (zat v0.3.0-alpha.7, zqlite master)
- Io.Threaded with explicit io passing (no debug_io hack)
- Io.Mutex, Io.Timestamp, Io.net, smp_allocator
- thread-per-connection replaces Thread.Pool
- Dockerfile updated to zig 0.16.0-dev.3059
frontend: handle autocomplete, layout/styling updates
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The ON CONFLICT clause was missing dpop_private_key, pds_url, and
authserver_iss. Re-logging in generated a new DPoP keypair but the DB
kept the old one, so DPoP proofs didn't match the new access token.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
AT Protocol OAuth access tokens expire after ~5 minutes. When the PDS
returns 401, refresh the token using the refresh token and retry the
request. Only delete the session if refresh also fails.
Also keeps the exchange token pattern from the previous commit for
more reliable cookie setting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Setting cookies on 302 redirects from cross-site OAuth flows is
unreliable. Instead, redirect to frontend with a short-lived exchange
token, then the frontend POSTs to /api/exchange which sets the cookie
on a normal same-origin response.
Follows the same pattern as plyr.fm's auth flow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- detect 401 responses in api client, clear user state via callback
- layout registers onUnauthorized to reset user on session expiry
- poll creation waits for jetstream indexing before navigating home
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
drop 270 lines of local crypto code in favor of zat.oauth module.
only API rename: oauth.jwkPublicKey() → keypair.jwk().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- replace GPA (debug allocator) with page_allocator
- remove sendJsonWithCredentials alias (was identical to sendJson)
- fix profile cache: re-fetch when stale instead of returning stale data forever
- convert recursive pdsAuthedRequest DPoP nonce retry to bounded loop (max 1 retry)
- remove base64urlEncodeBytes alias in oauth.zig (was identical to base64urlEncode)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
backend:
- replace tap (node firehose consumer) with native jetstream client
- add full oauth flow (DPoP, PKCE, session management)
- add poll deletion endpoint (DELETE /api/polls/{uri})
- add DELETE to CORS allowed methods
- add voter handle resolution + profile caching
frontend:
- rewrite from vanilla vite/ts to sveltekit with static adapter
- fix vote switch detection (per-option count comparison, not totals)
- add inline vote feedback (voting.../voted/failed)
- add poll deletion (owner only, with confirmation)
- add VotersTooltip cache invalidation after voting
- add mobile tap support for voter tooltips
- link handles to bsky.app profiles
- add timestamp hover (full localized datetime)
- 44px min touch targets on option buttons
- add favicon (◉)
- defensive JSON parsing in api helper
cleanup:
- remove old vanilla frontend (src/, dist/, functions/, public/)
- remove tap/ (replaced by jetstream.zig)
- remove docs/ (outdated architecture docs)
- move lexicons to tech.waow.pollz namespace
- rewrite readme
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- add readme.md with ASCII architecture diagram in details block
- remove jetstream connection (vestige from pre-tap architecture)
- remove loadUserVotes and poll.votes Map (unused)
- add [src] link to tangled in header
- add .wrangler to gitignore
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- replace jetstream.zig/backfill.zig with tap integration
- use putRecord to update votes instead of delete+create
(avoids race condition with out-of-order firehose events)
- add upsert logic in db.insertVote with timestamp comparison
- handle "update" action in tap consumer
- reorganize docs into docs/ directory
- simplify frontend voting flow
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- frontend: vite + typescript SPA for creating/viewing polls
- backend: zig + httpz server with sqlite persistence
- cloudflare pages function for dynamic OG tags on poll links
- jetstream integration for real-time vote/poll sync
- justfile with deploy targets for fly.io and cloudflare pages
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
backend: zig 0.15 → 0.16 (zat v0.3.0-alpha.7, zqlite master)
- Io.Threaded with explicit io passing (no debug_io hack)
- Io.Mutex, Io.Timestamp, Io.net, smp_allocator
- thread-per-connection replaces Thread.Pool
- Dockerfile updated to zig 0.16.0-dev.3059
frontend: handle autocomplete, layout/styling updates
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
AT Protocol OAuth access tokens expire after ~5 minutes. When the PDS
returns 401, refresh the token using the refresh token and retry the
request. Only delete the session if refresh also fails.
Also keeps the exchange token pattern from the previous commit for
more reliable cookie setting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Setting cookies on 302 redirects from cross-site OAuth flows is
unreliable. Instead, redirect to frontend with a short-lived exchange
token, then the frontend POSTs to /api/exchange which sets the cookie
on a normal same-origin response.
Follows the same pattern as plyr.fm's auth flow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- replace GPA (debug allocator) with page_allocator
- remove sendJsonWithCredentials alias (was identical to sendJson)
- fix profile cache: re-fetch when stale instead of returning stale data forever
- convert recursive pdsAuthedRequest DPoP nonce retry to bounded loop (max 1 retry)
- remove base64urlEncodeBytes alias in oauth.zig (was identical to base64urlEncode)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
backend:
- replace tap (node firehose consumer) with native jetstream client
- add full oauth flow (DPoP, PKCE, session management)
- add poll deletion endpoint (DELETE /api/polls/{uri})
- add DELETE to CORS allowed methods
- add voter handle resolution + profile caching
frontend:
- rewrite from vanilla vite/ts to sveltekit with static adapter
- fix vote switch detection (per-option count comparison, not totals)
- add inline vote feedback (voting.../voted/failed)
- add poll deletion (owner only, with confirmation)
- add VotersTooltip cache invalidation after voting
- add mobile tap support for voter tooltips
- link handles to bsky.app profiles
- add timestamp hover (full localized datetime)
- 44px min touch targets on option buttons
- add favicon (◉)
- defensive JSON parsing in api helper
cleanup:
- remove old vanilla frontend (src/, dist/, functions/, public/)
- remove tap/ (replaced by jetstream.zig)
- remove docs/ (outdated architecture docs)
- move lexicons to tech.waow.pollz namespace
- rewrite readme
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- add readme.md with ASCII architecture diagram in details block
- remove jetstream connection (vestige from pre-tap architecture)
- remove loadUserVotes and poll.votes Map (unused)
- add [src] link to tangled in header
- add .wrangler to gitignore
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- replace jetstream.zig/backfill.zig with tap integration
- use putRecord to update votes instead of delete+create
(avoids race condition with out-of-order firehose events)
- add upsert logic in db.insertVote with timestamp comparison
- handle "update" action in tap consumer
- reorganize docs into docs/ directory
- simplify frontend voting flow
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- frontend: vite + typescript SPA for creating/viewing polls
- backend: zig + httpz server with sqlite persistence
- cloudflare pages function for dynamic OG tags on poll links
- jetstream integration for real-time vote/poll sync
- justfile with deploy targets for fly.io and cloudflare pages
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>