Dan Ditomaso f899c97ac8 feat: PR #12 Phase C — delete packages/core, retarget transports to @meshtastic/sdk, bump majors
The legacy `@meshtastic/core` package is gone. The six transport-*
packages and the web app no longer depend on it; everything routes
through `@meshtastic/sdk`.

Transport packages (transport-deno, transport-http, transport-node,
transport-node-serial, transport-web-bluetooth, transport-web-serial):
- package.json deps swap `@meshtastic/core: workspace:*` for
  `@meshtastic/sdk: workspace:*`.
- src/transport.ts + src/transport.test.ts imports point at
  `@meshtastic/sdk` (the `Types` and `Utils` namespaces are still
  exported from the SDK so source code is otherwise unchanged).
- README.md examples updated to import from `@meshtastic/sdk`.

apps/web:
- Drops the leftover `@meshtastic/core` workspace dep; nothing in
  apps/web/src imports from it.

@meshtastic/sdk:
- README description loses the "Replaces @meshtastic/core" suffix —
  there's nothing left to replace.
- Three legacy shim files keep their re-exports but their docstrings
  drop the "Phase-A shim, removed in Phase C" framing. The MeshDevice
  facade survives because the web app's `connection.factoryResetDevice()`
  / `connection.reboot()` / etc. callsites still go through it; new
  consumers should reach into `client.config` / `client.chat` / etc.
- New scripts/rename-dts.mjs is a postbuild step that renames tsdown's
  hashed entry-point dts outputs (`mod-<hash>.d.ts` etc.) back to their
  canonical names so package.json `types` and downstream dts-bundlers
  can find them. Internal chunk dts files (e.g. `Transport-<hash>.d.ts`)
  are intentionally NOT renamed because mod.d.ts imports them by path.
- build:npm runs tsdown then the rename script.

Version bumps (signal: now require @meshtastic/sdk):
- @meshtastic/sdk             0.1.0 -> 1.0.0
- @meshtastic/sdk-react       0.1.0 -> 1.0.0
- @meshtastic/sdk-storage-sqlocal 0.1.0 -> 1.0.0
- @meshtastic/transport-http       0.2.5 -> 1.0.0
- @meshtastic/transport-web-serial 0.2.5 -> 1.0.0
- @meshtastic/transport-web-bluetooth 0.1.5 -> 1.0.0
- @meshtastic/transport-deno       0.1.1 -> 1.0.0
- @meshtastic/transport-node       0.0.2 -> 1.0.0
- @meshtastic/transport-node-serial 0.0.2 -> 1.0.0

Workflows: nothing referenced packages/core directly (only the
release-packages.yml glob which already collapsed in the apps/web
move). README packages table loses the legacy `packages/core` row.

Verified: web build clean, all four package suites green
(web 236, sdk 65, sdk-react 8, storage 30).

The transport packages' dist build is currently blocked by a tsdown
cross-chunk dts resolution glitch where the `Types` namespace import
can't follow `mod.d.ts`'s reference to the internal `Transport-<hash>`
chunk. Runtime is fine — only the published-types path is affected,
and transport packages publish via their own release flow. Logged as
follow-up.
2026-04-26 12:16:57 -04:00
2025-07-07 11:49:18 -04:00
2025-07-10 12:28:23 -04:00

Meshtastic Web Monorepo

CI CI CLA assistant Fiscal Contributors Vercel

Overview

This monorepo consolidates the official Meshtastic web interface, the domain-driven JavaScript SDK that drives it, and a set of runtime-specific transport packages. Everything you need to read state from or send commands to a Meshtastic device lives here.

Note

You can find the main Meshtastic documentation at https://meshtastic.org/docs/introduction/.

Packages

All projects live under packages/.

Package Purpose
packages/sdk Framework-agnostic TypeScript SDK. Domain-driven feature slices (device, chat, nodes, channels, config, telemetry, position, traceroute, files) built around a MeshClient orchestrator with @preact/signals-core reactive state.
packages/sdk-react React hooks + MeshProvider on top of @meshtastic/sdk. Wraps signals in useSyncExternalStore for concurrent-safe renders.
apps/web Reference React web client. Hosted at client.meshtastic.org.
packages/ui Shared Radix + Tailwind component library.
packages/protobufs Generated TypeScript stubs from meshtastic/protobufs, produced via buf generate. Source of truth for every wire-level type.
packages/transport-http HTTP transport for devices exposing a network interface.
packages/transport-web-bluetooth Web Bluetooth transport for BLE-capable devices (browsers).
packages/transport-web-serial Web Serial transport for USB-serial devices (browsers).
packages/transport-node TCP transport for Node.js.
packages/transport-node-serial Serial transport for Node.js.
packages/transport-deno TCP transport for Deno.
packages/transport-mock In-memory transport for tests.

All publishable packages ship to both JSR and NPM.

Architecture

@meshtastic/sdk organises its source by feature slice. Each slice follows the same DDD layout:

features/<slice>/
  domain/          # entities & value objects — pure TypeScript types
  application/     # use-cases (SendTextUseCase, FavoriteNodeUseCase, …)
  infrastructure/  # protobuf ↔ domain mappers, admin-message adapters
  state/           # signals-backed reactive stores
  <Slice>Client.ts # public facade exposing readable signals + command methods
  index.ts

The shared kernel under packages/sdk/src/core/ owns:

  • client/MeshClient, the thin orchestrator that owns the transport, queue, event bus, and one instance of every slice client.
  • transport/ — the Transport interface every transport-* package implements.
  • event-bus/ — typed pub/sub channels populated by the packet codec.
  • packet-codec/ — frame parser (0x94 0xC3), FromRadio decoder, portnum router.
  • queue/, xmodem/ — packet ack/timeout pipeline and file-transfer protocol.
  • signals/ — signal and keyed-collection helpers consumed by every slice.
  • logging/tslog factory used consistently by every class.
  • identifiers/, errors/ — small primitives shared across slices.

The protobuf boundary is strict: wire messages enter through the packet codec, get mapped into domain entities inside features/*/infrastructure/*Mapper.ts, and signals only ever expose the domain shape.

 Transport   ─▶   Packet codec   ─▶   EventBus   ─▶   Slice infrastructure
                                                            │
                                                            ▼
                                                    Signals (state)  ─▶  sdk-react hooks  ─▶  UI
                                                            ▲
                                                            │
 Slice application (use-cases)  ─▶   MeshClient.sendPacket  ─▶   Queue   ─▶   Transport

Expected domain errors are returned as Result<T, E> via better-result; exceptions are reserved for programmer errors and truly exceptional conditions.

Getting Started

Prerequisites

You need pnpm installed. If you plan to regenerate protobufs, also install the Buf CLI.

Setup

git clone https://github.com/meshtastic/web.git
cd web
pnpm install

Run the web client

pnpm --filter @meshtastic/web dev

Build everything

pnpm -r build

Run tests

pnpm -r test

Lint + format

pnpm check
pnpm check:fix

Developing

Adding a new feature slice to @meshtastic/sdk

  1. Create packages/sdk/src/features/<slice>/ with domain/, application/, infrastructure/, state/ subdirectories plus an index.ts barrel.
  2. Implement a signals-backed store in state/.
  3. Subscribe to the relevant EventBus channel(s) inside a <Slice>Client.ts class and write mapped domain entities to the store.
  4. Wire the new client into MeshClient and re-export types from packages/sdk/mod.ts.
  5. Add vitest coverage: domain invariants, use-cases against createFakeTransport(), and round-trip mapper fixtures.
  6. If the slice has React callers, add a matching hook under packages/sdk-react/src/hooks/.

Adding a new transport

Implement the Transport interface exported from @meshtastic/sdk/transport:

interface Transport {
  toDevice: WritableStream<Uint8Array>;
  fromDevice: ReadableStream<DeviceOutput>;
  disconnect(): Promise<void>;
}

The SDK does the framing and decoding — transports only supply raw bytes.

Testing

Vitest is wired at the repo root and picks up packages/* projects. The SDK ships @meshtastic/sdk/testing with createFakeTransport() for wiring tests without real hardware.

Publishing

Each publishable package has build:npm / publish:npm / prepare:jsr / publish:jsr scripts. See each package's package.json for details.

Repository activity

Project Repobeats
Meshtastic Web Alt

Feedback

If you encounter any issues, please report them in our issues tracker. Your feedback helps improve the stability of future releases.

Star history

Star History Chart

Contributors

License

GPL-3.0-only. See LICENSE.

Description
No description provided
Readme GPL-3.0 25 MiB
Languages
TypeScript 98.5%
CSS 0.6%
JavaScript 0.5%
Python 0.3%