@ttt-productions/notification-core 0.12.0 → 0.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/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export type { NotificationDoc, PendingNotification, NotificationCategoryConfig, NotificationTypeConfig, NotificationSystemConfig, UseActiveNotificationsOptions, UseUnreadCountOptions, UseArchiveNotificationOptions, UseArchiveAllNotificationsOptions, ArchiveAllResult, ArchiveAllLoopResult, NotificationListProps, NotificationEmptyStateProps, NotificationUnreadBadgeProps, } from './types.js';
1
+ export type { NotificationDoc, PendingNotification, NotificationCategoryConfig, NotificationTypeConfig, NotificationSystemConfig, UseActiveNotificationsOptions, UseUnreadCountOptions, UseArchiveNotificationOptions, UseArchiveAllNotificationsOptions, ArchiveAllJobStatus, EnqueueArchiveAllResult, ArchiveAllJobSnapshot, ArchiveAllPollResult, NotificationListProps, NotificationEmptyStateProps, NotificationUnreadBadgeProps, } from './types.js';
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,EACxB,6BAA6B,EAC7B,qBAAqB,EACrB,6BAA6B,EAC7B,iCAAiC,EACjC,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,EACxB,6BAA6B,EAC7B,qBAAqB,EACrB,6BAA6B,EAC7B,iCAAiC,EACjC,mBAAmB,EACnB,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,YAAY,CAAC"}
@@ -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, archiveFn, archiveAllFn, onClearAll, refetchInterval, emptyText, }: NotificationListProps): import("react").JSX.Element;
5
+ export declare function NotificationList({ config, userId, category, onNotificationClick, archiveFn, enqueueArchiveAllFn, getArchiveAllStatusFn, onClearAll, refetchInterval, emptyText, }: NotificationListProps): import("react").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":"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,+BA2IvB"}
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,mBAAmB,EACnB,qBAAqB,EACrB,UAAU,EACV,eAAe,EACf,SAAS,GACV,EAAE,qBAAqB,+BA+IvB"}
@@ -10,7 +10,7 @@ import { formatRelativeTime } from './relative-time.js';
10
10
  /**
11
11
  * Scrollable list of active notifications with click-to-archive and clear-all.
12
12
  */
13
- export function NotificationList({ config, userId, category, onNotificationClick, archiveFn, archiveAllFn, onClearAll, refetchInterval, emptyText, }) {
13
+ export function NotificationList({ config, userId, category, onNotificationClick, archiveFn, enqueueArchiveAllFn, getArchiveAllStatusFn, onClearAll, refetchInterval, emptyText, }) {
14
14
  const { data: notifications, isLoading, hasNextPage, nextPage, } = useActiveNotifications({
15
15
  config,
16
16
  userId,
@@ -25,7 +25,8 @@ export function NotificationList({ config, userId, category, onNotificationClick
25
25
  const archiveAllMutation = useArchiveAllNotifications({
26
26
  userId,
27
27
  category,
28
- archiveAllFn,
28
+ enqueueArchiveAllFn,
29
+ getArchiveAllStatusFn,
29
30
  });
30
31
  const handleNotificationClick = useCallback(async (notification) => {
31
32
  try {
@@ -36,9 +37,11 @@ export function NotificationList({ config, userId, category, onNotificationClick
36
37
  }
37
38
  onNotificationClick(notification);
38
39
  }, [archiveMutation, onNotificationClick]);
39
- // I3: surface a failed/incomplete clear instead of swallowing it. `onClearAll` (and the
40
- // tray-closing side effects the app wires to it) fires ONLY when the active set was fully
41
- // drained — otherwise the user keeps the "notifications remain — try again" affordance.
40
+ // Surface a failed/incomplete clear instead of swallowing it. `onClearAll` (and the tray-closing
41
+ // side effects the app wires to it) fires ONLY when the server job fully drained the category —
42
+ // otherwise the user keeps the "notifications remain — try again" affordance. The poller resolves
43
+ // with an explicit terminal result (`complete` | `incomplete` | `failed`) and only rejects on a
44
+ // hard enqueue/poll throw.
42
45
  const [clearIncomplete, setClearIncomplete] = useState(false);
43
46
  const handleClearAll = useCallback(async () => {
44
47
  setClearIncomplete(false);
@@ -47,12 +50,13 @@ export function NotificationList({ config, userId, category, onNotificationClick
47
50
  result = await archiveAllMutation.mutateAsync();
48
51
  }
49
52
  catch {
50
- // Hard failure: do not fire onClearAll; surface the retry affordance.
53
+ // Hard failure (enqueue/poll threw): do not fire onClearAll; surface the retry affordance.
51
54
  setClearIncomplete(true);
52
55
  return;
53
56
  }
54
57
  if (!result.complete) {
55
- // Resolved but the active set was not fully drained — keep notifications, prompt a retry.
58
+ // Job terminated without fully draining the category (incomplete/failed) — keep the
59
+ // notifications and prompt a retry.
56
60
  setClearIncomplete(true);
57
61
  return;
58
62
  }
@@ -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,22 +1,33 @@
1
- import type { ArchiveAllLoopResult, UseArchiveAllNotificationsOptions } from '../../types.js';
1
+ import type { ArchiveAllPollResult, UseArchiveAllNotificationsOptions } from '../../types.js';
2
2
  /**
3
- * Archive the caller's whole category through an app-supplied callable adapter.
3
+ * Trigger + poll a SERVER-OWNED archive-all job for one notification category.
4
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
+ * This is a THIN STATUS POLLER, not a client loop. It:
6
+ * 1. enqueues ONE server job via `enqueueArchiveAllFn(category)` (the category the tab the tray
7
+ * was invoked on — flows into the job, preserving per-tab scoping: the worker archives ONLY
8
+ * that category's active cards, never all tabs);
9
+ * 2. polls `getArchiveAllStatusFn(jobId)` until the job reaches a terminal state
10
+ * (`complete` | `incomplete` | `failed`);
11
+ * 3. resolves an {@link ArchiveAllPollResult} the caller gates side effects on, and invalidates
12
+ * the read keys on a completed drain.
13
+ *
14
+ * All paging + ownership-checked per-card deletion happen server-side. The hook performs no client
15
+ * Firestore writes and never chains archive calls. The generic package hardcodes no callable name —
16
+ * the app injects both adapters.
8
17
  *
9
18
  * @example
10
19
  * ```tsx
11
- * const archiveNotification = httpsCallable(functions, 'archiveNotification');
20
+ * const enqueue = httpsCallable(functions, 'enqueueArchiveAll');
21
+ * const getStatus = httpsCallable(functions, 'getArchiveAllStatus');
12
22
  * const archiveAll = useArchiveAllNotifications({
13
23
  * userId: user.uid,
14
24
  * category: 'user',
15
- * archiveAllFn: () => archiveNotification({ category: 'user', scope: { kind: 'all' } }),
25
+ * enqueueArchiveAllFn: (category) => enqueue({ category }).then((r) => r.data),
26
+ * getArchiveAllStatusFn: (jobId) => getStatus({ jobId }).then((r) => r.data),
16
27
  * });
17
28
  *
18
29
  * archiveAll.mutate();
19
30
  * ```
20
31
  */
21
- export declare function useArchiveAllNotifications({ userId, category, archiveAllFn, invalidateKeys, }: UseArchiveAllNotificationsOptions): import("@tanstack/react-query").UseMutationResult<ArchiveAllLoopResult, Error, void, unknown>;
32
+ export declare function useArchiveAllNotifications({ userId, category, enqueueArchiveAllFn, getArchiveAllStatusFn, pollIntervalMs, maxPolls, invalidateKeys, }: UseArchiveAllNotificationsOptions): import("@tanstack/react-query").UseMutationResult<ArchiveAllPollResult, Error, void, unknown>;
22
33
  //# sourceMappingURL=useArchiveAllNotifications.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useArchiveAllNotifications.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useArchiveAllNotifications.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,iCAAiC,EAAE,MAAM,gBAAgB,CAAC;AAE9F;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,cAAc,GACf,EAAE,iCAAiC,iGA0CnC"}
1
+ {"version":3,"file":"useArchiveAllNotifications.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useArchiveAllNotifications.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,oBAAoB,EACpB,iCAAiC,EAClC,MAAM,gBAAgB,CAAC;AASxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,MAAM,EACN,QAAQ,EACR,mBAAmB,EACnB,qBAAqB,EACrB,cAAyC,EACzC,QAA4B,EAC5B,cAAc,GACf,EAAE,iCAAiC,iGAqDnC"}
@@ -1,25 +1,41 @@
1
1
  'use client';
2
2
  import { useMutation, useQueryClient } from '@tanstack/react-query';
3
+ const DEFAULT_POLL_INTERVAL_MS = 1500;
4
+ const DEFAULT_MAX_POLLS = 120; // ~3 min at the default interval
5
+ function sleep(ms) {
6
+ return new Promise((resolve) => setTimeout(resolve, ms));
7
+ }
3
8
  /**
4
- * Archive the caller's whole category through an app-supplied callable adapter.
9
+ * Trigger + poll a SERVER-OWNED archive-all job for one notification category.
10
+ *
11
+ * This is a THIN STATUS POLLER, not a client loop. It:
12
+ * 1. enqueues ONE server job via `enqueueArchiveAllFn(category)` (the category — the tab the tray
13
+ * was invoked on — flows into the job, preserving per-tab scoping: the worker archives ONLY
14
+ * that category's active cards, never all tabs);
15
+ * 2. polls `getArchiveAllStatusFn(jobId)` until the job reaches a terminal state
16
+ * (`complete` | `incomplete` | `failed`);
17
+ * 3. resolves an {@link ArchiveAllPollResult} the caller gates side effects on, and invalidates
18
+ * the read keys on a completed drain.
5
19
  *
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.
20
+ * All paging + ownership-checked per-card deletion happen server-side. The hook performs no client
21
+ * Firestore writes and never chains archive calls. The generic package hardcodes no callable name —
22
+ * the app injects both adapters.
9
23
  *
10
24
  * @example
11
25
  * ```tsx
12
- * const archiveNotification = httpsCallable(functions, 'archiveNotification');
26
+ * const enqueue = httpsCallable(functions, 'enqueueArchiveAll');
27
+ * const getStatus = httpsCallable(functions, 'getArchiveAllStatus');
13
28
  * const archiveAll = useArchiveAllNotifications({
14
29
  * userId: user.uid,
15
30
  * category: 'user',
16
- * archiveAllFn: () => archiveNotification({ category: 'user', scope: { kind: 'all' } }),
31
+ * enqueueArchiveAllFn: (category) => enqueue({ category }).then((r) => r.data),
32
+ * getArchiveAllStatusFn: (jobId) => getStatus({ jobId }).then((r) => r.data),
17
33
  * });
18
34
  *
19
35
  * archiveAll.mutate();
20
36
  * ```
21
37
  */
22
- export function useArchiveAllNotifications({ userId, category, archiveAllFn, invalidateKeys, }) {
38
+ export function useArchiveAllNotifications({ userId, category, enqueueArchiveAllFn, getArchiveAllStatusFn, pollIntervalMs = DEFAULT_POLL_INTERVAL_MS, maxPolls = DEFAULT_MAX_POLLS, invalidateKeys, }) {
23
39
  const queryClient = useQueryClient();
24
40
  const defaultInvalidateKeys = [
25
41
  ['notifications', 'active', category, userId],
@@ -27,37 +43,44 @@ export function useArchiveAllNotifications({ userId, category, archiveAllFn, inv
27
43
  ['notifications', 'history', category, userId],
28
44
  ];
29
45
  return useMutation({
30
- // I3: "Clear All" must actually clear ALL but it must also report HONESTLY when it could not.
31
- // The server bounds each call to a small page and returns `hasMore`; loop the adapter until the
32
- // active set is drained (bounded so a pathological tray can't run forever). The loop resolves on
33
- // an incomplete drain rather than throwing, so it returns an explicit `complete` flag the caller
34
- // gates side effects on (it is NOT a plain success — see ArchiveAllLoopResult).
46
+ // Server-owned archive-all: enqueue ONE job scoped to `category`, then poll its status until it
47
+ // reaches a terminal state. No browser loop, no chain of archive transactions. The mutation
48
+ // resolves with an explicit terminal result (never throws for an incomplete drain) `complete`
49
+ // is the load-bearing flag callers gate post-clear side effects on.
35
50
  mutationFn: async () => {
36
- const MAX_PASSES = 25; // bound: 25 × the server page cap — far beyond any real tray
37
- let archived = 0;
38
- let hasMore = true;
39
- let pass = 0;
40
- while (hasMore && pass < MAX_PASSES) {
41
- const r = await archiveAllFn();
42
- archived += r.archived;
43
- hasMore = r.hasMore;
44
- pass += 1;
45
- // No-progress guard: a pass that archived nothing yet still reports `hasMore` cannot make
46
- // progress on the next pass either (e.g. a generation-less head card the server can never
47
- // advance past) — looping would livelock to the pass bound. Stop now and report incomplete.
48
- if (r.archived === 0 && hasMore)
49
- break;
51
+ const { jobId } = await enqueueArchiveAllFn(category);
52
+ // Poll until terminal or until the guard bound is hit. A job that never terminates resolves
53
+ // `incomplete` (mirrors the old loop's honest "some remain" result) rather than hanging. The
54
+ // first poll happens immediately so a fast/already-complete job resolves without a delay.
55
+ let lastArchived = 0;
56
+ for (let poll = 0; poll < maxPolls; poll += 1) {
57
+ const snap = await getArchiveAllStatusFn(jobId);
58
+ lastArchived = snap.archived ?? 0;
59
+ if (snap.state === 'complete') {
60
+ return { status: 'complete', category, archived: lastArchived, complete: true };
61
+ }
62
+ if (snap.state === 'incomplete') {
63
+ return { status: 'incomplete', category, archived: lastArchived, complete: false };
64
+ }
65
+ if (snap.state === 'failed') {
66
+ return { status: 'failed', category, archived: lastArchived, complete: false, error: snap.error };
67
+ }
68
+ // Still in-progress — wait before the next poll unless this was the last allowed poll.
69
+ if (poll < maxPolls - 1)
70
+ await sleep(pollIntervalMs);
50
71
  }
51
- // `complete` is true ONLY when the active set was fully drained (`hasMore` is false). Hitting
52
- // the pass bound or the no-progress guard with `hasMore` still true returns an EXPLICIT
53
- // incomplete result, never a plain success.
54
- return { archived, hasMore, complete: !hasMore };
72
+ // Guard: the job never reached a terminal state within the poll budget report incomplete.
73
+ return { status: 'incomplete', category, archived: lastArchived, complete: false };
55
74
  },
56
- onSuccess: () => {
75
+ onSuccess: (result) => {
76
+ // Only a completed drain changed the active set; still invalidate on an incomplete drain since
77
+ // SOME cards were archived. A hard enqueue/poll failure rejects the mutation (onError), so this
78
+ // never runs for `failed`.
57
79
  const keysToInvalidate = invalidateKeys ?? defaultInvalidateKeys;
58
80
  keysToInvalidate.forEach((key) => {
59
81
  queryClient.invalidateQueries({ queryKey: [...key], exact: false });
60
82
  });
83
+ void result;
61
84
  },
62
85
  });
63
86
  }
@@ -1 +1 @@
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,gGAAgG;QAChG,gGAAgG;QAChG,iGAAiG;QACjG,iGAAiG;QACjG,gFAAgF;QAChF,UAAU,EAAE,KAAK,IAAmC,EAAE;YACpD,MAAM,UAAU,GAAG,EAAE,CAAC,CAAC,6DAA6D;YACpF,IAAI,QAAQ,GAAG,CAAC,CAAC;YACjB,IAAI,OAAO,GAAG,IAAI,CAAC;YACnB,IAAI,IAAI,GAAG,CAAC,CAAC;YACb,OAAO,OAAO,IAAI,IAAI,GAAG,UAAU,EAAE,CAAC;gBACpC,MAAM,CAAC,GAAG,MAAM,YAAY,EAAE,CAAC;gBAC/B,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC;gBACvB,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;gBACpB,IAAI,IAAI,CAAC,CAAC;gBACV,0FAA0F;gBAC1F,0FAA0F;gBAC1F,4FAA4F;gBAC5F,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,IAAI,OAAO;oBAAE,MAAM;YACzC,CAAC;YACD,8FAA8F;YAC9F,wFAAwF;YACxF,4CAA4C;YAC5C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,CAAC;QACnD,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":"useArchiveAllNotifications.js","sourceRoot":"","sources":["../../../src/react/hooks/useArchiveAllNotifications.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -168,42 +168,79 @@ export interface UseArchiveNotificationOptions {
168
168
  invalidateKeys?: readonly unknown[][];
169
169
  }
170
170
  /**
171
- * Result of ONE archive-all server call. `hasMore` is true when the server hit its per-invocation
172
- * cap and the caller's active set was NOT fully drained — `useArchiveAllNotifications` loops the
173
- * adapter until `hasMore` is false so "Clear All" actually clears all (I3).
171
+ * Terminal + transient states of a server-owned archive-all job, as surfaced to the UI.
174
172
  *
175
- * NOTE: the loop's aggregate result carries the same `archived`/`hasMore` shape PLUS a `complete`
176
- * flag (`ArchiveAllLoopResult`); a single server page does not know whether the WHOLE active set
177
- * was drained, so the per-call shape here intentionally has no `complete`.
173
+ * - `idle` — nothing enqueued yet (initial / reset state).
174
+ * - `enqueuing` the enqueue adapter is in flight (job not yet acknowledged).
175
+ * - `in-progress` the job is enqueued/running; the worker is still draining the category.
176
+ * - `complete` — TERMINAL: the worker fully drained the category's active set.
177
+ * - `incomplete` — TERMINAL: the job stopped without draining everything (e.g. hit its own
178
+ * bound / a non-advanceable card). The tray keeps a "some remain — try again"
179
+ * affordance, mirroring the old loop's incomplete result.
180
+ * - `failed` — TERMINAL: the enqueue call threw, or the job dead-lettered / reported failure.
178
181
  */
179
- export interface ArchiveAllResult {
180
- archived: number;
181
- hasMore: boolean;
182
+ export type ArchiveAllJobStatus = 'idle' | 'enqueuing' | 'in-progress' | 'complete' | 'incomplete' | 'failed';
183
+ /**
184
+ * Result of the INJECTED enqueue adapter — triggers exactly one server-owned archive-all job for
185
+ * the given category and returns immediately with the job's id (idempotent per user+category+request
186
+ * on the app side). The app wires this to its `httpsCallable(functions, 'enqueueArchiveAll')`
187
+ * (or equivalent); the generic package never names the callable.
188
+ */
189
+ export interface EnqueueArchiveAllResult {
190
+ /** Server job id the poller then polls via the status adapter. */
191
+ jobId: string;
192
+ }
193
+ /**
194
+ * Snapshot of a server-owned archive-all job, returned by the INJECTED status-query adapter.
195
+ * The poller maps `state` → {@link ArchiveAllJobStatus} and stops polling on any terminal state.
196
+ * `category` echoes the tab/category the job was enqueued for so the UI can assert per-tab scoping.
197
+ */
198
+ export interface ArchiveAllJobSnapshot {
199
+ /** Job lifecycle state as owned by the server worker. */
200
+ state: 'in-progress' | 'complete' | 'incomplete' | 'failed';
201
+ /** The notification category/tab this job is scoped to (must match the enqueue category). */
202
+ category: string;
203
+ /** Cards archived so far (monotonic); optional progress for the UI. */
204
+ archived?: number;
205
+ /** Human-readable failure reason when `state === 'failed'` (optional). */
206
+ error?: string;
182
207
  }
183
208
  /**
184
- * Aggregate result of the `useArchiveAllNotifications` continuation loop (I3). `complete` is the
185
- * load-bearing completion contract: it is `true` ONLY when the active set was fully drained
186
- * (`hasMore` reached `false`). It is `false` when the loop stopped early either the no-progress
187
- * guard tripped (a pass archived nothing yet still reported `hasMore`, e.g. a generation-less head
188
- * card that can't advance) or the per-mutation pass bound was hit with `hasMore` still `true`.
189
- * Callers MUST gate post-clear side effects (closing the tray, `onClearAll`) on `complete`, not on
190
- * mere resolution — the mutation resolves on an incomplete drain rather than throwing.
209
+ * Aggregate result the poller resolves with once the job reaches a terminal state.
210
+ * `complete` is the load-bearing completion contract (true ONLY when the whole category was
211
+ * drained), preserved from the old loop so callers gate side effects the same way.
191
212
  */
192
- export interface ArchiveAllLoopResult {
213
+ export interface ArchiveAllPollResult {
214
+ status: Extract<ArchiveAllJobStatus, 'complete' | 'incomplete' | 'failed'>;
215
+ category: string;
193
216
  archived: number;
194
- hasMore: boolean;
195
217
  complete: boolean;
218
+ error?: string;
196
219
  }
197
220
  export interface UseArchiveAllNotificationsOptions {
198
221
  userId: string;
199
222
  category: string;
200
223
  /**
201
- * App-supplied adapter that archives ONE bounded page of the caller's whole category — typically
202
- * an `httpsCallable(functions, 'archiveNotification')` invoked with the `{ kind: 'all' }` scope.
203
- * Returns `{ archived, hasMore }`; the hook re-invokes it while `hasMore` is true. No client
204
- * Firestore writes.
224
+ * App-supplied adapter that ENQUEUES one server-owned archive-all job scoped to `category` and
225
+ * returns its `jobId`. The `category` is passed so the app callable can carry the tab/source into
226
+ * the job (per-tab scoping is REQUIRED — the worker archives only that category's active cards).
227
+ * Typically `(category) => enqueueArchiveAll({ category })` over an `httpsCallable`.
228
+ */
229
+ enqueueArchiveAllFn: (category: string) => Promise<EnqueueArchiveAllResult>;
230
+ /**
231
+ * App-supplied adapter that returns the current {@link ArchiveAllJobSnapshot} for a job id — the
232
+ * hook polls it until the job reaches a terminal state. Typically
233
+ * `(jobId) => getArchiveAllStatus({ jobId })` over an `httpsCallable`, or a Firestore read of the
234
+ * job doc. No client Firestore writes.
205
235
  */
206
- archiveAllFn: () => Promise<ArchiveAllResult>;
236
+ getArchiveAllStatusFn: (jobId: string) => Promise<ArchiveAllJobSnapshot>;
237
+ /** Poll interval in ms while the job is in-progress (default 1500). */
238
+ pollIntervalMs?: number;
239
+ /**
240
+ * Max number of status polls before the poller gives up and resolves `incomplete` (guards a job
241
+ * that never reaches a terminal state — default 120, i.e. ~3 min at the default interval).
242
+ */
243
+ maxPolls?: number;
207
244
  invalidateKeys?: readonly unknown[][];
208
245
  }
209
246
  export interface NotificationListProps {
@@ -217,11 +254,17 @@ export interface NotificationListProps {
217
254
  */
218
255
  archiveFn: (notificationId: string) => Promise<unknown>;
219
256
  /**
220
- * Adapter that archives ONE bounded page of the caller's whole category (returns
221
- * `{ archived, hasMore }`). Passed straight through to `useArchiveAllNotifications`, which loops
222
- * it until fully drained; the app wires it to its callable.
257
+ * Adapter that ENQUEUES one server-owned archive-all job scoped to `category` and returns its
258
+ * `jobId`. Passed straight through to `useArchiveAllNotifications`; the app wires it to its
259
+ * enqueue callable. Per-tab scoping: the category flows through to the job.
260
+ */
261
+ enqueueArchiveAllFn: (category: string) => Promise<EnqueueArchiveAllResult>;
262
+ /**
263
+ * Adapter that returns the current status snapshot for an archive-all `jobId`. Passed straight
264
+ * through to `useArchiveAllNotifications`, which polls it until the job is terminal; the app wires
265
+ * it to its status callable / job-doc read.
223
266
  */
224
- archiveAllFn: () => Promise<ArchiveAllResult>;
267
+ getArchiveAllStatusFn: (jobId: string) => Promise<ArchiveAllJobSnapshot>;
225
268
  onClearAll?: () => void;
226
269
  refetchInterval?: number;
227
270
  emptyText?: string;
@@ -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.12.0",
3
+ "version": "0.13.0",
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",