@12-apps/notifications 3.0.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/ADOPTING.md CHANGED
@@ -20,7 +20,7 @@ sweep — endpoints and screens included.
20
20
  | **Core** | `@12-apps/notifications` | Nothing to wire — the framework-free, storage-free vocabulary both halves share: types, the generator registry, the preference policy, the phone rules, the copy table, the inbox wire shape. Safe in a browser. |
21
21
  | **Server** | `@12-apps/notifications/server` | Call `createApiNotifications({ db, contacts, transports })` and mount the `routes` it returns — the nine inbox / preferences / push-subscription endpoints, with parsing, statuses and the `{ data }` envelope inside. It also returns `notify` (the emit front door), `notifyByPermission`, `dispatchDeliveries`, `drainPending` and the three stores. |
22
22
  | **Hono** | `@12-apps/notifications/hono` | `const notifications = notificationsRouter({ ...serverConfig, resolveActor }); app.route('/api/account', notifications.router)`. A one-call mount; `hono` is an OPTIONAL peer, so importing the root, `/server` or `/react` never resolves it. |
23
- | **React** | `@12-apps/notifications/react` | Call `createWebNotifications({ apiBase })`. `BellWithPanel` is the whole feature as one element; `BellButton` + `Panel` are the pair for a host with its own chrome; `page` is the preferences screen you route to. pt-BR product copy and the future-pay test ids ship inside. |
23
+ | **React** | `@12-apps/notifications/react` | Call `createWebNotifications({ apiBase })`. `BellWithPanel` is the whole feature as one element; `BellButton` + `Panel` are the pair for a host with its own chrome; `page` is the preferences screen you route to. pt-BR product copy and the origin host's test ids ship inside. |
24
24
  | **Web Push** | `@12-apps/notifications/web-push` | `sender: vapidPushSender({ subject, publicKey, privateKey })` on the `WEB_PUSH` declaration. Its own subpath because it is the only piece that needs `web-push` — an OPTIONAL peer a host that never enables the channel never installs. |
25
25
  | **Prisma** | `prisma/notifications.prisma` + `prisma/migrations/*` | Run `pnpm --filter @12-apps/notifications prisma:sync -- <host schema dir>`: the partial is **COPIED** into the host's multi-file schema folder — never symlinked (a symlinked migration is silently skipped by Prisma; a symlinked partial dangles under `turbo prune`). Migrations are discovered structurally from the installed package's `prisma/migrations` by the host's plugin-migration sync. |
26
26
 
@@ -35,7 +35,7 @@ sweep — endpoints and screens included.
35
35
  someone else's inbox would be a different surface with a different actor.
36
36
 
37
37
  2. **`contacts` is not optional, and it is not the `users` table.** A transport
38
- needs an address: `getContact(userId) → { email, phone } | null`. future-pay's
38
+ needs an address: `getContact(userId) → { email, phone } | null`. The origin host's
39
39
  router read `users.email` / `users.phone` directly, which is the one thing in
40
40
  the pipeline that was always the host's — a package cannot know the shape of
41
41
  an identity table, and a host with phone VERIFICATION wants to answer the
@@ -105,8 +105,8 @@ sweep — endpoints and screens included.
105
105
  it with hand-written SQL. The argument shapes are CLOSED (documented in
106
106
  `src/server/db.ts`), so a non-Prisma host has a finite surface to fill.
107
107
 
108
- 5. **`categories` is product vocabulary.** The default is future-pay's four
109
- (`orders` / `payments` / `stock` / `system`) and the preferences screen
108
+ 5. **`categories` is product vocabulary, and REQUIRED.** There is no default:
109
+ the host declares its own taxonomy, and the preferences screen
110
110
  renders whatever the api half was given — the taxonomy travels on the
111
111
  `GET /notification-preferences` payload, so the two halves cannot disagree
112
112
  about it. The packaged migration deliberately puts **no CHECK** on
@@ -115,7 +115,7 @@ sweep — endpoints and screens included.
115
115
  6. **`generators` are registered from the OUTSIDE, and stay the host's.** A
116
116
  generator maps a domain event to `{ title, body, link, data }`, and the
117
117
  events are exactly what does not port: `order.paid`, `stock.low` and
118
- `short-payment` are Future Pay's, not any host's. Pass them in `generators`,
118
+ `short-payment` are the origin host's, not any host's. Pass them in `generators`,
119
119
  or call `registerGenerator` for a module imported later. The generator's
120
120
  `category` is what the router gates fan-out on.
121
121
 
@@ -184,7 +184,7 @@ sweep — endpoints and screens included.
184
184
  notified — and the log line that tells "nobody holds it" apart from "every
185
185
  dispatch failed". Two rules for your implementation:
186
186
 
187
- - `listCandidates` must be **bounded to people who hold a role**. future-pay's
187
+ - `listCandidates` must be **bounded to people who hold a role**. The origin host's
188
188
  requires a role grant, which keeps a store's storefront BUYERS out of a loop
189
189
  that resolves permissions one user at a time.
190
190
  - `getPermissions` must be **scoped to the tenant**. Unioning a user's grants
@@ -222,7 +222,7 @@ sweep — endpoints and screens included.
222
222
 
223
223
  13. **These endpoints are cookie-authenticated WRITES. CSRF is yours.** Eight of
224
224
  the nine change state, and `resolveActor` typically reads a session cookie —
225
- so the host, not this package, owns the cross-site question. In future-pay it
225
+ so the host, not this package, owns the cross-site question. In the origin host it
226
226
  is fully mitigated by the Auth.js cookie's `SameSite=Lax`; a host
227
227
  authenticating with `SameSite=None`, or one whose `resolveActor` trusts a
228
228
  header a proxy sets, inherits an unguarded write surface. The one that matters
package/README.md CHANGED
@@ -79,7 +79,7 @@ which no sweep selects again.
79
79
 
80
80
  ## The endpoints
81
81
 
82
- Mounted under whatever prefix the host chooses (future-pay: `/api/account`):
82
+ Mounted under whatever prefix the host chooses (the origin host: `/api/account`):
83
83
 
84
84
  | | |
85
85
  |---|---|
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@12-apps/notifications",
3
- "version": "3.0.0",
3
+ "version": "4.1.0",
4
4
  "type": "module",
5
5
  "description": "Plug-and-play notification system (12-15): an always-on in-app inbox, per-user × per-category channel preferences, and email / SMS / WhatsApp / web-push transports behind vendor DRIVERS so a second provider is a config entry. Framework-free core (.), host-mounted backend surface (./server: inbox / preferences / push-subscription endpoints, the channel router with delivery records + retry sweep, the permission fan-out, duck-typed Prisma seam), Hono adapter (./hono), React surface (./react: bell + badge, inbox drawer, preferences screen), VAPID sender (./web-push) and the package-owned Prisma partial + migrations. Standardized adoption contract in ADOPTING.md.",
6
6
  "exports": {
@@ -22,7 +22,7 @@
22
22
  "prisma:sync:check": "node scripts/sync-notifications-schema.mjs --check"
23
23
  },
24
24
  "dependencies": {
25
- "@12-apps/ui": "^4.1.0"
25
+ "@12-apps/ui": "^5.0.0"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "hono": ">=4.0.0",
@@ -24,7 +24,7 @@
24
24
  --
25
25
  -- ============================ REPLAY SAFETY ================================
26
26
  -- Every statement is guarded, because the first adopters ALREADY HAVE these
27
- -- tables: future-pay created them by hand before the package existed, so this
27
+ -- tables: the origin host created them by hand before the package existed, so this
28
28
  -- migration must be a no-op there and correct on an empty database.
29
29
  --
30
30
  -- The guards are per COLUMN, not per table. `CREATE TABLE IF NOT EXISTS` alone
@@ -22,7 +22,7 @@
22
22
  // and for a stronger reason: the category set is HOST vocabulary (`categories`
23
23
  // on the server config), so a closed set in the schema would be wrong for every
24
24
  // adopter but the first. A host that wants its own taxonomy enforced adds the
25
- // CHECK in a migration of its own — future-pay does. Only `channel` and `status`
25
+ // CHECK in a migration of its own — the origin host does. Only `channel` and `status`
26
26
  // on the delivery row are closed here, because those two are the LIBRARY's.
27
27
  model Notification {
28
28
  id String @id @default(uuid())
@@ -20,7 +20,7 @@
20
20
  * The host package that owns the schema folder MUST also declare this package
21
21
  * as a dependency, so the source of the copy is present in every build context.
22
22
  *
23
- * Default host path follows the future-pay layout
23
+ * Default host path follows the origin host layout
24
24
  * (`packages/prisma/prisma/schema/`); another repo passes its own schema folder
25
25
  * as the positional argument, or sets NOTIFICATIONS_HOST_SCHEMA_DIR.
26
26
  */