@josephuspaye/chrome-native-bridge
v0.3.0
Published
A utility for building Chrome native messaging hosts with Node.js
Downloads
8
Readme
chrome-native-bridge
A utility for building Chrome native messaging hosts with Node.js. Allows you to write Node scripts that can communicate bi-directionally with extensions and apps in Chrome.
This project is part of #CreateWeekly, my attempt to create something new publicly every week in 2020.
Installation
npm install @josephuspaye/chrome-native-bridge --save
Usage
The following example shows a Node script that echoes all messages sent to it from Chrome. Note that it doesn't use console.log()
, as that writes to stdout, which Chrome reads for messages.
import { ChromeNativeBridge } from '@josephuspaye/chrome-native-bridge';
const bridge = new ChromeNativeBridge(
process.argv, // The arguments to the current process
process.stdin, // The input stream that Chrome writes to
process.stdout, // The output stream that Chrome reads from
{
onMessage(message) {
// A message has been received, echo it
// by sending it back
bridge.emit(message);
},
onError(err) {
// There's been an error parsing a received message.
// Do something to handle it here...
},
onEnd() {
// End of `process.stdin` detected: it's likely Chrome wants
// to end the native host process, so we exit here
process.exit();
},
}
);
// This is the origin of the caller, usually chrome-extension://[ID of allowed extension]
const origin = bridge.origin;
// This is the decimal handle value of the calling Chrome window. Available on Windows only.
const parentWindow = bridge.parentWindow;
Example
There is an example native host script and a corresponding Chrome extension at example/host and example/extension respectively. Together they implement a basic text chat to demonstrate communication over the native bridge.
You can view a demonstration GIF (2MB) here.
Get it
- Clone this repo:
git clone https://github.com/JosephusPaye/chrome-native-bridge.git
- Change into the cloned directory:
cd chrome-native-bridge
- Install dependencies:
yarn
(ornpm install
)
Install it
Open the Extensions page in Chrome (navigate to chrome://extensions), enable developer mode, click "Load unpacked", and then select the example/extension folder in the repo.
When the extension is loaded, copy the generated ID, change it to the form chrome-extension://EXTENSION_ID_HERE/
, and paste it into the example/host/manifest.json file, in the allowed_origins
array.
Next, install the host manifest by running the following in a Command Prompt, from the repo root directory:
example\host\install.bat
Similarly, you can uninstall the host manifest by running example\host\uninstall.bat
.
Note: the install and uninstall scripts are Windows only, but similar scripts can be written for Linux or macOS.
Run it
Start the example/host/chat.js script in Node, by running the following from the repo root directory.
node example/host/chat.js
This will start the native chat client and wait for a connection from the host script, which will be launched by Chrome when it connects.
In Chrome, navigate to chrome://apps and launch the Chrome Native Bridge example app, then click "Connect to chat". If the host manifest was installed correctly, Chrome will connect to the host, and a chat interface will be shown.
You can now exchanges messages between the Chrome app and the native chat.js
script by typing in the input in Chrome, or the terminal running the chat.js
script.
API
ChromeNativeBridge
class
Implements the Chrome Native Messaging protocol and provides a nicer interface over stdin/stdout for communicating with a Chrome extension from a native Node script.
class ChromeNativeBridge<TSend = any, TReceive = any> {
/**
* Origin of the caller, usually chrome-extension://[ID of allowed extension]
*/
origin: string;
/**
* The decimal handle value of the calling Chrome window. Available on Windows only.
*/
parentWindow?: number;
/**
* Create a new bridge with the given input and output.
*
* @param args The arguments to the script. Use `process.argv`.
* @param input A readable stream for getting messages from Chrome. Use `process.stdin`.
* @param output A writable stream for sending message to Chrome. Use `process.stdout`.
*/
constructor(
args: string[],
input: stream.Readable,
output: stream.Writable,
options: {
onMessage: OnMessageHandler<TReceive>;
onError: OnErrorHandler;
onEnd: OnEndHandler;
mirrorInputTo?: Writable;
mirrorOutputTo?: Writable;
}
);
/**
* Send the given data to the output. The data will be passed to
* `JSON.stringify()` for serialisation, and will throw an error
* [if `JSON.stringify()` throws](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#Exceptions).
*/
emit(data: TSend): void;
/**
* Close the bridge.
*/
close(): void;
}
Types
The following additional types are used by the ChromeNativeBridge class:
/**
* An error that occurs while sending or receiving messages.
*/
type ChromeNativeBridgeError = Error & {
type: 'SEND_ERROR' | 'RECEIVE_ERROR';
};
/**
* Handle a new message.
*/
type OnMessageHandler<T> = (message: T) => void;
/**
* Handle an error receiving data. The second parameter
* is the raw string of the message that caused the error.
*/
type OnErrorHandler = (err: ChromeNativeBridgeError, data: string) => void;
/**
* Handle the end of the input stream. This can be used to know when
* to exit the native host process, since it seems like when Chrome
* wants to end the process, it closes stdin, triggering its 'end'
* event (at least from every case I've observed so far).
*/
export type OnEndHandler = () => void;
Related
- jdiamond/chrome-native-messaging: similar project that solves the same problem with a lower-level stream API
- JosephusPaye/pipe-emitter: inter-process event emitter that allows for communicating with the native messaging host from another process