Skip to content

poolse-hq/js-sdk

Repository files navigation

poolse-js

TypeScript SDKs for the poolse Chat-as-a-Service backend.

This repository is a pnpm monorepo. Four packages, each usable independently:

Package What Use when
@poolse/sdk Headless TypeScript SDK. REST + WebSocket + offline queue. No React, no DOM. Building for Node, vanilla JS, mobile (RN), or you want zero UI opinions.
@poolse/react Headless React hooks built on @poolse/sdk. Provider + useMessages / useTyping / usePresence / etc. No UI. You want real-time wired up but you're building your own UI from scratch.
@poolse/react-ui Plug-and-play React components built on @poolse/react. CSS-variable theming + render-slot escape hatches. You want a working chat in 5 minutes; eject to lower layers later if needed.
@poolse/react-native Plug-and-play React Native components — same component names + prop shapes as react-ui, JS theme tokens, Expo-ready. You're shipping an Expo / bare React Native app.

You can mix and match. <ConversationView> uses the hooks from @poolse/react, which use the client from @poolse/sdk — drop down a layer at any point without re-architecting.

Quickstart (5-minute chat — web)

pnpm add @poolse/sdk @poolse/react @poolse/react-ui

React Native (Expo)

npx expo install \
  @poolse/sdk @poolse/react @poolse/react-native \
  react-native-svg \
  react-native-markdown-display \
  react-native-safe-area-context \
  expo-clipboard \
  expo-image-picker \
  expo-document-picker \
  expo-image-manipulator

All peer dependencies are required — see @poolse/react-native README for what each one powers and the iOS Info.plist keys you'll need.

import '@poolse/react-ui/styles.css';
import { PoolseProvider } from '@poolse/react';
import { ConversationView } from '@poolse/react-ui';

const config = {
  apiUrl: import.meta.env.VITE_POOLSE_URL ?? 'http://localhost:4000',
  getToken: async () => fetchJwtFromYourBackend(),
};

export default function App() {
  return (
    <PoolseProvider config={config}>
      <ConversationView conversationId="..." />
    </PoolseProvider>
  );
}

Hooks-only (custom UI, real-time wired)

import { PoolseProvider, useMessages, useTyping } from '@poolse/react';

function Chat({ conversationId }: { conversationId: string }) {
  const { messages, send, loadMore, hasMore } = useMessages(conversationId);
  const { typing, signalTyping } = useTyping(conversationId);

  return (
    <YourCustomChatUI
      messages={messages}
      typing={typing}
      onSend={(body) => send({ body })}
      onInput={signalTyping}
    />
  );
}

Headless core only (no React)

import { Poolse } from '@poolse/sdk';

const chat = new Poolse({ apiUrl, getToken });

const conv = chat.realtime.conversation('conv-uuid');
conv.onMessage((msg) => render(msg));
conv.sendTyping();

await chat.conversations.one('conv-uuid').messages.send({ body: 'hello' });

Customization

@poolse/react-ui defaults are driven by CSS variables — rebrand without touching JS:

:root {
  --poolse-color-primary: #ff5722;
  --poolse-color-self-bubble: #ff5722;
  --poolse-radius: 8px;
}

Need more control? Three escape hatches in order:

  1. Render slots — swap a specific subcomponent:
    <ConversationView renderMessage={(msg, currentUserId) => <MyBubble {...} />} />
  2. Component composition — use individual pieces (<MessageBubble>, <MessageComposer>, <TypingIndicator>) directly.
  3. Drop to @poolse/react — write your own component using the same hooks <ConversationView> uses. No fork.

Wiring user identity

The SDK doesn't store user names or avatars — that's your app's data. Pass userResolver once on the provider and every sender label, mention dropdown, member list, and read-receipt tooltip lights up automatically:

<PoolseProvider
  config={{
    apiUrl,
    getToken,
    userResolver: async (userId) => {
      const u = await fetch(`/api/users/by-poolse-id/${userId}`).then((r) => r.json());
      return { displayName: u.full_name, avatarUrl: u.avatar_url };
    },
  }}
>

See @poolse/react for caching semantics.

What's in v1

  • A11y baselinerole="log" messages, live regions for typing + status + connection, combobox ARIA on mentions, focus management on thread + lightbox, scoped prefers-reduced-motion.
  • Mobile baseline — 44px touch targets, 16px composer (no iOS auto-zoom), safe-area-inset on overlays + composer, tap-reveal for message actions, full-screen thread pane <760px.
  • Attachments — multi-file picker, drag-and-drop a batch onto the conversation, XHR progress per item with cancel + retry-on-error dismissal, image lightbox with ESC + click-outside + body-scroll lock.

Development

All work runs inside Docker — nothing in this project should be installed on the host (matches the backend repo's rule).

docker compose run --rm node pnpm install      # one-time
docker compose run --rm node pnpm check        # everything CI runs (typecheck + lint + format + test + build)
docker compose run --rm node pnpm test         # all packages
docker compose run --rm node pnpm -F @poolse/sdk test    # just one package
docker compose run --rm node pnpm build        # build all packages

Layout

poolse-js-sdk/
├── packages/
│   ├── sdk/            @poolse/sdk
│   ├── react/          @poolse/react
│   ├── react-ui/       @poolse/react-ui
│   └── react-native/   @poolse/react-native
├── tsconfig.base.json      ← shared base for all packages
├── eslint.config.js        ← shared (flat config, ESLint 9)
├── .prettierrc.json
├── docker-compose.yml
└── Dockerfile.dev

About

Realtime chat SDK — TypeScript core + React and React Native components. Messages, presence, typing, reactions, threads, attachments, signed webhooks. MIT. Sendbird / Stream / Pusher / TalkJS alternative.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors