
Research
/Security News
Miasma Mini Shai-Hulud Hits ImmobiliareLabs npm Packages
Miasma Mini Shai-Hulud hits @immobiliarelabs Backstage plugins, targeting GitLab and LDAP auth packages on npm.
subetha-bridge
Advanced tools
Host SubEtha clients and messages
version 0.0.2-alpha by Bemi Faison
SubEtha-Bridge (or Bridge) is a supporting library within the SubEtha messaging architecture. A bridge routes messages between clients on the same bridge, and relays messages between bridges on the same "network" - i.e., the channel and url origin.
Bridges primarily implement the SubEtha protocol for communicating with Clients, and require zero configuration. Some security, monitoring and bootstrapping options are available.
Note: Please see the SubEtha project page, for important background information, plus development, implementation, and security considerations.
The Bridge module runs in a web page that is separate from your application code. Bridges are loaded in iframes by the SubEtha-Client library, as needed.
Implementing your own Bridge is a simple matter of hosting a static web page. The web page should do little more than load the Bridge module, except for however you choose to customize it's behavior.
Below demonstrates a complete bridge implementation that you could host on any server.
<!doctype html>
<html>
<head>
<script src="path/to/subetha-bridge.min.js"></script>
<title>My SubEtha-Bridge</title>
</head>
</html>
If the url to your bridge were http://my.site.com/bridge.html, clients could then connect to it in their applications, like so:
// open a channel on your bridge
var myAppClient = new Subetha.Client();
myAppClient.open('some-channel@my.site.com/bridge.html');
If applications plan to use several clients with your bridge, they might set and use a convenient alias, instead.
// define an alias to your bridge url
Subetha.urls.mybridge = 'my.site.com/bridge.html';
// open a channel using an alias
var myAppClient = new Subetha.Client();
myAppClient.open('some-channel@mybridge');
The Bridge module has a bootstrap process that involves capturing the first message event - sent via postMessage, from the SubEtha-Client in the parent window. It is strongly recommended that you load the Bridge module synchronously (via a SCRIPT tag, or otherwise, before the DOM is ready). If you do load the Bridge module asynchronously, you must capture the first message event and pass it's data, manually.
Below demonstrates loading the Bridge module with require.js and capturing the first message event. It ensures the bridge is only initialized when both it and the event are available, regardless of load order.
<!doctype html>
<html>
<head>
<script data-main="scripts/config" src="js/require.js"></script>
<script>
(function () {
var
bridgeRef,
bootData;
window.addEventListener('message', function myCb(evt) {
// remove our one-time listener
window.removeEventListener('message', myCb);
// capture data from first message
bootData = evt.data;
tryBridgeInit();
});
requirejs(['subetha-bridge'], function (SBridge) {
// capture bridge reference
bridgeRef = SBridge;
tryBridgeInit();
});
//initialize bridge when both are ready
function tryBridgeInit() {
if (bridgeRef && bootData) {
// start bridge with captured data
bridgeRef.init(bootData);
}
}
})();
</script>
</head>
</html>
Note: The above leaves scripts/config to configure the "subetha-bridge" module path and dependencies.
Bridges handle two types of client requests: authentication requests, and message-relay requests. These requests are accepted by default, such that any client may join a channel and send any message.
To handle requests manually, simply subscribe to the "auth" and/or "relay" events. Callbacks receive a request object, which represents the suspended state of a request. Requests may be answered asynchronously, but can only be answered once.
// handle client authentication requests
SBridge.on('auth', function (req) {
// perform logic now and/or handle this request later
});
// handle message relay requests
SBridge.on('relay', function (req) {
// perform logic now and/or handle this request later
});
To answer a request invoke it's #allow(), #deny(), or #ignore() method. The first call to any method will return true, but once handled these methods (do nothing and) return false.
SBridge.on('auth', function (req) {
if (req.client.origin != 'http://example.com') {
// the first method called, wins
req.deny(); // returns `true`
}
// does nothing if already denied
req.allow(); // returns `false`
});
Note: The same request object is passed to all callbacks. If using multiple callbacks for an event, ensure only - and, at least - one handles the request object.
To restore the default behavior, remove all subscriptions to the given event type. Invoke #off(), passing only the event type.
// re-enable default handling of authentication requests
SBridge.off('auth');
// re-enable default handling of message-relay requests
SBridge.off('relay');
Authentication-requests may be handled in any order, and are stored in the SBridge.pendingAuths hash until processed. If your bridge employs some form of authorization, requests expose any credentials given by the client, in a .credentials array. (An empty array, means no credentials were sent.)
SBridge.on('auth', function (req) {
if (req.credentials.length) {
// verify credentials, now or later
} else {
req.deny();
}
});
Message-relay requests can only be handled in the order they are received. When a request is suspended, it is passed to subscribers of the "relay" event, and set in the SBridge.pendingRelay namespace.
It's important to consider latency, when processing a relay request. More message-relay requests will pile up as you perform your logic, which can reduce perceived performance of your bridge. Try to handle message-relay requests immediately, instead of asynchronously.
Below, demonstrates logic that prevents broadcast messages - messages without a recipient.
SBridge.on('relay', function (req) {
// the message has no client id in the "to" field
if (!req.msg.to) {
req.deny();
} else {
req.allow();
}
});
The following events are available for you to observe, on the Bridge module directly.
Note: Unlike the SubEtha-Client module, Bridge events are not prefixed.
Below demonstrates logic that observes when a new client has been authenticated by the current bridge.
SBridge.on('join', function (client) {
if (SBridge.id == client.bid) {
// do something, now that a client joined via this bridge
}
});
Below is reference documentation for the SubEtha-Bridge module.
A singleton, representing the client authorization and message routing logic for the window.
The bridge fires the following events.
request - An object representing the suspended request.request - An object representing the suspended request.client - A reference to the client that recently joined the network.client - A reference to the client that recently left the network.msg - The message relayed on the network.End handling network clients and messages. You can not reuse the bridge once destroyed.
SBridge.destroy();
Triggers callbacks, subscribed to this event.
SBridge.fire(event [, args, ... ]);
Begin handling network clients and messages.
SBridge.init(token);
This method simply exits if the bridge has already been initialized.
Unsubscribe callback(s) from an event. When invoked with no arguments, all subscriptions are removed.
SBridge.off([event [, callback [, scope]]]);
Subscribe a callback to an event.
SBridge.on(event, callback [, scope]);
Indicates when the bridge is incompatible with the runtime environment.
A hash to uniquely identify this bridge.
The name of the network, as prescribed by the bootstrap token.
The last pending message relay request object. If no relay is pending, the value is null.
Hash of pending authorization request objects. Keys are of clients waiting to gain access.
The SemVer compatible version of the SubEtha protocol supported by this module.
The SemVer compatible version of this module.
SubEtha-Bridge works within, and is intended for, modern JavaScript browsers. It is available on bower, component and npm as a CommonJS or AMD module.
If SubEtha-Bridge isn't compatible with your favorite runtime, please file an issue or pull-request (preferred).
SubEtha-Bridge depends on the following modules:
SubEtha-Bridge also uses the following ECMAScript 5 and HTML 5 features:
You will need to implement shims for these browser features in unsupported environments. Note however that postMessage and localStorage shims will only allow this module to run without errors, not work as expected.
Use a <SCRIPT> tag to load the subetha-bridge.min.js file in your web page. The file includes all module dependencies, for your convenience. Doing so, adds SBridge to the global scope.
<script type="text/javascript" src="path/to/subetha-bridge.min.js"></script>
<script type="text/javascript">
// ... SubEtha-Bridge dependent code ...
</script>
Note: The minified file was compressed by Closure Compiler.
npm install subetha-bridgecomponent install bemson/subetha-bridgebower install subetha-bridgeAssuming you have a require.js compatible loader, configure an alias for the SubEtha-Bridge module (the term "subetha-bridge" is recommended, for consistency). The subetha-bridge module exports a module namespace.
require.config({
paths: {
'subetha-bridge': 'libs/subetha-bridge'
}
});
Then require and use the module in your application code:
require(['subetha-bridge'], function (SBridge) {
// ... SubEtha Bridge dependent code ...
});
Warning: Do not load the minified file via AMD, since it includes modular dependencies that themselves export modules. Use AMD optimizers like r.js, in order to roll-up your dependency tree.
Note: When loaded asynchronously, you must manually bootstrap this module. (See the usage section for more details.)
SubEtha-Bridge is available under the terms of the Apache-License.
Copyright 2014, Bemi Faison
FAQs
Host SubEtha clients and messages
The npm package subetha-bridge receives a total of 2 weekly downloads. As such, subetha-bridge popularity was classified as not popular.
We found that subetha-bridge demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

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.

Research
/Security News
Miasma Mini Shai-Hulud hits @immobiliarelabs Backstage plugins, targeting GitLab and LDAP auth packages on npm.

Security News
Rolldown paused Rust React Compiler integration after a 5MB binary size increase raised concerns about shipping React-specific code to all Vite users.

Security News
/Research
Mini Shai-Hulud expands into the Go ecosystem after hitting LeoPlatform npm packages and targeting GitHub Actions workflows.