Skip to content

A comprehensive toolkit for building type-safe browser extensions with robust messaging patterns.

License

Notifications You must be signed in to change notification settings

doprz/browser-extension-toolkit

Repository files navigation

Browser Extension Toolkit

A comprehensive toolkit for building type-safe browser extensions with robust messaging patterns.

Features

  • πŸ”’ Type-safe messaging system
  • πŸ’Ύ Storage management system
  • πŸ”„ Background script proxy pattern
  • 🎯 Runtime validation
  • πŸ“¦ Modular handler system
  • πŸš€ Built with Bun + Vite + TypeScript

Installation

bun add browser-extension-toolkit webextension-polyfill
# or
npm install browser-extension-toolkit webextension-polyfill

Project Structure

src/
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ messaging/
β”‚   β”‚   β”œβ”€β”€ types.ts           # Core type definitions
β”‚   β”‚   β”œβ”€β”€ interfaces.ts      # Operation interfaces
β”‚   β”‚   β”œβ”€β”€ constants.ts       # Message type constants
β”‚   β”‚   └── messenger.ts       # MessagingProxy class
β”‚   β”œβ”€β”€ storage/               # Storage system
β”‚   β”‚   β”œβ”€β”€ types.ts           # Storage type definitions
β”‚   β”‚   β”œβ”€β”€ storage.ts         # ExtensionStorage class
β”‚   β”‚   └── decorators.ts      # Storage decorators
β”‚   β”œβ”€β”€ proxy/
β”‚   β”‚   β”œβ”€β”€ handlers/
β”‚   β”‚   β”‚   β”œβ”€β”€ index.ts       # Handler exports
β”‚   β”‚   β”‚   └── tabs.ts        # Tab operations
β”‚   └── utils/
β”‚       └── testing.ts         # Test utilities
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ setup.ts               # Test configuration
β”‚   β”œβ”€β”€ messenger.test.ts      # Core tests
β”‚   └── handlers.test.ts       # Handler tests
└── examples/
    β”œβ”€β”€ popup/
    β”‚   └── messaging.ts       # Popup usage example
    └── background/
        └── setup.ts           # Background setup example

Quick Start

Messaging

In your popup script:

import type { MessageTypes } from "browser-extension-toolkit";
import { MESSAGE_TYPES, MessagingProxy } from "browser-extension-toolkit";

const backgroundProxy = new MessagingProxy<MessageTypes>("popup");

// Open a new tab
const response = await proxy.sendProxyMessage(MESSAGE_TYPES.TAB.OPEN, {
  url: "https://example.com",
});

In your background script:

import type { MessageTypes } from "browser-extension-toolkit";
import {
  MESSAGE_TYPES,
  MessagingProxy,
  tabProxyHandlers,
} from "browser-extension-toolkit";

const backgroundProxy = new MessagingProxy<MessageTypes>("background");

// Register handlers
backgroundProxy.registerProxyHandler(
  MESSAGE_TYPES.TAB.OPEN,
  tabProxyHandlers.openTab,
);

Handlers

The toolkit includes pre-built handlers for common operations:

// Tab operations
tabProxyHandlers.openTab;
tabProxyHandlers.closeTab;
tabProxyHandlers.updateTab;

// Extension page operations
extensionProxyHandlers.openOptionsPage;
extensionProxyHandlers.openPopup;

Custom Handlers

Create your own handlers with full type safety:

import type { MessageHandler } from "browser-extension-toolkit";

const customHandler: MessageHandler<InputType, OutputType> = async (
  data,
  source,
  sender,
) => {
  // Implementation
  return result;
};

Storage

// Define your storage schema
interface UserPreferences {
  theme: "light" | "dark";
  fontSize: number;
  notifications: boolean;
}

// Using ExtensionStorage class
const storage = new ExtensionStorage<UserPreferences>({
  area: "sync",
  prefix: "prefs",
});

// Set multiple values in storage at once
await storage.bulkSet({ theme: "light", fontSize: 12, notifications: true });

// Set multiple values and remove others atomically
await store.bulkUpdate({
  set: {
    theme: "dark",
    fontSize: 16,
  },
  remove: ["notifications"],
});

// Set and get values with type safety
await storage.set("theme", "dark");
const theme = await storage.get("theme");

// Listen for changes
storage.addChangeListener((changes) => {
  if ("theme" in changes) {
    console.log("Theme changed:", changes.theme.newValue);
  }
});

// Using decorators
class Settings {
  @persist({ area: "sync", prefix: "settings" })
  public theme!: "light" | "dark";

  @persist({ area: "local", prefix: "settings" })
  public fontSize!: number;
}

Advanced Storage Usage

// Namespace isolation
const userStorage = new ExtensionStorage<UserData>({ prefix: "user" });
const settingsStorage = new ExtensionStorage<Settings>({ prefix: "settings" });

// Batch operations
const allSettings = await settingsStorage.getAll();

// Area-specific storage
const syncStorage = new ExtensionStorage<SyncData>({ area: "sync" });
const localStorage = new ExtensionStorage<LocalData>({ area: "local" });

// With serialization control
const rawStorage = new ExtensionStorage<RawData>({
  serialize: false,
});

// Change detection
storage.addChangeListener(async (changes, area) => {
  for (const [key, { oldValue, newValue }] of Object.entries(changes)) {
    console.log(`${key} changed in ${area}:`, { oldValue, newValue });
  }
});

Documentation

Contributing

See CONTRIBUTING.md for development setup and guidelines.

License

MIT License. See LICENSE for details.

About

A comprehensive toolkit for building type-safe browser extensions with robust messaging patterns.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published