Move docs/ package mirror into document-navigator plugin
Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
# @suaveplan/broadcast-channel - Typed cross-tab messaging built on the BroadcastChannel API — leader election, tab presence, Zod-validated boundaries, OpenTelemetry-instrumented hot paths, StorageLike-backed fallback for Safari < 15.4. Browser-tier.
|
||||
|
||||
Typed cross-tab messaging built on the Web `BroadcastChannel` API. Browser-tier package — leader election, tab presence and heartbeats, message-type handler registry, Zod-validated boundaries, OpenTelemetry-instrumented hot paths, deterministic `Clock` / `Rng` / `LoggerLike` injection, and a `StorageLike`-backed fallback transport for Safari < 15.4 (and any sandbox where the native `BroadcastChannel` is unavailable).
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
## Documentation tree
|
||||
|
||||
- [ask](./src/ask/ask.md) — `AskController` is the request-side engine for the cross-tab request/response primitive layered on top of `TypedBroadca…
|
||||
- [ask](./src/ask/ask.md) — `AskController` is the request-side engine for the cross-tab request/response primitive layered on top of `TypedBroadca…
|
||||
- [responder](./src/ask/responder.md) — `AskResponderRegistry` is the response-side counterpart to `AskController`. It maps an inbound `handlerKey` to the sing…
|
||||
- [channel](./src/channel/channel.md) — `TypedBroadcastChannel` is the high-level cross-tab messaging object exported by `@suaveplan/broadcast-channel`. It wra…
|
||||
- [channel](./src/channel/channel.md) — `TypedBroadcastChannel` is the high-level cross-tab messaging object exported by `@suaveplan/broadcast-channel`. It wra…
|
||||
- [heartbeat](./src/channel/heartbeat.md) — `HeartbeatRunner` is a tiny lifecycle helper that owns the pair of `setInterval` timers a `TypedBroadcastChannel` needs…
|
||||
- [errors](./src/errors/codes.md) — This module declares the stable error-code registry for `@suaveplan/broadcast-channel`. Every error the package throws…
|
||||
- [codes](./src/errors/codes.md) — This module declares the stable error-code registry for `@suaveplan/broadcast-channel`. Every error the package throws…
|
||||
- [id](./src/id/id.md) — `generateId` is the shared 16-character lowercase-hex identifier generator used for tab IDs and per-message IDs through…
|
||||
- [id](./src/id/id.md) — `generateId` is the shared 16-character lowercase-hex identifier generator used for tab IDs and per-message IDs through…
|
||||
- [logger](./src/logger/noop.md) — `noopLogger` is a shared zero-cost `LoggerLike` implementation used as the default by `TypedBroadcastChannel` and by `c…
|
||||
- [noop](./src/logger/noop.md) — `noopLogger` is a shared zero-cost `LoggerLike` implementation used as the default by `TypedBroadcastChannel` and by `c…
|
||||
- [otel](./src/otel/metrics.md) — This module declares the six OpenTelemetry counter instruments emitted by `@suaveplan/broadcast-channel`. Every counter…
|
||||
- [metrics](./src/otel/metrics.md) — This module declares the six OpenTelemetry counter instruments emitted by `@suaveplan/broadcast-channel`. Every counter…
|
||||
- [schemas](./src/schemas/messages.md) — This module declares the Zod boundary schemas for `@suaveplan/broadcast-channel`. `ChannelMessageSchema` validates ever…
|
||||
- [messages](./src/schemas/messages.md) — This module declares the Zod boundary schemas for `@suaveplan/broadcast-channel`. `ChannelMessageSchema` validates ever…
|
||||
- [local-storage](./src/transport/local-storage.md) — `createLocalStorageChannelFactory` is the `StorageLike`-backed fallback transport. Use it whenever the host lacks a nat…
|
||||
- [native](./src/transport/native.md) — `nativeChannelFactory` is a thin adapter that exposes the global `BroadcastChannel` constructor as a `ChannelLike`. Use…
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
bun add @suaveplan/broadcast-channel
|
||||
```
|
||||
|
||||
## Quick start
|
||||
|
||||
```ts
|
||||
import {
|
||||
nativeChannelFactory,
|
||||
TypedBroadcastChannel,
|
||||
} from "@suaveplan/broadcast-channel";
|
||||
|
||||
const channel = new TypedBroadcastChannel({
|
||||
config: { name: "app-bus" },
|
||||
factory: nativeChannelFactory,
|
||||
});
|
||||
|
||||
channel.open();
|
||||
channel.on<{ userId: string }>("user:signed-in", (msg) => {
|
||||
console.log(`peer tab ${msg.senderId} signed in as ${msg.payload.userId}`);
|
||||
});
|
||||
channel.send("user:signed-in", { userId: "u_123" });
|
||||
```
|
||||
|
||||
## Fallback transport (Safari < 15.4)
|
||||
|
||||
```ts
|
||||
import {
|
||||
createLocalStorageChannelFactory,
|
||||
isNativeBroadcastChannelAvailable,
|
||||
nativeChannelFactory,
|
||||
TypedBroadcastChannel,
|
||||
} from "@suaveplan/broadcast-channel";
|
||||
import { yourStorageLike } from "./storage";
|
||||
|
||||
const factory = isNativeBroadcastChannelAvailable()
|
||||
? nativeChannelFactory
|
||||
: createLocalStorageChannelFactory(yourStorageLike, {
|
||||
pollIntervalMs: 50,
|
||||
retentionMs: 30_000,
|
||||
});
|
||||
|
||||
const channel = new TypedBroadcastChannel({
|
||||
config: { name: "app-bus" },
|
||||
factory,
|
||||
});
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
- [`channel/channel`](./src/channel/channel.md) — `TypedBroadcastChannel` core.
|
||||
- [`channel/heartbeat`](./src/channel/heartbeat.md) — `HeartbeatRunner` interval pair.
|
||||
- [`errors/codes`](./src/errors/codes.md) — `BROADCAST_CHANNEL_CODES` registry + four typed error subclasses.
|
||||
- [`id/id`](./src/id/id.md) — `generateId(rng)` shared 16-hex id generator.
|
||||
- [`logger/noop`](./src/logger/noop.md) — shared no-op `LoggerLike` default.
|
||||
- [`otel/metrics`](./src/otel/metrics.md) — six OpenTelemetry counters.
|
||||
- [`schemas/messages`](./src/schemas/messages.md) — Zod boundary schemas.
|
||||
- [`transport/native`](./src/transport/native.md) — native `BroadcastChannel` adapter.
|
||||
- [`transport/local-storage`](./src/transport/local-storage.md) — `StorageLike`-backed fallback.
|
||||
- [`types/broadcast-channel`](./src/types/broadcast-channel.types.ts) — public shapes.
|
||||
|
||||
## Error codes
|
||||
|
||||
| Code | When |
|
||||
|---|---|
|
||||
| `BROADCAST_CHANNEL.CHANNEL_CLOSED` | `send()` called before `open()` or after `close()` |
|
||||
| `BROADCAST_CHANNEL.MESSAGE_MALFORMED` | inbound frame fails `ChannelMessageSchema` |
|
||||
| `BROADCAST_CHANNEL.PAYLOAD_TOO_LARGE` | outbound payload exceeds `config.maxMessageBytes` (default 1 MiB) |
|
||||
| `BROADCAST_CHANNEL.STORAGE_FAILED` | fallback-transport `StorageLike` get/set/list/delete rejected |
|
||||
|
||||
## OpenTelemetry
|
||||
|
||||
Six counters under meter `@suaveplan/broadcast-channel@0.1.0`:
|
||||
|
||||
- `channel.message.sent` (`{ type, channel }`)
|
||||
- `channel.message.received` (`{ type, channel }`)
|
||||
- `channel.message.dropped` (`{ reason, channel }`)
|
||||
- `channel.tab.joined` (`{ channel }`)
|
||||
- `channel.tab.left` (`{ channel }`)
|
||||
- `channel.leader.elected` (`{ channel }`)
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
Reference in New Issue
Block a user