@dereekb/firebase 13.31.0 → 13.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/firebase",
3
- "version": "13.31.0",
3
+ "version": "13.32.0",
4
4
  "sideEffects": false,
5
5
  "exports": {
6
6
  "./test": {
@@ -24,10 +24,10 @@
24
24
  }
25
25
  },
26
26
  "peerDependencies": {
27
- "@dereekb/date": "13.31.0",
28
- "@dereekb/model": "13.31.0",
29
- "@dereekb/rxjs": "13.31.0",
30
- "@dereekb/util": "13.31.0",
27
+ "@dereekb/date": "13.32.0",
28
+ "@dereekb/model": "13.32.0",
29
+ "@dereekb/rxjs": "13.32.0",
30
+ "@dereekb/util": "13.32.0",
31
31
  "@firebase/rules-unit-testing": "5.0.0",
32
32
  "@marcbachmann/cel-js": "^7.6.1",
33
33
  "@typescript-eslint/parser": "8.59.3",
@@ -9,6 +9,8 @@ export * from './notification.create.loggedevent';
9
9
  export * from './notification.loggedevent.loader';
10
10
  export * from './notification.create.task';
11
11
  export * from './notification.details';
12
+ export * from './notification.healthcheck';
13
+ export * from './notification.healthcheck.mailgun';
12
14
  export * from './notification.item';
13
15
  export * from './notification.id';
14
16
  export * from './notification.message';
@@ -13,6 +13,7 @@ import { type E164PhoneNumber, type EmailAddress, type IndexNumber, type Maybe }
13
13
  import { type NotificationTypes } from './notification';
14
14
  import { type NotificationUserDefaultNotificationBoxRecipientConfig, type NotificationBoxRecipientTemplateConfigArrayEntry, NotificationBoxRecipientFlag } from './notification.config';
15
15
  import { type NotificationBoxId, type NotificationSummaryId, type NotificationTemplateType } from './notification.id';
16
+ import { type NotificationHealthCheck, NotificationDeliveryMethod } from './notification.healthcheck';
16
17
  import { type NotificationSendEmailMessagesResult, type NotificationSendTextMessagesResult, type NotificationSendNotificationSummaryMessagesResult } from './notification.send';
17
18
  import { type NotificationTaskServiceTaskHandlerCompletionType } from './notification.task';
18
19
  export declare const NOTIFICATION_RECIPIENT_NAME_MIN_LENGTH = 0;
@@ -95,6 +96,101 @@ export { targetModelParamsType as resyncNotificationUserParamsType } from '../..
95
96
  export interface ResyncNotificationUserResult {
96
97
  readonly notificationBoxesUpdated: number;
97
98
  }
99
+ /**
100
+ * Used for running a notification delivery health check for a user.
101
+ *
102
+ * The check always inspects the user's configuration, their notification box subscriptions, and whatever
103
+ * read-only diagnostics each configured delivery method's send service offers. Actually dispatching a
104
+ * test message is opt-in via `sendProbe`, since that delivers real mail/SMS to the user.
105
+ */
106
+ export interface NotificationUserHealthCheckParams extends TargetModelParams {
107
+ /**
108
+ * Restrict the check to these delivery methods. Defaults to every method the server has a send
109
+ * service configured for.
110
+ */
111
+ readonly methods?: Maybe<NotificationDeliveryMethod[]>;
112
+ /**
113
+ * Dispatch a real test message through each checked method that supports probing.
114
+ *
115
+ * Defaults to false. Delivery confirmation is asynchronous, so a dispatched probe is usually still
116
+ * pending when the check returns and is resolved by a later {@link verifyPendingProbesOnly} run.
117
+ */
118
+ readonly sendProbe?: Maybe<boolean>;
119
+ /**
120
+ * Only resolve probes left pending by the previous check, skipping the configuration, history, and
121
+ * provider diagnostics.
122
+ *
123
+ * Defaults to false. This is the POLL that settles an in-flight test message, and it is deliberately
124
+ * cheap enough to be called repeatedly: it consults a provider only for a method that actually has a
125
+ * probe in flight, and touches nothing else. It answers to its own short window rather than the run
126
+ * window, and advances the stored check's `vat` rather than its `at`, so polling a test message never
127
+ * consumes the user's allowance for running the check itself.
128
+ */
129
+ readonly verifyPendingProbesOnly?: Maybe<boolean>;
130
+ /**
131
+ * The notification template type to evaluate per-template configuration against.
132
+ *
133
+ * Defaults to the app's default template type.
134
+ */
135
+ readonly notificationTemplateType?: Maybe<NotificationTemplateType>;
136
+ /**
137
+ * Skip inspecting the user's notification box subscriptions.
138
+ *
139
+ * Defaults to false. Skipping avoids a document read per subscription, at the cost of not detecting
140
+ * a subscription that is broken, still being set up, or out of sync with the user's settings.
141
+ */
142
+ readonly skipSubscriptionChecks?: Maybe<boolean>;
143
+ /**
144
+ * Ignore the run and test message throttle windows.
145
+ *
146
+ * PRIVILEGED — admin only. The windows exist to stop a user from repeatedly hammering the delivery
147
+ * providers and their own inbox, so this must never be honoured for an ordinary caller. The action
148
+ * itself cannot tell who is calling, so the API layer that can is responsible for clearing this
149
+ * before the params reach it:
150
+ *
151
+ * ```ts
152
+ * const params = isAdminInRequest(request) ? data : { ...data, force: undefined };
153
+ * ```
154
+ *
155
+ * Defaults to false.
156
+ */
157
+ readonly force?: Maybe<boolean>;
158
+ /**
159
+ * Return the complete health check rather than just the part the call was about.
160
+ *
161
+ * A `sendProbe` call is about one delivery method's test message, so by default its result carries only
162
+ * the methods it actually probed — the caller already has the rest, and a client rendering the report
163
+ * reads it from the {@link NotificationUser} document instead. Set this to get the whole check back.
164
+ *
165
+ * Defaults to false. Has no effect on a plain run, which always returns everything, and never affects
166
+ * what is persisted: the stored check is always the complete picture.
167
+ */
168
+ readonly returnFullHealthCheck?: Maybe<boolean>;
169
+ }
170
+ export declare const notificationUserHealthCheckParamsType: Type<NotificationUserHealthCheckParams>;
171
+ /**
172
+ * The result of a `healthCheck` invocation.
173
+ */
174
+ export interface NotificationUserHealthCheckResult {
175
+ /**
176
+ * The health check that was produced.
177
+ *
178
+ * The COMPLETE check is always persisted to the {@link NotificationUser}'s `hc` field. What comes back
179
+ * here can be narrower: a `sendProbe` call is about one delivery method's test message, so unless
180
+ * `returnFullHealthCheck` was set its result carries only the methods that were actually probed, with
181
+ * `s` rolled up over just those and the account-wide findings left out. Read the document for the
182
+ * whole picture — see {@link NotificationUserHealthCheckParams.returnFullHealthCheck}.
183
+ */
184
+ readonly healthCheck: NotificationHealthCheck;
185
+ /**
186
+ * The number of probes dispatched by this run.
187
+ */
188
+ readonly probesDispatched: number;
189
+ /**
190
+ * The number of previously-pending probes this run resolved to a final status.
191
+ */
192
+ readonly probesResolved: number;
193
+ }
98
194
  export interface ResyncAllNotificationUserParams {
99
195
  }
100
196
  export declare const resyncAllNotificationUserParamsType: Type<ResyncAllNotificationUserParams>;
@@ -310,6 +406,9 @@ export type NotificationBoxModelCrudFunctionsConfig = {
310
406
  _: UpdateNotificationUserParams;
311
407
  resync: [ResyncNotificationUserParams, ResyncNotificationUserResult];
312
408
  };
409
+ invoke: {
410
+ healthCheck: [NotificationUserHealthCheckParams, NotificationUserHealthCheckResult];
411
+ };
313
412
  };
314
413
  readonly notificationSummary: {
315
414
  update: {
@@ -344,6 +443,9 @@ export declare abstract class NotificationFunctions implements ModelFirebaseFunc
344
443
  update: ModelFirebaseCrudFunction<UpdateNotificationUserParams>;
345
444
  resync: ModelFirebaseCrudFunction<ResyncNotificationUserParams, ResyncNotificationUserResult>;
346
445
  };
446
+ invokeNotificationUser: {
447
+ healthCheck: ModelFirebaseCrudFunction<NotificationUserHealthCheckParams, NotificationUserHealthCheckResult>;
448
+ };
347
449
  };
348
450
  abstract notificationSummary: {
349
451
  updateNotificationSummary: {
@@ -40,3 +40,18 @@ export declare const NOTIFICATION_USER_BLOCKED_FROM_BEING_ADD_TO_RECIPIENTS_ERRO
40
40
  * Thrown when attempting to update a recipient config that is locked by the user.
41
41
  */
42
42
  export declare const NOTIFICATION_USER_LOCKED_CONFIG_FROM_BEING_UPDATED_ERROR_CODE = "NOTIFICATION_USER_LOCKED_CONFIG_FROM_BEING_UPDATED";
43
+ /**
44
+ * Thrown when a NotificationUser health check is run again before its throttle window has passed.
45
+ */
46
+ export declare const NOTIFICATION_USER_HEALTH_CHECK_THROTTLED_ERROR_CODE = "NOTIFICATION_USER_HEALTH_CHECK_THROTTLED";
47
+ /**
48
+ * Thrown when a NotificationUser health check test message is dispatched again before its throttle
49
+ * window has passed. Tracked separately from the run throttle, since a probe sends a real message.
50
+ */
51
+ export declare const NOTIFICATION_USER_HEALTH_CHECK_PROBE_THROTTLED_ERROR_CODE = "NOTIFICATION_USER_HEALTH_CHECK_PROBE_THROTTLED";
52
+ /**
53
+ * Thrown when a NotificationUser health check's pending probes are verified again before its throttle
54
+ * window has passed. Tracked separately from the run throttle: verifying an in-flight test message is
55
+ * cheap and meant to be polled, so it neither answers to nor consumes the user's run allowance.
56
+ */
57
+ export declare const NOTIFICATION_USER_HEALTH_CHECK_VERIFY_THROTTLED_ERROR_CODE = "NOTIFICATION_USER_HEALTH_CHECK_VERIFY_THROTTLED";
@@ -22,6 +22,7 @@ import { type NotificationBoxRecipient, type NotificationRecipientWithConfig, ty
22
22
  import { type YearWeekCode } from '@dereekb/date';
23
23
  import { type UserRelatedById, type UserRelated } from '../user';
24
24
  import { AbstractFirestoreDocument, AbstractFirestoreDocumentWithParent, type CollectionGroup, type CollectionReference, type FirestoreCollection, type FirestoreCollectionGroup, type FirestoreCollectionWithParent, type FirestoreContext, type FirestoreModelKey, type SavedToFirestoreIfTrue, type SavedToFirestoreIfFalse, type PagedItemConverter, type PagedItemFirestoreCollection, type PagedItemPageData } from '../../common';
25
+ import { type NotificationHealthCheck } from './notification.healthcheck';
25
26
  import { type NotificationItem } from './notification.item';
26
27
  /**
27
28
  * Abstract class providing access to all notification-related Firestore collections.
@@ -142,6 +143,16 @@ export interface NotificationUser extends UserRelated, UserRelatedById {
142
143
  * @dbxModelVariable needsConfigSync
143
144
  */
144
145
  ns?: Maybe<NeedsSyncBoolean>;
146
+ /**
147
+ * The result of the most recent notification delivery health check run for this user.
148
+ *
149
+ * Persisted rather than returned-and-forgotten because delivery confirmation is asynchronous:
150
+ * a probe dispatched by one health check run is resolved by a later one. Absent until a check
151
+ * has been run at least once.
152
+ *
153
+ * @dbxModelVariable healthCheck
154
+ */
155
+ hc?: Maybe<NotificationHealthCheck>;
145
156
  }
146
157
  export type NotificationUserRoles = 'sync' | GrantedUpdateRole | GrantedReadRole;
147
158
  export declare class NotificationUserDocument extends AbstractFirestoreDocument<NotificationUser, NotificationUserDocument, typeof notificationUserIdentity> {