npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

bun_plugins

v1.1.1

Published

A powerful and secure plugin system for Bun applications

Downloads

361

Readme

🔌 Bun Plugins

A powerful, secure, and isolated plugin system designed specifically for Bun applications. Build extensible applications with fine-grained control over security, resource management, and inter-plugin communication.

NPM Version License Bun

🌟 Key Features

  • 🛡️ Isolation: Run plugins in dedicated Bun Workers for crash protection and security boundaries.
  • 🔐 Permission System: Fine-grained control over Network (with whitelist), Filesystem, and Environment access.
  • 🔄 Communication RPC: Seamless, proxy-based async communication between host and plugins.
  • 🧹 Automatic Resource Cleanup: Automatically stops workers, clears timers, and removes event listeners when a plugin unloads.
  • Type Safe: Fully written in TypeScript with Zod validation for plugin configurations.
  • 🏗️ Plugin Hooks: Intercept resource loading with onResolve and onLoad hooks, fully compatible with Bun's native plugin API.
  • 🔋 Persistence: Built-in JSON-based KV storage for each plugin.
  • 🔥 Hot Reloading: Watch plugin directories and automatically reload changed plugins.
  • 📦 Dependency Management: Cross-plugin dependencies with semver version checking.

🚀 Quick Start

1. Installation

bun add bun_plugins

2. Create your first Plugin

import { type IPlugin, type PluginContext } from "bun_plugins";

export class MyPlugin implements IPlugin {
  name = "hello-world";
  version = "1.0.0";

  async onLoad(context: PluginContext) {
    context.log.info("Hello World Plugin Loaded!");

    // Listen to global app events
    context.on("app:ready", () => {
      context.log.info("The application is ready!");
    });

    // Expose functionality via events
    context.emit("plugin:hello", { message: "Hello from plugin!" });
  }
}

3. Initialize the Manager

import { PluginManager } from "bun_plugins";
import { MyPlugin } from "./plugins/MyPlugin";

const manager = new PluginManager();

// Register a class instance
await manager.register(new MyPlugin());

// Emit an event to all plugins
manager.emit("app:ready", {});

🛠️ Core Concepts

🧩 The Plugin Interface (IPlugin)

All plugins must implement the IPlugin interface.

| Property | Type | Description | | :--------------- | :------------------- | :-------------------------------------------------------------- | | name | string | Unique identifier for the plugin. | | version | string | Semver compatible version. | | permissions | PluginPermission[] | List of requested permissions (network, filesystem, env). | | allowedDomains | string[] | Whitelist for network access. | | configSchema | ZodSchema | Zod schema for configuration validation. | | onLoad | (ctx) => void | Primary entry point for plugin logic. | | onUnload | () => void | Cleanup logic when plugin is removed. |

🧪 Plugin Context (PluginContext)

The context provided to onLoad is the primary way plugins interact with the host.

  • 📝 context.log: Scoped logging (info, warn, error).
  • 📡 context.events: typed event bus (emit, on).
  • 📦 context.storage: Persistent JSON storage (get, set, delete).
  • 🌐 context.network: Safe fetch implementation (requires 'network' permission).
  • 📂 context.file: Access Bun's File API (requires 'filesystem' permission).
  • 🔐 context.env: Read-only access to environment variables (requires 'env' permission).
  • ⏲️ context.setTimeout/Interval: Automatically cleaned up on unload.

🔒 Security & Permissions

Plugins are restricted by default. To access sensitive APIs, you must explicitly declare permissions:

export class NetworkPlugin implements IPlugin {
  name = "weather-fetcher";
  version = "1.0.0";

  // Request network access
  permissions = [PluginPermission.Network];
  // Whitelist specific domains
  allowedDomains = ["api.weather.com"];

  async onLoad(context: PluginContext) {
    // This works
    const data = await context.network.fetch(
      "https://api.weather.com/v1/forecast"
    );

    // This throws AccessDeniedError (not in whitelist)
    await context.network.fetch("https://malicious.com");
  }
}

🧊 Isolated Worker Plugins

For maximum security and stability, you can load plugins into dedicated workers. These plugins run in a separate process and communicate via RPC.

// Load a plugin from a file into a worker
await manager.registerIsolated(
  "./plugins/ExternalPlugin.ts",
  "isolated-plugin"
);

🔌 Native Bun Integration

bun_plugins can act as a bridge to Bun's native plugin system, allowing your library plugins to handle your application's module resolution.

// In your entry point
const manager = new PluginManager();
await manager.loadPluginsFromDirectory();

// Register as a native Bun plugin
Bun.plugin(manager.toBunPlugin());

🤝 Inter-Plugin Communication

Plugins can share APIs with each other safely:

// Plugin A: Exposes an API
export class ProviderPlugin implements IPlugin {
  name = "db-provider";
  getSharedApi() {
    return {
      query: (q: string) => `Result for ${q}`,
    };
  }
}

// Plugin B: Consumes the API
export class ConsumerPlugin implements IPlugin {
  name = "app-logic";
  async onLoad(context: PluginContext) {
    const db = context.getPlugin("db-provider");
    const result = db.query("SELECT *");
  }
}

📜 License

MIT © memelser