feat(examples): add Signal demo app#6
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…test userIds Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b283ee7070
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (typeof sessionStorage === "undefined") return "user-demo"; | ||
| const stored = sessionStorage.getItem("signal-uid"); | ||
| if (stored) return stored; | ||
| const uid = `user-${Math.random().toString(36).slice(2, 9)}`; | ||
| sessionStorage.setItem("signal-uid", uid); |
There was a problem hiding this comment.
Derive rollout user ID consistently across SSR/client
The userId is computed during render from sessionStorage, but server prerendering has no sessionStorage and falls back to "user-demo", while first client render can generate a random ID. Since the layout variant is derived from this ID, first-time visits can hydrate with a different variant than the HTML, causing layout mismatch/flash and inconsistent A/B assignment. Use an ID source available on both server and client (e.g., cookie) or defer variant selection until after mount.
Useful? React with 👍 / 👎.
| const data = await res.json(); | ||
| setSearchResults(data.results ?? []); | ||
| setSearchError(null); |
There was a problem hiding this comment.
Ignore stale search responses before setting results
Search responses are applied unconditionally after await res.json(), so an older request can finish after a newer one and overwrite the latest query's results (common when typing quickly on variable latency). This makes the visible results drift from the current input. Gate updates by request id or cancel superseded fetches with AbortController.
Useful? React with 👍 / 👎.
Summary
examples/signal/— a full-stack Next.js developer discovery feed that demonstrates five sathergate-toolkit packages as invisible infrastructurenew_feed_layoutA/B rollout), croncall (hourly trending score job), and vaultbox (env fallback pattern)votes / (ageHours + 2)^1.5)Test Plan
cd examples/signal && npm install && npm run dev— server starts on :3000new_feed_layoutflag varies by session userIdGET /api/cronwithoutAuthorizationheader — returns 401GET /api/cronwithAuthorization: Bearer test-secret(.env.local) — returns{ job: "trending", scores: [...] }🚩 new_feed_layout (50% rollout) · 🛡 Search: 60 req/min · Submit: 5 req/hr · ⏰ Trending: hourly cron🤖 Generated with Claude Code