import { type Observable } from 'rxjs'; import { type FirestoreCollectionCache, type FirestoreCollectionDocumentCache } from '../cache/cache'; import { type FirestoreAccessorDriverRef } from '../driver/accessor'; import { type FirestoreCollectionNameRef, type FirestoreModelId, type FirestoreModelIdentityCollectionName, type FirestoreModelIdentityModelType, type FirestoreModelIdentityRef, type FirestoreModelIdRef, type FirestoreModelKey, type FirestoreModelKeyRef, type FirestoreModelTypeRef, type FirestoreModelIdentity, type FirestoreModelTypeModelIdentityRef } from './../collection/collection'; import { type DocumentReference, type CollectionReference, type Transaction, type WriteBatch, type DocumentSnapshot, type SnapshotOptions, type WriteResult, type FirestoreDataConverter } from '../types'; import { type FirestoreAccessorIncrementUpdate, type FirestoreDocumentDataAccessor, type FirestoreDocumentUpdateParams, type FirestoreAccessorStreamMode, type FirestoreAccessorArrayUpdate } from './accessor'; import { type CollectionReferenceRef, type DocumentReferenceRef, type FirestoreContextReference, type FirestoreDataConverterRef } from '../reference'; import { type FirestoreDocumentContext } from './context'; import { type Building, type Maybe } from '@dereekb/util'; import { type InterceptAccessorFactoryFunction } from './accessor.wrap'; import { type FirestoreDataConverterFactory, type FirestoreDataConverterFactoryRef, type InterceptFirestoreDataConverterFactory } from './converter'; /** * Represents a typed Firestore document with full CRUD capabilities and reactive streaming. * * This is the primary interface for interacting with individual Firestore documents in the application. * It combines document reference metadata, data conversion, and all read/write operations into a * single cohesive interface. Documents are created via {@link FirestoreDocumentAccessor} which provides * the appropriate execution context (standard, transaction, or batch). * * Key capabilities: * - **Read**: `snapshot()`, `snapshotData()`, `exists()` * - **Stream**: `snapshotStream()`, `snapshotDataStream()` for real-time updates * - **Write**: `create()`, `update()`, `increment()`, `arrayUpdate()` * - **Identity**: `id`, `key` (full path), `modelType`, `collectionName` * * @template T - The document data type * @template I - The model identity type (provides modelType and collectionName) */ export interface FirestoreDocument extends FirestoreDataConverterRef, DocumentReferenceRef, CollectionReferenceRef, FirestoreModelIdentityRef, FirestoreModelTypeRef>, FirestoreCollectionNameRef>, FirestoreModelKeyRef, FirestoreModelIdRef { readonly accessor: FirestoreDocumentDataAccessor; readonly cache: FirestoreCollectionDocumentCache; readonly id: FirestoreModelId; snapshotStream(mode: FirestoreAccessorStreamMode): Observable>; snapshotDataStream(mode: FirestoreAccessorStreamMode, options?: SnapshotOptions): Observable>; snapshot(): Promise>; snapshotData(options?: SnapshotOptions): Promise>; exists(): Promise; create(data: T): Promise; update(data: Partial): Promise; increment(data: FirestoreAccessorIncrementUpdate): Promise; arrayUpdate(data: FirestoreAccessorArrayUpdate): Promise; } /** * Refers to the FirestoreDocument's data type using only the FirestoreDocument */ export type FirestoreDocumentData> = D extends FirestoreDocument ? T : never; /** * Abstract base implementation of {@link FirestoreDocument}. * * Provides the standard implementation for all document operations by delegating to the * underlying {@link FirestoreDocumentDataAccessor}. The `update()` method uses the document's * converter (via {@link updateWithAccessorUpdateAndConverterFunction}) so that partial updates * go through the same conversion pipeline as full writes. * * Subclasses must implement `modelIdentity` to provide the model type and collection name. * Also exposes `stream$` and `data$` lazy observables for reactive consumption. * * @template T - The document data type * @template D - The concrete document subclass type (for self-referential typing) * @template I - The model identity type */ export declare abstract class AbstractFirestoreDocument, I extends FirestoreModelIdentity = FirestoreModelIdentity> implements FirestoreDocument, LimitedFirestoreDocumentAccessorRef, CollectionReferenceRef { private readonly _accessor; private readonly _documentAccessor; private readonly _cache; readonly stream$: Observable>; readonly data$: Observable; constructor(accessor: FirestoreDocumentDataAccessor, documentAccessor: LimitedFirestoreDocumentAccessor); get accessor(): FirestoreDocumentDataAccessor; get cache(): FirestoreCollectionDocumentCache; get documentAccessor(): LimitedFirestoreDocumentAccessor; abstract get modelIdentity(): I; get modelType(): FirestoreModelIdentityModelType; get collectionName(): FirestoreModelIdentityCollectionName; get id(): FirestoreModelId; get key(): FirestoreModelKey; get documentRef(): DocumentReference; get collection(): CollectionReference; get converter(): FirestoreDataConverter; /** * Retrieves a DocumentSnapshot of the document as an Observable. Streams based on the input mode. * * Passively populates the cache with each emitted snapshot. * * @param mode - The stream mode controlling how the Observable emits snapshot updates * @returns An Observable that emits DocumentSnapshot values based on the given mode */ snapshotStream(mode: FirestoreAccessorStreamMode): Observable>; /** * Retrieves the data of the DocumentSnapshot of the document as an Observable. Streams based on the input mode. * * Passively populates the cache via {@link snapshotStream}. * * @param mode - The stream mode controlling how the Observable emits snapshot data updates * @param options - Optional SnapshotOptions for reading the document data * @returns An Observable that emits the document data or undefined based on the given mode */ snapshotDataStream(mode: FirestoreAccessorStreamMode, options?: SnapshotOptions): Observable>; /** * Retrieves a DocumentSnapshot of the document from Firestore. * * Passively populates the cache with the fetched snapshot. * * @returns A Promise resolving to the document snapshot */ snapshot(): Promise>; /** * Retrieves the data of the document, checking the cache first. * * If a fresh cache entry exists, returns it without hitting Firestore. * Otherwise falls through to {@link snapshot} which populates the cache. * * @param options - Optional SnapshotOptions for reading the document data * @returns A Promise resolving to the document data, or undefined if the document does not exist */ snapshotData(options?: SnapshotOptions): Promise>; /** * Returns true if the model exists. * * @param data * @returns */ exists(): Promise; /** * Creates the document if it does not exist, using the accessor's create functionality. * * Populates the cache with the written data after a successful create. * * @param data - The document data to create * @returns A Promise that resolves when the create completes */ create(data: T): Promise; /** * Updates the document using the accessor's update functionality if the document exists. This differs from Firestore's default * update implementation which does not use the configured converter. This update function will, allowing the use of * snapshotConverterFunctions(). * * Invalidates the cache entry since partial updates don't provide the full document. * Throws an exception when the document does not exist. * * @param data - Partial document data to update * @param params - Optional update parameters * @returns A Promise that resolves when the update completes */ update(data: Partial, params?: FirestoreDocumentUpdateParams): Promise; /** * Updates the document using the accessor's increment functionality. * * Invalidates the cache entry since increment updates don't provide the full document. * * @param data - The increment update to apply to numeric fields * @returns A Promise that resolves when the increment update completes */ increment(data: FirestoreAccessorIncrementUpdate): Promise; /** * Updates the document using the accessor's array field update functionality. * * Invalidates the cache entry since array updates don't provide the full document. * * @param data - The array field update to apply (union or remove elements) * @returns A Promise that resolves when the array update completes */ arrayUpdate(data: FirestoreAccessorArrayUpdate): Promise; } /** * Reference to a {@link LimitedFirestoreDocumentAccessor}. */ export interface LimitedFirestoreDocumentAccessorRef = FirestoreDocument, A extends LimitedFirestoreDocumentAccessor = LimitedFirestoreDocumentAccessor> { readonly documentAccessor: A; } export type FirestoreDocumentAccessorRef = FirestoreDocument> = LimitedFirestoreDocumentAccessorRef>; /** * Provides document loading capabilities without the ability to create new documents. * * Used in contexts where you have a document reference or key but don't have (or need) access * to the parent collection — for example, in subcollection accessors or when loading documents * from known paths. For full access including `newDocument()` and `loadDocumentForId()`, * use {@link FirestoreDocumentAccessor}. * * @template T - The document data type * @template D - The concrete FirestoreDocument subclass */ export interface LimitedFirestoreDocumentAccessor = FirestoreDocument> extends FirestoreDataConverterRef, FirestoreModelTypeModelIdentityRef, FirestoreAccessorDriverRef { readonly databaseContext: FirestoreDocumentContext; /** * Returns the collection cache for the given document reference. * * Returns a noop cache when operating within a transaction or write batch context, * since cache reads/writes must be bypassed in those contexts. * * @param ref - The document reference to get the cache for * @returns The collection cache (real or noop) for the document */ cacheForDocument(ref: DocumentReference): FirestoreCollectionDocumentCache; /** * Loads a document from the datastore. * * @param ref */ loadDocument(ref: DocumentReference): D; /** * Loads a document from an existing FirestoreDocument * * @param document */ loadDocumentFrom(document: FirestoreDocument): D; /** * Loads a document from the datastore with the given key/full path. * * @param ref */ loadDocumentForKey(fullPath: FirestoreModelKey): D; /** * Creates a document ref with a key/full path. * * @param ref */ documentRefForKey(fullPath: FirestoreModelKey): DocumentReference; /** * This is the default converter. Be sure to use the converterFactory instead when attempting to get the accurate converter for a document. */ readonly converter: FirestoreDataConverter; /** * Returns the converter factory for this accessor. */ readonly converterFactory: FirestoreDataConverterFactory; } /** * Full document accessor with collection-level operations including creating new documents. * * Extends {@link LimitedFirestoreDocumentAccessor} with `newDocument()` (auto-generates an ID) * and `loadDocumentForId()` (loads by document ID relative to the collection). This is the * standard accessor used when you have access to the collection reference. * * @template T - The document data type * @template D - The concrete FirestoreDocument subclass */ export interface FirestoreDocumentAccessor = FirestoreDocument> extends LimitedFirestoreDocumentAccessor, CollectionReferenceRef, FirestoreAccessorDriverRef { readonly databaseContext: FirestoreDocumentContext; /** * Creates a new document. */ newDocument(): D; /** * Loads a document from the datastore with the given id/path. * * @param ref */ loadDocumentForId(id: FirestoreModelId): D; /** * Creates a document ref relative to the current context and given the input path. * * @param path * @param pathSegments */ documentRefForId(id: FirestoreModelId): DocumentReference; } /** * Factory function that creates a typed {@link FirestoreDocument} from a raw data accessor. * * Used by the accessor factory system to create concrete document instances (e.g., `NotificationDocument`) * from their underlying accessor and document accessor context. */ export type FirestoreDocumentFactoryFunction = FirestoreDocument> = (accessor: FirestoreDocumentDataAccessor, documentAccessor: LimitedFirestoreDocumentAccessor) => D; /** * Factory function used for creating a FirestoreDocumentAccessor. */ export type LimitedFirestoreDocumentAccessorFactoryFunction = FirestoreDocument, A extends LimitedFirestoreDocumentAccessor = LimitedFirestoreDocumentAccessor> = ((context?: FirestoreDocumentContext) => A) & FirestoreDataConverterFactoryRef; /** * Factory type used for creating a FirestoreDocumentAccessor. */ export interface LimitedFirestoreDocumentAccessorFactory = FirestoreDocument, A extends LimitedFirestoreDocumentAccessor = LimitedFirestoreDocumentAccessor> { /** * Creates a new FirestoreDocumentAccessor using the given context. * * @param context Optional context to retrieve items from. */ readonly documentAccessor: LimitedFirestoreDocumentAccessorFactoryFunction; } /** * FirestoreDocumentAccessor configuration. */ export interface LimitedFirestoreDocumentAccessorFactoryConfig = FirestoreDocument> extends FirestoreDataConverterRef, FirestoreModelTypeModelIdentityRef, FirestoreContextReference, FirestoreAccessorDriverRef { /** * Optional InterceptAccessorFactoryFunction to intercept/return a modified accessor factory. */ readonly accessorFactory?: InterceptAccessorFactoryFunction; /** * Optional InterceptFirestoreDataConverterFactory to return a modified converter. */ readonly converterFactory?: InterceptFirestoreDataConverterFactory; /** * The collection cache for documents created by this factory. */ readonly cache: FirestoreCollectionCache; readonly makeDocument: FirestoreDocumentFactoryFunction; } /** * Creates a {@link LimitedFirestoreDocumentAccessorFactoryFunction} from the provided configuration. * * @param config - Configuration including converter, accessor factory, and document factory * @returns A factory function for creating LimitedFirestoreDocumentAccessor instances */ export declare function limitedFirestoreDocumentAccessorFactory = FirestoreDocument>(config: LimitedFirestoreDocumentAccessorFactoryConfig): LimitedFirestoreDocumentAccessorFactoryFunction; /** * Factory function used for creating a FirestoreDocumentAccessor. */ export type FirestoreDocumentAccessorFactoryFunction = FirestoreDocument> = LimitedFirestoreDocumentAccessorFactoryFunction>; /** * Factory type used for creating a FirestoreDocumentAccessor. */ export type FirestoreDocumentAccessorFactory = FirestoreDocument> = LimitedFirestoreDocumentAccessorFactory>; /** * FirestoreDocumentAccessor configuration. */ export interface FirestoreDocumentAccessorFactoryConfig = FirestoreDocument> extends CollectionReferenceRef, LimitedFirestoreDocumentAccessorFactoryConfig { readonly makeDocument: FirestoreDocumentFactoryFunction; } /** * Creates a {@link FirestoreDocumentAccessorFactoryFunction} from the provided configuration. * * Extends the limited accessor factory with collection-level operations such as creating new documents * and loading documents by ID. * * @param config - Configuration including the collection reference and document factory * @returns A factory function for creating FirestoreDocumentAccessor instances */ export declare function firestoreDocumentAccessorFactory = FirestoreDocument>(config: FirestoreDocumentAccessorFactoryConfig): FirestoreDocumentAccessorFactoryFunction; export interface LimitedFirestoreDocumentAccessorForTransactionFactory = FirestoreDocument, A extends LimitedFirestoreDocumentAccessor = LimitedFirestoreDocumentAccessor> { /** * Creates a new FirestoreDocumentAccessor for a Transaction. If transaction is null/undefined, an accessor with a default context is returned. */ documentAccessorForTransaction(transaction: Maybe): A; } export type FirestoreDocumentAccessorForTransactionFactory = FirestoreDocument> = LimitedFirestoreDocumentAccessorForTransactionFactory>; export interface LimitedFirestoreDocumentAccessorForWriteBatchFactory = FirestoreDocument, A extends LimitedFirestoreDocumentAccessor = LimitedFirestoreDocumentAccessor> { /** * Creates a new FirestoreDocumentAccessor for a WriteBatch. If writeBatch is null/undefined an accessor with a default context is returned. */ documentAccessorForWriteBatch(writeBatch: Maybe): A; } export type FirestoreDocumentAccessorForWriteBatchFactory = FirestoreDocument> = LimitedFirestoreDocumentAccessorForWriteBatchFactory>; export interface LimitedFirestoreDocumentAccessorContextExtensionConfig = FirestoreDocument> extends FirestoreAccessorDriverRef { readonly documentAccessor: LimitedFirestoreDocumentAccessorFactoryFunction; } export interface FirestoreDocumentAccessorContextExtensionConfig = FirestoreDocument> extends LimitedFirestoreDocumentAccessorContextExtensionConfig { readonly documentAccessor: FirestoreDocumentAccessorFactoryFunction; } export interface LimitedFirestoreDocumentAccessorContextExtension = FirestoreDocument> extends LimitedFirestoreDocumentAccessorFactory, LimitedFirestoreDocumentAccessorForTransactionFactory, LimitedFirestoreDocumentAccessorForWriteBatchFactory { } export interface FirestoreDocumentAccessorContextExtension = FirestoreDocument> extends FirestoreDocumentAccessorFactory, FirestoreDocumentAccessorForTransactionFactory, FirestoreDocumentAccessorForWriteBatchFactory { } /** * Creates a context extension object that adds transaction and write batch accessor support to a document accessor. * * @param config - Configuration containing the document accessor and firestore accessor driver * @param config.documentAccessor - The document accessor factory function * @param config.firestoreAccessorDriver - The firestore accessor driver used to create transaction and write batch contexts * @returns An extension object with document accessor factory methods for default, transaction, and write batch contexts */ export declare function firestoreDocumentAccessorContextExtension = FirestoreDocument>({ documentAccessor, firestoreAccessorDriver }: FirestoreDocumentAccessorContextExtensionConfig): FirestoreDocumentAccessorContextExtension; export declare function firestoreDocumentAccessorContextExtension = FirestoreDocument>({ documentAccessor, firestoreAccessorDriver }: LimitedFirestoreDocumentAccessorContextExtensionConfig): LimitedFirestoreDocumentAccessorContextExtension; /** * A {@link FirestoreDocument} that resides in a subcollection and provides access to its parent document reference. * * @template P - The parent document's data type * @template T - This document's data type * @template I - The model identity type */ export interface FirestoreDocumentWithParent extends FirestoreDocument { readonly parent: DocumentReference

; } export declare abstract class AbstractFirestoreDocumentWithParent, I extends FirestoreModelIdentity = FirestoreModelIdentity> extends AbstractFirestoreDocument implements FirestoreDocumentWithParent { get parent(): DocumentReference

; constructor(accessor: FirestoreDocumentDataAccessor, documentAccessor: LimitedFirestoreDocumentAccessor); } /** * Accessor for collections that contain only a single known document (e.g., system state, user profile). * * Provides convenience methods that load the single document by its fixed identifier, * supporting both transaction and write batch contexts. * * @template T - The document data type * @template D - The concrete FirestoreDocument subclass */ export interface FirestoreSingleDocumentAccessor = FirestoreDocument> { readonly singleItemIdentifier: string; loadDocument(): D; loadDocumentForTransaction(transaction: Maybe): D; loadDocumentForWriteBatch(writeBatch: Maybe): D; documentRef(): DocumentReference; } export interface FirestoreSingleDocumentAccessorConfig = FirestoreDocument> { readonly singleItemIdentifier: string; readonly accessors: FirestoreDocumentAccessorContextExtension; } /** * Creates a {@link FirestoreSingleDocumentAccessor} for a collection that contains a single known document. * * @param config - Configuration specifying the single item identifier and the document accessor context extension * @returns A FirestoreSingleDocumentAccessor providing convenient access to the single document */ export declare function firestoreSingleDocumentAccessor = FirestoreDocument>(config: FirestoreSingleDocumentAccessorConfig): FirestoreSingleDocumentAccessor; /** * Default document ID used for single-document collections. The document is stored at path `/0`. */ export declare const DEFAULT_SINGLE_ITEM_FIRESTORE_COLLECTION_DOCUMENT_IDENTIFIER = "0"; /** * Document ID used for the single document in a single-item Firestore collection. * * @semanticType * @semanticTopic identifier * @semanticTopic string * @semanticTopic dereekb-firebase:firestore */ export type SingleItemFirestoreCollectionDocumentIdentifier = string; export interface SingleItemFirestoreCollectionDocumentIdentifierRef { /** * Identifier of the single document in the collection. */ readonly singleItemIdentifier: SingleItemFirestoreCollectionDocumentIdentifier; } /** * Extends a Firestore collection object in-place with single-document accessor methods. * * @param x - The collection object to extend with single-document accessor methods * @param singleItemIdentifier - Optional identifier for the single document; defaults to {@link DEFAULT_SINGLE_ITEM_FIRESTORE_COLLECTION_DOCUMENT_IDENTIFIER} */ export declare function extendFirestoreCollectionWithSingleDocumentAccessor & FirestoreDocumentAccessorContextExtension, T, D extends FirestoreDocument = FirestoreDocument>(x: Building, singleItemIdentifier?: SingleItemFirestoreCollectionDocumentIdentifier): void;