@12-apps/notifications 4.12.0 → 4.13.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/dist/{chunk-PNY6S6WH.js → chunk-4DTUD74E.js} +2 -2
- package/dist/{chunk-WZBX7YCE.js → chunk-53SH5ABN.js} +82 -34
- package/dist/chunk-53SH5ABN.js.map +1 -0
- package/dist/{chunk-CPQKKLPS.js → chunk-CSMFJJXY.js} +1 -1
- package/dist/{chunk-CPQKKLPS.js.map → chunk-CSMFJJXY.js.map} +1 -1
- package/dist/{chunk-FBBPS2LT.js → chunk-QPO6NSRR.js} +2 -2
- package/dist/{chunk-GK6GSC2J.js → chunk-XFODKRRB.js} +2 -2
- package/dist/{create-api-notifications-BTudlaSC.d.ts → create-api-notifications-cIEbFqoZ.d.ts} +121 -30
- package/dist/{create-web-notifications-2xxbKnrW.d.ts → create-web-notifications-BODiQRK-.d.ts} +2 -2
- package/dist/{generators-CQYdJfB5.d.ts → generators-GUF-Kml-.d.ts} +1 -1
- package/dist/hono/index.d.ts +5 -5
- package/dist/hono/index.js +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/{jobs-CaovU4GM.d.ts → jobs-wKoOz91Q.d.ts} +1 -1
- package/dist/manifest/server.d.ts +6 -6
- package/dist/manifest/server.js +4 -4
- package/dist/manifest/web.d.ts +3 -3
- package/dist/manifest/web.js +1 -1
- package/dist/{preferences-screen-S3ZHX5LB.js → preferences-screen-YRPNUZS5.js} +2 -2
- package/dist/react/index.d.ts +4 -4
- package/dist/react/index.js +1 -1
- package/dist/server/index.d.ts +7 -7
- package/dist/server/index.js +4 -4
- package/dist/{types-H_aFzLA0.d.ts → types-DPiePHJD.d.ts} +19 -1
- package/dist/web-push/index.d.ts +2 -2
- package/dist/{web-push-C6U-5JCV.d.ts → web-push-DUn_d_gj.d.ts} +12 -2
- package/dist/{wire-Bn6aA2nL.d.ts → wire-CJka1AvM.d.ts} +1 -1
- package/package.json +2 -2
- package/prisma/migrations/20260914210000_scope_push_subscriptions_per_store/migration.sql +31 -0
- package/prisma/notifications.prisma +12 -0
- package/src/server/context.ts +15 -0
- package/src/server/db.ts +50 -8
- package/src/server/dispatch.ts +9 -2
- package/src/server/inbox.ts +87 -18
- package/src/server/index.ts +2 -0
- package/src/server/push-subscriptions.ts +61 -7
- package/src/server/router.ts +5 -1
- package/src/server/routes.ts +14 -5
- package/src/server/transports/web-push.ts +15 -2
- package/src/types.ts +19 -1
- package/dist/chunk-WZBX7YCE.js.map +0 -1
- /package/dist/{chunk-PNY6S6WH.js.map → chunk-4DTUD74E.js.map} +0 -0
- /package/dist/{chunk-FBBPS2LT.js.map → chunk-QPO6NSRR.js.map} +0 -0
- /package/dist/{chunk-GK6GSC2J.js.map → chunk-XFODKRRB.js.map} +0 -0
- /package/dist/{preferences-screen-S3ZHX5LB.js.map → preferences-screen-YRPNUZS5.js.map} +0 -0
package/dist/{create-api-notifications-BTudlaSC.d.ts → create-api-notifications-cIEbFqoZ.d.ts}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { N as NotificationGeneratorRegistry } from './generators-
|
|
2
|
-
import { b as NotificationRow, C as ChannelMatrix, a as ChannelRow, T as TypeChannelRules, L as ListNotificationsResult, k as NotificationsCopySource, c as NotificationWireMessages } from './wire-
|
|
3
|
-
import { c as NotificationChannel, D as DeliveryStatus, g as NotificationLogger, j as NotificationTransport, d as NotificationContent, b as NotificationCategory, e as NotificationEvent, N as NotificationGenerator } from './types-
|
|
4
|
-
import { e as WebPushSubscriptionSource, D as DriverDeclarationBase, a as WebPushDriverDeclaration, c as WebPushSender } from './web-push-
|
|
1
|
+
import { N as NotificationGeneratorRegistry } from './generators-GUF-Kml-.js';
|
|
2
|
+
import { b as NotificationRow, C as ChannelMatrix, a as ChannelRow, T as TypeChannelRules, L as ListNotificationsResult, k as NotificationsCopySource, c as NotificationWireMessages } from './wire-CJka1AvM.js';
|
|
3
|
+
import { c as NotificationChannel, D as DeliveryStatus, g as NotificationLogger, j as NotificationTransport, d as NotificationContent, b as NotificationCategory, e as NotificationEvent, N as NotificationGenerator } from './types-DPiePHJD.js';
|
|
4
|
+
import { e as WebPushSubscriptionSource, D as DriverDeclarationBase, a as WebPushDriverDeclaration, c as WebPushSender } from './web-push-DUn_d_gj.js';
|
|
5
5
|
import { d as EmailChromeCopy, f as EmailTheme } from './template-Dlt5S54z.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -51,25 +51,45 @@ interface NotificationPageAfter {
|
|
|
51
51
|
createdAt: Date;
|
|
52
52
|
id: string;
|
|
53
53
|
}
|
|
54
|
-
/**
|
|
55
|
-
|
|
54
|
+
/**
|
|
55
|
+
* One BRANCH of an inbox filter — a member of `AND`/`OR`, never a whole read.
|
|
56
|
+
*
|
|
57
|
+
* Split out when the store scope arrived, and the split is what keeps `deletedAt: null`
|
|
58
|
+
* REQUIRED on the read itself (see {@link NotificationWhere}). Widening `OR`
|
|
59
|
+
* from the old fixed keyset tuple to a general array needed its members to be
|
|
60
|
+
* valid filters, and the tempting move — relaxing `deletedAt` on the one type —
|
|
61
|
+
* would have removed the only thing that makes a Prisma-backed host exclude
|
|
62
|
+
* soft-deleted rows. Both in-package doubles hard-code that filter regardless,
|
|
63
|
+
* so Prisma is precisely the implementation the requirement was protecting.
|
|
64
|
+
*
|
|
65
|
+
* `createdAt` and `id: { lt }` are here because the keyset boundary is built
|
|
66
|
+
* from them (`../inbox.ts`'s `pageWhere`); without them the branch type cannot
|
|
67
|
+
* express the very thing the widening exists to preserve.
|
|
68
|
+
*/
|
|
69
|
+
interface NotificationWhereBranch {
|
|
56
70
|
userId?: string;
|
|
57
71
|
id?: string | {
|
|
58
72
|
in: string[];
|
|
73
|
+
} | {
|
|
74
|
+
lt: string;
|
|
59
75
|
};
|
|
60
|
-
|
|
76
|
+
createdAt?: Date | {
|
|
77
|
+
lt: Date;
|
|
78
|
+
};
|
|
79
|
+
deletedAt?: null;
|
|
61
80
|
readAt?: null;
|
|
62
|
-
/**
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
81
|
+
/** `null` matches the platform-wide rows that travel with every store scope. */
|
|
82
|
+
clientId?: string | null;
|
|
83
|
+
OR?: NotificationWhereBranch[];
|
|
84
|
+
AND?: NotificationWhereBranch[];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The inbox read filter. `deletedAt: null` is on every read, always — and it
|
|
88
|
+
* stays REQUIRED here, which is the whole reason {@link NotificationWhereBranch}
|
|
89
|
+
* is a separate type.
|
|
90
|
+
*/
|
|
91
|
+
interface NotificationWhere extends NotificationWhereBranch {
|
|
92
|
+
deletedAt: null;
|
|
73
93
|
}
|
|
74
94
|
interface NotificationDelegate {
|
|
75
95
|
create(args: {
|
|
@@ -227,13 +247,28 @@ interface PushSubscriptionRow {
|
|
|
227
247
|
endpoint: string;
|
|
228
248
|
p256dh: string;
|
|
229
249
|
auth: string;
|
|
250
|
+
/** The origin this browser registered on; `null` = the platform origin. */
|
|
251
|
+
clientId: string | null;
|
|
230
252
|
userAgent: string | null;
|
|
231
253
|
}
|
|
254
|
+
/**
|
|
255
|
+
* Which of a user's subscriptions one send may reach.
|
|
256
|
+
*
|
|
257
|
+
* The disjunction is load-bearing and `clientId: { in: [x, null] }` is NOT a
|
|
258
|
+
* shortcut for it: SQL `IN` never matches NULL, so the platform-wide rows that
|
|
259
|
+
* must travel with every store scope would silently vanish.
|
|
260
|
+
*/
|
|
261
|
+
interface PushSubscriptionWhere {
|
|
262
|
+
userId: string;
|
|
263
|
+
OR?: [{
|
|
264
|
+
clientId: null;
|
|
265
|
+
}, {
|
|
266
|
+
clientId: string;
|
|
267
|
+
}];
|
|
268
|
+
}
|
|
232
269
|
interface PushSubscriptionDelegate {
|
|
233
270
|
count(args: {
|
|
234
|
-
where:
|
|
235
|
-
userId: string;
|
|
236
|
-
};
|
|
271
|
+
where: PushSubscriptionWhere;
|
|
237
272
|
}): Promise<number>;
|
|
238
273
|
/**
|
|
239
274
|
* The row holding one endpoint, whoever owns it. Read BEFORE an upsert so a
|
|
@@ -247,9 +282,7 @@ interface PushSubscriptionDelegate {
|
|
|
247
282
|
};
|
|
248
283
|
}): Promise<PushSubscriptionRow | null>;
|
|
249
284
|
findMany(args: {
|
|
250
|
-
where:
|
|
251
|
-
userId: string;
|
|
252
|
-
};
|
|
285
|
+
where: PushSubscriptionWhere;
|
|
253
286
|
}): Promise<PushSubscriptionRow[]>;
|
|
254
287
|
upsert(args: {
|
|
255
288
|
where: {
|
|
@@ -260,12 +293,14 @@ interface PushSubscriptionDelegate {
|
|
|
260
293
|
endpoint: string;
|
|
261
294
|
p256dh: string;
|
|
262
295
|
auth: string;
|
|
296
|
+
clientId: string | null;
|
|
263
297
|
userAgent: string | null;
|
|
264
298
|
};
|
|
265
299
|
update: {
|
|
266
300
|
userId: string;
|
|
267
301
|
p256dh: string;
|
|
268
302
|
auth: string;
|
|
303
|
+
clientId: string | null;
|
|
269
304
|
userAgent: string | null;
|
|
270
305
|
};
|
|
271
306
|
}): Promise<PushSubscriptionRow>;
|
|
@@ -338,6 +373,11 @@ interface PushSubscriptionInput {
|
|
|
338
373
|
};
|
|
339
374
|
/** Optional browser/device hint for a device list. */
|
|
340
375
|
userAgent?: string;
|
|
376
|
+
/**
|
|
377
|
+
* Which ORIGIN this browser subscribed on — the HOST's resolved
|
|
378
|
+
* value, never anything the caller sent. Absent/null = the platform origin.
|
|
379
|
+
*/
|
|
380
|
+
clientId?: string | null;
|
|
341
381
|
}
|
|
342
382
|
interface PushSubscriptionStore extends WebPushSubscriptionSource {
|
|
343
383
|
/**
|
|
@@ -355,8 +395,19 @@ interface PushSubscriptionStore extends WebPushSubscriptionSource {
|
|
|
355
395
|
save(userId: string, input: PushSubscriptionInput): Promise<void>;
|
|
356
396
|
/** Remove one browser's subscription (owner-scoped; unknown = no-op). */
|
|
357
397
|
remove(userId: string, endpoint: string): Promise<void>;
|
|
358
|
-
/**
|
|
359
|
-
|
|
398
|
+
/**
|
|
399
|
+
* How many devices the user has registered.
|
|
400
|
+
*
|
|
401
|
+
* TWO callers with different questions. The settings screen asks unscoped —
|
|
402
|
+
* "you have 2 devices" is a fact about the PERSON — and passes nothing. The
|
|
403
|
+
* dispatch path passes the notification's tenant, because this is what
|
|
404
|
+
* `supports()` gates on: left unscoped there, the router would enqueue a
|
|
405
|
+
* WEB_PUSH delivery for a notification no reachable subscription exists for,
|
|
406
|
+
* `send` would find an empty list and throw, and the sweep would burn every
|
|
407
|
+
* attempt before writing DEAD — a FAILED row for something that was never
|
|
408
|
+
* undeliverable, only out of scope.
|
|
409
|
+
*/
|
|
410
|
+
count(userId: string, notificationClientId?: string | null): Promise<number>;
|
|
360
411
|
/**
|
|
361
412
|
* Whether THIS endpoint is currently registered to THIS user.
|
|
362
413
|
*
|
|
@@ -792,6 +843,21 @@ type NotifyByPermission = <TPayload>(clientId: string, permissions: readonly str
|
|
|
792
843
|
*/
|
|
793
844
|
interface NotificationsActor {
|
|
794
845
|
userId: string;
|
|
846
|
+
/**
|
|
847
|
+
* The store whose ORIGIN this request arrived on, resolved by the
|
|
848
|
+
* HOST from the hostname — never read from the body or the query.
|
|
849
|
+
*
|
|
850
|
+
* The paragraph above still holds: this is not a tenant the surface
|
|
851
|
+
* authorizes against, it is a NARROWING of a read that is already the
|
|
852
|
+
* caller's own, and it can never widen one. A host with a single origin never
|
|
853
|
+
* sets it and every endpoint answers exactly what it answered before.
|
|
854
|
+
*
|
|
855
|
+
* It exists because a multi-tenant host installs one storefront per store as
|
|
856
|
+
* its own PWA, and a PWA's identity is its ORIGIN — so an inbox answering a
|
|
857
|
+
* store's own app with a neighbour's notifications is one store reporting on
|
|
858
|
+
* another.
|
|
859
|
+
*/
|
|
860
|
+
scopeClientId?: string;
|
|
795
861
|
}
|
|
796
862
|
/** One request, already authenticated and routed by the host. */
|
|
797
863
|
interface NotificationsRequest {
|
|
@@ -844,6 +910,18 @@ declare function foldApiError(error: unknown): NotificationsResponse;
|
|
|
844
910
|
* Soft-deleted rows (`deletedAt` set) are excluded from every read and can
|
|
845
911
|
* never be resurrected by mark-read.
|
|
846
912
|
*/
|
|
913
|
+
/**
|
|
914
|
+
* The store whose ORIGIN the caller is reading from, or absent for the platform
|
|
915
|
+
* origin.
|
|
916
|
+
*
|
|
917
|
+
* A host that installs one storefront per store as its own PWA reads this from
|
|
918
|
+
* the request's hostname; a host with one origin never sets it and every read
|
|
919
|
+
* below is exactly what it was. Set, it narrows to that store's rows PLUS the
|
|
920
|
+
* platform-wide ones (`clientId IS NULL`) — a password reset or a security
|
|
921
|
+
* notice is about the person and not about a store, so hiding it inside the
|
|
922
|
+
* only app a customer opens would be a worse failure than the leak this fixes.
|
|
923
|
+
*/
|
|
924
|
+
type NotificationScope = string | undefined;
|
|
847
925
|
interface ListNotificationsInput {
|
|
848
926
|
/** `unread` narrows to unread rows; default lists all non-deleted. */
|
|
849
927
|
filter?: 'all' | 'unread';
|
|
@@ -859,10 +937,23 @@ interface ListNotificationsInput {
|
|
|
859
937
|
limit?: number;
|
|
860
938
|
}
|
|
861
939
|
interface NotificationInboxStore {
|
|
862
|
-
list(userId: string, input?: ListNotificationsInput): Promise<ListNotificationsResult>;
|
|
863
|
-
|
|
940
|
+
list(userId: string, input?: ListNotificationsInput, scope?: NotificationScope): Promise<ListNotificationsResult>;
|
|
941
|
+
/** Scoped with `list`, or the badge and the list it sits over disagree. */
|
|
942
|
+
unreadCount(userId: string, scope?: NotificationScope): Promise<number>;
|
|
864
943
|
markRead(userId: string, ids: readonly string[]): Promise<number>;
|
|
865
|
-
|
|
944
|
+
/**
|
|
945
|
+
* Scoped too, and this one is a WRITE.
|
|
946
|
+
*
|
|
947
|
+
* Unscoped, "mark all as read" pressed inside store A's app clears store B's
|
|
948
|
+
* unread rows everywhere — a cross-store write from the app that exists to be
|
|
949
|
+
* isolated, and strictly worse than the read leak. `markRead(ids)` and
|
|
950
|
+
* `softDelete(ids)` need nothing: their ids come from the already-scoped list.
|
|
951
|
+
*
|
|
952
|
+
* The platform-wide rows ARE cleared from any origin, and that follows from
|
|
953
|
+
* the scope rule rather than contradicting it — those rows are one person's,
|
|
954
|
+
* not one store's.
|
|
955
|
+
*/
|
|
956
|
+
markAllRead(userId: string, scope?: NotificationScope): Promise<number>;
|
|
866
957
|
softDelete(userId: string, ids: readonly string[]): Promise<number>;
|
|
867
958
|
}
|
|
868
959
|
|
|
@@ -977,4 +1068,4 @@ interface ApiNotifications {
|
|
|
977
1068
|
}
|
|
978
1069
|
declare function createApiNotifications(config: NotificationsServerConfig): ApiNotifications;
|
|
979
1070
|
|
|
980
|
-
export {
|
|
1071
|
+
export { type WhatsAppDriverDeclaration as $, type ApiNotifications as A, type NotificationsDbClient as B, type CommittedNotification as C, type NotificationsDbProvider as D, EMAIL_DRIVERS as E, type NotificationsRequest as F, type NotificationsResponse as G, type NotifyByPermission as H, type NotifyOptions as I, type NotifyResult as J, type PermissionNotificationSkip as K, type ListNotificationsInput as L, type PushSubscriptionDelegate as M, type NotificationsServerConfig as N, type PushSubscriptionInput as O, type PermissionNotificationResult as P, type PushSubscriptionRow as Q, type PushSubscriptionStore as R, type PushSubscriptionWhere as S, SMS_DRIVERS as T, type SmsDriver as U, type SmsDriverDeclaration as V, type SmsMessage as W, type TransportDeclaration as X, type TransportRegistry as Y, WHATSAPP_DRIVERS as Z, type WhatsAppDriver as _, type NotificationsActor as a, type WhatsAppMessage as a0, createApiNotifications as a1, createTransportRegistry as a2, emailTransport as a3, foldApiError as a4, formatEmail as a5, formatSms as a6, formatWhatsApp as a7, ok as a8, smsTransport as a9, whatsAppTransport as aa, type NotificationsRoute as b, type EmailDriver as c, type EmailDriverDeclaration as d, type EmailMessage as e, type ExtraDrivers as f, type NotificationAudienceDirectory as g, type NotificationChannelPolicy as h, type NotificationCommittedListener as i, type NotificationContactDirectory as j, type NotificationCreateData as k, type NotificationDelegate as l, type NotificationDeliveryDelegate as m, type NotificationDeliveryRow as n, type NotificationDeliveryWhere as o, type NotificationDispatchScheduler as p, type NotificationInboxStore as q, type NotificationPageAfter as r, type NotificationPreferenceDelegate as s, type NotificationPreferenceRow as t, type NotificationPreferenceStore as u, type NotificationRouter as v, type NotificationWhere as w, type NotificationWhereBranch as x, NotificationsApiError as y, type NotificationsDb as z };
|
package/dist/{create-web-notifications-2xxbKnrW.d.ts → create-web-notifications-BODiQRK-.d.ts}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode, JSX, ComponentType } from 'react';
|
|
2
|
-
import { L as ListNotificationsResult, a as ChannelRow, I as InboxNotification, N as NotificationMessages } from './wire-
|
|
3
|
-
import { c as NotificationChannel } from './types-
|
|
2
|
+
import { L as ListNotificationsResult, a as ChannelRow, I as InboxNotification, N as NotificationMessages } from './wire-CJka1AvM.js';
|
|
3
|
+
import { c as NotificationChannel } from './types-DPiePHJD.js';
|
|
4
4
|
import { b as LiveActivity } from './live-DYxEFO49.js';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/hono/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Hono, Context } from 'hono';
|
|
2
|
-
import { A as ApiNotifications, N as NotificationsServerConfig, a as NotificationsActor } from '../create-api-notifications-
|
|
3
|
-
import '../generators-
|
|
4
|
-
import '../types-
|
|
5
|
-
import '../wire-
|
|
6
|
-
import '../web-push-
|
|
2
|
+
import { A as ApiNotifications, N as NotificationsServerConfig, a as NotificationsActor } from '../create-api-notifications-cIEbFqoZ.js';
|
|
3
|
+
import '../generators-GUF-Kml-.js';
|
|
4
|
+
import '../types-DPiePHJD.js';
|
|
5
|
+
import '../wire-CJka1AvM.js';
|
|
6
|
+
import '../web-push-DUn_d_gj.js';
|
|
7
7
|
import '../template-Dlt5S54z.js';
|
|
8
8
|
|
|
9
9
|
/**
|
package/dist/hono/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createApiNotifications
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-53SH5ABN.js";
|
|
4
|
+
import "../chunk-XFODKRRB.js";
|
|
5
5
|
import {
|
|
6
6
|
messagesOf
|
|
7
7
|
} from "../chunk-M2TVBVH2.js";
|
|
8
8
|
import "../chunk-RTURLH5U.js";
|
|
9
|
-
import "../chunk-
|
|
9
|
+
import "../chunk-CSMFJJXY.js";
|
|
10
10
|
import "../chunk-EKUSNUBT.js";
|
|
11
11
|
import {
|
|
12
12
|
__name
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { D as DeliveryStatus, a as NOTIFICATION_CHANNELS, b as NotificationCategory, c as NotificationChannel, d as NotificationContent, e as NotificationEvent, f as NotificationGenerateContext, N as NotificationGenerator, g as NotificationLogger, h as NotificationRecipient, i as NotificationTaxonomy, j as NotificationTransport, T as TransportRecipient, t as taxonomyOf } from './types-
|
|
2
|
-
export { N as NotificationGeneratorRegistry, c as createGeneratorRegistry } from './generators-
|
|
3
|
-
export { C as ChannelMatrix, a as ChannelRow, D as DEFAULT_CHANNEL_ROW, I as InboxNotification, L as ListNotificationsResult, N as NotificationMessages, b as NotificationRow, c as NotificationWireMessages, T as TypeChannelRules, d as availableChannelsOf, e as capToAvailable, f as defaultChannelMatrix, g as enabledChannelsOf, i as inboxWire, m as mergeChoices, h as mergeStoredRow, j as messagesOf, r as resolveTypeChannels } from './wire-
|
|
1
|
+
export { D as DeliveryStatus, a as NOTIFICATION_CHANNELS, b as NotificationCategory, c as NotificationChannel, d as NotificationContent, e as NotificationEvent, f as NotificationGenerateContext, N as NotificationGenerator, g as NotificationLogger, h as NotificationRecipient, i as NotificationTaxonomy, j as NotificationTransport, T as TransportRecipient, t as taxonomyOf } from './types-DPiePHJD.js';
|
|
2
|
+
export { N as NotificationGeneratorRegistry, c as createGeneratorRegistry } from './generators-GUF-Kml-.js';
|
|
3
|
+
export { C as ChannelMatrix, a as ChannelRow, D as DEFAULT_CHANNEL_ROW, I as InboxNotification, L as ListNotificationsResult, N as NotificationMessages, b as NotificationRow, c as NotificationWireMessages, T as TypeChannelRules, d as availableChannelsOf, e as capToAvailable, f as defaultChannelMatrix, g as enabledChannelsOf, i as inboxWire, m as mergeChoices, h as mergeStoredRow, j as messagesOf, r as resolveTypeChannels } from './wire-CJka1AvM.js';
|
|
4
4
|
export { L as LIVE_PUSH_TAG_PREFIX, a as LIVE_SUBJECT_KEY, b as LiveActivity, c as LiveActivityLane, d as LiveActivityStep, l as liveActivityLane, e as livePushTag } from './live-DYxEFO49.js';
|
|
5
5
|
|
|
6
6
|
/** Thrown by `notify` when no generator is registered for the event type. */
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
mergeStoredRow,
|
|
13
13
|
normalizePhoneE164,
|
|
14
14
|
resolveTypeChannels
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-XFODKRRB.js";
|
|
16
16
|
import {
|
|
17
17
|
messagesOf
|
|
18
18
|
} from "./chunk-M2TVBVH2.js";
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
import {
|
|
26
26
|
NOTIFICATION_CHANNELS,
|
|
27
27
|
taxonomyOf
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-CSMFJJXY.js";
|
|
29
29
|
import "./chunk-7QVYU63E.js";
|
|
30
30
|
export {
|
|
31
31
|
DEFAULT_CHANNEL_ROW,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WireJobBlueprint } from '@12-apps/wiring';
|
|
2
|
-
import { A as ApiNotifications } from './create-api-notifications-
|
|
2
|
+
import { A as ApiNotifications } from './create-api-notifications-cIEbFqoZ.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The two background jobs getting a message out actually needs.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { EmailPreviewRoute } from '../email/previews/index.js';
|
|
2
2
|
import * as _12_apps_wiring from '@12-apps/wiring';
|
|
3
3
|
import { WireRequest } from '@12-apps/wiring';
|
|
4
|
-
import { N as NotificationsServerConfig, A as ApiNotifications, b as NotificationsRoute } from '../create-api-notifications-
|
|
5
|
-
import { N as NotificationsJobDeps } from '../jobs-
|
|
4
|
+
import { N as NotificationsServerConfig, A as ApiNotifications, b as NotificationsRoute } from '../create-api-notifications-cIEbFqoZ.js';
|
|
5
|
+
import { N as NotificationsJobDeps } from '../jobs-wKoOz91Q.js';
|
|
6
6
|
import { E as EmailPreviewsConfig } from '../catalog-BOVZ2b-b.js';
|
|
7
|
-
import '../generators-
|
|
8
|
-
import '../types-
|
|
9
|
-
import '../wire-
|
|
10
|
-
import '../web-push-
|
|
7
|
+
import '../generators-GUF-Kml-.js';
|
|
8
|
+
import '../types-DPiePHJD.js';
|
|
9
|
+
import '../wire-CJka1AvM.js';
|
|
10
|
+
import '../web-push-DUn_d_gj.js';
|
|
11
11
|
import '../template-Dlt5S54z.js';
|
|
12
12
|
|
|
13
13
|
/** One `NotificationsRoute` as the wiring contract reads it. */
|
package/dist/manifest/server.js
CHANGED
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
} from "../chunk-FTFLU6KH.js";
|
|
4
4
|
import {
|
|
5
5
|
NOTIFICATIONS_JOBS
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-QPO6NSRR.js";
|
|
7
7
|
import {
|
|
8
8
|
createApiNotifications
|
|
9
|
-
} from "../chunk-
|
|
10
|
-
import "../chunk-
|
|
9
|
+
} from "../chunk-53SH5ABN.js";
|
|
10
|
+
import "../chunk-XFODKRRB.js";
|
|
11
11
|
import "../chunk-M2TVBVH2.js";
|
|
12
12
|
import "../chunk-RTURLH5U.js";
|
|
13
|
-
import "../chunk-
|
|
13
|
+
import "../chunk-CSMFJJXY.js";
|
|
14
14
|
import "../chunk-EKUSNUBT.js";
|
|
15
15
|
import {
|
|
16
16
|
__name
|
package/dist/manifest/web.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { c as createEmailPreviewScreen } from '../preview-screen-DYJRAnAY.js';
|
|
2
|
-
import { c as createWebNotifications } from '../create-web-notifications-
|
|
2
|
+
import { c as createWebNotifications } from '../create-web-notifications-BODiQRK-.js';
|
|
3
3
|
import 'react';
|
|
4
|
-
import '../wire-
|
|
5
|
-
import '../types-
|
|
4
|
+
import '../wire-CJka1AvM.js';
|
|
5
|
+
import '../types-DPiePHJD.js';
|
|
6
6
|
import '../live-DYxEFO49.js';
|
|
7
7
|
|
|
8
8
|
/**
|
package/dist/manifest/web.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-CQZMTFPY.js";
|
|
5
5
|
import {
|
|
6
6
|
NOTIFICATION_CHANNELS
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-CSMFJJXY.js";
|
|
8
8
|
import {
|
|
9
9
|
__name
|
|
10
10
|
} from "./chunk-7QVYU63E.js";
|
|
@@ -291,4 +291,4 @@ __name(PreferencesScreen, "PreferencesScreen");
|
|
|
291
291
|
export {
|
|
292
292
|
PreferencesScreen
|
|
293
293
|
};
|
|
294
|
-
//# sourceMappingURL=preferences-screen-
|
|
294
|
+
//# sourceMappingURL=preferences-screen-YRPNUZS5.js.map
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { L as LiveActivitiesConfig, N as NotificationsApiClient } from '../create-web-notifications-
|
|
2
|
-
export { B as BADGE_POLL_MS, a as BADGE_RECONCILE_MS, b as BadgeSyncOptions, d as BellBadge, e as BellButtonProps, I as InboxListStatus, f as InboxState, g as InboxStore, h as LiveActivitiesHook, i as LiveActivityMessages, j as NotificationsHttpError, k as NotificationsPanelProps, l as NotificationsResult, m as NotificationsSignalHook, n as NotificationsSubscribe, o as NotificationsTransport, p as NotificationsWebConfig, P as PAGE_SIZE, q as PreferencesPayload, r as PreferencesScreenProps, s as PushRegistrationPayload, W as WebNotifications, t as WebPushPlatformHint, u as WebPushSetupConfig, v as createInboxStore, w as createNotificationsApiClient, c as createWebNotifications, x as httpNotificationsTransport, y as useInboxList, z as useInboxState, A as useUnreadCount } from '../create-web-notifications-
|
|
1
|
+
import { L as LiveActivitiesConfig, N as NotificationsApiClient } from '../create-web-notifications-BODiQRK-.js';
|
|
2
|
+
export { B as BADGE_POLL_MS, a as BADGE_RECONCILE_MS, b as BadgeSyncOptions, d as BellBadge, e as BellButtonProps, I as InboxListStatus, f as InboxState, g as InboxStore, h as LiveActivitiesHook, i as LiveActivityMessages, j as NotificationsHttpError, k as NotificationsPanelProps, l as NotificationsResult, m as NotificationsSignalHook, n as NotificationsSubscribe, o as NotificationsTransport, p as NotificationsWebConfig, P as PAGE_SIZE, q as PreferencesPayload, r as PreferencesScreenProps, s as PushRegistrationPayload, W as WebNotifications, t as WebPushPlatformHint, u as WebPushSetupConfig, v as createInboxStore, w as createNotificationsApiClient, c as createWebNotifications, x as httpNotificationsTransport, y as useInboxList, z as useInboxState, A as useUnreadCount } from '../create-web-notifications-BODiQRK-.js';
|
|
3
3
|
import { JSX, ReactNode } from 'react';
|
|
4
4
|
import { b as LiveActivity } from '../live-DYxEFO49.js';
|
|
5
5
|
export { c as LiveActivityLane, d as LiveActivityStep, l as liveActivityLane } from '../live-DYxEFO49.js';
|
|
6
|
-
import { N as NotificationMessages } from '../wire-
|
|
7
|
-
import '../types-
|
|
6
|
+
import { N as NotificationMessages } from '../wire-CJka1AvM.js';
|
|
7
|
+
import '../types-DPiePHJD.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* What the reader has already been shown, so the bell can say NEW rather than
|
package/dist/react/index.js
CHANGED
package/dist/server/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { A as ApiNotifications } from '../create-api-notifications-
|
|
2
|
-
export { C as CommittedNotification, E as EMAIL_DRIVERS, c as EmailDriver, d as EmailDriverDeclaration, e as EmailMessage, f as ExtraDrivers, L as ListNotificationsInput, g as NotificationAudienceDirectory, h as NotificationChannelPolicy, i as NotificationCommittedListener, j as NotificationContactDirectory, k as NotificationCreateData, l as NotificationDelegate, m as NotificationDeliveryDelegate, n as NotificationDeliveryRow, o as NotificationDeliveryWhere, p as NotificationDispatchScheduler, q as NotificationInboxStore, r as NotificationPageAfter, s as NotificationPreferenceDelegate, t as NotificationPreferenceRow, u as NotificationPreferenceStore, v as NotificationRouter, w as NotificationWhere, a as NotificationsActor,
|
|
3
|
-
export { D as DriverDeclarationBase, F as FetchImpl, N as NotificationProviderError, W as WEB_PUSH_DRIVERS, a as WebPushDriverDeclaration, b as WebPushMessage, c as WebPushSender, d as WebPushSubscription, e as WebPushSubscriptionSource, f as absoluteLink, g as formatWebPush, w as webPushTransport } from '../web-push-
|
|
1
|
+
import { A as ApiNotifications } from '../create-api-notifications-cIEbFqoZ.js';
|
|
2
|
+
export { C as CommittedNotification, E as EMAIL_DRIVERS, c as EmailDriver, d as EmailDriverDeclaration, e as EmailMessage, f as ExtraDrivers, L as ListNotificationsInput, g as NotificationAudienceDirectory, h as NotificationChannelPolicy, i as NotificationCommittedListener, j as NotificationContactDirectory, k as NotificationCreateData, l as NotificationDelegate, m as NotificationDeliveryDelegate, n as NotificationDeliveryRow, o as NotificationDeliveryWhere, p as NotificationDispatchScheduler, q as NotificationInboxStore, r as NotificationPageAfter, s as NotificationPreferenceDelegate, t as NotificationPreferenceRow, u as NotificationPreferenceStore, v as NotificationRouter, w as NotificationWhere, x as NotificationWhereBranch, a as NotificationsActor, y as NotificationsApiError, z as NotificationsDb, B as NotificationsDbClient, D as NotificationsDbProvider, F as NotificationsRequest, G as NotificationsResponse, b as NotificationsRoute, N as NotificationsServerConfig, H as NotifyByPermission, I as NotifyOptions, J as NotifyResult, P as PermissionNotificationResult, K as PermissionNotificationSkip, M as PushSubscriptionDelegate, O as PushSubscriptionInput, Q as PushSubscriptionRow, R as PushSubscriptionStore, S as PushSubscriptionWhere, T as SMS_DRIVERS, U as SmsDriver, V as SmsDriverDeclaration, W as SmsMessage, X as TransportDeclaration, Y as TransportRegistry, Z as WHATSAPP_DRIVERS, _ as WhatsAppDriver, $ as WhatsAppDriverDeclaration, a0 as WhatsAppMessage, a1 as createApiNotifications, a2 as createTransportRegistry, a3 as emailTransport, a4 as foldApiError, a5 as formatEmail, a6 as formatSms, a7 as formatWhatsApp, a8 as ok, a9 as smsTransport, aa as whatsAppTransport } from '../create-api-notifications-cIEbFqoZ.js';
|
|
3
|
+
export { D as DriverDeclarationBase, F as FetchImpl, N as NotificationProviderError, W as WEB_PUSH_DRIVERS, a as WebPushDriverDeclaration, b as WebPushMessage, c as WebPushSender, d as WebPushSubscription, e as WebPushSubscriptionSource, f as absoluteLink, g as formatWebPush, w as webPushTransport } from '../web-push-DUn_d_gj.js';
|
|
4
4
|
import { NotifyPort } from '@12-apps/wiring/ports';
|
|
5
|
-
export { a as NOTIFICATIONS_DRAIN_CRON, b as NOTIFICATIONS_DRAIN_LEASE_MS, c as NOTIFICATIONS_JOBS, d as NOTIFICATIONS_SWEEP_QUEUE, N as NotificationsJobDeps } from '../jobs-
|
|
6
|
-
import '../generators-
|
|
7
|
-
import '../types-
|
|
8
|
-
import '../wire-
|
|
5
|
+
export { a as NOTIFICATIONS_DRAIN_CRON, b as NOTIFICATIONS_DRAIN_LEASE_MS, c as NOTIFICATIONS_JOBS, d as NOTIFICATIONS_SWEEP_QUEUE, N as NotificationsJobDeps } from '../jobs-wKoOz91Q.js';
|
|
6
|
+
import '../generators-GUF-Kml-.js';
|
|
7
|
+
import '../types-DPiePHJD.js';
|
|
8
|
+
import '../wire-CJka1AvM.js';
|
|
9
9
|
import '../template-Dlt5S54z.js';
|
|
10
10
|
import '@12-apps/wiring';
|
|
11
11
|
|
package/dist/server/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
NOTIFICATIONS_JOBS,
|
|
5
5
|
NOTIFICATIONS_SWEEP_QUEUE,
|
|
6
6
|
wireNotifyPort
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-QPO6NSRR.js";
|
|
8
8
|
import {
|
|
9
9
|
EMAIL_DRIVERS,
|
|
10
10
|
NotificationProviderError,
|
|
@@ -25,11 +25,11 @@ import {
|
|
|
25
25
|
smsTransport,
|
|
26
26
|
webPushTransport,
|
|
27
27
|
whatsAppTransport
|
|
28
|
-
} from "../chunk-
|
|
29
|
-
import "../chunk-
|
|
28
|
+
} from "../chunk-53SH5ABN.js";
|
|
29
|
+
import "../chunk-XFODKRRB.js";
|
|
30
30
|
import "../chunk-M2TVBVH2.js";
|
|
31
31
|
import "../chunk-RTURLH5U.js";
|
|
32
|
-
import "../chunk-
|
|
32
|
+
import "../chunk-CSMFJJXY.js";
|
|
33
33
|
import "../chunk-EKUSNUBT.js";
|
|
34
34
|
import "../chunk-7QVYU63E.js";
|
|
35
35
|
export {
|
|
@@ -181,8 +181,26 @@ interface TransportRecipient {
|
|
|
181
181
|
locale?: string | null;
|
|
182
182
|
/** Phone as the host stores it (transports normalize per provider rules). */
|
|
183
183
|
phone: string | null;
|
|
184
|
-
/**
|
|
184
|
+
/**
|
|
185
|
+
* How many push subscriptions this NOTIFICATION can actually reach — not how
|
|
186
|
+
* many the user holds. Scoped by {@link TransportRecipient.clientId}.
|
|
187
|
+
*/
|
|
185
188
|
pushSubscriptionCount: number;
|
|
189
|
+
/**
|
|
190
|
+
* The store this notification belongs to, or `null` for a platform-wide one
|
|
191
|
+
*.
|
|
192
|
+
*
|
|
193
|
+
* REQUIRED, and deliberately so where optional is the tempting answer. An
|
|
194
|
+
* optional field fails OPEN: a construction site that forgets it yields
|
|
195
|
+
* `undefined`, which the push scope reads as "platform notification -> every
|
|
196
|
+
* subscription" — precisely the cross-store fan-out this exists to stop.
|
|
197
|
+
* Three construction sites is the argument FOR requiring it, not against; the
|
|
198
|
+
* compiler then names them.
|
|
199
|
+
*
|
|
200
|
+
* Not a breaking change for adopters: every external use CONSUMES a recipient
|
|
201
|
+
* through `supports`/`send` below, and the only constructors are in-package.
|
|
202
|
+
*/
|
|
203
|
+
clientId: string | null;
|
|
186
204
|
}
|
|
187
205
|
/**
|
|
188
206
|
* One pluggable channel adapter: a FORMATTER (agnostic content → channel
|
package/dist/web-push/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as WebPushSender } from '../web-push-
|
|
2
|
-
import '../types-
|
|
1
|
+
import { c as WebPushSender } from '../web-push-DUn_d_gj.js';
|
|
2
|
+
import '../types-DPiePHJD.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* `@12-apps/notifications/web-push` — the VAPID sender, behind its own subpath.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as NotificationLogger, d as NotificationContent, j as NotificationTransport } from './types-
|
|
1
|
+
import { g as NotificationLogger, d as NotificationContent, j as NotificationTransport } from './types-DPiePHJD.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The DRIVER port — the reason a host adds a vendor with a config entry and no
|
|
@@ -133,7 +133,17 @@ interface WebPushDriverDeclaration extends DriverDeclarationBase {
|
|
|
133
133
|
}
|
|
134
134
|
/** The subscriptions the transport reads and prunes (db-backed by the mount). */
|
|
135
135
|
interface WebPushSubscriptionSource {
|
|
136
|
-
|
|
136
|
+
/**
|
|
137
|
+
* The subscriptions one notification may reach.
|
|
138
|
+
*
|
|
139
|
+
* `notificationClientId` is the notification's tenant — `null` for a
|
|
140
|
+
* platform-wide one, which every subscription receives. An ADOPTER with a
|
|
141
|
+
* hand-written source must honour it: a function declared with fewer
|
|
142
|
+
* parameters still type-checks, so an un-updated implementation silently
|
|
143
|
+
* ignores the scope and keeps fanning out to every origin, with nothing
|
|
144
|
+
* failing to compile to say so.
|
|
145
|
+
*/
|
|
146
|
+
list(userId: string, notificationClientId?: string | null): Promise<{
|
|
137
147
|
id: string;
|
|
138
148
|
endpoint: string;
|
|
139
149
|
p256dh: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@12-apps/notifications",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.13.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"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.",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"prisma:sync:check": "node scripts/sync-notifications-schema.mjs --check"
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {
|
|
74
|
-
"@12-apps/ui": "^6.
|
|
74
|
+
"@12-apps/ui": "^6.27.1"
|
|
75
75
|
},
|
|
76
76
|
"peerDependencies": {
|
|
77
77
|
"@12-apps/wiring": ">=1.3.0",
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
-- @12-apps/notifications: which ORIGIN a browser subscription was
|
|
2
|
+
-- registered on.
|
|
3
|
+
--
|
|
4
|
+
-- A multi-tenant host installs one storefront per store as its own PWA, and a
|
|
5
|
+
-- PWA's identity is its ORIGIN — so two stores are two apps. Without this
|
|
6
|
+
-- column the Web Push transport fans every notification out to every row a user
|
|
7
|
+
-- holds, and store B's push lands inside store A's installed app wearing store
|
|
8
|
+
-- A's icon.
|
|
9
|
+
--
|
|
10
|
+
-- NULL means the PLATFORM origin: the marketplace host itself, or any adopter
|
|
11
|
+
-- that serves one origin and has no per-store apps at all. That is why the
|
|
12
|
+
-- column is nullable and why every EXISTING row reads correctly with no
|
|
13
|
+
-- backfill — an adopter who never had custom domains keeps today's behaviour
|
|
14
|
+
-- exactly, which is what makes this a MINOR release rather than a breaking one.
|
|
15
|
+
--
|
|
16
|
+
-- A by-value scalar with NO foreign key, exactly as `user_id` and
|
|
17
|
+
-- `notifications.client_id` already are here (the payments-backend doctrine at
|
|
18
|
+
-- the top of `notifications.prisma`): this package must not constrain a host's
|
|
19
|
+
-- tenant table, whose name it does not know.
|
|
20
|
+
--
|
|
21
|
+
-- Additive DDL, so no expand/contract ceremony: the previous release reads a
|
|
22
|
+
-- table that has gained a nullable column it never mentions, which is safe.
|
|
23
|
+
ALTER TABLE "push_subscriptions" ADD COLUMN IF NOT EXISTS "client_id" TEXT;
|
|
24
|
+
|
|
25
|
+
-- Serves the ONE query the send path makes per notification:
|
|
26
|
+
-- user_id = $1 AND ($2 IS NULL OR client_id IS NULL OR client_id = $2)
|
|
27
|
+
-- `user_id` leads because it is the selective half and is on every read; the
|
|
28
|
+
-- existing `push_subscriptions_user_id_idx` stays for the unscoped counts the
|
|
29
|
+
-- settings screen still makes.
|
|
30
|
+
CREATE INDEX IF NOT EXISTS "push_subscriptions_user_id_client_id_idx"
|
|
31
|
+
ON "push_subscriptions" ("user_id", "client_id");
|