/**
 * IndexedDB database name.
 */
type DBName = string;
/**
 * Raw encryption key string used to derive an AES-GCM key.
 */
type EncryptionKey = string;
/**
 * Object store name used as a logical category.
 */
type Category = string;
/**
 * Number expected to be positive by runtime validation.
 */
type PositiveNumber = number;
/**
 * Canonical record structure stored by LocalSave before encryption.
 */
interface DBItem {
    /** Unix timestamp in milliseconds when the item was written. */
    timestamp: number;
    /** User payload associated with the key. */
    data: unknown;
}
/**
 * Base64 payload containing IV + encrypted record bytes.
 */
type DBItemEncryptedBase64 = string;
/**
 * Configuration options for constructing LocalSave.
 */
interface Config {
    /**
     * The name of the database to use for local save
     *
     * @default "LocalSave"
     */
    dbName?: DBName;
    /**
     * The key to use for encrypting and decrypting data
     * Not providing this will store data in plain text
     * Should be a string without spaces of length 16, 24, or 32 characters
     *
     * @default undefined
     */
    encryptionKey?: EncryptionKey;
    /**
     * The categories to use for storing data
     * You can use these to separate different types of data
     *
     * @default ["userData"]
     */
    categories?: Category[];
    /**
     * The threshold in milliseconds for expiring data.
     *
     * Example day-to-ms conversion: days * 24 * 60 * 60 * 1000
     *
     * Default is 30 days - 30 * 24 * 60 * 60 * 1000
     * @default 2592000000
     */
    expiryThreshold?: PositiveNumber;
    /**
     * The time in milliseconds to wait before failing blocked IndexedDB open/delete requests.
     *
     * @default 10000
     */
    blockedTimeoutThreshold?: PositiveNumber;
    /**
     * Whether to clear all data for a category if an error occurs while decrypting data
     * Most likely reason of error is due to an incorrect encryption key
     *
     * @default true
     */
    clearOnDecryptError?: boolean;
    /**
     * Whether to print logs
     * Includes debug and errors logs
     *
     * @default false
     */
    printLogs?: boolean;
}

/**
 * LocalSave provides a small IndexedDB-backed key-value API with optional AES-GCM encryption,
 * category-based separation, and utility operations like key listing, expiration, and teardown.
 */
declare class LocalSave {
    dbName: DBName;
    encryptionKey?: EncryptionKey;
    private crypto;
    categories: Category[];
    expiryThreshold: PositiveNumber;
    blockedTimeoutThreshold: PositiveNumber;
    clearOnDecryptError: boolean;
    printLogs: boolean;
    /**
     * Creates a LocalSave instance and applies configuration defaults.
     *
     * - Persists constructor options into instance fields used by all operations.
     * - Validates encryption key format when provided.
     * - Validates numeric thresholds to fail fast for invalid runtime behavior.
     *
     * @param config Optional runtime configuration object.
     * @param config.dbName Optional IndexedDB database name override.
     * @param config.encryptionKey Optional AES-GCM key (no whitespace, length 16, 24, or 32).
     * @param config.categories Optional list of object store categories to use.
     * @param config.expiryThreshold Optional default expiration window in milliseconds.
     * @param config.blockedTimeoutThreshold Optional timeout in milliseconds for blocked open/delete requests.
     * @param config.clearOnDecryptError Optional flag to clear a category when decrypt fails.
     * @param config.printLogs Optional flag to enable debug/error logging.
     *
     * @throws {LocalSaveConfigError} If encryption key contains whitespace or its length is invalid.
     * @throws {LocalSaveConfigError} If expiryThreshold is not a positive finite number.
     * @throws {LocalSaveConfigError} If blockedTimeoutThreshold is not a positive finite number.
     */
    constructor(config?: Config);
    /**
     * Opens a connection to the IndexedDB database.
     * It handles the database versioning and ensures that the required object stores are created if they do not exist.
     *
     * @internal
     *
     * @param version - The version of the database to open. Optional.
     *
     * @returns {Promise<IDBDatabase>} A promise that resolves to the opened IDBDatabase instance.
     */
    private openDB;
    /**
     * Lists all object stores currently available in the configured database.
     *
     * @internal
     *
     * @returns {Promise<Category[]>} A promise that resolves to an array of object store names.
     */
    private listStores;
    /**
     * Retrieves an object store from the IndexedDB database.
     * It handles the transaction mode and ensures that the requested object store is returned.
     *
     * If the object store does not exist in the database and the category is valid, it will create a new version of the database with the object store.
     *
     * @internal
     *
     * @param category - The name of the object store to retrieve.
     * @param mode - The mode for the transaction (default is "readonly").
     *
     * @returns {Promise<IDBObjectStore>} A promise that resolves to the requested object store.
     *
     * @throws {LocalSaveError} Will throw an error if the object store does not exist in the database and the category is invalid
     */
    private getStore;
    /**
     * Encrypts a DBItem using the configured encryption key.
     * Delegates to the extracted crypto helper.
     *
     * @internal
     *
     * @param data The item payload to encrypt.
     *
     * @returns {Promise<DBItemEncryptedBase64>} A promise that resolves to a base64 payload containing IV + ciphertext.
     *
     * @throws {LocalSaveEncryptionKeyError} If the encryption key is not configured or invalid.
     * @throws {LocalSaveError} If encryption fails.
     */
    private encryptData;
    /**
     * Decrypts data using the configured encryption key.
     *
     * @param encryptedBase64Data The data to decrypt, as a string.
     * @returns {Promise<DBItem>} A promise that resolves to the decrypted data object.
     *
     * @throws {LocalSaveError} If decryption fails.
     */
    decryptData(encryptedBase64Data: string): Promise<DBItem>;
    /**
     * Stores data in the specified category with the given item key.
     * If encryption key is configured, the data is encrypted first before being stored.
     *
     * @param category The category under which the data should be stored.
     * @param itemKey The key to identify the stored data.
     * @param data The data to be stored.
     *
     * @returns {Promise<true>} A promise that resolves to `true` if the operation was successful.
     *
     * @throws {LocalSaveError} Will reject the promise if an error occurs during the saving process.
     */
    set(category: Category, itemKey: string, data: unknown): Promise<true>;
    /**
     * Retrieves an item from the specified category in the IndexedDB.
     * If the item is not found, the promise resolves to 'null'.
     * If an encryption key is configured, the data is decrypted before being returned.
     *
     * @param category The category from which to retrieve the item.
     * @param itemKey The key of the item to retrieve.
     *
     * @returns {Promise<DBItem | null>} A promise that resolves to the retrieved item or null if not found.
     *
     * @throws {LocalSaveError} Will reject the promise if an error occurs while decrypting the data. Depending on the 'clearOnDecryptError' configuration, all data for the category can be cleared.
     * @throws {LocalSaveError} Will reject the promise if an error occurs during the retrieval process.
     */
    get(category: Category, itemKey: string): Promise<DBItem | null>;
    /**
     * Lists all categories (object stores) currently available in the database.
     *
     * @returns {Promise<Category[]>} A promise that resolves to an array of category names.
     */
    listCategories(): Promise<Category[]>;
    /**
     * Lists all item keys stored under the specified category.
     *
     * @param category The category from which item keys should be listed.
     *
     * @returns {Promise<string[]>} A promise that resolves to an array of item keys.
     *
     * @throws {LocalSaveError} Will reject the promise if an error occurs while listing keys.
     */
    listKeys(category: Category): Promise<string[]>;
    /**
     * Removes an entry from the specified category and the specific itemKey in the IndexedDB store.
     *
     * @param category The category from which the item should be removed.
     * @param itemKey The key of the item to be removed.
     *
     * @returns {Promise<true>} A promise that resolves to `true` if the operation was successful.
     *
     * @throws {LocalSaveError} Will reject the promise if an error occurs during the removal process.
     */
    remove(category: Category, itemKey: string): Promise<true>;
    /**
     * Clears all entries in the specified category.
     *
     * @param category - The category to clear.
     *
     * @returns {Promise<true>} A promise that resolves to `true` if the operation was successful.
     *
     * @throws {LocalSaveError} Will reject the promise if an error occurs during the clearing process.
     */
    clear(category: Category): Promise<true>;
    /**
     * Expires data older than the specified threshold in milliseconds.
     *
     * For each category, this method performs a readonly cursor scan to identify candidate
     * records, decrypts encrypted entries to inspect their timestamps, and then deletes the
     * expired keys in a separate readwrite transaction.
     *
     * If decryption fails during expiration and `clearOnDecryptError` is enabled, the category
     * is cleared before the error is rethrown.
     *
     * @param {number} [thresholdMs=this.expiryThreshold] The threshold in milliseconds to use for expiring data.
     * Defaults to expiryThreshold from config if not provided.
     *
     * @returns {Promise<true>} A promise that resolves to `true` if the operation was successful.
     *
     * @throws {LocalSaveError} - Throws an error if there is an issue scanning entries, decrypting data, or removing expired items.
     */
    expire(thresholdMs?: number): Promise<true>;
    /**
     * Asynchronously destroys the database by deleting it from IndexedDB.
     *
     * @returns {Promise<true>} A promise that resolves to `true` if the operation was successful.
     *
     * @throws {LocalSaveError} Will reject the promise if an error occurs during the deletion process.
     */
    destroy(): Promise<true>;
}

export { type Category, type Config, type DBItem, type DBItemEncryptedBase64, type DBName, type EncryptionKey, type PositiveNumber, LocalSave as default };
