javascript icon indicating copy to clipboard operation
javascript copied to clipboard

feat(react): Implement waitlist hook with signal primitives

Open brkalow opened this issue 3 months ago • 5 comments

Description

This PR introduces the useWaitlist() hook, a new signal-backed hook in @clerk/react that enables developers to build custom waitlist UIs with reactive state management. It follows the pattern of useSignIn() and useSignUp(), exposing waitlist (resource), errors, and fetchStatus.

The Waitlist resource in @clerk/clerk-js has been integrated with the signal system, providing a WaitlistFuture instance for reactive updates. The State class now manages a lazily initialized, singleton Waitlist instance, ensuring its independence from the Client resource and proper signal propagation.

An integration test has been added to validate the hook's functionality, including joining the waitlist, error handling, and loading states.

To test the changes, run the new integration test: pnpm playwright test integration/tests/custom-flows/waitlist.test.ts

Checklist

  • [x] pnpm test runs as expected.
  • [x] pnpm build runs as expected.
  • [x] (If applicable) JSDoc comments have been added or updated for any package exports
  • [ ] (If applicable) Documentation has been updated

Type of change

  • [ ] 🐛 Bug fix
  • [x] 🌟 New feature
  • [ ] 🔨 Breaking change
  • [ ] 📖 Refactoring / dependency upgrade / documentation
  • [ ] other:

Open in Cursor Open in Web

Summary by CodeRabbit

  • New Features

    • Added Waitlist functionality with a new useWaitlist React hook for accessing waitlist state and join operations
    • Introduced Waitlist component for email signup with validation and loading states
    • Added ability to join the waitlist with email address submission and error handling
  • Bug Fixes

    • Fixed environment configuration typo
  • Tests

    • Added comprehensive integration tests for waitlist feature
  • Chores

    • Removed experimental export entry from package exports

✏️ Tip: You can customize this high-level summary in your review settings.

brkalow avatar Oct 29 '25 18:10 brkalow

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch. Learn more about Cursor Agents

cursor[bot] avatar Oct 29 '25 18:10 cursor[bot]

⚠️ No Changeset found

Latest commit: 406f16a67ec2390c484cdf9d322e35bdfcd20542

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

changeset-bot[bot] avatar Oct 29 '25 18:10 changeset-bot[bot]

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
clerk-js-sandbox Ready Ready Preview Comment Dec 8, 2025 7:37pm

vercel[bot] avatar Oct 29 '25 18:10 vercel[bot]

Walkthrough

This pull request introduces a new waitlist feature across the Clerk SDK, including core resource and signal management, React hooks, state proxy integration, type definitions, and test utilities. Additionally, it fixes a typo in environment preset naming and removes an experimental package export.

Changes

Cohort / File(s) Summary
Environment & Preset Configuration
integration/presets/envs.ts, integration/tests/waitlist-mode.test.ts
Fixed typo: renamed environment preset constant and ID from withWaitlistdMode to withWaitlistMode; updated test reference to use corrected preset name.
React Template Routes & Components
integration/templates/custom-flows-react-vite/src/main.tsx, integration/templates/custom-flows-react-vite/src/routes/Waitlist.tsx
Added Waitlist route and component. Route imports and renders new Waitlist component at /waitlist path. Component uses useWaitlist hook, renders email input form with validation, displays success state after joining, and includes navigation links.
Test Infrastructure
integration/testUtils/index.ts, integration/testUtils/waitlistService.ts, integration/tests/custom-flows/waitlist.test.ts
Added WaitlistService utility for clearing waitlist entries by email via Clerk client. Integrated service into test utils. Added Playwright test suite covering waitlist join flow with valid/invalid email and loading states.
Core Waitlist Resource
packages/clerk-js/src/core/resources/Waitlist.ts
Extended Waitlist constructor to accept nullable data, added instance method join() that delegates to static method via runAsyncResourceTask, emits resource:update event on hydration.
Signal Management
packages/clerk-js/src/core/signals.ts
Introduced waitlist signal set: waitlistResourceSignal, waitlistErrorSignal, waitlistFetchSignal, and computed waitlistComputedSignal. Added helper function errorsToWaitlistErrors() for error transformation.
State Management
packages/clerk-js/src/core/state.ts
Added four public signal properties (waitlistResourceSignal, waitlistErrorSignal, waitlistFetchSignal, waitlistSignal), created internal Waitlist instance, exposed via __internal_waitlist getter, and wired resource event handlers for error/update/fetch flows.
React Hooks
packages/react/src/hooks/index.ts, packages/react/src/hooks/useClerkSignal.ts
Added useWaitlist() hook exported from barrel. Extended useClerkSignal() overloads and implementation to support 'waitlist' signal type with WaitlistSignalValue.
State Proxy
packages/react/src/stateProxy.ts
Added waitlistSignal() accessor and __internal_waitlist getter. Implemented buildWaitlistProxy() to construct waitlist sub-proxy with errors, fetchStatus, and join/reload operations.
Type Definitions
packages/shared/src/types/clerk.ts, packages/shared/src/types/state.ts, packages/shared/src/types/waitlist.ts
Moved JoinWaitlistParams from clerk.ts to waitlist.ts. Added WaitlistFields, WaitlistErrors, WaitlistSignalValue, NullableWaitlistSignal, WaitlistSignal types. Extended WaitlistResource with readonly properties and join() method. Extended State interface with waitlistSignal and __internal_waitlist.
Documentation & Configuration
packages/localizations/README.md, packages/tanstack-react-start/package.json
Added extra blank line in localization README. Removed "./experimental" export entry from package.json exports map.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant WaitlistUI as Waitlist Component
    participant Hook as useWaitlist Hook
    participant ClerkState as Clerk State
    participant WaitlistResource as Waitlist Resource
    participant API as Clerk Backend

    User->>WaitlistUI: Submit email
    WaitlistUI->>Hook: Call useWaitlist()
    activate Hook
    Hook->>ClerkState: Subscribe to waitlistSignal
    deactivate Hook
    
    WaitlistUI->>WaitlistResource: Call waitlist.join({ emailAddress })
    activate WaitlistResource
    WaitlistResource->>ClerkState: Emit waitlistFetchSignal ('fetching')
    activate ClerkState
    deactivate WaitlistResource
    
    WaitlistResource->>API: POST /waitlist/join
    activate API
    API-->>WaitlistResource: WaitlistResource response
    deactivate API
    
    WaitlistResource->>ClerkState: Emit waitlistResourceSignal (updated)
    WaitlistResource->>ClerkState: Emit waitlistFetchSignal ('idle')
    deactivate ClerkState
    
    ClerkState-->>Hook: Signal updated
    Hook-->>WaitlistUI: Re-render with success state
    WaitlistUI-->>User: Show "Successfully joined!"

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Signal and state management wiring: Ensure waitlistResourceSignal, waitlistErrorSignal, and waitlistFetchSignal are correctly composed in the computed signal and properly exposed through State class public members.
  • Type definitions coordination: Verify JoinWaitlistParams, WaitlistErrors, WaitlistSignalValue, and WaitlistSignal are consistently used across clerk.ts, state.ts, and waitlist.ts type files.
  • StateProxy implementation: Review buildWaitlistProxy() logic for consistency with existing signIn/signUp proxy patterns; ensure error handling and fetch status management align with established patterns.
  • React hook overloads: Confirm useClerkSignal() overload ordering and switch-case logic handle the new 'waitlist' signal correctly without breaking existing signIn/signUp cases.
  • Error transformation pipeline: Verify errorsToWaitlistErrors() correctly maps ClerkError to WaitlistErrors structure matching WaitlistFields.
  • Resource lifecycle: Check Waitlist constructor nullable data handling, join method delegation via runAsyncResourceTask, and event emissions don't introduce race conditions or memory leaks.

Poem

🐰 A waitlist arrives in the Clerk today,
With signals and hooks along the way!
New types, new states, new flows so clean,
The hopping begins—join now, we've seen!
From bunny-approved types to React's embrace,
This feature hops into place with grace! 🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change—implementing a waitlist hook using signal primitives in the React package—which is the primary focus across the changeset.
✨ Finishing touches
  • [ ] 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • [ ] Create PR with unit tests
  • [ ] Post copyable unit tests in a comment
  • [ ] Commit unit tests in branch cursor/implement-waitlist-hook-with-signal-primitives-3ad1

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot] avatar Oct 29 '25 18:10 coderabbitai[bot]

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7097
@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7097
@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7097
@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7097
@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7097
@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7097
@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@7097
@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7097
@clerk/express

npm i https://pkg.pr.new/@clerk/express@7097
@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7097
@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7097
@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7097
@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7097
@clerk/react

npm i https://pkg.pr.new/@clerk/react@7097
@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7097
@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7097
@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7097
@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7097
@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@7097
@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7097
@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7097

commit: 406f16a

pkg-pr-new[bot] avatar Nov 18 '25 23:11 pkg-pr-new[bot]