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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@webext-pegasus/rpc

v0.3.6

Published

RPC Messaging in Web Extensions made easy and type safe. Out of the box.

Downloads

2,794

Readme

webext-pegasus Logo

@webext-pegasus/rpc

License GitHub Actions Workflow Status Package version

RPC Messaging in Web Extensions made easy and type safe. Out of the box. It provides a simple type-safe wrapper around the web extension messaging APIs that lets you call a function/class from anywhere, but execute it in the target runtime context.

Supports

  • Runtime contexts: window (injected script), popup, devtools, content script, background, options, sidepanel (planned)
  • Browsers: Chrome, Firefox, Safari, Opera, Edge + others supported by webextension-polyfill

🚀 Quick Start

npm install -S @webext-pegasus/transport @webext-pegasus/rpc
  • Create service in a form of a class or function that implements IPegasusRPCService<YourService>
  • Export TypeScript interface for it
  • Register interface via registerRPCService('serviceName', yourService) in the target runtime context (ex: background)
  • Acquire service wrapper via getRPCService<YourServiceType>('serviceName', 'background')
    • That's it! Now you can call it from any other place in your extension!

[!TIP] Refer to ./packages/example-extension for more examples.

MathService.ts

import {IPegasusRPCService, PegasusRPCMessage} from '@webext-pegasus/rpc';

export type IMathService = InstanceType<
  typeof MathService
>;

export class MathService
  implements IPegasusRPCService<MathService>
{
  // Every public method shall:
  // - accept "sender: PegasusRPCMessage" as first parameter, if it accepts any params
  // - accept / return only serializable values, as RPC messages must be serialized as they move between extension contexts 
  // See "./src/types.test.ts" for more examples
  fibonacci(_sender: PegasusRPCMessage, num: number): number {
    return this.#fibonacciImpl(num);
  }

  // We keep implemenation in private method as we don't need sender information here
  #fibonacciImpl(num: number): number {
    return (num <= 1) ? 1 : this.#fibonacciImpl(num - 1) + this.#fibonacciImpl(num - 2);
  }
}

background.ts

import {registerRPCService} from '@webext-pegasus/rpc';
import {initPegasusTransport} from '@webext-pegasus/transport/background';

import {MathService} from './MathService.ts';

// Done once in every runtime context to init transport layer
initPegasusTransport();

registerRPCService(
  'MathService',
  new MathService(),
);

injected.ts

// Important to import type only as we don't want to cause any errors by injecting
// code that expects web extension runtime to be loaded on target webpag
import type {IMathService} from './MathService.ts';

import {getRPCService} from '@webext-pegasus/rpc';
import {initPegasusTransport} from '@webext-pegasus/transport/window';

// Done once in every runtime context to init transport layer
initPegasusTransport();

const mathService = getRPCService<IMathService>(
  // Same ID that was used for registration
  // We may have multiple instances of the same service executed independently
  'MathService',
  // Where sevice was registered
  'background',
);

// Note that now mathService.fibonacci() returns Promise
mathService.fibonacci(10).then(console.log);
// Output: 89

Functional services

This library also allows you to define RPC service as a function (as showcased in example).

getTestHelloService.ts

import {PegasusRPCMessage} from '@webext-pegasus/rpc';

export type ITestHelloService = typeof getTestHelloService;

export function getTestHelloService(
  _message: PegasusRPCMessage,
  name: string,
): string {
  return `Warmest hello for ${name} from the service!`;
}

Which can be later called (don't forget to register it first via registerRPCService) in the following way:

const getTestHelloService = getRPCService<ITestHelloService>(
  'getTestHello',
  'background',
);

getTestHelloService('Mike').then(console.log);
// Will print: 
// Warmest hello for Mike from the service!

PegasusRPCMessage

Message information provided as a first parameter to every public method of Pegasus RPC service serves a purpose of identifying caller identity and providing relevant response.

This is useful for example to create a SelfIDService that allows to retrieve it's tabId and frameId for content script, window script or popup.

getSelfIDService.ts

import {PegasusRPCMessage} from '@webext-pegasus/rpc';
import browser from 'webextension-polyfill';

export type ISelfIDService = typeof getSelfIDService;

export async function getSelfIDService(message: PegasusRPCMessage): Promise<{
  tabId: number;
  frameId?: number;
}> {
  let tabId: number | undefined = message.sender.tabId;
  if (message.sender.context === 'popup') {
    tabId = (await browser.tabs.query({active: true, currentWindow: true}))[0]
      .id;
  }
  if (tabId === undefined) {
    throw new Error(`Could not get tab ID for message: ${message.toString()}`);
  }
  return {frameId: message.sender.frameId, tabId};
}