@dittolive/ditto
Version:
Ditto is a cross-platform SDK that allows apps to sync with and even without internet connectivity.
1,199 lines (1,180 loc) • 129 kB
TypeScript
/** @internal */
declare class KeepAlive {
/** @internal */
get isActive(): boolean;
/** @internal */
constructor();
/** @internal */
retain(id: string): void;
/** @internal */
release(id: string): void;
/** @internal */
currentIDs(): string[];
/** @internal */
countForID(id: string): number | null;
private static finalizationRegistry;
private intervalID;
private countsByID;
}
/** @internal */
type ObserverToken = string;
/** @internal */
interface ObserverManaging {
hasObserver(token: ObserverToken): boolean;
removeObserver(token: ObserverToken): void;
}
/** @internal */
type ObserverOptions = {
stopsWhenFinalized?: boolean;
};
/**
* Generic observer handle returned by various observation APIs. The observation
* remains active until the {@link stop | stop()} method is called explicitly or
* the observer instance is garbage collected. Therefore, to keep the observation
* alive, you have to keep a reference to the corresponding observer.
*/
declare class Observer {
/** @internal */
readonly observerManager: ObserverManaging;
/** @internal */
get token(): ObserverToken | undefined;
/** @internal */
readonly options?: ObserverOptions;
/** @internal */
constructor(observerManager: ObserverManaging, token: any, options?: ObserverOptions);
/**
* Returns `true` if the observer has been explicitly stopped via the `stop()`
* method. Otherwise returns `false`.
*/
get isStopped(): boolean;
/**
* Stops the observation. Calling this method multiple times has no effect.
*/
stop(): void;
private static finalizationRegistry;
private _token?;
private static finalize;
}
/**
* Error codes for FFI result.
*
* This should include all variants of `FfiError` in `ffi/src/result/error.rs`.
*
* @internal
*/
type FFIResultErrorCode = 'ActivationLicenseTokenExpired' | 'ActivationLicenseTokenInvalid' | 'ActivationLicenseUnsupportedFutureVersion' | 'ActivationNotActivated' | 'ActivationUnnecessary' | 'AuthenticationExpirationHandlerMissing' | 'Base64Invalid' | 'CborInvalid' | 'CborUnsupported' | 'Crdt' | 'DifferIdentityKeyPathInvalid' | 'DqlEvaluationError' | 'DqlInvalidQueryArgs' | 'DqlQueryCompilation' | 'DqlUnsupported' | 'IoAlreadyExists' | 'IoNotFound' | 'IoOperationFailed' | 'IoPermissionDenied' | 'JsFloatingStoreOperation' | 'LockedDittoWorkingDirectory' | 'EncryptionExtraneousPassphraseGiven' | 'ParameterQuery' | 'StoreDatabase' | 'StoreDocumentId' | 'StoreDocumentNotFound' | 'StoreTransactionReadOnly' | 'StoreQuery' | 'Transport' | 'Unknown' | 'Unsupported' | 'ValidationDepthLimitExceeded' | 'ValidationInvalidCbor' | 'ValidationInvalidDittoConfig' | 'ValidationInvalidJson' | 'ValidationNotAMap' | 'ValidationInvalidTransportConfig' | 'ValidationSizeLimitExceeded';
/**
* Represents an exception that occurred during a call into the Ditto FFI.
*
* Use the {@link throwOnErrorStatus | throwOnErrorStatus()} helper to
* automatically throw this error when an FFI call returns with a non-zero
* return value.
*
* @internal
*/
declare class DittoFFIError extends Error {
/**
* The code identifying this error.
*
* May be a numerical status code returned by an FFI call or an
* {@link FFIResultErrorCode} for errors returned on FFI result objects.
*
* @see {@link throwOnErrorStatus | throwOnErrorStatus()}
*/
readonly code: number | FFIResultErrorCode;
/**
* Only call this constructor after having called `FFI.ensureInitialized()`
* and `FFI.trace()`.
*
* @param code numerical status code returned by an FFI call or an
* {@link FFIResultErrorCode} for errors returned on FFI result objects
* @param messageOverride overrides the thread-local error message set in
* Ditto core
* @param messageFallback fallback message to use if the thread-local error
* message is empty
*/
constructor(code: number | FFIResultErrorCode, messageOverride?: string, messageFallback?: string);
}
/** @internal */
type Pointer<Type> = {
type: Type;
addr: string;
};
/** @internal */
declare const DittoCRDTTypeKey = "_ditto_internal_type_jkb12973t4b";
/** @internal */
type FFIQueryResultItem = 'dittoffi_query_result_item_t';
/** @internal */
type FFIQueryResult = 'dittoffi_query_result_t';
/** @internal */
type FFIDiffer = 'dittoffi_differ_t';
/** @internal */
type FFIDitto = 'CDitto_t';
/** @internal */
declare enum DittoCRDTType {
counter = 0,
register = 1,
attachment = 2,
rga = 3,
rwMap = 4
}
/** Various options to pass the web assembly module to Ditto. */
type WebAssemblyModule = RequestInfo | URL | Response | BufferSource | WebAssembly.Module | string | null;
interface DittoConfigConnectServer$1 {
type: 'server';
url: string;
}
interface DittoConfigConnectSmallPeersOnly$1 {
type: 'small_peers_only';
private_key?: string;
}
interface DittoConfig$1 {
database_id: string;
connect: DittoConfigConnectServer$1 | DittoConfigConnectSmallPeersOnly$1;
persistence_directory: string | null;
experimental: {};
}
/** @internal */
type UntypedAttachmentToken = {
id: string;
len: number | bigint;
metadata: AttachmentMetadata;
};
/** @internal */
type TypedAttachmentTokenV1 = {
[DittoCRDTTypeKey]?: DittoCRDTType.attachment;
_id: Uint8Array;
_len: number | bigint;
_meta: AttachmentMetadata;
};
/**
* Serves as a token for a specific attachment that you can pass to a call to
* {@link Store.fetchAttachment | ditto.store.fetchAttachment()}.
*
* @internal
*/
declare class AttachmentToken {
/** The attachment's ID. */
readonly id: string;
/** The attachment's size given as number of bytes. */
readonly len: number | bigint;
/** The attachment's metadata. */
readonly metadata: AttachmentMetadata;
/** @internal */
constructor(jsObj: UntypedAttachmentToken | TypedAttachmentTokenV1);
/** @internal */
readonly idBytes: Uint8Array;
/**
* Validate an input value that has a field `[FFI.DittoCRDTTypeKey]` and
* return its contents.
*
* @throws {Error} If the input is invalid.
* @returns {object} binary id, len and metadata of the attachment token
*/
private static validateTypedInput;
/**
* Validate an untyped input value and return its contents.
*
* Converts _unpadded_ base64-encoded ID in input to _padded_ base64-encoded
* ID before returning it as `Uint8Array`.
*
* @throws {@link DittoError} `store/attachment-token-invalid` If the input id
* is not a valid base64 string.
* @returns {object} binary id, len and metadata of the attachment token
*/
private static validateUntypedInput;
}
type ErrorCode = keyof typeof ERROR_CODES;
/**
* Error code and default error message for all Ditto error messages.
*
* Keys of this object define _error codes_ with each value containing the
* accompanying error description that is set as the default error message for
* errors instantiated with this code.
*
* Error codes may start with an error domain and a slash to group categories of
* errors together.
*/
declare const ERROR_CODES: {
/** Internal error for unexpected system states */
readonly internal: "An unexpected internal error occurred. Please get in touch with Ditto customer service to report this incident.";
/** Internal error with an unknown error cause */
readonly unknown: "An unexpected internal error occurred. Please get in touch with Ditto customer service to report this incident.";
/** Error when using a feature not supported by the current environment */
readonly unsupported: "The feature is not supported by the current environment.";
/** Error when authentication failed */
readonly 'authentication/failed-to-authenticate': "Ditto failed to authenticate.";
/** Error when the required expiration handler is not set before starting sync. */
readonly 'authentication/expiration-handler-missing': "The expiration handler must be set before starting sync.";
/** Error when a file or directory already exists */
readonly 'io/already-exists': "A file or directory already exists.";
/** Error when a file or directory could not be found */
readonly 'io/not-found': "A file or directory could not be found.";
/** Error when permission is denied for a file operation */
readonly 'io/permission-denied': "The operation failed due to insufficient permissions.";
/** Error when an IO operation failed for an unspecified reason. See error message for details. */
readonly 'io/operation-failed': "The operation failed.";
/** Error for invalid DQL query arguments. */
readonly 'query/arguments-invalid': "The query arguments were invalid.";
/** Errors that occur during evaluation of a query */
readonly 'query/evaluation': "The query could not be evaluated.";
/** Errors that occur during execution of a query */
readonly 'query/execution': "The query could not be executed.";
/** Error for an invalid DQL query. */
readonly 'query/invalid': "The query was invalid.";
/** Error for a query that uses DQL features not supported in this version or not supported by the currently used API. */
readonly 'query/unsupported': "The query contains unsupported features.";
/** Error for a failed query updating system parameters */
readonly 'query/parameter': "The query to update system parameters failed.";
/** Error in the storage backend. */
readonly 'store/backend': "An error occurred with the storage backend.";
/** Error for an invalid CRDT. */
readonly 'store/crdt': "An error occurred processing a CRDT.";
/** Error for a document not found. */
readonly 'store/document-not-found': "The document with the provided ID could not be found.";
/** Error for writing to a read-only transaction. */
readonly 'store/transaction-read-only': "A mutating DQL query was attempted using a read-only transaction.";
/** Error for an invalid document ID. */
readonly 'store/document-id': "The document ID is invalid.";
/** Error when the chosen persistence directory is already in use by another Ditto instance. */
readonly 'store/persistence-directory-locked': "The chosen persistence directory is already in use by another Ditto instance.";
/** Permission has been denied for a file operation when working with attachments. */
readonly 'store/attachment-file-permission-denied': "Permission has been denied for a file operation when working with attachments.";
/** The source file for an attachment does not exist. */
readonly 'store/attachment-file-not-found': "The source file for the attachment does not exist.";
/** Attachment could not be found. */
readonly 'store/attachment-not-found': "The attachment could not be found.";
/** Attachment token is invalid. */
readonly 'store/attachment-token-invalid': "The attachment token is invalid.";
/** An unclassified error while creating an attachment. */
readonly 'store/failed-to-create-attachment': "The attachment could not be created.";
/** An unclassified error while fetching an attachment. */
readonly 'store/failed-to-fetch-attachment': "The attachment could not be fetched.";
/** An error representing an invalid license token. */
readonly 'activation/license-token-verification-failed': "Please provide a valid license token.";
/** An error representing an expired license token. */
readonly 'activation/license-token-expired': "The license token expired. Please renew it.";
/** An error representing a token is in an unsupported future format. */
readonly 'activation/license-token-unsupported-future-version': "The provided license token is in an unsupported future format.";
/** The operation failed because it requires an activated Ditto instance. */
readonly 'activation/not-activated': "The operation failed because the Ditto instance has not yet been activated.";
/** Activation is unnecessary for this Ditto instance, because of its identity. */
readonly 'activation/unnecessary': "Activation is unnecessary for this Ditto instance, because of its identity.";
/** A validation error where the maximum depth limit was exceeded. */
readonly 'validation/depth-limit-exceeded': "The maximum depth limit has been exceeded.";
/** A validation error where the value is not valid CBOR. */
readonly 'validation/invalid-cbor': "The value provided is not valid CBOR.";
/** A validation error where the value is not valid JSON. */
readonly 'validation/invalid-json': "The value provided is not valid JSON.";
/** A validation error where the TransportConfig is invalid for the active platform. */
readonly 'validation/invalid-transport-config': "The TransportConfig is invalid for the active platform.";
/** A validation error where the {@link DittoConfig} is invalid. */
readonly 'validation/invalid-ditto-config': "The DittoConfig provided is invalid.";
/** A validation error where a value is required to be a JavaScript object */
readonly 'validation/not-an-object': "The value provided is not of type object.";
/** The value provided can not be serialized as JSON. */
readonly 'validation/not-json-compatible': "Value is not serializable as JSON.";
/** A validation error where a size limit was exceeded. */
readonly 'validation/size-limit-exceeded': "The size limit has been exceeded.";
/**
* Error when a passphrase was provided but the store is not encrypted.
*
* This error is not in use for the JavaScript SDK, which currently does not
* support encrypted stores.
*/
readonly 'encryption/extraneous-passphrase-given': "Unexpected passphrase provided for the currently unencrypted store.";
/** */
readonly 'differ/identity-key-path-invalid': "A provided identity key path is invalid.";
};
/**
* `DittoError` is a subclass of the default Javascript `Error`. You can
* identify specific errors programatically using the
* {@link DittoError.code | code} property.
*
* Please reference {@link ERROR_CODES} for a comprehensive list of
* possible error codes in this SDK version.
*
* @example
* Handling a specific error code:
* ```typescript
* import { Attachment, DittoError } from '@dittolive/ditto'
*
* let attachment: Attachment
* try {
* attachment = await ditto.store.newAttachment(filePath)
* } catch (error) {
* if (error instanceof DittoError && error.code === 'store/attachment-file-not-found') {
* // Handle a non-existing file
* }
* throw error // Rethrow any other error
* }
* ```
*/
declare class DittoError extends Error {
/**
* Use the error code to identify a specific error programatically.
*
* @see {@link ERROR_CODES} for a comprehensive list of possible
* error codes in this SDK version.
*/
readonly code: ErrorCode;
/** Some environments provide a stack trace that is attached to any error. */
readonly stack?: string;
/**
* @internal
* @param code string error code, see {@link ERROR_CODES}
* @param message optional error message that replace's the message for the given error code
* @throws {@link DittoError} `internal`: when supplied with an invalid error code
*/
constructor(code: ErrorCode, message?: string | null);
/**
* Create a {@link DittoError} from a {@link DittoFFIError}.
*
* The error message will be set to the optional `messageOverride` parameter
* if supplied, otherwise it will be taken from the `message` property of the
* given {@link DittoFFIError}.
*
* @internal
* @param code string error code from {@link ERROR_CODES}
* @param messageOverride optional string that will be used as the error
* message even if a thread-local error message has been retrieved from the
* FFI
* @returns {@link DittoError}
*/
static fromFFIError(ffiError: DittoFFIError, code: ErrorCode, messageOverride?: string): DittoError;
}
/**
* Wraps the given function to catch any {@link DittoFFIError} and rethrow it as
* a {@link DittoError}, mapping status codes of the {@link DittoFFIError} to
* error codes of the {@link DittoError} using the given `statusCodeMapping`.
*
* Use either this function or {@link mapFFIErrorsAsync} to wrap all calls into
* the FFI that can fail.
*
* If the given status code mapping contains error messages, they will replace
* any error message that is returned by the FFI.
*
* @internal
* @param closure function that can throw a {@link DittoFFIError}
* @param statusCodeMapping optional mapping of status codes of the
* {@link DittoFFIError} to error codes of the {@link DittoError}
* @throws {@link DittoError} when the wrapped function throws a {@link DittoFFIError}
*/
declare function mapFFIErrors<T>(closure: () => T, statusCodeMapping?: Partial<FFIErrorMapping>): T;
/**
* Wraps the given async function to catch any {@link DittoFFIError} and rethrow
* it as a {@link DittoError}, mapping status codes of the {@link DittoFFIError}
* to error codes of the {@link DittoError} using the given `statusCodeMapping`.
*
* Use either this function or {@link mapFFIErrors} to wrap any calls into the
* FFI that can fail.
*
* If the given status code mapping contains error messages, they will replace
* any error message that is returned by the FFI.
*
* @internal
* @param closure async function that can throw a {@link DittoFFIError}
* @param statusCodeMapping optional mapping of status codes of the
* {@link DittoFFIError} to error codes of the {@link DittoError}.
* @throws {@link DittoError} when the wrapped function throws a {@link DittoFFIError}
*/
declare function mapFFIErrorsAsync<T>(closure: () => Promise<T>, statusCodeMapping?: Partial<FFIErrorMapping>): Promise<T>;
/**
* Defines which status code of an FFI response should be mapped to which error
* code of a {@link DittoError}.
*
* The second element of the tuple is an optional string that will be used as
* the error message of the {@link DittoError} instead of the FFI error message
* if defined.
*
* If a key `default` is present, it will be used as the error code if no
* mapping for a given status code is found.
*
* @example
* ```typescript
* const statusCodeMapping: FFIErrorMapping = {
* '-1': ['activation/failed', 'It just didn\'t work out'],
* 'default': ['sdk/environment-incompatible']
* }
* ```
*
* @internal
*/
type FFIErrorMapping = Record<FFIResultErrorCode | number | 'default' | string, [
ErrorCode,
string?
]>;
/**
* Provides info about the authentication status.
*/
type AuthenticationStatus = {
/**
* Returns `true` if authenticated, otherwise returns `false`.
*/
isAuthenticated: boolean;
/**
* If authenticated, returns the `userID` if one was provided by the
* authentication service. Otherwise returns `null`.
*/
userID: string | null;
};
/**
* Represents the result of a login attempt.
*/
type LoginResult = {
/**
* JSON-formatted client info returned by the authentication webhook, if any.
* This field is populated for both successful and failed login attempts and
* is only `null` when no client info was provided by the webhook.
*
* See Ditto's online documentation for more information on how to provide
* client info using an authentication webhook.
*/
clientInfo: string | null;
/**
* If the login attempt was successful, this property will be `null`. If the
* login attempt failed, this property will contain a {@link DittoError} object with
* details about the error.
*/
error: DittoError | null;
};
/**
* A function type that handles authentication expiration events for Ditto.
*
* This handler is called when the authentication for a Ditto instance has or is
* about to expire, or if authentication has not yet occurred. It provides the
* relevant {@link Ditto} instance and the time interval (in seconds) until
* expiration. You can use this to login or to perform other necessary actions
* before authentication expires.
*
* **Important:** When using the _server_ connection mode (i.e.
* {@link DittoConfigConnectServer}), you **must** set an expiration handler via
* {@link Authenticator.setExpirationHandler | ditto.auth.setExpirationHandler() }.
* Otherwise, {@link Sync.start | ditto.sync.start()} will throw
* {@link DittoError} with code `authentication/expiration-handler-missing`.
*
* @param ditto The {@link Ditto} instance whose authentication is expiring.
* @param timeUntilExpiration The time interval, in seconds, until
* authentication expires.
*/
type AuthenticationExpirationHandler = (ditto: Ditto, timeUntilExpiration: number) => Promise<any> | any;
/**
* Provides access to authentication information and methods for logging on to
* Ditto Cloud. Relevant when using a `server` connection mode.
*/
declare class Authenticator {
/**
* Returns `true` if authentication is available and the login methods can be
* used, otherwise returns `false`. Currently, authentication is only
* available if Ditto was initialized with an "server" connection mode
* (i.e. {@link DittoConfigConnectServer}).
*/
readonly loginSupported: boolean;
/**
* The built-in development authentication provider to be used together with
* development authentication tokens.
*
* @see {@link Authenticator.login | Authenticator.login()} for more information
* about the `provider` parameter.
*/
static get DEVELOPMENT_PROVIDER(): string;
/**
* The handler that will be called when authentication for this Ditto instance
* is about to expire.
*
* **Important:** If the Ditto instance is configured with a
* {@link DittoConfigConnectServer} this property **must** be set and the
* handler **must** properly authenticate when called.
*
* @see {@link setExpirationHandler}
*/
get expirationHandler(): AuthenticationExpirationHandler | null;
/**
* Sets the handler that will be called when authentication for this Ditto
* instance is about to expire.
*
* Assign a handler function to be notified before authentication expires,
* allowing you to login or perform other necessary actions.
*
* @see {@link expirationHandler}
*/
setExpirationHandler(handler: AuthenticationExpirationHandler | null): Promise<void>;
/**
Returns the current authentication status.
*/
get status(): AuthenticationStatus;
/**
* Log in to Ditto with a third-party token.
*
* Returns a promise that resolves to a `LoginResult` object. When the login
* attempt is successful, the `error` property of the response will be `null`,
* otherwise it will contain a {@link DittoError} object with details about
* the error.
*
* If the authentication service provides additional client info, it will be
* returned in the `clientInfo` property of the response, whether the login
* attempt was successful or not.
*
* @param token The authentication token required to log in.
* @param provider The name of the authentication provider. Use
* {@link Authenticator.DEVELOPMENT_PROVIDER} with development tokens.
* @throws {@link DittoError} `authentication/failed-to-authenticate` if the
* Ditto instance is closed.
* @returns A promise that resolves to a `LoginResult` object.
*/
login(token: string, provider: string): Promise<LoginResult>;
/**
* Log out of Ditto.
*
* This will stop sync, shut down all replication sessions, and remove any
* cached authentication credentials. Note that this does not remove any data
* from the store. If you wish to delete data from the store then use the
* optional `cleanupFn` parameter to perform any required cleanup.
*
* @param cleanupFn An optional function that will be called with the relevant
* [Ditto] instance as the sole argument that allows you to perform any
* required cleanup of the store as part of the logout process.
*/
logout(cleanupFn?: (ditto: Ditto) => void): Promise<void>;
observeStatus(callback: (authenticationStatus: AuthenticationStatus) => void): Observer;
/** @internal */
constructor(keepAlive: KeepAlive, ditto: Ditto);
/** @internal */
close(): void;
/** @internal */
private readonly ditto;
/** @internal */
private keepAlive;
/** @internal */
private observerManager;
/** @internal */
private _status;
/** @internal */
private _expirationHandler;
private authenticationStatusUpdated;
private updateAndNotify;
private makeFFFIAuthenticationExpirationHandler;
}
/**
* Specifies how this instance discovers and connects to peers, including
* network settings and authentication options. This is a substructure of
* {@link DittoConfig}.
*/
type DittoConfigConnect = DittoConfigConnectServer | DittoConfigConnectSmallPeersOnly;
/**
* Connects this Ditto instance to a Big Peer at the specified URL. This is a
* substructure of {@link DittoConfig}.
*
* **Important**: For sync to work with server connections, Ditto requires (a) a
* {@link AuthenticationExpirationHandler} to be set via
* {@link Authenticator.setExpirationHandler | ditto.auth.setExpirationHandler()}, and
* (b) that handler to properly authenticate when requested.
* {@link Sync.start | startSync()} will throw if the expiration handler is
* not set.
*/
interface DittoConfigConnectServer {
mode: 'server';
url: string;
}
/**
* Restricts connectivity to small peers only, optionally using a shared secret
* (in the form of a private key) for authentication.
*
* If a {@link DittoConfigConnectSmallPeersOnly.privateKey | privateKey} is
* provided, it will be used as a shared secret for authenticating peer-to-peer
* connections. The default value is `null`, which means no encryption is used
* in transit.
*/
interface DittoConfigConnectSmallPeersOnly {
mode: 'smallPeersOnly';
privateKey?: string | null;
}
/**
* A configuration object for initializing a {@link Ditto} instance.
*
* Encapsulates all the parameters required to configure a Ditto instance,
* including identity, connectivity, and persistence.
*/
declare class DittoConfig {
/**
* The default database ID, used when no database ID is provided.
*
* @see {@link DittoConfig.databaseID | database_id} for more information about the
* `databaseID` parameter.
*/
static get DEFAULT_DATABASE_ID(): string;
/**
* Returns a default {@link DittoConfig} instance with standard settings.
*
* This is useful as a starting point or for quickly creating a basic
* configuration, but for production use you should customize the
* configuration as needed.
*/
static get default(): DittoConfig;
/**
* The unique identifier for the Ditto instance.
*
* This must be a valid UUID string. You can find the ID in the Ditto portal,
* or provide your own if you only need to sync with a small set of peers.
*
* Note: "Database ID" was referred to as "App ID" in older versions of the
* SDK.
*
* @see {@link DittoConfig.DEFAULT_DATABASE_ID | DEFAULT_DATABASE_ID} for the
* default database ID used when no ID is provided.
*/
databaseID: string;
/**
* The connectivity configuration for this Ditto instance.
*
* Specifies how this instance discovers and connects to peers, including
* network settings and authentication options.
*/
connect: DittoConfigConnect;
/**
* The persistence directory used by Ditto to persist data.
*
* This property can have three types of values:
* - **Absolute path**: A string with an absolute file path (e.g.,
* `/Users/joe/some/path/to/my-project.ddb`)
* - **Relative path**: A string with a relative file path (e.g.,
* `some/path/to/my-project.ddb`)
* - **undefined**: Uses the default persistence directory
*
* When a relative path is set, it will be resolved relative to
* {@link Ditto.DEFAULT_ROOT_DIRECTORY}. When this is `undefined`, Ditto will
* use a default directory name of `ditto-{id}` within
* {@link Ditto.DEFAULT_ROOT_DIRECTORY}, where `{id}` is the lowercase version
* of the {@link DittoConfig.databaseID | id} set in this `DittoConfig`.
*
* To access the final resolved absolute path after creating a Ditto instance,
* use {@link Ditto.absolutePersistenceDirectory}. This property will always
* return the effective absolute file path being used, regardless of whether
* you provided an absolute path, relative path, or `undefined`.
*
* Note: It is not recommended to directly read from or write to this directory, as
* its structure and contents are managed by Ditto and may change in future
* versions.
*
* Note: When {@link Logger} is enabled, logs may be written to this directory even
* after a Ditto instance has been deallocated. Please refer to the
* documentation of {@link Logger} for more information.
*
* @see {@link Ditto.absolutePersistenceDirectory}
*/
persistenceDirectory?: string;
/**
* Initializes a new {@link DittoConfig} instance with the new API.
*/
constructor(id: string, connect: DittoConfigConnect, persistenceDirectory?: string);
/**
* Returns true if the receiver has been frozen using
* {@link DittoConfig.freeze | freeze()}.
*/
get isFrozen(): boolean;
/**
* Deep freezes the receiver such that it can't be modified anymore.
*
* Use {@link DittoConfig.copy | copy()} to create a copy of the receiver that
* is not frozen.
*
* @see {@link DittoConfig.isFrozen}
*/
freeze(): Readonly<this>;
/**
* Returns a deep copy of the receiver.
*
* The copy is not frozen, so it's properties can be modified.
*
* Warning: This does not create copies of
* {@link AuthenticationExpirationHandler | authentication expiration handlers}
* referenced by the config. Changes inside the handlers will be reflected in
* the copy.
*/
copy(): DittoConfig;
private _isFrozen;
/** @internal */
get requiresOfflineLicenseToken(): boolean;
/**
* @param legacyPersistenceDirectory - SDKS-3187: optional v4 default path for
* migration fallback. Passed by Ditto.open()/openSync() when the user hasn't
* set an explicit persistenceDirectory.
* @internal
*/
toCBOR(legacyPersistenceDirectory?: string): Uint8Array;
/**
* Validates the config structure.
*
* Only covers type and presence validation as anything beyond that is handled
* by core.
*/
private validate;
}
/**
* Converts a FFI {@link DittoConfig} into a {@link DittoConfig} instance.
*
* @internal
*/
declare function fromFFICBORData(data: DittoConfig$1): DittoConfig;
/**
* The types of attachment fetch events that can be delivered to an attachment
* fetcher's `callback`.
*/
type AttachmentFetchEventType = 'Completed' | 'Progress' | 'Deleted';
/**
* An attachment fetch event used when the attachment's download has completed.
*/
type AttachmentFetchEventCompleted = {
type: 'Completed';
attachment: Attachment;
};
/**
* An attachment fetch event used when the attachment's download progressed but
* is not yet complete.
*/
type AttachmentFetchEventProgress = {
type: 'Progress';
totalBytes: number | bigint;
downloadedBytes: number | bigint;
};
/**
* An attachment fetch event used when the attachment is deleted.
*/
type AttachmentFetchEventDeleted = {
type: 'Deleted';
};
/**
* A representation of the events that can occur in relation to an attachment
* fetch.
*
* There are three different attachment fetch events: `Completed`, `Progress`,
* or `Deleted`.
*
* There will be at most one `Completed` or `Deleted` event per attachment
* fetch. There can be many `Progress` events delivered for each attachment
* fetch.
*
* Updates relating to an attachment fetch are delivered by registering an
* {@link AttachmentFetcher} through a call to
* {@link Store["fetchAttachment"] | ditto.store.fetchAttachment()}.
*/
type AttachmentFetchEvent = AttachmentFetchEventCompleted | AttachmentFetchEventProgress | AttachmentFetchEventDeleted;
/**
* These objects are returned by calls to
* {@link Store.fetchAttachment | ditto.store.fetchAttachment()}
* and allow you to stop an in-flight attachment fetch.
*/
declare class AttachmentFetcher implements PromiseLike<Attachment | null> {
/**
* Returns a promise for the attachment that you can `await`.
*
* The promise is rejected if an error occurs during the fetch. Note that the
* `AttachmentFetcher` itself implements `PromiseLike`, so you can `await` it
* directly.
*/
readonly attachment: Promise<Attachment>;
/**
* Stops fetching the associated attachment and cleans up any associated
* resources.
*
* Note that you are not required to call `stop()` once your attachment fetch
* operation has finished. The method primarily exists to allow you to cancel
* an attachment fetch request while it is ongoing if you no longer wish for
* the attachment to be made available locally to the device.
*/
stop(): void;
/** @internal */
readonly cancelTokenPromise: Promise<number | bigint | null> | null;
/** @internal */
readonly ditto: Ditto;
/** @internal */
readonly id: string;
/** @internal */
readonly tokenIDBytes: Uint8Array;
/** @internal */
readonly token: UntypedAttachmentToken;
/** @internal */
then<TResult1 = any, TResult2 = never>(onfulfilled?: ((value: any) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined): PromiseLike<TResult1 | TResult2>;
/** @internal */
constructor(ditto: Ditto, token: UntypedAttachmentToken, eventHandler?: (attachmentFetchEvent: AttachmentFetchEvent) => void);
/**
* `true` if the fetcher has completed or was stopped.
*
* @internal
*/
get isStopped(): boolean;
/**
* This function is defined while a fetch is in progress and is used to reject
* the promise `this.attachment` when the fetch is canceled.
*
* @internal
*/
private rejectPendingFetch;
}
declare const CUSTOM_INSPECT_SYMBOL: unique symbol;
/**
* Represents a single match of a DQL query, similar to a “row” in SQL terms.
* It’s a reference type serving as a “cursor”, allowing for efficient access of
* the underlying data in various formats.
*
* The {@link QueryResultItem.value | value } property is lazily materialized
* and kept in memory until it goes out of scope. To reduce the memory
* footprint, structure your code such that items can be processed as a stream,
* i.e. one by one (or in batches) and
* {@link QueryResultItem.dematerialize | dematerialize() } them right after
* use.
*
* @template T The type of the item's {@link QueryResultItem.value | value }.
*/
declare class QueryResultItem<T = any> {
/**
* Returns the content as a materialized object.
*
* The item's value is
* {@link QueryResultItem.materialize | materialized() } on first access
* and subsequently on each access after performing
* {@link QueryResultItem.dematerialize | dematerialize() }. Once
* materialized, the value is kept in memory until explicitly
* {@link QueryResultItem.dematerialize | dematerialize() }-ed or the item
* goes out of scope.
*/
get value(): T;
/**
* Returns `true` if value is currently held materialized in memory, otherwise
* returns `false`.
*
* See {@link QueryResultItem.materialize | materialize()} and
* {@link QueryResultItem.dematerialize | dematerialize()}.
*/
get isMaterialized(): boolean;
/**
* Loads the CBOR representation of the item's content, decodes it as an
* object so it can be accessed via {@link QueryResultItem.value | value }.
* Keeps the object in memory until
* {@link QueryResultItem.dematerialize | dematerialize() } is called. No-op
* if {@link QueryResultItem.value | value } is already materialized.
*/
materialize(): void;
/**
* Releases the materialized value from memory. No-op if item is not
* materialized.
*/
dematerialize(): void;
/**
* Returns the content of the item as CBOR data.
*
* Important: The returned CBOR data is not cached, make sure to call this
* method once and keep it for as long as needed.
*/
cborData(): Uint8Array;
/**
* Returns the content of the item as a JSON string.
*
* Important: The returned JSON string is not cached, make sure to call this
* method once and keep it for as long as needed.
*/
jsonString(): string;
/**
* Defines a custom inspect representation for Node.js that will be used when
* the object is inspected with console.log() or util.inspect().
*
* @internal
*/
[CUSTOM_INSPECT_SYMBOL](_depth: number, _inspectOptions: any, inspect: any): string;
private materializedValue;
/** @internal */
constructor();
/** @internal */
static fromJSON(jsonData: string): QueryResultItem<any>;
/** @internal */
deref(): Pointer<FFIQueryResultItem>;
}
/**
* Represents results returned when executing a DQL query containing a
* {@link QueryResultItem} for each match.
*
* More info, such as metrics, will be provided in the near future.
*
* @template T The type of items in the query result.
*/
declare class QueryResult<T = any> {
/**
* Individual items matching a DQL query.
*/
readonly items: QueryResultItem<T>[];
/**
* IDs of documents that were mutated _locally_ by a _mutating_ DQL query
* passed to {@link Store.execute | `execute()`}. Empty array if no documents
* have been mutated.
*
* **Note: Query results received from a {@link StoreObserver} never contain
* mutated document IDs because a store observer is always registered using a
* non-mutating `SELECT` query.
/**
* IDs of documents that were mutated _locally_ by a _mutating_ DQL query
* passed to {@link Store.execute | `execute()`}. Empty array if no documents
* have been mutated.
*
* **Note: Query results received from a {@link StoreObserver} never contain
* mutated document IDs because a store observer is always registered using a
* non-mutating `SELECT` query.
*
* **Important:** The returned document IDs are not cached, make sure to call
* this method once and keep the return value for as long as needed.
*
* @returns an array of document ID values as JSON-compatible values
*/
mutatedDocumentIDsV2(): any[];
/**
* The commit ID associated with this query result, if any.
*
* This ID uniquely identifies the commit in which this change was accepted
* into the _local_ store. The commit ID is available for all query results
* involving insertions, updates, or deletions. This ID can be used to track
* whether a local change has been synced to other peers.
*
* For write transactions, the commit ID is only available after the
* transaction has been successfully committed. Queries executed within an
* uncommitted transaction will not have a commit ID.
*/
get commitID(): bigint | null;
/** @internal */
constructor(queryResultPointer: Pointer<FFIQueryResult>);
}
/**
* A store observation handler is called whenever an active store observer
* receives new results.
*
* @template T The type of items in the query result.
*/
type StoreObservationHandler<T = any> = (queryResult: QueryResult<T>) => void;
/**
* A store observation handler is called whenever an active store observer
* receives new results.
*
* Call `signalNext()` to signal that the handler is ready to receive the next
* callback from the store observer.
*
* @template T The type of items in the query result.
*/
type StoreObservationHandlerWithSignalNext<T = any> = (queryResult: QueryResult<T>, signalNext: () => any) => void;
/**
* A store observer invokes a given handler whenever results for its query
* change.
*
* The store observer will remain active until it is {@link cancel | cancelled},
* or the Ditto instance managing the observer has been
* {@link Ditto.close | closed}.
*
* Create a store observer by calling
* {@link Store.registerObserver | `ditto.store.registerObserver()`}.
*
* {@link StoreObserver.queryString | query} nor validated against it.
* @template S The type of query arguments.
*/
declare class StoreObserver {
/**
* The Ditto instance this store observer is registered with.
*/
readonly ditto: Ditto;
/**
* The query string of the store observer (as passed when registering it).
*/
get queryString(): string;
/**
* The query arguments of the store observer (as passed when registering it).
*/
get queryArguments(): Readonly<any> | undefined;
/**
* The query arguments of the store observer, serialized as CBOR, (as passed
* when adding it to the store).
*
* Note that any {@link Attachment} values passed in as query arguments when
* creating this store observer will be represented by a serialized version of
* that attachment.
*/
get queryArgumentsCBORData(): Uint8Array | undefined;
/**
* The query arguments of the store observer, serialized as JSON, (as passed
* when adding it to the store).
*
* Note that any {@link Attachment} values passed in as query arguments when
* creating this store observer will be represented by a serialized version of
* that attachment.
*/
get queryArgumentsJSONString(): string | undefined;
/**
* Convenience property, returns `true` once the store observer has been
* cancelled.
*/
get isCancelled(): boolean;
/**
* Cancels the store observer and unregisters it. No-op if the store observer
* has already been cancelled.
*/
cancel(): void;
/** @internal */
constructor(ditto: Ditto);
private deref;
}
/**
* Defines the interface for executing DQL queries. Implemented by
* {@link Store | Store} and {@link Transaction | Transaction}.
*/
interface QueryExecuting {
/**
* Executes a DQL query and returns matching items as a query result.
*
* **Note:** only returns results from the local store without waiting for any
* {@link SyncSubscription | sync subscriptions} to have caught up with the
* latest changes. Only use this method if your program must proceed with
* immediate results. Use a {@link StoreObserver | store observer} to receive
* updates to query results as soon as they have been synced to this peer.
*
* @param query A string containing a valid query expressed in DQL.
* @param args An object of values keyed by the placeholder name
* without the leading `:`. Example: `{ "name": "John" }` for a query like
* `SELECT * FROM people WHERE name = :name`.
* @template T The type of items returned by the query. This is a convenience
* type that is neither inferred from the `query` parameter nor validated
* against it.
* @template U The type of the query arguments
* @returns A promise for a {@link QueryResult} containing a
* {@link QueryResultItem} for each match.
* @throws {@link DittoError} `query/invalid`: if `query` argument is not a
* string or not valid DQL.
* @throws {@link DittoError} `query/arguments-invalid`: if `args`
* argument is invalid (e.g. contains unsupported types).
* @throws {@link DittoError} `transaction-read-only`: if a mutating DQL query
* was attempted using a read-only transaction. (only for
* the `transaction.execute()` API).
* @throws {@link DittoError} may throw other errors.
*/
execute<T = any, U extends DQLQueryArguments = DQLQueryArguments>(query: string, args?: U): Promise<QueryResult<T>>;
}
/** Encapsulates information about a transaction.
*
* @see {@link Store.transaction | ditto.store.transaction()}
*/
declare class TransactionInfo {
/** A globally unique ID of the transaction. */
id: string;
/**
* The user hint passed when creating the transaction, useful
* for debugging and testing.
*/
hint?: string | undefined;
/**
* Indicates whether mutating DQL statements can be executed in the
* transaction. Defaults to `false`.
*/
isReadOnly: boolean;
constructor(id: string, isReadOnly: boolean, hint?: string);
}
/**
* Represents an action that completes a transaction, by either committing it or
* rolling it back.
*/
type TransactionCompletionAction = 'commit' | 'rollback';
/**
* Represents a transaction in the Ditto store.
*
* A `Transaction` groups multiple operations into a single atomic unit,
* ensuring that all operations within the transaction are either fully applied
* or not applied at all, thereby maintaining data integrity.
*
* For more information on creating and using transactions, refer to the
* {@link Store.transaction | ditto.store.transaction()} method. For a comprehensive guide on
* transactions, please visit the
* [Ditto documentation](https://ditto.com/link/sdk-latest-crud-transactions).
*/
declare class Transaction implements QueryExecuting {
/** The store this transaction belongs to. */
readonly store: Store;
constructor(store: Store);
/** Provides information about the current transaction. */
get info(): TransactionInfo;
execute<T = any, U extends DQLQueryArguments = DQLQueryArguments>(query: string, queryArguments?: U): Promise<QueryResult<T>>;
/** @internal */
complete(action: TransactionCompletionAction): Promise<TransactionCompletionAction>;
}
/**
* Interface representing options for a transaction.
*/
type TransactionOptions = {
/**
* Indicates whether the transaction is read-only. Defaults to `false`.
*/
isReadOnly?: boolean;
/**
* A hint for the transaction, useful for debugging and testing.
* Defaults to `null`.
*/
hint?: string;
};
/**
* The entrypoint for all actions that relate to data stored by Ditto. Provides
* access to collections, a write transaction API, and a query hash API.
*
* You don't create one directly but can access it from a particular
* {@link Ditto} instance via its {@link Ditto.store | store} property.
*/
declare class Store implements QueryExecuting {
/** The {@link Ditto} instance this store belongs to. */
readonly ditto: Ditto;
/**
* All currently active store observers.
*
* **Note:** Manage store observers using
* {@link registerObserver | registerObserver()} to register a new store
* observer and {@link StoreObserver.cancel | StoreObserver.cancel()} to
* remove an existing store observer.
*
* @throws when this Ditto instance has been closed.
*/
get observers(): Readonly<Array<StoreObserver>>;
/**
* All currently active attachment fetchers.
*
* **Note:** Manage attachment fetchers using
* {@link fetchAttachment | fetchAttachment()} to start a new attachment fetch
* and {@link AttachmentFetcher.stop | AttachmentFetcher.stop()} to cancel
* an existing attachment fetch.
*/
readonly attachmentFetchers: Readonly<Array<AttachmentFetcher>>;
/** @internal */
get transactions(): TransactionInfo[];
/**
* Register a handler to be called whenever a query's results change in the
* local store.
*
* Convenience method, same as
* {@link registerObserverWithSignalNext | registerObserverWithSignalNext()},
* except that here, the next invocation of the observation handler is
* triggered automatically instead of having to call the passed in
* `signalNext` function.
*
* @param query A string containing a valid query expressed in DQL.
* @param observationHandler A function that is called whenever the query's
* results change. The function is passed a {@link QueryResult} containing a
* {@link QueryResultItem} for each match.
* @param queryArguments An object of values keyed by the placeholder name
* without the leading `:`. Example: `{ "name": "Joanna" }` for a query like
* `SELECT * FROM people WHERE name = :name`.
* @template T The type of items returned by the query. This is a convenience
* type that is neither inferred from the `query` parameter nor validated
* against it.
* @returns A {@link StoreObserver} that can be used to cancel the
* observation.
* @throws {@link DittoError} `query/invalid`: if `query` argument is not a
* string or not valid DQL.
* @throws {@link DittoError} `query/arguments-invalid`: if `queryArguments`
* argument is invalid (e.g. contains unsupported types).
* @throws {@link DittoError} `query/unsupported`: if the query is not a
* `SELECT` query.
* @throws {@link DittoError} may throw other errors.
*/
registerObserver<T = any>(query: string, observationHandler: StoreObservationHandler<T>, queryArguments?: DQLQueryArguments): StoreObserver;
/**
* Registers and returns a store observer for a query, configuring Ditto to
* trigger the passe