mirror of
https://github.com/meshtastic/web.git
synced 2026-07-31 06:56:28 -04:00
docs(sdk,sdk-react): expand README for npm publish
Both packages publish to npm with `files: [..., "README.md", ...]` so the README is the landing page. Old versions were one-line stubs. - @meshtastic/sdk: explain feature-client surface, subpath exports (/transport, /protobuf, /testing), the fake transport for tests, and the migration story from @meshtastic/core (one SDK, separate transport packages, framework-agnostic core). - @meshtastic/sdk-react: single-client + registry quickstarts, grouped hook reference, and why the React bindings split out of core. Shim note carried forward in the sdk README: legacyMeshDevice export stays until the web client finishes migrating; new code should target MeshClient directly.
This commit is contained in:
@@ -1,20 +1,20 @@
|
||||
# @meshtastic/sdk-react
|
||||
|
||||
React hooks and provider for `@meshtastic/sdk`.
|
||||
|
||||
## Install
|
||||
React hooks for [`@meshtastic/sdk`](https://www.npmjs.com/package/@meshtastic/sdk). Wraps the SDK's
|
||||
signal-based state in hooks that only re-render when the data they touch changes.
|
||||
|
||||
```sh
|
||||
pnpm add @meshtastic/sdk @meshtastic/sdk-react @meshtastic/transport-web-serial
|
||||
```
|
||||
|
||||
## Quickstart
|
||||
## One device
|
||||
|
||||
If your app talks to a single radio at a time, wrap your tree in `MeshProvider` and you're done:
|
||||
|
||||
```tsx
|
||||
import { MeshClient } from "@meshtastic/sdk";
|
||||
import { MeshClient, ChannelNumber } 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 });
|
||||
@@ -31,11 +31,101 @@ function App() {
|
||||
function Status() {
|
||||
const { status, myNodeNum } = useDevice();
|
||||
const { messages, send } = useChat(ChannelNumber.Primary);
|
||||
return <div>{status} / {myNodeNum} / {messages.length} msgs</div>;
|
||||
return (
|
||||
<div>
|
||||
{status} · node #{myNodeNum} · {messages.length} msgs
|
||||
<button onClick={() => send("hello mesh")}>send</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
All hooks are read-only against a single `MeshClient` instance supplied through context. Commands are returned as stable functions.
|
||||
## Several devices
|
||||
|
||||
For apps that hold multiple connections at once — say, a desktop dashboard with a USB device plus a
|
||||
Bluetooth one — use the registry provider instead. Hooks default to the "active" client, and you can
|
||||
target a specific one by id when you need to.
|
||||
|
||||
```tsx
|
||||
import { MeshRegistry } from "@meshtastic/sdk";
|
||||
import { MeshRegistryProvider, useNodes } from "@meshtastic/sdk-react";
|
||||
|
||||
const registry = new MeshRegistry();
|
||||
registry.register("usb-1", usbClient);
|
||||
registry.register("ble-1", bleClient);
|
||||
registry.setActive("usb-1");
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<MeshRegistryProvider registry={registry}>
|
||||
<Nodes />
|
||||
</MeshRegistryProvider>
|
||||
);
|
||||
}
|
||||
|
||||
function Nodes() {
|
||||
const nodes = useNodes(); // active client
|
||||
return <div>{nodes.length} nodes</div>;
|
||||
}
|
||||
```
|
||||
|
||||
## Why this is a separate package
|
||||
|
||||
The SDK used to live in `@meshtastic/core`, and its React conventions (effects, refs, a few hook
|
||||
helpers) were baked right into protocol code. That made it impossible to ship the SDK to non-React
|
||||
consumers — Node CLIs, Deno scripts, native shells — without dragging React along.
|
||||
|
||||
When we split that up, the React bits moved here. Now the layering is straightforward:
|
||||
|
||||
- `@meshtastic/sdk` — protocol, state, transports. No React, no DOM.
|
||||
- `@meshtastic/sdk-react` — this. Hooks and providers, nothing else.
|
||||
- `@meshtastic/transport-*` — per-runtime byte transports.
|
||||
|
||||
If you're not using React, you don't need this package at all. Read `@meshtastic/sdk` directly.
|
||||
|
||||
## Hooks
|
||||
|
||||
Most components only need two or three of these. The full list is here for reference:
|
||||
|
||||
**Plumbing**
|
||||
|
||||
- `useClient()` — the client from `MeshProvider`
|
||||
- `useActiveClient()` — the active client from a `MeshRegistryProvider`
|
||||
- `useClientById(id)` — a specific client from the registry
|
||||
- `useMeshRegistry()` / `useOptionalMeshRegistry()` — the registry itself
|
||||
- `useSignal(signal)` / `useSignalValue(signal)` — bridge any SDK signal into React state
|
||||
|
||||
**Connection**
|
||||
|
||||
- `useConnection()` — status + lifecycle helpers
|
||||
- `useConnectionProgress()` — live "configuring" progress with per-section counters (handy for
|
||||
building a connecting overlay)
|
||||
- `useMeshDevice()` — convenience wrapper around the legacy `MeshDevice` shim
|
||||
|
||||
**Device & node state**
|
||||
|
||||
- `useDevice()`
|
||||
- `useNodes()` / `useNode(num)`
|
||||
- `useNodeError(num)` / `useNodeErrors()` / `useHasNodeError(num)`
|
||||
|
||||
**Messaging**
|
||||
|
||||
- `useChat(channel)` — channel messages
|
||||
- `useDirectChat(peer)` — DMs
|
||||
- `useDraft(...)` — draft messages
|
||||
|
||||
**Config**
|
||||
|
||||
- `useChannels()` / `useChannel(idx)`
|
||||
- `useConfig()` / `useModuleConfig()` / `useIsRegionUnset()`
|
||||
- `useConfigEditor()` — staged edits with dirty tracking
|
||||
|
||||
Each hook reads from a single signal, so updates only re-render components that actually use that
|
||||
data.
|
||||
|
||||
## Source / issues
|
||||
|
||||
<https://github.com/meshtastic/web>
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
# @meshtastic/sdk
|
||||
|
||||
Domain-driven SDK for Meshtastic devices. Feature slices with signals-backed reactive state.
|
||||
|
||||
Replaces `@meshtastic/core`. During migration a shim layer re-exports the legacy `MeshDevice` class so existing consumers keep building — see `src/shim/`.
|
||||
|
||||
## Install
|
||||
TypeScript SDK for talking to [Meshtastic](https://meshtastic.org) radios. Works in the browser, in
|
||||
Node, and in Deno. Pick a transport, hand it a `MeshClient`, and you've got reactive access to the
|
||||
device's chat, nodes, channels, config, and telemetry.
|
||||
|
||||
```sh
|
||||
pnpm add @meshtastic/sdk @meshtastic/transport-web-serial
|
||||
```
|
||||
|
||||
## Quickstart
|
||||
## Quick example
|
||||
|
||||
```ts
|
||||
import { MeshClient } from "@meshtastic/sdk";
|
||||
@@ -20,20 +18,90 @@ const transport = await TransportWebSerial.create({ baudRate: 115200 });
|
||||
const client = new MeshClient({ transport });
|
||||
await client.connect();
|
||||
|
||||
client.chat.send({ text: "hello mesh" });
|
||||
console.log(client.nodes.list.value);
|
||||
client.device.status.subscribe((s) => console.log("status:", s));
|
||||
console.log("my node:", client.device.myNodeNum.value);
|
||||
console.log("nodes:", client.nodes.list.value);
|
||||
|
||||
await client.chat.send({ text: "hello mesh" });
|
||||
|
||||
client.events.onConfigComplete.subscribe(() => console.log("configured"));
|
||||
client.events.onRebooted.subscribe(() => console.log("device rebooted"));
|
||||
```
|
||||
|
||||
See the repo root [README](../../README.md) for architecture and feature slice layout.
|
||||
State is exposed as signals. Subscribe to them, or read `.value` synchronously. Commands are async and
|
||||
resolve when the device acks.
|
||||
|
||||
## Layout
|
||||
## Why this is a new package
|
||||
|
||||
If you've used Meshtastic on the web before, you've probably seen `@meshtastic/core`. That package
|
||||
mixed protocol, transports, and consumer state in one class. It worked, but it bled assumptions:
|
||||
browser apps still pulled the Node serial driver, slice state had a few React-isms baked in, and there
|
||||
wasn't a clean seam for unit testing or non-browser runtimes.
|
||||
|
||||
We split it into three pieces:
|
||||
|
||||
- `@meshtastic/sdk` (this one) owns the protocol, the queue, the codec, and the reactive state. No
|
||||
React. No DOM. No Node builtins. It runs the same everywhere.
|
||||
- `@meshtastic/transport-*` packages are thin byte adapters. Install only the ones you need. The SDK
|
||||
talks to them through a tiny `Transport` interface (`fromDevice` / `toDevice` streams plus
|
||||
`disconnect()`), so you can write your own without forking anything.
|
||||
- `@meshtastic/sdk-react` lives separately for the React hooks. Skip it if you're not using React.
|
||||
|
||||
The old `MeshDevice` class is still exported from `src/shim/` so existing `@meshtastic/core` apps can
|
||||
upgrade without a full rewrite. The shim will be removed once the web client finishes its migration —
|
||||
new code should use `MeshClient` directly.
|
||||
|
||||
## What's in the client
|
||||
|
||||
`MeshClient` is just a small composition root. The interesting bits are the feature clients hanging
|
||||
off it:
|
||||
|
||||
- `client.device` — identity, status, metadata, reboot / shutdown / factory-reset
|
||||
- `client.chat` — channel + direct messages, drafts, unread tracking
|
||||
- `client.nodes` — live node list, per-node lookups, error states
|
||||
- `client.channels` — channel config
|
||||
- `client.config` — device + module config, plus a staged-edit `ConfigEditor`
|
||||
- `client.telemetry` — environment / device / power metrics
|
||||
- `client.position` — position broadcast + node positions
|
||||
- `client.traceroute` — mesh route discovery
|
||||
- `client.files` — XModem get/put
|
||||
|
||||
Each one can be used on its own; `MeshClient` just hands them a shared transport, queue, and event
|
||||
bus.
|
||||
|
||||
## Subpath exports
|
||||
|
||||
| Import path | What's there |
|
||||
| --- | --- |
|
||||
| `@meshtastic/sdk` | `MeshClient`, feature clients, signal types |
|
||||
| `@meshtastic/sdk/transport` | The `Transport` interface and related types — use this if you're writing a custom adapter |
|
||||
| `@meshtastic/sdk/protobuf` | Re-export of `@meshtastic/protobufs` for raw packet construction |
|
||||
| `@meshtastic/sdk/testing` | `createFakeTransport()` for unit tests |
|
||||
|
||||
## Testing without a radio
|
||||
|
||||
```ts
|
||||
import { MeshClient } from "@meshtastic/sdk";
|
||||
import { createFakeTransport } from "@meshtastic/sdk/testing";
|
||||
|
||||
const { transport, respond } = createFakeTransport();
|
||||
const client = new MeshClient({ transport });
|
||||
|
||||
respond.withMyNodeInfo({ myNodeNum: 42 });
|
||||
respond.withConfigCompleteId(1);
|
||||
|
||||
// client.device, client.nodes, etc. are now populated.
|
||||
```
|
||||
src/
|
||||
core/ # shared kernel: client, transport, event-bus, queue, xmodem, signals, logging, packet-codec
|
||||
features/ # DDD feature slices (device, chat, nodes, channels, config, telemetry, position, traceroute, files)
|
||||
shim/ # legacy MeshDevice compatibility exports (removed in Phase C)
|
||||
```
|
||||
|
||||
The fake transport is the same one the SDK's own integration tests use.
|
||||
|
||||
## React?
|
||||
|
||||
[`@meshtastic/sdk-react`](https://www.npmjs.com/package/@meshtastic/sdk-react).
|
||||
|
||||
## Source / issues
|
||||
|
||||
<https://github.com/meshtastic/web>
|
||||
|
||||
## License
|
||||
|
||||
|
||||
Reference in New Issue
Block a user