@ttt-productions/notification-core 0.4.9 → 0.4.10
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/react/components/NotificationList.d.ts.map +1 -1
- package/dist/react/components/NotificationList.js +7 -13
- package/dist/react/components/NotificationList.js.map +1 -1
- package/dist/server/activeNotificationId.d.ts +23 -0
- package/dist/server/activeNotificationId.d.ts.map +1 -0
- package/dist/server/activeNotificationId.js +0 -0
- package/dist/server/activeNotificationId.js.map +1 -0
- package/dist/server/createNotificationHelper.d.ts.map +1 -1
- package/dist/server/createNotificationHelper.js +56 -52
- package/dist/server/createNotificationHelper.js.map +1 -1
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/processBatchHelper.d.ts.map +1 -1
- package/dist/server/processBatchHelper.js +70 -66
- package/dist/server/processBatchHelper.js.map +1 -1
- package/dist/server/types.d.ts +9 -0
- package/dist/server/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/styles/notifications.css +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotificationList.d.ts","sourceRoot":"","sources":["../../../src/react/components/NotificationList.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"NotificationList.d.ts","sourceRoot":"","sources":["../../../src/react/components/NotificationList.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAmB,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE7E;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,MAAM,EACN,QAAQ,EACR,mBAAmB,EACnB,SAAS,EACT,YAAY,EACZ,UAAU,EACV,eAAe,EACf,SAAS,GACV,EAAE,qBAAqB,2CAwHvB"}
|
|
@@ -5,7 +5,6 @@ import { Badge, Button, Separator } from '@ttt-productions/ui-core/react';
|
|
|
5
5
|
import { useActiveNotifications } from '../hooks/useActiveNotifications.js';
|
|
6
6
|
import { useArchiveNotification } from '../hooks/useArchiveNotification.js';
|
|
7
7
|
import { useArchiveAllNotifications } from '../hooks/useArchiveAllNotifications.js';
|
|
8
|
-
import { useUnreadCount } from '../hooks/useUnreadCount.js';
|
|
9
8
|
import { NotificationEmptyState } from './NotificationEmptyState.js';
|
|
10
9
|
import { formatRelativeTime } from './relative-time.js';
|
|
11
10
|
/**
|
|
@@ -18,12 +17,6 @@ export function NotificationList({ config, userId, category, onNotificationClick
|
|
|
18
17
|
category,
|
|
19
18
|
refetchInterval,
|
|
20
19
|
});
|
|
21
|
-
const { count: unreadCount } = useUnreadCount({
|
|
22
|
-
config,
|
|
23
|
-
userId,
|
|
24
|
-
category,
|
|
25
|
-
refetchInterval,
|
|
26
|
-
});
|
|
27
20
|
const archiveMutation = useArchiveNotification({
|
|
28
21
|
userId,
|
|
29
22
|
category,
|
|
@@ -56,11 +49,12 @@ export function NotificationList({ config, userId, category, onNotificationClick
|
|
|
56
49
|
const typeConfig = config.types[type];
|
|
57
50
|
return typeConfig?.icon ?? '🔔';
|
|
58
51
|
}, [config]);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
e.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
52
|
+
const hasNotifications = !!notifications && notifications.length > 0;
|
|
53
|
+
return (_jsxs("div", { className: "ntf-list", children: [_jsx("div", { className: "ntf-list-header", children: _jsx(Button, { variant: "ghost", size: "sm", onClick: handleClearAll, disabled: !hasNotifications || archiveAllMutation.isPending, children: archiveAllMutation.isPending ? 'Clearing...' : 'Clear All' }) }), _jsx(Separator, {}), _jsx("div", { className: "ntf-list-body", children: isLoading ? (_jsx("div", { className: "ntf-loading", children: "Loading..." })) : !notifications || notifications.length === 0 ? (_jsx(NotificationEmptyState, { text: emptyText })) : (_jsxs(_Fragment, { children: [notifications.map((notification) => (_jsxs("div", { className: "ntf-item", role: "button", tabIndex: 0, onClick: () => handleNotificationClick(notification), onKeyDown: (e) => {
|
|
54
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
55
|
+
e.preventDefault();
|
|
56
|
+
handleNotificationClick(notification);
|
|
57
|
+
}
|
|
58
|
+
}, children: [_jsx("div", { className: "ntf-item-icon", children: getTypeIcon(notification.type) }), _jsxs("div", { className: "ntf-item-content", children: [_jsx("div", { className: "ntf-item-title", children: notification.title }), _jsx("div", { className: "ntf-item-message", children: notification.message }), _jsx("div", { className: "ntf-item-timestamp", children: formatRelativeTime(notification.updatedAt) })] }), notification.count > 1 && (_jsx("div", { className: "ntf-item-count", children: _jsxs(Badge, { variant: "secondary", children: ["\u00D7", notification.count] }) }))] }, notification.id))), hasNextPage && (_jsx("div", { className: "ntf-list-footer", children: _jsx(Button, { variant: "ghost", size: "sm", onClick: nextPage, children: "Load more" }) }))] })) })] }));
|
|
65
59
|
}
|
|
66
60
|
//# sourceMappingURL=NotificationList.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotificationList.js","sourceRoot":"","sources":["../../../src/react/components/NotificationList.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,0BAA0B,EAAE,MAAM,wCAAwC,CAAC;AACpF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"NotificationList.js","sourceRoot":"","sources":["../../../src/react/components/NotificationList.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic active-notification document IDs.
|
|
3
|
+
*
|
|
4
|
+
* The active doc for a given dedup scope always lives at the same ID, so
|
|
5
|
+
* concurrent writers (real-time sends racing each other or the batch
|
|
6
|
+
* materializer) converge on one document inside a transaction instead of
|
|
7
|
+
* racing a query-then-write. The ID hashes the same fields the dedup lookup
|
|
8
|
+
* used to filter on: category, audience scope, and dedupKey.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Build the deterministic doc ID for an active notification.
|
|
12
|
+
*
|
|
13
|
+
* Personal notifications scope per recipient (a fan-out to many users must
|
|
14
|
+
* never collapse into one recipient's doc); shared notifications are
|
|
15
|
+
* intentionally a single doc for the whole audience.
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildActiveNotificationDocId(params: {
|
|
18
|
+
category: string;
|
|
19
|
+
audienceType: 'personal' | 'shared';
|
|
20
|
+
targetUserId: string | null | undefined;
|
|
21
|
+
dedupKey: string;
|
|
22
|
+
}): string;
|
|
23
|
+
//# sourceMappingURL=activeNotificationId.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activeNotificationId.d.ts","sourceRoot":"","sources":["../../src/server/activeNotificationId.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,UAAU,GAAG,QAAQ,CAAC;IACpC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACxC,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,MAAM,CAOT"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activeNotificationId.js","sourceRoot":"","sources":["../../src/server/activeNotificationId.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,UAAU,4BAA4B,CAAC,MAK5C;IACC,MAAM,KAAK,GACT,MAAM,CAAC,YAAY,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,YAAY,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC1F,OAAO,UAAU,CAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,IAAI,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;SACxD,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createNotificationHelper.d.ts","sourceRoot":"","sources":["../../src/server/createNotificationHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,EACV,eAAe,EAEf,kBAAkB,EACnB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"createNotificationHelper.d.ts","sourceRoot":"","sources":["../../src/server/createNotificationHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,EACV,eAAe,EAEf,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAQpB;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,EAAE,EAAE,eAAe,EACnB,MAAM,EAAE,wBAAwB,GAC/B,kBAAkB,CAkJpB"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Factory that creates the notification sending helper.
|
|
3
3
|
* This is THE single entry point for all notification creation in any app.
|
|
4
4
|
*/
|
|
5
|
+
import { buildActiveNotificationDocId } from './activeNotificationId.js';
|
|
5
6
|
const DEFAULT_COUNT_CAP = 5000;
|
|
6
7
|
const DEFAULT_ACTOR_CAP = 5;
|
|
7
8
|
/** Firestore hard limit on writes per batch. */
|
|
@@ -46,58 +47,61 @@ export function createNotificationHelper(db, config) {
|
|
|
46
47
|
const dedupKey = typeConfig.dedupKeyPattern(metadata);
|
|
47
48
|
const countCap = typeConfig.countCap ?? DEFAULT_COUNT_CAP;
|
|
48
49
|
const actorCap = typeConfig.actorCap ?? DEFAULT_ACTOR_CAP;
|
|
49
|
-
// Dedup
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
50
|
+
// Dedup via deterministic doc ID: the active doc for this scope always
|
|
51
|
+
// lives at the same ID (hash of category + audience scope + dedupKey), so
|
|
52
|
+
// concurrent sends converge on one doc inside the transaction instead of
|
|
53
|
+
// racing a query-then-write. Personal notifications are scoped to the
|
|
54
|
+
// recipient so user B's notification never re-lights user A's active doc
|
|
55
|
+
// that shares the same dedupKey; shared notifications are intentionally a
|
|
56
|
+
// single doc for all admins.
|
|
57
|
+
const activeDocRef = db.collection(activePath).doc(buildActiveNotificationDocId({
|
|
58
|
+
category: typeConfig.category,
|
|
59
|
+
audienceType: categoryConfig.audienceType,
|
|
60
|
+
targetUserId: targetUserId ?? null,
|
|
61
|
+
dedupKey,
|
|
62
|
+
}));
|
|
63
|
+
await db.runTransaction(async (tx) => {
|
|
64
|
+
const existingSnap = await tx.get(activeDocRef);
|
|
65
|
+
if (existingSnap.exists) {
|
|
66
|
+
// Increment existing notification
|
|
67
|
+
const existingData = (existingSnap.data() ?? {});
|
|
68
|
+
const currentCount = existingData.count || 1;
|
|
69
|
+
const currentActorIds = existingData.latestActorIds || [];
|
|
70
|
+
// Cap actors (id-only — newest first, deduped)
|
|
71
|
+
const newActorIds = [actorId, ...currentActorIds.filter((id) => id !== actorId)].slice(0, actorCap);
|
|
72
|
+
const newCount = Math.min(currentCount + 1, countCap);
|
|
73
|
+
tx.update(activeDocRef, {
|
|
74
|
+
count: newCount,
|
|
75
|
+
latestActorIds: newActorIds,
|
|
76
|
+
message: typeConfig.messagePattern(metadata, newCount),
|
|
77
|
+
// New activity on an existing notification re-lights the unread badge.
|
|
78
|
+
seenAt: 0,
|
|
79
|
+
updatedAt: Date.now(),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Create new notification
|
|
84
|
+
const targetPath = resolveTargetPath(typeConfig.defaultTargetPath, metadata);
|
|
85
|
+
const now = Date.now();
|
|
86
|
+
const newDoc = {
|
|
87
|
+
type,
|
|
88
|
+
dedupKey,
|
|
89
|
+
category: typeConfig.category,
|
|
90
|
+
targetUserId: targetUserId ?? null,
|
|
91
|
+
title: typeConfig.titlePattern(metadata),
|
|
92
|
+
message: typeConfig.messagePattern(metadata, 1),
|
|
93
|
+
count: 1,
|
|
94
|
+
latestActorIds: [actorId],
|
|
95
|
+
targetPath,
|
|
96
|
+
metadata,
|
|
97
|
+
// Active docs are created unseen so the unread count() predicate matches.
|
|
98
|
+
seenAt: 0,
|
|
99
|
+
createdAt: now,
|
|
100
|
+
updatedAt: now,
|
|
101
|
+
};
|
|
102
|
+
tx.set(activeDocRef, newDoc);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
101
105
|
}
|
|
102
106
|
async function queueForBatch(input) {
|
|
103
107
|
const pendingDoc = buildPendingDoc(input, Date.now());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createNotificationHelper.js","sourceRoot":"","sources":["../../src/server/createNotificationHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"createNotificationHelper.js","sourceRoot":"","sources":["../../src/server/createNotificationHelper.ts"],"names":[],"mappings":"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"}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -3,5 +3,6 @@ export { processBatchHelper } from './processBatchHelper.js';
|
|
|
3
3
|
export { archiveNotificationHelper, archiveAllNotificationsHelper, } from './archiveNotificationHelper.js';
|
|
4
4
|
export { markSeenHelper } from './markSeenHelper.js';
|
|
5
5
|
export { NotificationPermissionError } from './errors.js';
|
|
6
|
-
export
|
|
6
|
+
export { buildActiveNotificationDocId } from './activeNotificationId.js';
|
|
7
|
+
export type { ServerFirestore, ServerCollectionRef, ServerQuery, ServerQuerySnapshot, ServerDocSnapshot, ServerDocRef, ServerWriteBatch, ServerTransaction, CreateNotificationInput, NotificationHelper, } from './types.js';
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EACL,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EACL,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAGzE,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
|
package/dist/server/index.js
CHANGED
|
@@ -4,4 +4,5 @@ export { processBatchHelper } from './processBatchHelper.js';
|
|
|
4
4
|
export { archiveNotificationHelper, archiveAllNotificationsHelper, } from './archiveNotificationHelper.js';
|
|
5
5
|
export { markSeenHelper } from './markSeenHelper.js';
|
|
6
6
|
export { NotificationPermissionError } from './errors.js';
|
|
7
|
+
export { buildActiveNotificationDocId } from './activeNotificationId.js';
|
|
7
8
|
//# sourceMappingURL=index.js.map
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EACL,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EACL,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"processBatchHelper.d.ts","sourceRoot":"","sources":["../../src/server/processBatchHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAuB,MAAM,aAAa,CAAC;AACjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"processBatchHelper.d.ts","sourceRoot":"","sources":["../../src/server/processBatchHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAuB,MAAM,aAAa,CAAC;AACjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAQlD,UAAU,kBAAkB;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,eAAe,EACnB,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CAiM7B"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Batch processor helper — called by the app's scheduled Cloud Function.
|
|
3
3
|
* Reads pending notifications, groups by dedupKey, creates/increments active docs.
|
|
4
4
|
*/
|
|
5
|
+
import { buildActiveNotificationDocId } from './activeNotificationId.js';
|
|
5
6
|
const DEFAULT_COUNT_CAP = 5000;
|
|
6
7
|
const DEFAULT_ACTOR_CAP = 5;
|
|
7
8
|
const PROCESSING_BATCH_SIZE = 500;
|
|
@@ -79,14 +80,16 @@ export async function processBatchHelper(db, config) {
|
|
|
79
80
|
});
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
|
-
// Process each group:
|
|
83
|
-
//
|
|
84
|
-
// a
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
83
|
+
// Process each group: create or increment the group's active doc.
|
|
84
|
+
// Each group's groupKey uniquely determines a single active doc — the doc ID
|
|
85
|
+
// is a deterministic hash of exactly the dedupKey + category (+ targetUserId
|
|
86
|
+
// for personal) that compose the groupKey — so two distinct groups can never
|
|
87
|
+
// resolve to the same active doc and there is no cross-group contention. The
|
|
88
|
+
// work per group is independent I/O, so Promise.all turns N sequential
|
|
89
|
+
// round-trips into one parallel wave, removing the timeout risk under high
|
|
90
|
+
// dedup-group counts. WITHIN a dedup scope, the transactional read-modify-write
|
|
91
|
+
// on the deterministic ID makes concurrent writers (a racing real-time send,
|
|
92
|
+
// or an overlapping batch run) converge on one doc with correct counts.
|
|
90
93
|
const groupResults = await Promise.all(Array.from(groups.values()).map(async (group) => {
|
|
91
94
|
const typeConfig = config.types[group.type];
|
|
92
95
|
if (!typeConfig)
|
|
@@ -98,64 +101,65 @@ export async function processBatchHelper(db, config) {
|
|
|
98
101
|
const dedupKey = typeConfig.dedupKeyPattern(group.metadata);
|
|
99
102
|
const countCap = typeConfig.countCap ?? DEFAULT_COUNT_CAP;
|
|
100
103
|
const actorCap = typeConfig.actorCap ?? DEFAULT_ACTOR_CAP;
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
.
|
|
106
|
-
.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
104
|
+
// Personal notifications are scoped to the recipient so different
|
|
105
|
+
// recipients never share an active doc; shared notifications omit
|
|
106
|
+
// targetUserId by design.
|
|
107
|
+
const activeDocRef = db.collection(activePath).doc(buildActiveNotificationDocId({
|
|
108
|
+
category: group.category,
|
|
109
|
+
audienceType: categoryConfig.audienceType,
|
|
110
|
+
targetUserId: group.targetUserId,
|
|
111
|
+
dedupKey,
|
|
112
|
+
}));
|
|
113
|
+
return db.runTransaction(async (tx) => {
|
|
114
|
+
const existingSnap = await tx.get(activeDocRef);
|
|
115
|
+
if (existingSnap.exists) {
|
|
116
|
+
// Increment existing
|
|
117
|
+
const existingData = (existingSnap.data() ?? {});
|
|
118
|
+
const currentCount = existingData.count || 1;
|
|
119
|
+
const currentActorIds = existingData.latestActorIds || [];
|
|
120
|
+
// Merge actor ids (new first, deduped, capped)
|
|
121
|
+
const newActorIds = group.actorIds.filter((id) => !currentActorIds.includes(id));
|
|
122
|
+
const mergedActorIds = [
|
|
123
|
+
...newActorIds,
|
|
124
|
+
...currentActorIds,
|
|
125
|
+
].slice(0, actorCap);
|
|
126
|
+
const newCount = Math.min(currentCount + group.count, countCap);
|
|
127
|
+
tx.update(activeDocRef, {
|
|
128
|
+
count: newCount,
|
|
129
|
+
latestActorIds: mergedActorIds,
|
|
130
|
+
message: typeConfig.messagePattern(group.metadata, newCount),
|
|
131
|
+
// New activity on an existing notification re-lights the unread badge.
|
|
132
|
+
seenAt: 0,
|
|
133
|
+
updatedAt: Date.now(),
|
|
134
|
+
});
|
|
135
|
+
return 'updated';
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
// Create new notification
|
|
139
|
+
const targetPath = typeof typeConfig.defaultTargetPath === 'function'
|
|
140
|
+
? typeConfig.defaultTargetPath(group.metadata)
|
|
141
|
+
: typeConfig.defaultTargetPath;
|
|
142
|
+
const now = Date.now();
|
|
143
|
+
const newDoc = {
|
|
144
|
+
type: group.type,
|
|
145
|
+
dedupKey,
|
|
146
|
+
category: group.category,
|
|
147
|
+
targetUserId: group.targetUserId,
|
|
148
|
+
title: typeConfig.titlePattern(group.metadata),
|
|
149
|
+
message: typeConfig.messagePattern(group.metadata, group.count),
|
|
150
|
+
count: group.count,
|
|
151
|
+
latestActorIds: group.actorIds.slice(0, actorCap),
|
|
152
|
+
targetPath,
|
|
153
|
+
metadata: group.metadata,
|
|
154
|
+
// Active docs are created unseen so the unread count() predicate matches.
|
|
155
|
+
seenAt: 0,
|
|
156
|
+
createdAt: now,
|
|
157
|
+
updatedAt: now,
|
|
158
|
+
};
|
|
159
|
+
tx.set(activeDocRef, newDoc);
|
|
160
|
+
return 'created';
|
|
161
|
+
}
|
|
162
|
+
});
|
|
159
163
|
}));
|
|
160
164
|
for (const r of groupResults) {
|
|
161
165
|
if (r === 'created')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"processBatchHelper.js","sourceRoot":"","sources":["../../src/server/processBatchHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"processBatchHelper.js","sourceRoot":"","sources":["../../src/server/processBatchHelper.ts"],"names":[],"mappings":"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"}
|
package/dist/server/types.d.ts
CHANGED
|
@@ -10,6 +10,15 @@ export interface ServerFirestore {
|
|
|
10
10
|
collection(path: string): ServerCollectionRef;
|
|
11
11
|
doc(path: string): ServerDocRef;
|
|
12
12
|
batch(): ServerWriteBatch;
|
|
13
|
+
runTransaction<T>(updateFunction: (transaction: ServerTransaction) => Promise<T>): Promise<T>;
|
|
14
|
+
}
|
|
15
|
+
export interface ServerTransaction {
|
|
16
|
+
get(ref: ServerDocRef): Promise<ServerDocSnapshot>;
|
|
17
|
+
set(ref: ServerDocRef, data: Record<string, unknown>, options?: {
|
|
18
|
+
merge?: boolean;
|
|
19
|
+
}): ServerTransaction;
|
|
20
|
+
update(ref: ServerDocRef, data: Record<string, unknown>): ServerTransaction;
|
|
21
|
+
delete(ref: ServerDocRef): ServerTransaction;
|
|
13
22
|
}
|
|
14
23
|
export interface ServerCollectionRef {
|
|
15
24
|
doc(id?: string): ServerDocRef;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,CAAC;IAC9C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAAC;IAChC,KAAK,IAAI,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttt-productions/notification-core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.10",
|
|
4
4
|
"description": "Shared notification system for TTT Productions apps — active/history two-tier architecture with dedup, batch processing, and themed UI components",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"@tanstack/react-query": ">=5.0.0",
|
|
42
|
-
"@ttt-productions/query-core": "^0.8.
|
|
42
|
+
"@ttt-productions/query-core": "^0.8.8",
|
|
43
43
|
"@ttt-productions/ui-core": "^0.6.4",
|
|
44
44
|
"firebase": ">=10.0.0",
|
|
45
45
|
"react": ">=18.0.0",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@tanstack/react-query": "^5.0.0",
|
|
70
|
-
"@ttt-productions/query-core": "^0.8.
|
|
70
|
+
"@ttt-productions/query-core": "^0.8.8",
|
|
71
71
|
"@ttt-productions/ui-core": "^0.6.4",
|
|
72
72
|
"@types/react": "^19.0.0",
|
|
73
73
|
"@types/react-dom": "^19.0.0",
|
|
@@ -11,23 +11,23 @@
|
|
|
11
11
|
display: flex;
|
|
12
12
|
flex-direction: column;
|
|
13
13
|
max-height: 24rem;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Header stays pinned; only the body scrolls. */
|
|
17
|
+
.ntf-list-body {
|
|
18
|
+
flex: 1;
|
|
19
|
+
min-height: 0;
|
|
14
20
|
overflow-y: auto;
|
|
15
21
|
}
|
|
16
22
|
|
|
17
23
|
.ntf-list-header {
|
|
18
24
|
display: flex;
|
|
19
25
|
align-items: center;
|
|
20
|
-
justify-content:
|
|
21
|
-
padding: 0.
|
|
26
|
+
justify-content: flex-end;
|
|
27
|
+
padding: 0.25rem 0.5rem;
|
|
22
28
|
border-bottom: 1px solid hsl(var(--border));
|
|
23
29
|
}
|
|
24
30
|
|
|
25
|
-
.ntf-list-header-title {
|
|
26
|
-
font-weight: 600;
|
|
27
|
-
font-size: 0.875rem;
|
|
28
|
-
color: hsl(var(--foreground));
|
|
29
|
-
}
|
|
30
|
-
|
|
31
31
|
.ntf-list-footer {
|
|
32
32
|
display: flex;
|
|
33
33
|
align-items: center;
|