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

redbone

Package Overview
Dependencies
Maintainers
2
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

redbone - npm Package Compare versions

Comparing version 4.0.0-beta.1 to 4.0.0-beta.2

lib/createAction.js

17

classes/Redbone.js

@@ -1,5 +0,8 @@

const isNot = require('../lib/isNot');
const Middleware = require('./Middleware');
const Client = require('./Client');
const isNot = require('../lib/isNot');
const isActionOfType = require('../lib/isActionOfType');
const createAction = require('../lib/createAction');
/**

@@ -13,2 +16,3 @@ * Handler type for a middleware or watcher

* @prop {String} type
* @prop {Mixed} [payload]
*/

@@ -33,4 +37,4 @@

*/
watch(type, watcher) {
this.watchers.use(type, watcher);
watch(/* type, watcher */) {
this.watchers.use(...arguments);
// It is need for chaining

@@ -58,3 +62,3 @@ return this;

*/
use() {
use(/* type, middleware */) {
return this.before.use(...arguments);

@@ -102,3 +106,8 @@ }

Redbone.prototype.is = isActionOfType;
Redbone.prototype.createAction = createAction;
Redbone.is = isActionOfType;
Redbone.createAction = createAction;
Redbone.Client = Client;
module.exports = Redbone;
{
"name": "redbone",
"version": "4.0.0-beta.1",
"version": "4.0.0-beta.2",
"description": "Polymorphic library for two-way dispatching of actions",

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

@@ -130,13 +130,14 @@ # Redbone

```js
// We will look it closer later
const { Server } = require('net');
const Redbone = require('redbone');
// We will look it later
const Client = require('./Client');
// Transport should be an EventEmitter child
class TcpTransport {
#server = null;
const Types = {
CONNECTION: 'connection',
DISCONNECT: 'disconnect'
}
// the constructor will be his own for each transport
constructor(server) {
super();
// this field will be added when transport will be added to a Redbone's instance
class RedboneTransportTCP {
constructor(options) {
this.redbone = new Redbone();

@@ -146,13 +147,17 @@

this.onError = this.onError.bind(this);
this.server = server;
this.onRedboneError = this.onRedboneError.bind(this);
this.server = new Server(options);
// Add redbone's catcher
this.redbone.catch(this.onRedboneError);
}
set server(server) {
if (this.#server) this._unsub(this.#server);
if (this._server) this._unsub(this._server);
this._sub(server);
this.#server = server;
this._server = server;
}
get server() {
return this.#server;
return this._server || null;
}

@@ -166,43 +171,115 @@

_unsub(server) {
server.removeListener('connection', this.onConnection);
server.removeListener('error', this.onError);
server.off('connection', this.onConnection);
server.off('error', this.onError);
}
listen(port) {
if (!this._server) throw new ReferenceError('no server for listen')
return new Promise((resolve, reject) => {
this._server.listen(port, (err) => {
if (err) return reject(err);
return resolve();
});
});
}
close() {
if (!this._server) return;
return new Promise((resolve, reject) => {
this._server.close((err) => {
if (err) return reject(err);
return resolve();
});
});
}
_processAction(client, data) {
try {
// process action every message
const action = JSON.parse(data);
// When transport has a client and an action
// it should call redbone's dispatch
this.redbone.dispatch(client, action);
} catch (err) {
// If JSON is invalid
this.redbone.catcher(err, client, action);
this.onError(err);
}
}
onConnection(socket) {
// client is an instance of Client class.
// Every platform shoud implement Client class, inherited from Redbone's Client,
// we will look it closer later
const client = new Client({ transport: this, native: socket });
this.redbone.dispatch(client, { type: 'connection' });
_changeSocketSub(socket, onData, onDisconnect, onError, on = true) {
const method = on ? 'on' : 'off';
socket[method]('data', onData);
socket[method]('error', onError);
socket[method]('close', onDisconnect);
}
_createClient(socket) {
socket.setEncoding('utf8');
socket.on('data', (data) => this._processAction(data, client));
socket.on('error', (err) => console.error(err));
socket.on('disconnect', () => {
this.redbone.dispatch(client, { type: 'disconnect' });
// create client
return new Client({
transport: this,
native: socket
});
}
_createOnData(client) {
return (data) => {
this._processAction(client, data);
};
}
_createOnDisconnect(client, onData) {
const { DISCONNECT } = this.constructor.Types;
const onDisconnect = () => {
// dispatch disconnect action
this.redbone.dispatch(client, { type: DISCONNECT });
this._changeSocketSub(
client.native, onData, onDisconnect, this.onError, false
);
}
return onDisconnect;
}
_subClient(client) {
const onData = this._createOnData(client);
const onDisconnect = this._createOnDisconnect(client, onData);
this._changeSocketSub(
client.native, onData, onDisconnect, this.onError
);
}
onConnection(socket) {
const { CONNECTION } = this.constructor.Types;
const client = this._createClient(socket);
this._subClient(client);
// dispatch connection action
return this.redbone.dispatch(client, { type: CONNECTION });
}
onError(err) {
console.error(err);
}
onRedboneError(err, client) {
if (!err.statusCode) {
throw err;
}
client.dispatch({
type: 'error',
code: err.statusCode || 500
});
}
}
RedboneTransportTCP.Types = Types;
module.exports = RedboneTransportTCP;
```
Redbone has several transports out of the box.
Redbone has several transports in different modules.
You can examine the examples in detail in a [separate repository](https://github.com/ya-kostik/redbone-examples).
## Clients
Redbone needs clients to get a way to send reaction from it to client.
Clients objects lives until connection is broken.
Clients objects lives until connection is closed.

@@ -213,12 +290,33 @@ Every transport should implement own Client class, inherited from Redbone's Client class.

```js
const { Client: ClientMain } = require('redbone');
const Redbone = require('../../');
const { write } = require('./lib/socket');
class Client extends ClientMain {
// send is the only method the Сlient should implement
const PERMITTED_ERRORS = new Set([
'EPIPE' // Send action after socket closed
]);
class Client extends Redbone.Client {
send(action) {
this.native.write(JSON.stringify(action));
return this.write(action).
catch((err) => {
if (PERMITTED_ERRORS.has(err.code)) return;
return this.transport.onError(err);
});
}
write(action) {
return new Promise((resolve, reject) => {
const message = JSON.stringify(action);
this.native.once('error', reject);
return this.native.write(action, (err) => {
if (err) return reject(err);
return resolve();
});
});
}
}
module.exports = Client;
```
`send` calls every time, when `client.dispatch(action)` occurs.
/* global jest describe test expect */
const ACTION_ERROR_TEXT = 'is not a valid action';
const Redbone = require('../classes/Redbone');

@@ -9,25 +7,8 @@ const MainClient = require('../classes/Client');

function getTestWatcher(redbone, client, type) {
return (client, action) => {
expect(action.type).toBe(type);
expect(client).toBe(client);
expect(client.redbone).toBe(redbone);
};
}
const createMiddlewares = require('./lib/createMiddlewares');
const getTestWatcher = require('./lib/getTestWatcher');
const inspectMiddlewares = require('./lib/inspectMiddlewares');
function createMiddlewares(count, cb) {
const middlewares = [];
for (let i = 0; i < count; i++) {
middlewares.push(jest.fn(cb));
}
const ACTION_ERROR_TEXT = 'is not a valid action';
return middlewares;
}
function inspectMiddlewares(middlewares, count = 1) {
for (const middleware of middlewares) {
expect(middleware.mock.calls.length).toBe(count);
}
}
function createMiddlewaresTest(firstUse, secondUse) {

@@ -258,2 +239,39 @@ return async () => {

}));
test('creates boilerplate action', () => {
const type = 'test';
const actionWithoutPayload = Redbone.createAction(type);
const actionWithPayload = Redbone.createAction(type, { message: type });
const actionWithNullPayload = Redbone.createAction(type, null);
const redbone = new Redbone();
const actionCreatedByInstance = redbone.createAction(type);
expect(actionWithoutPayload).toEqual({ type });
expect(actionWithPayload).toEqual({
type,
payload: { message: type }
});
expect(actionWithNullPayload).toEqual({ type, payload: null });
expect(actionCreatedByInstance).toEqual(actionWithoutPayload);
});
test('compares action and type', () => {
const firstType = 'first test';
const secondType = 'second test';
const thirdType = 'crazy type';
const regexpType = /test/;
const firstAction = Redbone.createAction(firstType);
const secondAction = Redbone.createAction(secondType);
const thirdAction = Redbone.createAction(thirdType);
expect(Redbone.is(firstAction, firstType)).toBe(true);
expect(Redbone.is(firstAction, secondType)).toBe(false);
expect(Redbone.is(firstAction, regexpType)).toBe(true);
expect(Redbone.is(secondAction, regexpType)).toBe(true);
expect(Redbone.is(thirdAction, regexpType)).toBe(false);
});
});
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