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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@eidos.space/electron-ipc

v0.1.0

Published

Decorator-based IPC framework for Electron with automatic method discovery

Readme

@eidos.space/electron-ipc

Decorator-based IPC framework for Electron with automatic method discovery.

Features

  • Zero Boilerplate: Define IPC handlers with simple decorators
  • Automatic Method Discovery: No need to manually list methods in preload
  • Type Safety: Full TypeScript support with automatic type inference
  • Natural Error Handling: Errors throw naturally, just like direct function calls
  • Flexible Exposure Control: Choose between exposing all methods or only decorated ones

Installation

pnpm add @eidos.space/electron-ipc

Quick Start

1. Define an IPC Service

import { IpcService, IpcServiceBase } from "@eidos.space/electron-ipc"

@IpcService("my-service")
class MyService extends IpcServiceBase {
  async getData(id: string) {
    return { id, name: "Example" }
  }

  async saveData(data: any) {
    // Save logic here
    return { success: true }
  }
}

2. Register in Main Process

import { setupRegistryIpc } from "@eidos.space/electron-ipc"

app.whenReady().then(() => {
  // Setup registry IPC (required for auto-discovery)
  setupRegistryIpc()

  // Create and register service
  const myService = new MyService()
  myService.register()
})

3. Expose in Preload

import { createPreloadApiByNamespace } from "@eidos.space/electron-ipc"

contextBridge.exposeInMainWorld("eidos", {
  myService: createPreloadApiByNamespace("my-service"),
})

4. Use in Renderer

// Direct return value - no wrapper!
const data = await window.eidos.myService.getData("123")
console.log(data) // { id: "123", name: "Example" }

// Errors throw naturally - use try/catch
 try {
   await window.eidos.myService.saveData({ invalid: true })
 } catch (error) {
   console.error("Save failed:", error)
 }

API Reference

Decorators

@IpcService(namespace, options?)

Class decorator to mark a service as an IPC service.

  • namespace: The IPC channel namespace (e.g., "browser-view", "opendata")
  • options?.exposeMode:
    • "all" (default): Expose all public methods
    • "decorated": Only expose methods with @IpcMethod decorator
@IpcService("browser-view")
class BrowserViewManager extends IpcServiceBase {
  // All public methods are exposed
}

@IpcService("opendata", { exposeMode: "decorated" })
class OpenDataService extends IpcServiceBase {
  @IpcMethod()
  async findAdapters() { /* exposed */ }

  async _privateMethod() { /* not exposed (underscore prefix) */ }
}

@IpcMethod(channel?)

Method decorator to explicitly mark a method for IPC exposure. Only effective when exposeMode: "decorated".

@IpcService("my-service", { exposeMode: "decorated" })
class MyService extends IpcServiceBase {
  @IpcMethod()
  async method1() { /* exposed */ }

  @IpcMethod("custom-channel")
  async method2() { /* exposed as "custom-channel" */ }

  async method3() { /* not exposed */ }
}

Base Class

IpcServiceBase

Abstract base class providing IPC registration functionality.

Methods:

  • register(): Register all IPC handlers. Called automatically, idempotent.
  • unregister(): Unregister all IPC handlers. Call when service is destroyed.
  • getRegisteredMethods(): Get list of registered method names.

Registry Functions

setupRegistryIpc()

Setup the IPC handler for synchronous method retrieval from preload. Must be called in main process before creating services.

import { setupRegistryIpc } from "@eidos.space/electron-ipc"

app.whenReady().then(() => {
  setupRegistryIpc()
  // ... create and register services
})

createPreloadApiByNamespace(namespace)

Create a preload API object for a given namespace. Methods are automatically discovered from the registry.

import { createPreloadApiByNamespace } from "@eidos.space/electron-ipc"

const api = createPreloadApiByNamespace("my-service")
// api now has all methods bound to ipcRenderer.invoke

Types

ExtractIpcApi<T>

Type utility to extract the IPC API type from a service class.

import type { ExtractIpcApi } from "@eidos.space/electron-ipc"
import { MyService } from "./my-service"

type MyServiceApi = ExtractIpcApi<typeof MyService>
// All methods become async and return raw results

Error Handling

Unlike traditional IPC frameworks that wrap responses in { success, data, error } objects, this framework lets errors throw naturally:

// In main process
@IpcService("my-service")
class MyService extends IpcServiceBase {
  async validateUser(id: string) {
    if (!id) throw new Error("ID is required")
    return { id, name: "User" }
  }
}

// In renderer
 try {
   const user = await window.eidos.myService.validateUser("")
   console.log(user)
 } catch (error) {
   // Error throws naturally!
   console.error(error.message) // "ID is required"
 }

This approach:

  • ✅ More intuitive - works like regular async functions
  • ✅ Better TypeScript inference - no need to check result.success
  • ✅ Standard try/catch patterns work as expected
  • ✅ Stack traces preserved

Advanced Usage

Adding Event Listeners

For event-based communication (not request/response), add custom methods in preload:

browserView: {
  ...createPreloadApiByNamespace("browser-view"),
  onUpdate: (viewId: string, callback: (data: any) => void) => {
    const listener = (_: any, id: string, data: any) => {
      if (id === viewId) callback(data)
    }
    ipcRenderer.on("browser-view:update", listener)
    return () => ipcRenderer.removeListener("browser-view:update", listener)
  },
}

Service Lifecycle

class MyService extends IpcServiceBase {
  register() {
    super.register()
    // Additional setup
  }

  unregister() {
    // Cleanup
    super.unregister()
  }
}

// In main process
const service = new MyService()
service.register()

// When done
service.unregister()

Best Practices

  1. Use underscore prefix for private methods: async _privateMethod()
  2. Use exposeMode: "decorated" when you need fine-grained control over exposed methods
  3. Always call setupRegistryIpc() before creating services in main process
  4. Use try/catch for error handling in renderer code
  5. Unregister services when windows are closed to prevent memory leaks

License

MIT