Skip to content

Latest commit

 

History

History
355 lines (272 loc) · 25.8 KB

File metadata and controls

355 lines (272 loc) · 25.8 KB

🟢 beeping-node — Documento de Producto

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 en docs/ROADMAP.md.


1. ℹ️ Información básica

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)

2. 🎯 Qué es

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 al npm install.
  • Online (cloud) — cliente HTTP a beepbox-server vía undici. 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.


3. 📊 Objetivo medible

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

4. 🚧 Restricciones clave

  • 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 / .dll correspondiente al target) y beepbox-server (OpenAPI 3.1 spec-first).
  • Telemetry opt-out estricto (BEE-129): BEEPING_TELEMETRY=0 y createClient({ 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.

5. 🚀 Entorno y distribución

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).


6. 📦 Alcance (qué incluye)

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) vs OfflineStrategy (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-server dev 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-please para versionado conventional commits.
  • pnpm publish --provenance con OIDC.

7. ❌ Qué NO incluye

  • Browser supportbeeping-node es server-side. El equivalente browser/PWA es beeping-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/Uint8Array PCM como input. La captura de audio del micrófono es responsabilidad del consumidor (con sox, 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.

8. 🔄 Cambios de alcance

Cualquier cambio de scope (añadir feature, eliminar feature, ajustar SP) requiere:

  1. PR a docs/PRODUCTO.md con justificación.
  2. Update del milestone description en Linear (vía projectMilestoneUpdate).
  3. Update de docs/ROADMAP.md + entrada en docs/ROADMAP_CHANGELOG.md con trigger Scope change (regla global).

9. 🧭 Principios de producto

  • 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).

10. 🔀 Flujo principal

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}

11. ⚠️ Estados y errores

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.


12. 🛡️ Requisitos no funcionales

  • 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 audit en CI), provenance npm activado, signed releases, supply-chain locked vía pnpm-lock.yaml.
  • Reproducibility: lock file committed, engines field estricto en package.json.
  • Internationalization: errores en inglés (mensajes técnicos), copy de telemetry opt-in/out localizable downstream.

13. 🛠️ Stack técnico

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

14. 🧩 Componentes principales

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

15. 🔌 Integraciones externas

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/*

16. 🤔 Decisiones técnicas

  • undici sobre node:fetch (built-in) — undici expone Agent pool 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/node con ambos modos; tree-shaking + lazy load del native garantiza bundle size razonable.

17. 👥 Usuarios target

  • 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-core en lambdas, CronJobs, sidecars sin necesidad de empaquetar C++.
  • Indie hackers del ecosistema Beeping con prototipos en Node (sample apps).

18. 📈 Métricas de éxito

  • ≥80 % statements + ≥75 % branches coverage en develop (gated).
  • Mutation score Stryker ≥70 % en módulos críticos.
  • 0 vulnerabilidades altas en pnpm audit durante 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.

19. ⚠️ Riesgos y mitigaciones

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

20. 📅 Timeline (milestones)

# 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. Ver docs/ROADMAP_CHANGELOG.md.

ROADMAP detallado con fechas calculadas (margen +20%) vive en docs/ROADMAP.md.


Última actualización: 2026-05-12 (bootstrap /worktree-init)