cloudsignal-websocket
CloudSignal WebSocket — React MQTT Context Generator
Generate a production-grade React context provider for real-time messaging over CloudSignal's MQTT broker using WebSocket. The generated code handles the full connection lifecycle: authentication via external auth providers, reconnection, proactive token refresh, message routing, and cleanup.
What You Generate
-
mqtt-context.tsx— React context provider with:- Auth-provider token exchange (Clerk, Supabase, Auth0, Firebase, or custom OIDC)
- WebSocket connection to CloudSignal MQTT broker
- Auth error circuit-breaker (max 3 retries, 10s delay)
- Proactive token refresh at 50 minutes (before 60-min TTL expiry)
- Exact topic routing with safe JSON parsing
- React StrictMode double-mount protection
- Tab visibility reconnection
- Typed subscription hooks (jobs, notifications, transactions, or custom)
-
cloudsignal.d.ts— TypeScript declarations for@cloudsignal/mqtt-client(the npm package does not ship types)
Before You Start
Ask the user for these inputs (use defaults if not provided):
| Input | Example | Default |
|---|---|---|
| Auth provider | Clerk, Supabase, Auth0, Firebase | Ask (required) |
| Organization ID | org_k7xm4pqr2n5t |
Ask (required) |
| Topic namespace | myapp |
App name from package.json |
| Message types needed | notifications, jobs, transactions | All three |
| Target directory | src/lib/ or src/contexts/ |
src/lib/ |
Generation Steps
Step 1: Read the Reference Implementation
Read references/mqtt-context.tsx in this skill's directory. This is the canonical reference — a production-tested context provider extracted from a live SaaS. Use it as the base for all generated code.
Step 2: Adapt the Auth Provider Hooks
The reference contains two placeholder functions that MUST be replaced based on the user's auth provider:
useCurrentUser() — must return { id: string } | null:
| Provider | Implementation |
|---|---|
| Clerk | import { useUser } from "@clerk/nextjs"; const { user } = useUser(); return user ? { id: user.id } : null; |
| Supabase | import { useSession } from "@supabase/auth-helpers-react"; const session = useSession(); return session ? { id: session.user.id } : null; |
| Auth0 | import { useAuth0 } from "@auth0/auth0-react"; const { user, isAuthenticated } = useAuth0(); return isAuthenticated && user ? { id: user.sub! } : null; |
| Firebase | import { useAuthState } from "react-firebase-hooks/auth"; import { auth } from "@/lib/firebase"; const [user] = useAuthState(auth); return user ? { id: user.uid } : null; |
useGetToken() — must return () => Promise<string | null>:
| Provider | Implementation |
|---|---|
| Clerk | import { useAuth } from "@clerk/nextjs"; const { getToken } = useAuth(); return getToken; |
| Supabase | import { useSupabaseClient } from "@supabase/auth-helpers-react"; const supabase = useSupabaseClient(); return async () => { const { data } = await supabase.auth.getSession(); return data.session?.access_token ?? null; }; |
| Auth0 | import { useAuth0 } from "@auth0/auth0-react"; const { getAccessTokenSilently } = useAuth0(); return async () => { try { return await getAccessTokenSilently(); } catch { return null; } }; |
| Firebase | import { auth } from "@/lib/firebase"; return async () => auth.currentUser?.getIdToken() ?? null; |
Step 3: Customize Message Types
Replace the reference message interfaces with the user's domain. Keep the structure (interface + handler type + registry pattern) but adapt field names and types.
Default message types from reference: ProgressMessage, StatusMessage, TransactionMessage, NotificationMessage.
Step 4: Set Configuration Constants
const CLOUDSIGNAL_ORG_ID = process.env.NEXT_PUBLIC_CLOUDSIGNAL_ORG_ID;
const CLOUDSIGNAL_HOST = process.env.NEXT_PUBLIC_CLOUDSIGNAL_HOST || "wss://connect.cloudsignal.app:18885/";
const TOPIC_ROOT = "{user's namespace}";
Step 5: Write the Type Declarations
Read references/cloudsignal.d.ts and write it to the user's types/ directory (or wherever their project keeps type declarations). This file is required because @cloudsignal/mqtt-client does not ship .d.ts files.
Step 6: Write the Context Provider
Combine the adapted auth hooks, customized message types, and the full provider logic from the reference into the final mqtt-context.tsx. Preserve ALL of these production patterns:
- Stable ref pattern:
connectRefupdated every render, used by timers - Auth error circuit-breaker:
authErrorCountRefwithMAX_AUTH_ERRORS = 3 - Proactive token refresh:
scheduleTokenRefresh()at 50 minutes - StrictMode guard:
connectingRef+mountedRefprevent double connections - Exact topic matching:
topic === \${prefix}/notifications`not.includes()` - Safe JSON parsing: try/catch around
JSON.parsein message handler - Client destruction on auth error: Stops SDK's stale-token reconnect loop
- Tab visibility reconnect:
visibilitychangeevent listener
Step 7: Show Usage
Provide a usage example showing:
- Provider wrapping in
app/providers.tsx(nested inside the auth provider) - A consumer component using
useMQTT()hook - Environment variable setup (
.env.local)
Critical SDK Pitfalls
Read references/sdk-pitfalls.md for the full list. These MUST be handled in generated code:
- Token expiry reconnect loop: Destroy client on
onAuthError, don't rely on SDK reconnect externalTokennotidToken: UseexternalTokeninconnectWithToken()- No TypeScript declarations: Always generate
cloudsignal.d.ts - React StrictMode double-mount: Use
connectingRef+mountedRefguards - Token service version: SDK v2.x expects
/v2/tokens/exchange - CJS
require()breaksmqtt.connect(): Always use ESMimport, neverrequire()
Environment Variables
Tell the user to add these to .env.local:
NEXT_PUBLIC_CLOUDSIGNAL_ORG_ID=org_xxxxxxxxxxxxx # From CloudSignal dashboard
NEXT_PUBLIC_CLOUDSIGNAL_HOST=wss://connect.cloudsignal.app:18885/ # Optional, this is default
CloudSignal Dashboard Setup
Remind the user they need to configure their CloudSignal organization:
- Create an organization at https://dashboard.cloudsignal.app
- Configure an External Auth Provider integration (select their provider, enter JWKS URL)
- Note the
org_xxxID for the environment variable
npm Dependency
The user needs to install the CloudSignal MQTT client:
npm install @cloudsignal/mqtt-client