or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

database-management.mderror-handling.mdevents.mdindex.mdlive-queries.mdquery-building.mdschema-management.mdtable-operations.mdutility-functions.md
tile.json

database-management.mddocs/

Database Management

Core database functionality including connection management, schema definition, versioning, and transaction handling.

Capabilities

Dexie Constructor

Creates a new database instance.

/**
 * Creates a new Dexie database instance
 * @param name - Database name (must be unique per origin)
 * @param options - Optional configuration options
 */
constructor(name: string, options?: DexieOptions);

interface DexieOptions {
  /** Add-on functions to apply to the database */
  addons?: Array<(db: Dexie) => void>;
  /** Whether to automatically open the database (default: true) */
  autoOpen?: boolean;
  /** Custom IndexedDB implementation (for testing/Node.js) */
  indexedDB?: IDBFactory;
  /** Custom IDBKeyRange implementation */
  IDBKeyRange?: typeof IDBKeyRange;
  /** Allow opening empty database without schema (default: false) */
  allowEmptyDB?: boolean;
  /** Chunk size for modify operations */
  modifyChunkSize?: number;
  /** Chrome transaction durability setting */
  chromeTransactionDurability?: "default" | "strict" | "relaxed";
  /** Cache strategy for queries and results */
  cache?: "immutable" | "cloned" | "disabled";
}

Usage Examples:

import Dexie from "dexie";

// Basic database creation
const db = new Dexie("MyAppDatabase");

// Database with options
const db = new Dexie("MyAppDatabase", {
  autoOpen: false,
  cache: "immutable",
  modifyChunkSize: 100
});

Database Opening

Opens the database connection.

/**
 * Opens the database, creating it if it doesn't exist
 * @returns Promise that resolves to the database instance
 */
open(): PromiseExtended<Dexie>;

Usage Examples:

// Auto-open (default behavior)
const db = new Dexie("MyDatabase");
db.version(1).stores({ friends: "++id, name, age" });
// Database opens automatically when first used

// Manual open
const db = new Dexie("MyDatabase", { autoOpen: false });
db.version(1).stores({ friends: "++id, name, age" });
await db.open();

// Handle open errors
try {
  await db.open();
  console.log("Database opened successfully");
} catch (error) {
  console.error("Failed to open database:", error);
}

Database Closing

Closes the database connection.

/**
 * Closes the database connection
 * @param options - Closure options
 */
close(options?: { disableAutoOpen?: boolean }): void;

Usage Examples:

// Close database
db.close();

// Close and prevent auto-reopening
db.close({ disableAutoOpen: true });

// Temporarily close database
db.close();
// Database will reopen automatically on next operation unless disableAutoOpen was set

Database Deletion

Deletes the entire database.

/**
 * Deletes the entire database and all its data
 * @param options - Deletion options
 * @returns Promise that resolves when deletion completes
 */
delete(options?: { disableAutoOpen?: boolean }): Promise<void>;

Usage Examples:

// Delete database
await db.delete();

// Delete and prevent auto-recreation
await db.delete({ disableAutoOpen: true });

// Safe deletion with error handling
try {
  await db.delete();
  console.log("Database deleted successfully");
} catch (error) {
  console.error("Failed to delete database:", error);
}

Schema Versioning

Defines database schema versions for evolution and migration.

/**
 * Defines a database schema version
 * @param versionNumber - Version number (must be sequential, starting from 1)
 * @returns Version instance for chaining
 */
version(versionNumber: number): Version;

interface Version {
  /** Define table schemas for this version */
  stores(schema: { [tableName: string]: string | null }): Version;
  /** Define upgrade function for migrating from previous version */
  upgrade(upgradeFunction: (trans: Transaction) => PromiseLike<any> | void): Version;
}

Schema Syntax:

  • "++id" - Auto-incrementing primary key
  • "id" - Non-auto-incrementing primary key
  • "id, name, age" - Primary key with indexes on name and age
  • "id, *tags" - Multi-entry index (for array values)
  • "id, [firstName+lastName]" - Compound index
  • null - Delete table in this version

Usage Examples:

// Basic schema definition
db.version(1).stores({
  friends: "++id, name, age",
  messages: "++id, friendId, message, timestamp"
});

// Schema evolution
db.version(1).stores({
  friends: "++id, name, age"
});

db.version(2)
  .stores({
    friends: "++id, name, age, email", // Add email index
    messages: "++id, friendId, message, timestamp"
  })
  .upgrade(trans => {
    // Migrate existing data
    return trans.friends.toCollection().modify(friend => {
      friend.email = friend.email || null;
    });
  });

db.version(3).stores({
  friends: "++id, name, age, email",
  messages: "++id, friendId, message, timestamp",
  groups: "++id, name, [ownerId+name]" // Add new table with compound index
});

// Delete table in version 4
db.version(4).stores({
  friends: "++id, name, age, email",
  messages: null, // Delete messages table
  groups: "++id, name, [ownerId+name]"
});

Transaction Management

Creates explicit transactions for atomic operations across multiple tables.

/**
 * Creates an explicit transaction
 * @param mode - Transaction mode ('r'/'readonly' or 'rw'/'readwrite')
 * @param tables - Array of table names to include in transaction
 * @param scope - Function to execute within the transaction
 * @returns Promise that resolves to the scope function's result
 */
transaction<T>(
  mode: TransactionMode, 
  tables: string[], 
  scope: () => T | PromiseLike<T>
): Promise<T>;

type TransactionMode = "r" | "rw" | "readonly" | "readwrite";

interface Transaction {
  /** Database reference */
  db: Dexie;
  /** Whether transaction is still active */
  active: boolean;
  /** Transaction mode */
  mode: IDBTransactionMode;
  /** Table names included in transaction */
  storeNames: string[];
  /** Parent transaction (for sub-transactions) */
  parent?: Transaction;
  /** Get table bound to this transaction */
  table(tableName: string): Table<any, any>;
  /** Abort the transaction */
  abort(): void;
}

Usage Examples:

// Read-only transaction
const result = await db.transaction("readonly", ["friends", "messages"], async () => {
  const friends = await db.friends.toArray();
  const messages = await db.messages.toArray();
  return { friends, messages };
});

// Read-write transaction
await db.transaction("readwrite", ["friends", "messages"], async () => {
  const newFriend = await db.friends.add({ name: "Alice", age: 25 });
  await db.messages.add({
    friendId: newFriend,
    message: "Welcome!",
    timestamp: Date.now()
  });
});

// Transaction with error handling
try {
  await db.transaction("rw", ["friends"], async () => {
    await db.friends.add({ name: "Bob", age: 30 });
    await db.friends.add({ name: "Charlie", age: 35 });
    // If any operation fails, entire transaction is rolled back
  });
} catch (error) {
  console.error("Transaction failed:", error);
}

// Access transaction object
await db.transaction("rw", ["friends"], async (trans) => {
  const friends = trans.table("friends");
  await friends.add({ name: "David", age: 40 });
});

Table Access

Accesses database tables for operations.

/**
 * Gets a table instance for performing operations
 * @param tableName - Name of the table
 * @returns Table instance
 */
table(tableName: string): Table<any, any>;
table<T>(tableName: string): Table<T, any>;
table<T, Key>(tableName: string): Table<T, Key>;
table<T, Key, TInsertType>(tableName: string): Table<T, Key, TInsertType>;

Usage Examples:

// Access table with inferred types
const friends = db.table("friends");

// Access table with explicit typing
interface Friend {
  id: number;
  name: string;
  age: number;
}

const typedFriends = db.table<Friend, number>("friends");
await typedFriends.add({ name: "Alice", age: 25 });

Database Properties

Key database properties and metadata.

interface Dexie {
  /** Database name */
  readonly name: string;
  /** Current version number */
  readonly verno: number;
  /** All tables in the database */
  readonly tables: Table[];
  /** VIP instance for priority operations */
  readonly vip: Dexie;
  /** Whether database is currently open */
  readonly isOpen: boolean;
  /** Whether database has failed to open or had an error */
  readonly hasFailed: boolean;
  /** Whether database has been explicitly closed */
  readonly hasBeenClosed: boolean;
  /** Whether database was opened with auto-schema (no version specified) */
  readonly dynamicallyOpened: boolean;
  /** Native IndexedDB database instance (may be null if closed) */
  readonly idbdb: IDBDatabase | null;
}

Usage Examples:

console.log("Database name:", db.name);
console.log("Current version:", db.verno);
console.log("Available tables:", db.tables.map(t => t.name));
console.log("Database open:", db.isOpen);
console.log("Database failed:", db.hasFailed);
console.log("Database closed:", db.hasBeenClosed);
console.log("Auto-schema mode:", db.dynamicallyOpened);

// Check native IndexedDB instance
if (db.idbdb) {
  console.log("Native IDB version:", db.idbdb.version);
  console.log("Native IDB store names:", Array.from(db.idbdb.objectStoreNames));
}

// Use VIP instance for priority operations
await db.vip.friends.add({ name: "VIP User", age: 30 });

// Check database status before operations
if (db.hasBeenClosed) {
  console.log("Database was explicitly closed");
}

if (db.hasFailed) {
  console.log("Database has encountered errors");
}

Static Properties

Static utilities available on the Dexie constructor.

interface DexieConstructor {
  /** Library version */
  static readonly version: string;
  /** Semantic version */
  static readonly semVer: string;
  /** Maximum IndexedDB key value */
  static readonly maxKey: any;
  /** Minimum IndexedDB key value */
  static readonly minKey: any;
  /** Global addon registry */
  static addons: Array<(db: Dexie) => void>;
  /** Current active transaction */
  static currentTransaction: Transaction | null;
  
  /** Wait for external promises in transactions */
  static waitFor<T>(promise: PromiseLike<T>, timeoutMs?: number): Promise<T>;
  /** Run code outside transaction context */
  static ignoreTransaction<T>(fn: () => T): T;
  /** Run with VIP priority */
  static vip<T>(fn: () => T): T;
  
  /** Delete a database by name */
  static delete(databaseName: string): Promise<void>;
  /** Check if a database exists */
  static exists(databaseName: string): Promise<boolean>;
  /** Get list of all database names */
  static getDatabaseNames(): Promise<string[]>;
  static getDatabaseNames<R>(thenShortcut: ThenShortcut<string[], R>): Promise<R>;
  
  /** Convert generator function to async function */
  static async<T>(generatorFn: Function): (...args: any[]) => Promise<T>;
  /** Spawn a generator function with arguments */
  static spawn<T>(generatorFn: Function, args?: any[], thiz?: any): Promise<T>;
}

Usage Examples:

console.log("Dexie version:", Dexie.version);
console.log("Semantic version:", Dexie.semVer);
console.log("Max key:", Dexie.maxKey);
console.log("Min key:", Dexie.minKey);

// Database management operations
const dbExists = await Dexie.exists("MyDatabase");
if (dbExists) {
  console.log("Database exists");
}

// Get all database names
const dbNames = await Dexie.getDatabaseNames();
console.log("Available databases:", dbNames);

// Delete a database
await Dexie.delete("OldDatabase");

// Wait for external promise in transaction
await db.transaction("rw", ["friends"], async () => {
  const externalData = await Dexie.waitFor(fetch("/api/friends"));
  const friends = await externalData.json();
  await db.friends.bulkAdd(friends);
});

// Check current transaction
if (Dexie.currentTransaction) {
  console.log("Currently in transaction");
}

// Run with VIP priority
Dexie.vip(() => {
  return db.friends.add({ name: "Priority User", age: 25 });
});

// Run code outside transaction context
const result = Dexie.ignoreTransaction(() => {
  // This code runs outside any current transaction
  return someNonTransactionalOperation();
});

// Using async/spawn with generators (legacy support)
const asyncFn = Dexie.async(function* () {
  const result1 = yield somePromise();
  const result2 = yield anotherPromise();
  return result1 + result2;
});

const spawnResult = await Dexie.spawn(function* () {
  return yield someGenerator();
});

Static Utility Methods

Utility functions available on the Dexie constructor for common operations.

interface DexieUtilities {
  /** Get property value by key path */
  static getByKeyPath(obj: Object, keyPath: string | string[]): any;
  /** Set property value by key path */
  static setByKeyPath(obj: Object, keyPath: string | string[], value: any): void;
  /** Delete property by key path */
  static delByKeyPath(obj: Object, keyPath: string | string[]): void;
  /** Create shallow clone of object */
  static shallowClone<T>(obj: T): T;
  /** Create deep clone of object */
  static deepClone<T>(obj: T): T;
  /** Compare two IndexedDB keys */
  static cmp(a: any, b: any): number;
  /** Schedule function to run as soon as possible */
  static asap(fn: Function): void;
  /** Debug mode control */
  static debug: false | true | "dexie";
}

Usage Examples:

// Working with key paths
const obj = { user: { profile: { name: "John" } } };

// Get nested value
const name = Dexie.getByKeyPath(obj, "user.profile.name"); // "John"
const nameArray = Dexie.getByKeyPath(obj, ["user", "profile", "name"]); // "John"

// Set nested value
Dexie.setByKeyPath(obj, "user.profile.age", 25);
console.log(obj.user.profile.age); // 25

// Delete nested property
Dexie.delByKeyPath(obj, "user.profile.name");
console.log(obj.user.profile.name); // undefined

// Object cloning
const original = { a: 1, b: { c: 2 } };
const shallow = Dexie.shallowClone(original); // { a: 1, b: { c: 2 } }
const deep = Dexie.deepClone(original); // { a: 1, b: { c: 2 } }

// Note: shallow.b === original.b (same reference)
// Note: deep.b !== original.b (different reference)

// Key comparison (follows IndexedDB key ordering)
console.log(Dexie.cmp("a", "b")); // -1 (a < b)
console.log(Dexie.cmp(1, 2)); // -1 (1 < 2)
console.log(Dexie.cmp([1, 2], [1, 3])); // -1 ([1,2] < [1,3])

// Schedule immediate execution
Dexie.asap(() => {
  console.log("This runs as soon as possible");
});

// Debug mode
Dexie.debug = true; // Enable debug logging
Dexie.debug = "dexie"; // Enable debug with Dexie stack frames
Dexie.debug = false; // Disable debug

Error Classes and Dependencies

Error classes and development utilities available on the Dexie constructor.

interface DexieErrorClasses {
  /** Base class for all Dexie errors */
  static DexieError: typeof DexieError;
  /** Database failed to open */
  static OpenFailedError: typeof OpenFailedError;
  /** Version change error during upgrade */
  static VersionChangeError: typeof VersionChangeError;
  /** Schema definition error */
  static SchemaError: typeof SchemaError;
  /** Database upgrade error */
  static UpgradeError: typeof UpgradeError;
  /** Invalid table name or reference */
  static InvalidTableError: typeof InvalidTableError;
  /** Missing IndexedDB API */
  static MissingAPIError: typeof MissingAPIError;
  /** Database doesn't exist */
  static NoSuchDatabaseError: typeof NoSuchDatabaseError;
  /** Invalid argument passed to method */
  static InvalidArgumentError: typeof InvalidArgumentError;
  /** Sub-transaction constraint violation */
  static SubTransactionError: typeof SubTransactionError;
  /** Unsupported operation */
  static UnsupportedError: typeof UnsupportedError;
  /** Internal Dexie error */
  static InternalError: typeof InternalError;
  /** Database was closed */
  static DatabaseClosedError: typeof DatabaseClosedError;
  /** Transaction committed prematurely */
  static PrematureCommitError: typeof PrematureCommitError;
}

interface DexieDependencies {
  /** DOM dependencies for browser/Node.js compatibility */
  static dependencies: {
    indexedDB: IDBFactory;
    IDBKeyRange: typeof IDBKeyRange;
  };
  /** Error name constants */
  static errnames: DexieErrors;
}

Usage Examples:

// Using error classes
try {
  await db.open();
} catch (error) {
  if (error instanceof Dexie.OpenFailedError) {
    console.log("Failed to open database:", error.message);
  } else if (error instanceof Dexie.VersionChangeError) {
    console.log("Version change error:", error.message);
  } else if (error instanceof Dexie.DexieError) {
    console.log("General Dexie error:", error.message);
  }
}

// Checking error types by name
try {
  await db.table("nonexistent").get(1);
} catch (error) {
  if (error.name === Dexie.errnames.InvalidTable) {
    console.log("Invalid table error");
  }
}

// Custom error handling
function handleDexieError(error: any) {
  switch (error.constructor) {
    case Dexie.DatabaseClosedError:
      console.log("Database is closed, attempting to reopen...");
      return db.open();
    case Dexie.NoSuchDatabaseError:
      console.log("Database doesn't exist, creating new one...");
      return createNewDatabase();
    default:
      console.error("Unhandled Dexie error:", error);
      throw error;
  }
}

// Accessing DOM dependencies (useful for Node.js setup)
console.log("IndexedDB implementation:", Dexie.dependencies.indexedDB);
console.log("IDBKeyRange implementation:", Dexie.dependencies.IDBKeyRange);

// Setting custom dependencies (Node.js example)
// const FDBFactory = require('fake-indexeddb/lib/FDBFactory');
// const FDBKeyRange = require('fake-indexeddb/lib/FDBKeyRange');
// 
// Object.assign(Dexie.dependencies, {
//   indexedDB: new FDBFactory(),
//   IDBKeyRange: FDBKeyRange
// });

Middleware System

Register and manage middleware for extending database functionality.

/**
 * Register middleware for extending database operations
 * @param middleware - Middleware specification
 * @returns Database instance for chaining
 */
use(middleware: Middleware<DBCore>): this;

/**
 * Unregister middleware by function reference or name
 * @param spec - Middleware specification to remove
 * @returns Database instance for chaining
 */
unuse(spec: { stack: keyof DexieStacks; create: Function }): this;
unuse(spec: { stack: keyof DexieStacks; name: string }): this;

interface Middleware<TStack> {
  /** Target middleware stack */
  stack: keyof DexieStacks;
  /** Factory function that creates the middleware */
  create: (downlevelDatabase: TStack) => TStack;
  /** Priority level (lower numbers run first, default: 10) */
  level?: number;
  /** Optional name for the middleware */
  name?: string;
}

Usage Examples:

// Custom logging middleware
const loggingMiddleware = {
  stack: "dbcore" as const,
  name: "logging",
  create: (downlevelDatabase) => ({
    ...downlevelDatabase,
    table(name) {
      const table = downlevelDatabase.table(name);
      return {
        ...table,
        mutate(req) {
          console.log(`${req.type} operation on table ${name}:`, req);
          return table.mutate(req).then(result => {
            console.log(`${req.type} completed:`, result);
            return result;
          });
        }
      };
    }
  })
};

// Register middleware
db.use(loggingMiddleware);

// Performance monitoring middleware
const performanceMiddleware = {
  stack: "dbcore" as const,
  level: 1, // Run early
  create: (downlevelDatabase) => ({
    ...downlevelDatabase,
    table(name) {
      const table = downlevelDatabase.table(name);
      return {
        ...table,
        query(req) {
          const start = performance.now();
          return table.query(req).then(result => {
            const duration = performance.now() - start;
            console.log(`Query on ${name} took ${duration}ms`);
            return result;
          });
        }
      };
    }
  })
};

db.use(performanceMiddleware);

// Remove middleware by name
db.unuse({ stack: "dbcore", name: "logging" });

// Remove middleware by function reference
db.unuse({ stack: "dbcore", create: performanceMiddleware.create });

Database Events

Handle database lifecycle and operational events.

interface DbEvents {
  /** Database ready event - fires when database is successfully opened */
  ready: DexieOnReadyEvent;
  /** Database blocked event - fires when database operations are blocked */
  blocked: DexieEvent;
  /** Version change event - fires when another connection wants to upgrade/delete database */
  versionchange: DexieVersionChangeEvent;
  /** Database close event - fires when database connection is closed */
  close: DexieCloseEvent;
  /** Populate event - fires during database creation for initial data setup */
  populate: DexiePopulateEvent;
}

interface DexieOnReadyEvent {
  /** Subscribe to ready event with optional sticky behavior */
  subscribe(fn: (vipDb: Dexie) => any, bSticky?: boolean): void;
  /** Unsubscribe from ready event */
  unsubscribe(fn: (vipDb: Dexie) => any): void;
  /** Fire ready event (internal use) */
  fire(vipDb: Dexie): any;
}

interface DbEventFns {
  /** Subscribe to events with a single function call */
  (eventName: "ready", subscriber: (vipDb: Dexie) => any, bSticky?: boolean): void;
  (eventName: "blocked", subscriber: (event: IDBVersionChangeEvent) => any): void;
  (eventName: "versionchange", subscriber: (event: IDBVersionChangeEvent) => any): void;
  (eventName: "close", subscriber: (event: Event) => any): void;
  (eventName: "populate", subscriber: (trans: Transaction) => any): void;
}

/**
 * Subscribe to database events using 'once' - automatically unsubscribes after first trigger
 * @param eventName - Name of the event to subscribe to
 * @param callback - Function to call when event fires
 */
once: DbEventFns;

Usage Examples:

// Ready event - database successfully opened
db.on("ready", (vipDb) => {
  console.log("Database is ready!");
  // You can perform VIP operations here
  return vipDb.friends.count();
});

// Sticky ready subscription - will fire immediately if db is already open
db.on("ready", (vipDb) => {
  console.log("This will fire immediately if db is already open");
}, true); // bSticky = true

// Blocked event - database operations blocked by another connection
db.on("blocked", (event) => {
  console.log("Database operations are blocked", event);
});

// Version change event - another connection wants to upgrade/delete
db.on("versionchange", (event) => {
  console.log("Another connection is requesting version change", event);
  if (event.newVersion === null) {
    console.log("Database is being deleted");
  } else {
    console.log(`Upgrading to version ${event.newVersion}`);
  }
  // Default behavior: close database to allow upgrade
  db.close({ disableAutoOpen: false });
});

// Close event - database connection closed
db.on("close", (event) => {
  console.log("Database connection closed", event);
});

// Populate event - initial data setup during database creation
db.on("populate", (trans) => {
  console.log("Populating initial data");
  // Add initial data to tables
  trans.friends.add({ name: "John", age: 30 });
  trans.friends.add({ name: "Jane", age: 25 });
});

// Using once() for single-use subscriptions
db.once("ready", (vipDb) => {
  console.log("This will only fire once");
});

db.once("blocked", (event) => {
  console.log("This blocked handler will only fire once");
});

// Multiple event handlers
db.on("ready", () => console.log("Handler 1"));
db.on("ready", () => console.log("Handler 2"));

// Unsubscribe from events
const readyHandler = (vipDb) => console.log("Ready!");
db.on("ready", readyHandler);
db.on.ready.unsubscribe(readyHandler);

Database Status Methods

Methods to check the current status and state of the database connection.

/**
 * Check if the database is currently open
 * @returns True if database is open and ready for use
 */
isOpen(): boolean;

/**
 * Check if the database has been closed
 * @returns True if database has been explicitly closed
 */
hasBeenClosed(): boolean;

/**
 * Check if the database has failed to open
 * @returns True if database opening failed
 */
hasFailed(): boolean;

/**
 * Check if database was opened dynamically (without schema)
 * @returns True if opened without predefined schema
 */
dynamicallyOpened(): boolean;

/**
 * Get the native IndexedDB database instance
 * @returns Native IDBDatabase instance or null if closed
 */
backendDB(): IDBDatabase | null;

Usage Examples:

// Check database status before operations
if (db.isOpen()) {
  await db.friends.add({ name: "Alice", age: 25 });
} else {
  console.log("Database is not open, attempting to open...");
  await db.open();
}

// Handle closed databases
if (db.hasBeenClosed()) {
  console.log("Database was explicitly closed");
  // Reopen if needed
  await db.open();
}

// Handle failed database connections
if (db.hasFailed()) {
  console.error("Database failed to open");
  // Implement fallback logic or error handling
}

// Check if database was dynamically opened
if (db.dynamicallyOpened()) {
  console.log("Database opened without predefined schema");
  console.log("Available tables:", db.tables.map(t => t.name));
}

// Access native IndexedDB instance for advanced operations
const nativeDB = db.backendDB();
if (nativeDB) {
  console.log("Native DB version:", nativeDB.version);
  console.log("Object stores:", Array.from(nativeDB.objectStoreNames));
  
  // You can use native IndexedDB APIs if needed
  // (though this is rarely necessary with Dexie)
  const transaction = nativeDB.transaction(["friends"], "readonly");
  const store = transaction.objectStore("friends");
}

Additional Static Methods

Additional static utility methods available on the Dexie class.

/**
 * Check if a database exists
 * @param name - Database name to check
 * @returns Promise resolving to true if database exists
 */
static exists(name: string): Promise<boolean>;

/**
 * Delete a database by name
 * @param name - Database name to delete
 * @returns Promise that resolves when deletion is complete
 */
static delete(databaseName: string): Promise<void>;

/**
 * Ignore current transaction context
 * @param scopeFunc - Function to execute outside current transaction
 * @returns Result of the scope function
 */
static ignoreTransaction<T>(scopeFunc: () => T): T;

/**
 * Wait for a promise or function result
 * @param promiseOrFunction - Promise or function to wait for
 * @param optionalTimeout - Optional timeout in milliseconds
 * @returns Promise that resolves to the result
 */
static waitFor<T>(promiseOrFunction: T | (() => T), optionalTimeout?: number): Promise<T>;

/**
 * Current active transaction
 * @returns Current transaction or null if none active
 */
static currentTransaction: Transaction | null;

Usage Examples:

// Check if database exists before operations
const exists = await Dexie.exists("MyDatabase");
if (exists) {
  console.log("Database exists");
} else {
  console.log("Database does not exist");
}

// Static delete (without creating instance)
await Dexie.delete("OldDatabase");
console.log("Database deleted");

// Ignore current transaction for logging
await db.transaction("rw", ["friends"], async () => {
  await db.friends.add({ name: "Alice", age: 25 });
  
  // Log this operation in a separate transaction
  Dexie.ignoreTransaction(() => {
    db.logs.add({ action: "user_added", timestamp: Date.now() });
  });
});

// Wait for external promise within transaction
await db.transaction("rw", ["friends"], async () => {
  const externalData = await Dexie.waitFor(
    fetch("/api/user-data").then(r => r.json()),
    5000 // 5 second timeout
  );
  
  await db.friends.add(externalData);
});

// Check current transaction
if (Dexie.currentTransaction) {
  console.log("Currently in transaction:", Dexie.currentTransaction.mode);
} else {
  console.log("No active transaction");
}