@12-apps/notifications 1.0.0 → 2.0.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/package.json +2 -2
- package/src/index.ts +0 -1
- package/src/server/create-api-notifications.ts +10 -2
- package/src/server/transports/whatsapp.ts +11 -3
- package/src/types.ts +31 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@12-apps/notifications",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.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.0
|
|
25
|
+
"@12-apps/ui": "^4.1.0"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"hono": ">=4.0.0",
|
package/src/index.ts
CHANGED
|
@@ -76,8 +76,16 @@ export interface NotificationsServerConfig {
|
|
|
76
76
|
drivers?: ExtraDrivers;
|
|
77
77
|
/** The domain events this mount can emit. */
|
|
78
78
|
generators?: readonly NotificationGenerator<never>[];
|
|
79
|
-
/**
|
|
80
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Preference categories — the granularity at which a user chooses channels.
|
|
81
|
+
*
|
|
82
|
+
* REQUIRED. This defaulted to one product's four (`orders`, `payments`,
|
|
83
|
+
* `stock`, `system`), which is the host's vocabulary and not this library's:
|
|
84
|
+
* a host that omitted it rendered four rows it never chose, with its own
|
|
85
|
+
* categories absent, and nothing failed — `category` is a free string by
|
|
86
|
+
* design, so there was no layer left to notice.
|
|
87
|
+
*/
|
|
88
|
+
categories: readonly NotificationCategory[];
|
|
81
89
|
/** Override which channels a never-touched category defaults to. */
|
|
82
90
|
channelDefaults?: Partial<ChannelRow>;
|
|
83
91
|
/** The tenant plan gate, answered per emit. */
|
|
@@ -54,8 +54,16 @@ export interface WhatsAppDriverDeclaration extends DriverDeclarationBase {
|
|
|
54
54
|
accessToken?: string;
|
|
55
55
|
phoneNumberId?: string;
|
|
56
56
|
templateName?: string;
|
|
57
|
-
/**
|
|
58
|
-
|
|
57
|
+
/**
|
|
58
|
+
* The WhatsApp template's language code, e.g. `pt_BR`, `en_US`.
|
|
59
|
+
*
|
|
60
|
+
* REQUIRED: a template is registered with Meta under one language, and
|
|
61
|
+
* sending it with the wrong code is rejected by the Graph API. This defaulted
|
|
62
|
+
* to `pt_BR` — one market's answer — so a host that forgot it did not get a
|
|
63
|
+
* sensible fallback, it got somebody else's template language and a delivery
|
|
64
|
+
* failure it had no reason to expect.
|
|
65
|
+
*/
|
|
66
|
+
templateLanguage: string;
|
|
59
67
|
/** Graph API base, so a host can pin a version. */
|
|
60
68
|
graphApiBase?: string;
|
|
61
69
|
appUrl?: string;
|
|
@@ -80,7 +88,7 @@ function templatePayload(
|
|
|
80
88
|
type: 'template',
|
|
81
89
|
template: {
|
|
82
90
|
name: declaration.templateName,
|
|
83
|
-
language: { code: declaration.templateLanguage
|
|
91
|
+
language: { code: declaration.templateLanguage },
|
|
84
92
|
components: [
|
|
85
93
|
{
|
|
86
94
|
type: 'body',
|
package/src/types.ts
CHANGED
|
@@ -18,18 +18,25 @@ export const NOTIFICATION_CHANNELS = ['EMAIL', 'SMS', 'WHATSAPP', 'WEB_PUSH'] as
|
|
|
18
18
|
export type NotificationChannel = (typeof NOTIFICATION_CHANNELS)[number];
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* The
|
|
22
|
-
* channels. Every notification `type` belongs to exactly one category via its
|
|
23
|
-
* generator.
|
|
21
|
+
* The preference categories are the HOST's, and required.
|
|
24
22
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
23
|
+
* There used to be a `NOTIFICATION_CATEGORIES = ['orders','payments','stock',
|
|
24
|
+
* 'system']` here — one product's set — and `taxonomyOf` fell back to it
|
|
25
|
+
* whenever a host passed none. The docstring argued the case itself: "it is
|
|
26
|
+
* product vocabulary, not machinery", and then shipped the vocabulary anyway as
|
|
27
|
+
* the default, which is the only part a forgetful host would ever see.
|
|
28
|
+
*
|
|
29
|
+
* The consequence was quiet rather than loud: the settings screen renders four
|
|
30
|
+
* rows a foreign host never chose, its own categories are absent, and every
|
|
31
|
+
* preference a user sets is filed against a taxonomy nothing else in that
|
|
32
|
+
* system uses. Nothing throws, because `category` is deliberately a free string
|
|
33
|
+
* — the packaged migration puts **no CHECK** on it, precisely because a closed
|
|
34
|
+
* set would be wrong for every host but the first. That freedom is what made
|
|
35
|
+
* the default undetectable.
|
|
36
|
+
*
|
|
37
|
+
* `channel` and `status` are different and keep their CHECKs: those ARE this
|
|
38
|
+
* library's own closed sets.
|
|
31
39
|
*/
|
|
32
|
-
export const NOTIFICATION_CATEGORIES = ['orders', 'payments', 'stock', 'system'] as const;
|
|
33
40
|
export type NotificationCategory = string;
|
|
34
41
|
|
|
35
42
|
/**
|
|
@@ -140,13 +147,22 @@ export interface NotificationTaxonomy {
|
|
|
140
147
|
categories: readonly NotificationCategory[];
|
|
141
148
|
}
|
|
142
149
|
|
|
143
|
-
/**
|
|
150
|
+
/**
|
|
151
|
+
* The taxonomy in force. `categories` is REQUIRED — see above.
|
|
152
|
+
*
|
|
153
|
+
* The empty check was already here and stays: an empty list and a missing one
|
|
154
|
+
* are the same mistake, and both now fail at assembly rather than rendering an
|
|
155
|
+
* empty settings screen or somebody else's four rows.
|
|
156
|
+
*/
|
|
144
157
|
export function taxonomyOf(config: {
|
|
145
|
-
categories
|
|
158
|
+
categories: readonly NotificationCategory[];
|
|
146
159
|
}): NotificationTaxonomy {
|
|
147
|
-
const categories = config.categories
|
|
148
|
-
if (categories.length === 0) {
|
|
149
|
-
throw new Error(
|
|
160
|
+
const categories = config.categories;
|
|
161
|
+
if (!categories || categories.length === 0) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
'@12-apps/notifications: `categories` is required and must not be empty — ' +
|
|
164
|
+
'the preference categories are the host\'s product vocabulary.',
|
|
165
|
+
);
|
|
150
166
|
}
|
|
151
167
|
return { categories: [...categories] };
|
|
152
168
|
}
|