npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fluxy-chat/sdk

v0.4.2

Published

Fluxychat JavaScript/TypeScript SDK — WebSocket rooms, REST messages, FluxyRealtimeProvider, useChat with loadMore

Readme

@fluxy-chat/sdk

Socket Badge

Client for a Fluxychat Worker (self-hosted or Fluxychat Cloud): rooms, messages, WebSockets, agents, and optional React useChat.

The SDK talks to your Worker URL. It does not include LLM API keys — only your Fluxy project API key or member JWT.

Install

npm install @fluxy-chat/sdk zustand
# or
pnpm add @fluxy-chat/sdk zustand

Peer dependencies: install react (18+) when you use useChat / FluxyRealtimeProvider, and zustand (5+) for useChat, createFluxyRoomSession, or the room store helpers. The SDK has no runtime npm dependencies — only your Worker URL is contacted over the network (Socket network-access note).

Vanilla store (Vue, Solid, Node)

import { createFluxyRoomSession } from "@fluxy-chat/sdk";

const { store, stop } = createFluxyRoomSession({
  roomId: "my-room",
  client,
});

const unsub = store.subscribe((state) => {
  console.log(state.messages, state.connectionState);
});

store.getState().sendMessage("hello");
store.getState().sendMessage("", null, undefined, {
  templateId: "tpl_…",
  templateVars: { name: "Ada" },
});

// cleanup: unsub(); stop();

What you must configure

| Piece | Who sets it | Notes | |--------|-------------|--------| | Worker baseUrl | You | e.g. https://fluxychat-worker.<account>.workers.dev or your custom domain | | Project API key (fc_…) | Worker / console | Mint JWTs via POST /auth/token with header X-Fluxy-Api-Keyserver-side only | | Member JWT | Your backend or Fluxychat console | Passed to FluxyChatClient / useChat as token | | LLM provider keys | Worker secrets or console | For agents; never embed in the npm package |

Minimal backend (mint JWT)

curl -X POST "$WORKER_URL/auth/token" \
  -H "Content-Type: application/json" \
  -H "X-Fluxy-Api-Key: fc_your_project_key" \
  -d '{"userId":"alice","roles":["member"],"ttlSeconds":3600}'

Use the returned token in the browser.

Quick start (React)

Quick smoke test run this before writing SDK code

# Set these in your shell or .env.local first.
export WORKER_URL=https://your-worker.example.workers.dev
export JWT=eyJ...                              # member JWT from /auth/token
export ROOM_ID=general

# 1. Send a message
curl -sS -X POST "$WORKER_URL/messages" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d "{\"roomId\":\"$ROOM_ID\",\"content\":\"hello from the smoke test\"}"

# 2. Read it back
curl -sS "$WORKER_URL/api/messages?roomId=$ROOM_ID&limit=1" \
  -H "Authorization: Bearer $JWT"
# Verified against @fluxy-chat/[email protected]  2026-06-26

If both calls return 200 and the message id round-trips, your Worker URL, JWT, and room are wired correctly. Skip to Option A below.

Option A — explicit client

import { FluxyChatClient, useChat } from "@fluxy-chat/sdk";

const client = new FluxyChatClient({
  baseUrl: process.env.NEXT_PUBLIC_FLUXYCHAT_WORKER_URL!,
  userId: "alice",
  token: memberJwtFromYourBackend,
});

function Room({ roomId }: { roomId: string }) {
  const {
    messages,
    sendMessage,
    connectionState,
    retryMessage,
    loadMore,
    hasMore,
    isLoadingMore,
  } = useChat({ roomId, client, markReadLatest: true });
  // connectionState.nextRetryAt → "Reconnecting in 3s…"
  // messages[].deliveryStatus → pending | sent | failed
  // render messages; call loadMore() when the user scrolls to the top
}
// Verified against @fluxy-chat/[email protected]  2026-06-26

Room catch-up + drafts

const catchUp = await client.getRoomCatchUp(roomId);
// { unreadCount, lastReadMessageId, firstUnreadMessageId }

await client.putRoomDraft(roomId, { content: "…", replyToId: null });
const draft = await client.getRoomDraft(roomId);

// Ephemeral message (1 hour TTL)
await client.createMessage(roomId, "self-destructs", null, undefined, undefined, {
  expiresInSeconds: 3600,
});

Rooms unread + notifications

const rooms = await client.listRooms(); // may include unreadCount per room
const notes = await client.listNotifications({ unreadOnly: true });
await client.markNotificationRead(notes[0].id);
// useNotifications(client) — React hook for in-app notification inbox

Option B — FluxyRealtimeProvider (hosted Next.js or custom mint)

Wrap your app (or chat layout) once. The provider refreshes the member JWT before expiry and on auth errors.

import { FluxyRealtimeProvider, useChat } from "@fluxy-chat/sdk";

export function ChatLayout({ children }: { children: React.ReactNode }) {
  return (
    <FluxyRealtimeProvider
      workerUrl={process.env.NEXT_PUBLIC_FLUXYCHAT_WORKER_URL!}
      connectUrl="/api/fluxy/connect"
    >
      {children}
    </FluxyRealtimeProvider>
  );
}

function Room({ roomId }: { roomId: string }) {
  const { messages, sendMessage, loadMore, hasMore } = useChat({ roomId });
  // …
}

For your own backend mint flow, pass authTokenProvider={() => fetch("/api/chat-token").then(r => r.json())} instead of connectUrl.

Pagination

GET /api/messages supports a before cursor (createdAt of the oldest visible message). The SDK sorts history chronologically and exposes:

  • hasMore — another page may exist
  • isLoadingMoreloadMore() in flight
  • loadMore() — prepends older messages

Live snapshot (getParticipants)

GET /rooms/:id/live returns the room's Pusher-style channel stats plus a members: [{ userId, userInfo }] array (aggregated across shards for supergroup rooms, P10-SB8). Use it from the SDK to know "who's connected right now" without waiting for the next presence WS event:

const live = await client.getRoomLive("lobby");
// { occupied, online, subscriptionCount, userCount, users[], members: [{ userId, userInfo }], socketIds[] }

// Just the participants slice
const participants = await client.getRoomParticipants("lobby");

// React hook exposes a live snapshot in the store
const { live, loadLive } = useChat({ roomId: "lobby" });
await loadLive(); // refresh on demand

userInfo reflects whatever was passed in the WS presenceInfo query (or the JWT name / agent profile). For agent-typed participants, userInfo.agentId is set; consumers can branch on that.

Connection resilience

connectRoom() (used by useChat / createFluxyRoomSession) includes:

  • Exponential backoff reconnectconnectionState.status, nextRetryAt, reconnectAttempt
  • Outbound queuesendJson queues while connecting or reconnecting (cap 100 frames, 5 min TTL); flush on open. Inspect with getOutboundQueueDepth().
  • Heartbeat — client sends { type: "ping" } every 25s by default; server replies { type: "pong" }. Disable with heartbeatIntervalMs: 0 on connectRoom options.
  • WS connect snapshotreplay=connect + replayLimit query params; server sends { type: "replay", messages } (or history by default). Set replay: "off" via connect(roomId, { replay: "off" }) for heavy rooms.
  • REST history replay after reconnect only if no WS snapshot arrived first (replayHistoryOnReconnect, default true)
  • Streaming edit batching — rapid edit events with streaming: true are coalesced (~80ms) to reduce React re-renders during agent token streams
  • SSE / polling fallback when reconnect attempts are exhausted (see transport fallback doc in monorepo)
const conn = client.connectRoom(roomId, {
  heartbeatIntervalMs: 25_000,
  onOutboundQueueDrop: (n) => console.warn("dropped", n),
});

Reconnect backoff defaults — FluxyChat vs Fluxy reference

computeReconnectBackoffMs(attempt, baseMs, maxMs) is min(maxMs, baseMs * 2^attempt), capped internally at attempt ≤ 6 and bounded by maxReconnectAttempts (default 8). The two default profiles produce the schedule below:

| Attempt | FluxyChat default (500ms / 20s) | Fluxy reference (1s / 8s) | |--------:|--------------------------------------:|--------------------------------:| | 0 | 500 ms | 1 000 ms | | 1 | 1 000 ms | 2 000 ms | | 2 | 2 000 ms | 4 000 ms | | 3 | 4 000 ms | 8 000 ms (capped) | | 4 | 8 000 ms | 8 000 ms | | 5 | 16 000 ms | 8 000 ms | | 6 | 20 000 ms (capped) | 8 000 ms | | 7 | 20 000 ms | 8 000 ms | | Total wall time (8 tries) | ≈ 71.5 s | ≈ 47 s |

Why we keep the wider window (current default)

  • Shorter transient drops recover faster. Mobile networks flap in the 1–3 s window; a 500 ms first step lands a reconnect before most apps show a "disconnected" toast, which is what the dashboard UX relies on (connectionState.status is rendered in the room header).
  • Longer outages still give up reasonably fast. The 20 s cap means a 10-minute Worker outage costs ~30 reconnect attempts' worth of traffic, and the SSE/polling fallback (useChat) kicks in well before users notice.
  • It's configurable per-room. Call sites that want the Fluxy-style curve set baseBackoffMs: 1_000, maxBackoffMs: 8_000 on connectRoom options; see the P11-B2 entry in ROADMAP_EXECUTION.md.

When to flip to the Fluxy profile

  • Heavy rooms (≥ 1k concurrent sockets) where each reconnect attempt costs meaningful origin CPU on the Worker, and you'd rather batch retries at 8 s.
  • Backend-driven bots / workers where the long backoff is fine because the agent is the only writer.
  • Network profiles known to be slow (satellite, intermittent VPNs) where the extra 500 ms either way is in the noise.

When to keep the current default

  • Consumer chat UIs, mobile-first apps, anything where the user perceives the first 1–2 s after a drop.
  • The dashboard, agent chat, and any room where presenceInfo is shown live.
// Match the Fluxy-style curve (1s base, 8s cap)
const conn = client.connectRoom(roomId, {
  baseBackoffMs: 1_000,
  maxBackoffMs: 8_000,
});

See docs/research/ws-client-benchmark-fluxy.md § 1 for the upstream reference. The defaults are not changing in this minor; P11-B2 stays in the roadmap as a documented decision rather than a code change.

Self-host vs hosted cloud

  • Self-host: deploy apps/worker from the monorepo, run D1 migrations, set secrets. See apps/worker/.dev.vars.example.
  • Hosted cloud: use the Fluxychat dashboard on Vercel; sign in with Clerk; project + API keys are provisioned for you.

Full operator docs: docs/dashboard-integration.md.

Agents

Agent invokes run on the Worker (POST /agents/:id/invoke or @handle in a room message). Configure provider keys on the Worker or per-project in the console.

  • invokeAgentRest(agentId, roomId, content, { replyTo }) — REST invoke with optional thread parent message id.
  • getAgentRuns(agentId) — run history including tool_calls when tools were used.
  • Live room events (WebSocket): tool_call, tool_result, tool_error, agentRun (latency, tokens, status).

History replay (heavy rooms)

const { messages, loadHistory, historyLoaded } = useChat({
  roomId,
  replay: "request", // skip REST + WS history on connect
});
// later: await loadHistory();

Default is replay: "connect". Pass replayHistoryOnReconnect: false to connectRoom if you manage history yourself.

Custom bot streaming (FluxyMessageStream)

For bots outside the built-in agent runtime, stream into one message row over WebSocket:

import { FluxyChatClient, FluxyMessageStream } from "@fluxy-chat/sdk";

const connection = client.connectRoom(roomId);
// connectRoom() auto-connects  no .connect() needed
const stream = new FluxyMessageStream(connection, agentUserId, { parentId: null });
stream.push("Hello ");
stream.end();
// Verified against @fluxy-chat/[email protected]  2026-06-26

See docs/cookbook/bot-streaming-fluxy-message-stream.md in the monorepo.

P12 / open beta APIs (2026)

| Feature | SDK method | |---------|------------| | AI image generation | generateAiImage(roomId, prompt, opts?) — requires AI_IMAGE_GENERATION_ENABLED on Worker | | Composer tool prompts | buildDeepResearchPrompt(), buildWebSearchPrompt(), buildImageGenerationCaption() | | AI reply suggestions | suggestReplies(roomId, parentId?) | | Thread TL;DR | summarizeThread(messageId) | | Full-text search | searchMessages({ q, roomId?, from?, to? }) | | Unified inbox | getInbox(), snoozeRoom(), createInboxFollowUp() | | Room export | exportRoomMarkdown(roomId), exportRoomPdf(roomId) | | Custom domains (admin) | listCustomDomains(), createCustomDomain(), … | | Embed config (admin) | getEmbedConfig(), updateEmbedConfig() | | Quiet hours | getQuietHoursPreferences(), updateQuietHoursPreferences() | | Digest preferences | getDigestPreferences(), updateDigestPreferences() | | Agent handoff | getRoomHandoff(), requestRoomHandoff(), resolveRoomHandoff() | | Agent queue | getAgentQueue(), claimAgentTask(), resolveAgentTask() | | Feature flags (P12-J) | getFeatureFlags() — backoff applied on room session connect | | Public host / embed | getPublicHostConfig(), getPublicEmbedConfig() |

Docs in monorepo: docs/README.md · deploy: docs/operations/open-beta-deploy-guide.md

Pusher Channels parity (P9)

FluxyChat maps Pusher Channels features to rooms + JWT. Full matrix: docs/pusher-channels-parity.md.

| Feature | SDK API | |---------|---------| | Presence / subscription count | WS events: subscription_succeeded, member_joined, member_left, subscription_count | | Cache channel | connect(roomId, { cache: true }) | | E2E encrypted room | getRoomE2eKey(roomId) + encrypted sends | | User channel | signIn({ userId, roles, ttlSeconds }), connectUser(), triggerUserEvent(), useUserChannel() | | Multi-room HTTP trigger | triggerEvents({ roomIds, name, data, excludeSocketId }) | | Exclude sender | excludeSocketId on trigger (no connection.socketId in the SDK) | | Connection state | connectionState, state_change event | | Global binding | connection.onAnyEvent() / connection.offAnyEvent(), useChat({ onAnyEvent }) | | Watchlist | listWatchlist(), addWatchlistTarget(), removeWatchlistTarget() | | Terminate connections | terminateUserConnections(userId) | | Public room | Room type: "public" — any project member may connect (JWT still required) |

// signIn() mints a member JWT using the apiKey configured on the client
const signed = await client.signIn({ userId: "alice", roles: ["member"], ttlSeconds: 3600 });
// For React: prefer the `useUserChannel` hook  it wraps the WS lifecycle.
// For non-React: use `client.connectUser()` directly (returns a raw WebSocket).
const userWs = client.connectUser(signed.userId);
userWs.onmessage = (event) => console.log("user-channel:", event.data);

await client.triggerEvents({
  roomIds: ["lobby", "scores"],
  name: "leaderboard",
  data: { top: 3 },
});

// onAnyEvent lives on the room connection, not the client
const conn = client.connectRoom("lobby");
conn.onAnyEvent((type, payload) => {
  if (type.startsWith("client-")) return;
});
// Verified against @fluxy-chat/[email protected]  2026-06-26
import { useUserChannel } from "@fluxy-chat/sdk";

function Inbox({ userId }: { userId: string }) {
  const { events, connectionState } = useUserChannel({ userId });
  // …
}

P10 — Sendbird / Sent / remaining Pusher

See docs/competitive-parity-p10.md.

| Feature | SDK API | |---------|---------| | Live channel stats | getRoomLive(roomId) | | Pin message | pinMessage(roomId, messageId \| null) | | Terminate one socket | terminateRoomConnection(roomId, socketId) | | Poll message | createPoll(), votePoll(), getPoll() — WS poll_updated | | Block user (global) | blockUser(), unblockUser(), listBlocks() | | Guest open channel | FluxyChatClient.joinPublicRoomAsGuest(baseUrl, roomId) | | Pusher channel auth | authorizeChannel(socketId, roomIdOrChannel) | | Message translation | translateMessage(messageId, targetLang, sourceLang?) | | Delivery receipts | markMessageDelivered(), getMessageDeliveries() — WS delivery_updated | | FCM push devices | registerPushDevice(), unregisterPushDevice(), listPushDevices() | | Sent contact sync | syncSentContact(e164, userId?) | | SMS OTP login | FluxyChatClient.requestSmsOtp() / verifySmsOtp() (API key) | | Supergroup shards | PATCH /rooms/:id { shardCount: 4 } — see docs/supergroup-room-sharding.md |

const guest = await FluxyChatClient.joinPublicRoomAsGuest(workerUrl, "lobby");
const guestClient = new FluxyChatClient({
  baseUrl: workerUrl,
  userId: guest.userId,
  token: guest.token,
});
const channelAuth = await client.authorizeChannel(socketId, "private-room-lobby");
await client.translateMessage(messageId, "it");
await client.markMessageDelivered(messageId);
await client.registerPushDevice("fcm", fcmToken);

Architecture features

FluxyChat includes a full-stack adapter system, streaming markdown renderer, card builder, and AI tool presets — all designed for multi-platform chat deployments.

| Feature | What it does | |---------|-------------| | Multi-platform adapters | Pluggable adapter system (Web, WhatsApp, Telegram, Slack, Discord, Teams, Email, SMS, Webhook, Matrix) with unified thread ID encoding and channel mapping | | Streaming markdown | Real-time markdown rendering with table buffering, code fence tracking, and inline marker healing for partial bold/strikethrough/backtick sequences | | Card builder | Composable card elements (Text, Button, Image, Divider, Table, Fields) with renderers for fallback text, Markdown, Slack Block Kit, and Teams Adaptive Cards | | AI tool presets | Pre-configured tool groups (reader, messenger, moderator) with per-tool approval gates for enterprise governance | | Tool overrides | Customize tool descriptions, titles, and approval requirements per agent profile without duplicating tool code | | Message format | Canonical mdast AST format for messages, with serialization/deserialization and typed stream chunks (markdown_text, task_update, plan_update) | | SentMessage factory | Post methods return objects with .edit(), .delete(), .addReaction(), .removeReaction() for cleaner message lifecycle management |

// Multi-platform adapter example
import { getAdapter, dispatchThreadEvent, dispatchMessageEvent } from "@fluxy-chat/sdk";

const adapter = getAdapter("web");
const threadId = adapter.encodeThreadId({ userId, roomId }); // "web:{userId}:{roomId}"

// Streaming markdown
import { StreamingMarkdownRenderer } from "@fluxy-chat/sdk";
const renderer = new StreamingMarkdownRenderer();
renderer.push("**bold** and `code`");
const html = renderer.getHtml(); // renders incrementally

// Card builder
import { Card, Text, Button, cardToMarkdown } from "@fluxy-chat/sdk";
const card = Card(Text("Hello"), Button("Click me", "https://example.com"));
const markdown = cardToMarkdown(card);

P22–P25: AI-Native Architecture (2026-07)

Adopted from the Vercel Chat SDK and AI SDK architecture. See ROADMAP_EXECUTION.md for full details.

P22 — Adapter Pattern, Streaming Markdown, Cards, Tool Presets

| Feature | SDK export | |---------|------------| | Multi-platform adapters | getAdapter(slug), listAdapters(), BaseAdapter | | WebAdapter | Registered by default in worker | | FormatConverter | toAst(text), fromAst(ast), renderPostable(message) | | StreamingMarkdownRenderer | new StreamingMarkdownRenderer().push(), .getHtml(), .finish() | | Card builder (function API) | Card, Section, Text, Button, LinkButton, Actions, Image, Divider, Field, Fields, Table, CardLink | | Card builder (JSX) | /** @jsxImportSource @fluxy-chat/sdk */ — custom JSX runtime, no React needed | | Card rendering | cardToMarkdown(card), cardToFallbackText(card) | | AI tool presets | getToolPreset("reader" \| "messenger" \| "moderator") | | Tool overrides | applyToolOverrides(tools, overrides) | | Concurrency strategies | drop, queue, debounce, burst, concurrent | | Message format | mdast AST canonical format, StreamChunk union type | | Serialization | toJSON() / fromJSON() with _type discriminator | | SentMessage factory | .edit(), .delete(), .addReaction(), .removeReaction() | | Transcripts API | append(), list(), count(), delete() | | Custom emoji | createEmoji(), getEmoji() with platform-specific maps | | Callback URLs | Encode callback tokens in button values for server-side routing | | Errors | ChatError, RateLimitError, LockError, NotImplementedError | | Logger | ConsoleLogger with child loggers and log levels | | Thread state | Per-thread key-value with TTL | | Mock adapter | MockAdapter for testing |

P23 — AI SDK Core Features

| Feature | SDK export | |---------|------------| | Stream resumption | client.resumeStream(streamId), client.getActiveStreams(roomId) | | Human-in-the-loop approval | needsApproval flag, approval workflow UI cards | | MCP client | createMcpClient({ transport, url }).listTools(), .listResources(), .readResource() | | MCP tool conversion | convertMcpTools(mcpTools) → FluxyChat tool definitions | | LLM middleware | wrapLanguageModel(), transformParams(), wrapGenerate(), wrapStream() | | Middleware composition | composeMiddleware([mw1, mw2, ...]) | | DevTools web UI | Visual inspector for LLM calls, tool calls, token usage | | OpenTelemetry | GenAI semantic conventions, @ai-sdk/otel compatible | | Per-step performance | Model output timing, streaming speed, tool execution time | | WorkflowAgent | new WorkflowAgent({ agentId, model, tools }).step(), .run() | | Typed runtime context | defineContext(schema) for type-safe cross-step data | | Sandbox sessions | SandboxSession for isolated code execution | | Realtime voice | Bidirectional voice-to-voice AI with tool calling | | Scoped tool context | Per-tool secret/config isolation via contextSchema |

P24 — AI SDK Medium Features

| Feature | SDK export | |---------|------------| | Tool call streaming | onInputStart / onInputDelta / onInputAvailable callbacks | | Multi-step loop control | maxSteps, stopWhen, isStepCount, hasToolCall, isLoopFinished | | Provider-defined tools | Provider supplies schema, developer provides execute | | Provider-executed tools | Server-side tools (web search, code execution) | | Pluggable transport | DefaultChatTransport, ChatTransport interface | | Typed UIMessage | Generic type parameter for end-to-end type safety | | Data parts | Stream arbitrary typed data alongside text | | extractReasoningMiddleware | extractReasoningMiddleware() | | RAG middleware | createRagMiddleware({ retrieve }) | | Provider-level middleware | wrapProvider(provider, [middleware]) | | Image generation | generateImage() API | | Speech generation | generateSpeech() (TTS) | | useObject hook | useObject() — stream structured JSON from LLM | | Structured output | generateObject(), streamObject() with Zod schemas | | MCP Apps | Sandboxed iframe rendering of tool UIs | | Slash commands | Cross-platform /command handling |

P25 — AI SDK Low Features

| Feature | SDK export | |---------|------------| | experimental_throttle | Configurable render throttle for streaming | | smoothStream | Flicker-free text streaming | | Ephemeral messages | User-only visible with DM fallback | | Cosine similarity | cosineSimilarity(a, b) utility | | Strict tool calling | strict: true schema enforcement | | sendAutomaticallyWhen | Auto-submit when all tool results available | | Sensitive context controls | Prevent secrets in telemetry |

Guides with examples: docs/guides/

Product links

Support

Questions: [email protected] · Issues: github.com/AlessandroFare/fluxychat/issues

License

MIT — see LICENSE.