CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-electric-sql--pglite

PGlite is a WASM Postgres build packaged into a TypeScript client library that enables you to run Postgres in the browser, Node.js and Bun, with no need to install any other dependencies.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

worker-support.mddocs/

Worker Support

Multi-tab shared database access through dedicated or shared worker threads, enabling concurrent database operations across browser tabs.

Import

import { PGliteWorker, worker } from "@electric-sql/pglite/worker";

Capabilities

PGliteWorker Class

Client-side class for connecting to a PGlite database running in a worker thread.

/**
 * Multi-tab shared database client extending BasePGlite
 * Connects to PGlite database running in a worker thread
 */
class PGliteWorker extends BasePGlite {
  constructor(worker: Worker, options?: PGliteWorkerOptions);
  
  /** Promise resolving when worker connection is ready */
  readonly waitReady: Promise<void>;
  /** Whether the worker connection is ready */
  readonly ready: boolean;
  /** Whether the worker connection is closed */
  readonly closed: boolean;
  /** Data directory path from worker */
  readonly dataDir?: string;
}

Worker Setup Function

Server-side function to set up PGlite in a worker thread.

/**
 * Setup function for worker thread side
 * Call this in your worker script to handle PGlite operations
 * @param options - Worker configuration options
 */
function worker(options?: WorkerOptions): void;

Leader Changed Error

Error thrown when the worker leader changes during multi-tab scenarios.

/**
 * Error thrown when worker leader changes
 * Indicates that another tab has taken control
 */
class LeaderChangedError extends Error {
  constructor(message?: string);
}

Worker Options

Configuration options for PGlite worker setup.

interface WorkerOptions {
  /** PGlite initialization options */
  pgliteOptions?: PGliteOptions;
  /** Custom message handler */
  messageHandler?: (message: any) => Promise<any>;
  /** Error handler */
  errorHandler?: (error: Error) => void;
}

interface PGliteWorkerOptions<TExtensions = Record<string, Extension>> {
  /** Worker instance */
  worker?: Worker;
  /** Debug level */
  debug?: DebugLevel;
  /** Extension configuration */
  extensions?: TExtensions;
  /** Connection timeout in milliseconds */
  connectionTimeout?: number;
  /** Retry configuration */
  retryConfig?: {
    maxRetries: number;
    retryDelay: number;
  };
}

Worker Message Protocol

Internal message types used for worker communication.

interface WorkerMessage {
  /** Unique message ID */
  id: string;
  /** Message type */
  type: 'query' | 'exec' | 'transaction' | 'close' | 'listen' | 'unlisten';
  /** Message payload */
  payload: any;
}

interface WorkerResponse {
  /** Message ID this responds to */
  id: string;
  /** Whether the operation succeeded */
  success: boolean;
  /** Response data or error */
  data: any;
}

Types

type WorkerExtensionSetup<TNamespace = any> = (
  pg: PGliteInterface,
  options: any
) => Promise<TNamespace>;

Usage Examples:

Worker Script Setup

// worker.js
import { worker } from "@electric-sql/pglite/worker";
import { PGlite } from "@electric-sql/pglite";
import { live } from "@electric-sql/pglite/live";
import { vector } from "@electric-sql/pglite/vector";

// Setup PGlite in worker
worker({
  pgliteOptions: {
    dataDir: "shared-database",
    extensions: {
      live,
      vector,
    },
  },
  errorHandler: (error) => {
    console.error("Worker error:", error);
  },
});

Client-Side Usage

// main.js
import { PGliteWorker } from "@electric-sql/pglite/worker";

// Create worker
const workerInstance = new Worker("./worker.js");

// Connect to worker database
const db = new PGliteWorker(workerInstance, {
  debug: 1,
  connectionTimeout: 5000,
  retryConfig: {
    maxRetries: 3,
    retryDelay: 1000,
  },
});

// Wait for connection
await db.waitReady;

// Use like regular PGlite
const results = await db.query("SELECT * FROM users");
console.log(results.rows);

// Transactions work across worker boundary
const transactionResult = await db.transaction(async (tx) => {
  await tx.query("INSERT INTO users (name) VALUES ($1)", ["Alice"]);
  return tx.query("SELECT * FROM users");
});

// Listen for notifications
const unlisten = await db.listen("user_updates", (payload) => {
  console.log("User updated:", payload);
});

// Cleanup
await unlisten();
await db.close();

Multi-Tab Shared Database

// shared-worker.js
import { worker } from "@electric-sql/pglite/worker";
import { IdbFs } from "@electric-sql/pglite";

// Setup shared database
worker({
  pgliteOptions: {
    dataDir: "multi-tab-db",
    fs: new IdbFs("multi-tab-db"),
  },
});
// Each tab connects to shared worker
const sharedWorker = new SharedWorker("./shared-worker.js");
const db = new PGliteWorker(sharedWorker.port);

await db.waitReady;

// All tabs share the same database state
await db.query("CREATE TABLE IF NOT EXISTS shared_data (id SERIAL, value TEXT)");
await db.query("INSERT INTO shared_data (value) VALUES ($1)", [`Tab ${Date.now()}`]);

const allData = await db.query("SELECT * FROM shared_data");
console.log("Shared data across tabs:", allData.rows);

Error Handling

import { PGliteWorker, LeaderChangedError } from "@electric-sql/pglite/worker";

const db = new PGliteWorker(worker);

try {
  await db.query("SELECT * FROM users");
} catch (error) {
  if (error instanceof LeaderChangedError) {
    console.log("Leader changed, reconnecting...");
    // Handle leader change - possibly reconnect
    await db.close();
    const newDb = new PGliteWorker(new Worker("./worker.js"));
    await newDb.waitReady;
  } else {
    console.error("Database error:", error);
  }
}

Advanced Worker Configuration

// worker.js with custom message handling
import { worker } from "@electric-sql/pglite/worker";

worker({
  pgliteOptions: {
    dataDir: "./data",
    debug: 2,
    relaxedDurability: true,
  },
  messageHandler: async (message) => {
    // Custom message processing
    if (message.type === 'custom-operation') {
      // Handle custom operations
      return { result: 'custom-handled' };
    }
    // Return null to use default handling
    return null;
  },
  errorHandler: (error) => {
    // Custom error logging
    console.error(`[Worker] ${error.message}`, error);
  },
});

Install with Tessl CLI

npx tessl i tessl/npm-electric-sql--pglite

docs

database-operations.md

extensions.md

filesystem-storage.md

index.md

live-queries.md

sql-templates.md

vector-operations.md

worker-support.md

tile.json