repo_description: A fast, local first, reactive Database for JavaScript Applications https://rxdb.info/
repo_topics: angular browser-database couchdb crdt database firebase graphql indexeddb ionic local-first localstorage nodejs nosql postgres pouchdb react-native realtime realtime-database rxdb sqlite
code: import type { ChangeEvent } from 'event-reduce-js';
  import type { RxChangeEvent } from './rx-change-event.d.ts';
  import type { RxDocumentMeta } from './rx-document.d.ts';
  import type { RxStorageWriteError } from './rx-error.d.ts';
  import type { RxJsonSchema } from './rx-schema.d.ts';
  import type { Override } from './util.d.ts';
  
  /**
   * The document data how it comes out of the storage instance.
   * Contains all meta data like revision, attachments and deleted-flag.
   */
  export type RxDocumentData<T> = T & {
  
      /**
       * As other NoSQL databases,
       * RxDB also assumes that no data is finally deleted.
       * Instead the documents are stored with _deleted: true
       * which means they will not be returned at queries.
       */
      _deleted: boolean;
  
      /**
       * The attachments meta data is stored besides to document.
       */
      _attachments: {
          [attachmentId: string]: RxAttachmentData;
      };
  
      /**
       * Contains a revision which is concatenated with a [height: number]-[identifier: string]
       * like: '1-3hl4kj3l4kgj34g34glk'.
       * The revision is used to detect write conflicts and have a document history.
       * Revisions behave similar to couchdb revisions:
       * @link https://docs.couchdb.org/en/stable/replication/conflicts.html#revision-tree
  
      * When writing a document, you must send the correct revision in the previous-field
       * to make sure that you do not cause a write conflict.
       * The revision of the 'new' document-field must be created, for example via util.createRevision().
       * Any revision that matches the [height]-[hash] format can be used.
       */
      _rev: string;
      _meta: RxDocumentMeta;
  };
  
  export type RxDocumentDataById<RxDocType> = {
      [documentId: string]: RxDocumentData<RxDocType>;
  };
  
  /**
   * The document data how it is send to the
   * storage instance to save it.
   */
  // We & T here instead of in RxDocumentData to preserver indexability by keyof T which the Override breaks
  export type RxDocumentWriteData<T> = T & Override<RxDocumentData<{}>, {
      _attachments: {
          /**
           * To create a new attachment, set the write data
           * To delete an attachment, leave it out on the _attachments property.
           * To change an attachment, set the new write data.
           * To not touch an attachment, just send the stub again
           * which came out of the storage instance.
           */
          [attachmentId: string]: RxAttachmentData | RxAttachmentWriteData;
      };
  }>;
  
  export type WithDeleted<DocType> = DocType & {
      _deleted: boolean;
  };
  export type WithDeletedAndAttachments<DocType> = DocType & {
      _deleted: boolean;
  
      /**
       * Here the _attachments might exist
       * or might not, depending one the use case.
       */
      _attachments?: {
          [attachmentId: string]: RxAttachmentData | RxAttachmentWriteData;
      };
  };
  
  /**
   * Send to the bulkWrite() method of a storage instance.
   */
  export type BulkWriteRow<RxDocType> = {
      /**
       * The current document state in the storage engine,
       * assumed by the application.
       * Undefined if the document is a new insert.
       * Notice that we send the full document data as 'previous', not just the revision.
       * The reason is that to get the previous revision you anyway have to get the full
       * previous document and so it is easier to just send it all to the storage instance.
       * This will later allow us to use something different then the _rev key for conflict detection
       * when we implement other storage instances.
       */
      previous?: RxDocumentData<RxDocType>;
      /**
       * The new document data to be stored in the storage instance.
       */
      document: RxDocumentWriteData<RxDocType>;
  };
  export type BulkWriteRowById<RxDocType> = {
      [documentId: string]: BulkWriteRow<RxDocType>;
  };
  
  /**
   * After the RxStorage has processed all rows,
   * we have this to work with afterwards.
   */
  export type BulkWriteRowProcessed<RxDocType> = BulkWriteRow<RxDocType> & {
      document: RxDocumentData<RxDocType>;
  };
  
  
  export type RxAttachmentData = {
      /**
       * Size of the attachments data
       */
      length: number;
      /**
       * Content type like 'plain/text'
       */
      type: string;
      /**
       * The hash of the attachments content.
       * It is calculated by RxDB, and send to the storage.
       * The only guarantee is that the digest will change when the attachments data changes.
       * @link https://github.com/pouchdb/pouchdb/issues/3156#issuecomment-66831010
       * @link https://github.com/pubkey/rxdb/pull/4107
       */
      digest: string;
  };
  
  /**
   * Data which is needed for new attachments
   * that are send from RxDB to the RxStorage implementation.
   */
  export type RxAttachmentWriteData = RxAttachmentData & {
      /**
       * The data of the attachment as a Blob.
       * Blob is the canonical internal type because:
       * - Attachments are blob-like things (images, videos, PDFs)
       * - Blob is immutable (safe, no accidental mutation)
       * - Blob.type carries MIME type metadata
       * - Blob.size gives length synchronously
       * - Blob is structured-cloneable (works with Worker/Electron postMessage)
       * - IndexedDB stores Blobs efficiently (some engines use external blob storage)
       *
       * Conversion to ArrayBuffer only happens at boundaries that require it:
       * encryption (Web Crypto), compression (CompressionStream), digest hashing,
       * and WebSocket serialization.
       *
       * Encryption/compression run in the wrapRxStorageInstance layer OUTSIDE
       * storage transactions, so Blob does not extend transaction lifetimes.
       */
      data: Blob;
  };
  
  
  /**
   * The returned data from RxStorageInstance.bulkWrite()
   * For better performance, we do NOT use an indexed object,
   * but only plain arrays. Because most of the time
   * RxDB anyway only need the array data and we can save performance
   * by not indexing the results.
   *
   * We do not longer return the written documents. We only return the errors.
   * This is because we construct the written docs array from the input+errors anyway
   * and transferring large amounts of data has bad performance when the storage
   * is running in a different realm like a WebWorker or remote.
   */
  export type RxStorageBulkWriteResponse<RxDocType> = {
      /**
       * contains all errored writes.
       */
      error: RxStorageWriteError<RxDocType>[];
  };
  
  /**
   * We return a complex object instead of a single array
   * so we are able to add additional fields in the future.
   */
  export type RxStorageQueryResult<RxDocType> = {
      // the found documents, sort order is important.
      documents: RxDocumentData<RxDocType>[];
  };
  
  export type RxStorageCountResult = {
      count: number;
      /**
       * Returns the mode which was used by the storage
       * to count the documents.
       * If this returns 'slow', RxDB will throw by default
       * if 'allowSlowCount' is not set.
       */
      mode: 'fast' | 'slow';
  };
  
  export type RxStorageInstanceCreationParams<RxDocType, InstanceCreationOptions> = {
  
      /**
       * A string to uniquely identify the instance of the JavaScript object
       * of the RxDatabase where this RxStorageInstance belongs to.
       * In most cases you would use RxDatabase.token here.
       *
       * This is used so that we can add caching or reuse stuff that belongs to the same RxDatabase.
       * For example the BroadcastChannel that is used for event propagation between multiple browser tabs
       * is cached by this token.
       *
       * In theory we could just use the databaseName for that. But to make it easier in unit tests
       * to simulate cross-tab usage, we cannot assume that the databaseName is unique in a single
       * JavaScript process. Therefore we use the instance token instead.
       */
      databaseInstanceToken: string;
  
  
      databaseName: string;
      collectionName: string;
      schema: RxJsonSchema<RxDocumentData<RxDocType>>;
      options: InstanceCreationOptions;
      /**
       * If multiInstance is true, there can be more
       * then one instance of the database, for example
       * when multiple browser tabs exist or more then one Node.js
       * process relies on the same storage.
       */
      multiInstance: boolean;
      /**
       * Typed as `any` because different encryption plugins
       * may use passwords that are not strings.
       */
      password?: string | any;
  
      /**
       * Some storages can do additional checks
       * that are performance expensive
       * and should only be done in dev-mode.
       */
      devMode: boolean;
  };
  
  export type ChangeStreamOptions = {
  
      /**
       * Sequence number of the first event to start with.
       * If you want to get all ongoing events,
       * first get the latest sequence number and input it here.
       *
       * Optional on changeStream,
       * will start from the newest sequence.
       */
      startSequence?: number;
      /**
       * limits the amount of results
       */
      limit?: number;
  };
  
  /**
   * In the past we handles each RxChangeEvent by its own.
   * But it has been shown that this take way more performance then needed,
   * especially when the events get transferred over a data layer
   * like with WebWorkers or the BroadcastChannel.
   * So we now process events as bulks internally.
   */
  export type EventBulk<EventType, CheckpointType> = {
      /**
       * Unique id of the bulk,
       * used to detect duplicate bulks
       * that have already been processed.
       */
      id: string;
      events: EventType[];
  
      /**
       * Required for replication.
       * Passing this checkpoint into getChangedDocumentsSince()
       * must return all items that have been modified AFTER this write event.
       */
      checkpoint: CheckpointType;
  
      /**
       * The context that was given at the call to bulkWrite()
       * that caused this EventBulk.
       */
      context: string;
  };
  
  export type ChangeStreamEvent<DocType> = ChangeEvent<RxDocumentData<DocType>> & {
      /**
       * An integer that is increasing
       * and unique per event.
       * Can be used to sort events or get information
       * about how many events there are.
       */
      sequence: number;
      /**
       * The value of the primary key
       * of the changed document
       */
      id: string;
  };
  
  export type RxStorageChangeEvent<RxDocType> = Omit<RxChangeEvent<RxDocType>, 'isLocal' | 'collectionName'>;
  
  /**
   * An example for how a RxStorage checkpoint can look like.
   * NOTICE: Not all implementations use this type.
   */
  export type RxStorageDefaultCheckpoint = {
      id: string;
      lwt: number;
  };
  
  
  
  
  export type CategorizeBulkWriteRowsOutput<RxDocType> = {
      bulkInsertDocs: BulkWriteRowProcessed<RxDocType>[];
      bulkUpdateDocs: BulkWriteRowProcessed<RxDocType>[];
  
      errors: RxStorageWriteError<RxDocType>[];
      eventBulk: EventBulk<RxStorageChangeEvent<RxDocumentData<RxDocType>>, any>;
      attachmentsAdd: {
          documentId: string;
          attachmentId: string;
          attachmentData: RxAttachmentWriteData;
          digest: string;
      }[];
      attachmentsRemove: {
          documentId: string;
          attachmentId: string;
          digest: string;
      }[];
      attachmentsUpdate: {
          documentId: string;
          attachmentId: string;
          attachmentData: RxAttachmentWriteData;
          digest: string;
      }[];
      /**
       * Contains the non-error document row that
       * has the newest _meta.lwt time.
       * Empty if no successful write exists.
       */
      newestRow?: BulkWriteRowProcessed<RxDocType>;
  };
  