wats.sh
Concepts

WATS Package Map

Canonical dependency map and per-package status for the WATS workspace.

active · applies to 0.3.x-alpha-tooling · reviewed 2026-05-04

The canonical dependency map for the WATS workspace. Arrows point from dependent package to dependency. The graph is generated from the package manifests at build time — it cannot drift from the code.

Dependency graph

Dependency graph of the @wats packages. Arrows point from dependent package to dependency.

@wats/internal-utils is a published internal support package used by public runtime packages that need shared helpers. It exists so registry installs resolve; it is not a stable application API.

Packages

@wats/types

Shared TypeScript domain contracts for config, webhook envelopes, messages, statuses, contacts, entities, and error payloads.

  • Runtime targets: Bun, Node, Workers, Deno.
  • Public: yes.
  • Dependencies out: none.
  • Stability: foundations-complete.

@wats/crypto

CryptoProvider seam plus Node/Bun and WebCrypto adapters.

  • Runtime targets: Bun, Node, Workers, Deno.
  • Public: yes.
  • Dependencies out: @wats/types for shared error payload contracts.
  • Stability: foundations-complete.

@wats/graph

Graph client, transport seam, endpoint registry, scoped clients, error registry, pagination, and endpoint catalog.

  • Runtime targets: Bun, Node, Workers, Deno through injected Transport / fetch.
  • Public: yes.
  • Dependencies out: @wats/types.
  • Stability: foundations-complete for client/transport/errors/pagination; endpoint breadth is expanding.

Runtime endpoints and helpers:

  • POST /{phoneNumberId}/messages
  • POST /{phoneNumberId}/marketing_messages via sendMarketingTemplate and PhoneNumberClient.sendMarketingTemplate(...)
  • PhoneNumberClient.sendText(...) for arbitrary-recipient text starts
  • PhoneNumberClient composer helpers for media, location, contacts, reaction, interactive variants, template send, mark-as-read, and typing indicators
  • Template Group helpers for Graph template_groups and template_group_analytics (listTemplateGroups, getTemplateGroupAnalytics)
  • profile/commerce mutation helpers for Graph whatsapp_business_profile and whatsapp_commerce_settings (updateBusinessProfile, updateCommerceSettings) via root @wats/graph and @wats/graph/endpoints/business-management; WATS maps profilePictureHandle to Graph profile_picture_handle and isCartEnabled / isCatalogVisible to is_cart_enabled / is_catalog_visible
  • business-management helpers for Graph block_users, official_business_account, and new_display_name (listBlockedUsers, blockUsers, unblockUsers, getOfficialBusinessAccountStatus, requestOfficialBusinessAccountReview, submitDisplayNameForReview)
  • Groups helpers for Graph groups, invite_link, participants, and join_requests, including PhoneNumberClient.createGroup, PhoneNumberClient.listGroups, PhoneNumberClient.group(groupId), and GroupClient
  • GET /{wabaId}/phone_numbers

Endpoint subpaths:

  • @wats/graph/endpoints/messages
  • @wats/graph/endpoints/media
  • @wats/graph/endpoints/templates
  • @wats/graph/endpoints/flows
  • @wats/graph/endpoints/calling
  • @wats/graph/endpoints/business-management
  • @wats/graph/endpoints/groups
  • @wats/graph/node-media (Node/Bun-only; filesystem path media helpers; not imported by the root/browser-safe entrypoint)

Run bun run api:check after changing this list. It verifies package exports, source files, fixture imports, docs, and the changelog all agree on the same Graph endpoint subpaths.

Media runtime:

  • uploadMedia sends a single multipart POST /{phoneNumberId}/media with strict validation and finite upload caps.
  • downloadMedia resolves media metadata via GET /{mediaId}.
  • downloadMediaBytes fetches resolved media bytes through the injected transport with finite download caps and optional SHA-256 verification.
  • deleteMedia calls DELETE /{mediaId}.
  • decryptEncryptedMedia verifies and decrypts encrypted media bundles.
  • createUploadSession, uploadFileToSession, and getUploadSession implement resumable upload sessions.

@wats/http

Application-edge webhook package: challenge/signature primitives, runtime-neutral WebhookAdapter, and Bun/Node/Fetch wrappers. It verifies signatures and normalizes raw webhooks into typed updates via @wats/core's normalizeWebhookEnvelope before dispatching them to a structural { dispatch(update) } facade-like object.

  • Runtime targets: Bun, Node, Workers, Deno-style Fetch runtimes.
  • Public: yes.
  • Dependencies out: @wats/crypto, @wats/core, @wats/types.
  • Layer: application-edge — composes @wats/core (NOT a peer of @wats/graph; it sits above @wats/core, while @wats/graph sits below it).
  • Stability: foundations-complete.

@wats/http depends on @wats/core for the normalizer. Its adapter accepts only a structural { dispatch(update) } facade-like object at runtime.

@wats/core

Typed webhook normalization, typed filters, raw filters, routers, listener registry, and WhatsApp facade composition root.

  • Runtime targets: Bun, Node, Workers, Deno where dependencies are available.
  • Public: yes.
  • Dependencies out: @wats/types, @wats/graph.
  • Stability: foundations-complete.

The facade binds a GraphClient, optional PhoneNumberClient / WABAClient, a TypedRouter, and optional listener registry support. WhatsApp.sendText(...) (alias startChat(...)) delegates through the bound PhoneNumberClient to send a text with any valid phone-number-like recipient — no contacts lookup. Facade composer helpers (media, location, contacts, reaction, interactive variants, template send, mark-as-read, typing indicators) require a bound phoneNumberId and use the same phone-number client.

@wats/config

YAML/JSON config schema, env-secret references, config loading, validation, and redaction.

  • Runtime targets: Bun and Node-compatible ESM; config parsing itself is runtime-light.
  • Public: yes, experimental.
  • Dependencies out: @wats/internal-utils for shared object guards.
  • Stability: experimental until the CLI/service config contract settles.

@wats/cli

Package-manager CLI surface for safe config validation, OpenAPI export, help, and local webhook token generation.

  • Runtime targets: Bun now; Node-compatible ESM is the direction for the publishable CLI.
  • Public: yes, experimental.
  • Dependencies out: @wats/config, @wats/service.
  • Stability: experimental until init/doctor/serve process behavior settles.

@wats/service

Runtime-neutral standalone webhook/API service foundation plus generated OpenAPI 3.1 document for the service routes.

  • Runtime targets: Bun and Web Fetch-compatible runtimes for the core Request -> Response app; Node/Bun server wrappers are later work.
  • Public: yes, experimental.
  • Dependencies out: @wats/config, @wats/core, @wats/http, @wats/graph, @wats/crypto.
  • Stability: experimental until CLI serve/openapi integration and broader route coverage settle.

@wats/persistence

Experimental persistence contracts, the SQLite local adapter, and the Postgres adapter, plus the migration runner, webhook/service idempotency records, message projection, and outbox record APIs.

  • Runtime targets: Bun for @wats/persistence/sqlite; @wats/persistence/postgres runs wherever pg does; root contracts and runOutboxWorkerOnce are TypeScript-only.
  • Public: yes, experimental.
  • Published subpaths: @wats/persistence, @wats/persistence/sqlite, @wats/persistence/postgres.
  • Future subpaths: @wats/persistence/testing.
  • Dependencies out: none.
  • Dependency direction: @wats/service consumes @wats/persistence through injected stores, not direct env reads.
  • Stability: experimental until outbox/service enqueueing and live Postgres validation settle. The Postgres adapter is shape-only, mock-client tested; no default CI runs a live Postgres service.

@wats/internal-utils

Internal support package for shared pure helpers required by public runtime packages.

  • Public: yes for package-manager completeness; do not treat it as stable public API.
  • Published: yes, because @wats/config depends on it at runtime.
  • Dependencies out: none.

@wats/testing

Private workspace tests, consumer fixtures, fixture payloads, and policy checks.

  • Runtime targets: Bun test runner only.
  • Public: no.
  • Published: no.
  • Dependencies out: workspace packages under test.

Invariants

  1. @wats/types has no runtime dependencies.
  2. @wats/graph and @wats/crypto expose portable seams and keep runtime-specific behavior behind adapters. @wats/http also keeps its runtime wrappers behind adapters, but it is an application-edge package that composes @wats/core (it is not a foundation peer of @wats/graph).
  3. @wats/core is the core composition root; app-layer packages compose it rather than duplicating router/webhook semantics.
  4. @wats/internal-utils may be published only as an internal support package; @wats/testing stays private and is never published.
  5. Consumer fixtures import through package specifiers, never relative source paths.

Runtime-target matrix

packageBunNodeWorkersDenonotes
@wats/typesYYYYtype-first
@wats/cryptoYYYYadapter chosen at runtime
@wats/graphYYYYinjected transport
@wats/httpYYYYruntime wrappers
@wats/coreYYYYno server binding
@wats/configYYpossiblepossibleboundary validation; file loading runtime-dependent
@wats/persistenceYYNNSQLite and optional Postgres adapters are server/runtime-side
@wats/cliYplannedNNconfig validation + OpenAPI export + package-manager UX
@wats/internal-utilsYYpossiblepossibleinternal support package
@wats/testingYNNNBun tests only
@wats/serviceYplannedpossiblepossibleruntime-neutral app plus OpenAPI generator; server wrappers later

On this page