@ttt-productions/notification-core 0.4.2 → 0.4.3

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.
Files changed (39) hide show
  1. package/dist/react/components/NotificationList.d.ts +1 -1
  2. package/dist/react/components/NotificationList.d.ts.map +1 -1
  3. package/dist/react/components/NotificationList.js +7 -20
  4. package/dist/react/components/NotificationList.js.map +1 -1
  5. package/dist/react/hooks/useArchiveAllNotifications.d.ts +10 -12
  6. package/dist/react/hooks/useArchiveAllNotifications.d.ts.map +1 -1
  7. package/dist/react/hooks/useArchiveAllNotifications.js +10 -58
  8. package/dist/react/hooks/useArchiveAllNotifications.js.map +1 -1
  9. package/dist/react/hooks/useArchiveNotification.d.ts +12 -11
  10. package/dist/react/hooks/useArchiveNotification.d.ts.map +1 -1
  11. package/dist/react/hooks/useArchiveNotification.js +12 -39
  12. package/dist/react/hooks/useArchiveNotification.js.map +1 -1
  13. package/dist/react/hooks/useUnreadCount.d.ts +30 -21
  14. package/dist/react/hooks/useUnreadCount.d.ts.map +1 -1
  15. package/dist/react/hooks/useUnreadCount.js +29 -15
  16. package/dist/react/hooks/useUnreadCount.js.map +1 -1
  17. package/dist/server/archiveNotificationHelper.d.ts +14 -3
  18. package/dist/server/archiveNotificationHelper.d.ts.map +1 -1
  19. package/dist/server/archiveNotificationHelper.js +35 -7
  20. package/dist/server/archiveNotificationHelper.js.map +1 -1
  21. package/dist/server/createNotificationHelper.d.ts.map +1 -1
  22. package/dist/server/createNotificationHelper.js +31 -4
  23. package/dist/server/createNotificationHelper.js.map +1 -1
  24. package/dist/server/index.d.ts +1 -0
  25. package/dist/server/index.d.ts.map +1 -1
  26. package/dist/server/index.js +1 -0
  27. package/dist/server/index.js.map +1 -1
  28. package/dist/server/markSeenHelper.d.ts +17 -0
  29. package/dist/server/markSeenHelper.d.ts.map +1 -0
  30. package/dist/server/markSeenHelper.js +29 -0
  31. package/dist/server/markSeenHelper.js.map +1 -0
  32. package/dist/server/processBatchHelper.d.ts.map +1 -1
  33. package/dist/server/processBatchHelper.js +4 -0
  34. package/dist/server/processBatchHelper.js.map +1 -1
  35. package/dist/server/types.d.ts +6 -0
  36. package/dist/server/types.d.ts.map +1 -1
  37. package/dist/types.d.ts +39 -5
  38. package/dist/types.d.ts.map +1 -1
  39. package/package.json +1 -1
@@ -2,5 +2,5 @@ import type { NotificationListProps } from '../../types.js';
2
2
  /**
3
3
  * Scrollable list of active notifications with click-to-archive and clear-all.
4
4
  */
5
- export declare function NotificationList({ config, userId, category, onNotificationClick, onClearAll, refetchInterval, device, emptyText, }: NotificationListProps): import("react/jsx-runtime").JSX.Element;
5
+ export declare function NotificationList({ config, userId, category, onNotificationClick, archiveFn, archiveAllFn, onClearAll, refetchInterval, emptyText, }: NotificationListProps): import("react/jsx-runtime").JSX.Element;
6
6
  //# sourceMappingURL=NotificationList.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"NotificationList.d.ts","sourceRoot":"","sources":["../../../src/react/components/NotificationList.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAmB,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE7E;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,MAAM,EACN,QAAQ,EACR,mBAAmB,EACnB,UAAU,EACV,eAAe,EACf,MAAc,EACd,SAAS,GACV,EAAE,qBAAqB,2CA2IvB"}
1
+ {"version":3,"file":"NotificationList.d.ts","sourceRoot":"","sources":["../../../src/react/components/NotificationList.tsx"],"names":[],"mappings":"AAUA,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,2CA8HvB"}
@@ -11,7 +11,7 @@ import { formatRelativeTime } from './relative-time.js';
11
11
  /**
12
12
  * Scrollable list of active notifications with click-to-archive and clear-all.
13
13
  */
14
- export function NotificationList({ config, userId, category, onNotificationClick, onClearAll, refetchInterval, device = 'web', emptyText, }) {
14
+ export function NotificationList({ config, userId, category, onNotificationClick, archiveFn, archiveAllFn, onClearAll, refetchInterval, emptyText, }) {
15
15
  const { data: notifications, isLoading, hasNextPage, nextPage, } = useActiveNotifications({
16
16
  config,
17
17
  userId,
@@ -25,46 +25,33 @@ export function NotificationList({ config, userId, category, onNotificationClick
25
25
  refetchInterval,
26
26
  });
27
27
  const archiveMutation = useArchiveNotification({
28
- config,
29
28
  userId,
30
29
  category,
30
+ archiveFn,
31
31
  });
32
32
  const archiveAllMutation = useArchiveAllNotifications({
33
- config,
34
33
  userId,
35
34
  category,
35
+ archiveAllFn,
36
36
  });
37
37
  const handleNotificationClick = useCallback(async (notification) => {
38
38
  try {
39
- await archiveMutation.mutateAsync({
40
- notificationId: notification.id,
41
- archivalInfo: {
42
- archivedBy: userId,
43
- archivedAt: Date.now(),
44
- device,
45
- },
46
- });
39
+ await archiveMutation.mutateAsync(notification.id);
47
40
  }
48
41
  catch {
49
42
  // Still navigate even if archive fails
50
43
  }
51
44
  onNotificationClick(notification);
52
- }, [archiveMutation, userId, device, onNotificationClick]);
45
+ }, [archiveMutation, onNotificationClick]);
53
46
  const handleClearAll = useCallback(async () => {
54
47
  try {
55
- await archiveAllMutation.mutateAsync({
56
- archivalInfo: {
57
- archivedBy: userId,
58
- archivedAt: Date.now(),
59
- device,
60
- },
61
- });
48
+ await archiveAllMutation.mutateAsync();
62
49
  }
63
50
  catch {
64
51
  // Silently fail
65
52
  }
66
53
  onClearAll?.();
67
- }, [archiveAllMutation, userId, device, onClearAll]);
54
+ }, [archiveAllMutation, onClearAll]);
68
55
  const getTypeIcon = useCallback((type) => {
69
56
  const typeConfig = config.types[type];
70
57
  return typeConfig?.icon ?? '🔔';
@@ -1 +1 @@
1
- {"version":3,"file":"NotificationList.js","sourceRoot":"","sources":["../../../src/react/components/NotificationList.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"NotificationList.js","sourceRoot":"","sources":["../../../src/react/components/NotificationList.tsx"],"names":[],"mappings":"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"}
@@ -1,24 +1,22 @@
1
- import type { ArchivalInfo, UseArchiveAllNotificationsOptions } from '../../types.js';
1
+ import type { UseArchiveAllNotificationsOptions } from '../../types.js';
2
2
  /**
3
- * Archive all active notifications in batches.
4
- * Reads active docs in batches of 50, archives each batch, repeats until empty.
3
+ * Archive the caller's whole category through an app-supplied callable adapter.
4
+ *
5
+ * Like {@link useArchiveNotification}, this performs no client Firestore writes
6
+ * — paging + ownership-checked deletion happen server-side via the callable the
7
+ * app wires into `archiveAllFn`. On success it invalidates the read keys.
5
8
  *
6
9
  * @example
7
10
  * ```tsx
11
+ * const archiveNotification = httpsCallable(functions, 'archiveNotification');
8
12
  * const archiveAll = useArchiveAllNotifications({
9
- * config: TTT_NOTIFICATION_CONFIG,
10
13
  * userId: user.uid,
11
14
  * category: 'user',
15
+ * archiveAllFn: () => archiveNotification({ category: 'user', scope: { kind: 'all' } }),
12
16
  * });
13
17
  *
14
- * archiveAll.mutate({
15
- * archivalInfo: { archivedBy: user.uid, archivedAt: Date.now(), device: 'web' },
16
- * });
18
+ * archiveAll.mutate();
17
19
  * ```
18
20
  */
19
- export declare function useArchiveAllNotifications({ config, userId, category, invalidateKeys, }: UseArchiveAllNotificationsOptions): import("@tanstack/react-query").UseMutationResult<{
20
- totalArchived: number;
21
- }, Error, {
22
- archivalInfo: ArchivalInfo;
23
- }, unknown>;
21
+ export declare function useArchiveAllNotifications({ userId, category, archiveAllFn, invalidateKeys, }: UseArchiveAllNotificationsOptions): import("@tanstack/react-query").UseMutationResult<unknown, Error, void, unknown>;
24
22
  //# sourceMappingURL=useArchiveAllNotifications.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useArchiveAllNotifications.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useArchiveAllNotifications.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAEV,YAAY,EACZ,iCAAiC,EAClC,MAAM,gBAAgB,CAAC;AAIxB;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,MAAM,EACN,MAAM,EACN,QAAQ,EACR,cAAc,GACf,EAAE,iCAAiC;;;kBAehB,YAAY;YAkE/B"}
1
+ {"version":3,"file":"useArchiveAllNotifications.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useArchiveAllNotifications.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,gBAAgB,CAAC;AAExE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,cAAc,GACf,EAAE,iCAAiC,oFAkBnC"}
@@ -1,81 +1,33 @@
1
1
  'use client';
2
2
  import { useMutation, useQueryClient } from '@tanstack/react-query';
3
- import { collection, query, where, orderBy, limit, getDocs, doc, writeBatch, } from 'firebase/firestore';
4
- import { useFirestoreDb } from '@ttt-productions/query-core/react';
5
- const BATCH_SIZE = 50;
6
3
  /**
7
- * Archive all active notifications in batches.
8
- * Reads active docs in batches of 50, archives each batch, repeats until empty.
4
+ * Archive the caller's whole category through an app-supplied callable adapter.
5
+ *
6
+ * Like {@link useArchiveNotification}, this performs no client Firestore writes
7
+ * — paging + ownership-checked deletion happen server-side via the callable the
8
+ * app wires into `archiveAllFn`. On success it invalidates the read keys.
9
9
  *
10
10
  * @example
11
11
  * ```tsx
12
+ * const archiveNotification = httpsCallable(functions, 'archiveNotification');
12
13
  * const archiveAll = useArchiveAllNotifications({
13
- * config: TTT_NOTIFICATION_CONFIG,
14
14
  * userId: user.uid,
15
15
  * category: 'user',
16
+ * archiveAllFn: () => archiveNotification({ category: 'user', scope: { kind: 'all' } }),
16
17
  * });
17
18
  *
18
- * archiveAll.mutate({
19
- * archivalInfo: { archivedBy: user.uid, archivedAt: Date.now(), device: 'web' },
20
- * });
19
+ * archiveAll.mutate();
21
20
  * ```
22
21
  */
23
- export function useArchiveAllNotifications({ config, userId, category, invalidateKeys, }) {
24
- const db = useFirestoreDb();
22
+ export function useArchiveAllNotifications({ userId, category, archiveAllFn, invalidateKeys, }) {
25
23
  const queryClient = useQueryClient();
26
- const categoryConfig = config.categories[category];
27
24
  const defaultInvalidateKeys = [
28
25
  ['notifications', 'active', category, userId],
29
26
  ['notifications', 'unread-count', category, userId],
30
27
  ['notifications', 'history', category, userId],
31
28
  ];
32
29
  return useMutation({
33
- mutationFn: async ({ archivalInfo, }) => {
34
- if (!categoryConfig) {
35
- throw new Error(`[notification-core] Unknown category: ${category}`);
36
- }
37
- const activePath = categoryConfig.activePath;
38
- const historyPath = categoryConfig.historyPath(userId);
39
- const isPersonal = categoryConfig.audienceType === 'personal';
40
- let totalArchived = 0;
41
- let hasMore = true;
42
- while (hasMore) {
43
- const constraints = [
44
- ...(isPersonal ? [where('targetUserId', '==', userId)] : []),
45
- orderBy('updatedAt', 'desc'),
46
- limit(BATCH_SIZE),
47
- ];
48
- const q = query(collection(db, activePath), ...constraints);
49
- const snapshot = await getDocs(q);
50
- if (snapshot.empty) {
51
- hasMore = false;
52
- break;
53
- }
54
- const batch = writeBatch(db);
55
- snapshot.docs.forEach((docSnap) => {
56
- const data = docSnap.data();
57
- // Write to history
58
- const historyRef = doc(db, historyPath, docSnap.id);
59
- batch.set(historyRef, {
60
- ...data,
61
- id: docSnap.id,
62
- archival: archivalInfo,
63
- ...(categoryConfig.audienceType === 'shared'
64
- ? { handledBy: archivalInfo.archivedBy }
65
- : {}),
66
- });
67
- // Delete from active
68
- const activeRef = doc(db, activePath, docSnap.id);
69
- batch.delete(activeRef);
70
- });
71
- await batch.commit();
72
- totalArchived += snapshot.docs.length;
73
- if (snapshot.docs.length < BATCH_SIZE) {
74
- hasMore = false;
75
- }
76
- }
77
- return { totalArchived };
78
- },
30
+ mutationFn: async () => archiveAllFn(),
79
31
  onSuccess: () => {
80
32
  const keysToInvalidate = invalidateKeys ?? defaultInvalidateKeys;
81
33
  keysToInvalidate.forEach((key) => {
@@ -1 +1 @@
1
- {"version":3,"file":"useArchiveAllNotifications.js","sourceRoot":"","sources":["../../../src/react/hooks/useArchiveAllNotifications.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useArchiveAllNotifications.js","sourceRoot":"","sources":["../../../src/react/hooks/useArchiveAllNotifications.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGpE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,0BAA0B,CAAC,EACzC,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,cAAc,GACoB;IAClC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,MAAM,qBAAqB,GAAG;QAC5B,CAAC,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC;QAC7C,CAAC,eAAe,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,CAAC;QACnD,CAAC,eAAe,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC;KAC/C,CAAC;IAEF,OAAO,WAAW,CAAC;QACjB,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,YAAY,EAAE;QACtC,SAAS,EAAE,GAAG,EAAE;YACd,MAAM,gBAAgB,GAAG,cAAc,IAAI,qBAAqB,CAAC;YACjE,gBAAgB,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBAC/B,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACtE,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -1,23 +1,24 @@
1
- import type { ArchivalInfo, UseArchiveNotificationOptions } from '../../types.js';
1
+ import type { UseArchiveNotificationOptions } from '../../types.js';
2
2
  /**
3
- * Archive a single notification: read from active write to history → delete from active.
3
+ * Archive a single notification through an app-supplied callable adapter.
4
+ *
5
+ * The notification system is Cloud-Functions-only: clients never write
6
+ * notification docs. This hook performs no Firestore writes — it delegates to
7
+ * `archiveFn` (wired by the app to `httpsCallable(functions, 'archiveNotification')`)
8
+ * and invalidates the read keys on success.
4
9
  *
5
10
  * @example
6
11
  * ```tsx
12
+ * const archiveNotification = httpsCallable(functions, 'archiveNotification');
7
13
  * const archive = useArchiveNotification({
8
- * config: TTT_NOTIFICATION_CONFIG,
9
14
  * userId: user.uid,
10
15
  * category: 'user',
16
+ * archiveFn: (notificationId) =>
17
+ * archiveNotification({ category: 'user', scope: { kind: 'single', notificationId } }),
11
18
  * });
12
19
  *
13
- * archive.mutate({
14
- * notificationId: 'abc123',
15
- * archivalInfo: { archivedBy: user.uid, archivedAt: Date.now(), device: 'web' },
16
- * });
20
+ * archive.mutate('abc123');
17
21
  * ```
18
22
  */
19
- export declare function useArchiveNotification({ config, userId, category, invalidateKeys, }: UseArchiveNotificationOptions): import("@tanstack/react-query").UseMutationResult<void, Error, {
20
- notificationId: string;
21
- archivalInfo: ArchivalInfo;
22
- }, unknown>;
23
+ export declare function useArchiveNotification({ userId, category, archiveFn, invalidateKeys, }: UseArchiveNotificationOptions): import("@tanstack/react-query").UseMutationResult<unknown, Error, string, unknown>;
23
24
  //# sourceMappingURL=useArchiveNotification.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useArchiveNotification.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useArchiveNotification.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAGV,YAAY,EACZ,6BAA6B,EAC9B,MAAM,gBAAgB,CAAC;AAExB;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,EACN,MAAM,EACN,QAAQ,EACR,cAAc,GACf,EAAE,6BAA6B;oBAgBV,MAAM;kBACR,YAAY;YA2C/B"}
1
+ {"version":3,"file":"useArchiveNotification.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useArchiveNotification.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,EACN,QAAQ,EACR,SAAS,EACT,cAAc,GACf,EAAE,6BAA6B,sFAkB/B"}
@@ -1,62 +1,35 @@
1
1
  'use client';
2
2
  import { useMutation, useQueryClient } from '@tanstack/react-query';
3
- import { doc, getDoc, setDoc, deleteDoc } from 'firebase/firestore';
4
- import { useFirestoreDb } from '@ttt-productions/query-core/react';
5
3
  /**
6
- * Archive a single notification: read from active write to history → delete from active.
4
+ * Archive a single notification through an app-supplied callable adapter.
5
+ *
6
+ * The notification system is Cloud-Functions-only: clients never write
7
+ * notification docs. This hook performs no Firestore writes — it delegates to
8
+ * `archiveFn` (wired by the app to `httpsCallable(functions, 'archiveNotification')`)
9
+ * and invalidates the read keys on success.
7
10
  *
8
11
  * @example
9
12
  * ```tsx
13
+ * const archiveNotification = httpsCallable(functions, 'archiveNotification');
10
14
  * const archive = useArchiveNotification({
11
- * config: TTT_NOTIFICATION_CONFIG,
12
15
  * userId: user.uid,
13
16
  * category: 'user',
17
+ * archiveFn: (notificationId) =>
18
+ * archiveNotification({ category: 'user', scope: { kind: 'single', notificationId } }),
14
19
  * });
15
20
  *
16
- * archive.mutate({
17
- * notificationId: 'abc123',
18
- * archivalInfo: { archivedBy: user.uid, archivedAt: Date.now(), device: 'web' },
19
- * });
21
+ * archive.mutate('abc123');
20
22
  * ```
21
23
  */
22
- export function useArchiveNotification({ config, userId, category, invalidateKeys, }) {
23
- const db = useFirestoreDb();
24
+ export function useArchiveNotification({ userId, category, archiveFn, invalidateKeys, }) {
24
25
  const queryClient = useQueryClient();
25
- const categoryConfig = config.categories[category];
26
26
  const defaultInvalidateKeys = [
27
27
  ['notifications', 'active', category, userId],
28
28
  ['notifications', 'unread-count', category, userId],
29
29
  ['notifications', 'history', category, userId],
30
30
  ];
31
31
  return useMutation({
32
- mutationFn: async ({ notificationId, archivalInfo, }) => {
33
- if (!categoryConfig) {
34
- throw new Error(`[notification-core] Unknown category: ${category}`);
35
- }
36
- const activePath = categoryConfig.activePath;
37
- const historyPath = categoryConfig.historyPath(userId);
38
- // Read active doc
39
- const activeRef = doc(db, activePath, notificationId);
40
- const activeSnap = await getDoc(activeRef);
41
- if (!activeSnap.exists()) {
42
- // Already archived or deleted — no-op
43
- return;
44
- }
45
- const activeData = { id: activeSnap.id, ...activeSnap.data() };
46
- // Build history doc
47
- const historyDoc = {
48
- ...activeData,
49
- archival: archivalInfo,
50
- ...(categoryConfig.audienceType === 'shared'
51
- ? { handledBy: archivalInfo.archivedBy }
52
- : {}),
53
- };
54
- // Write to history
55
- const historyRef = doc(db, historyPath, notificationId);
56
- await setDoc(historyRef, historyDoc);
57
- // Delete from active
58
- await deleteDoc(activeRef);
59
- },
32
+ mutationFn: async (notificationId) => archiveFn(notificationId),
60
33
  onSuccess: () => {
61
34
  const keysToInvalidate = invalidateKeys ?? defaultInvalidateKeys;
62
35
  keysToInvalidate.forEach((key) => {
@@ -1 +1 @@
1
- {"version":3,"file":"useArchiveNotification.js","sourceRoot":"","sources":["../../../src/react/hooks/useArchiveNotification.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAQnE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,sBAAsB,CAAC,EACrC,MAAM,EACN,MAAM,EACN,QAAQ,EACR,cAAc,GACgB;IAC9B,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;IAC5B,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,MAAM,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAEnD,MAAM,qBAAqB,GAAG;QAC5B,CAAC,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC;QAC7C,CAAC,eAAe,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,CAAC;QACnD,CAAC,eAAe,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC;KAC/C,CAAC;IAEF,OAAO,WAAW,CAAC;QACjB,UAAU,EAAE,KAAK,EAAE,EACjB,cAAc,EACd,YAAY,GAIb,EAAE,EAAE;YACH,IAAI,CAAC,cAAc,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,yCAAyC,QAAQ,EAAE,CAAC,CAAC;YACvE,CAAC;YAED,MAAM,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC;YAC7C,MAAM,WAAW,GAAG,cAAc,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAEvD,kBAAkB;YAClB,MAAM,SAAS,GAAG,GAAG,CAAC,EAAE,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC;YACtD,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;YAE3C,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;gBACzB,sCAAsC;gBACtC,OAAO;YACT,CAAC;YAED,MAAM,UAAU,GAAG,EAAE,EAAE,EAAE,UAAU,CAAC,EAAE,EAAE,GAAG,UAAU,CAAC,IAAI,EAAE,EAAqB,CAAC;YAElF,oBAAoB;YACpB,MAAM,UAAU,GAAuC;gBACrD,GAAG,UAAU;gBACb,QAAQ,EAAE,YAAY;gBACtB,GAAG,CAAC,cAAc,CAAC,YAAY,KAAK,QAAQ;oBAC1C,CAAC,CAAC,EAAE,SAAS,EAAE,YAAY,CAAC,UAAU,EAAE;oBACxC,CAAC,CAAC,EAAE,CAAC;aACR,CAAC;YAEF,mBAAmB;YACnB,MAAM,UAAU,GAAG,GAAG,CAAC,EAAE,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;YACxD,MAAM,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YAErC,qBAAqB;YACrB,MAAM,SAAS,CAAC,SAAS,CAAC,CAAC;QAC7B,CAAC;QACD,SAAS,EAAE,GAAG,EAAE;YACd,MAAM,gBAAgB,GAAG,cAAc,IAAI,qBAAqB,CAAC;YACjE,gBAAgB,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBAC/B,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACtE,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"useArchiveNotification.js","sourceRoot":"","sources":["../../../src/react/hooks/useArchiveNotification.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGpE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,sBAAsB,CAAC,EACrC,MAAM,EACN,QAAQ,EACR,SAAS,EACT,cAAc,GACgB;IAC9B,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,MAAM,qBAAqB,GAAG;QAC5B,CAAC,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC;QAC7C,CAAC,eAAe,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,CAAC;QACnD,CAAC,eAAe,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC;KAC/C,CAAC;IAEF,OAAO,WAAW,CAAC;QACjB,UAAU,EAAE,KAAK,EAAE,cAAsB,EAAE,EAAE,CAAC,SAAS,CAAC,cAAc,CAAC;QACvE,SAAS,EAAE,GAAG,EAAE;YACd,MAAM,gBAAgB,GAAG,cAAc,IAAI,qBAAqB,CAAC;YACjE,gBAAgB,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBAC/B,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACtE,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -1,7 +1,16 @@
1
- import type { NotificationDoc, UseUnreadCountOptions } from '../../types.js';
1
+ import type { UseUnreadCountOptions } from '../../types.js';
2
2
  /**
3
- * Lightweight unread count query. Fetches up to `countLimit` docs to determine count.
4
- * Uses polling for cost control.
3
+ * Unread-count badge backed by a Firestore `count()` aggregation (a server-side
4
+ * count, not a doc fetch). Polls for cost control; displays capped
5
+ * (`hasMore` → `99+`).
6
+ *
7
+ * - **personal** categories count **unseen** active items (`seenAt == 0`),
8
+ * scoped to the caller (`targetUserId == uid`);
9
+ * - **shared** categories have no per-admin seen state, so the indicator is
10
+ * existence-based — a count of all active items, with no `seenAt` predicate.
11
+ *
12
+ * The personal `seenAt == 0` predicate needs a composite index, captured as an
13
+ * app-side index step.
5
14
  *
6
15
  * @example
7
16
  * ```tsx
@@ -35,9 +44,9 @@ export declare function useUnreadCount({ config, userId, category, enabled, refe
35
44
  isRefetching: boolean;
36
45
  isStale: boolean;
37
46
  isEnabled: boolean;
38
- refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<import("@ttt-productions/query-core/types").WithId<NotificationDoc>[], Error>>;
39
- fetchStatus: import("@tanstack/query-core").FetchStatus;
40
- promise: Promise<import("@ttt-productions/query-core/types").WithId<NotificationDoc>[]>;
47
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<number, Error>>;
48
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
49
+ promise: Promise<number>;
41
50
  count: number;
42
51
  hasMore: boolean;
43
52
  } | {
@@ -63,9 +72,9 @@ export declare function useUnreadCount({ config, userId, category, enabled, refe
63
72
  isRefetching: boolean;
64
73
  isStale: boolean;
65
74
  isEnabled: boolean;
66
- refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<import("@ttt-productions/query-core/types").WithId<NotificationDoc>[], Error>>;
67
- fetchStatus: import("@tanstack/query-core").FetchStatus;
68
- promise: Promise<import("@ttt-productions/query-core/types").WithId<NotificationDoc>[]>;
75
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<number, Error>>;
76
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
77
+ promise: Promise<number>;
69
78
  count: number;
70
79
  hasMore: boolean;
71
80
  } | {
@@ -91,9 +100,9 @@ export declare function useUnreadCount({ config, userId, category, enabled, refe
91
100
  isRefetching: boolean;
92
101
  isStale: boolean;
93
102
  isEnabled: boolean;
94
- refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<import("@ttt-productions/query-core/types").WithId<NotificationDoc>[], Error>>;
95
- fetchStatus: import("@tanstack/query-core").FetchStatus;
96
- promise: Promise<import("@ttt-productions/query-core/types").WithId<NotificationDoc>[]>;
103
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<number, Error>>;
104
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
105
+ promise: Promise<number>;
97
106
  count: number;
98
107
  hasMore: boolean;
99
108
  } | {
@@ -119,9 +128,9 @@ export declare function useUnreadCount({ config, userId, category, enabled, refe
119
128
  isRefetching: boolean;
120
129
  isStale: boolean;
121
130
  isEnabled: boolean;
122
- refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<import("@ttt-productions/query-core/types").WithId<NotificationDoc>[], Error>>;
123
- fetchStatus: import("@tanstack/query-core").FetchStatus;
124
- promise: Promise<import("@ttt-productions/query-core/types").WithId<NotificationDoc>[]>;
131
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<number, Error>>;
132
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
133
+ promise: Promise<number>;
125
134
  count: number;
126
135
  hasMore: boolean;
127
136
  } | {
@@ -147,9 +156,9 @@ export declare function useUnreadCount({ config, userId, category, enabled, refe
147
156
  isRefetching: boolean;
148
157
  isStale: boolean;
149
158
  isEnabled: boolean;
150
- refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<import("@ttt-productions/query-core/types").WithId<NotificationDoc>[], Error>>;
151
- fetchStatus: import("@tanstack/query-core").FetchStatus;
152
- promise: Promise<import("@ttt-productions/query-core/types").WithId<NotificationDoc>[]>;
159
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<number, Error>>;
160
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
161
+ promise: Promise<number>;
153
162
  count: number;
154
163
  hasMore: boolean;
155
164
  } | {
@@ -175,9 +184,9 @@ export declare function useUnreadCount({ config, userId, category, enabled, refe
175
184
  isRefetching: boolean;
176
185
  isStale: boolean;
177
186
  isEnabled: boolean;
178
- refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<import("@ttt-productions/query-core/types").WithId<NotificationDoc>[], Error>>;
179
- fetchStatus: import("@tanstack/query-core").FetchStatus;
180
- promise: Promise<import("@ttt-productions/query-core/types").WithId<NotificationDoc>[]>;
187
+ refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<number, Error>>;
188
+ fetchStatus: import("@tanstack/react-query").FetchStatus;
189
+ promise: Promise<number>;
181
190
  count: number;
182
191
  hasMore: boolean;
183
192
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useUnreadCount.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useUnreadCount.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAK7E;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAc,EACd,eAA0C,EAC1C,UAAgC,GACjC,EAAE,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BvB"}
1
+ {"version":3,"file":"useUnreadCount.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useUnreadCount.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAK5D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAc,EACd,eAA0C,EAC1C,UAAgC,GACjC,EAAE,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkCvB"}
@@ -1,11 +1,21 @@
1
1
  'use client';
2
- import { useFirestoreCollection } from '@ttt-productions/query-core/react';
3
- import { where, orderBy, limit } from 'firebase/firestore';
2
+ import { useQuery } from '@tanstack/react-query';
3
+ import { collection, query, where, getCountFromServer, } from 'firebase/firestore';
4
+ import { useFirestoreDb } from '@ttt-productions/query-core/react';
4
5
  const DEFAULT_REFETCH_INTERVAL = 30_000;
5
6
  const DEFAULT_COUNT_LIMIT = 99;
6
7
  /**
7
- * Lightweight unread count query. Fetches up to `countLimit` docs to determine count.
8
- * Uses polling for cost control.
8
+ * Unread-count badge backed by a Firestore `count()` aggregation (a server-side
9
+ * count, not a doc fetch). Polls for cost control; displays capped
10
+ * (`hasMore` → `99+`).
11
+ *
12
+ * - **personal** categories count **unseen** active items (`seenAt == 0`),
13
+ * scoped to the caller (`targetUserId == uid`);
14
+ * - **shared** categories have no per-admin seen state, so the indicator is
15
+ * existence-based — a count of all active items, with no `seenAt` predicate.
16
+ *
17
+ * The personal `seenAt == 0` predicate needs a composite index, captured as an
18
+ * app-side index step.
9
19
  *
10
20
  * @example
11
21
  * ```tsx
@@ -17,28 +27,32 @@ const DEFAULT_COUNT_LIMIT = 99;
17
27
  * ```
18
28
  */
19
29
  export function useUnreadCount({ config, userId, category, enabled = true, refetchInterval = DEFAULT_REFETCH_INTERVAL, countLimit = DEFAULT_COUNT_LIMIT, }) {
30
+ const db = useFirestoreDb();
20
31
  const categoryConfig = config.categories[category];
21
32
  if (!categoryConfig) {
22
33
  throw new Error(`[notification-core] Unknown category: ${category}`);
23
34
  }
24
35
  const collectionPath = categoryConfig.activePath;
25
36
  const isPersonal = categoryConfig.audienceType === 'personal';
26
- const constraints = [
27
- ...(isPersonal ? [where('targetUserId', '==', userId)] : []),
28
- orderBy('updatedAt', 'desc'),
29
- limit(countLimit),
30
- ];
31
- const { data: notifications, ...rest } = useFirestoreCollection({
32
- collectionPath,
37
+ const { data, ...rest } = useQuery({
33
38
  queryKey: ['notifications', 'unread-count', category, userId],
34
- constraints,
39
+ queryFn: async () => {
40
+ const collectionRef = collection(db, collectionPath);
41
+ const constraints = isPersonal
42
+ ? [where('targetUserId', '==', userId), where('seenAt', '==', 0)]
43
+ : [];
44
+ const q = constraints.length > 0 ? query(collectionRef, ...constraints) : collectionRef;
45
+ const snapshot = await getCountFromServer(q);
46
+ return snapshot.data().count;
47
+ },
35
48
  enabled: enabled && !!userId,
36
- subscribe: false,
37
49
  staleTime: refetchInterval,
50
+ refetchInterval,
38
51
  });
52
+ const count = data ?? 0;
39
53
  return {
40
- count: notifications?.length ?? 0,
41
- hasMore: (notifications?.length ?? 0) >= countLimit,
54
+ count,
55
+ hasMore: count > countLimit,
42
56
  ...rest,
43
57
  };
44
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"useUnreadCount.js","sourceRoot":"","sources":["../../../src/react/hooks/useUnreadCount.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAwB,MAAM,oBAAoB,CAAC;AAGjF,MAAM,wBAAwB,GAAG,MAAM,CAAC;AACxC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAE/B;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAAC,EAC7B,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAO,GAAG,IAAI,EACd,eAAe,GAAG,wBAAwB,EAC1C,UAAU,GAAG,mBAAmB,GACV;IACtB,MAAM,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACnD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,yCAAyC,QAAQ,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,cAAc,GAAG,cAAc,CAAC,UAAU,CAAC;IACjD,MAAM,UAAU,GAAG,cAAc,CAAC,YAAY,KAAK,UAAU,CAAC;IAE9D,MAAM,WAAW,GAAsB;QACrC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5D,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC;QAC5B,KAAK,CAAC,UAAU,CAAC;KAClB,CAAC;IAEF,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,IAAI,EAAE,GAAG,sBAAsB,CAAkB;QAC/E,cAAc;QACd,QAAQ,EAAE,CAAC,eAAe,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,CAAC;QAC7D,WAAW;QACX,OAAO,EAAE,OAAO,IAAI,CAAC,CAAC,MAAM;QAC5B,SAAS,EAAE,KAAK;QAChB,SAAS,EAAE,eAAe;KAC3B,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;QACjC,OAAO,EAAE,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC,CAAC,IAAI,UAAU;QACnD,GAAG,IAAI;KACR,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"useUnreadCount.js","sourceRoot":"","sources":["../../../src/react/hooks/useUnreadCount.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EACL,UAAU,EACV,KAAK,EACL,KAAK,EACL,kBAAkB,GAEnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAGnE,MAAM,wBAAwB,GAAG,MAAM,CAAC;AACxC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAE/B;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,cAAc,CAAC,EAC7B,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAO,GAAG,IAAI,EACd,eAAe,GAAG,wBAAwB,EAC1C,UAAU,GAAG,mBAAmB,GACV;IACtB,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;IAE5B,MAAM,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACnD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,yCAAyC,QAAQ,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,cAAc,GAAG,cAAc,CAAC,UAAU,CAAC;IACjD,MAAM,UAAU,GAAG,cAAc,CAAC,YAAY,KAAK,UAAU,CAAC;IAE9D,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,QAAQ,CAAC;QACjC,QAAQ,EAAE,CAAC,eAAe,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,CAAC;QAC7D,OAAO,EAAE,KAAK,IAAqB,EAAE;YACnC,MAAM,aAAa,GAAG,UAAU,CAAC,EAAE,EAAE,cAAc,CAAC,CAAC;YACrD,MAAM,WAAW,GAAsB,UAAU;gBAC/C,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;gBACjE,CAAC,CAAC,EAAE,CAAC;YACP,MAAM,CAAC,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;YACxF,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,CAAC,CAAC,CAAC;YAC7C,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;QAC/B,CAAC;QACD,OAAO,EAAE,OAAO,IAAI,CAAC,CAAC,MAAM;QAC5B,SAAS,EAAE,eAAe;QAC1B,eAAe;KAChB,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,CAAC;IAExB,OAAO;QACL,KAAK;QACL,OAAO,EAAE,KAAK,GAAG,UAAU;QAC3B,GAAG,IAAI;KACR,CAAC;AACJ,CAAC"}
@@ -7,20 +7,31 @@ import type { ServerFirestore } from './types.js';
7
7
  interface ArchiveInput {
8
8
  notificationId: string;
9
9
  category: string;
10
- userId: string;
10
+ /** uid of the caller requesting the archive (ownership is verified against it). */
11
+ callerUid: string;
12
+ /** Whether the caller holds an admin/jrAdmin claim (required for shared notifications). */
13
+ callerIsAdmin: boolean;
11
14
  archivalInfo: ArchivalInfo;
15
+ /**
16
+ * App-supplied epoch ms persisted on the history doc to back native TTL.
17
+ * The retention window is app policy; the helper just writes the value.
18
+ */
19
+ expireAt?: number;
12
20
  }
13
21
  interface ArchiveAllInput {
14
22
  category: string;
15
- userId: string;
23
+ callerUid: string;
24
+ callerIsAdmin: boolean;
16
25
  archivalInfo: ArchivalInfo;
26
+ expireAt?: number;
17
27
  }
18
28
  interface ArchiveResult {
19
29
  success: boolean;
20
30
  archived: number;
21
31
  }
22
32
  /**
23
- * Archive a single notification on the server side.
33
+ * Archive a single notification on the server side. Verifies ownership before
34
+ * the active → history move and persists the app-supplied `expireAt`.
24
35
  */
25
36
  export declare function archiveNotificationHelper(db: ServerFirestore, config: NotificationSystemConfig, input: ArchiveInput): Promise<ArchiveResult>;
26
37
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"archiveNotificationHelper.d.ts","sourceRoot":"","sources":["../../src/server/archiveNotificationHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,wBAAwB,EACxB,YAAY,EACb,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,UAAU,YAAY;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED,UAAU,eAAe;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED,UAAU,aAAa;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,eAAe,EACnB,MAAM,EAAE,wBAAwB,EAChC,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,aAAa,CAAC,CAmCxB;AAED;;GAEG;AACH,wBAAsB,6BAA6B,CACjD,EAAE,EAAE,eAAe,EACnB,MAAM,EAAE,wBAAwB,EAChC,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,aAAa,CAAC,CAoDxB"}
1
+ {"version":3,"file":"archiveNotificationHelper.d.ts","sourceRoot":"","sources":["../../src/server/archiveNotificationHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,wBAAwB,EACxB,YAAY,EACb,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,UAAU,YAAY;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,mFAAmF;IACnF,SAAS,EAAE,MAAM,CAAC;IAClB,2FAA2F;IAC3F,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,eAAe;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,aAAa;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AA+BD;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,eAAe,EACnB,MAAM,EAAE,wBAAwB,EAChC,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,aAAa,CAAC,CAsCxB;AAED;;GAEG;AACH,wBAAsB,6BAA6B,CACjD,EAAE,EAAE,eAAe,EACnB,MAAM,EAAE,wBAAwB,EAChC,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,aAAa,CAAC,CA8DxB"}
@@ -3,26 +3,48 @@
3
3
  * Moves active → history with ArchivalInfo, deletes from active.
4
4
  */
5
5
  /**
6
- * Archive a single notification on the server side.
6
+ * Assert the caller may archive a notification in this category.
7
+ *
8
+ * - personal: the active doc's `targetUserId` must equal `callerUid`.
9
+ * - shared: the category must be `shared` and the caller must be an admin.
10
+ *
11
+ * Throws on mismatch so the callable surfaces a permission error.
12
+ */
13
+ function assertCanArchive(audienceType, activeData, callerUid, callerIsAdmin) {
14
+ if (audienceType === 'shared') {
15
+ if (!callerIsAdmin) {
16
+ throw new Error('[notification-core] Permission denied: shared notifications can only be archived by an admin');
17
+ }
18
+ return;
19
+ }
20
+ if (activeData.targetUserId !== callerUid) {
21
+ throw new Error('[notification-core] Permission denied: caller does not own this notification');
22
+ }
23
+ }
24
+ /**
25
+ * Archive a single notification on the server side. Verifies ownership before
26
+ * the active → history move and persists the app-supplied `expireAt`.
7
27
  */
8
28
  export async function archiveNotificationHelper(db, config, input) {
9
- const { notificationId, category, userId, archivalInfo } = input;
29
+ const { notificationId, category, callerUid, callerIsAdmin, archivalInfo, expireAt } = input;
10
30
  const categoryConfig = config.categories[category];
11
31
  if (!categoryConfig) {
12
32
  throw new Error(`[notification-core] Unknown category: ${category}`);
13
33
  }
14
34
  const activePath = categoryConfig.activePath;
15
- const historyPath = categoryConfig.historyPath(userId);
35
+ const historyPath = categoryConfig.historyPath(callerUid);
16
36
  const activeRef = db.doc(`${activePath}/${notificationId}`);
17
37
  const activeSnap = await activeRef.get();
18
38
  if (!activeSnap.exists) {
19
39
  return { success: true, archived: 0 };
20
40
  }
21
41
  const activeData = activeSnap.data();
42
+ assertCanArchive(categoryConfig.audienceType, activeData, callerUid, callerIsAdmin);
22
43
  const historyDoc = {
23
44
  ...activeData,
24
45
  id: notificationId,
25
46
  archival: archivalInfo,
47
+ ...(expireAt !== undefined ? { expireAt } : {}),
26
48
  ...(categoryConfig.audienceType === 'shared'
27
49
  ? { handledBy: archivalInfo.archivedBy }
28
50
  : {}),
@@ -38,20 +60,25 @@ export async function archiveNotificationHelper(db, config, input) {
38
60
  * Archive all active notifications for a user/category on the server side.
39
61
  */
40
62
  export async function archiveAllNotificationsHelper(db, config, input) {
41
- const { category, userId, archivalInfo } = input;
63
+ const { category, callerUid, callerIsAdmin, archivalInfo, expireAt } = input;
42
64
  const categoryConfig = config.categories[category];
43
65
  if (!categoryConfig) {
44
66
  throw new Error(`[notification-core] Unknown category: ${category}`);
45
67
  }
46
- const activePath = categoryConfig.activePath;
47
- const historyPath = categoryConfig.historyPath(userId);
48
68
  const isPersonal = categoryConfig.audienceType === 'personal';
69
+ // Shared archive-all is an admin-only bulk action; personal stays bounded to
70
+ // the caller by the `targetUserId == callerUid` query filter below.
71
+ if (!isPersonal && !callerIsAdmin) {
72
+ throw new Error('[notification-core] Permission denied: shared notifications can only be archived by an admin');
73
+ }
74
+ const activePath = categoryConfig.activePath;
75
+ const historyPath = categoryConfig.historyPath(callerUid);
49
76
  let totalArchived = 0;
50
77
  let hasMore = true;
51
78
  while (hasMore) {
52
79
  const baseQuery = db.collection(activePath);
53
80
  const q = isPersonal
54
- ? baseQuery.where('targetUserId', '==', userId).orderBy('updatedAt', 'desc').limit(50)
81
+ ? baseQuery.where('targetUserId', '==', callerUid).orderBy('updatedAt', 'desc').limit(50)
55
82
  : baseQuery.orderBy('updatedAt', 'desc').limit(50);
56
83
  const snapshot = await q.get();
57
84
  if (snapshot.empty) {
@@ -66,6 +93,7 @@ export async function archiveAllNotificationsHelper(db, config, input) {
66
93
  ...data,
67
94
  id: docSnap.id,
68
95
  archival: archivalInfo,
96
+ ...(expireAt !== undefined ? { expireAt } : {}),
69
97
  ...(categoryConfig.audienceType === 'shared'
70
98
  ? { handledBy: archivalInfo.archivedBy }
71
99
  : {}),
@@ -1 +1 @@
1
- {"version":3,"file":"archiveNotificationHelper.js","sourceRoot":"","sources":["../../src/server/archiveNotificationHelper.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"archiveNotificationHelper.js","sourceRoot":"","sources":["../../src/server/archiveNotificationHelper.ts"],"names":[],"mappings":"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"}
@@ -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;AAKpB;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,EAAE,EAAE,eAAe,EACnB,MAAM,EAAE,wBAAwB,GAC/B,kBAAkB,CA2GpB"}
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;AAOpB;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,EAAE,EAAE,eAAe,EACnB,MAAM,EAAE,wBAAwB,GAC/B,kBAAkB,CAwIpB"}
@@ -4,6 +4,8 @@
4
4
  */
5
5
  const DEFAULT_COUNT_CAP = 5000;
6
6
  const DEFAULT_ACTOR_CAP = 5;
7
+ /** Firestore hard limit on writes per batch. */
8
+ const MAX_BATCH_WRITES = 500;
7
9
  /**
8
10
  * Create a notification helper bound to a Firestore instance and config.
9
11
  *
@@ -64,6 +66,8 @@ export function createNotificationHelper(db, config) {
64
66
  count: newCount,
65
67
  latestActorIds: newActorIds,
66
68
  message: typeConfig.messagePattern(metadata, newCount),
69
+ // New activity on an existing notification re-lights the unread badge.
70
+ seenAt: 0,
67
71
  updatedAt: Date.now(),
68
72
  });
69
73
  }
@@ -82,6 +86,8 @@ export function createNotificationHelper(db, config) {
82
86
  latestActorIds: [actorId],
83
87
  targetPath,
84
88
  metadata,
89
+ // Active docs are created unseen so the unread count() predicate matches.
90
+ seenAt: 0,
85
91
  createdAt: now,
86
92
  updatedAt: now,
87
93
  };
@@ -89,17 +95,38 @@ export function createNotificationHelper(db, config) {
89
95
  }
90
96
  }
91
97
  async function queueForBatch(input) {
98
+ const pendingDoc = buildPendingDoc(input, Date.now());
99
+ await db.collection(pendingPath).add(pendingDoc);
100
+ }
101
+ function buildPendingDoc(input, now) {
92
102
  const { type, actorId, targetUserId, metadata } = input;
93
103
  const { typeConfig } = getTypeConfig(type);
94
- const pendingDoc = {
104
+ // Pending docs carry NO seenAt — seenAt lives only on active docs, set by
105
+ // the materializer (sendRealTime / processBatchHelper).
106
+ return {
95
107
  type,
96
108
  category: typeConfig.category,
97
109
  targetUserId: targetUserId ?? null,
98
110
  actorId,
99
111
  metadata,
100
- createdAt: Date.now(),
112
+ createdAt: now,
101
113
  };
102
- await db.collection(pendingPath).add(pendingDoc);
114
+ }
115
+ async function queueManyForBatch(inputs) {
116
+ if (inputs.length === 0)
117
+ return;
118
+ const pendingCollection = db.collection(pendingPath);
119
+ const now = Date.now();
120
+ // Write in ≤500-write chunks (the Firestore batch limit).
121
+ for (let i = 0; i < inputs.length; i += MAX_BATCH_WRITES) {
122
+ const chunk = inputs.slice(i, i + MAX_BATCH_WRITES);
123
+ const batch = db.batch();
124
+ for (const input of chunk) {
125
+ const ref = pendingCollection.doc();
126
+ batch.set(ref, buildPendingDoc(input, now));
127
+ }
128
+ await batch.commit();
129
+ }
103
130
  }
104
131
  async function send(input) {
105
132
  const { typeConfig } = getTypeConfig(input.type);
@@ -108,6 +135,6 @@ export function createNotificationHelper(db, config) {
108
135
  }
109
136
  return queueForBatch(input);
110
137
  }
111
- return { send, sendRealTime, queueForBatch };
138
+ return { send, sendRealTime, queueForBatch, queueManyForBatch };
112
139
  }
113
140
  //# sourceMappingURL=createNotificationHelper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createNotificationHelper.js","sourceRoot":"","sources":["../../src/server/createNotificationHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAC/B,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAE5B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,wBAAwB,CACtC,EAAmB,EACnB,MAAgC;IAEhC,MAAM,WAAW,GAAG,MAAM,CAAC,qBAAqB,IAAI,sBAAsB,CAAC;IAE3E,SAAS,aAAa,CAAC,IAAY;QACjC,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,kDAAkD,IAAI,EAAE,CAAC,CAAC;QAC5E,CAAC;QACD,MAAM,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC9D,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,yCAAyC,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC;QAClF,CAAC;QACD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;IACxC,CAAC;IAED,SAAS,iBAAiB,CACxB,WAAqE,EACrE,QAAiC;QAEjC,OAAO,OAAO,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;IACjF,CAAC;IAED,KAAK,UAAU,YAAY,CAAC,KAA8B;QACxD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;QACxD,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QAC3D,MAAM,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC;QAE7C,MAAM,QAAQ,GAAG,UAAU,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QACtD,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,IAAI,iBAAiB,CAAC;QAC1D,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,IAAI,iBAAiB,CAAC;QAE1D,yDAAyD;QACzD,MAAM,gBAAgB,GAAG,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QACnD,MAAM,aAAa,GAAG,gBAAgB;aACnC,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,QAAQ,CAAC;aACjC,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC;aAC5C,KAAK,CAAC,CAAC,CAAC,CAAC;QAEZ,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,CAAC;QAE/C,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;YACxB,kCAAkC;YAClC,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACzC,MAAM,YAAY,GAAG,WAAW,CAAC,IAAI,EAA6B,CAAC;YACnE,MAAM,YAAY,GAAI,YAAY,CAAC,KAAgB,IAAI,CAAC,CAAC;YACzD,MAAM,eAAe,GAAI,YAAY,CAAC,cAA2B,IAAI,EAAE,CAAC;YAExE,+CAA+C;YAC/C,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,EAAU,EAAE,EAAE,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;YAE5G,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;YAEtD,MAAM,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC;gBAC3B,KAAK,EAAE,QAAQ;gBACf,cAAc,EAAE,WAAW;gBAC3B,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC;gBACtD,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,0BAA0B;YAC1B,MAAM,UAAU,GAAG,iBAAiB,CAAC,UAAU,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;YAC7E,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAEvB,MAAM,MAAM,GAAsD;gBAChE,IAAI;gBACJ,QAAQ;gBACR,QAAQ,EAAE,UAAU,CAAC,QAAQ;gBAC7B,YAAY,EAAE,YAAY,IAAI,IAAI;gBAClC,KAAK,EAAE,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC;gBACxC,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC/C,KAAK,EAAE,CAAC;gBACR,cAAc,EAAE,CAAC,OAAO,CAAC;gBACzB,UAAU;gBACV,QAAQ;gBACR,SAAS,EAAE,GAAG;gBACd,SAAS,EAAE,GAAG;aACf,CAAC;YAEF,MAAM,gBAAgB,CAAC,GAAG,CAAC,MAAiC,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED,KAAK,UAAU,aAAa,CAAC,KAA8B;QACzD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;QACxD,MAAM,EAAE,UAAU,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QAE3C,MAAM,UAAU,GAA0D;YACxE,IAAI;YACJ,QAAQ,EAAE,UAAU,CAAC,QAAQ;YAC7B,YAAY,EAAE,YAAY,IAAI,IAAI;YAClC,OAAO;YACP,QAAQ;YACR,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QAEF,MAAM,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,UAAqC,CAAC,CAAC;IAC9E,CAAC;IAED,KAAK,UAAU,IAAI,CAAC,KAA8B;QAChD,MAAM,EAAE,UAAU,EAAE,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,UAAU,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;YACvC,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC;AAC/C,CAAC"}
1
+ {"version":3,"file":"createNotificationHelper.js","sourceRoot":"","sources":["../../src/server/createNotificationHelper.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  export { createNotificationHelper } from './createNotificationHelper.js';
2
2
  export { processBatchHelper } from './processBatchHelper.js';
3
3
  export { archiveNotificationHelper, archiveAllNotificationsHelper, } from './archiveNotificationHelper.js';
4
+ export { markSeenHelper } from './markSeenHelper.js';
4
5
  export type { ServerFirestore, ServerCollectionRef, ServerQuery, ServerQuerySnapshot, ServerDocSnapshot, ServerDocRef, ServerWriteBatch, CreateNotificationInput, NotificationHelper, } from './types.js';
5
6
  //# 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;AAGxC,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,YAAY,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;AAGrD,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
@@ -2,4 +2,5 @@
2
2
  export { createNotificationHelper } from './createNotificationHelper.js';
3
3
  export { processBatchHelper } from './processBatchHelper.js';
4
4
  export { archiveNotificationHelper, archiveAllNotificationsHelper, } from './archiveNotificationHelper.js';
5
+ export { markSeenHelper } from './markSeenHelper.js';
5
6
  //# sourceMappingURL=index.js.map
@@ -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"}
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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Mark-seen helper — used by the app's `markNotificationsSeen` callable.
3
+ * Batches `seenAt = now` writes for a set of active notification doc refs.
4
+ */
5
+ import type { ServerFirestore, ServerDocRef } from './types.js';
6
+ /**
7
+ * Stamp `seenAt` on a set of active notification doc refs, writing in
8
+ * ≤500-write chunks per commit (the Firestore batch limit).
9
+ *
10
+ * Generic — no domain knowledge. The consuming app's callable supplies the
11
+ * ownership-filtered set of refs (personal `targetUserId == uid`); this helper
12
+ * just stamps them. It does not archive and writes no audit event.
13
+ */
14
+ export declare function markSeenHelper(db: ServerFirestore, docRefs: ServerDocRef[], seenAt: number): Promise<{
15
+ updated: number;
16
+ }>;
17
+ //# sourceMappingURL=markSeenHelper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markSeenHelper.d.ts","sourceRoot":"","sources":["../../src/server/markSeenHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAKhE;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,eAAe,EACnB,OAAO,EAAE,YAAY,EAAE,EACvB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAe9B"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Mark-seen helper — used by the app's `markNotificationsSeen` callable.
3
+ * Batches `seenAt = now` writes for a set of active notification doc refs.
4
+ */
5
+ /** Firestore hard limit on writes per batch. */
6
+ const MAX_BATCH_WRITES = 500;
7
+ /**
8
+ * Stamp `seenAt` on a set of active notification doc refs, writing in
9
+ * ≤500-write chunks per commit (the Firestore batch limit).
10
+ *
11
+ * Generic — no domain knowledge. The consuming app's callable supplies the
12
+ * ownership-filtered set of refs (personal `targetUserId == uid`); this helper
13
+ * just stamps them. It does not archive and writes no audit event.
14
+ */
15
+ export async function markSeenHelper(db, docRefs, seenAt) {
16
+ if (docRefs.length === 0) {
17
+ return { updated: 0 };
18
+ }
19
+ for (let i = 0; i < docRefs.length; i += MAX_BATCH_WRITES) {
20
+ const chunk = docRefs.slice(i, i + MAX_BATCH_WRITES);
21
+ const batch = db.batch();
22
+ for (const ref of chunk) {
23
+ batch.update(ref, { seenAt });
24
+ }
25
+ await batch.commit();
26
+ }
27
+ return { updated: docRefs.length };
28
+ }
29
+ //# sourceMappingURL=markSeenHelper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markSeenHelper.js","sourceRoot":"","sources":["../../src/server/markSeenHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,gDAAgD;AAChD,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAE7B;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,EAAmB,EACnB,OAAuB,EACvB,MAAc;IAEd,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACxB,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,gBAAgB,EAAE,CAAC;QAC1D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,gBAAgB,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;YACxB,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QAChC,CAAC;QACD,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC;IACvB,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;AACrC,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;AAOlD,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,CA4J7B"}
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;AAOlD,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,CAgK7B"}
@@ -105,6 +105,8 @@ export async function processBatchHelper(db, config) {
105
105
  count: newCount,
106
106
  latestActorIds: mergedActorIds,
107
107
  message: typeConfig.messagePattern(group.metadata, newCount),
108
+ // New activity on an existing notification re-lights the unread badge.
109
+ seenAt: 0,
108
110
  updatedAt: Date.now(),
109
111
  });
110
112
  notificationsUpdated++;
@@ -126,6 +128,8 @@ export async function processBatchHelper(db, config) {
126
128
  latestActorIds: group.actorIds.slice(0, actorCap),
127
129
  targetPath,
128
130
  metadata: group.metadata,
131
+ // Active docs are created unseen so the unread count() predicate matches.
132
+ seenAt: 0,
129
133
  createdAt: now,
130
134
  updatedAt: now,
131
135
  };
@@ -1 +1 @@
1
- {"version":3,"file":"processBatchHelper.js","sourceRoot":"","sources":["../../src/server/processBatchHelper.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"processBatchHelper.js","sourceRoot":"","sources":["../../src/server/processBatchHelper.ts"],"names":[],"mappings":"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"}
@@ -75,5 +75,11 @@ export interface NotificationHelper {
75
75
  sendRealTime(input: CreateNotificationInput): Promise<void>;
76
76
  /** Queue for batch processing */
77
77
  queueForBatch(input: CreateNotificationInput): Promise<void>;
78
+ /**
79
+ * Queue many pending docs at once, writing in ≤500-write chunks per commit
80
+ * (the Firestore batch limit). Generic per-user fan-out primitive — it only
81
+ * sees uids + payload; the batch processor materializes per-user active docs.
82
+ */
83
+ queueManyForBatch(inputs: CreateNotificationInput[]): Promise<void>;
78
84
  }
79
85
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -35,6 +35,15 @@ export interface NotificationDoc {
35
35
  targetPath: string;
36
36
  /** Type-specific metadata (e.g. { entityId, reason }) */
37
37
  metadata: Record<string, unknown>;
38
+ /**
39
+ * Epoch ms the recipient last marked this notification seen, or `0` when
40
+ * unseen. Generic field — no domain knowledge. Always present (initialized
41
+ * to `0` on creation and reset to `0` on dedup-increment) so the unread
42
+ * `count()` aggregation can match it with a `seenAt == 0` equality predicate.
43
+ * `seenAt` is a personal concept; shared notifications carry it for shape
44
+ * uniformity but their unread indicator is existence-based and ignores it.
45
+ */
46
+ seenAt: number;
38
47
  /** First occurrence */
39
48
  createdAt: number;
40
49
  /** Latest occurrence */
@@ -48,8 +57,6 @@ export interface ArchivalInfo {
48
57
  archivedBy: string;
49
58
  /** Epoch ms */
50
59
  archivedAt: number;
51
- /** Device context */
52
- device: 'web' | 'mobile';
53
60
  }
54
61
  /**
55
62
  * History document — extends active with archival info.
@@ -57,6 +64,13 @@ export interface ArchivalInfo {
57
64
  export interface NotificationHistoryDoc extends NotificationDoc {
58
65
  /** Who/when/how it was archived */
59
66
  archival: ArchivalInfo;
67
+ /**
68
+ * Epoch ms after which native Firestore TTL may delete this history doc.
69
+ * The retention window is app policy (set by the consuming app at archive
70
+ * time); the helper just persists whatever value it is handed. Generic
71
+ * field — no domain knowledge.
72
+ */
73
+ expireAt: number;
60
74
  /** Admin userId (admin history only, quick-access field) */
61
75
  handledBy?: string;
62
76
  }
@@ -142,15 +156,26 @@ export interface UseUnreadCountOptions {
142
156
  countLimit?: number;
143
157
  }
144
158
  export interface UseArchiveNotificationOptions {
145
- config: NotificationSystemConfig;
146
159
  userId: string;
147
160
  category: string;
161
+ /**
162
+ * App-supplied adapter that performs the archive (active → history) for one
163
+ * notification — typically `httpsCallable(functions, 'archiveNotification')`.
164
+ * The hook performs no client Firestore writes; it only invalidates the read
165
+ * keys on success.
166
+ */
167
+ archiveFn: (notificationId: string) => Promise<unknown>;
148
168
  invalidateKeys?: readonly unknown[][];
149
169
  }
150
170
  export interface UseArchiveAllNotificationsOptions {
151
- config: NotificationSystemConfig;
152
171
  userId: string;
153
172
  category: string;
173
+ /**
174
+ * App-supplied adapter that archives the caller's whole category — typically
175
+ * an `httpsCallable(functions, 'archiveNotification')` invoked with the
176
+ * `{ kind: 'all' }` scope. The hook performs no client Firestore writes.
177
+ */
178
+ archiveAllFn: () => Promise<unknown>;
154
179
  invalidateKeys?: readonly unknown[][];
155
180
  }
156
181
  export interface UseNotificationHistoryOptions {
@@ -165,9 +190,18 @@ export interface NotificationListProps {
165
190
  userId: string;
166
191
  category: string;
167
192
  onNotificationClick: (notification: NotificationDoc) => void;
193
+ /**
194
+ * Adapter that archives one notification (active → history). Passed straight
195
+ * through to `useArchiveNotification`; the app wires it to its callable.
196
+ */
197
+ archiveFn: (notificationId: string) => Promise<unknown>;
198
+ /**
199
+ * Adapter that archives the caller's whole category. Passed straight through
200
+ * to `useArchiveAllNotifications`; the app wires it to its callable.
201
+ */
202
+ archiveAllFn: () => Promise<unknown>;
168
203
  onClearAll?: () => void;
169
204
  refetchInterval?: number;
170
- device?: 'web' | 'mobile';
171
205
  emptyText?: string;
172
206
  }
173
207
  export interface NotificationEmptyStateProps {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/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.2",
3
+ "version": "0.4.3",
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",