# @suaveplan/api-plugin-notifications - Notifications plugin for @suaveplan/api. Ships SurrealDB-backed NotificationRepository + DeviceTokenRepository, /notifications and /push Hono OpenAPI route groups, an APN service with injectable transport (no hardcoded network library), an event-bus integration via ctx.eventBus, 18 NOTIFICATIONS_PLUGIN_* error codes, and 6 OTel counters. Server-tier — runs in Bun and Node. SurrealDB-backed notifications + push plugin for `@suaveplan/api`. Ships a `NotificationRepository` + `DeviceTokenRepository` pair, an `ApnService` with a pluggable transport contract (no hardcoded `@parse/node-apn` dependency), eleven `/notifications/*` Hono OpenAPI routes, five `/push/*` routes, an opt-in multi-channel `NotificationDispatcher` (`apn` + `email`) wired on top of `@suaveplan/notification-channel`, `@suaveplan/emailer`, and `@suaveplan/delivery-tracking`, twenty-two `NOTIFICATIONS_PLUGIN_*` error codes, and eight OTel counters. Server-tier — runs in Bun and Node. ## Documentation tree - [apn-channel](./src/channels/apn-channel/apn-channel.md) — Adapts the in-package `ApnService` to the `@suaveplan/notification-channel` `DeliveryChannel` interface so `Notificatio… - [apn-channel](./src/channels/apn-channel/apn-channel.md) — Adapts the in-package `ApnService` to the `@suaveplan/notification-channel` `DeliveryChannel` interface so `Notificatio… - [email-channel](./src/channels/email-channel/email-channel.md) — Adapts `@suaveplan/emailer`'s `EmailService` to the `@suaveplan/notification-channel` `DeliveryChannel` interface so `N… - [email-channel](./src/channels/email-channel/email-channel.md) — Adapts `@suaveplan/emailer`'s `EmailService` to the `@suaveplan/notification-channel` `DeliveryChannel` interface so `N… - [idempotency-adapter](./src/dispatcher/idempotency-adapter/idempotency-adapter.md) — Defines the narrow contract that lets `NotificationDispatcher` delegate per-call deduplication to a caller-supplied imp… - [idempotency-adapter](./src/dispatcher/idempotency-adapter/idempotency-adapter.md) — Defines the narrow contract that lets `NotificationDispatcher` delegate per-call deduplication to a caller-supplied imp… - [notification-dispatcher](./src/dispatcher/notification-dispatcher/notification-dispatcher.md) — Top-level orchestrator that lets callers send one notification through whichever delivery channel they pick (APN, email… - [notification-dispatcher](./src/dispatcher/notification-dispatcher/notification-dispatcher.md) — Top-level orchestrator that lets callers send one notification through whichever delivery channel they pick (APN, email… - [error-codes](./src/error-codes/error-codes.md) — Stable error-code registry for `@suaveplan/api-plugin-notifications`. The module exports a frozen `NOTIFICATIONS_PLUGIN… - [error-codes](./src/error-codes/error-codes.md) — Stable error-code registry for `@suaveplan/api-plugin-notifications`. The module exports a frozen `NOTIFICATIONS_PLUGIN… - [otel](./src/otel/instruments.md) — OpenTelemetry instrument bundle for `@suaveplan/api-plugin-notifications`. The module exposes a lazy, memoised factory… - [instruments](./src/otel/instruments.md) — OpenTelemetry instrument bundle for `@suaveplan/api-plugin-notifications`. The module exposes a lazy, memoised factory… - [plugin](./src/plugin/plugin.md) — Plugin descriptor factory for `@suaveplan/api-plugin-notifications`. Composes everything in the package — Zod-validated… - [plugin](./src/plugin/plugin.md) — Plugin descriptor factory for `@suaveplan/api-plugin-notifications`. Composes everything in the package — Zod-validated… - [device-token-repository](./src/repositories/device-token-repository/device-token-repository.md) — SurrealDB-backed repository for the `device_token` table. Owns every SurrealQL statement the plugin issues against devi… - [device-token-repository](./src/repositories/device-token-repository/device-token-repository.md) — SurrealDB-backed repository for the `device_token` table. Owns every SurrealQL statement the plugin issues against devi… - [notification-repository](./src/repositories/notification-repository/notification-repository.md) — SurrealDB-backed repository for the `notification` table. Owns every SurrealQL statement the plugin issues against noti… - [notification-repository](./src/repositories/notification-repository/notification-repository.md) — SurrealDB-backed repository for the `notification` table. Owns every SurrealQL statement the plugin issues against noti… - [notifications-routes](./src/routes/notifications-routes/notifications-routes.md) — Hono OpenAPI route module exposing the `/notifications/*` surface. Eleven endpoints cover list / unread-count / create… - [notifications-routes](./src/routes/notifications-routes/notifications-routes.md) — Hono OpenAPI route module exposing the `/notifications/*` surface. Eleven endpoints cover list / unread-count / create… - [push-routes](./src/routes/push-routes/push-routes.md) — Hono OpenAPI route module exposing the `/push/*` surface for device- token registration and APN delivery. Five endpoint… - [push-routes](./src/routes/push-routes/push-routes.md) — Hono OpenAPI route module exposing the `/push/*` surface for device- token registration and APN delivery. Five endpoint… - [dispatch-schemas](./src/schemas/dispatch-schemas.md) — Defines the Zod boundary for the `NotificationDispatcher` surface. The dispatcher fans a single call out to whichever d… - [notification-schemas](./src/schemas/notification-schemas.md) — Zod boundary schemas for the notification entity and every wire surface the plugin exposes — list / get / create / upda… - [options](./src/schemas/options.md) — Zod schema for plugin options accepted by `createNotificationsPlugin()` plus the nested APN configuration shape (`ApnCo… - [push-schemas](./src/schemas/push-schemas.md) — Zod boundary schemas for the `/push/*` route group and the device-token entity stored in SurrealDB. Schemas describe bo… - [services](./src/services/registry-augmentation.md) — Module-augmentation file that declares three new service slots on `@suaveplan/api-plugin/service-registry`'s `ServiceRe… - [apn-service](./src/services/apn-service/apn-service.md) — Apple Push Notification delivery service. Validates an `ApnConfig` at construction-time, builds a pluggable `ApnTranspo… - [apn-service](./src/services/apn-service/apn-service.md) — Apple Push Notification delivery service. Validates an `ApnConfig` at construction-time, builds a pluggable `ApnTranspo… - [registry-augmentation](./src/services/registry-augmentation.md) — Module-augmentation file that declares three new service slots on `@suaveplan/api-plugin/service-registry`'s `ServiceRe… - [apn-transport](./src/transport/apn-transport/apn-transport.md) — Pluggable transport contract for Apple Push Notification delivery. The plugin never depends on a concrete APN client li… - [apn-transport](./src/transport/apn-transport/apn-transport.md) — Pluggable transport contract for Apple Push Notification delivery. The plugin never depends on a concrete APN client li… - [types](./src/types/types.md) — Public type aliases for cross-module wiring: the typed event-bus payload map (`NotificationsPluginEvents`), the discrim… - [types](./src/types/types.md) — Public type aliases for cross-module wiring: the typed event-bus payload map (`NotificationsPluginEvents`), the discrim… ## Modules - [`src/error-codes/error-codes.md`](src/error-codes/error-codes.md) - [`src/otel/instruments.md`](src/otel/instruments.md) - [`src/plugin/plugin.md`](src/plugin/plugin.md) - [`src/repositories/notification-repository/notification-repository.md`](src/repositories/notification-repository/notification-repository.md) - [`src/repositories/device-token-repository/device-token-repository.md`](src/repositories/device-token-repository/device-token-repository.md) - [`src/routes/notifications-routes/notifications-routes.md`](src/routes/notifications-routes/notifications-routes.md) - [`src/routes/push-routes/push-routes.md`](src/routes/push-routes/push-routes.md) - [`src/schemas/options.md`](src/schemas/options.md) - [`src/schemas/notification-schemas.md`](src/schemas/notification-schemas.md) - [`src/schemas/push-schemas.md`](src/schemas/push-schemas.md) - [`src/services/apn-service/apn-service.md`](src/services/apn-service/apn-service.md) - [`src/services/registry-augmentation.md`](src/services/registry-augmentation.md) - [`src/transport/apn-transport/apn-transport.md`](src/transport/apn-transport/apn-transport.md) - [`src/types/types.md`](src/types/types.md) - [`src/channels/apn-channel/apn-channel.md`](src/channels/apn-channel/apn-channel.md) - [`src/channels/email-channel/email-channel.md`](src/channels/email-channel/email-channel.md) - [`src/dispatcher/notification-dispatcher/notification-dispatcher.md`](src/dispatcher/notification-dispatcher/notification-dispatcher.md) - [`src/dispatcher/idempotency-adapter/idempotency-adapter.md`](src/dispatcher/idempotency-adapter/idempotency-adapter.md) - [`src/schemas/dispatch-schemas.md`](src/schemas/dispatch-schemas.md) ## Usage ```ts import { createNotificationsPlugin } from "@suaveplan/api-plugin-notifications"; await api.loadPlugin( createNotificationsPlugin({ basePath: "/v1/notifications", pushBasePath: "/v1/push", enablePush: true, apn: { token: { key: "/keys/AuthKey.p8", keyId: "K", teamId: "T" }, defaultTopic: "com.example.app", production: true, }, }) ); ``` ## Pluggable APN transport Production hosts inject a `node-apn`-backed `ApnTransport`; tests use the deterministic `MemoryApnTransport`: ```ts import { ApnService, type ApnTransport } from "@suaveplan/api-plugin-notifications"; const transport: ApnTransport = makeNodeApnTransport(provider); const service = new ApnService({ config, transport }); ``` See `src/transport/apn-transport/apn-transport.md` for the full contract.