Files
web/packages/sdk-react
Dan Ditomaso 4b146c4d4f feat(sdk,web): drafts persisted in SDK chat slice (SQLite-backed)
Moves per-conversation draft text out of the legacy Zustand messageStore
into the SDK chat slice so drafts share the same persistence + signal
machinery as messages. MessageInput now binds directly to the SDK; the
legacy `useMessages().getDraft/setDraft/clearDraft` API is no longer
called from the input.

packages/sdk
- New DraftRepository port + InMemoryDraftRepository default.
- ChatClient.drafts namespace: get(key) returns a ReadonlySignal<string>;
  set/clear keyed by ConversationKey.
- ChatClient.send auto-clears the draft for the resolved conversation on
  success (parity with prior Zustand clearDraft-on-send behavior).
- Lazy hydrate from the DraftRepository on first read of a conversation.
- 3 new tests in ChatClient.drafts.test.ts.

packages/sdk-react
- New useDraft(conversation) hook returning { text, setText, clear }.

packages/sdk-storage-sqlocal
- New `drafts` table (device_id + conversation_key composite PK, text,
  updated_at). Drizzle schema in src/schema/drafts.ts.
- Migration v2 in src/schema/migrations.ts creates the table on first
  open of an existing v1 DB.
- SqlocalDraftRepository implementing DraftRepository: load/save/clear/
  loadAll, scoped by device_id, upsert on conflict, delete on empty save.
- 6 new tests covering save/load round-trip, empty-string deletion,
  upsert, multi-device isolation, loadAll.

packages/web
- useConnections wires the SqlocalDraftRepository alongside the existing
  SqlocalMessageRepository per registered MeshClient.
- MessageInput accepts `conversation: ConversationKey` instead of the
  prior `to: Types.Destination` — fixes the legacy bug where every
  broadcast channel shared a single draft slot.
- MessagesPage passes the appropriate ConversationKey for direct/
  broadcast chats.
- MessageInput.test.tsx rewritten to mock useDraft from sdk-react.

Test counts: sdk 39 (+3), sdk-storage-sqlocal 18 (+6), web 294 unchanged.
Production Vite build clean.
2026-04-24 22:10:32 -04:00
..

@meshtastic/sdk-react

React hooks and provider for @meshtastic/sdk.

Install

pnpm add @meshtastic/sdk @meshtastic/sdk-react @meshtastic/transport-web-serial

Quickstart

import { MeshClient } from "@meshtastic/sdk";
import { MeshProvider, useDevice, useChat } from "@meshtastic/sdk-react";
import { TransportWebSerial } from "@meshtastic/transport-web-serial";
import { ChannelNumber } from "@meshtastic/sdk";

const transport = await TransportWebSerial.create({ baudRate: 115200 });
const client = new MeshClient({ transport });
await client.connect();

function App() {
  return (
    <MeshProvider client={client}>
      <Status />
    </MeshProvider>
  );
}

function Status() {
  const { status, myNodeNum } = useDevice();
  const { messages, send } = useChat(ChannelNumber.Primary);
  return <div>{status} / {myNodeNum} / {messages.length} msgs</div>;
}

All hooks are read-only against a single MeshClient instance supplied through context. Commands are returned as stable functions.

License

GPL-3.0-only.