🚀 DAY 1 OF LAUNCH WEEK: Reachability for Ruby Now in Beta.Learn more →
Socket
Book a DemoInstallSign in
Socket

@webext-pegasus/rpc

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@webext-pegasus/rpc

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

latest
Source
npmnpm
Version
0.3.6
Version published
Maintainers
1
Created
Source

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};
}

Keywords

chrome

FAQs

Package last updated on 04 Aug 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts