UNPKG

@trycourier/courier-ui-inbox

Version:

Inbox components for the Courier web UI

229 lines (228 loc) 8.19 kB
import { InboxMessage } from '@trycourier/courier-js'; import { CourierInboxFeed, InboxDataSet } from '../types/inbox-data-set'; import { CourierInboxDataStoreListener } from './datastore-listener'; /** * Shared datastore for Inbox components. * * CourierInboxDatastore is a singleton. Use `CourierInboxDatastore.shared` * to access the shared instance. * * @public */ export declare class CourierInboxDatastore { private static readonly TAG; private static readonly OPEN_BATCH_DELAY_MS; private static readonly OPEN_BATCH_MAX_SIZE; private static instance; private _datasets; private _listeners; private _removeMessageEventListener?; private _pendingOpenMessageIds; private _openBatchTimer; /** * Global message store is a map of Message ID to Message for all messages * that have been loaded. * * This acts as the source of truth to apply messages mutations to a message * given its ID and propagate those mutations to individual datasets. */ private _globalMessages; /** Access CourierInboxDatastore through {@link CourierInboxDatastore.shared} */ private constructor(); /** * Instantiate the datastore with the feeds specified. * * Feeds are added to the datastore as datasets. Each feed has a respective * dataset. Existing datasets will be cleared before the feeds specified are added. * * @param feeds - The feeds with which to instantiate the datastore */ registerFeeds(feeds: CourierInboxFeed[]): void; private createDatasetsFromFilters; /** * Add a message to the datastore. * * The message will be added to any datasets for which it qualifies. * * @param message - The message to add */ addMessage(message: InboxMessage): void; private updateDatasetsWithMessageChange; /** * Listen for real-time message updates from the Courier backend. * * If an existing WebSocket connection is open, it will be re-used. If not, * a new connection will be opened. */ listenForUpdates(): Promise<void>; /** * Load unread counts for multiple tabs in a single GraphQL query. * This populates tab badges without loading messages. * @param tabIds - Array of tab IDs to load counts for */ loadUnreadCountsForTabs(tabIds: string[]): Promise<void>; /** * Add a datastore listener, whose callbacks will be called in response to various message events. * @param listener - The listener instance to add */ addDataStoreListener(listener: CourierInboxDataStoreListener): void; /** * Remove a datastore listener. * @param listener - The listener instance to remove */ removeDataStoreListener(listener: CourierInboxDataStoreListener): void; /** * Mark a message as read. * @param message - The message to mark as read */ readMessage({ message }: { message: InboxMessage; }): Promise<void>; /** * Mark a message as unread. * @param message - The message to mark as unread */ unreadMessage({ message }: { message: InboxMessage; }): Promise<void>; /** * Mark a message as opened. * * The local state is updated optimistically and the server call is * batched: multiple opens arriving within a short window * are collected and flushed as a single GraphQL request. * * @param message - The message to mark as opened */ openMessage({ message }: { message: InboxMessage; }): void; private scheduleBatchOpen; private flushBatchOpen; /** * Unarchive a message. * @param message - The message to unarchive */ unarchiveMessage({ message }: { message: InboxMessage; }): Promise<void>; /** * Archive a message. * @param message - The message to archive */ archiveMessage({ message }: { message: InboxMessage; }): Promise<void>; /** * Track a click event for a message. * @param message - The message that was clicked */ clickMessage({ message }: { message: InboxMessage; }): Promise<void>; /** * Archive all messages for the specified dataset. */ archiveAllMessages(): Promise<void>; /** * Mark all messages read across all datasets. */ readAllMessages(): Promise<void>; /** * Archive all read messages for the specified dataset. */ archiveReadMessages(): Promise<void>; /** * Load datasets from the backend. * * Props: * - canUseCache: If true and the dataset has already been loaded once, this will return the dataset from memory. * - datasetIds: Optional: The set of dataset IDs to load. If unset, all known datasets will be loaded. * * @param props - Options to load datasets, see method documentation */ load(props?: { canUseCache: boolean; datasetIds?: string[]; }): Promise<void>; private loadDatasets; /** * Sync messages from a dataset to the global message store. * This is called after datasets load messages to ensure the global store has all messages. */ private syncDatasetMessagesToGlobalStore; /** * Fetch the next page of messages for the specified feed or datasetId. * * feedType is deprecated and will be removed in the next major release. * Please migrate to pass the same identifier as datasetId. * While both options are present, exactly one is required. * * @param props - Options to fetch the next page of messages, see method documetation */ fetchNextPageOfMessages(props: { feedType?: string; datasetId?: string; }): Promise<InboxDataSet | null>; /** * Get the {@link InboxDataSet} representation of the dataset ID specified. * @param datasetId - The dataset ID to get */ getDatasetById(datasetId: string): InboxDataSet | undefined; /** * Get datasets currently in the datastore. * @returns A record mapping dataset IDs to their InboxDataSet representations */ getDatasets(): Record<string, InboxDataSet>; /** * Get the total unread count across all datasets. */ get totalUnreadCount(): number; private fetchNextPageForDataset; private handleMessageEvent; /** * Update all messages across all datasets from an InboxMessageEvent. * This only handles InboxMessageEvents that do not specify a messageId * and mutate all messages. * * Related: {@link CourierInboxDatastore.updateMessage} */ private updateAllMessages; /** * Update a single message across all datasets from an InboxMessageEvent. * This only handles InboxMessageEvents that specify a messageId. * * Related: {@link CourierInboxDatastore.updateAllMessages} */ private updateMessage; private clearDatasets; private static getISONow; /** * Create a snapshot of all datasets and global messages for rollback purposes. * This captures the current state of all messages and metadata. */ private createDatastoreSnapshot; /** * Restore all datasets and global messages from a snapshot, reverting any mutations. * This is used for rollback when API calls or updates to downstream datasets fail. */ private restoreDatastoreSnapshot; /** * Execute an operation with automatic rollback on failure. * Snapshots all datasets before the operation and restores them if the operation throws. * * Note: Errors are caught and logged, but not re-thrown to match the behavior * for backwards compatibility with the legacy (inbox/archive) datastore implementation. * * Note: This method exists at the datastore level (rather than dataset) to handle * errors from API calls. */ private executeWithRollback; /** * Get the shared instance of CourierInboxDatastore. * * CourierInboxDatastore is a singleton. Instance methods should be accessed * through this `shared` static accessor. */ static get shared(): CourierInboxDatastore; }