Este documento es la fuente única de verdad del producto
beeping-node. Está derivado del milestone 🟢 Phase 13 — beeping-node en Linear (Beeping Platform) y de las 9 tareas que lo componen (BEE-124 → BEE-132). Cualquier cambio de scope se refleja primero aquí, luego en Linear, y luego endocs/ROADMAP.md.
| Campo | Valor |
|---|---|
| Nombre | beeping-node |
| Tagline | 🟢 SDK oficial Node.js del ecosistema Beeping — encode/decode ultrasónico + gestión cloud, dual-mode local/online |
| Versión inicial | 0.0.0 (regla 0.x global del ecosistema — salto a 1.0.0 sólo en Phase 28 Launch readiness, coordinado con todo el ecosistema) |
| Fecha de inicio | 2026-05-12 |
| License | Apache-2.0 |
| Repo | https://github.com/beeping-io/beeping-node |
| Branch base | develop |
| Package | @beeping/node (npm — publish en BEE-132) |
| Linear team | BEE (Beeping) |
| Linear project | 🔊 Beeping Platform (a83369a5-3cb8-4fca-932d-ee33f6a7a00e) |
| Milestone | 🟢 Phase 13 (46c86303-7573-42f8-ac2c-eed1d0209d6e) |
| Tareas | BEE-124 → BEE-132 (9 tareas, ~48 SP) |
beeping-node es el SDK Node.js canónico del ecosistema Beeping (Data Over Sound).
Permite a servicios server-side de Node.js (Express, Fastify, NestJS, scripts CLI, AWS Lambdas, edge runtimes compatibles) codificar y decodificar payloads ultrasónicos entre dispositivos, así como gestionar proyectos y API keys del workspace cloud.
Dos modos de operación que coexisten en el mismo paquete:
- Offline (local) — N-API binding nativo a
beeping-core(C++20) vía prebuildify. Encode/decode 100% local, sin red. Binarios pre-compilados por target descargados alnpm install. - Online (cloud) — cliente HTTP a
beepbox-servervíaundici. Encode/decode delegado al server + features que requieren backend (login, projects, keys).
La selección de modo se decide en construcción (createClient({ mode: 'online' | 'offline' | 'auto' })) o desde env (BEEPING_MODE), siguiendo un strategy pattern + factory (BEE-127) que normaliza la API pública: el consumidor llama al mismo client.encode(payload) independientemente del modo.
Convertirse en el SDK Node.js canónico para integrar Data Over Sound en backends y herramientas server-side del ecosistema JavaScript, instalable con pnpm add @beeping/node y con paridad funcional offline/online.
Criterios cuantitativos:
| Métrica | Target |
|---|---|
| Plataformas soportadas (prebuilt N-API binaries) | macOS arm64+x86_64, Linux amd64+arm64, Linux musl, Windows x86_64 (6 binarios) |
| Node versions soportados | LTS activas (20.x, 22.x, 24.x — actualizado conforme el calendario LTS) |
| Module formats | ESM + CJS (dual build via tsup) + .d.ts types |
| Encode local 32 bytes (offline mode, M-series) | <300 ms end-to-end (incluye PCM render) |
| Throughput decoder offline | >1000 frames/s en Apple Silicon M-series |
npm install @beeping/node cold |
<8 s incluyendo descarga del prebuilt nativo |
| Bundle size publicado | <5 MB sin binarios nativos (binarios separados por target) |
| Test coverage | ≥80 % statements + ≥75 % branches (Vitest + c8) |
| Mutation score (Stryker) | ≥70 % en módulos críticos (strategy resolver, codec adapters) |
| CI matrix | Verde en los 6 targets prebuild + 3 versiones Node por PR |
| Sample apps | Express, Fastify, NestJS funcionando end-to-end contra dev workspace |
- TypeScript strict (
strict: true,noUncheckedIndexedAccess,exactOptionalPropertyTypes). ESM-first source + dual CJS/ESM publish. - Apache-2.0 (regla del ecosistema, ADR-003 en
beeping-meta). - Compatibilidad estricta con
beeping-core(C++20, consumido vía GitHub Releases pre-built — el N-API binding lee el.dylib/.so/.dllcorrespondiente al target) ybeepbox-server(OpenAPI 3.1 spec-first). - Telemetry opt-out estricto (BEE-129):
BEEPING_TELEMETRY=0ycreateClient({ telemetry: false })honrados en ambos modos. Cero PII por default. Tests de privacy obligatorios que assertean la ausencia de PII y de audio data en el payload de telemetría. - Privacy by default: el modo offline NO debe hacer ninguna conexión saliente (ni telemetry síncrono, ni update checks). Telemetry offline se persiste y se flushea diferida + best-effort.
- No estado global: el cliente es instanciable y self-contained — no singletons, no module-level mutables.
- Cross-platform desde día 1: prebuilds en CI para los 6 targets prebuild + smoke test en cada target.
- Dual-mode sin sorpresas: cuando un método online se invoca en modo offline (o viceversa), error tipado explícito (
BeepingModeMismatchError) + JSON error consistente con el resto del ecosistema. - No secrets en código — todos los tokens leen de env o se pasan explícitos al constructor.
| Canal | Comando de instalación | Status target |
|---|---|---|
npm (@beeping/node) |
pnpm add @beeping/node / npm i @beeping/node |
✅ Phase 13 final (BEE-132) |
| GitHub Releases | binarios N-API prebuilt + .tgz del paquete | ✅ Phase 13 |
| GitHub Packages (mirror) | npm i @beeping-io/beeping-node (fallback durante review pública) |
✅ desde día 1 |
| Provenance attestation | npm --provenance activado en CI |
✅ Phase 13 final (BEE-132) |
Fallback obligatorio sin npm público: durante la cola de aprobación / propagación, los wrappers downstream pueden consumir vía git+https://github.com/beeping-io/beeping-node.git#vX.Y.Z o via GitHub Packages — documentado en docs/install.md. Sin excepciones (regla global de package registries).
Core SDK (src/):
createClient({ mode, token, baseUrl, telemetry, logger })— factory pública.client.encode(payload, opts)/client.decode(audioBuffer, opts)— codec API uniforme.client.projects.list()/client.projects.get(id)/client.keys.*— recursos cloud.client.health()— diagnóstico (online: ping server; offline: ping native).- Strategy pattern interno:
OnlineStrategy(undici+ retry + circuit breaker) vsOfflineStrategy(N-API call), seleccionado en factory (BEE-127). - Logging estructurado con pino + propagación de trace-ID entre cloud y local (BEE-128).
- Telemetry hook async con opt-out + buffer offline (BEE-129).
- Errores tipados:
BeepingError,BeepingNetworkError,BeepingDecodeError,BeepingModeMismatchError, etc.
Sample apps (examples/) — BEE-131:
examples/express/— REST API minimal con encode + decode.examples/fastify/— equivalente con Fastify.examples/nest/— módulo NestJS injectable + provider.
Tests (tests/) — BEE-130:
- Unit (Vitest) — strategies, factory, error mapping.
- Integration (Vitest) — cliente contra
beepbox-serverdev real + native binding round-trip. - Property-based (
fast-check) — round-trip encode→decode invariantes. - Mutation (
Stryker) — score ≥70% en módulos críticos. - Privacy tests — assertean ausencia de PII en telemetry payload.
Distribución (.github/workflows/) — BEE-132:
- Prebuilds N-API por target (6 binarios) via
prebuildify. release-pleasepara versionado conventional commits.pnpm publish --provenancecon OIDC.
- Browser support —
beeping-nodees server-side. El equivalente browser/PWA esbeeping-web(Phase 11) con WASM. Si Node 24+ trae APIs Web Audio compatibles, se evaluará reuso pero NO es scope de Phase 13. - Edge-only runtimes incompatibles con N-API — Cloudflare Workers, Deno Deploy edge: no soportados oficialmente en offline mode. Cloud mode (
mode: 'online') sí debería funcionar pero requiere QA específico fuera del scope inicial. - Audio capture en runtime — el SDK acepta
Buffer/Uint8ArrayPCM como input. La captura de audio del micrófono es responsabilidad del consumidor (consox,naudiodon, o helpers de OS). - CLI wrapper — el CLI canónico es
beeping-cli(Phase 14, Rust). No duplicamos. - Soporte de Node legacy — Node <20 LTS. Si alguien lo necesita, debe usar una versión anterior del paquete.
Cualquier cambio de scope (añadir feature, eliminar feature, ajustar SP) requiere:
- PR a
docs/PRODUCTO.mdcon justificación. - Update del milestone description en Linear (vía
projectMilestoneUpdate). - Update de
docs/ROADMAP.md+ entrada endocs/ROADMAP_CHANGELOG.mdcon triggerScope change(regla global).
- Same API, same semantics, two backends: el código que usa
client.encode(...)no cambia entre offline y online. - Strict mode top to bottom: TypeScript strict, ESLint strict, Vitest fail-on-coverage-drop.
- Pure ESM source, dual publish: el código vive en ESM moderno; tsup produce CJS+ESM para consumidores.
- Privacy first: telemetry opt-out trivial + offline mode sin red.
- Errors over warnings: nunca log silenciosos en producción — todo error es un Error tipado lanzable.
- Predictable bundle size: binarios nativos separados por target, jamás bundleados con el paquete JS.
- Boring tech where possible: undici (estándar Node), pino (logging estándar), Vitest (mainstream).
Consumer (Express handler / Fastify route / NestJS service)
│
│ const client = createClient({ mode: 'auto' });
▼
┌─────────────────────────────────────────┐
│ @beeping/node — public API surface │
│ createClient / client.encode / decode │
│ projects / keys / health / on(event) │
└─────────────────────────────────────────┘
│ strategy resolver (BEE-127)
│ 1. explicit mode arg
│ 2. BEEPING_MODE env
│ 3. auto: token+server? online : offline
▼
┌────────────────────┐ ┌────────────────────────────┐
│ OnlineStrategy │ │ OfflineStrategy │
│ undici → beepbox- │ │ N-API → beeping-core (C++20)│
│ server (HTTP/2) │ │ via prebuildify .node │
└────────────────────┘ └────────────────────────────┘
│ │
▼ ▼
beepbox.beeping.io dlopen libbeeping_core.{dylib,so,dll}
| Caso | Error tipado | Exit / behavior |
|---|---|---|
Token cloud inválido o expirado en mode: online |
BeepingAuthError (HTTP 401 unwrap) |
rejected promise, no retry |
mode: offline y subcomando cloud-only |
BeepingModeMismatchError |
rejected promise inmediato |
mode: offline y native binding falta |
BeepingNativeNotFoundError |
rejected promise + URL al fallback prebuild |
Server 5xx en mode: online |
BeepingNetworkError con cause |
retry exponencial vía undici (3 intentos) |
| Decode falla integridad | BeepingDecodeError con offset + checksum |
rejected promise, payload parcial accesible |
| Telemetry opt-out activo | (silencioso, no error) | hook no se invoca |
Cada error implementa toJSON() con code, message, traceId para logging downstream consistente.
- Compatibilidad: Node 20.x, 22.x, 24.x LTS. ESM + CJS via export conditions.
- Performance: cold start del paquete <50 ms (lazy load del native binding). Encode 32 bytes offline <300 ms M-series.
- Memory: footprint <20 MB residente del SDK en idle.
- Observability: pino logger inyectable, namespaces
beeping:*, trace-ID propagado en headers HTTP y en logs estructurados. - Security: dependencias auditadas (
pnpm auditen CI), provenance npm activado, signed releases, supply-chain locked víapnpm-lock.yaml. - Reproducibility: lock file committed,
enginesfield estricto enpackage.json. - Internationalization: errores en inglés (mensajes técnicos), copy de telemetry opt-in/out localizable downstream.
| Capa | Tool | Versión / config |
|---|---|---|
| Language | TypeScript | 5.x latest, strict: true, target ES2022 |
| Runtime | Node | 20+ LTS |
| Package manager | pnpm | latest stable (matching ecosistema) |
| Build | tsup | dual CJS+ESM + .d.ts |
| HTTP client | undici | latest (built-in fetch successor en Node) |
| Native binding | N-API + prebuildify | targets: darwin-arm64, darwin-x64, linux-x64-gnu, linux-x64-musl, linux-arm64-gnu, win32-x64 |
| Logging | pino | + pino-pretty (dev only), namespaces beeping:* |
| Test runner | Vitest | + c8 para coverage |
| Property-based | fast-check | round-trip invariantes |
| Mutation | Stryker | StrykerJS con Vitest runner |
| Lint | ESLint | flat config + @typescript-eslint strict + eslint-plugin-import + eslint-plugin-n |
| Format | Prettier | singleQuote: true, printWidth: 100, trailingComma: all |
| Hooks | lefthook | pre-commit: lint + format check; pre-push: tests |
| Commit lint | commitlint | conventional + custom rule linear-id-required (BEE-NNN o BEE-NNNN) |
| CI | GitHub Actions | matrix Node × OS × target |
| Coverage upload | Codecov | gate >80 % statements |
| Release | release-please | conventional commits → SemVer → npm publish con provenance |
src/
├─ index.ts # public exports (createClient + types)
├─ client.ts # Client class (composes strategy + plugins)
├─ factory.ts # createClient resolver (BEE-127)
├─ strategies/
│ ├─ online.ts # undici HTTP client (BEE-125)
│ ├─ offline.ts # N-API bridge (BEE-126)
│ └─ types.ts # Strategy interface
├─ native/ # N-API bindings (prebuildify)
│ ├─ binding.gyp
│ └─ src/binding.cc
├─ logging/ # pino + trace-ID (BEE-128)
├─ telemetry/ # opt-out async hook (BEE-129)
├─ errors.ts # tipados públicos
└─ types.ts # public types
tests/ # Vitest unit + integration + property
examples/ # Express + Fastify + NestJS
| Sistema | Uso | Cómo |
|---|---|---|
beeping-core |
offline encode/decode | N-API binding a .dylib/.so/.dll prebuilt en external/ |
beepbox-server |
online endpoint | undici client a https://beepbox.beeping.io (prod) / https://beepbox-dev.beeping.io (dev) |
| Linear | task tracking | API key en .env.local, curl directo (no MCP) |
| Codecov | coverage upload en CI | repo upload token en CODECOV_TOKEN secret |
| npm registry | publish @beeping/node |
provenance via OIDC en GitHub Actions |
| GitHub Packages | mirror durante fallback | npm scope @beeping-io/* |
- undici sobre
node:fetch(built-in) — undici exponeAgentpool tuning, HTTP/2, retry semantics + permite estar al día independientemente del LTS activo. - N-API sobre
node-ffi-napi— N-API es ABI estable across Node majors, oficialmente soportado, sin runtime FFI overhead. - prebuildify sobre
node-pre-gyp— prebuildify ships binaries dentro del propio tarball (no descarga post-install), más simple para air-gapped y CI determinístico. - Vitest sobre Jest — ESM nativo, fast watch mode, top-level await en tests.
- fast-check sobre
jsverify— mantenimiento activo, mejor API moderna. - Stryker sobre
mutmut(Python equivalent) — Stryker tiene runner Vitest officially supported. - release-please sobre
semantic-release— release-please funciona via PR (auditable, revertible) y no requiere personal access tokens. - single-binary dual-mode (no split package) — un solo
@beeping/nodecon ambos modos; tree-shaking + lazy load del native garantiza bundle size razonable.
- Backend engineers integrando ultrasónico en flows server-side (Express/Fastify/Nest).
- Bot / AI agent developers que necesitan emitir / capturar señales sonoras desde un proceso headless.
- DevOps / SRE integrando
beeping-coreen lambdas, CronJobs, sidecars sin necesidad de empaquetar C++. - Indie hackers del ecosistema Beeping con prototipos en Node (sample apps).
- ≥80 % statements + ≥75 % branches coverage en
develop(gated). - Mutation score Stryker ≥70 % en módulos críticos.
- 0 vulnerabilidades altas en
pnpm auditdurante 30 días post-launch. - ≥3 sample apps (Express + Fastify + Nest) funcionando contra dev workspace y green-tested.
- npm provenance presente en cada publish.
- Time-to-first-encode (instalación → primera llamada exitosa en sample) <5 min con la quickstart doc.
| Riesgo | Probabilidad | Impacto | Mitigación |
|---|---|---|---|
beeping-core aún no expone API estable para N-API |
Media | Alto | BEE-126 espera a milestone Phase 1 done; documentar la API consumida + mock binding mientras tanto |
| Prebuilds rotos en Linux musl (Alpine) | Media | Medio | Smoke test en Alpine via Docker en CI; fallback documented node-gyp build from source |
| npm publish rate limits / propagation | Baja | Bajo | GitHub Packages mirror como fallback; documentar ambos |
| Stryker mutation runs lentos en CI | Alta | Bajo | Stryker solo en main post-merge y en nightly cron, no en cada PR |
| Cambios de ABI N-API entre Node majors | Baja | Medio | Pinear N-API version, smoke test de prebuild por Node LTS major |
| Telemetry leak (PII en payload) | Baja | Alto | Privacy tests + code review obligatoria del telemetry hook + redacted by default |
| Phase 13 atrasada por dependencias de Phase 1 (beeping-core) | Alta | Alto | Mockear el binding mientras core no esté listo; trabajar HTTP path primero |
| # | Milestone Linear | Entregable | Tareas |
|---|---|---|---|
| 1 | 🟢 Phase 13 — beeping-node | npm @beeping/node v0.1.0 publicado con dual-mode operativo y 3 sample apps verdes |
BEE-124 → BEE-132 |
Tareas dentro de Phase 13 — orden lógico:
| # | Task | Tipo | SP | Resumen |
|---|---|---|---|---|
| 1 | BEE-124 | feat | 3 | 🌱 Crear repo beeping-node + TypeScript strict + Vitest + tsup |
| 2 | BEE-125 | feat | 5 | 🌐 Cliente HTTP a beepbox-server con undici (cloud mode) |
| 3 | BEE-126 | feat | 13 | 📦 Native binding via N-API a beeping-core (local mode) con prebuildify |
| 4 | BEE-127 | feat | 3 | 🎭 Strategy pattern dual mode + factory |
| 5 | BEE-128 | feat | 3 | 🪵 Logging pino + trace-ID propagation |
| 6 | BEE-129 | feat | 3 | 📡 Telemetry hook Node con opt-out + tests de privacy |
| 7 | BEE-130 | test | 8 | 🧪 Tests: Vitest unit + integration + fast-check property + Stryker mutation |
| 8 | BEE-131 | docs | 5 | 📚 Sample apps: Express + Fastify + NestJS |
| 9 | BEE-132 | infra | 5 | 📦 Publish npm @beeping/node con provenance + release-please |
Total Phase 13: ~48 SP.
📜 Nota histórica: Phase 13 originalmente bundleaba
beeping-node+beeping-python(18 tasks, 96 SP). El 2026-05-13 se splitteó en🟢 Phase 13 — beeping-node(este repo, 9 tasks, 48 SP) y🐍 Phase 13.5 — beeping-python(9 tasks, 48 SP) para habilitar cierre y shipping independiente de cada SDK. Verdocs/ROADMAP_CHANGELOG.md.
ROADMAP detallado con fechas calculadas (margen +20%) vive en docs/ROADMAP.md.
Última actualización: 2026-05-12 (bootstrap /worktree-init)