Extensions
Introduction
Webfuse Extensions are a way to add new functionality to spaces, tabs and browsed websites. Extensions give you access to the source code of the original website, user interface of the webfuse session and even possibility to run code on a separate browser thread by letting you create a service worker.
Format
We aim to follow well-known browser's extensions format. You can read more about extensions here and here.
In a nutshell, extensions are a collection of files that can be loaded into a space session. Each file has a specific role and is loaded in different ways.
The entry point of the extension is the manifest.json
file which is a JSON file that contains information about the extension.
Let's take a look at an example of a simple manifest.json
file which allows you to load 4 different components of the extension: a worker script, a content script, a popup window and a custom new tab page.
{
// Manifest version. We only support version 3
"manifest_version": 3,
// The name of the extension
"name": "example-extension",
// The version of the extension
"version": "1.0",
"action": {
// This is the popup window which will be opened when the user clicks on a button in the extension. It is available for all session participants.
"default_popup": "popup.html"
},
"background": {
// The service worker which runs in a separate thread. It is available for all session participants.
"service_worker": "background.js"
},
"content_scripts": [
{
// List of content scripts which will be loaded in all tabs. It is loaded only on the tab's owner side.
// Please note, content script is not loaded in the custom new tab page.
"js": ["content.js"],
// Coming soon. List of tabs' URLs which will be matched by the content script.
"matches": ["<all_urls>"]
}
],
// The new tab page which will be opened when the user clicks on a button in the extension. It is available for all session participants.
"chrome_url_overrides": {
"newtab": "newtab.html"
}
}
How to Install an Extension
Extensions are only available for space sessions. So, in order to load an extension in a space session, you need to follow these steps:
- Create a space or join an existing space with admin privileges in Chrome browser.
- Start a space session.
- Open the space editor panel.
- Click on the "Extensions" button.
- Click on the "Add new" button.
- Select the folder containing the extension you want to load.
- Click on the "Load extension" button.
- The extension will be loaded in the space session.
How to Update an Extension
To update an extension, follow the same steps as for loading an extension, only select the extension which you want to update in the list of installed extensions and click on the "Refresh extension" button.
Communication beetween components
All components of the extension can communicate with each other. Messaging between components is implemented similar to the Extension Messaging API.
There are 2 ways to send messages between components:
Sending messages
Sending a message from any component to popup, service worker, and new tab page:
surflyExtension.runtime.sendMessage(message);
Sending message from popup, service worker, and new tab to the tab content script:
NB: Currently, tabId
parameter is ignored and the message is sent to all content scripts of all the tabs in the session.
surflyExtension.tabs.sendMessage(tabId, message);
Listening for extension messages
surflyExtension.runtime.onMessage.addListener((message, sender) => {});
Message API
In addition to traditional messaging, we provide a message API which allows you to send messages to all extensions in the session. This functionality can be used to communicate with extensions loaded on other participants' side.
There are 2 ways to send messages to all extensions in the session:
JS API:
surflyExtension.surflySession.broadcastMessage(message);
REST API:
Using JS API
Using Javascript API
Webfuse Javascript API is available in all components of the extension.
surflyExtension.surflySession.apiRequest({cmd: <cmd_to_execute>, ...params});
List of available commands match Javascript API methods.
However, currently instead of using the method directly you need to pass the command name to the cmd
parameter.
Available commands:
end
, relocate
, log
, open_tab
, make_host
, pause_tabs
, request_control
, request_to_host
, request_tab_control
, transfer_tab_control
, get_session_participants
, get_session_tabs
, activate_tab
, revoke_tab_control
, return_tab_control
, pause_tabs
, resume_tabs
, toggle_videochat_fullscreen
, toggle_videochat_mode
, toggle_videochat_microphone
, start_screensharing
, toggle_drawing
, upload_file
, send_chat_message
, broadcast_message
Parameters of the commands correspond to API methods defined in Surfly Session Object.
NB: We are currently working on implementing Chrome-like API for the extension. In the future, cmd
method will be removed.
Listening for session events
All session events are also delivered to all components of the extension.
surflyExtension.surflySession.onMessage.addListener(messageData => {
if (messageData.event_type === 'relocated') {
console.log('Session relocated to: ', messageData.url);
}
});
Example extension
Here is an example of a simple extension that allows you to load 4 different components of the extension: an extension service worker script, a content script, a popup window and a custom new tab page.
This extension listens for relocated
session events in the service worker, propagates the event to the popup window, content script and new tab page. Also, it implements the relocate
command which allows you to change the session location from the custom new tab page.
Full source code of the example extension can be found here.
manifest.json
{
"manifest_version": 3,
"name": "Surfly Extension",
"version": "0.1",
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
],
"chrome_url_overrides": {
"newtab": "newtab.html"
},
"action": {
"default_popup": "popup.html"
}
}
newtab.html
<form id="url-form" onsubmit="goTo(); return false">
<input type="url" name="url" id="url" placeholder="Enter URL" />
</form>
<script>
function goTo() {
const url = document.getElementById('url').value;
surflyExtension.surflySession.apiRequest({
cmd: 'relocate',
url,
newTab: false,
});
}
surflyExtension.runtime.onMessage.addListener((message, sender) => {
if (message?.event_type === 'relocated_propagated') {
console.log('newtab received relocated propagated message', message);
}
});
</script>
popup.html
<html>
<head>
<title>Popup</title>
</head>
<body>
<script>
surflyExtension.runtime.onMessage.addListener((message, sender) => {
if (message?.event_type === 'relocated_propagated') {
console.log('popup received relocated propagated message', message);
}
});
</script>
</body>
</html>
background.js
surflyExtension.surflySession.onMessage.addListener((message, sender) => {
if (message?.event_type === 'relocated') {
console.log('background received relocated message', message);
surflyExtension.runtime.sendMessage({
event_type: 'relocated_propagated',
from: 'background',
});
surflyExtension.tabs.sendMessage(null, {
event_type: 'relocated_propagated',
from: 'background',
});
}
});
content.js:
surflyExtension.runtime.onMessage.addListener((message, sender) => {
if (message?.event_type === 'relocated_propagated') {
console.log('content received relocated propagated message', message);
}
});
How to Uninstall an Extension
To uninstall an extension, follow the same steps as for loading an extension, only select the extension which you want to uninstall in the list of installed extensions and click on the "Delete" button.