![Create React App Officially Deprecated Amid React 19 Compatibility Issues](https://cdn.sanity.io/images/cgdhsj6q/production/04fa08cf844d798abc0e1a6391c129363cc7e2ab-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Create React App Officially Deprecated Amid React 19 Compatibility Issues
Create React App is officially deprecated due to React 19 issues and lack of maintenance—developers should switch to Vite or other modern alternatives.
Mosi is a minimal Javascript library (written in Typescript) that simplifies Chrome extension messaging. Mosi makes communication organized and intuitive through a declarative, event-driven, pub/sub API with built-in logging.
Check out Saka Key to see how Mosi is used in a real extension.
init({
// set log to true to enable logging
log: boolean
// which messages it subscribes to
subscriptions: [string],
// actions to execute in background page once a node is connected
onConnect: [{action: string, arg: any}],
// actions to execute in background page when a node disconneced
onDisconnect: [{action: string, arg: any}}],
// action handlers to execute when a message is received
actions: {
action1: (arg, src) => { doSomething(arg, src); },
action2: (arg, src) => { doSomething(arg, src); },
...
}
// callback to execute locally when a node disconnects
onClientDisconnect: () => void,
});
msg(
// the node(s) that should receive the message
target,
// specifies which action handler will be called by receivers
action,
// the argument to be passed to the action handlers
arg
);
// get returns a promise of an array of results
const result = await get(
// the node(s) that should receive the message
target,
// specifies which action handler will be called by receivers
action,
// the argument to be passed to the action handlers
arg,
// how many milliseconds to wait for the response before a timeout exception is thrown
timeout
);
// the value returned by the action handler
result[0].v
// the error reported on the target node
result[0].e
// the id of the node
result[0].id
This is code for an extension that displays a count on every tab. The count starts at 0 and can be incremented by pressing a button. All tabs share the same count so that when the count is incremented from one tab, the change is synchronized to all other tabs.
import { init, msg } from 'mosi/core';
let count = 0;
init({
log: true,
actions: {
INCREMENT: (increment = 1) => {
count += increment;
msg('count', 'NEW_COUNT', count);
},
COUNT: (_, src) => {
msg(src, 'NEW_COUNT', count);
}
}
});
The background page stores the count value. It declares two actions that other nodes can trigger: INCREMENT and COUNT.
If INCREMENT is triggered, the count is incremented and a message is sent to every node that subscribes to 'count' with the updated count value.
If COUNT is triggered, it sends a message to the source node that issued COUNT with the current value of count.
import { init, msg } from 'mosi/client';
// Inject Counter GUI into topright of page
const counter = document.createElement('div');
counter.setAttribute('style', 'z-index: 99999; position: fixed; top: 0; right: 0;');
counter.innerHTML = '<button id="increment">Increment</button><input id="count" disabled/>';
document.body.appendChild(counter);
init({
log: true,
subscriptions: ['count'],
onConnect: [{ action: 'COUNT' }],
actions: {
NEW_COUNT: (count) => {
document.getElementById('count').value = count;
}
}
});
document.getElementById('increment').addEventListener('click', () => {
msg(1, 'INCREMENT');
});
The content script injects an increment button and counter into each page. It subscribes to 'count' to receive all actions issued via net('count'). It specifies that the background page should execute the COUNT action on connection. It declares a single action, NEW_COUNT, which updates the displayed count with the given count. It then adds a listener to the increment button that sends an INCREMENT message to the background page (through the pre-defined target 1).
npm install --save mosi
This exposes the following modules:
You can then import from the appropriate module.
import { init, net } from 'mosi/core';
init({ actions: { NADA: () => {} } });
msg(1, 'HELLO');
Your extension will not work if you import from the wrong module. Currently, Mosi requires an es6 environment and a module bundler with support for es6 import/export syntax like Webpack 2. See any of the examples in the test-extension directory, or check out Saka Key to see how Mosi is used in a real extension.
The following functions are provided by each package:
init
initializes a node for messaging, and in the case of a client node, connects it to the core. It must be called before any calls to msg() or get(). It accepts a configuration object with properties log
, subscriptions
, onConnect
, onDisconnect
, and actions
. All properties are optional.
log
is a boolean parameter that enables logging when set to true
. Logging is disabled by default.
subscriptions
is an array of string specifying a node's subscriptions. This is how a node declares to the world it wants to receive all messages for a given subscription. When sending a message using msg
or get
from any node, you can specify a subscription as the target, and all nodes that have the target subscription will receive the message.
onConnect
is an array of actions descriptors that the core executes as soon as a client node is connected. Every action descriptor is an object that must have an action
property corresponding to the type of action to execute. The optional arg
property
onDisconnect
is an array of action descriptors that the core executes as soon as it detects a client has disconnected.
actions
is an object whose keys are action types and values are action handlers. An action handler is a function that is called a message is received. All calls to msg
and get
must specify the name of the action to be executed. If a client receives a message for an action type it doesn't have a handler for, it throws an error. The first argument of an action handler is the arg
specified by the call to msg
or get
by the sending node. The second argument is the src
node identifier, which is an integer. You can send a response back to the message source from a handler by calling msg
or get
and specifying src
as the target. The value returned by an action handler is the result returned to calls to get
.
onClientDisconnect
is a callback to execute when a node disconnects. This property is only valid in Mosi clients, not the core background page.
init({
// which messages it subscribes to
subscriptions: [string],
// actions to execute once the node is connected
onConnect: [{action: string, arg: any}],
// actions to execute when the node disconnects
onDisconnect: [{action: string}],
// action handlers to execute when a message is received
actions: {
action1: (arg, src) => { doSomething(arg, src); },
action2: (arg, src) => { doSomething(arg, src); },
...
}
// callback to execute locally when a node disconnects
onClientDisconnect: () => void,
});
msg
sends a message to target node(s). Specify the target
node(s) that will receive the message and the name of the action
handler that targets execute when they receive the message. Optionaly specify an argument
to be passed to the action handler.
target
describes the nodes that should receive a message. target
may be an integer that identifies a single node, or a condition string that limits which nodes receive the message.
Integer Targets:
src
node id is available as the second argument of all action handlers to make replying to messages easy.String Targets
A string target specifies conditions that must be specified for a node to receive a message. The most common type of condition is a subscription - only nodes with a given subscription receive a message.
Other conditions take the form of selectors like only 'only nodes in the tab with id 4' or 'only nodes in frames with id 0.' Conditions can be cominbined with '&' so that 'a&b' means a node will only receive a message if it meets both conditions 'a' and 'b'. Conditions can also be combined with '|' so that 'a|b' means a node will receive a message if it meets either condition 'a' or 'b'. & has higher precedence than |.
The reserved condtion strings are: tab[N]
, frame[N]
, id[N]
, topFrame
, childFrames
, thisTab
, other
, and otherFrames
Examle target strings:
'onlyCoolMessages'
- only nodes subscribing to 'onlyCoolMessages''tab[1]'
- only nodes in tab with id 1'tab[3]&frame[2]'
- only the node in tab id 3 and frame id 2'tab[2]&topFrame'
- only the node in tab id 2 in the top frame'tab[5]&childFrames'
- all nodes in tab id 5 that aren't the top node'id[23]'
- only the node with id 23, this is equivalent to the integer target 23
'cats&topFrame&tab[3]'
- only nodes subscribing to cat that are in the top frame and in tab id 3'dog|food&topFrame'
- nodes that subscribe to 'dog' or (subscribe to 'food' and are in the top frame)'rats|lions|zebras'
- nodes that subscribe to 'rats' or 'lions' or 'zebras'thisTab
- all frames in the current tabmango&other
- only nodes subscribing to 'mango' but not the current nodethisTab&otherFrames
- all frames in the current tab except the source frame, NOTE: otherFrames
should always be used in conjunction with thisTab
action
is a string corresponding to the name of the action handler to be executed by target nodes. Target nodes that don't have a handler for the specified action will throw errors.
arg
is an optional argument to be passed to the action handler of target nodes. If you want to pass multiple arguments, simply package them as properties of a single object, e.g. msg(1, 'COOORDINATES', { x, y });
.
msg(
// the node(s) that should receive the message
target,
// specifies which action handler will be called by receivers
action,
// the argument to be passed to the action handlers
arg
);
get
sends a message to target node(s) and returns a promise for an array of responses from every messaged node. The first arguments of get
are identical to the argumentss of msg
, but an optional third argument timeout
specifies how many milliseconds to wait for the response before a timeout exception is thrown. The default timeout is 5 seconds. A response is an array of objects, one per target node. Each object has exactly one of two properties: v
and e
. v
is short for value, which will be set to the value returned by the target node's action handler. e
is short for error, and will be set if something went wrong retreiving the response.
// get returns a promise of an array of results
const result = await get(
// the node(s) that should receive the message
target,
// specifies which action handler will be called by receivers
action,
// the argument to be passed to the action handlers
arg
// how many milliseconds to wait for the response before a timeout exception is thrown
timeout
);
// the value returned by the action handler
result[0].v
// the error reported on the target node
result[0].e
meta
is a function that takes a node id as its only argument. It returns basic information about that node. meta
is only available on the core node, not on client nodes. meta
returns an object of the form:
{
frameId: frameId,
tabId: tabId,
// https://developer.chrome.com/extensions/runtime#type-MessageSender
sender: MessageSender,
subs: [subscriptions],
data: { custom properties }
};
If you want to associate data with a connection, add it to the data
property, which is intialized to an empty object. This data will be persistent for the lifetime of the connection. All other propeties are read only.
This following action handler function loadClient
shows how a background page uses meta to query the tabId and fameId of a node so it can dynamically insert a script into that node.
function loadClient (_, src) {
const { frameId, tabId } = meta(src);
chrome.tabs.executeScript(tabId, {
file: 'content_script.js',
frameId,
});
};
Note that Mosi has not been optimized for performance and there is significant leeway to improve it.
All contributions welcome.
If you encounter a bug, create an issue. If you're amazing, fix it and submit a pull request.
If you have any suggestions, create an issue for discussion.
Mosi's API is minimal and simple, but may be a little inflexible given a node's actions and subscriptions are declared statically. If you can provide a use case for dynamic actions and subscriptions and an elegant API, please create an issue.
FAQs
Simpler messaging for chrome extensions
The npm package mosi receives a total of 6 weekly downloads. As such, mosi popularity was classified as not popular.
We found that mosi 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.
Security News
Create React App is officially deprecated due to React 19 issues and lack of maintenance—developers should switch to Vite or other modern alternatives.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.