@dereekb/dbx-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.
@@ -1,19 +1,19 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { InjectionToken, inject, Injectable, provideAppInitializer, makeEnvironmentProviders, Component, model, computed, ChangeDetectionStrategy, signal, Directive, EventEmitter, input, output, Injector, viewChild, HostListener, NgModule, ElementRef, forwardRef, effect, DestroyRef, Inject, Optional, Pipe } from '@angular/core';
3
3
  import { DbxAnalyticsService } from '@dereekb/dbx-analytics';
4
- import { asObservable, timeoutStartWith, filterMaybe, isNot, SubscriptionObject, lazyFrom, switchMapWhileTrue, loadingStateFromObs, distinctUntilKeysChange, cleanupDestroyable, iterationHasNextAndCanLoadMore, pageItemAccumulatorCurrentPage, accumulatorFlattenPageListLoadingState, useFirst, itemAccumulatorNextPageUntilResultsCount, iteratorNextPageUntilPage, iteratorNextPageUntilMaxPageLoadLimit, pageLoadingStateFromObs, useAsObservable, filterMaybeArray, mapEachAsync, invertObservableDecision, filterItemsWithObservableDecision, switchMapMaybe, beginLoading, mapLoadingStateValueWithOperator, valueFromFinishedLoadingState, skipInitialMaybe, distinctUntilModelKeyChange, successResult, errorResult, isLoadingStateLoading, cleanup, mapLoadingState, throwErrorFromLoadingStateError, maybeValueFromObservableOrValue, distinctUntilHasDifferentValues, MultiSubscriptionObject, startWithBeginLoading, skipAllInitialMaybe } from '@dereekb/rxjs';
5
- import { Observable, switchMap, of, shareReplay, map, Subject, merge, distinctUntilChanged, EMPTY, catchError, firstValueFrom, tap, BehaviorSubject, combineLatest, first, from, interval, exhaustMap, filter, take, startWith, throttleTime, NEVER, defaultIfEmpty, combineLatestWith, mergeMap } from 'rxjs';
4
+ import { asObservable, timeoutStartWith, filterMaybe, isNot, SubscriptionObject, lazyFrom, switchMapWhileTrue, loadingStateFromObs, distinctUntilKeysChange, cleanupDestroyable, iterationHasNextAndCanLoadMore, pageItemAccumulatorCurrentPage, accumulatorFlattenPageListLoadingState, useFirst, itemAccumulatorNextPageUntilResultsCount, iteratorNextPageUntilPage, iteratorNextPageUntilMaxPageLoadLimit, pageLoadingStateFromObs, useAsObservable, filterMaybeArray, mapEachAsync, invertObservableDecision, filterItemsWithObservableDecision, switchMapMaybe, beginLoading, mapLoadingStateValueWithOperator, valueFromFinishedLoadingState, skipInitialMaybe, distinctUntilModelKeyChange, successResult, errorResult, isLoadingStateLoading, cleanup, mapLoadingState, startWithBeginLoading, throwErrorFromLoadingStateError, maybeValueFromObservableOrValue, distinctUntilHasDifferentValues, MultiSubscriptionObject, skipAllInitialMaybe } from '@dereekb/rxjs';
5
+ import { Observable, switchMap, of, shareReplay, map, Subject, merge, distinctUntilChanged, EMPTY, catchError, firstValueFrom, tap, BehaviorSubject, combineLatest, first, from, interval, exhaustMap, filter, take, startWith, throttleTime, NEVER, defaultIfEmpty, combineLatestWith, timer, takeWhile, withLatestFrom, mergeMap } from 'rxjs';
6
6
  import * as i2 from '@dereekb/dbx-core';
7
- import { loggedInObsFromIsLoggedIn, loggedOutObsFromIsLoggedIn, authUserIdentifier, DbxInjectionContext, DBX_INJECTION_COMPONENT_DATA, DbxInjectionComponent, AbstractForwardDbxInjectionContextDirective, DbxInjectionContextDirective, DbxAuthImpersonationDelegate, DbxAuthService, provideDbxAuthImpersonation, DbxActionButtonDirective, completeOnDestroy, cleanSubscription, DbxActionDirective, DbxActionEnforceModifiedDirective, DbxActionHandlerDirective, DbxActionAutoTriggerDirective, clean, cleanLoadingContext, provideDbxRouteModelIdDirectiveDelegate, provideDbxRouteModelKeyDirectiveDelegate, AbstractIfDirective, LockSetComponentStore, newWithInjector, CutTextPipe, DbxActionContextStoreSourceInstance, DbxActionHandlerInstance, cleanSubscriptionWithLockSet, DbxButton, SimpleStorageAccessorFactory, dbxRouteParamReaderInstance, DbxRouteParamDefaultRedirectInstance } from '@dereekb/dbx-core';
7
+ import { loggedInObsFromIsLoggedIn, loggedOutObsFromIsLoggedIn, authUserIdentifier, DbxInjectionContext, DBX_INJECTION_COMPONENT_DATA, DbxInjectionComponent, AbstractForwardDbxInjectionContextDirective, DbxInjectionContextDirective, DbxAuthImpersonationDelegate, DbxAuthService, provideDbxAuthImpersonation, DbxActionButtonDirective, completeOnDestroy, cleanSubscription, DbxActionDirective, DbxActionEnforceModifiedDirective, DbxActionHandlerDirective, DbxActionAutoTriggerDirective, clean, cleanLoadingContext, provideDbxRouteModelIdDirectiveDelegate, provideDbxRouteModelKeyDirectiveDelegate, AbstractIfDirective, LockSetComponentStore, newWithInjector, DbxActionDisabledDirective, CutTextPipe, DbxActionValueDirective, DbxActionContextStoreSourceInstance, DbxActionHandlerInstance, cleanSubscriptionWithLockSet, DbxButton, SimpleStorageAccessorFactory, dbxRouteParamReaderInstance, DbxRouteParamDefaultRedirectInstance } from '@dereekb/dbx-core';
8
8
  import { onAuthStateChanged, onIdTokenChanged, confirmPasswordReset, sendPasswordResetEmail, signInWithPopup, signInWithRedirect, linkWithPopup, linkWithRedirect, linkWithCredential, unlink, createUserWithEmailAndPassword, signInWithEmailAndPassword, signInAnonymously, reauthenticateWithPopup, reauthenticateWithRedirect, getRedirectResult, OAuthProvider, FacebookAuthProvider, GithubAuthProvider, GoogleAuthProvider, TwitterAuthProvider, getAuth, connectAuthEmulator } from 'firebase/auth';
9
- import { AUTH_ADMIN_ROLE, cachedGetter, urlWithoutParameters, addToSet, removeFromSet, filterMaybeArrayValues, mapIterable, asArray, excludeValuesFromArray, containsStringAnyCase, addToSetCopy, iterableToArray, runAsyncTasksForValues, forEachKeyValue, countAllInNestedArray, invertDecision, useIterableOrValue, filterUniqueValues, reverseCompareFn, sortByNumberFunction, separateValues, readableError, isMaybeSo, firstValue, splitJoinRemainder, MS_IN_HOUR, SECONDS_IN_MINUTE, MS_IN_DAY, unixDateTimeSecondsNumberForNow, MS_IN_MINUTE, addMilliseconds, unixDateTimeSecondsNumberFromDate, dateFromDateOrTimeSecondsNumber, MS_IN_SECOND, isPast } from '@dereekb/util';
9
+ import { AUTH_ADMIN_ROLE, cachedGetter, urlWithoutParameters, addToSet, removeFromSet, filterMaybeArrayValues, mapIterable, asArray, excludeValuesFromArray, containsStringAnyCase, addToSetCopy, iterableToArray, runAsyncTasksForValues, forEachKeyValue, countAllInNestedArray, invertDecision, useIterableOrValue, filterUniqueValues, reverseCompareFn, sortByNumberFunction, separateValues, readableError, isMaybeSo, firstValue, areEqualPOJOValues, MS_IN_SECOND, splitJoinRemainder, MS_IN_HOUR, SECONDS_IN_MINUTE, MS_IN_DAY, unixDateTimeSecondsNumberForNow, MS_IN_MINUTE, addMilliseconds, unixDateTimeSecondsNumberFromDate, dateFromDateOrTimeSecondsNumber, isPast } from '@dereekb/util';
10
10
  import { safeFormatToISO8601DateString, msToSeconds, isSameDate } from '@dereekb/date';
11
11
  import { getToken, initializeAppCheck, ReCaptchaV3Provider } from 'firebase/app-check';
12
12
  import * as i1$1 from '@dereekb/dbx-web';
13
- import { DbxLinkComponent, DbxActionModule, DbxButtonModule, DbxErrorComponent, DbxActionErrorDirective, DbxButtonComponent, DbxButtonSpacerDirective, DbxRouterAnchorModule, DbxSectionComponent, DbxWidgetService, AbstractDbxSelectionListWrapperDirective, DbxListWrapperComponentImportsModule, provideDbxListViewWrapper, DEFAULT_LIST_WRAPPER_COMPONENT_CONFIGURATION_TEMPLATE, AbstractDbxSelectionListViewDirective, DbxSelectionValueListViewComponentImportsModule, provideDbxListView, DEFAULT_DBX_SELECTION_VALUE_LIST_COMPONENT_CONFIGURATION_TEMPLATE, AbstractDbxValueListViewItemComponent, TwoColumnsContextStore, DbxAnchorComponent, DbxTwoColumnFullLeftDirective, DbxWidgetViewComponent, DbxTwoColumnComponent, DbxTwoBlockComponent, DbxTwoColumnRightComponent, AbstractPopupDirective, DbxPopupService, DbxPopupContentComponent, DbxPopupControlsComponent, DbxModelTypesService, DbxModelTrackerService, allDbxModelViewTrackerEventModelKeys, DbxListItemAnchorModifierDirective, DbxValueListItemModifierDirective, AbstractPopoverDirective, DbxPopoverContentComponent, DbxPopoverHeaderComponent, DbxPopoverScrollContentDirective, DbxListEmptyContentComponent, AbstractPopoverRefDirective, DbxPopoverService, DbxLoadingComponent, DbxDetailBlockComponent, DbxClickToCopyTextComponent, DbxDownloadTextViewComponent, DbxModelObjectStateService, DbxListViewWrapper, AbstractDbxWidgetComponent, DbxPopoverInteractionModule, DbxListModifierModule, DbxWebFilePreviewService, DbxActionSnackbarErrorDirective, DbxActionDialogDirective, compressImageFile, DbxFileUploadComponent, DbxPdfMergeEditorStore, PDF_MERGE_RESULT_MIME_TYPE, DbxActionLoadingContextDirective, DbxFileUploadActionSyncDirective } from '@dereekb/dbx-web';
13
+ import { DbxLinkComponent, DbxActionModule, DbxButtonModule, DbxErrorComponent, DbxActionErrorDirective, DbxButtonComponent, DbxButtonSpacerDirective, DbxRouterAnchorModule, DbxSectionComponent, DbxWidgetService, AbstractDbxSelectionListWrapperDirective, DbxListWrapperComponentImportsModule, provideDbxListViewWrapper, DEFAULT_LIST_WRAPPER_COMPONENT_CONFIGURATION_TEMPLATE, AbstractDbxSelectionListViewDirective, DbxSelectionValueListViewComponentImportsModule, provideDbxListView, DEFAULT_DBX_SELECTION_VALUE_LIST_COMPONENT_CONFIGURATION_TEMPLATE, AbstractDbxValueListViewItemComponent, TwoColumnsContextStore, DbxAnchorComponent, DbxTwoColumnFullLeftDirective, DbxWidgetViewComponent, DbxTwoColumnComponent, DbxTwoBlockComponent, DbxTwoColumnRightComponent, AbstractPopupDirective, DbxPopupService, DbxPopupContentComponent, DbxPopupControlsComponent, DbxModelTypesService, DbxModelTrackerService, allDbxModelViewTrackerEventModelKeys, DbxListItemAnchorModifierDirective, DbxValueListItemModifierDirective, AbstractPopoverDirective, DbxPopoverContentComponent, DbxPopoverHeaderComponent, DbxPopoverScrollContentDirective, DbxListEmptyContentComponent, AbstractPopoverRefDirective, DbxPopoverService, DbxLoadingComponent, DbxDetailBlockComponent, DbxClickToCopyTextComponent, DbxDownloadTextViewComponent, DbxModelObjectStateService, DbxListViewWrapper, DbxChipDirective, DbxColorDirective, DbxIconTileComponent, DbxActionConfirmDirective, DbxContentPitDirective, AbstractDbxWidgetComponent, AbstractDialogDirective, DbxDialogContentDirective, DbxPopoverInteractionModule, DbxListModifierModule, DbxWebFilePreviewService, DbxActionSnackbarErrorDirective, DbxActionDialogDirective, compressImageFile, DbxFileUploadComponent, DbxPdfMergeEditorStore, PDF_MERGE_RESULT_MIME_TYPE, DbxActionLoadingContextDirective, DbxFileUploadActionSyncDirective } from '@dereekb/dbx-web';
14
14
  import * as i1 from '@angular/material/icon';
15
15
  import { MatIconModule, MatIcon } from '@angular/material/icon';
16
- import { firebaseAuthErrorToReadableError, FIREBASE_AUTH_PASSWORD_MIN_LENGTH, FirebaseDevelopmentFunctions, ScheduledFunctionDevelopmentFunctionTypeEnum, clientFirebaseFirestoreContextFactory, SystemStateFirestoreCollections, NotificationFirestoreCollections, StorageFileFirestoreCollections, FIREBASE_DEVELOPMENT_FUNCTIONS_MAP_KEY, iterationQueryDocChangeWatcher, firebaseQuerySnapshotAccumulator, firebaseQueryItemAccumulator, firestoreModelKeysFromDocuments, firestoreModelIdsFromDocuments, documentReferencesFromDocuments, getDocumentSnapshots, getDataFromDocumentSnapshots, latestSnapshotsFromDocuments, dataFromDocumentSnapshots, loadDocumentsForKeys, loadDocumentsForDocumentReferences, loadDocumentsForIds, firestoreModelKeyCollectionTypePair, buildFirebaseCollectionTypeModelTypeMap, firestoreModelId, flatFirestoreModelKey, twoWayFlatFirestoreModelKey, FirestoreAccessorStreamMode, firestoreModelIdsFromKey, firestoreModelKeyPartPairs, firestoreModelKeyPairObject, documentDataWithIdAndKey, isClientFirebaseError, FIRESTORE_PERMISSION_DENIED_ERROR_CODE, inferKeyFromTwoWayFlatFirestoreModelKey, firestoreModelKeyParentKey, AppNotificationTemplateTypeInfoRecordService, NotificationFunctions, unreadNotificationItems, StorageFileFunctions, firestoreModelKey, storageFileIdentity, clientFirebaseStorageContextFactory } from '@dereekb/firebase';
16
+ import { firebaseAuthErrorToReadableError, FIREBASE_AUTH_PASSWORD_MIN_LENGTH, FirebaseDevelopmentFunctions, ScheduledFunctionDevelopmentFunctionTypeEnum, clientFirebaseFirestoreContextFactory, SystemStateFirestoreCollections, NotificationFirestoreCollections, StorageFileFirestoreCollections, FIREBASE_DEVELOPMENT_FUNCTIONS_MAP_KEY, iterationQueryDocChangeWatcher, firebaseQuerySnapshotAccumulator, firebaseQueryItemAccumulator, firestoreModelKeysFromDocuments, firestoreModelIdsFromDocuments, documentReferencesFromDocuments, getDocumentSnapshots, getDataFromDocumentSnapshots, latestSnapshotsFromDocuments, dataFromDocumentSnapshots, loadDocumentsForKeys, loadDocumentsForDocumentReferences, loadDocumentsForIds, firestoreModelKeyCollectionTypePair, buildFirebaseCollectionTypeModelTypeMap, firestoreModelId, flatFirestoreModelKey, twoWayFlatFirestoreModelKey, FirestoreAccessorStreamMode, firestoreModelIdsFromKey, firestoreModelKeyPartPairs, firestoreModelKeyPairObject, documentDataWithIdAndKey, isClientFirebaseError, FIRESTORE_PERMISSION_DENIED_ERROR_CODE, inferKeyFromTwoWayFlatFirestoreModelKey, firestoreModelKeyParentKey, NotificationHealthCheckStatus, NotificationDeliveryMethod, MailgunNotificationHealthCheckIssueCode, KnownNotificationHealthCheckIssueCode, AppNotificationTemplateTypeInfoRecordService, NotificationFunctions, notificationUserHealthCheckNextRunAt, notificationUserHealthCheckNextProbeAtByMethod, notificationHealthCheckPendingProbeMethods, notificationUserHealthCheckNextVerifyAt, DEFAULT_NOTIFICATION_USER_HEALTH_CHECK_VERIFY_THROTTLE_SECONDS, ALL_NOTIFICATION_DELIVERY_METHODS, unreadNotificationItems, StorageFileFunctions, firestoreModelKey, storageFileIdentity, clientFirebaseStorageContextFactory } from '@dereekb/firebase';
17
17
  import * as i1$2 from '@dereekb/dbx-form';
18
18
  import { AbstractSyncForgeFormDirective, dbxForgeEmailField, DbxForgeFormComponentImportsModule, dbxForgeFormComponentProviders, DBX_FORGE_FORM_COMPONENT_TEMPLATE, AbstractConfigAsyncForgeFormDirective, dbxForgeUsernameLoginField, dbxForgeTextPasswordField, dbxForgeTextVerifyPasswordField, DbxActionFormDirective, DbxFormSourceDirective, dbxForgeTextPasswordWithVerifyField, dbxForgeTextField, dbxForgePickableChipField, filterPickableItemFieldValuesByLabel } from '@dereekb/dbx-form';
19
19
  import { NgTemplateOutlet, DatePipe } from '@angular/common';
@@ -30,6 +30,7 @@ import { MatExpansionPanel, MatExpansionPanelHeader, MatExpansionPanelTitle, Mat
30
30
  import { ComponentStore } from '@ngrx/component-store';
31
31
  import { __decorate, __param } from 'tslib';
32
32
  import { MatDialog } from '@angular/material/dialog';
33
+ import { isAfter, addMinutes } from 'date-fns';
33
34
  import { BaseError } from 'make-error';
34
35
 
35
36
  /**
@@ -288,6 +289,34 @@ const DEFAULT_DBX_FIREBASE_AUTH_SERVICE_DELEGATE = {
288
289
  return of(undefined);
289
290
  }
290
291
  };
292
+ /**
293
+ * Creates a function that returns a shared observable scoped to the input's uid, discarding and rebuilding it
294
+ * whenever the uid changes.
295
+ *
296
+ * Exists because a `shareReplay()` buffer cannot be cleared: a shared stream that outlives the signed-in user
297
+ * hands the NEXT user's subscribers a value derived from the PREVIOUS user's token, synchronously. Any consumer
298
+ * that reads the first emission — the UIRouter auth transition hooks, for instance — then acts on data belonging
299
+ * to a different user. Rebuilding per-uid gives a same-page re-login (log out, log back in as someone else
300
+ * without reloading) the same cold-start behavior as a page reload.
301
+ *
302
+ * The per-uid observable should use `refCount: true` so the discarded uid's source is torn down rather than
303
+ * leaking one live subscription per user switch. That is safe here because the returned observable is only
304
+ * consumed through a `switchMap`, so its reference count tracks the outer subscribers exactly.
305
+ *
306
+ * @param config - The uid reader and the per-uid observable factory.
307
+ * @returns Function that returns the shared observable for the input.
308
+ */
309
+ function sharedObservableForUidFunction(config) {
310
+ const { uidForInput, factoryForInput } = config;
311
+ let current;
312
+ return (input) => {
313
+ const uid = uidForInput(input);
314
+ if (current == null || current.uid !== uid) {
315
+ current = { uid, obs: factoryForInput(input) };
316
+ }
317
+ return current.obs;
318
+ };
319
+ }
291
320
  // MARK: Service
292
321
  class DbxFirebaseAuthService {
293
322
  firebaseAuth = inject(FIREBASE_AUTH_TOKEN);
@@ -328,26 +357,71 @@ class DbxFirebaseAuthService {
328
357
  * Alias for uid$
329
358
  */
330
359
  userIdentifier$ = this.uid$;
331
- currentIdTokenString$ = firebaseIdToken(this.firebaseAuth).pipe(distinctUntilChanged(), shareReplay(1));
360
+ /**
361
+ * The current ID token string, or null while logged out.
362
+ *
363
+ * Scoped per-uid via {@link sharedObservableForUidFunction} so the replay buffer can never hand a subscriber
364
+ * the PREVIOUS user's token after a same-page re-login.
365
+ */
366
+ currentIdTokenString$ = (() => {
367
+ const sharedForUid = sharedObservableForUidFunction({
368
+ uidForInput: (uid) => uid,
369
+ factoryForInput: (uid) => (uid == null ? of(null) : firebaseIdToken(this.firebaseAuth).pipe(distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: true })))
370
+ });
371
+ return this.currentUid$.pipe(switchMap((uid) => sharedForUid(uid)));
372
+ })();
332
373
  idTokenString$ = this.currentUid$.pipe(switchMap((x) => (x ? this.currentIdTokenString$.pipe(filterMaybe()) : EMPTY)));
333
- currentIdTokenResult$ = this.currentAuthUser$.pipe(switchMap((x) => (x ? this.currentIdTokenString$.pipe(switchMap((y) => (y ? x.getIdTokenResult() : of(null)))) : of(null))), distinctUntilChanged(), shareReplay(1));
374
+ /**
375
+ * The current user's decoded ID token, or null while logged out.
376
+ *
377
+ * Scoped per-uid via {@link sharedObservableForUidFunction}. Token refreshes still flow through, as they arrive
378
+ * on {@link currentIdTokenString$}; only a uid change rebuilds the stream.
379
+ */
380
+ currentIdTokenResult$ = (() => {
381
+ const sharedForUser = sharedObservableForUidFunction({
382
+ uidForInput: (user) => user?.uid,
383
+ factoryForInput: (user) => user == null
384
+ ? of(null)
385
+ : this.currentIdTokenString$.pipe(switchMap((token) => (token ? user.getIdTokenResult() : of(null))), distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: true }))
386
+ });
387
+ return this.currentAuthUser$.pipe(distinctUntilChanged((a, b) => a?.uid === b?.uid), switchMap((user) => sharedForUser(user)));
388
+ })();
334
389
  idTokenResult$ = this.currentIdTokenResult$.pipe(filterMaybe());
335
- currentClaims$ = this.currentIdTokenResult$.pipe(map((x) => (x ? x.claims : null)), distinctUntilChanged(), shareReplay(1));
390
+ /**
391
+ * The current user's token claims, or null while logged out.
392
+ *
393
+ * Intentionally not replayed: {@link currentIdTokenResult$} is already shared per-uid, and a buffer here would
394
+ * reintroduce the cross-user staleness that scoping removes.
395
+ */
396
+ currentClaims$ = this.currentIdTokenResult$.pipe(map((x) => (x ? x.claims : null)), distinctUntilChanged());
336
397
  claims$ = this.currentClaims$.pipe(filterMaybe());
337
398
  currentAuthContextInfo$ = this.currentAuthUser$.pipe(switchMap((x) => this.loadAuthContextInfoForUser(x)), shareReplay(1));
338
399
  authContextInfo$ = this.currentAuthContextInfo$.pipe(filterMaybe());
400
+ /**
401
+ * The current {@link AuthUserState}.
402
+ *
403
+ * The delegate's state stream is scoped per-uid via {@link sharedObservableForUidFunction}, so it is rebuilt
404
+ * whenever the signed-in uid changes. Without that, a subscriber attaching right after a same-page re-login is
405
+ * served the prior session's state synchronously from the replay buffer — and every consumer that reads the
406
+ * first emission, including the UIRouter auth transition hooks, then routes on it. The delegate factory is
407
+ * re-invoked per uid so the delegate's own internal replay is discarded along with it.
408
+ */
339
409
  authUserState$ = (() => {
340
- const delegateAuthUserStateObs = this.delegate.authUserStateObs(this).pipe(catchError(() => of('error')), distinctUntilChanged(), shareReplay(1));
341
- let obs;
342
- if (this.delegate.fullControlOfAuthUserState) {
343
- obs = delegateAuthUserStateObs;
344
- }
345
- else {
346
- obs = this._authState$.pipe(distinctUntilChanged(), switchMap((x) => {
347
- return x == null ? of('none') : delegateAuthUserStateObs;
348
- }));
349
- }
350
- return obs;
410
+ const fullControlOfAuthUserState = Boolean(this.delegate.fullControlOfAuthUserState);
411
+ const sharedDelegateStateForUid = sharedObservableForUidFunction({
412
+ uidForInput: (user) => user?.uid,
413
+ factoryForInput: (user) => {
414
+ let obs;
415
+ if (user == null && !fullControlOfAuthUserState) {
416
+ obs = of('none');
417
+ }
418
+ else {
419
+ obs = this.delegate.authUserStateObs(this).pipe(catchError(() => of('error')), distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: true }));
420
+ }
421
+ return obs;
422
+ }
423
+ });
424
+ return this._authState$.pipe(distinctUntilChanged((a, b) => a?.uid === b?.uid), switchMap((user) => sharedDelegateStateForUid(user)));
351
425
  })();
352
426
  authRoles$ = this.delegate.authRolesObs(this);
353
427
  isOnboarded$ = this.delegate.isOnboarded(this);
@@ -2279,7 +2353,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
2279
2353
  function authRolesObsWithClaimsService(config) {
2280
2354
  const { addAuthUserStateToRoles: addAuthUserState, claimsService } = config;
2281
2355
  return (dbxFirebaseAuthService) => {
2282
- let obs = dbxFirebaseAuthService.idTokenResult$.pipe(map((x) => claimsService.toRoles(x.claims)));
2356
+ /**
2357
+ * Sourced from currentIdTokenResult$ instead of idTokenResult$ so the logged-out null is not swallowed by that
2358
+ * stream's filterMaybe(): the claim-derived roles have to CLEAR when there is no token. Otherwise they persist
2359
+ * through the entire logged-out window and on into the next user's session, and a role guard evaluated in that
2360
+ * window passes on the PREVIOUS user's roles.
2361
+ */
2362
+ let obs = dbxFirebaseAuthService.currentIdTokenResult$.pipe(map((x) => (x == null ? new Set() : claimsService.toRoles(x.claims))));
2283
2363
  if (addAuthUserState) {
2284
2364
  obs = obs.pipe(switchMap((authRoleSet) => dbxFirebaseAuthService.authUserState$.pipe(map((userState) => addToSetCopy(authRoleSet, [userState])))));
2285
2365
  }
@@ -6182,6 +6262,648 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
6182
6262
  }]
6183
6263
  }] });
6184
6264
 
6265
+ /**
6266
+ * App-level tuning for the notification delivery health check UI.
6267
+ *
6268
+ * These windows are ENFORCED BY THE SERVER; the client only counts down to them so it can disable an
6269
+ * action instead of letting the user trigger a call that comes back as an error. So every value here
6270
+ * must match what the server was configured with — declare it once in a package both sides import
6271
+ * rather than writing the number down twice, or the UI will offer a test message the server rejects.
6272
+ */
6273
+ class DbxFirebaseNotificationHealthCheckConfig {
6274
+ }
6275
+ /**
6276
+ * How long the client keeps watching an in-flight test message before giving up on it.
6277
+ *
6278
+ * Comfortably longer than a provider takes to record a delivery outcome — the point is to stop polling
6279
+ * a provider that is never going to answer, not to impose a deadline of the client's own.
6280
+ */
6281
+ const DEFAULT_NOTIFICATION_HEALTH_CHECK_PROBE_WATCH_MINUTES = 20;
6282
+ /**
6283
+ * Configuration for the {@link DbxFirebaseNotificationHealthCheckPresentationService}.
6284
+ */
6285
+ class DbxFirebaseNotificationHealthCheckPresentationServiceConfig {
6286
+ }
6287
+ /**
6288
+ * Colour for each health check status.
6289
+ *
6290
+ * `WARNING` and `ERROR` deliberately share `warn` — the palette has no distinct error tone — so they
6291
+ * are told apart by their icons instead.
6292
+ */
6293
+ const NOTIFICATION_HEALTH_CHECK_STATUS_COLORS = {
6294
+ [NotificationHealthCheckStatus.OK]: 'success',
6295
+ [NotificationHealthCheckStatus.WARNING]: 'warn',
6296
+ [NotificationHealthCheckStatus.ERROR]: 'warn',
6297
+ [NotificationHealthCheckStatus.PENDING]: 'notice',
6298
+ [NotificationHealthCheckStatus.SKIPPED]: 'grey',
6299
+ [NotificationHealthCheckStatus.UNKNOWN]: 'grey'
6300
+ };
6301
+ /**
6302
+ * Icon for each health check status. Also what distinguishes a warning from an error.
6303
+ */
6304
+ const NOTIFICATION_HEALTH_CHECK_STATUS_ICONS = {
6305
+ [NotificationHealthCheckStatus.OK]: 'check_circle',
6306
+ [NotificationHealthCheckStatus.WARNING]: 'warning',
6307
+ [NotificationHealthCheckStatus.ERROR]: 'error',
6308
+ [NotificationHealthCheckStatus.PENDING]: 'hourglass_top',
6309
+ [NotificationHealthCheckStatus.SKIPPED]: 'remove_circle_outline',
6310
+ [NotificationHealthCheckStatus.UNKNOWN]: 'help'
6311
+ };
6312
+ /**
6313
+ * Human-readable label for each health check status.
6314
+ *
6315
+ * Used as the chip label for an issue code with no registered entry.
6316
+ */
6317
+ const NOTIFICATION_HEALTH_CHECK_STATUS_LABELS = {
6318
+ [NotificationHealthCheckStatus.OK]: 'OK',
6319
+ [NotificationHealthCheckStatus.WARNING]: 'Warning',
6320
+ [NotificationHealthCheckStatus.ERROR]: 'Problem',
6321
+ [NotificationHealthCheckStatus.PENDING]: 'Pending',
6322
+ [NotificationHealthCheckStatus.SKIPPED]: 'Not Checked',
6323
+ [NotificationHealthCheckStatus.UNKNOWN]: 'Unknown'
6324
+ };
6325
+ /**
6326
+ * Human-readable label for each delivery method.
6327
+ */
6328
+ const NOTIFICATION_DELIVERY_METHOD_LABELS = {
6329
+ [NotificationDeliveryMethod.EMAIL]: 'Email',
6330
+ [NotificationDeliveryMethod.TEXT]: 'Text Message',
6331
+ [NotificationDeliveryMethod.PUSH]: 'Push Notification',
6332
+ [NotificationDeliveryMethod.NOTIFICATION_SUMMARY]: 'In-App Notification'
6333
+ };
6334
+ /**
6335
+ * Icon for each delivery method.
6336
+ */
6337
+ const NOTIFICATION_DELIVERY_METHOD_ICONS = {
6338
+ [NotificationDeliveryMethod.EMAIL]: 'mail',
6339
+ [NotificationDeliveryMethod.TEXT]: 'sms',
6340
+ [NotificationDeliveryMethod.PUSH]: 'notifications',
6341
+ [NotificationDeliveryMethod.NOTIFICATION_SUMMARY]: 'inbox'
6342
+ };
6343
+ /**
6344
+ * Label for each delivery method's "send a test message" action.
6345
+ *
6346
+ * Always names what the method actually delivers — "Send Test Email", "Send Test Text Message" — rather
6347
+ * than a generic "Send Test Message", so the button says which of a user's contact details it is about
6348
+ * to send something real to.
6349
+ */
6350
+ const NOTIFICATION_DELIVERY_METHOD_TEST_MESSAGE_LABELS = {
6351
+ [NotificationDeliveryMethod.EMAIL]: 'Send Test Email',
6352
+ [NotificationDeliveryMethod.TEXT]: 'Send Test Text Message',
6353
+ [NotificationDeliveryMethod.PUSH]: 'Send Test Push Notification',
6354
+ [NotificationDeliveryMethod.NOTIFICATION_SUMMARY]: 'Send Test In-App Notification'
6355
+ };
6356
+ /**
6357
+ * Noun for what each delivery method's test message actually is, for use mid-sentence.
6358
+ *
6359
+ * Lowercase because it reads inside prose — "A test text message was sent recently."
6360
+ */
6361
+ const NOTIFICATION_DELIVERY_METHOD_TEST_MESSAGE_NOUNS = {
6362
+ [NotificationDeliveryMethod.EMAIL]: 'test email',
6363
+ [NotificationDeliveryMethod.TEXT]: 'test text message',
6364
+ [NotificationDeliveryMethod.PUSH]: 'test push notification',
6365
+ [NotificationDeliveryMethod.NOTIFICATION_SUMMARY]: 'test in-app notification'
6366
+ };
6367
+ /**
6368
+ * Short name for each delivery method, for a label that has to stay compact.
6369
+ *
6370
+ * Used to compose the probe chips — `Test Email Sent`, `Test Text Sent` — where the full
6371
+ * {@link NOTIFICATION_DELIVERY_METHOD_LABELS} wording would make the chip too long to scan.
6372
+ */
6373
+ const NOTIFICATION_DELIVERY_METHOD_SHORT_LABELS = {
6374
+ [NotificationDeliveryMethod.EMAIL]: 'Email',
6375
+ [NotificationDeliveryMethod.TEXT]: 'Text',
6376
+ [NotificationDeliveryMethod.PUSH]: 'Push',
6377
+ [NotificationDeliveryMethod.NOTIFICATION_SUMMARY]: 'In-App'
6378
+ };
6379
+ /**
6380
+ * What each probe lifecycle code says happened to the test message.
6381
+ *
6382
+ * The other half of the composed probe chip label — see {@link notificationHealthCheckProbeIssueLabel}.
6383
+ */
6384
+ const NOTIFICATION_HEALTH_CHECK_PROBE_ISSUE_OUTCOMES = {
6385
+ [KnownNotificationHealthCheckIssueCode.PROBE_PENDING]: 'Sent',
6386
+ [KnownNotificationHealthCheckIssueCode.PROBE_DELIVERED]: 'Delivered',
6387
+ [KnownNotificationHealthCheckIssueCode.PROBE_FAILED]: 'Failed',
6388
+ [KnownNotificationHealthCheckIssueCode.PROBE_DISPATCH_FAILED]: 'Not Sent',
6389
+ [MailgunNotificationHealthCheckIssueCode.PROBE_NOT_CONFIGURED]: 'Unavailable'
6390
+ };
6391
+ /**
6392
+ * The chip label for a probe lifecycle finding, naming the delivery method it belongs to.
6393
+ *
6394
+ * Every provider emits the same probe codes, so these labels cannot be fixed strings in the presentation
6395
+ * registry the way every other code's is: the same `probeDelivered` finding should read `Test Email
6396
+ * Delivered` in the email section and `Test Text Delivered` in the text section.
6397
+ *
6398
+ * @param code - The issue code to label.
6399
+ * @param method - The delivery method whose section the finding is rendered in.
6400
+ * @returns The composed label, or undefined when the code is not a probe lifecycle code.
6401
+ */
6402
+ function notificationHealthCheckProbeIssueLabel(code, method) {
6403
+ const outcome = NOTIFICATION_HEALTH_CHECK_PROBE_ISSUE_OUTCOMES[code];
6404
+ return outcome == null ? undefined : `Test ${NOTIFICATION_DELIVERY_METHOD_SHORT_LABELS[method] ?? 'Message'} ${outcome}`;
6405
+ }
6406
+ /**
6407
+ * Presentation entries for every issue code the library and the Mailgun email check emit.
6408
+ *
6409
+ * None of them set a colour — see {@link DbxFirebaseNotificationHealthCheckPresentationEntry.color}.
6410
+ */
6411
+ const DEFAULT_NOTIFICATION_HEALTH_CHECK_PRESENTATION_ENTRIES = [
6412
+ // configuration
6413
+ { code: KnownNotificationHealthCheckIssueCode.SEND_SERVICE_NOT_CONFIGURED, label: 'Not Available', icon: 'block' },
6414
+ { code: KnownNotificationHealthCheckIssueCode.SEND_SERVICE_HEALTH_CHECK_UNAVAILABLE, label: 'Not Verified', icon: 'help' },
6415
+ { code: KnownNotificationHealthCheckIssueCode.NO_DELIVERY_TARGET, label: 'No Destination', icon: 'person_off' },
6416
+ { code: KnownNotificationHealthCheckIssueCode.RECIPIENT_OPTED_OUT, label: 'Opted Out', icon: 'unsubscribe' },
6417
+ { code: KnownNotificationHealthCheckIssueCode.RECIPIENT_DISABLED, label: 'Turned Off', icon: 'notifications_off' },
6418
+ { code: KnownNotificationHealthCheckIssueCode.METHOD_DISABLED_GLOBALLY, label: 'Off Everywhere', icon: 'notifications_off' },
6419
+ { code: KnownNotificationHealthCheckIssueCode.METHOD_DISABLED_FOR_TEMPLATE, label: 'Off For This Type', icon: 'notifications_paused' },
6420
+ { code: KnownNotificationHealthCheckIssueCode.METHOD_DISABLED_FOR_BOX, label: 'Off For A Subscription', icon: 'notifications_paused' },
6421
+ // subscriptions
6422
+ { code: KnownNotificationHealthCheckIssueCode.NO_NOTIFICATION_BOXES, label: 'No Subscriptions', icon: 'inbox' },
6423
+ { code: KnownNotificationHealthCheckIssueCode.NOTIFICATION_BOX_EXCLUSIONS, label: 'Suppressed', icon: 'filter_alt_off' },
6424
+ { code: KnownNotificationHealthCheckIssueCode.NEEDS_CONFIG_SYNC, label: 'Still Saving', icon: 'sync_problem' },
6425
+ { code: KnownNotificationHealthCheckIssueCode.SUBSCRIPTION_BROKEN, label: 'Broken Subscription', icon: 'link_off' },
6426
+ { code: KnownNotificationHealthCheckIssueCode.SUBSCRIPTION_NOT_READY, label: 'Still Setting Up', icon: 'hourglass_top' },
6427
+ // probe. These labels are only the fallback for a finding rendered without a delivery method in hand:
6428
+ // given one, notificationHealthCheckProbeIssueLabel() names it — `Test Email Sent`, `Test Text Sent`.
6429
+ { code: KnownNotificationHealthCheckIssueCode.PROBE_PENDING, label: 'Test Sent', icon: 'hourglass_top' },
6430
+ { code: KnownNotificationHealthCheckIssueCode.PROBE_DELIVERED, label: 'Test Delivered', icon: 'mark_email_read' },
6431
+ { code: KnownNotificationHealthCheckIssueCode.PROBE_FAILED, label: 'Test Failed', icon: 'error' },
6432
+ { code: KnownNotificationHealthCheckIssueCode.PROBE_DISPATCH_FAILED, label: 'Test Not Sent', icon: 'error' },
6433
+ // mailgun
6434
+ { code: MailgunNotificationHealthCheckIssueCode.SUPPRESSED_BOUNCE, label: 'Blocked After Bounce', icon: 'block' },
6435
+ { code: MailgunNotificationHealthCheckIssueCode.SUPPRESSED_COMPLAINT, label: 'Blocked After Spam Report', icon: 'report' },
6436
+ { code: MailgunNotificationHealthCheckIssueCode.SUPPRESSED_UNSUBSCRIBE, label: 'Unsubscribed', icon: 'unsubscribe' },
6437
+ { code: MailgunNotificationHealthCheckIssueCode.RECENT_DELIVERY_FAILURE, label: 'Recent Delivery Failed', icon: 'error' },
6438
+ { code: MailgunNotificationHealthCheckIssueCode.RECENT_DELIVERY_SUCCESS, label: 'Recently Delivered', icon: 'mark_email_read' },
6439
+ { code: MailgunNotificationHealthCheckIssueCode.NO_RECENT_ACTIVITY, label: 'No Recent Activity', icon: 'history_toggle_off' },
6440
+ { code: MailgunNotificationHealthCheckIssueCode.DOMAIN_NOT_ACTIVE, label: 'Sending System Down', icon: 'dns' },
6441
+ { code: MailgunNotificationHealthCheckIssueCode.ADDRESS_UNDELIVERABLE, label: 'Address Undeliverable', icon: 'person_off' },
6442
+ { code: MailgunNotificationHealthCheckIssueCode.ADDRESS_DISPOSABLE, label: 'Disposable Address', icon: 'delete_forever' },
6443
+ { code: MailgunNotificationHealthCheckIssueCode.PROBE_NOT_CONFIGURED, label: 'Test Unavailable', icon: 'block' }
6444
+ ];
6445
+
6446
+ /**
6447
+ * Registry of presentation metadata for notification health check findings.
6448
+ *
6449
+ * Health check issue codes are open-ended, so this maps a code to a label and an icon. An
6450
+ * unregistered code is not an error — it falls back to a presentation derived from the issue's
6451
+ * status, and the issue's own `m`/`f` strings carry the meaning either way.
6452
+ *
6453
+ * Apps extend the table by supplying a {@link DbxFirebaseNotificationHealthCheckPresentationServiceConfig}
6454
+ * through `provideDbxFirebaseNotifications({ healthCheckPresentation })`.
6455
+ */
6456
+ class DbxFirebaseNotificationHealthCheckPresentationService {
6457
+ _config = inject(DbxFirebaseNotificationHealthCheckPresentationServiceConfig, { optional: true });
6458
+ _entries = new Map();
6459
+ constructor() {
6460
+ if (this._config?.registerDefaultEntries !== false) {
6461
+ this.register(DEFAULT_NOTIFICATION_HEALTH_CHECK_PRESENTATION_ENTRIES);
6462
+ }
6463
+ if (this._config?.entries) {
6464
+ this.register(this._config.entries);
6465
+ }
6466
+ }
6467
+ /**
6468
+ * Registers presentation entries, overriding any already registered for the same code by default.
6469
+ *
6470
+ * @param entries - The entries to register.
6471
+ * @param override - Whether to replace an existing entry for the same code. Defaults to true.
6472
+ */
6473
+ register(entries, override = true) {
6474
+ asArray(entries).forEach((entry) => {
6475
+ if (override || !this._entries.has(entry.code)) {
6476
+ this._entries.set(entry.code, entry);
6477
+ }
6478
+ });
6479
+ }
6480
+ /**
6481
+ * The entry registered for an issue code, if any.
6482
+ *
6483
+ * @param code - The issue code to look up.
6484
+ * @returns The registered entry, or undefined when the code has none.
6485
+ */
6486
+ entryForCode(code) {
6487
+ return this._entries.get(code);
6488
+ }
6489
+ /**
6490
+ * Resolves how to present a single finding.
6491
+ *
6492
+ * Pass the delivery method whose section the finding is rendered in to get a probe label that names
6493
+ * it — `Test Email Sent` rather than `Test Sent`. Every provider emits the same probe codes, so that
6494
+ * is the one label a registry entry cannot supply on its own.
6495
+ *
6496
+ * @param issue - The finding to present.
6497
+ * @param method - The delivery method the finding belongs to, when it belongs to one.
6498
+ * @returns The label, icon, and colour to render it with.
6499
+ */
6500
+ presentationForIssue(issue, method) {
6501
+ const entry = this._entries.get(issue.c);
6502
+ const probeLabel = method == null ? undefined : notificationHealthCheckProbeIssueLabel(issue.c, method);
6503
+ return {
6504
+ label: probeLabel ?? entry?.label ?? this.labelForStatus(issue.s),
6505
+ icon: entry?.icon ?? this.iconForStatus(issue.s),
6506
+ color: entry?.color ?? this.colorForStatus(issue.s)
6507
+ };
6508
+ }
6509
+ /**
6510
+ * @param status - The status to colour.
6511
+ * @returns The theme colour for the status.
6512
+ */
6513
+ colorForStatus(status) {
6514
+ return NOTIFICATION_HEALTH_CHECK_STATUS_COLORS[status] ?? NOTIFICATION_HEALTH_CHECK_STATUS_COLORS[NotificationHealthCheckStatus.UNKNOWN];
6515
+ }
6516
+ /**
6517
+ * @param status - The status to find an icon for.
6518
+ * @returns The icon for the status.
6519
+ */
6520
+ iconForStatus(status) {
6521
+ return NOTIFICATION_HEALTH_CHECK_STATUS_ICONS[status] ?? NOTIFICATION_HEALTH_CHECK_STATUS_ICONS[NotificationHealthCheckStatus.UNKNOWN];
6522
+ }
6523
+ /**
6524
+ * @param status - The status to label.
6525
+ * @returns The human-readable label for the status.
6526
+ */
6527
+ labelForStatus(status) {
6528
+ return NOTIFICATION_HEALTH_CHECK_STATUS_LABELS[status] ?? NOTIFICATION_HEALTH_CHECK_STATUS_LABELS[NotificationHealthCheckStatus.UNKNOWN];
6529
+ }
6530
+ /**
6531
+ * @param method - The delivery method to label.
6532
+ * @returns The human-readable label for the delivery method.
6533
+ */
6534
+ labelForDeliveryMethod(method) {
6535
+ return NOTIFICATION_DELIVERY_METHOD_LABELS[method] ?? 'Notification';
6536
+ }
6537
+ /**
6538
+ * @param method - The delivery method to find an icon for.
6539
+ * @returns The icon for the delivery method.
6540
+ */
6541
+ iconForDeliveryMethod(method) {
6542
+ return NOTIFICATION_DELIVERY_METHOD_ICONS[method] ?? 'notifications';
6543
+ }
6544
+ /**
6545
+ * @param method - The delivery method whose test message action is being labelled.
6546
+ * @returns The label for the method's "send a test message" action, naming what it sends.
6547
+ */
6548
+ testMessageLabelForDeliveryMethod(method) {
6549
+ return NOTIFICATION_DELIVERY_METHOD_TEST_MESSAGE_LABELS[method] ?? 'Send Test Message';
6550
+ }
6551
+ /**
6552
+ * @param method - The delivery method whose test message is being described.
6553
+ * @returns The lowercase noun for the method's test message, for use mid-sentence.
6554
+ */
6555
+ testMessageNounForDeliveryMethod(method) {
6556
+ return NOTIFICATION_DELIVERY_METHOD_TEST_MESSAGE_NOUNS[method] ?? 'test message';
6557
+ }
6558
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationHealthCheckPresentationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
6559
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationHealthCheckPresentationService, providedIn: 'root' });
6560
+ }
6561
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationHealthCheckPresentationService, decorators: [{
6562
+ type: Injectable,
6563
+ args: [{
6564
+ providedIn: 'root'
6565
+ }]
6566
+ }], ctorParameters: () => [] });
6567
+
6568
+ /**
6569
+ * Renders a single {@link NotificationHealthCheckIssue}: its status chip, what was found, and what to
6570
+ * do about it.
6571
+ *
6572
+ * The chip's label and icon come from the {@link DbxFirebaseNotificationHealthCheckPresentationService}
6573
+ * registry; the message and the suggested fix always come from the issue itself, so an issue code the
6574
+ * registry has never seen still renders correctly.
6575
+ *
6576
+ * The finding's structured detail (`d`) is deliberately not rendered — values like the sending domain
6577
+ * or the delivery method key are diagnostic rather than user-facing. They remain on the issue itself,
6578
+ * so an API/callModel consumer still receives them.
6579
+ */
6580
+ class DbxFirebaseNotificationHealthCheckIssueComponent {
6581
+ _presentationService = inject(DbxFirebaseNotificationHealthCheckPresentationService);
6582
+ issue = input(...(ngDevMode ? [undefined, { debugName: "issue" }] : /* istanbul ignore next */ []));
6583
+ /**
6584
+ * The delivery method this finding belongs to, when it belongs to one.
6585
+ *
6586
+ * Only used to label a probe finding with what was actually sent — `Test Email Sent` rather than the
6587
+ * method-agnostic `Test Sent` — since every provider emits the same probe codes. An account-wide
6588
+ * finding leaves it unset.
6589
+ */
6590
+ method = input(...(ngDevMode ? [undefined, { debugName: "method" }] : /* istanbul ignore next */ []));
6591
+ presentationSignal = computed(() => {
6592
+ const issue = this.issue();
6593
+ const method = this.method();
6594
+ return issue ? this._presentationService.presentationForIssue(issue, method) : { label: '', icon: '', color: 'grey' };
6595
+ }, ...(ngDevMode ? [{ debugName: "presentationSignal" }] : /* istanbul ignore next */ []));
6596
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationHealthCheckIssueComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6597
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: DbxFirebaseNotificationHealthCheckIssueComponent, isStandalone: true, selector: "dbx-firebase-notification-healthcheck-issue", inputs: { issue: { classPropertyName: "issue", publicName: "issue", isSignal: true, isRequired: false, transformFunction: null }, method: { classPropertyName: "method", publicName: "method", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "d-block dbx-firebase-notification-healthcheck-issue" }, ngImport: i0, template: `
6598
+ @if (issue(); as issueValue) {
6599
+ <div class="dbx-flex-bar dbx-pb1">
6600
+ <dbx-icon-tile class="dbx-icon-spacer" [icon]="presentationSignal().icon" [dbxColor]="presentationSignal().color" [dbxColorTone]="18"></dbx-icon-tile>
6601
+ <dbx-chip [small]="true" [color]="presentationSignal().color">{{ presentationSignal().label }}</dbx-chip>
6602
+ </div>
6603
+ <p class="no-margin">{{ issueValue.m }}</p>
6604
+ @if (issueValue.f) {
6605
+ <p class="dbx-hint no-margin dbx-pt1">{{ issueValue.f }}</p>
6606
+ }
6607
+ }
6608
+ `, isInline: true, dependencies: [{ kind: "directive", type: DbxChipDirective, selector: "dbx-chip", inputs: ["small", "block", "color", "display", "tone"] }, { kind: "directive", type: DbxColorDirective, selector: "[dbxColor]", inputs: ["dbxColor", "dbxColorTone"], outputs: ["dbxColorChange"] }, { kind: "component", type: DbxIconTileComponent, selector: "dbx-icon-tile", inputs: ["icon", "round"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6609
+ }
6610
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationHealthCheckIssueComponent, decorators: [{
6611
+ type: Component,
6612
+ args: [{
6613
+ selector: 'dbx-firebase-notification-healthcheck-issue',
6614
+ template: `
6615
+ @if (issue(); as issueValue) {
6616
+ <div class="dbx-flex-bar dbx-pb1">
6617
+ <dbx-icon-tile class="dbx-icon-spacer" [icon]="presentationSignal().icon" [dbxColor]="presentationSignal().color" [dbxColorTone]="18"></dbx-icon-tile>
6618
+ <dbx-chip [small]="true" [color]="presentationSignal().color">{{ presentationSignal().label }}</dbx-chip>
6619
+ </div>
6620
+ <p class="no-margin">{{ issueValue.m }}</p>
6621
+ @if (issueValue.f) {
6622
+ <p class="dbx-hint no-margin dbx-pt1">{{ issueValue.f }}</p>
6623
+ }
6624
+ }
6625
+ `,
6626
+ host: {
6627
+ class: 'd-block dbx-firebase-notification-healthcheck-issue'
6628
+ },
6629
+ standalone: true,
6630
+ imports: [DbxChipDirective, DbxColorDirective, DbxIconTileComponent],
6631
+ changeDetection: ChangeDetectionStrategy.OnPush
6632
+ }]
6633
+ }], propDecorators: { issue: [{ type: i0.Input, args: [{ isSignal: true, alias: "issue", required: false }] }], method: [{ type: i0.Input, args: [{ isSignal: true, alias: "method", required: false }] }] } });
6634
+
6635
+ /**
6636
+ * Renders one delivery method's health check result: where it would deliver to, everything the check
6637
+ * found for it, the state of any test message that was sent through it, and — when the method can be
6638
+ * probed and an action is supplied — the button for sending a new one.
6639
+ *
6640
+ * Presentational: it injects nothing beyond the presentation registry, so it can be dropped anywhere a
6641
+ * result is already in hand. The test message action is an input rather than something it resolves.
6642
+ */
6643
+ class DbxFirebaseNotificationHealthCheckMethodComponent {
6644
+ _presentationService = inject(DbxFirebaseNotificationHealthCheckPresentationService);
6645
+ result = input(...(ngDevMode ? [undefined, { debugName: "result" }] : /* istanbul ignore next */ []));
6646
+ /**
6647
+ * The test message action to offer for this method, when the owner of the check has one to offer.
6648
+ *
6649
+ * Ignored unless the result reports that the method can actually be probed.
6650
+ */
6651
+ probeAction = input(...(ngDevMode ? [undefined, { debugName: "probeAction" }] : /* istanbul ignore next */ []));
6652
+ methodLabelSignal = computed(() => {
6653
+ const method = this.result()?.me;
6654
+ return method ? this._presentationService.labelForDeliveryMethod(method) : '';
6655
+ }, ...(ngDevMode ? [{ debugName: "methodLabelSignal" }] : /* istanbul ignore next */ []));
6656
+ methodIconSignal = computed(() => {
6657
+ const method = this.result()?.me;
6658
+ return method ? this._presentationService.iconForDeliveryMethod(method) : 'notifications';
6659
+ }, ...(ngDevMode ? [{ debugName: "methodIconSignal" }] : /* istanbul ignore next */ []));
6660
+ statusColorSignal = computed(() => {
6661
+ const status = this.result()?.s;
6662
+ return status ? this._presentationService.colorForStatus(status) : 'grey';
6663
+ }, ...(ngDevMode ? [{ debugName: "statusColorSignal" }] : /* istanbul ignore next */ []));
6664
+ statusLabelSignal = computed(() => {
6665
+ const status = this.result()?.s;
6666
+ return status ? this._presentationService.labelForStatus(status) : '';
6667
+ }, ...(ngDevMode ? [{ debugName: "statusLabelSignal" }] : /* istanbul ignore next */ []));
6668
+ /**
6669
+ * Introduces the dispatched probe's timestamp, naming what was actually sent.
6670
+ *
6671
+ * Sentence-cased from the method's mid-sentence noun, since it opens the line.
6672
+ */
6673
+ testMessageSentLabelSignal = computed(() => {
6674
+ const method = this.result()?.me;
6675
+ const noun = method ? this._presentationService.testMessageNounForDeliveryMethod(method) : 'test message';
6676
+ return `${noun.charAt(0).toUpperCase()}${noun.slice(1)} sent`;
6677
+ }, ...(ngDevMode ? [{ debugName: "testMessageSentLabelSignal" }] : /* istanbul ignore next */ []));
6678
+ /**
6679
+ * The action to render, which requires the server to have reported this method as probe-capable.
6680
+ *
6681
+ * The result is the authority on that, so an action supplied for a method that cannot be probed is
6682
+ * dropped rather than offering the user a test message the server would refuse to send.
6683
+ */
6684
+ probeActionSignal = computed(() => {
6685
+ const probeSupported = this.result()?.pb === true;
6686
+ const probeAction = this.probeAction();
6687
+ return probeSupported ? probeAction : undefined;
6688
+ }, ...(ngDevMode ? [{ debugName: "probeActionSignal" }] : /* istanbul ignore next */ []));
6689
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationHealthCheckMethodComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6690
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: DbxFirebaseNotificationHealthCheckMethodComponent, isStandalone: true, selector: "dbx-firebase-notification-healthcheck-method", inputs: { result: { classPropertyName: "result", publicName: "result", isSignal: true, isRequired: false, transformFunction: null }, probeAction: { classPropertyName: "probeAction", publicName: "probeAction", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "d-block dbx-firebase-notification-healthcheck-method" }, ngImport: i0, template: `
6691
+ @if (result(); as resultValue) {
6692
+ <div class="dbx-flex-bar dbx-pb1">
6693
+ <dbx-icon-tile class="dbx-icon-spacer" [icon]="methodIconSignal()" [dbxColor]="statusColorSignal()" [dbxColorTone]="18"></dbx-icon-tile>
6694
+ <div class="dbx-flex-fill">
6695
+ <div class="dbx-text-title-medium">{{ methodLabelSignal() }}</div>
6696
+ @if (resultValue.tg) {
6697
+ <div class="dbx-text-body-small dbx-hint">{{ resultValue.tg }}</div>
6698
+ } @else {
6699
+ <div class="dbx-text-body-small dbx-hint">No destination</div>
6700
+ }
6701
+ </div>
6702
+ <dbx-chip [small]="true" [color]="statusColorSignal()">{{ statusLabelSignal() }}</dbx-chip>
6703
+ </div>
6704
+
6705
+ @for (issue of resultValue.is; track $index) {
6706
+ <div class="dbx-pt2">
6707
+ <dbx-firebase-notification-healthcheck-issue [issue]="issue" [method]="resultValue.me"></dbx-firebase-notification-healthcheck-issue>
6708
+ </div>
6709
+ }
6710
+
6711
+ @if (resultValue.pr; as probe) {
6712
+ <div class="dbx-pt2 dbx-text-body-small dbx-hint">
6713
+ {{ testMessageSentLabelSignal() }} {{ probe.at | date: 'medium' }}
6714
+ @if (probe.d) {
6715
+ · {{ probe.d }}
6716
+ }
6717
+ </div>
6718
+ }
6719
+
6720
+ @if (probeActionSignal(); as probeAction) {
6721
+ <div class="dbx-pt2">
6722
+ <!-- dbxActionDisabled rather than the button's own disabled input, since dbxActionButton drives that from the action's state -->
6723
+ <div dbxAction [dbxActionDisabled]="probeAction.disabled === true" [dbxActionHandler]="probeAction.handler" [dbxActionConfirm]="probeAction.confirm">
6724
+ <dbx-button dbxActionButton [stroked]="true" [text]="probeAction.label" [icon]="probeAction.icon"></dbx-button>
6725
+ <dbx-error dbxActionError></dbx-error>
6726
+ </div>
6727
+ </div>
6728
+ @if (probeAction.notice) {
6729
+ <div class="dbx-small dbx-hint dbx-pt2">{{ probeAction.notice }}</div>
6730
+ }
6731
+ }
6732
+ }
6733
+ `, isInline: true, dependencies: [{ kind: "directive", type: DbxActionButtonDirective, selector: "[dbxActionButton]", inputs: ["dbxActionButtonEcho"] }, { kind: "directive", type: DbxActionConfirmDirective, selector: "[dbxActionConfirm]", inputs: ["dbxActionConfirm", "dbxActionConfirmSkip"] }, { kind: "directive", type: DbxActionDirective, selector: "dbx-action,[dbxAction]", exportAs: ["action", "dbxAction"] }, { kind: "directive", type: DbxActionDisabledDirective, selector: "[dbxActionDisabled]", inputs: ["dbxActionDisabled"] }, { kind: "directive", type: DbxActionErrorDirective, selector: "[dbxActionError]" }, { kind: "directive", type: DbxActionHandlerDirective, selector: "[dbxActionHandler]", inputs: ["dbxActionHandler"] }, { kind: "component", type: DbxButtonComponent, selector: "dbx-button", inputs: ["bar", "type", "buttonStyle", "color", "spinnerColor", "customButtonColor", "customTextColor", "customSpinnerColor", "basic", "tonal", "raised", "stroked", "flat", "iconOnly", "fab", "customContent", "allowClickPropagation", "mode"] }, { kind: "directive", type: DbxChipDirective, selector: "dbx-chip", inputs: ["small", "block", "color", "display", "tone"] }, { kind: "directive", type: DbxColorDirective, selector: "[dbxColor]", inputs: ["dbxColor", "dbxColorTone"], outputs: ["dbxColorChange"] }, { kind: "component", type: DbxErrorComponent, selector: "dbx-error", inputs: ["error", "iconOnly"], outputs: ["popoverOpened"] }, { kind: "component", type: DbxIconTileComponent, selector: "dbx-icon-tile", inputs: ["icon", "round"] }, { kind: "component", type: DbxFirebaseNotificationHealthCheckIssueComponent, selector: "dbx-firebase-notification-healthcheck-issue", inputs: ["issue", "method"] }, { kind: "pipe", type: DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6734
+ }
6735
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationHealthCheckMethodComponent, decorators: [{
6736
+ type: Component,
6737
+ args: [{
6738
+ selector: 'dbx-firebase-notification-healthcheck-method',
6739
+ template: `
6740
+ @if (result(); as resultValue) {
6741
+ <div class="dbx-flex-bar dbx-pb1">
6742
+ <dbx-icon-tile class="dbx-icon-spacer" [icon]="methodIconSignal()" [dbxColor]="statusColorSignal()" [dbxColorTone]="18"></dbx-icon-tile>
6743
+ <div class="dbx-flex-fill">
6744
+ <div class="dbx-text-title-medium">{{ methodLabelSignal() }}</div>
6745
+ @if (resultValue.tg) {
6746
+ <div class="dbx-text-body-small dbx-hint">{{ resultValue.tg }}</div>
6747
+ } @else {
6748
+ <div class="dbx-text-body-small dbx-hint">No destination</div>
6749
+ }
6750
+ </div>
6751
+ <dbx-chip [small]="true" [color]="statusColorSignal()">{{ statusLabelSignal() }}</dbx-chip>
6752
+ </div>
6753
+
6754
+ @for (issue of resultValue.is; track $index) {
6755
+ <div class="dbx-pt2">
6756
+ <dbx-firebase-notification-healthcheck-issue [issue]="issue" [method]="resultValue.me"></dbx-firebase-notification-healthcheck-issue>
6757
+ </div>
6758
+ }
6759
+
6760
+ @if (resultValue.pr; as probe) {
6761
+ <div class="dbx-pt2 dbx-text-body-small dbx-hint">
6762
+ {{ testMessageSentLabelSignal() }} {{ probe.at | date: 'medium' }}
6763
+ @if (probe.d) {
6764
+ · {{ probe.d }}
6765
+ }
6766
+ </div>
6767
+ }
6768
+
6769
+ @if (probeActionSignal(); as probeAction) {
6770
+ <div class="dbx-pt2">
6771
+ <!-- dbxActionDisabled rather than the button's own disabled input, since dbxActionButton drives that from the action's state -->
6772
+ <div dbxAction [dbxActionDisabled]="probeAction.disabled === true" [dbxActionHandler]="probeAction.handler" [dbxActionConfirm]="probeAction.confirm">
6773
+ <dbx-button dbxActionButton [stroked]="true" [text]="probeAction.label" [icon]="probeAction.icon"></dbx-button>
6774
+ <dbx-error dbxActionError></dbx-error>
6775
+ </div>
6776
+ </div>
6777
+ @if (probeAction.notice) {
6778
+ <div class="dbx-small dbx-hint dbx-pt2">{{ probeAction.notice }}</div>
6779
+ }
6780
+ }
6781
+ }
6782
+ `,
6783
+ host: {
6784
+ class: 'd-block dbx-firebase-notification-healthcheck-method'
6785
+ },
6786
+ standalone: true,
6787
+ imports: [DatePipe, DbxActionButtonDirective, DbxActionConfirmDirective, DbxActionDirective, DbxActionDisabledDirective, DbxActionErrorDirective, DbxActionHandlerDirective, DbxButtonComponent, DbxChipDirective, DbxColorDirective, DbxErrorComponent, DbxIconTileComponent, DbxFirebaseNotificationHealthCheckIssueComponent],
6788
+ changeDetection: ChangeDetectionStrategy.OnPush
6789
+ }]
6790
+ }], propDecorators: { result: [{ type: i0.Input, args: [{ isSignal: true, alias: "result", required: false }] }], probeAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "probeAction", required: false }] }] } });
6791
+
6792
+ /**
6793
+ * Delivery methods this report never renders a section for, whatever the check says about them.
6794
+ *
6795
+ * The in-app summary channel is the app's own notification page, so the user is looking at the delivery
6796
+ * target while they read the report — there is nothing a section could tell them that the page does not
6797
+ * already show. The server has no health check service for it either, so it can currently only report
6798
+ * "Not Checked", which reads as a broken channel next to a working inbox.
6799
+ *
6800
+ * The server still checks and stores the method, so an API/callModel consumer keeps the result. Drop the
6801
+ * entry here to bring the section back if the server starts contributing findings worth acting on.
6802
+ */
6803
+ const HIDDEN_NOTIFICATION_DELIVERY_METHODS = new Set([NotificationDeliveryMethod.NOTIFICATION_SUMMARY]);
6804
+ /**
6805
+ * Renders a whole {@link NotificationHealthCheck}: the rolled-up status, then one section per delivery
6806
+ * method that this system can actually send through.
6807
+ *
6808
+ * This is the inlineable report — it takes the check as an input and injects nothing beyond the
6809
+ * presentation registry, so it can be dropped anywhere a check is already in hand (a settings page, a
6810
+ * dialog, an admin view). The per-method test message actions are an input for the same reason: the
6811
+ * report renders them, whoever owns the store supplies them.
6812
+ *
6813
+ * The view is client-facing, so it shows only what the user can act on. The check's account-wide
6814
+ * findings (`is`), any method the system has no send service for, and the methods in
6815
+ * {@link HIDDEN_NOTIFICATION_DELIVERY_METHODS} are left out here — all of them remain on the check
6816
+ * itself for an API/callModel consumer.
6817
+ */
6818
+ class DbxFirebaseNotificationHealthCheckComponent {
6819
+ _presentationService = inject(DbxFirebaseNotificationHealthCheckPresentationService);
6820
+ healthCheck = input(...(ngDevMode ? [undefined, { debugName: "healthCheck" }] : /* istanbul ignore next */ []));
6821
+ /**
6822
+ * The test message action to offer in each method's section, keyed by delivery method.
6823
+ *
6824
+ * Left unset the report is read-only, which is what an admin or historical view wants.
6825
+ */
6826
+ probeActions = input(...(ngDevMode ? [undefined, { debugName: "probeActions" }] : /* istanbul ignore next */ []));
6827
+ statusColorSignal = computed(() => {
6828
+ const status = this.healthCheck()?.s;
6829
+ return status ? this._presentationService.colorForStatus(status) : 'grey';
6830
+ }, ...(ngDevMode ? [{ debugName: "statusColorSignal" }] : /* istanbul ignore next */ []));
6831
+ statusIconSignal = computed(() => {
6832
+ const status = this.healthCheck()?.s;
6833
+ return status ? this._presentationService.iconForStatus(status) : 'help';
6834
+ }, ...(ngDevMode ? [{ debugName: "statusIconSignal" }] : /* istanbul ignore next */ []));
6835
+ statusLabelSignal = computed(() => {
6836
+ const status = this.healthCheck()?.s;
6837
+ return status ? this._presentationService.labelForStatus(status) : '';
6838
+ }, ...(ngDevMode ? [{ debugName: "statusLabelSignal" }] : /* istanbul ignore next */ []));
6839
+ /**
6840
+ * The method results worth showing the user.
6841
+ *
6842
+ * A method the server has no send service for is not something the user can do anything about, so it
6843
+ * is dropped rather than rendered as a "Not Checked" section, as is any method this report does not
6844
+ * render at all — see {@link HIDDEN_NOTIFICATION_DELIVERY_METHODS}.
6845
+ */
6846
+ methodResultsSignal = computed(() => (this.healthCheck()?.m ?? []).filter((result) => !HIDDEN_NOTIFICATION_DELIVERY_METHODS.has(result.me) && !result.is.some((issue) => issue.c === KnownNotificationHealthCheckIssueCode.SEND_SERVICE_NOT_CONFIGURED)), ...(ngDevMode ? [{ debugName: "methodResultsSignal" }] : /* istanbul ignore next */ []));
6847
+ /**
6848
+ * Each method section to render, paired with the test message action for its method.
6849
+ *
6850
+ * Paired up here rather than indexed in the template so the map lookup stays out of the view.
6851
+ */
6852
+ methodSectionsSignal = computed(() => {
6853
+ const probeActions = this.probeActions();
6854
+ return this.methodResultsSignal().map((result) => ({ result, probeAction: probeActions?.[result.me] }));
6855
+ }, ...(ngDevMode ? [{ debugName: "methodSectionsSignal" }] : /* istanbul ignore next */ []));
6856
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationHealthCheckComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6857
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: DbxFirebaseNotificationHealthCheckComponent, isStandalone: true, selector: "dbx-firebase-notification-healthcheck", inputs: { healthCheck: { classPropertyName: "healthCheck", publicName: "healthCheck", isSignal: true, isRequired: false, transformFunction: null }, probeActions: { classPropertyName: "probeActions", publicName: "probeActions", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "d-block dbx-firebase-notification-healthcheck" }, ngImport: i0, template: `
6858
+ @if (healthCheck(); as healthCheckValue) {
6859
+ <div class="dbx-flex-bar dbx-pb3">
6860
+ <dbx-icon-tile class="dbx-icon-spacer" [icon]="statusIconSignal()" [dbxColor]="statusColorSignal()" [dbxColorTone]="18"></dbx-icon-tile>
6861
+ <div class="dbx-flex-fill">
6862
+ <div class="dbx-text-label-medium dbx-uppercase dbx-tracked-wide dbx-hint">Notification Delivery</div>
6863
+ <div class="dbx-text-title-large">{{ statusLabelSignal() }}</div>
6864
+ <div class="dbx-text-body-small dbx-hint">Last checked {{ healthCheckValue.at | date: 'medium' }}</div>
6865
+ </div>
6866
+ </div>
6867
+
6868
+ @for (methodSection of methodSectionsSignal(); track methodSection.result.me) {
6869
+ <dbx-content-pit class="dbx-mb3">
6870
+ <dbx-firebase-notification-healthcheck-method [result]="methodSection.result" [probeAction]="methodSection.probeAction"></dbx-firebase-notification-healthcheck-method>
6871
+ </dbx-content-pit>
6872
+ }
6873
+ }
6874
+ `, isInline: true, dependencies: [{ kind: "directive", type: DbxColorDirective, selector: "[dbxColor]", inputs: ["dbxColor", "dbxColorTone"], outputs: ["dbxColorChange"] }, { kind: "directive", type: DbxContentPitDirective, selector: "dbx-content-pit, [dbxContentPit]", inputs: ["scrollable", "square"] }, { kind: "component", type: DbxIconTileComponent, selector: "dbx-icon-tile", inputs: ["icon", "round"] }, { kind: "component", type: DbxFirebaseNotificationHealthCheckMethodComponent, selector: "dbx-firebase-notification-healthcheck-method", inputs: ["result", "probeAction"] }, { kind: "pipe", type: DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6875
+ }
6876
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationHealthCheckComponent, decorators: [{
6877
+ type: Component,
6878
+ args: [{
6879
+ selector: 'dbx-firebase-notification-healthcheck',
6880
+ template: `
6881
+ @if (healthCheck(); as healthCheckValue) {
6882
+ <div class="dbx-flex-bar dbx-pb3">
6883
+ <dbx-icon-tile class="dbx-icon-spacer" [icon]="statusIconSignal()" [dbxColor]="statusColorSignal()" [dbxColorTone]="18"></dbx-icon-tile>
6884
+ <div class="dbx-flex-fill">
6885
+ <div class="dbx-text-label-medium dbx-uppercase dbx-tracked-wide dbx-hint">Notification Delivery</div>
6886
+ <div class="dbx-text-title-large">{{ statusLabelSignal() }}</div>
6887
+ <div class="dbx-text-body-small dbx-hint">Last checked {{ healthCheckValue.at | date: 'medium' }}</div>
6888
+ </div>
6889
+ </div>
6890
+
6891
+ @for (methodSection of methodSectionsSignal(); track methodSection.result.me) {
6892
+ <dbx-content-pit class="dbx-mb3">
6893
+ <dbx-firebase-notification-healthcheck-method [result]="methodSection.result" [probeAction]="methodSection.probeAction"></dbx-firebase-notification-healthcheck-method>
6894
+ </dbx-content-pit>
6895
+ }
6896
+ }
6897
+ `,
6898
+ host: {
6899
+ class: 'd-block dbx-firebase-notification-healthcheck'
6900
+ },
6901
+ standalone: true,
6902
+ imports: [DatePipe, DbxColorDirective, DbxContentPitDirective, DbxIconTileComponent, DbxFirebaseNotificationHealthCheckMethodComponent],
6903
+ changeDetection: ChangeDetectionStrategy.OnPush
6904
+ }]
6905
+ }], propDecorators: { healthCheck: [{ type: i0.Input, args: [{ isSignal: true, alias: "healthCheck", required: false }] }], probeActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "probeActions", required: false }] }] } });
6906
+
6185
6907
  /**
6186
6908
  * Client-side service used for retrieving notification templates.
6187
6909
  */
@@ -6460,6 +7182,529 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
6460
7182
  }]
6461
7183
  }] });
6462
7184
 
7185
+ /**
7186
+ * Document store for a single NotificationUser with update, resync, and health check functions.
7187
+ */
7188
+ class NotificationUserDocumentStore extends AbstractDbxFirebaseDocumentStore {
7189
+ notificationFunctions = inject(NotificationFunctions);
7190
+ constructor() {
7191
+ super({ firestoreCollection: inject(NotificationFirestoreCollections).notificationUserCollection });
7192
+ }
7193
+ updateNotificationUser = firebaseDocumentStoreUpdateFunction(this, this.notificationFunctions.notificationUser.updateNotificationUser.update);
7194
+ resyncNotificationUser = firebaseDocumentStoreUpdateFunction(this, this.notificationFunctions.notificationUser.updateNotificationUser.resync);
7195
+ /**
7196
+ * Runs a delivery health check for this NotificationUser.
7197
+ *
7198
+ * Dispatching a real test message is opt-in via the `sendProbe` param, since it delivers actual
7199
+ * mail/SMS to the user.
7200
+ *
7201
+ * The result is only returned by the call, so use the DbxFirebaseNotificationUserHealthCheckStore
7202
+ * to run a check whose outcome is retained as state.
7203
+ */
7204
+ healthCheck = firebaseDocumentStoreInvokeFunction(this, this.notificationFunctions.notificationUser.invokeNotificationUser.healthCheck);
7205
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: NotificationUserDocumentStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
7206
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: NotificationUserDocumentStore });
7207
+ }
7208
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: NotificationUserDocumentStore, decorators: [{
7209
+ type: Injectable
7210
+ }], ctorParameters: () => [] });
7211
+
7212
+ /**
7213
+ * Counts down the seconds until the input time, once per second.
7214
+ *
7215
+ * Emits 0 and stops ticking as soon as the time passes, so nothing keeps counting while the action it
7216
+ * gates is available. A null input means there is nothing to wait for.
7217
+ *
7218
+ * @param date$ - The time being waited for.
7219
+ * @returns The seconds remaining, counting down to 0.
7220
+ */
7221
+ function secondsRemainingUntil(date$) {
7222
+ return date$.pipe(switchMap((date) => date == null
7223
+ ? of(0)
7224
+ : timer(0, 1000).pipe(map(() => Math.max(0, Math.ceil((date.getTime() - Date.now()) / 1000))), takeWhile((secondsRemaining) => secondsRemaining > 0, true))), distinctUntilChanged(), shareReplay(1));
7225
+ }
7226
+ /**
7227
+ * Counts down the seconds until each delivery method's time, once per second.
7228
+ *
7229
+ * The per-method form of {@link secondsRemainingUntil}. One timer drives every method, so several open
7230
+ * countdowns tick in step rather than drifting apart, and the ticking stops once every window has
7231
+ * passed. A method with nothing to wait for is left out.
7232
+ *
7233
+ * @param datesByMethod$ - The time being waited for on each method.
7234
+ * @returns The seconds remaining per method, counting down to 0.
7235
+ */
7236
+ function secondsRemainingUntilByMethod(datesByMethod$) {
7237
+ return datesByMethod$.pipe(switchMap((datesByMethod) => {
7238
+ const pendingEntries = Object.entries(datesByMethod).filter(([, date]) => date != null);
7239
+ return pendingEntries.length === 0
7240
+ ? of({})
7241
+ : timer(0, 1000).pipe(map(() => {
7242
+ const secondsRemainingByMethod = {};
7243
+ pendingEntries.forEach(([method, date]) => {
7244
+ secondsRemainingByMethod[method] = Math.max(0, Math.ceil((date.getTime() - Date.now()) / 1000));
7245
+ });
7246
+ return secondsRemainingByMethod;
7247
+ }),
7248
+ // emit the all-zero value, then stop: every window has passed
7249
+ takeWhile((secondsRemainingByMethod) => Object.values(secondsRemainingByMethod).some((x) => x > 0), true));
7250
+ }), distinctUntilChanged(areEqualPOJOValues), shareReplay(1));
7251
+ }
7252
+ /**
7253
+ * Store for running a notification delivery health check against the NotificationUser of the
7254
+ * injected {@link NotificationUserDocumentStore}, and for retaining the result of that run.
7255
+ *
7256
+ * Exists separately from the document store because a run returns more than what is persisted:
7257
+ * `probesDispatched`/`probesResolved` are only available on the invocation result, and are only
7258
+ * relevant to the session that ran the check.
7259
+ */
7260
+ class DbxFirebaseNotificationUserHealthCheckStore extends ComponentStore {
7261
+ notificationUserDocumentStore = inject(NotificationUserDocumentStore);
7262
+ /**
7263
+ * The app's health check tuning, when it configured any.
7264
+ *
7265
+ * Optional: without it both windows fall back to the library defaults, which is correct for an app
7266
+ * that did not override them on the server either.
7267
+ */
7268
+ _config = inject(DbxFirebaseNotificationHealthCheckConfig, { optional: true });
7269
+ constructor() {
7270
+ super({});
7271
+ }
7272
+ // MARK: Accessors
7273
+ /**
7274
+ * Whether the NotificationUser being checked exists.
7275
+ *
7276
+ * There is nothing to check until notifications have been set up for the account.
7277
+ */
7278
+ exists$ = this.notificationUserDocumentStore.currentExists$;
7279
+ /**
7280
+ * The health check stored on the document.
7281
+ *
7282
+ * The check is persisted on every run, so the most recent one renders without invoking anything.
7283
+ */
7284
+ healthCheck$ = this.notificationUserDocumentStore.data$.pipe(map((x) => x.hc), distinctUntilChanged(), shareReplay(1));
7285
+ /**
7286
+ * The loading state of the most recent {@link runHealthCheck} dispatch.
7287
+ *
7288
+ * A dispatch sets this to a loading state synchronously, so a caller that dispatches and then
7289
+ * watches this observable is watching its own run.
7290
+ */
7291
+ healthCheckResultState$ = this.select((state) => state.healthCheckResultState).pipe(distinctUntilChanged(), shareReplay(1));
7292
+ /**
7293
+ * The full result of the most recent {@link runHealthCheck} run from this store.
7294
+ *
7295
+ * `probesDispatched`/`probesResolved` are not part of the document, so they are only available here
7296
+ * and only until the store is destroyed.
7297
+ */
7298
+ latestHealthCheckResult$ = this.healthCheckResultState$.pipe(map((x) => x?.value), distinctUntilChanged(), shareReplay(1));
7299
+ // MARK: Throttle
7300
+ /**
7301
+ * The earliest time another run is allowed, derived from the check stored on the document.
7302
+ *
7303
+ * Undefined until a check has been run.
7304
+ */
7305
+ nextRunAt$ = this.healthCheck$.pipe(map((healthCheck) => notificationUserHealthCheckNextRunAt({ healthCheck, throttleMinutes: this._config?.runThrottleMinutes })), distinctUntilChanged((a, b) => a?.getTime() === b?.getTime()), shareReplay(1));
7306
+ /**
7307
+ * The earliest time another test message may be dispatched through each delivery method.
7308
+ *
7309
+ * Per method, because the server's probe window is per method: each method has its own test message
7310
+ * action, and a test email must not hold the test text message off. Tracked separately from
7311
+ * {@link nextRunAt$} as well — running the check does not consume the test message allowance, so a
7312
+ * plain run must not disable any of the probe actions.
7313
+ */
7314
+ nextProbeAtByMethod$ = this.healthCheck$.pipe(map((healthCheck) => notificationUserHealthCheckNextProbeAtByMethod({ healthCheck, throttleMinutes: this._config?.probeThrottleMinutes })), distinctUntilChanged(areEqualPOJOValues), shareReplay(1));
7315
+ /**
7316
+ * How long until another run is allowed, counting down once per second.
7317
+ */
7318
+ throttleSecondsRemaining$ = secondsRemainingUntil(this.nextRunAt$);
7319
+ /**
7320
+ * How long until another test message may be dispatched through each delivery method, counting down
7321
+ * once per second.
7322
+ *
7323
+ * A method whose window has never opened — no probe has been dispatched through it — is absent, which
7324
+ * a consumer reads the same as 0.
7325
+ */
7326
+ probeThrottleSecondsRemainingByMethod$ = secondsRemainingUntilByMethod(this.nextProbeAtByMethod$);
7327
+ /**
7328
+ * Whether the server would reject a run right now.
7329
+ *
7330
+ * The server enforces the throttle; this is what lets the view disable the action instead of letting
7331
+ * the user trigger a call that comes back as an error.
7332
+ */
7333
+ isThrottled$ = this.throttleSecondsRemaining$.pipe(map((secondsRemaining) => secondsRemaining > 0), distinctUntilChanged(), shareReplay(1));
7334
+ // MARK: Pending Probes
7335
+ /**
7336
+ * The delivery methods whose test message is still waiting on an outcome.
7337
+ *
7338
+ * The one part of a stored check that changes without anyone re-running it, so it is what
7339
+ * {@link watchPendingProbes} watches.
7340
+ */
7341
+ pendingProbeMethods$ = this.healthCheck$.pipe(map((healthCheck) => notificationHealthCheckPendingProbeMethods(healthCheck)), distinctUntilChanged(areEqualPOJOValues), shareReplay(1));
7342
+ /**
7343
+ * Whether a test message is in flight right now.
7344
+ */
7345
+ hasPendingProbe$ = this.pendingProbeMethods$.pipe(map((x) => x.length > 0), distinctUntilChanged(), shareReplay(1));
7346
+ /**
7347
+ * The next verification to run, or null when there is nothing to watch.
7348
+ *
7349
+ * Re-derived from the document on every change, which is what paces the loop: each verification
7350
+ * advances the stored check's `vat`, so the moment the server will accept another poll moves forward
7351
+ * and this emits the next one. The watch gives up once the oldest probe has been in flight longer than
7352
+ * the configured window — a provider that is never going to record an outcome should not be polled for
7353
+ * as long as the page stays open.
7354
+ */
7355
+ _nextProbeVerification$ = this.healthCheck$.pipe(map((healthCheck) => {
7356
+ const methods = notificationHealthCheckPendingProbeMethods(healthCheck);
7357
+ const dispatchedAt = filterMaybeArrayValues((healthCheck?.m ?? []).filter((x) => methods.includes(x.me)).map((x) => x.pr?.at));
7358
+ const watchMinutes = this._config?.probeWatchMinutes ?? DEFAULT_NOTIFICATION_HEALTH_CHECK_PROBE_WATCH_MINUTES;
7359
+ const oldestDispatchedAt = dispatchedAt.length ? new Date(Math.min(...dispatchedAt.map((x) => x.getTime()))) : undefined;
7360
+ const at = notificationUserHealthCheckNextVerifyAt({ healthCheck, throttleSeconds: this._config?.verifyThrottleSeconds }) ?? new Date();
7361
+ const stillWorthWatching = oldestDispatchedAt != null && isAfter(addMinutes(oldestDispatchedAt, watchMinutes), at);
7362
+ return stillWorthWatching ? { methods, at } : undefined;
7363
+ }), distinctUntilChanged(areEqualPOJOValues), shareReplay(1));
7364
+ // MARK: State Changes
7365
+ _setHealthCheckResultState = this.updater((state, healthCheckResultState) => ({ ...state, healthCheckResultState }));
7366
+ // MARK: Effects
7367
+ /**
7368
+ * Runs the document store's health check for its NotificationUser and puts the outcome on
7369
+ * {@link healthCheckResultState$}.
7370
+ *
7371
+ * Dispatching a real test message is opt-in via the `sendProbe` param, since it delivers actual
7372
+ * mail/SMS to the user.
7373
+ *
7374
+ * While a run is in flight further dispatches are ignored, so the state always reflects the run
7375
+ * that is actually happening.
7376
+ */
7377
+ runHealthCheck = this.effect((input) => input.pipe(exhaustMap((params) => this.notificationUserDocumentStore.healthCheck(params ?? {}).pipe(startWithBeginLoading(), // emit loading synchronously so a dispatcher can pick this run up off the state
7378
+ catchError((error) => of(errorResult(error))), // an error here would otherwise kill this effect's subscription
7379
+ tap((healthCheckResultState) => this._setHealthCheckResultState(healthCheckResultState))))));
7380
+ /**
7381
+ * Watches every in-flight test message until it has an outcome, without the user doing anything.
7382
+ *
7383
+ * A dispatched probe settles on the delivery provider's schedule rather than the caller's, so
7384
+ * something has to ask again once the outcome exists. That used to be the user, told to come back and
7385
+ * re-run the check; this is that same poll, run automatically. Each verification is scoped to the
7386
+ * methods actually awaiting an outcome and answers to its own server-side window, so it neither sends
7387
+ * anything nor consumes the user's allowance for running the check itself. The result lands on the
7388
+ * NotificationUser, which is already streamed into {@link healthCheck$}, so a settled probe simply
7389
+ * appears in the report.
7390
+ *
7391
+ * Idempotent to start and safe to leave running: it does nothing at all while no probe is in flight,
7392
+ * and stops on its own once every probe has settled or aged out.
7393
+ */
7394
+ watchPendingProbes = this.effect((input) => input.pipe(switchMap(() => this._nextProbeVerification$.pipe(
7395
+ // The interval is the recovery path: a verification that advances `vat` re-emits the value
7396
+ // above and restarts this timer, while one that fails to reach the server leaves the value
7397
+ // unchanged and is simply retried on the next tick.
7398
+ switchMap((verification) => (verification == null ? EMPTY : timer(Math.max(0, verification.at.getTime() - Date.now()), (this._config?.verifyThrottleSeconds ?? DEFAULT_NOTIFICATION_USER_HEALTH_CHECK_VERIFY_THROTTLE_SECONDS) * MS_IN_SECOND).pipe(map(() => verification.methods)))), withLatestFrom(this.healthCheckResultState$),
7399
+ // A verification carries the whole stored check forward, so one racing a run the user started
7400
+ // could write back a copy taken before that run's result landed. The user's run always wins.
7401
+ filter(([, healthCheckResultState]) => healthCheckResultState?.loading !== true), exhaustMap(([methods]) => this.notificationUserDocumentStore.healthCheck({ verifyPendingProbesOnly: true, methods }).pipe(catchError(() => EMPTY) // nothing to report: the poll is invisible, and the next tick retries
7402
+ ))))));
7403
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationUserHealthCheckStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
7404
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationUserHealthCheckStore });
7405
+ }
7406
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationUserHealthCheckStore, decorators: [{
7407
+ type: Injectable
7408
+ }], ctorParameters: () => [] });
7409
+
7410
+ /**
7411
+ * Formats a throttle countdown for display.
7412
+ *
7413
+ * @param secondsRemaining - Seconds left in the window.
7414
+ * @returns A short duration, e.g. `9m 12s` or `43s`.
7415
+ */
7416
+ function formatSecondsRemaining(secondsRemaining) {
7417
+ const minutes = Math.floor(secondsRemaining / 60);
7418
+ const minutesPrefix = minutes > 0 ? `${minutes}m ` : '';
7419
+ return `${minutesPrefix}${secondsRemaining % 60}s`;
7420
+ }
7421
+ /**
7422
+ * Renders the notification delivery health check for the ancestor NotificationUserDocumentStore, and
7423
+ * the actions for re-running it.
7424
+ *
7425
+ * The check is persisted on the NotificationUser, so the last one renders immediately without invoking
7426
+ * anything. "Run Check" re-runs it and stays a single global action, since a run only reads
7427
+ * configuration and provider state. Sending a test message is per delivery method instead — it
7428
+ * dispatches a real message through that one method, and answers to that method's own throttle window —
7429
+ * so its action lives in that method's section rather than in a footer.
7430
+ *
7431
+ * A dispatched test message settles later, on the delivery provider's schedule. This view watches for
7432
+ * that outcome itself rather than telling the user to come back and re-run the check: the store polls a
7433
+ * cheap server-side verification while anything is in flight, and the report — read live from the
7434
+ * document — updates the moment the result lands.
7435
+ */
7436
+ class DbxFirebaseNotificationHealthCheckViewComponent {
7437
+ _presentationService = inject(DbxFirebaseNotificationHealthCheckPresentationService);
7438
+ healthCheckStore = inject(DbxFirebaseNotificationUserHealthCheckStore);
7439
+ existsSignal = toSignal(this.healthCheckStore.exists$, { initialValue: false });
7440
+ healthCheckSignal = toSignal(this.healthCheckStore.healthCheck$);
7441
+ latestHealthCheckResultSignal = toSignal(this.healthCheckStore.latestHealthCheckResult$);
7442
+ throttleSecondsRemainingSignal = toSignal(this.healthCheckStore.throttleSecondsRemaining$, { initialValue: 0 });
7443
+ isThrottledSignal = toSignal(this.healthCheckStore.isThrottled$, { initialValue: false });
7444
+ probeThrottleSecondsRemainingByMethodSignal = toSignal(this.healthCheckStore.probeThrottleSecondsRemainingByMethod$, { initialValue: {} });
7445
+ _lastRequestedProbeMethod = signal(undefined, ...(ngDevMode ? [{ debugName: "_lastRequestedProbeMethod" }] : /* istanbul ignore next */ []));
7446
+ constructor() {
7447
+ // The report is streamed from the document, so an outcome the server settles shows up on its own.
7448
+ // This is what makes the server settle it without the user asking.
7449
+ this.healthCheckStore.watchPendingProbes();
7450
+ }
7451
+ /**
7452
+ * The delivery method whose test message was most recently requested from this view.
7453
+ *
7454
+ * Recorded because the invocation result reports only how many probes it dispatched, so this is what
7455
+ * lets the notice name what was sent.
7456
+ */
7457
+ lastRequestedProbeMethodSignal = this._lastRequestedProbeMethod.asReadonly();
7458
+ /**
7459
+ * The test message handler for each delivery method, built once up front.
7460
+ *
7461
+ * A per-method countdown rebuilds that method's action config every second, and `dbxActionHandler`
7462
+ * installs its handler in an effect, so handing over a fresh closure on each tick would re-install it
7463
+ * once a second for no reason.
7464
+ */
7465
+ _sendTestMessageHandlers = new Map(ALL_NOTIFICATION_DELIVERY_METHODS.map((method) => [
7466
+ method,
7467
+ (_, context) => {
7468
+ this._lastRequestedProbeMethod.set(method);
7469
+ this.runHealthCheckAsWork(context, { sendProbe: true, methods: [method] });
7470
+ }
7471
+ ]));
7472
+ /**
7473
+ * Explains why "Run Check" is disabled while the server's run throttle is in effect.
7474
+ */
7475
+ throttleNoticeSignal = computed(() => {
7476
+ const secondsRemaining = this.throttleSecondsRemainingSignal();
7477
+ return secondsRemaining > 0 ? `This was checked a moment ago. Another check can be run in ${formatSecondsRemaining(secondsRemaining)}.` : undefined;
7478
+ }, ...(ngDevMode ? [{ debugName: "throttleNoticeSignal" }] : /* istanbul ignore next */ []));
7479
+ /**
7480
+ * The test message action for each delivery method the check reports as probe-capable.
7481
+ *
7482
+ * A method that cannot be probed gets no entry, so no test message is offered where the server has no
7483
+ * way to send one.
7484
+ *
7485
+ * Everything the user needs to read about a test message belongs in the section holding the button
7486
+ * that sent it, so the notice is composed here rather than in a footer: what was just sent, that its
7487
+ * outcome is being watched for, and when another may be sent.
7488
+ */
7489
+ probeActionsSignal = computed(() => {
7490
+ const secondsRemainingByMethod = this.probeThrottleSecondsRemainingByMethodSignal();
7491
+ const justSentMethod = this.latestHealthCheckResultSignal()?.probesDispatched ? this.lastRequestedProbeMethodSignal() : undefined;
7492
+ const probeActions = {};
7493
+ (this.healthCheckSignal()?.m ?? [])
7494
+ .filter((methodResult) => methodResult.pb === true)
7495
+ .forEach(({ me: method, tg: target, pr: probe }) => {
7496
+ const label = this._presentationService.testMessageLabelForDeliveryMethod(method);
7497
+ const noun = this._presentationService.testMessageNounForDeliveryMethod(method);
7498
+ const methodLabel = this._presentationService.labelForDeliveryMethod(method).toLowerCase();
7499
+ const secondsRemaining = secondsRemainingByMethod[method] ?? 0;
7500
+ probeActions[method] = {
7501
+ label,
7502
+ icon: 'send',
7503
+ disabled: secondsRemaining > 0,
7504
+ notice: this.probeNoticeForMethod({ noun, secondsRemaining, justSent: method === justSentMethod, pending: probe?.s === NotificationHealthCheckStatus.PENDING }),
7505
+ confirm: {
7506
+ title: label,
7507
+ prompt: `This sends a real ${methodLabel} to ${target ?? 'your contact details'} so we can confirm whether it arrives. Continue?`,
7508
+ confirmText: label
7509
+ },
7510
+ handler: this._sendTestMessageHandlers.get(method)
7511
+ };
7512
+ });
7513
+ return probeActions;
7514
+ }, ...(ngDevMode ? [{ debugName: "probeActionsSignal" }] : /* istanbul ignore next */ []));
7515
+ /**
7516
+ * Composes one delivery method's test message notice.
7517
+ *
7518
+ * Deliberately never tells the user to come back and check: a pending outcome is watched for
7519
+ * automatically, so the only thing left to say about the wait is that they need do nothing.
7520
+ *
7521
+ * @param input - What the method sends, how long its window has left, and the state of its probe.
7522
+ * @returns The notice, or undefined when there is nothing worth saying.
7523
+ */
7524
+ probeNoticeForMethod(input) {
7525
+ const { noun, secondsRemaining, justSent, pending } = input;
7526
+ const sent = justSent ? `A ${noun} was just sent.` : secondsRemaining > 0 ? `A ${noun} was sent recently.` : undefined;
7527
+ const waiting = pending ? ' The result will appear here on its own as soon as we hear whether it arrived.' : '';
7528
+ const nextAllowed = secondsRemaining > 0 ? ` Another can be sent in ${formatSecondsRemaining(secondsRemaining)}.` : '';
7529
+ return sent == null ? undefined : `${sent}${waiting}${nextAllowed}`;
7530
+ }
7531
+ handleRunHealthCheck = (_, context) => {
7532
+ this.runHealthCheckAsWork(context, {});
7533
+ };
7534
+ /**
7535
+ * Dispatches a run to the store, then tracks that run's loading state as the action's work.
7536
+ *
7537
+ * The store's effect sets the loading state synchronously as it is dispatched, so handing the state
7538
+ * observable over afterwards tracks this run instead of completing on the previous run's result.
7539
+ *
7540
+ * @param context - The work instance of the action being handled.
7541
+ * @param params - The params for this run, such as which methods to send a test message through.
7542
+ */
7543
+ runHealthCheckAsWork(context, params) {
7544
+ this.healthCheckStore.runHealthCheck(params);
7545
+ context.startWorkingWithLoadingStateObservable(this.healthCheckStore.healthCheckResultState$);
7546
+ }
7547
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationHealthCheckViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7548
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: DbxFirebaseNotificationHealthCheckViewComponent, isStandalone: true, selector: "dbx-firebase-notification-healthcheck-view", host: { classAttribute: "d-block dbx-firebase-notification-healthcheck-view" }, providers: [DbxFirebaseNotificationUserHealthCheckStore], ngImport: i0, template: `
7549
+ @if (existsSignal()) {
7550
+ @if (healthCheckSignal(); as healthCheck) {
7551
+ <dbx-firebase-notification-healthcheck [healthCheck]="healthCheck" [probeActions]="probeActionsSignal()"></dbx-firebase-notification-healthcheck>
7552
+ } @else {
7553
+ <dbx-content-pit class="dbx-mb3">
7554
+ <p class="dbx-hint no-margin">Your notification delivery has not been checked yet. Run a check to find out why you may not be receiving notifications.</p>
7555
+ </dbx-content-pit>
7556
+ }
7557
+
7558
+ <div class="dbx-flex-bar">
7559
+ <!-- the action takes no input, so the bare dbxActionValue marks it value-ready on trigger -->
7560
+ <!-- dbxActionDisabled rather than the button's own disabled input, since dbxActionButton drives that from the action's state -->
7561
+ <div dbxAction dbxActionValue [dbxActionDisabled]="isThrottledSignal()" [dbxActionHandler]="handleRunHealthCheck">
7562
+ <dbx-button dbxActionButton [stroked]="true" text="Run Check" icon="refresh"></dbx-button>
7563
+ <dbx-error dbxActionError></dbx-error>
7564
+ </div>
7565
+ </div>
7566
+ <div>
7567
+ @if (throttleNoticeSignal(); as throttleNotice) {
7568
+ <div class="dbx-small dbx-hint dbx-pt2">{{ throttleNotice }}</div>
7569
+ }
7570
+ </div>
7571
+ } @else {
7572
+ <dbx-content-pit>
7573
+ <p class="dbx-hint no-margin">Notification settings have not been set up for this account yet, so there is nothing to check.</p>
7574
+ </dbx-content-pit>
7575
+ }
7576
+ `, isInline: true, dependencies: [{ kind: "directive", type: DbxActionButtonDirective, selector: "[dbxActionButton]", inputs: ["dbxActionButtonEcho"] }, { kind: "directive", type: DbxActionDirective, selector: "dbx-action,[dbxAction]", exportAs: ["action", "dbxAction"] }, { kind: "directive", type: DbxActionDisabledDirective, selector: "[dbxActionDisabled]", inputs: ["dbxActionDisabled"] }, { kind: "directive", type: DbxActionErrorDirective, selector: "[dbxActionError]" }, { kind: "directive", type: DbxActionHandlerDirective, selector: "[dbxActionHandler]", inputs: ["dbxActionHandler"] }, { kind: "directive", type: DbxActionValueDirective, selector: "dbxActionValue,[dbxActionValue]", inputs: ["dbxActionValue"] }, { kind: "component", type: DbxButtonComponent, selector: "dbx-button", inputs: ["bar", "type", "buttonStyle", "color", "spinnerColor", "customButtonColor", "customTextColor", "customSpinnerColor", "basic", "tonal", "raised", "stroked", "flat", "iconOnly", "fab", "customContent", "allowClickPropagation", "mode"] }, { kind: "directive", type: DbxContentPitDirective, selector: "dbx-content-pit, [dbxContentPit]", inputs: ["scrollable", "square"] }, { kind: "component", type: DbxErrorComponent, selector: "dbx-error", inputs: ["error", "iconOnly"], outputs: ["popoverOpened"] }, { kind: "component", type: DbxFirebaseNotificationHealthCheckComponent, selector: "dbx-firebase-notification-healthcheck", inputs: ["healthCheck", "probeActions"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7577
+ }
7578
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationHealthCheckViewComponent, decorators: [{
7579
+ type: Component,
7580
+ args: [{
7581
+ selector: 'dbx-firebase-notification-healthcheck-view',
7582
+ template: `
7583
+ @if (existsSignal()) {
7584
+ @if (healthCheckSignal(); as healthCheck) {
7585
+ <dbx-firebase-notification-healthcheck [healthCheck]="healthCheck" [probeActions]="probeActionsSignal()"></dbx-firebase-notification-healthcheck>
7586
+ } @else {
7587
+ <dbx-content-pit class="dbx-mb3">
7588
+ <p class="dbx-hint no-margin">Your notification delivery has not been checked yet. Run a check to find out why you may not be receiving notifications.</p>
7589
+ </dbx-content-pit>
7590
+ }
7591
+
7592
+ <div class="dbx-flex-bar">
7593
+ <!-- the action takes no input, so the bare dbxActionValue marks it value-ready on trigger -->
7594
+ <!-- dbxActionDisabled rather than the button's own disabled input, since dbxActionButton drives that from the action's state -->
7595
+ <div dbxAction dbxActionValue [dbxActionDisabled]="isThrottledSignal()" [dbxActionHandler]="handleRunHealthCheck">
7596
+ <dbx-button dbxActionButton [stroked]="true" text="Run Check" icon="refresh"></dbx-button>
7597
+ <dbx-error dbxActionError></dbx-error>
7598
+ </div>
7599
+ </div>
7600
+ <div>
7601
+ @if (throttleNoticeSignal(); as throttleNotice) {
7602
+ <div class="dbx-small dbx-hint dbx-pt2">{{ throttleNotice }}</div>
7603
+ }
7604
+ </div>
7605
+ } @else {
7606
+ <dbx-content-pit>
7607
+ <p class="dbx-hint no-margin">Notification settings have not been set up for this account yet, so there is nothing to check.</p>
7608
+ </dbx-content-pit>
7609
+ }
7610
+ `,
7611
+ host: {
7612
+ class: 'd-block dbx-firebase-notification-healthcheck-view'
7613
+ },
7614
+ standalone: true,
7615
+ imports: [DbxActionButtonDirective, DbxActionDirective, DbxActionDisabledDirective, DbxActionErrorDirective, DbxActionHandlerDirective, DbxActionValueDirective, DbxButtonComponent, DbxContentPitDirective, DbxErrorComponent, DbxFirebaseNotificationHealthCheckComponent],
7616
+ providers: [DbxFirebaseNotificationUserHealthCheckStore],
7617
+ changeDetection: ChangeDetectionStrategy.OnPush
7618
+ }]
7619
+ }], ctorParameters: () => [] });
7620
+
7621
+ /**
7622
+ * Dialog wrapper around {@link DbxFirebaseNotificationHealthCheckViewComponent}.
7623
+ */
7624
+ class DbxFirebaseNotificationHealthCheckDialogComponent extends AbstractDialogDirective {
7625
+ /**
7626
+ * Opens the notification delivery health check in a dialog.
7627
+ *
7628
+ * @param matDialog - The dialog service.
7629
+ * @param config - The injector to resolve the NotificationUserDocumentStore from.
7630
+ * @returns The dialog reference.
7631
+ */
7632
+ static openDialog(matDialog, config) {
7633
+ return matDialog.open(DbxFirebaseNotificationHealthCheckDialogComponent, {
7634
+ // a report with several delivery methods can exceed the viewport. Material inherits the pane's
7635
+ // max-height down to the dialog surface, which already scrolls, so capping it here keeps the
7636
+ // actions reachable. A percentage cap would not work, as the pane's height is not definite.
7637
+ maxHeight: 'calc(var(--vh100) * 0.9)',
7638
+ injector: config?.injector
7639
+ });
7640
+ }
7641
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationHealthCheckDialogComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
7642
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseNotificationHealthCheckDialogComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: `
7643
+ <dbx-dialog-content>
7644
+ <dbx-firebase-notification-healthcheck-view></dbx-firebase-notification-healthcheck-view>
7645
+ </dbx-dialog-content>
7646
+ `, isInline: true, dependencies: [{ kind: "directive", type: DbxDialogContentDirective, selector: "dbx-dialog-content,[dbxDialogContent],.dbx-dialog-content", inputs: ["width"] }, { kind: "component", type: DbxFirebaseNotificationHealthCheckViewComponent, selector: "dbx-firebase-notification-healthcheck-view" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7647
+ }
7648
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationHealthCheckDialogComponent, decorators: [{
7649
+ type: Component,
7650
+ args: [{
7651
+ template: `
7652
+ <dbx-dialog-content>
7653
+ <dbx-firebase-notification-healthcheck-view></dbx-firebase-notification-healthcheck-view>
7654
+ </dbx-dialog-content>
7655
+ `,
7656
+ standalone: true,
7657
+ imports: [DbxDialogContentDirective, DbxFirebaseNotificationHealthCheckViewComponent],
7658
+ changeDetection: ChangeDetectionStrategy.OnPush
7659
+ }]
7660
+ }] });
7661
+
7662
+ /**
7663
+ * Button that opens the notification delivery health check in a dialog.
7664
+ *
7665
+ * Place it inside a `dbxFirebaseNotificationUserDocument` so the dialog's view component can resolve
7666
+ * that directive's NotificationUserDocumentStore.
7667
+ */
7668
+ class DbxFirebaseNotificationHealthCheckDialogButtonComponent {
7669
+ _matDialog = inject(MatDialog);
7670
+ _injector = inject(Injector);
7671
+ config = input(...(ngDevMode ? [undefined, { debugName: "config" }] : /* istanbul ignore next */ []));
7672
+ text = input(...(ngDevMode ? [undefined, { debugName: "text" }] : /* istanbul ignore next */ []));
7673
+ icon = input(...(ngDevMode ? [undefined, { debugName: "icon" }] : /* istanbul ignore next */ []));
7674
+ textSignal = computed(() => {
7675
+ const config = this.config();
7676
+ return this.text() ?? config?.text ?? 'Check Notification Delivery';
7677
+ }, ...(ngDevMode ? [{ debugName: "textSignal" }] : /* istanbul ignore next */ []));
7678
+ iconSignal = computed(() => {
7679
+ const config = this.config();
7680
+ return this.icon() ?? config?.icon ?? 'monitor_heart';
7681
+ }, ...(ngDevMode ? [{ debugName: "iconSignal" }] : /* istanbul ignore next */ []));
7682
+ openHealthCheckDialog() {
7683
+ // the dialog renders outside this component's view, so its injector has to be handed over for the
7684
+ // NotificationUserDocumentStore to resolve inside it
7685
+ DbxFirebaseNotificationHealthCheckDialogComponent.openDialog(this._matDialog, { injector: this._injector });
7686
+ }
7687
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationHealthCheckDialogButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7688
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.11", type: DbxFirebaseNotificationHealthCheckDialogButtonComponent, isStandalone: true, selector: "dbx-firebase-notification-healthcheck-dialog-button", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "dbx-firebase-notification-healthcheck-dialog-button" }, ngImport: i0, template: `
7689
+ <dbx-button [stroked]="true" [text]="textSignal()" [icon]="iconSignal()" (buttonClick)="openHealthCheckDialog()"></dbx-button>
7690
+ `, isInline: true, dependencies: [{ kind: "component", type: DbxButtonComponent, selector: "dbx-button", inputs: ["bar", "type", "buttonStyle", "color", "spinnerColor", "customButtonColor", "customTextColor", "customSpinnerColor", "basic", "tonal", "raised", "stroked", "flat", "iconOnly", "fab", "customContent", "allowClickPropagation", "mode"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7691
+ }
7692
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseNotificationHealthCheckDialogButtonComponent, decorators: [{
7693
+ type: Component,
7694
+ args: [{
7695
+ selector: 'dbx-firebase-notification-healthcheck-dialog-button',
7696
+ template: `
7697
+ <dbx-button [stroked]="true" [text]="textSignal()" [icon]="iconSignal()" (buttonClick)="openHealthCheckDialog()"></dbx-button>
7698
+ `,
7699
+ host: {
7700
+ class: 'dbx-firebase-notification-healthcheck-dialog-button'
7701
+ },
7702
+ standalone: true,
7703
+ imports: [DbxButtonComponent],
7704
+ changeDetection: ChangeDetectionStrategy.OnPush
7705
+ }]
7706
+ }], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }] } });
7707
+
6463
7708
  const DEFAULT_DBX_FIREBASE_NOTIFICATION_ITEM_STORE_POPOVER_KEY = 'notification-item-store-notifications';
6464
7709
  class DbxFirebaseNotificationItemStorePopoverComponent extends AbstractPopoverDirective {
6465
7710
  static openPopover(popupService, { origin, header, icon, emptyText, makeNotificationItemAnchor, notificationItemsLoadingState$ }, popoverKey) {
@@ -6825,23 +8070,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
6825
8070
  }]
6826
8071
  }], ctorParameters: () => [] });
6827
8072
 
6828
- /**
6829
- * Document store for a single NotificationUser with update and resync functions.
6830
- */
6831
- class NotificationUserDocumentStore extends AbstractDbxFirebaseDocumentStore {
6832
- notificationFunctions = inject(NotificationFunctions);
6833
- constructor() {
6834
- super({ firestoreCollection: inject(NotificationFirestoreCollections).notificationUserCollection });
6835
- }
6836
- updateNotificationUser = firebaseDocumentStoreUpdateFunction(this, this.notificationFunctions.notificationUser.updateNotificationUser.update);
6837
- resyncNotificationUser = firebaseDocumentStoreUpdateFunction(this, this.notificationFunctions.notificationUser.updateNotificationUser.resync);
6838
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: NotificationUserDocumentStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
6839
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: NotificationUserDocumentStore });
6840
- }
6841
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: NotificationUserDocumentStore, decorators: [{
6842
- type: Injectable
6843
- }], ctorParameters: () => [] });
6844
-
6845
8073
  /**
6846
8074
  * Directive providing a {@link NotificationUserDocumentStore} for accessing a single notification user document.
6847
8075
  */
@@ -6868,7 +8096,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
6868
8096
  * @returns EnvironmentProviders.
6869
8097
  */
6870
8098
  function provideDbxFirebaseNotifications(config) {
6871
- const { appNotificationTemplateTypeInfoRecordService } = config;
8099
+ const { appNotificationTemplateTypeInfoRecordService, healthCheckPresentation, healthCheck } = config;
6872
8100
  const providers = [
6873
8101
  {
6874
8102
  provide: AppNotificationTemplateTypeInfoRecordService,
@@ -6894,6 +8122,18 @@ function provideDbxFirebaseNotifications(config) {
6894
8122
  }
6895
8123
  })
6896
8124
  ];
8125
+ if (healthCheckPresentation) {
8126
+ providers.push({
8127
+ provide: DbxFirebaseNotificationHealthCheckPresentationServiceConfig,
8128
+ useValue: healthCheckPresentation
8129
+ });
8130
+ }
8131
+ if (healthCheck) {
8132
+ providers.push({
8133
+ provide: DbxFirebaseNotificationHealthCheckConfig,
8134
+ useValue: healthCheck
8135
+ });
8136
+ }
6897
8137
  return makeEnvironmentProviders(providers);
6898
8138
  }
6899
8139
 
@@ -7252,7 +8492,7 @@ class DbxFirebaseStorageFileDownloadButtonComponent {
7252
8492
  if (downloadUrl || downloadUrl === null) {
7253
8493
  this.downloadUrlSignal.set(downloadUrl);
7254
8494
  }
7255
- }, { ...(ngDevMode ? { debugName: "storageFileDownloadUrlEffect" } : /* istanbul ignore next */ {}), allowSignalWrites: true });
8495
+ }, ...(ngDevMode ? [{ debugName: "storageFileDownloadUrlEffect" }] : /* istanbul ignore next */ []));
7256
8496
  // Preview
7257
8497
  showPreviewButtonSignal = computed(() => {
7258
8498
  const config = this.configSignal();
@@ -7286,7 +8526,7 @@ class DbxFirebaseStorageFileDownloadButtonComponent {
7286
8526
  this.downloadMimeTypeSignal.set(cachedPair.mimeType);
7287
8527
  this.downloadUrlExpiresAtSignal.set(cachedPair.expiresAt);
7288
8528
  }
7289
- }, { ...(ngDevMode ? { debugName: "cachedUrlEffect" } : /* istanbul ignore next */ {}), allowSignalWrites: true });
8529
+ }, ...(ngDevMode ? [{ debugName: "cachedUrlEffect" }] : /* istanbul ignore next */ []));
7290
8530
  // Expiration Effect
7291
8531
  downloadUrlExpiresAtDate$ = toObservable(this.downloadUrlExpiresAtSignal).pipe(map(dateFromDateOrTimeSecondsNumber), distinctUntilChanged(isSameDate), shareReplay(1));
7292
8532
  downloadUrlExpiresAtDateSignal = toSignal(this.downloadUrlExpiresAtDate$);
@@ -7308,7 +8548,7 @@ class DbxFirebaseStorageFileDownloadButtonComponent {
7308
8548
  this.downloadMimeTypeSignal.set(undefined);
7309
8549
  this.downloadUrlExpiresAtSignal.set(undefined);
7310
8550
  }
7311
- }, { ...(ngDevMode ? { debugName: "downloadUrlHasExpiredEffect" } : /* istanbul ignore next */ {}), allowSignalWrites: true });
8551
+ }, ...(ngDevMode ? [{ debugName: "downloadUrlHasExpiredEffect" }] : /* istanbul ignore next */ []));
7312
8552
  // Output Effect
7313
8553
  downloadDetailsSignal = computed(() => {
7314
8554
  const downloadUrl = this.downloadUrlSignal();
@@ -7333,7 +8573,7 @@ class DbxFirebaseStorageFileDownloadButtonComponent {
7333
8573
  if (source?.downloadDetailsChangeCallback) {
7334
8574
  source.downloadDetailsChangeCallback(details);
7335
8575
  }
7336
- }, { ...(ngDevMode ? { debugName: "sourceDownloadDetailsChangeCallbackEffect" } : /* istanbul ignore next */ {}), allowSignalWrites: true });
8576
+ }, ...(ngDevMode ? [{ debugName: "sourceDownloadDetailsChangeCallbackEffect" }] : /* istanbul ignore next */ []));
7337
8577
  // Handlers
7338
8578
  handleGetDownloadUrl = (value, context) => {
7339
8579
  const source = this.source();
@@ -8495,5 +9735,5 @@ function provideDbxFirebase(config) {
8495
9735
  * Generated bundle index. Do not edit.
8496
9736
  */
8497
9737
 
8498
- export { AbstractConfiguredDbxFirebaseLoginButtonDirective, AbstractDbxFirebaseCollectionStore, AbstractDbxFirebaseCollectionWithParentStore, AbstractDbxFirebaseDocumentStore, AbstractDbxFirebaseDocumentWithParentStore, AbstractDbxFirebaseModelEntityWidgetDirective, AbstractDbxFirebaseNotificationItemWidgetComponent, AbstractRootSingleItemDbxFirebaseDocument, AbstractSingleItemDbxFirebaseDocument, AbstractSystemStateDocumentStoreAccessor, DBX_CONFIGURED_DBX_FIREBASE_LOGIN_BUTTON_COMPONENT_CONFIGURATION, DBX_FIREBASE_APP_OPTIONS_TOKEN, DBX_FIREBASE_AUTH_FLOW_TOKEN, DBX_FIREBASE_DOCUMENT_STORE_CONTEXT_STORE_TOKEN, DBX_FIREBASE_MODEL_DOES_NOT_EXIST_ERROR, DBX_FIREBASE_MODEL_ENTITY_WITH_STORE_TOKEN, DBX_FIREBASE_STORAGEFILE_DOWNLOAD_STORAGE_ACCESSOR_TOKEN, DBX_FIREBASE_STORAGE_CONTEXT_CONFIG_TOKEN, DBX_FIREBASE_STORAGE_CONTEXT_TOKEN, DBX_FIREBASE_STORAGE_PDF_MERGE_UPLOAD_FILE_NAME, DBX_FIRESTORE_CONTEXT_TOKEN, DEFAULT_CONFIGURED_DBX_FIREBASE_LOGIN_BUTTON_TEMPLATE, DEFAULT_DBX_FIREBASE_ANALYTICS_USER_PROPERTIES_FACTORY, DEFAULT_DBX_FIREBASE_AUTH_FLOW, DEFAULT_DBX_FIREBASE_AUTH_SERVICE_DELEGATE, DEFAULT_DBX_FIREBASE_ID_ROUTER_PARAM_ID_PARAM_KEY, DEFAULT_DBX_FIREBASE_ID_ROUTER_PARAM_KEY_PARAM_KEY, DEFAULT_DBX_FIREBASE_ID_ROUTER_PARAM_USE_PARAM_VALUE, DEFAULT_DBX_FIREBASE_MODEL_ENTITIES_COMPONENT_POPOVER_KEY, DEFAULT_DBX_FIREBASE_MODEL_HISTORY_COMPONENT_POPOVER_KEY, DEFAULT_DBX_FIREBASE_NOTIFICATION_ITEM_STORE_POPOVER_KEY, DEFAULT_FIREBASE_AUTH_LOGIN_PASSWORD_CONFIG, DEFAULT_FIREBASE_AUTH_LOGIN_PASSWORD_CONFIG_TOKEN, DEFAULT_FIREBASE_AUTH_LOGIN_PROVIDERS_TOKEN, DEFAULT_FIREBASE_AUTH_LOGIN_TERMS_COMPONENT_CLASS_TOKEN, DEFAULT_FIREBASE_COLLECTION_CHANGE_TRIGGER_FUNCTION, DEFAULT_FIREBASE_DEVELOPMENT_ENABLED_TOKEN, DEFAULT_FIREBASE_DEVELOPMENT_POPUP_KEY, DEFAULT_FIREBASE_DEVELOPMENT_SCHEDULER_ENABLED_TOKEN, DEFAULT_FIREBASE_DEVELOPMENT_WIDGET_PROVIDERS_TOKEN, DEFAULT_FIREBASE_LOGIN_METHOD_CATEGORY, DEFAULT_FIREBASE_NOTIFICATION_ITEM_WIDGET_TYPE, DEVELOPMENT_FIREBASE_SERVER_SCHEDULER_WIDGET_KEY, DbxFirebaseAnalyticsUserEventsListenerService, DbxFirebaseAnalyticsUserSource, DbxFirebaseAppCheckHttpInterceptor, DbxFirebaseAuthImpersonationDelegate, DbxFirebaseAuthLoginService, DbxFirebaseAuthService, DbxFirebaseAuthServiceDelegate, DbxFirebaseCollectionChangeDirective, DbxFirebaseCollectionChangeTriggerInstance, DbxFirebaseCollectionHasChangeDirective, DbxFirebaseCollectionListDirective, DbxFirebaseCollectionLoaderInstance, DbxFirebaseCollectionStoreDirective, DbxFirebaseCollectionWithParentStoreDirective, DbxFirebaseDevelopmentDirective, DbxFirebaseDevelopmentModule, DbxFirebaseDevelopmentPopupComponent, DbxFirebaseDevelopmentPopupContentComponent, DbxFirebaseDevelopmentPopupContentForgeFormComponent, DbxFirebaseDevelopmentSchedulerListComponent, DbxFirebaseDevelopmentSchedulerListViewComponent, DbxFirebaseDevelopmentSchedulerListViewItemComponent, DbxFirebaseDevelopmentSchedulerService, DbxFirebaseDevelopmentSchedulerWidgetComponent, DbxFirebaseDevelopmentService, DbxFirebaseDevelopmentWidgetService, DbxFirebaseDocumentLoaderInstance, DbxFirebaseDocumentStoreContextModelEntitiesSourceDirective, DbxFirebaseDocumentStoreContextStore, DbxFirebaseDocumentStoreContextStoreDirective, DbxFirebaseDocumentStoreDirective, DbxFirebaseDocumentStoreIdFromTwoWayModelKeyDirective, DbxFirebaseDocumentStoreTwoWayKeyProvider, DbxFirebaseDocumentStoreTwoWayModelKeySourceDirective, DbxFirebaseEmailForgeFormComponent, DbxFirebaseEmailRecoveryForgeFormComponent, DbxFirebaseEmulatorService, DbxFirebaseLoginAnonymousComponent, DbxFirebaseLoginAppleComponent, DbxFirebaseLoginButtonComponent, DbxFirebaseLoginButtonContainerComponent, DbxFirebaseLoginComponent, DbxFirebaseLoginContext, DbxFirebaseLoginContextBackButtonComponent, DbxFirebaseLoginContextDirective, DbxFirebaseLoginEmailComponent, DbxFirebaseLoginEmailContentComponent, DbxFirebaseLoginFacebookComponent, DbxFirebaseLoginGitHubComponent, DbxFirebaseLoginGoogleComponent, DbxFirebaseLoginListComponent, DbxFirebaseLoginMicrosoftComponent, DbxFirebaseLoginTermsComponent, DbxFirebaseLoginTermsSimpleComponent, DbxFirebaseLoginTwitterComponent, DbxFirebaseManageAuthProvidersComponent, DbxFirebaseModelContextService, DbxFirebaseModelEntitiesComponent, DbxFirebaseModelEntitiesDebugWidgetComponent, DbxFirebaseModelEntitiesPopoverButtonComponent, DbxFirebaseModelEntitiesPopoverComponent, DbxFirebaseModelEntitiesSource, DbxFirebaseModelEntitiesWidgetService, DbxFirebaseModelEntitiesWidgetServiceConfig, DbxFirebaseModelHistoryComponent, DbxFirebaseModelHistoryPopoverButtonComponent, DbxFirebaseModelHistoryPopoverComponent, DbxFirebaseModelKeyComponent, DbxFirebaseModelModule, DbxFirebaseModelStoreModule, DbxFirebaseModelTrackerService, DbxFirebaseModelTypeInstanceListComponent, DbxFirebaseModelTypeInstanceListViewComponent, DbxFirebaseModelTypeInstanceListViewItemComponent, DbxFirebaseModelTypesService, DbxFirebaseModelTypesServiceConfig, DbxFirebaseModelViewedEventDirective, DbxFirebaseModule, DbxFirebaseNotificationBoxCollectionStoreDirective, DbxFirebaseNotificationBoxDocumentStoreDirective, DbxFirebaseNotificationCollectionStoreDirective, DbxFirebaseNotificationDocumentStoreDirective, DbxFirebaseNotificationItemContentComponent, DbxFirebaseNotificationItemDefaultViewComponent, DbxFirebaseNotificationItemListComponent, DbxFirebaseNotificationItemListViewComponent, DbxFirebaseNotificationItemListViewItemComponent, DbxFirebaseNotificationItemStore, DbxFirebaseNotificationItemStorePopoverButtonComponent, DbxFirebaseNotificationItemStorePopoverComponent, DbxFirebaseNotificationItemViewComponent, DbxFirebaseNotificationItemWidgetService, DbxFirebaseNotificationSummaryCollectionStoreDirective, DbxFirebaseNotificationSummaryDocumentStoreDirective, DbxFirebaseNotificationTemplateService, DbxFirebaseNotificationUserCollectionStoreDirective, DbxFirebaseNotificationUserDocumentStoreDirective, DbxFirebaseParsedEmulatorsConfig, DbxFirebasePasswordResetComponent, DbxFirebasePasswordResetFormComponent, DbxFirebaseRegisterComponent, DbxFirebaseRegisterEmailComponent, DbxFirebaseStorageFileCollectionStoreDirective, DbxFirebaseStorageFileDocumentStoreDirective, DbxFirebaseStorageFileDownloadButtonComponent, DbxFirebaseStorageFileDownloadService, DbxFirebaseStorageFileDownloadStorage, DbxFirebaseStorageFileGroupDocumentStoreDirective, DbxFirebaseStorageFileUploadActionHandlerDirective, DbxFirebaseStorageFileUploadInitializeDocumentDirective, DbxFirebaseStorageFileUploadModule, DbxFirebaseStorageFileUploadStore, DbxFirebaseStorageFileUploadStoreDirective, DbxFirebaseStorageFileUploadSyncDirective, DbxFirebaseStoragePdfMergeUploadSyncDirective, DbxFirebaseStorageService, DbxFirebaseSystemStateCollectionStoreDirective, DbxFirebaseSystemStateDocumentStoreDirective, DbxFirestoreContextService, DbxLimitedFirebaseDocumentLoaderInstance, FIREBASE_APP_CHECK_TOKEN, FIREBASE_APP_TOKEN, FIREBASE_AUTH_TOKEN, FIREBASE_FIRESTORE_TOKEN, FIREBASE_FUNCTIONS_TOKEN, FIREBASE_NOTIFICATION_ITEM_WIDGET_TYPE_PREFIX, FIREBASE_PROVIDER_ID_TO_LOGIN_METHOD_TYPE_MAP, FIREBASE_STORAGE_TOKEN, FlatFirestoreModelKeyPipe, IMPORTS_AND_EXPORTS, LOGIN_METHOD_TYPE_TO_FIREBASE_PROVIDER_ID_MAP, NotificationBoxCollectionStore, NotificationBoxDocumentStore, NotificationCollectionStore, NotificationDocumentStore, NotificationSummaryCollectionStore, NotificationSummaryDocumentStore, NotificationUserCollectionStore, NotificationUserDocumentStore, OAUTH_FIREBASE_LOGIN_METHOD_CATEGORY, StorageFileCollectionStore, StorageFileDocumentStore, StorageFileGroupDocumentStore, StorageFileUploadFilesError, SystemStateCollectionStore, SystemStateDocumentStore, TwoWayFlatFirestoreModelKeyPipe, authRolesObsWithClaimsService, authUserInfoFromAuthUser, authUserStateFromFirebaseAuthServiceFunction, createDbxFirebaseAppCheck, createDbxFirebaseAuth, createDbxFirebaseFirestore, createDbxFirebaseFunctions, createDbxFirebaseStorage, dbxFirebaseAuthContextInfo, dbxFirebaseCollectionChangeTrigger, dbxFirebaseCollectionChangeTriggerForStore, dbxFirebaseCollectionChangeTriggerForWatcher, dbxFirebaseCollectionChangeWatcher, dbxFirebaseCollectionLoaderInstance, dbxFirebaseCollectionLoaderInstanceWithCollection, dbxFirebaseDocumentLoaderInstance, dbxFirebaseDocumentLoaderInstanceWithAccessor, dbxFirebaseDocumentStoreContextModelEntitiesSourceFactory, dbxFirebaseIdRouteParamRedirect, dbxFirebaseInContextFirebaseModelServiceInstance, dbxFirebaseInContextFirebaseModelServiceInstanceFactory, dbxFirebaseKeyRouteParamRedirect, dbxFirebaseModelContextServiceInfoInstanceFactory, dbxFirebaseModelEntityWidgetInjectionConfigFactory, dbxFirebaseModelTypesServiceInstance, dbxFirebaseModelTypesServiceInstancePairForKeysFactory, dbxFirebaseSourceSelectLoadSource, dbxFirebaseStorageFileDownloadServiceCustomSourceFromObs, dbxFirebaseStorageFileImageCompressionFileModifier, dbxFirebaseStorageProvidersContextConfigFactory, dbxLimitedFirebaseDocumentLoaderInstance, dbxLimitedFirebaseDocumentLoaderInstanceWithAccessor, dbxWidgetTypeForNotificationTemplateType, defaultDbxFirebaseAuthServiceDelegateWithClaimsService, defaultDbxFirebaseStorageFileDownloadStorageAccessorFactory, developmentFirebaseServerSchedulerWidgetEntry, enableAppCheckDebugTokenGeneration, firebaseAuthState, firebaseAuthTokenFromUser, firebaseCollectionStoreCreateFunction, firebaseCollectionStoreCrudFunction, firebaseContextServiceEntityMap, firebaseDocumentStoreCreateFunction, firebaseDocumentStoreCrudFunction, firebaseDocumentStoreDeleteFunction, firebaseDocumentStoreInvokeFunction, firebaseDocumentStoreReadFunction, firebaseDocumentStoreUpdateFunction, firebaseIdToken, firebaseProviderIdToLoginMethodType, isDbxFirebaseModelEntityWithStore, isStandaloneWebApp, linkDocumentStoreToParentContextStores, loginMethodTypeToFirebaseProviderId, modelDoesNotExistError, parseDbxFirebaseEmulatorsConfig, provideDbxFirebase, provideDbxFirebaseAnalyticsUserEventsListenerService, provideDbxFirebaseApp, provideDbxFirebaseAuth, provideDbxFirebaseAuthImpersonation, provideDbxFirebaseCollectionStoreDirective, provideDbxFirebaseCollectionWithParentStoreDirective, provideDbxFirebaseDevelopment, provideDbxFirebaseDocumentStoreContextStore, provideDbxFirebaseDocumentStoreDirective, provideDbxFirebaseDocumentStoreTwoWayKeyProvider, provideDbxFirebaseFunctions, provideDbxFirebaseLogin, provideDbxFirebaseModelContextService, provideDbxFirebaseModelEntitiesWidgetService, provideDbxFirebaseNotifications, provideDbxFirebaseStorageFileService, provideDbxFirestoreCollection, provideNotificationFirestoreCollections, provideStorageFileFirestoreCollections, provideSystemStateFirestoreCollections, providedDbxFirebaseStorage, readDbxAnalyticsUserPropertiesFromAuthUserInfo, readValueFromIdToken, resolveDbxFirebaseAuthFlow, setParentStoreEffect, stateFromTokenForLoggedInUserFunction, storageFileUploadFiles, storageFileUploadHandler };
9738
+ export { AbstractConfiguredDbxFirebaseLoginButtonDirective, AbstractDbxFirebaseCollectionStore, AbstractDbxFirebaseCollectionWithParentStore, AbstractDbxFirebaseDocumentStore, AbstractDbxFirebaseDocumentWithParentStore, AbstractDbxFirebaseModelEntityWidgetDirective, AbstractDbxFirebaseNotificationItemWidgetComponent, AbstractRootSingleItemDbxFirebaseDocument, AbstractSingleItemDbxFirebaseDocument, AbstractSystemStateDocumentStoreAccessor, DBX_CONFIGURED_DBX_FIREBASE_LOGIN_BUTTON_COMPONENT_CONFIGURATION, DBX_FIREBASE_APP_OPTIONS_TOKEN, DBX_FIREBASE_AUTH_FLOW_TOKEN, DBX_FIREBASE_DOCUMENT_STORE_CONTEXT_STORE_TOKEN, DBX_FIREBASE_MODEL_DOES_NOT_EXIST_ERROR, DBX_FIREBASE_MODEL_ENTITY_WITH_STORE_TOKEN, DBX_FIREBASE_STORAGEFILE_DOWNLOAD_STORAGE_ACCESSOR_TOKEN, DBX_FIREBASE_STORAGE_CONTEXT_CONFIG_TOKEN, DBX_FIREBASE_STORAGE_CONTEXT_TOKEN, DBX_FIREBASE_STORAGE_PDF_MERGE_UPLOAD_FILE_NAME, DBX_FIRESTORE_CONTEXT_TOKEN, DEFAULT_CONFIGURED_DBX_FIREBASE_LOGIN_BUTTON_TEMPLATE, DEFAULT_DBX_FIREBASE_ANALYTICS_USER_PROPERTIES_FACTORY, DEFAULT_DBX_FIREBASE_AUTH_FLOW, DEFAULT_DBX_FIREBASE_AUTH_SERVICE_DELEGATE, DEFAULT_DBX_FIREBASE_ID_ROUTER_PARAM_ID_PARAM_KEY, DEFAULT_DBX_FIREBASE_ID_ROUTER_PARAM_KEY_PARAM_KEY, DEFAULT_DBX_FIREBASE_ID_ROUTER_PARAM_USE_PARAM_VALUE, DEFAULT_DBX_FIREBASE_MODEL_ENTITIES_COMPONENT_POPOVER_KEY, DEFAULT_DBX_FIREBASE_MODEL_HISTORY_COMPONENT_POPOVER_KEY, DEFAULT_DBX_FIREBASE_NOTIFICATION_ITEM_STORE_POPOVER_KEY, DEFAULT_FIREBASE_AUTH_LOGIN_PASSWORD_CONFIG, DEFAULT_FIREBASE_AUTH_LOGIN_PASSWORD_CONFIG_TOKEN, DEFAULT_FIREBASE_AUTH_LOGIN_PROVIDERS_TOKEN, DEFAULT_FIREBASE_AUTH_LOGIN_TERMS_COMPONENT_CLASS_TOKEN, DEFAULT_FIREBASE_COLLECTION_CHANGE_TRIGGER_FUNCTION, DEFAULT_FIREBASE_DEVELOPMENT_ENABLED_TOKEN, DEFAULT_FIREBASE_DEVELOPMENT_POPUP_KEY, DEFAULT_FIREBASE_DEVELOPMENT_SCHEDULER_ENABLED_TOKEN, DEFAULT_FIREBASE_DEVELOPMENT_WIDGET_PROVIDERS_TOKEN, DEFAULT_FIREBASE_LOGIN_METHOD_CATEGORY, DEFAULT_FIREBASE_NOTIFICATION_ITEM_WIDGET_TYPE, DEFAULT_NOTIFICATION_HEALTH_CHECK_PRESENTATION_ENTRIES, DEFAULT_NOTIFICATION_HEALTH_CHECK_PROBE_WATCH_MINUTES, DEVELOPMENT_FIREBASE_SERVER_SCHEDULER_WIDGET_KEY, DbxFirebaseAnalyticsUserEventsListenerService, DbxFirebaseAnalyticsUserSource, DbxFirebaseAppCheckHttpInterceptor, DbxFirebaseAuthImpersonationDelegate, DbxFirebaseAuthLoginService, DbxFirebaseAuthService, DbxFirebaseAuthServiceDelegate, DbxFirebaseCollectionChangeDirective, DbxFirebaseCollectionChangeTriggerInstance, DbxFirebaseCollectionHasChangeDirective, DbxFirebaseCollectionListDirective, DbxFirebaseCollectionLoaderInstance, DbxFirebaseCollectionStoreDirective, DbxFirebaseCollectionWithParentStoreDirective, DbxFirebaseDevelopmentDirective, DbxFirebaseDevelopmentModule, DbxFirebaseDevelopmentPopupComponent, DbxFirebaseDevelopmentPopupContentComponent, DbxFirebaseDevelopmentPopupContentForgeFormComponent, DbxFirebaseDevelopmentSchedulerListComponent, DbxFirebaseDevelopmentSchedulerListViewComponent, DbxFirebaseDevelopmentSchedulerListViewItemComponent, DbxFirebaseDevelopmentSchedulerService, DbxFirebaseDevelopmentSchedulerWidgetComponent, DbxFirebaseDevelopmentService, DbxFirebaseDevelopmentWidgetService, DbxFirebaseDocumentLoaderInstance, DbxFirebaseDocumentStoreContextModelEntitiesSourceDirective, DbxFirebaseDocumentStoreContextStore, DbxFirebaseDocumentStoreContextStoreDirective, DbxFirebaseDocumentStoreDirective, DbxFirebaseDocumentStoreIdFromTwoWayModelKeyDirective, DbxFirebaseDocumentStoreTwoWayKeyProvider, DbxFirebaseDocumentStoreTwoWayModelKeySourceDirective, DbxFirebaseEmailForgeFormComponent, DbxFirebaseEmailRecoveryForgeFormComponent, DbxFirebaseEmulatorService, DbxFirebaseLoginAnonymousComponent, DbxFirebaseLoginAppleComponent, DbxFirebaseLoginButtonComponent, DbxFirebaseLoginButtonContainerComponent, DbxFirebaseLoginComponent, DbxFirebaseLoginContext, DbxFirebaseLoginContextBackButtonComponent, DbxFirebaseLoginContextDirective, DbxFirebaseLoginEmailComponent, DbxFirebaseLoginEmailContentComponent, DbxFirebaseLoginFacebookComponent, DbxFirebaseLoginGitHubComponent, DbxFirebaseLoginGoogleComponent, DbxFirebaseLoginListComponent, DbxFirebaseLoginMicrosoftComponent, DbxFirebaseLoginTermsComponent, DbxFirebaseLoginTermsSimpleComponent, DbxFirebaseLoginTwitterComponent, DbxFirebaseManageAuthProvidersComponent, DbxFirebaseModelContextService, DbxFirebaseModelEntitiesComponent, DbxFirebaseModelEntitiesDebugWidgetComponent, DbxFirebaseModelEntitiesPopoverButtonComponent, DbxFirebaseModelEntitiesPopoverComponent, DbxFirebaseModelEntitiesSource, DbxFirebaseModelEntitiesWidgetService, DbxFirebaseModelEntitiesWidgetServiceConfig, DbxFirebaseModelHistoryComponent, DbxFirebaseModelHistoryPopoverButtonComponent, DbxFirebaseModelHistoryPopoverComponent, DbxFirebaseModelKeyComponent, DbxFirebaseModelModule, DbxFirebaseModelStoreModule, DbxFirebaseModelTrackerService, DbxFirebaseModelTypeInstanceListComponent, DbxFirebaseModelTypeInstanceListViewComponent, DbxFirebaseModelTypeInstanceListViewItemComponent, DbxFirebaseModelTypesService, DbxFirebaseModelTypesServiceConfig, DbxFirebaseModelViewedEventDirective, DbxFirebaseModule, DbxFirebaseNotificationBoxCollectionStoreDirective, DbxFirebaseNotificationBoxDocumentStoreDirective, DbxFirebaseNotificationCollectionStoreDirective, DbxFirebaseNotificationDocumentStoreDirective, DbxFirebaseNotificationHealthCheckComponent, DbxFirebaseNotificationHealthCheckConfig, DbxFirebaseNotificationHealthCheckDialogButtonComponent, DbxFirebaseNotificationHealthCheckDialogComponent, DbxFirebaseNotificationHealthCheckIssueComponent, DbxFirebaseNotificationHealthCheckMethodComponent, DbxFirebaseNotificationHealthCheckPresentationService, DbxFirebaseNotificationHealthCheckPresentationServiceConfig, DbxFirebaseNotificationHealthCheckViewComponent, DbxFirebaseNotificationItemContentComponent, DbxFirebaseNotificationItemDefaultViewComponent, DbxFirebaseNotificationItemListComponent, DbxFirebaseNotificationItemListViewComponent, DbxFirebaseNotificationItemListViewItemComponent, DbxFirebaseNotificationItemStore, DbxFirebaseNotificationItemStorePopoverButtonComponent, DbxFirebaseNotificationItemStorePopoverComponent, DbxFirebaseNotificationItemViewComponent, DbxFirebaseNotificationItemWidgetService, DbxFirebaseNotificationSummaryCollectionStoreDirective, DbxFirebaseNotificationSummaryDocumentStoreDirective, DbxFirebaseNotificationTemplateService, DbxFirebaseNotificationUserCollectionStoreDirective, DbxFirebaseNotificationUserDocumentStoreDirective, DbxFirebaseNotificationUserHealthCheckStore, DbxFirebaseParsedEmulatorsConfig, DbxFirebasePasswordResetComponent, DbxFirebasePasswordResetFormComponent, DbxFirebaseRegisterComponent, DbxFirebaseRegisterEmailComponent, DbxFirebaseStorageFileCollectionStoreDirective, DbxFirebaseStorageFileDocumentStoreDirective, DbxFirebaseStorageFileDownloadButtonComponent, DbxFirebaseStorageFileDownloadService, DbxFirebaseStorageFileDownloadStorage, DbxFirebaseStorageFileGroupDocumentStoreDirective, DbxFirebaseStorageFileUploadActionHandlerDirective, DbxFirebaseStorageFileUploadInitializeDocumentDirective, DbxFirebaseStorageFileUploadModule, DbxFirebaseStorageFileUploadStore, DbxFirebaseStorageFileUploadStoreDirective, DbxFirebaseStorageFileUploadSyncDirective, DbxFirebaseStoragePdfMergeUploadSyncDirective, DbxFirebaseStorageService, DbxFirebaseSystemStateCollectionStoreDirective, DbxFirebaseSystemStateDocumentStoreDirective, DbxFirestoreContextService, DbxLimitedFirebaseDocumentLoaderInstance, FIREBASE_APP_CHECK_TOKEN, FIREBASE_APP_TOKEN, FIREBASE_AUTH_TOKEN, FIREBASE_FIRESTORE_TOKEN, FIREBASE_FUNCTIONS_TOKEN, FIREBASE_NOTIFICATION_ITEM_WIDGET_TYPE_PREFIX, FIREBASE_PROVIDER_ID_TO_LOGIN_METHOD_TYPE_MAP, FIREBASE_STORAGE_TOKEN, FlatFirestoreModelKeyPipe, IMPORTS_AND_EXPORTS, LOGIN_METHOD_TYPE_TO_FIREBASE_PROVIDER_ID_MAP, NOTIFICATION_DELIVERY_METHOD_ICONS, NOTIFICATION_DELIVERY_METHOD_LABELS, NOTIFICATION_DELIVERY_METHOD_SHORT_LABELS, NOTIFICATION_DELIVERY_METHOD_TEST_MESSAGE_LABELS, NOTIFICATION_DELIVERY_METHOD_TEST_MESSAGE_NOUNS, NOTIFICATION_HEALTH_CHECK_PROBE_ISSUE_OUTCOMES, NOTIFICATION_HEALTH_CHECK_STATUS_COLORS, NOTIFICATION_HEALTH_CHECK_STATUS_ICONS, NOTIFICATION_HEALTH_CHECK_STATUS_LABELS, NotificationBoxCollectionStore, NotificationBoxDocumentStore, NotificationCollectionStore, NotificationDocumentStore, NotificationSummaryCollectionStore, NotificationSummaryDocumentStore, NotificationUserCollectionStore, NotificationUserDocumentStore, OAUTH_FIREBASE_LOGIN_METHOD_CATEGORY, StorageFileCollectionStore, StorageFileDocumentStore, StorageFileGroupDocumentStore, StorageFileUploadFilesError, SystemStateCollectionStore, SystemStateDocumentStore, TwoWayFlatFirestoreModelKeyPipe, authRolesObsWithClaimsService, authUserInfoFromAuthUser, authUserStateFromFirebaseAuthServiceFunction, createDbxFirebaseAppCheck, createDbxFirebaseAuth, createDbxFirebaseFirestore, createDbxFirebaseFunctions, createDbxFirebaseStorage, dbxFirebaseAuthContextInfo, dbxFirebaseCollectionChangeTrigger, dbxFirebaseCollectionChangeTriggerForStore, dbxFirebaseCollectionChangeTriggerForWatcher, dbxFirebaseCollectionChangeWatcher, dbxFirebaseCollectionLoaderInstance, dbxFirebaseCollectionLoaderInstanceWithCollection, dbxFirebaseDocumentLoaderInstance, dbxFirebaseDocumentLoaderInstanceWithAccessor, dbxFirebaseDocumentStoreContextModelEntitiesSourceFactory, dbxFirebaseIdRouteParamRedirect, dbxFirebaseInContextFirebaseModelServiceInstance, dbxFirebaseInContextFirebaseModelServiceInstanceFactory, dbxFirebaseKeyRouteParamRedirect, dbxFirebaseModelContextServiceInfoInstanceFactory, dbxFirebaseModelEntityWidgetInjectionConfigFactory, dbxFirebaseModelTypesServiceInstance, dbxFirebaseModelTypesServiceInstancePairForKeysFactory, dbxFirebaseSourceSelectLoadSource, dbxFirebaseStorageFileDownloadServiceCustomSourceFromObs, dbxFirebaseStorageFileImageCompressionFileModifier, dbxFirebaseStorageProvidersContextConfigFactory, dbxLimitedFirebaseDocumentLoaderInstance, dbxLimitedFirebaseDocumentLoaderInstanceWithAccessor, dbxWidgetTypeForNotificationTemplateType, defaultDbxFirebaseAuthServiceDelegateWithClaimsService, defaultDbxFirebaseStorageFileDownloadStorageAccessorFactory, developmentFirebaseServerSchedulerWidgetEntry, enableAppCheckDebugTokenGeneration, firebaseAuthState, firebaseAuthTokenFromUser, firebaseCollectionStoreCreateFunction, firebaseCollectionStoreCrudFunction, firebaseContextServiceEntityMap, firebaseDocumentStoreCreateFunction, firebaseDocumentStoreCrudFunction, firebaseDocumentStoreDeleteFunction, firebaseDocumentStoreInvokeFunction, firebaseDocumentStoreReadFunction, firebaseDocumentStoreUpdateFunction, firebaseIdToken, firebaseProviderIdToLoginMethodType, isDbxFirebaseModelEntityWithStore, isStandaloneWebApp, linkDocumentStoreToParentContextStores, loginMethodTypeToFirebaseProviderId, modelDoesNotExistError, notificationHealthCheckProbeIssueLabel, parseDbxFirebaseEmulatorsConfig, provideDbxFirebase, provideDbxFirebaseAnalyticsUserEventsListenerService, provideDbxFirebaseApp, provideDbxFirebaseAuth, provideDbxFirebaseAuthImpersonation, provideDbxFirebaseCollectionStoreDirective, provideDbxFirebaseCollectionWithParentStoreDirective, provideDbxFirebaseDevelopment, provideDbxFirebaseDocumentStoreContextStore, provideDbxFirebaseDocumentStoreDirective, provideDbxFirebaseDocumentStoreTwoWayKeyProvider, provideDbxFirebaseFunctions, provideDbxFirebaseLogin, provideDbxFirebaseModelContextService, provideDbxFirebaseModelEntitiesWidgetService, provideDbxFirebaseNotifications, provideDbxFirebaseStorageFileService, provideDbxFirestoreCollection, provideNotificationFirestoreCollections, provideStorageFileFirestoreCollections, provideSystemStateFirestoreCollections, providedDbxFirebaseStorage, readDbxAnalyticsUserPropertiesFromAuthUserInfo, readValueFromIdToken, resolveDbxFirebaseAuthFlow, setParentStoreEffect, stateFromTokenForLoggedInUserFunction, storageFileUploadFiles, storageFileUploadHandler };
8499
9739
  //# sourceMappingURL=dereekb-dbx-firebase.mjs.map