# `plugin/plugin` _(no submodules)_ ## Purpose Plugin descriptor factory for `@suaveplan/api-plugin-notifications`. Composes everything in the package — Zod-validated options, SurrealDB-backed `NotificationRepository` and `DeviceTokenRepository`, the optional `ApnService`, the two route modules, and the OTel instrument bundle — into a single `PluginDescriptor` that hosts mount via `@suaveplan/api-plugin`'s standard lifecycle. ## Features - Boundary Zod validation — invalid options throw `NotificationsPluginError(INVALID_CONFIG)` with the `ZodError` attached as `cause`. - Two-phase lifecycle: `onInit` registers repositories and the APN service in the host's `ServiceRegistry`; `onReady` mounts both route trees and refuses double-mount with `ROUTE_PREFIX_COLLISION`. - Event-bus integration — emits `notifications:initialized` and `notifications:ready` on the shared `ctx.eventBus` so siblings observe lifecycle transitions. Route-level events flow through a single `forwarder` callback that the route modules call via `emitEvent`. - Optional APN — `enablePush: false` (default) skips APN construction; `enablePush: true` without `config.apn` throws `APN_CONFIG_MISSING` at boot. - Graceful close — `onClose` shuts down the APN transport (if any) and clears the repository references so the GC can collect them. ## Usage: Basic ```ts import { createNotificationsPlugin } from "@suaveplan/api-plugin-notifications"; await api.loadPlugin(createNotificationsPlugin()); ``` ## Usage: Advanced Enable push delivery with a token-auth APN config and a custom mount prefix: ```ts await api.loadPlugin( createNotificationsPlugin({ basePath: "/v1/notifications", pushBasePath: "/v1/push", enablePush: true, apn: { token: { key: "/keys/AuthKey_ABC.p8", keyId: "ABC", teamId: "TEAM", }, defaultTopic: "com.example.app", production: true, }, maxBulkRecipients: 500, autoCleanOldDays: 14, }) ); ``` ## API Reference - `createNotificationsPlugin(options?: NotificationsPluginConfigInput)` → `PluginDescriptor` - Lifecycle hooks: `onInit(ctx)`, `onReady(ctx)`, `onClose()`. - Service slots registered: `notificationRepository`, `deviceTokenRepository`, `apnService` (only when `enablePush`). - Event-bus emissions: `notifications:initialized`, `notifications:ready`, plus every event in `NotificationsPluginEvents`. ## Implementation Notes The plugin name is `"notifications"`. Dependencies are `["database"]` — `onInit` will refuse to boot without an `@suaveplan/api-plugin-database`-registered `db` slot. The plugin calls `ctx.eventBus.emit(event.type, event.payload)` from a single `forwarder` callback rather than dragging the `eventBus` reference into every route handler. This matches the api-plugin-events pattern and means route handlers stay testable in isolation.