Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

sysend

Package Overview
Dependencies
Maintainers
1
Versions
41
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sysend - npm Package Compare versions

Comparing version 1.14.3 to 1.15.0

2

package.json
{
"name": "sysend",
"version": "1.14.3",
"version": "1.15.0",
"description": "Web application synchronization between different tabs",

@@ -5,0 +5,0 @@ "main": "sysend.js",

@@ -5,4 +5,4 @@ <p align="center">

[![npm](https://img.shields.io/badge/npm-1.14.3-blue.svg)](https://www.npmjs.com/package/sysend)
![bower](https://img.shields.io/badge/bower-1.14.3-yellow.svg)
[![npm](https://img.shields.io/badge/npm-1.15.0-blue.svg)](https://www.npmjs.com/package/sysend)
![bower](https://img.shields.io/badge/bower-1.15.0-yellow.svg)
![downloads](https://img.shields.io/npm/dt/sysend.svg)

@@ -78,2 +78,51 @@ [![jsdelivr](https://img.shields.io/jsdelivr/npm/hm/sysend)](https://www.jsdelivr.com/package/npm/sysend)

### Windows/tabs tracking
Tracking is high level API build on top of `on()` and `broadcast()`, that allows to manage windows/tabs. You can sent message directly to other windows/tabs:
```javascript
sysend.track('message', ({data, origin}) => {
console.log(`${origin} send message "${data}"`);
});
sysend.post('<ID>', 'Hello other window/tab');
```
and listen to events like:
```javascript
sysend.track('open', (data) => {
console.log(`${data.id} window/tab just opened`);
});
```
Other tracking events includes: close/primary/secondary executed when window/tab is closed or become primary or secondary. Track method was added in version 1.6.0. Another required event is `ready` (added in 1.10.0) that should be used when you want to get list of windows/tabs:
```javascript
sysend.track('ready', () => {
sysend.list().then(tabs => {
console.log(tabs);
});
});
```
with `list()` method and `open`/`close` events you can implement dynamic list of windows/tab. That will change when new window/tab is open or close.
In version 1.15.0 new API was added called `rpc()` (build on top of tracking mechanism) that allow to use RPC (Remote Procedure Call) between open windows/tabs.
```javascript
const rpc = sysend.rpc({
get_message() {
return document.querySelector('input').value;
}
});
button.addEventListener('click', () => {
rpc.get_message('<ID>').then(message => {
console.log(`Message from other tab is "${message}"`);
}).catch(e => {
console.log(`get_message (ERROR) ${e.message}`);
});
});
```
### Cross-Domain communication

@@ -131,6 +180,2 @@

## Articles
* [CSRF Protection Problem and How to Fix it](https://www.freecodecamp.org/news/csrf-protection-problem-and-how-to-fix-it/)
* [Synchronizacja stanu aplikacji www między zakładkami](https://bulldogjob.pl/news/1804-synchronizacja-stanu-aplikacji-www-miedzy-zakladkami)
## API

@@ -151,8 +196,8 @@

| `track(event, callback)` | track inter window communication events | event - any of the strings: `"open"`, `"close"`, `"primary"`, <br>`"secondary"`, `"message"`<br>callback - different function depend on the event:<br>* `"message"` - `{data, origin}` - where data is anything the `post()` sends, and origin is `id` of the sender.<br>* `"open"` - `{count, primary, id}` when new window/tab is opened<br>* `"close"` - `{count, primary, id, self}` when window/tab is closed<br>* `"primary"` and `"secondary"` function has no arguments and is called when window/tab become secondary or primary.<br>* `"ready"` - event when tracking is ready. | 1.6.0 except `ready` - 1.10.0 |
| `untrack(event [,callback])` | remove sigle event listener all all listeners for a given event | event - any of the strings `'open'`, `'close'`, `'primary'`, `'secondary'`, or `'message'`. | 1.6.0 |
| `untrack(event [,callback])` | remove single event listener all listeners for a given event | event - any of the strings `'open'`, `'close'`, `'primary'`, `'secondary'`, or `'message'`. | 1.6.0 |
| `isPrimary()` | function returns true if window is primary (first open or last that remain) | NA | 1.6.0 |
| `channel()` | function restrict cross domain communication to only allowed domains. You need to call this function on proxy iframe to limit number of domains (origins) that can listen and send events. | any number of origins (e.g. 'http://localhost:8080' or 'https://jcubic.github.io') you can also use valid URL. | 1.10.0 |
| `useLocalStorage([toggle])` | Function set or toggle localStorage mode. | argument is optional and can be `true` or `false`. | 1.14.0 |
| `rpc(object): Promise<fn(id, ...args): Promise>` | Function accept an object with methods and return a Promise that resolve to object with same methods but async. The result function accept first additional argument that is ID of window/tab that it should sent request to. The other window/tab call the function and return value resolve original promise. | 1.15.0 |
To see details of using the API, see [demo.html source code](https://github.com/jcubic/sysend.js/blob/master/demo.html) or [TypeScript definition file](https://github.com/jcubic/sysend.js/blob/master/sysend.d.ts).

@@ -164,7 +209,18 @@

And the name of the library is just random word "sy" and "send" suffix. But it can be an backronym for **Synchronizing Send** as in sychronizing application between browser tabs.
And the name of the library is just random word "sy" and "send" suffix. But it can be an backronym for **Synchronizing Send** as in synchronizing application between browser tabs.
## Articles
* [CSRF Protection Problem and How to Fix it](https://www.freecodecamp.org/news/csrf-protection-problem-and-how-to-fix-it/)
* [Synchronizacja stanu aplikacji www między zakładkami](https://bulldogjob.pl/news/1804-synchronizacja-stanu-aplikacji-www-miedzy-zakladkami)
## Press
The library was featured in:
* [Web Tools Weekly](https://webtoolsweekly.com/archives/issue-378/)
* [JavaScript Weekly](https://javascriptweekly.com/issues/581)
* [Impressive Webs](https://www.impressivewebs.com/most-interesting-front-end-developer-tools-2021/)
* [Front-end Architecture](https://frontend-architecture.com/2022/03/30/messaging-between-browser-tabs/)
## License
Copyright (C) 2014-2022 [Jakub T. Jankiewicz](https://jcubic.pl/me)<br/>
Copyright (C) 2014-2023 [Jakub T. Jankiewicz](https://jcubic.pl/me)<br/>
Released under the [MIT license](https://opensource.org/licenses/MIT)

@@ -171,0 +227,0 @@

/**@license
* sysend.js - send messages between browser windows/tabs version 1.14.3
* sysend.js - send messages between browser windows/tabs version 1.15.0
*
* Copyright (C) 2014-2022 Jakub T. Jankiewicz <https://jcubic.pl/me>
* Copyright (C) 2014-2023 Jakub T. Jankiewicz <https://jcubic.pl/me>
* Released under the MIT license

@@ -28,6 +28,12 @@ *

isPrimary(): boolean;
rpc<T extends Array<unknown>, U>(object: Record<string, (...args: T) => U>): Promise<Record<string, (id: string, ...args: T) => Promise<U>>>
}
//Promise<Record<string, (id: string, ...args: T) => Promise<U>>;
//type RPC<args extend Array
declare const sysend: Sysend;
export default sysend;
/**@license
* sysend.js - send messages between browser windows/tabs version 1.14.3
* sysend.js - send messages between browser windows/tabs version 1.15.0
*
* Copyright (C) 2014-2022 Jakub T. Jankiewicz <https://jcubic.pl/me>
* Copyright (C) 2014-2023 Jakub T. Jankiewicz <https://jcubic.pl/me>
* Released under the MIT license

@@ -46,2 +46,3 @@ *

var target_count = 1;
var rpc_count = 0;
var domains;

@@ -92,8 +93,8 @@

},
proxy: function() {
[].slice.call(arguments).forEach(function(url) {
proxy: function(...args) {
args.forEach(function(url) {
if (typeof url === 'string' && host(url) !== window.location.host) {
domains = domains || [];
domains.push(origin(url));
var iframe = document.createElement('iframe');
const iframe = document.createElement('iframe');
iframe.style.width = iframe.style.height = 0;

@@ -103,3 +104,3 @@ iframe.style.position = 'absolute';

iframe.style.border = 'none';
var proxy_url = url;
let proxy_url = url;
if (!url.match(/\.html$/)) {

@@ -116,3 +117,3 @@ proxy_url = url.replace(/\/$/, '') + '/proxy.html';

iframe.addEventListener('load', function handler() {
var win;
let win;
// fix for Safari

@@ -184,7 +185,7 @@ // https://stackoverflow.com/q/42632188/387194

list: function() {
var id = list_id++;
var marker = { target: target_id, id: id };
var timer = delay(sysend.timeout);
const id = list_id++;
const marker = { target: target_id, id: id };
const timer = delay(sysend.timeout);
return new Promise(function(resolve) {
var ids = [];
const ids = [];
sysend.on('__window_ack__', function(data) {

@@ -204,4 +205,4 @@ if (data.origin.target === target_id && data.origin.id === id) {

},
channel: function() {
domains = [].slice.apply(arguments).map(origin);
channel: function(...args) {
domains = args.map(origin);
return sysend;

@@ -219,2 +220,62 @@ },

},
rpc: function(object) {
const prefix = ++rpc_count;
const req = `__${prefix}_rpc_request__`;
const res = `__${prefix}_rpc_response__`;
let request_index = 0;
const timeout = 1000;
function request(id, method, args = []) {
const req_id = ++request_index;
return new Promise((resolve, reject) => {
sysend.track('message', function handler({data, origin}) {
if (data.type === res) {
const { result, error, id: res_id } = data;
if (origin === id && req_id === res_id) {
if (error) {
reject(error);
} else {
resolve(result);
}
clearTimeout(timer);
sysend.untrack('message', handler);
}
}
});
sysend.post(id, { method, id: req_id, type: req, args });
const timer = setTimeout(() => {
reject(new Error('Timeout error'));
}, timeout);
});
}
sysend.track('message', async function handler({ data, origin }) {
if (data.type == req) {
const { method, args, id } = data;
const type = res;
if (Object.hasOwn(object, method)) {
try {
unpromise(object[method](...args), function(result) {
sysend.post(origin, { result, id, type });
}, function(error) {
sysend.post(origin, { error: error.message, id, type });
});
} catch(e) {
sysend.post(origin, { error: e.message, id, type });
}
} else {
sysend.post(origin, { error: 'Method not found', id, type });
}
}
});
const error_msg = 'You need to specify the target window/tab';
return Object.fromEntries(Object.keys(object).map(name => {
return [name, (id, ...args) => {
if (!id) {
return Promise.reject(new Error(error_msg));
}
return request(id, name, args);
}];
}));
}
};

@@ -254,2 +315,20 @@ // -------------------------------------------------------------------------

// -------------------------------------------------------------------------
function is_promise(obj) {
return obj && typeof object == 'object' &&
typeof object.then === 'function';
}
// -------------------------------------------------------------------------
function unpromise(obj, callback, error = null) {
if (is_promise(obj)) {
const ret = obj.then(callback);
if (error === null) {
return ret;
} else {
return ret.catch(error);
}
} else {
return callback(obj);
}
}
// -------------------------------------------------------------------------
function delay(time) {

@@ -356,4 +435,3 @@ return function() {

// -------------------------------------------------------------------------
function trigger(arr) {
var args = [].slice.call(arguments, 1);
function trigger(arr, ...args) {
arr.forEach(function(fn) {

@@ -360,0 +438,0 @@ fn.apply(null, args);

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc