import { ILogger } from 'js-logger';
import { SyncStatus, SyncStatusOptions } from '../../../db/crud/SyncStatus.js';
import { BaseListener, BaseObserver, BaseObserverInterface, Disposable } from '../../../utils/BaseObserver.js';
import { BucketStorageAdapter } from '../bucket/BucketStorageAdapter.js';
import { AbstractRemote, FetchStrategy } from './AbstractRemote.js';
import { StreamingSyncRequestParameterType } from './streaming-sync-types.js';
export declare enum LockType {
    CRUD = "crud",
    SYNC = "sync"
}
export declare enum SyncStreamConnectionMethod {
    HTTP = "http",
    WEB_SOCKET = "web-socket"
}
export declare enum SyncClientImplementation {
    /**
     * Decodes and handles sync lines received from the sync service in JavaScript.
     *
     * This is the default option.
     *
     * @deprecated Don't use {@link SyncClientImplementation.JAVASCRIPT} directly. Instead, use
     * {@link DEFAULT_SYNC_CLIENT_IMPLEMENTATION} or omit the option. The explicit choice to use
     * the JavaScript-based sync implementation will be removed from a future version of the SDK.
     */
    JAVASCRIPT = "js",
    /**
     * This implementation offloads the sync line decoding and handling into the PowerSync
     * core extension.
     *
     * @experimental
     * While this implementation is more performant than {@link SyncClientImplementation.JAVASCRIPT},
     * it has seen less real-world testing and is marked as __experimental__ at the moment.
     *
     * ## Compatibility warning
     *
     * The Rust sync client stores sync data in a format that is slightly different than the one used
     * by the old {@link JAVASCRIPT} implementation. When adopting the {@link RUST} client on existing
     * databases, the PowerSync SDK will migrate the format automatically.
     * Further, the {@link JAVASCRIPT} client in recent versions of the PowerSync JS SDK (starting from
     * the version introducing {@link RUST} as an option) also supports the new format, so you can switch
     * back to {@link JAVASCRIPT} later.
     *
     * __However__: Upgrading the SDK version, then adopting {@link RUST} as a sync client and later
     * downgrading the SDK to an older version (necessarily using the JavaScript-based implementation then)
     * can lead to sync issues.
     */
    RUST = "rust"
}
/**
 * The default {@link SyncClientImplementation} to use.
 *
 * Please use this field instead of {@link SyncClientImplementation.JAVASCRIPT} directly. A future version
 * of the PowerSync SDK will enable {@link SyncClientImplementation.RUST} by default and remove the JavaScript
 * option.
 */
export declare const DEFAULT_SYNC_CLIENT_IMPLEMENTATION = SyncClientImplementation.JAVASCRIPT;
/**
 * Abstract Lock to be implemented by various JS environments
 */
export interface LockOptions<T> {
    callback: () => Promise<T>;
    type: LockType;
    signal?: AbortSignal;
}
export interface AbstractStreamingSyncImplementationOptions extends RequiredAdditionalConnectionOptions {
    adapter: BucketStorageAdapter;
    subscriptions: SubscribedStream[];
    uploadCrud: () => Promise<void>;
    /**
     * An identifier for which PowerSync DB this sync implementation is
     * linked to. Most commonly DB name, but not restricted to DB name.
     */
    identifier?: string;
    logger?: ILogger;
    remote: AbstractRemote;
}
export interface StreamingSyncImplementationListener extends BaseListener {
    /**
     * Triggered whenever a status update has been attempted to be made or
     * refreshed.
     */
    statusUpdated?: ((statusUpdate: SyncStatusOptions) => void) | undefined;
    /**
     * Triggers whenever the status' members have changed in value
     */
    statusChanged?: ((status: SyncStatus) => void) | undefined;
}
/**
 * Configurable options to be used when connecting to the PowerSync
 * backend instance.
 */
export type PowerSyncConnectionOptions = Omit<InternalConnectionOptions, 'serializedSchema'>;
export interface InternalConnectionOptions extends BaseConnectionOptions, AdditionalConnectionOptions {
}
/** @internal */
export interface BaseConnectionOptions {
    /**
     * A set of metadata to be included in service logs.
     */
    appMetadata?: Record<string, string>;
    /**
     * Whether to use a JavaScript implementation to handle received sync lines from the sync
     * service, or whether this work should be offloaded to the PowerSync core extension.
     *
     * This defaults to the JavaScript implementation ({@link SyncClientImplementation.JAVASCRIPT})
     * since the ({@link SyncClientImplementation.RUST}) implementation is experimental at the moment.
     */
    clientImplementation?: SyncClientImplementation;
    /**
     * The connection method to use when streaming updates from
     * the PowerSync backend instance.
     * Defaults to a HTTP streaming connection.
     */
    connectionMethod?: SyncStreamConnectionMethod;
    /**
     * The fetch strategy to use when streaming updates from the PowerSync backend instance.
     */
    fetchStrategy?: FetchStrategy;
    /**
     * These parameters are passed to the sync rules, and will be available under the`user_parameters` object.
     */
    params?: Record<string, StreamingSyncRequestParameterType>;
    /**
     * Whether to include streams that have `auto_subscribe: true` in their definition.
     *
     * This defaults to `true`.
     */
    includeDefaultStreams?: boolean;
    /**
     * The serialized schema - mainly used to forward information about raw tables to the sync client.
     */
    serializedSchema?: any;
}
/** @internal */
export interface AdditionalConnectionOptions {
    /**
     * Delay for retrying sync streaming operations
     * from the PowerSync backend after an error occurs.
     */
    retryDelayMs?: number;
    /**
     * Backend Connector CRUD operations are throttled
     * to occur at most every `crudUploadThrottleMs`
     * milliseconds.
     */
    crudUploadThrottleMs?: number;
}
/** @internal */
export interface RequiredAdditionalConnectionOptions extends Required<AdditionalConnectionOptions> {
    subscriptions: SubscribedStream[];
}
export interface StreamingSyncImplementation extends BaseObserverInterface<StreamingSyncImplementationListener>, Disposable {
    /**
     * Connects to the sync service
     */
    connect(options?: InternalConnectionOptions): Promise<void>;
    /**
     * Disconnects from the sync services.
     * @throws if not connected or if abort is not controlled internally
     */
    disconnect(): Promise<void>;
    getWriteCheckpoint: () => Promise<string>;
    hasCompletedSync: () => Promise<boolean>;
    isConnected: boolean;
    lastSyncedAt?: Date;
    syncStatus: SyncStatus;
    triggerCrudUpload: () => void;
    waitForReady(): Promise<void>;
    waitForStatus(status: SyncStatusOptions): Promise<void>;
    waitUntilStatusMatches(predicate: (status: SyncStatus) => boolean): Promise<void>;
    updateSubscriptions(subscriptions: SubscribedStream[]): void;
}
export declare const DEFAULT_CRUD_UPLOAD_THROTTLE_MS = 1000;
export declare const DEFAULT_RETRY_DELAY_MS = 5000;
export declare const DEFAULT_STREAMING_SYNC_OPTIONS: {
    retryDelayMs: number;
    crudUploadThrottleMs: number;
};
export type RequiredPowerSyncConnectionOptions = Required<BaseConnectionOptions>;
export declare const DEFAULT_STREAM_CONNECTION_OPTIONS: RequiredPowerSyncConnectionOptions;
export type SubscribedStream = {
    name: string;
    params: Record<string, any> | null;
};
export declare abstract class AbstractStreamingSyncImplementation extends BaseObserver<StreamingSyncImplementationListener> implements StreamingSyncImplementation {
    protected _lastSyncedAt: Date | null;
    protected options: AbstractStreamingSyncImplementationOptions;
    protected abortController: AbortController | null;
    protected uploadAbortController: AbortController | null;
    protected crudUpdateListener?: () => void;
    protected streamingSyncPromise?: Promise<void>;
    protected logger: ILogger;
    private activeStreams;
    private isUploadingCrud;
    private notifyCompletedUploads?;
    private handleActiveStreamsChange?;
    syncStatus: SyncStatus;
    triggerCrudUpload: () => void;
    constructor(options: AbstractStreamingSyncImplementationOptions);
    waitForReady(): Promise<void>;
    waitForStatus(status: SyncStatusOptions): Promise<void>;
    waitUntilStatusMatches(predicate: (status: SyncStatus) => boolean): Promise<void>;
    get lastSyncedAt(): Date | undefined;
    get isConnected(): boolean;
    dispose(): Promise<void>;
    abstract obtainLock<T>(lockOptions: LockOptions<T>): Promise<T>;
    hasCompletedSync(): Promise<boolean>;
    getWriteCheckpoint(): Promise<string>;
    protected _uploadAllCrud(): Promise<void>;
    connect(options?: PowerSyncConnectionOptions): Promise<void>;
    disconnect(): Promise<void>;
    /**
     * @deprecated use [connect instead]
     */
    streamingSync(signal?: AbortSignal, options?: PowerSyncConnectionOptions): Promise<void>;
    private collectLocalBucketState;
    /**
     * Older versions of the JS SDK used to encode subkeys as JSON in {@link OplogEntry.toJSON}.
     * Because subkeys are always strings, this leads to quotes being added around them in `ps_oplog`.
     * While this is not a problem as long as it's done consistently, it causes issues when a database
     * created by the JS SDK is used with other SDKs, or (more likely) when the new Rust sync client
     * is enabled.
     *
     * So, we add a migration from the old key format (with quotes) to the new one (no quotes). The
     * migration is only triggered when necessary (for now). The function returns whether the new format
     * should be used, so that the JS SDK is able to write to updated databases.
     *
     * @param requireFixedKeyFormat Whether we require the new format or also support the old one.
     *        The Rust client requires the new subkey format.
     * @returns Whether the database is now using the new, fixed subkey format.
     */
    private requireKeyFormat;
    protected streamingSyncIteration(signal: AbortSignal, options?: PowerSyncConnectionOptions): Promise<RustIterationResult | null>;
    private legacyStreamingSyncIteration;
    private rustSyncIteration;
    private updateSyncStatusForStartingCheckpoint;
    private applyCheckpoint;
    protected updateSyncStatus(options: SyncStatusOptions): void;
    private delayRetry;
    updateSubscriptions(subscriptions: SubscribedStream[]): void;
}
interface RustIterationResult {
    immediateRestart: boolean;
}
export {};
