Documentation Index
Fetch the complete documentation index at: https://docs.fanfare.io/llms.txt
Use this file to discover all available pages before exploring further.
V1 to V2 Migration
This guide covers migrating from Fanfare SDK v1.x to v2.x. Version 2.0 introduces significant improvements including a new journey-based API, better state management, and SolidJS widgets.
Breaking Changes Summary
| Category | V1 | V2 |
|---|
| Initialization | new FanfareClient() | Fanfare.init() |
| State | Callbacks | Nanostores |
| Journey | Manual state management | ExperienceJourney state machine |
| Widgets | None | SolidJS web components |
| Authentication | Separate auth flow | Integrated with SDK |
| Events | Event emitter | Typed event system |
Installation
# Remove v1
npm uninstall @waitify-io/fanfare-client
# Install v2
npm install @waitify-io/fanfare-sdk-core @waitify-io/fanfare-sdk-react
Initialization
import { FanfareClient } from "@waitify-io/fanfare-client";
const client = new FanfareClient({
apiKey: "pk_live_xxx",
organizationId: "org_xxx",
});
await client.connect();
import { Fanfare } from "@waitify-io/fanfare-sdk-core";
const sdk = await Fanfare.init({
organizationId: "org_xxx",
publishableKey: "pk_live_xxx",
// Optional: Restore existing session
// sessionToken: existingToken,
});
Authentication
// V1: Separate authentication
const session = await client.auth.login(email);
await client.auth.verifyOtp(otp);
// V2: Integrated auth module
const { challenge } = await sdk.auth.otp.start({ email });
const session = await sdk.auth.otp.verify({ code: otp });
// Or guest authentication
const session = await sdk.auth.guest();
Queue Operations
// V1: Direct queue methods
const queue = await client.queues.get("queue_123");
await client.queues.enter("queue_123");
client.on("queue:position", (position) => {
console.log("Position:", position);
});
client.on("queue:admitted", (data) => {
window.location.href = `/checkout?token=${data.token}`;
});
// V2: Module-based with reactive state
const queueModule = sdk.queues;
// Enter queue
const state = await queueModule.enter("queue_123");
// Subscribe to state changes
queueModule.subscribe("queue_123", (state) => {
if (state.status === "QUEUED") {
console.log("Position:", state.position);
}
if (state.status === "ADMITTED") {
window.location.href = `/checkout?token=${state.admittanceToken}`;
}
});
React Hooks
// V1: Custom hooks with callbacks
import { useQueue } from "@waitify-io/fanfare-client-react";
function QueueComponent() {
const { position, enter, leave } = useQueue("queue_123", {
onAdmitted: (token) => {
window.location.href = `/checkout?token=${token}`;
},
});
return <div>Position: {position}</div>;
}
// V2: Reactive hooks with status
import { useQueue, useFanfareAuth } from "@waitify-io/fanfare-sdk-react";
function QueueComponent() {
const { isAuthenticated, guest } = useFanfareAuth();
const { status, position, admittanceToken, enter, leave, isLoading } = useQueue("queue_123");
const handleEnter = async () => {
if (!isAuthenticated) await guest();
await enter();
};
if (status === "admitted" && admittanceToken) {
window.location.href = `/checkout?token=${admittanceToken}`;
return null;
}
return (
<div>
{status === "queued" && <p>Position: {position}</p>}
{status === "not_entered" && <button onClick={handleEnter}>Enter Queue</button>}
</div>
);
}
Draw Operations
// V1
await client.draws.enter("draw_123");
client.on("draw:result", (result) => {
if (result.won) {
console.log("You won!");
}
});
// V2
const state = await sdk.draws.enter("draw_123");
sdk.draws.subscribe("draw_123", (state) => {
if (state.status === "WON") {
console.log("You won!");
}
});
Experience Journey (New in V2)
V2 introduces ExperienceJourney for managing complex multi-step flows:
import { ExperienceJourney } from "@waitify-io/fanfare-sdk-core";
const journey = new ExperienceJourney(sdk);
// Start journey
await journey.start("exp_123");
// Listen to state changes
journey.state.listen((snapshot) => {
switch (snapshot.journeyStage) {
case "needs_auth":
// Show auth form
break;
case "needs_access_code":
// Show access code input
break;
case "routed":
// Handle based on sequence stage
break;
}
});
// Perform actions
await journey.perform("enter_queue");
await journey.perform("leave_participation");
Event System
// V1: String-based events
client.on("queue:position", handler);
client.off("queue:position", handler);
// V2: Typed event system
import type { SDKEvents } from "@waitify-io/fanfare-sdk-core";
sdk.events.on("queue:position-updated", (event) => {
// event is fully typed
console.log(event.queueId, event.position);
});
sdk.events.off("queue:position-updated", handler);
State Management
// V1: Callback-based updates
client.on("queue:state", (state) => {
updateUI(state);
});
// V2: Nanostores for reactive state
import { useStore } from "@nanostores/react";
// In React
function QueueStatus() {
const state = useStore(sdk.queues.getStore("queue_123"));
return <div>Status: {state?.status}</div>;
}
// Or subscribe directly
const unsubscribe = sdk.queues.getStore("queue_123").subscribe((state) => {
updateUI(state);
});
Provider Setup
// V1
import { FanfareProvider } from "@waitify-io/fanfare-client-react";
function App() {
return (
<FanfareProvider apiKey="pk_live_xxx" organizationId="org_xxx">
<YourApp />
</FanfareProvider>
);
}
// V2
import { FanfareProvider } from "@waitify-io/fanfare-sdk-react";
function App() {
return (
<FanfareProvider organizationId="org_xxx" publishableKey="pk_live_xxx">
<YourApp />
</FanfareProvider>
);
}
Web Components (New in V2)
V2 adds web component support:
import { registerWebComponents } from "@waitify-io/fanfare-sdk-solid";
registerWebComponents({
organizationId: "org_xxx",
publishableKey: "pk_live_xxx",
});
// Use in any framework
function QueuePage() {
return <fanfare-queue-widget queue-id="queue_123" />;
}
Type Changes
Session Types
// V1
interface Session {
token: string;
userId: string;
}
// V2
interface Session {
sessionToken: string;
consumerId: string;
organizationId: string;
expiresAt?: number;
isGuest: boolean;
}
Queue State Types
// V1
interface QueueState {
position: number;
admitted: boolean;
token?: string;
}
// V2
type QueueConsumerState =
| { status: "NOT_ENTERED" }
| { status: "QUEUED"; position: number; estimatedWaitTimeInSeconds?: number }
| { status: "ADMITTED"; admittanceToken: string; expiresAt: number };
Migration Checklist