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

xible

Package Overview
Dependencies
Maintainers
1
Versions
64
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

xible - npm Package Compare versions

Comparing version 0.6.0 to 0.7.0

app/CliQueue/index.js

3

.eslintrc.json

@@ -26,3 +26,4 @@ {

"no-restricted-syntax": ["off"],
"no-param-reassign": "off"
"no-param-reassign": "off",
"no-use-before-define": ["error", {"functions": false, "classes": false}]
},

@@ -29,0 +30,0 @@ "plugins": [

@@ -24,2 +24,3 @@ 'use strict';

fsExtra.copySync(DEFAULT_PATH, path);
fs.chmodSync(path, 0o600);
return true;

@@ -37,3 +38,5 @@ } catch (err) {

try {
fs.writeFileSync(path, configContents);
fs.writeFileSync(path, configContents, {
mode: 0o600
});
} catch (err) {

@@ -40,0 +43,0 @@ configDebug(`failed to write config to "${path}": ${err}`);

@@ -32,3 +32,5 @@ 'use strict';

EXPRESS_APP.get('/api/config/validatePermissions', (req, res) => {
Config.validatePermissions().then((result) => {
Config
.validatePermissions()
.then((result) => {
res.json(result);

@@ -35,0 +37,0 @@ });

@@ -21,2 +21,11 @@ 'use strict';

// check inspect arguments so we can fork properly
let inspectPortNumberIncrement = 0;
let inspectLevel = 0;
if (process.execArgv.some(arg => arg.includes('--inspect='))) {
inspectLevel = 1;
} else if (process.execArgv.some(arg => arg.includes('--inspect-brk='))) {
inspectLevel = 2;
}
/**

@@ -60,7 +69,8 @@ * Flow class

* Note that a path cannot be initiated twice because it is used for saveStatuses()
* @static
* @param {String} path The path to the directory containing the flows.
* @return {Object.<String, Flow>} list of flows by their _id
* @param {String} path The path to the directory containing the flows.
* @param {Boolean} cleanVault Indicates whether the json data from each flow
* needs vault sanitizing.
* @return {Object.<String, Flow>} List of flows by their _id.
*/
static initFromPath(flowPath) {
static initFromPath(flowPath, cleanVault) {
flowDebug(`init flows from "${flowPath}"`);

@@ -100,3 +110,3 @@ if (this.flowPath) {

const flow = new Flow(XIBLE);
flow.initJson(json);
flow.initJson(json, cleanVault);
flows[flow._id] = flow;

@@ -117,3 +127,3 @@ }

* @param {String} flowPath The path to the directory containing the flows.
* @return {Object.<String, Flow>} list of flows by their _id
* @return {Object.<String, Flow>} List of flows by their _id.
* @since 0.5.0

@@ -134,5 +144,5 @@ */

flows[flowId].forceStart()
.catch((err) => {
flowDebug(`failed to start "${flowId}": ${err}`);
});
.catch((err) => {
flowDebug(`failed to start "${flowId}": ${err}`);
});
} else if (flows[flowId].initLevel === Flow.INITLEVEL_FLOW) {

@@ -285,2 +295,3 @@ flows[flowId].init();

// remove those from the json (the json is used for saving)
// save the vault data thereafter
if (cleanVault) {

@@ -301,2 +312,4 @@ const nodeVaultKeys = nodeConstr.vault;

}
} else if (xibleNode.vault) {
Object.assign(xibleNode.data, xibleNode.vault.get());
}

@@ -467,3 +480,4 @@

/*
//uncommenting this needs to take care of commented _trackerTriggerTime elsewhere
// uncommenting this needs to take care of commented _trackerTriggerTime elsewhere
// and this.node.emit('triggerout', this); in /app/Node/index.js
node.prependListener('triggerout', (output) => {

@@ -484,3 +498,4 @@

} else {
msg = `triggered '${output.name}' @ ${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}:${d.getMilliseconds()}`;
msg = `triggered '${output.name}' @
${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}:${d.getMilliseconds()}`;
}

@@ -626,9 +641,9 @@

// trigger the action nodes
// trigger the action nodes
for (let i = 0; i < actionNodes.length; i += 1) {
actionNodes[i].getInputs()
.filter(input => input.type === 'trigger')
.forEach((input) => {
input.emit('trigger', null, flowState);
});
.filter(input => input.type === 'trigger')
.forEach((input) => {
input.emit('trigger', null, flowState);
});
}

@@ -670,3 +685,3 @@ });

return this.init()
.then(startFlow);
.then(startFlow);

@@ -688,3 +703,3 @@ case Flow.STATE_STOPPING:

return this.stop()
.then(() => this.forceStart(directNodes));
.then(() => this.forceStart(directNodes));

@@ -697,2 +712,4 @@ case Flow.STATE_STARTING:

}
return Promise.reject(new Error('Flow in unknown state'));
}

@@ -755,3 +772,11 @@

let flow;
this.worker = fork(`${__dirname}/../../child.js`);
const execArgv = [];
if (inspectLevel === 1) {
execArgv.push(`--inspect=0.0.0.0:${9229 + (inspectPortNumberIncrement += 1)}`);
} else if (inspectLevel === 2) {
execArgv.push(`--inspect-brk=0.0.0.0:${9229 + (inspectPortNumberIncrement += 1)}`);
}
this.worker = fork(`${__dirname}/../../child.js`, {
execArgv
});
this.worker.on('message', (message) => {

@@ -761,3 +786,2 @@ switch (message.method) {

case 'initializing':
if (this.worker && this.worker.connected) {

@@ -783,3 +807,2 @@ const initializingDiff = process.hrtime(this.timing.initStart);

case 'initialized':
this.timing.initEnd = process.hrtime();

@@ -802,3 +825,2 @@ const initializedDiff = process.hrtime(this.timing.initStart);

case 'started':
this.state = Flow.STATE_STARTED;

@@ -857,3 +879,2 @@ this.emit('started');

case 'stop':
this.forceStop();

@@ -863,3 +884,2 @@ break;

case 'broadcastWebSocket':
XIBLE.broadcastWebSocket(message.message);

@@ -869,3 +889,2 @@ break;

case 'usage':
this.usage = message.usage;

@@ -892,3 +911,3 @@ break;

this.init()
.catch((err) => { console.error(err); });
.catch(err => console.error(err));
}

@@ -914,2 +933,4 @@ });

* @param {Node[]} directNodes nodes to direct
* @fires Node#trigger
* @fires Node#init
* @return {Promise}

@@ -954,3 +975,2 @@ */

case 'started':
this.timing.startEnd = process.hrtime();

@@ -979,3 +999,3 @@ const startedDiff = process.hrtime(this.timing.startStart);

process.nextTick(() => {
// init all nodes
// init all nodes
for (let i = 0; i < this.nodes.length; i += 1) {

@@ -985,3 +1005,3 @@ this.nodes[i].emit('init', flowState);

// trigger all event objects that are listening
// trigger all event objects that are listening
for (let i = 0; i < this.nodes.length; i += 1) {

@@ -1035,2 +1055,4 @@ if (this.nodes[i].type === 'event') {

}
return Promise.reject(new Error('Flow in unknown state'));
}

@@ -1044,72 +1066,71 @@

stop() {
if (!XIBLE.child) {
if (this.state !== Flow.STATE_STARTED && this.state !== Flow.STATE_INITIALIZED) {
return Promise.reject('cannot stop; flow is not started or initialized');
}
this.state = Flow.STATE_STOPPING;
if (XIBLE.child) {
flowDebug('stopping flow from worker');
return new Promise((resolve) => {
this.saveStatus(false);
// close any node that wants to
this.nodes.forEach(node => node.emit('close'));
if (this.worker) {
XIBLE.broadcastWebSocket({
method: 'xible.flow.stopping',
flowId: this._id
});
flowDebug('stopped flow from worker');
process.exit(0);
}
flowDebug('stopping flow from master');
let killTimeout;
if (this.state !== Flow.STATE_STARTED && this.state !== Flow.STATE_INITIALIZED) {
return Promise.reject('cannot stop; flow is not started or initialized');
}
this.state = Flow.STATE_STOPPING;
this.worker.once('exit', () => {
if (killTimeout) {
clearTimeout(killTimeout);
killTimeout = null;
}
return new Promise((resolve) => {
this.saveStatus(false);
resolve(this);
});
if (this.worker) {
XIBLE.broadcastWebSocket({
method: 'xible.flow.stopping',
flowId: this._id
});
this.worker.on('disconnect', () => {
if (this.worker) {
flowDebug('killing worker the normal way');
this.worker.kill();
} else if (killTimeout) {
clearTimeout(killTimeout);
killTimeout = null;
}
});
flowDebug('stopping flow from master');
let killTimeout;
this.worker.send({
method: 'stop'
});
this.worker.once('exit', () => {
if (killTimeout) {
clearTimeout(killTimeout);
killTimeout = null;
}
this.worker.disconnect();
resolve(this);
});
// forcibly kill after 5 seconds
killTimeout = setTimeout(() => {
flowDebug('killing worker from master using SIGKILL');
this.worker.kill('SIGKILL');
this.worker.on('disconnect', () => {
if (this.worker) {
flowDebug('killing worker the normal way');
this.worker.kill();
} else if (killTimeout) {
clearTimeout(killTimeout);
killTimeout = null;
}
});
// cleanup all open statuses
XIBLE.broadcastWebSocket({
method: 'xible.flow.removeAllStatuses',
flowId: this._id
});
this.worker.send({
method: 'stop'
});
killTimeout = null;
}, 5000);
} else {
resolve(this);
}
});
}
this.worker.disconnect();
flowDebug('stopping flow from worker');
// forcibly kill after 5 seconds
killTimeout = setTimeout(() => {
flowDebug('killing worker from master using SIGKILL');
this.worker.kill('SIGKILL');
// close any node that wants to
this.nodes.forEach(node => node.emit('close'));
// cleanup all open statuses
XIBLE.broadcastWebSocket({
method: 'xible.flow.removeAllStatuses',
flowId: this._id
});
flowDebug('stopped flow from worker');
process.exit(0);
killTimeout = null;
}, 5000);
} else {
resolve(this);
}
});
}

@@ -1132,3 +1153,3 @@

*/
this.set = function (node, obj) {
this.set = function FlowStateSet(node, obj) {
if (!(node instanceof XIBLE.Node)) {

@@ -1149,3 +1170,3 @@ throw new Error('node must be instanceof Node');

*/
this.get = function (node) {
this.get = function FlowStateGet(node) {
if (!(node instanceof XIBLE.Node)) {

@@ -1162,3 +1183,3 @@ throw new Error('node must be instanceof Node');

*/
this.split = function () {
this.split = function FlowStateSplit() {
return new FlowState(Object.assign({}, states));

@@ -1165,0 +1186,0 @@ };

@@ -61,10 +61,11 @@ 'use strict';

EXPRESS_APP.patch('/api/flows/:flowId/stop', (req, res) => {
req.locals.flow.forceStop()
.then(() => {
res.end();
})
.catch((err) => {
console.error(err);
res.status(500).end();
});
req.locals.flow
.forceStop()
.then(() => {
res.end();
})
.catch((err) => {
console.error(err);
res.status(500).end();
});
});

@@ -75,10 +76,11 @@

EXPRESS_APP.patch('/api/flows/:flowId/start', (req, res) => {
req.locals.flow.forceStart()
.then(() => {
res.end();
})
.catch((err) => {
console.error(err);
res.status(500).end();
});
req.locals.flow
.forceStart()
.then(() => {
res.end();
})
.catch((err) => {
console.error(err);
res.status(500).end();
});
});

@@ -131,3 +133,5 @@

const flow = req.locals.flow;
flow.forceStop().then(() => {
flow
.forceStop()
.then(() => {
// init the newly provided json over the existing flow

@@ -137,3 +141,5 @@ flow.initJson(req.body, true);

// save it to file
flow.save().then(() => {
flow
.save()
.then(() => {
// output the flow id

@@ -151,8 +157,9 @@ res.json({

const flow = req.locals.flow;
flow.forceStop().then(() => {
flow.delete().then(() => {
res.end();
});
flow
.forceStop()
.then(() => flow.delete())
.then(() => {
res.end();
});
});
};

@@ -17,2 +17,17 @@ /* eslint-disable no-use-before-define */

/**
* Trigger event which is applied to event nodes when the flow starts,
* after all nodes have received the init event.
* It is also applied to a node when it gets triggered through
* an input trigger after a call from nodeOutput.trigger().
* @event Node#trigger
* @param {FlowState} state A blank state, equal to the state provided on the init event.
*/
/**
* Init event which is applied to all nodes, when the flow starts.
* @event Node#init
* @param {FlowState} state The initial (blank) state of the flow.
*/
/**
* Node class

@@ -58,5 +73,2 @@ * @extends EventEmitter

this.vault = new NodeVault(this);
// add vault data to the data field
Object.assign(this.data, this.vault.get());
}

@@ -690,2 +702,11 @@

/**
* This event is emitted after a node calls trigger() on one of its outputs.
* The event is fired for each of the input triggers connected to the output
* where trigger() was called upon.
* @event NodeInput#trigger
* @param {Connector} conn The connector responsible for the trigger.
* @param {FlowState} state The state provided from the calling node.
*/
/**
* Class for inputs of a Node.

@@ -699,2 +720,3 @@ * @extends NodeIo

* @param {FlowState} state The flowstate at the time of calling.
* @fires NodeOutput#trigger
* @returns {Promise.<Array>} An array of all values

@@ -713,3 +735,5 @@ * as returned by the outputs on the other ends of connected connectors or globals.

if (!conns.length && this.global) {
conns = this.node.flow.getGlobalOutputsByType(this.type).map(output => ({
conns = this.node.flow
.getGlobalOutputsByType(this.type)
.map(output => ({
origin: output

@@ -729,7 +753,10 @@ }));

const conn = conns[i];
let calledBack = false;
// trigger the input
conn.origin.emit('trigger', conn, state, (value) => { // eslint-disable-line
// let everyone know that the trigger is done
conn.origin.emit('triggerdone');
// verify that this callback wasn't already made.
if (calledBack) {
throw new Error('Already called back');
}
calledBack = true;

@@ -759,2 +786,13 @@ // we only send arrays between nodes

/**
* This event is emitted after a node calls getValues() on one of its inputs.
* The event is fired for each of the outputs connected to the input
* where getValues() was called upon.
* @event NodeOutput#trigger
* @param {Connector} conn The connector responsible for the trigger.
* @param {FlowState} state The state provided from the calling node.
* @param {Function} callback Use the callback function to return your value.
* You can only callback once, otherwise an Error is thrown.
*/
/**
* Class for outputs of a Node.

@@ -768,2 +806,3 @@ * @extends NodeIo

* @param {FlowState} state The flowstate at the time of calling.
* @fires NodeInput#trigger
* @throws {Error} Throws whenever this.type !== 'trigger'.

@@ -777,3 +816,3 @@ */

this.node.emit('triggerout', this);
// this.node.emit('triggerout', this);

@@ -809,3 +848,5 @@ const conns = this.connectors;

vaultDebug('creating new');
fs.writeFileSync(vaultPath, '{}');
fs.writeFileSync(vaultPath, '{}', {
mode: 0o600
});
}

@@ -816,3 +857,3 @@

} catch (err) {
vaultDebug(`could not open "${vaultPath}"`);
vaultDebug(`could not open "${vaultPath}"\n`, err);
}

@@ -823,5 +864,7 @@ }

try {
fs.writeFileSync(vaultPath, JSON.stringify(vault));
} catch (e) {
vaultDebug(`could not save "${vaultPath}"`);
fs.writeFileSync(vaultPath, JSON.stringify(vault), {
mode: 0o600
});
} catch (err) {
vaultDebug(`could not save "${vaultPath}"\n`, err);
}

@@ -828,0 +871,0 @@ }

@@ -140,17 +140,17 @@ 'use strict';

const onSuccess = () => XIBLE.Node
.initFromPath(nodeDestDir)
.then(cleanUp)
.then(() => {
// see if we can/need to reinit flows that are not runnable
const flows = XIBLE.getFlows();
for (const flowId in flows) {
if (!flows[flowId].runnable) {
flows[flowId].initJson(flows[flowId].json);
}
.initFromPath(nodeDestDir)
.then(cleanUp)
.then(() => {
// see if we can/need to reinit flows that are not runnable
const flows = XIBLE.getFlows();
for (const flowId in flows) {
if (!flows[flowId].runnable) {
flows[flowId].initJson(flows[flowId].json);
}
})
.then(resolve)
.catch((onSuccessErr) => {
reject(onSuccessErr);
});
}
})
.then(resolve)
.catch((onSuccessErr) => {
reject(onSuccessErr);
});

@@ -157,0 +157,0 @@ // remove existing node directory

@@ -9,16 +9,3 @@ 'use strict';

XIBLE_REGISTRY.NodePack
.getAll()
.then((nodePacks) => {
res.json(nodePacks);
})
.catch((err) => {
console.error(err);
res.status(500).end();
});
return;
}
XIBLE_REGISTRY.NodePack
.search(searchString)
.getAll()
.then((nodePacks) => {

@@ -31,2 +18,15 @@ res.json(nodePacks);

});
return;
}
XIBLE_REGISTRY.NodePack
.search(searchString)
.then((nodePacks) => {
res.json(nodePacks);
})
.catch((err) => {
console.error(err);
res.status(500).end();
});
});

@@ -39,8 +39,8 @@

XIBLE_REGISTRY.NodePack
.getByName(nodePackName)
.then((nodePack) => {
req.locals.nodePack = nodePack;
next();
})
.catch(() => res.status(404).end());
.getByName(nodePackName)
.then((nodePack) => {
req.locals.nodePack = nodePack;
next();
})
.catch(() => res.status(404).end());
});

@@ -54,11 +54,12 @@

EXPRESS_APP.patch('/api/registry/nodepacks/:nodePackName/install', (req, res) => {
req.locals.nodePack.install()
.then(() => {
res.end();
})
.catch((err) => {
console.error(err);
res.status(500).end();
});
req.locals.nodePack
.install()
.then(() => {
res.end();
})
.catch((err) => {
console.error(err);
res.status(500).end();
});
});
};
# Change Log
All notable changes to the XIBLE project will be documented in this file.
All notable changes to the [XIBLE project](https://xible.io) will be documented in this file.

@@ -10,2 +10,26 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)

## [0.7.0][]
### Added
- Flows can be [started](https://xible.io/docs/commandlinetools/xible#flow.start)/[stopped](https://xible.io/docs/commandlinetools/xible#flow.stop) and [deleted](https://xible.io/docs/commandlinetools/xible#flow.delete) using the cli. See the [xible cli documentation](https://xible.io/docs/commandlinetools/xible) for more information. ([#18](https://github.com/SpectrumBroad/xible/issues/18))
- The `xible` command line interface supports the 'config' context just like `xiblepm`. ([#22](https://github.com/SpectrumBroad/xible/issues/22))
- `console.log`, `console.error` and `console.clear` nodes are now included in XIBLE. `log.console` is deprecated and will be removed in a future release. ([#27](https://github.com/SpectrumBroad/xible/issues/27))
### Changed
- `xiblepm flow remove` is deprecated in favor of `xible flow delete`.
- The [command line interface tools](https://xible.io/docs/commandlinetools) `xible` & `xiblepm` are now stored in `./bin`.
- The `document.assign` node only callbacks once when multiple documents are hooked up to the 'document' input.
- Callbacks from nodes in response to `output.on('trigger')` resulting from a `input.getValues()` call can now only be called back once. An error is thrown if called multiple times.
- [Direct mode](https://xible.io/docs/editor#direct) can now be enabled/disabled through the settings. It is disabled by default. ([#26](https://github.com/SpectrumBroad/xible/issues/26))
### Fixed
- Resizing the editor to only narrowly fit the cpu/mem/delay charts no longer toggles the scrollbar in- and out of view. ([#11](https://github.com/SpectrumBroad/xible/issues/11))
- Publishing flows to the registry no longer includes the vault data ([#25](https://github.com/SpectrumBroad/xible/issues/25))
## [0.6.0][] - 2017-06-09

@@ -61,3 +85,4 @@ ### Added

[Unreleased]: https://github.com/SpectrumBroad/xible/compare/v0.6.0...HEAD
[Unreleased]: https://github.com/SpectrumBroad/xible/compare/v0.7.0...HEAD
[0.7.0]: https://github.com/SpectrumBroad/xible/compare/v0.6.0...v0.7.0
[0.6.0]: https://github.com/SpectrumBroad/xible/compare/v0.5.0...v0.6.0

@@ -64,0 +89,0 @@ [0.5.0]: https://github.com/SpectrumBroad/xible/compare/v0.4.1...v0.5.0

@@ -55,3 +55,2 @@ 'use strict';

case 'init':
xible = new Xible({

@@ -83,27 +82,27 @@ child: true

xible.init()
.then(() => {
flow = new xible.Flow();
flow.initJson(message.flow);
.then(() => {
flow = new xible.Flow();
flow.initJson(message.flow);
// inform the master that we initialized
if (process.connected) {
process.send({
method: 'initialized'
});
}
})
.catch((err) => {
console.error(err);
// inform the master that we initialized
if (process.connected) {
process.send({
method: 'initialized'
});
}
})
.catch((err) => {
console.error(err);
if (process.connected) {
process.send({
method: 'stop',
error: err
});
}
if (process.connected) {
process.send({
method: 'stop',
error: err
});
}
if (flow) {
flow.stop();
}
});
if (flow) {
flow.stop();
}
});

@@ -113,3 +112,2 @@ break;

case 'start':
let startPromise;

@@ -123,24 +121,24 @@ if (message.directNodes) {

startPromise
.then(() => {
// inform the master that we actually started
if (process.connected) {
process.send({
method: 'started'
});
}
})
.catch((err) => {
console.error(err);
.then(() => {
// inform the master that we actually started
if (process.connected) {
process.send({
method: 'started'
});
}
})
.catch((err) => {
console.error(err);
if (process.connected) {
process.send({
method: 'stop',
error: err
});
}
if (process.connected) {
process.send({
method: 'stop',
error: err
});
}
if (flow) {
flow.stop();
}
});
if (flow) {
flow.stop();
}
});

@@ -150,3 +148,2 @@ break;

case 'stop':
if (flow) {

@@ -159,3 +156,2 @@ flow.stop();

case 'directNodes':
if (flow) {

@@ -162,0 +158,0 @@ flow.direct(message.directNodes);

@@ -23,2 +23,16 @@ {

"editor": {
"nodes": {
"statuses": {
"max": null
}
},
"flows": {
"allowdirect": false
},
"viewstate": {
"zoomstateonopen": "untouched"
}
},
"registry": {

@@ -25,0 +39,0 @@ "url": "https://registry.xible.io",

class XibleEditorNode extends xibleWrapper.Node {
constructor(obj, ignoreData) {
let el = document.createElement('div');

@@ -10,11 +9,11 @@ el.classList.add('node');

//add ios
// add ios
let ios = el.appendChild(document.createElement('div'));
ios.classList.add('io');
//add input list
// add input list
let inputList = ios.appendChild(document.createElement('ul'));
inputList.classList.add('input');
//add output list
// add output list
let outputList = ios.appendChild(document.createElement('ul'));

@@ -31,4 +30,4 @@ outputList.classList.add('output');

//add additional content
if (this.hostsEditorContent) { //load editor static hosted content for this node
// add additional content
if (this.hostsEditorContent) { // load editor static hosted content for this node
this.getAndProcessEditorContent();

@@ -42,3 +41,3 @@ } else if (!this.nodeExists && obj.editorContent) {

//selection handlers
// selection handlers
this.element.addEventListener('mousedown', (event) => {

@@ -55,5 +54,4 @@ if (this.editor) {

//direct handler
// direct handler
headerEl.addEventListener('dblclick', (event) => {
if (!this.editor || this.type !== 'action' || !this.editor.browserSupport) {

@@ -63,18 +61,24 @@ return;

this.flow.undirect();
// check if direct mode is alowed before continuing
xibleWrapper.Config
.getValue('editor.flows.allowdirect')
.then((allowDirect) => {
if(!allowDirect) {
return;
}
//fetch all related connectors and nodes for the double clicked node
let related = XibleEditorNode.getAllInputObjectNodes(this);
this.flow.undirect();
//don't forget about globals
related.nodes = related.nodes.concat(this.flow.getGlobalNodes());
// fetch all related connectors and nodes for the double clicked node
let related = XibleEditorNode.getAllInputObjectNodes(this);
related.nodes.forEach((node) => {
// don't forget about globals
related.nodes = related.nodes.concat(this.flow.getGlobalNodes());
node._directSetDataListener = () => this.editor.loadedFlow.direct(related);
node.on('setdata', node._directSetDataListener);
related.nodes.forEach((node) => {
node._directSetDataListener = () => this.editor.loadedFlow.direct(related);
node.on('setdata', node._directSetDataListener);
});
});
this.editor.loadedFlow.nodes
this.editor.loadedFlow.nodes
.filter((node) => related.nodes.indexOf(node) === -1)

@@ -85,3 +89,3 @@ .forEach((node) => {

this.editor.loadedFlow.connectors
this.editor.loadedFlow.connectors
.filter((connector) => related.connectors.indexOf(connector) === -1)

@@ -92,8 +96,7 @@ .forEach((connector) => {

this.editor.loadedFlow.direct(related);
this.editor.loadedFlow.direct(related);
});
});
if (!obj.nodeExists) {
this.element.classList.add('fail');

@@ -105,5 +108,3 @@ this.addStatus({

});
}
}

@@ -338,3 +339,2 @@

updateProgressBarById(statusId, status) {
if (!this.statusEl || !statusId || !status || typeof status.percentage !== 'number') {

@@ -344,6 +344,5 @@ return;

let li = this.statusEl.querySelector('li.bar[data-statusid="' + statusId + '"]');
const li = this.statusEl.querySelector('li.bar[data-statusid="' + statusId + '"]');
if (li) {
let bar = li.querySelector('.holder>div');
const bar = li.querySelector('.holder>div');
bar.style.transition = 'none';

@@ -353,8 +352,7 @@ bar.style.width = `${status.percentage}%`;

if (status.updateOverTime) {
//check when this progressbar should start (future)
//or when it started (past)
// check when this progressbar should start (future)
// or when it started (past)
let startDiff = Date.now() - status.startDate + this.editor.serverClientDateDifference;
//max it out
// max it out
if (startDiff > status.updateOverTime) {

@@ -364,4 +362,4 @@ startDiff = status.updateOverTime;

//if this progressbar should have started in the past
//calculate where the width should be right now
// if this progressbar should have started in the past
// calculate where the width should be right now
if (startDiff > 0) {

@@ -374,6 +372,4 @@ bar.style.width = `${startDiff/status.updateOverTime*100}%`;

bar.style.width = '100%';
}
}
}

@@ -387,54 +383,53 @@

xibleWrapper.Config
.getValue('editor.nodes.statuses.max')
.then((configMaxStatuses) => {
let statusCount = 0;
let ul = this.statusEl;
if (!ul) {
ul = this.statusEl = this.element.appendChild(document.createElement('ul'));
ul.classList.add('statuses');
} else {
statusCount = ul.querySelectorAll('li:not(.bar)').length;
}
.getValue('editor.nodes.statuses.max')
.then((configMaxStatuses) => {
let statusCount = 0;
let ul = this.statusEl;
if (!ul) {
ul = this.statusEl = this.element.appendChild(document.createElement('ul'));
ul.classList.add('statuses');
} else {
statusCount = ul.querySelectorAll('li:not(.bar)').length;
}
// remove all statuses above the max config setting
if (typeof configMaxStatuses === 'number' && statusCount >= configMaxStatuses && ul.firstChild) {
while (statusCount >= configMaxStatuses && ul.firstChild) {
const removeChild = ul.firstChild;
this.removeStatusById(removeChild.getAttribute('data-statusid'));
statusCount -= 1;
}
// remove all statuses above the max config setting
if (typeof configMaxStatuses === 'number' && statusCount >= configMaxStatuses && ul.firstChild) {
while (statusCount >= configMaxStatuses && ul.firstChild) {
const removeChild = ul.firstChild;
this.removeStatusById(removeChild.getAttribute('data-statusid'));
statusCount -= 1;
}
}
if (configMaxStatuses === 0) {
return;
}
if (configMaxStatuses === 0) {
return;
}
let li = ul.appendChild(document.createElement('li'));
li.setAttribute('data-statusid', status._id);
const li = ul.appendChild(document.createElement('li'));
li.setAttribute('data-statusid', status._id);
if (status.color) {
li.classList.add(status.color);
}
if (status.color) {
li.classList.add(status.color);
}
if (typeof status.message === 'string') {
let messageLineSplit = status.message.split('\n');
for (let i = 0; i < messageLineSplit.length; i += 1) {
if (i) {
li.appendChild(document.createElement('br'));
}
li.appendChild(document.createTextNode(messageLineSplit[i]));
if (typeof status.message === 'string') {
let messageLineSplit = status.message.split('\n');
for (let i = 0; i < messageLineSplit.length; i += 1) {
if (i) {
li.appendChild(document.createElement('br'));
}
messageLineSplit = null;
li.appendChild(document.createTextNode(messageLineSplit[i]));
}
messageLineSplit = null;
}
if (status.timeout) {
this.statusTimeouts[status._id] = window.setTimeout(() => {
this.removeStatusById(status._id);
}, status.timeout);
}
});
if (status.timeout) {
this.statusTimeouts[status._id] = window.setTimeout(() => {
this.removeStatusById(status._id);
}, status.timeout);
}
});
}
updateStatusById(statusId, status) {
if (!this.statusEl) {

@@ -444,7 +439,5 @@ return;

let li = this.statusEl.querySelector(`li[data-statusid="${statusId}"]`);
const li = this.statusEl.querySelector(`li[data-statusid="${statusId}"]`);
if (li) {
if (status.message) {
if (li.lastChild) {

@@ -455,18 +448,12 @@ li.removeChild(li.lastChild);

li.appendChild(document.createTextNode(status.message));
}
}
}
removeStatusById(statusId, timeout) {
//clear timeout
if (this.statusTimeouts[statusId]) {
window.clearTimeout(this.statusTimeouts[statusId]);
this.statusTimeouts[statusId] = null;
delete this.statusTimeouts[statusId];
}

@@ -476,7 +463,5 @@

if (this.statusEl) {
let li = this.statusEl.querySelector(`li[data-statusid="${statusId}"]`);
const li = this.statusEl.querySelector(`li[data-statusid="${statusId}"]`);
if (li) {
let fn = () => {
const fn = () => {
if (this.statusEl) {

@@ -492,11 +477,7 @@ this.statusEl.removeChild(li);

}
}
}
}
removeAllStatuses() {
//clear all timeouts

@@ -517,3 +498,2 @@ let statusId;

}
}

@@ -520,0 +500,0 @@

@@ -18,3 +18,3 @@ View.routes['/editor'] = function(EL) {

</p>
<section class="buttons">
<section class="buttons editor">
<button type="button" id="xibleFlowDeployButton">Deploy</button>

@@ -26,17 +26,21 @@ <button type="button" id="xibleFlowStartButton">Start</button>

</section>
<section id="console">
<div class="stats">
<section class="stats">
<div>
<canvas id="cpuChart"></canvas>
<label id="cpu">cpu</label>
</div>
<label id="cpu">cpu</label>
</section>
<section class="stats">
<div>
<canvas id="memChart"></canvas>
<label id="rss">rss</label>
<label id="heapTotal">heap total</label>
<label id="heapUsed">heap used</label>
</div>
<label id="rss">rss</label>
<label id="heapTotal">heap total</label>
<label id="heapUsed">heap used</label>
</section>
<section class="stats">
<div>
<canvas id="delayChart"></canvas>
<label id="delay">event loop delay</label>
</div>
<label id="delay">event loop delay</label>
</section>

@@ -159,2 +163,4 @@ </div>

options: {
responsive: true,
maintainAspectRatio: false,
legend: {

@@ -225,2 +231,4 @@ display: false

options: {
responsive: true,
maintainAspectRatio: false,
legend: {

@@ -275,2 +283,4 @@ display: false

options: {
responsive: true,
maintainAspectRatio: false,
legend: {

@@ -277,0 +287,0 @@ display: false

@@ -8,3 +8,3 @@ View.routes['/nodes'] = function(EL) {

<ul>
<li><a href="/test">blaat</a></li>
<li><a href="/test"></a></li>
</ul>

@@ -11,0 +11,0 @@ </section>

@@ -20,2 +20,3 @@ View.routes['/settings'] = function(EL) {

<li><a href="/settings/editor#nodes" onclick="settingsViewHolder.navigate('/settings/editor#nodes'); return false;">Nodes</a></li>
<li><a href="/settings/editor#flows" onclick="settingsViewHolder.navigate('/settings/editor#flows'); return false;">Flows</a></li>
<li><a href="/settings/editor#viewstate" onclick="settingsViewHolder.navigate('/settings/editor#viewstate'); return false;">Viewstate</a></li>

@@ -22,0 +23,0 @@ </ul>

@@ -22,2 +22,23 @@ View.routes['/settings/editor'] = function(EL) {

<section id="flows">
<h2>Flows</h2>
<p class="warning">
Running a flow in direct mode can have undesired side-effects. Take special note of the <a href="https://xible.io/docs/editor#direct" target="_blank" rel="noopener">online documentation</a>.
</p>
<dl>
<dd class="checkbox">
<label for="settingsEditorFlowsAllowDirect">
<input type="checkbox" value="true" id="settingsEditorFlowsAllowDirect" data-configpath="editor.flows.allowdirect" />
<span></span>
</label>
</dd>
<dt class="checkbox">
<label for="settingsEditorFlowsAllowDirect">
Allow direct mode
<div>Enable or disable the ability to run part of a flow directly.</div>
</label>
</dt>
</dl>
</section>
<section id="viewstate">

@@ -24,0 +45,0 @@ <h2>Viewstate</h2>

@@ -5,2 +5,3 @@ 'use strict';

const os = require('os');
const fs = require('fs');
const debug = require('debug');

@@ -63,3 +64,3 @@

this.persistentWebSocketMessages = {};
appNames = ['Config', 'Flow', 'Node', 'Registry'];
appNames = ['Config', 'CliQueue', 'Flow', 'Node', 'Registry'];
}

@@ -72,2 +73,31 @@

/**
* Creates a PID file in path `${this.configPath}.pid`
*/
writePidFile() {
if (!this.configPath) {
throw new Error('Cannot write PID file, configPath not set.');
}
fs.writeFile(`${this.configPath}.pid`, process.pid, {
mode: 0o600
}, (err) => {
if (err) {
throw err;
}
xibleDebug('PID file created');
});
}
/**
* Removes the PID file from path `${this.configPath}.pid`
* This is a sync action as it can be called on process.exit
*/
removePidFile() {
if (!this.configPath) {
throw new Error('Cannot remove PID file, configPath not set.');
}
fs.unlinkSync(`${this.configPath}.pid`);
xibleDebug('PID file removed');
}
// load nodes and flows

@@ -89,2 +119,17 @@ init(obj) {

// write PID file
this.writePidFile();
this.CliQueue.init();
process.on('SIGINT', () => {
process.exit(1);
});
process.on('SIGTERM', () => {
process.exit(1);
});
process.on('exit', () => {
this.CliQueue.removeFile();
this.removePidFile();
xibleDebug('exit');
});
this.startWeb();

@@ -203,4 +248,4 @@

return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
.toString(16)
.substring(1);
}

@@ -219,4 +264,2 @@ return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4()}${s4()}${s4()}`;

const spdy = require('spdy');
const fs = require('fs');
const expressApp = this.expressApp;

@@ -256,3 +299,4 @@

const webSocketServer = new ws.Server({
server: webServer
server: webServer,
ssl: this.secure
});

@@ -366,3 +410,2 @@ this.webSocketServer = webSocketServer;

case 'xible.node.addProgressBar':
this.setPersistentWebSocketMessage(message);

@@ -379,3 +422,2 @@

case 'xible.node.updateProgressBarById':
copyMessage = Object.assign({}, message);

@@ -388,3 +430,2 @@ copyMessage.method = 'xible.node.addProgressBar';

case 'xible.node.updateStatusById':
copyMessage = Object.assign({}, message);

@@ -479,24 +520,4 @@ copyMessage.method = 'xible.node.addStatus';

deleteFlow(flow, callback) {
if (flow._id) {
delete this.flows[flow._id];
}
if (typeof callback === 'function') {
callback();
}
}
deleteFlowById(id, callback) {
if (id) {
delete this.flows[id];
}
if (typeof callback === 'function') {
callback();
}
}
}
module.exports = Xible;

@@ -1,38 +0,29 @@

module.exports = function(NODE) {
'use strict';
let docIn = NODE.getInputByName('document');
let variableIn = NODE.getInputByName('variable');
module.exports = (NODE) => {
const docIn = NODE.getInputByName('document');
const variableIn = NODE.getInputByName('variable');
let docOut = NODE.getOutputByName('document');
const docOut = NODE.getOutputByName('document');
docOut.on('trigger', (conn, state, callback) => {
Promise.all([docIn.getValues(state), variableIn.getValues(state)]).then(([docs, variables]) => {
const assignedDocs = docs.map((doc) => {
// copy the document
// FIXME: should merge deep
const copyDoc = Object.assign({}, doc);
docOut.on('trigger', (conn, state, callback) => {
// add/overwrite the new vars
variables.forEach((variable) => {
let val = variable.values;
if (val.length === 1) {
val = val[0];
}
Promise.all([docIn.getValues(state), variableIn.getValues(state)]).then(([docs, variables]) => {
docs.forEach((doc) => {
//copy the document
//FIXME: should merge deep
doc = Object.assign({}, doc);
//add/overwrite the new vars
variables.forEach((variable) => {
let val = variable.values;
if (val.length === 1) {
val = val[0];
}
doc[variable.name] = val;
});
callback(doc);
});
});
});
copyDoc[variable.name] = val;
});
return copyDoc;
});
callback(assignedDocs);
});
});
};
{
"name": "document.assign",
"type": "object",
"description": "Assigns new key/value pairs to an existing document.",
"description": "Assigns new key/value pairs to an existing document. Returns a new document, does not update the existing document.",
"inputs": {
"document": {
"type": "document"
},
"type": "document"
},
"variable": {
"type": "variable"
}
"type": "variable"
}
},
"outputs": {
"document": {
"type": "document"
}
"type": "document"
}
}
}

@@ -1,15 +0,13 @@

module.exports = function(NODE) {
'use strict';
let docIn = NODE.getInputByName('document');
module.exports = (NODE) => {
const docIn = NODE.getInputByName('document');
let stringOut = NODE.getOutputByName('json');
stringOut.on('trigger', (conn, state, callback) => {
docIn.getValues(state).then((docs) => {
callback(JSON.stringify(docs));
});
});
const stringOut = NODE.getOutputByName('json');
stringOut.on('trigger', (conn, state, callback) => {
docIn.getValues(state)
.then((docs) => {
callback(JSON.stringify(docs));
});
});
};

@@ -7,10 +7,10 @@ {

"document": {
"type": "document"
}
"type": "document"
}
},
"outputs": {
"json": {
"type": "string"
}
"type": "string"
}
}
}

@@ -1,29 +0,22 @@

module.exports = function(NODE) {
'use strict';
let variableIn = NODE.getInputByName('variable');
module.exports = (NODE) => {
const variableIn = NODE.getInputByName('variable');
let docOut = NODE.getOutputByName('document');
const docOut = NODE.getOutputByName('document');
docOut.on('trigger', (conn, state, callback) => {
variableIn.getValues(state).then((variables) => {
const doc = {};
variables.forEach((variable) => {
let val = variable.values;
if (val.length === 1) {
val = val[0];
}
docOut.on('trigger', (conn, state, callback) => {
doc[variable.name] = val;
});
variableIn.getValues(state).then((variables) => {
let doc = {};
variables.forEach((variable) => {
let val = variable.values;
if (val.length === 1) {
val = val[0];
}
doc[variable.name] = val;
});
callback(doc);
});
});
callback(doc);
});
});
};

@@ -7,10 +7,10 @@ {

"variable": {
"type": "variable"
}
"type": "variable"
}
},
"outputs": {
"document": {
"type": "document"
}
"type": "document"
}
}
}
'use strict';
function getFlow(flowId, callback) {
let messageHandler = (message) => {
if (message.flowId !== flowId || message.method !== 'returnFlow') {
return;
}
process.removeListener('message', messageHandler);
messageHandler = null;
callback(message.flow);
};
process.on('message', messageHandler);
process.send({
method: 'getFlowById',
flowId
});
}
module.exports = (NODE) => {

@@ -7,20 +26,15 @@ const flowOut = NODE.getOutputByName('flow');

const flowId = NODE.data.flowName || NODE.flow.name;
getFlow(flowId, callback);
});
let messageHandler = (message) => {
if (message.flowId !== flowId || message.method !== 'returnFlow') {
const timingOut = NODE.getOutputByName('timing');
timingOut.on('trigger', (conn, state, callback) => {
const flowId = NODE.data.flowName || NODE.flow.name;
getFlow(flowId, (flow) => {
if (!flow) {
return;
}
process.removeListener('message', messageHandler);
messageHandler = null;
callback(message.flow);
};
process.on('message', messageHandler);
process.send({
method: 'getFlowById',
flowId
callback(flow.timing);
});
});
};
{
"name": "xible.flow",
"type": "object",
"description": "Defines the current flow.",
"description": "Defines a flow.",
"outputs": {
"flow": {
"type": "xible.flow"
},
"timing": {
"type": "document",
"description": "Returns the timing object on the flow."
}
}
}
{
"name": "xible",
"version": "0.6.0",
"version": "0.7.0",
"description": "xible",

@@ -21,16 +21,25 @@ "license": "MIT",

"visual",
"flow",
"workflow",
"connector",
"string",
"wire",
"programming",
"node"
"automation",
"automate",
"flexible",
"node",
"nodejs",
"javascript"
],
"scripts": {
"start": "node cli.js server start",
"debug": "export DEBUG=\"xible*\" && ./node_modules/.bin/nodemon cli.js server start",
"inspect": "export DEBUG=\"xible*\" && ./node_modules/.bin/nodemon --inspect cli.js server start",
"debug": "export DEBUG=\"xible*\" && ./node_modules/.bin/nodemon ./bin/xible.js server start",
"inspect": "export DEBUG=\"xible*\" && ./node_modules/.bin/nodemon --inspect=0.0.0.0:9229 ./bin/xible.js server start",
"inspect-brk": "export DEBUG=\"xible*\" && ./node_modules/.bin/nodemon --inspect-brk=0.0.0.0:9229 ./bin/xible.js server start",
"prepublish": "npm shrinkwrap --only=prod"
},
"bin": {
"xible": "./cli.js",
"xiblepm": "./pmcli.js"
"xible": "./bin/xible.js",
"xiblepm": "./bin/xiblepm.js"
},

@@ -51,3 +60,4 @@ "main": "index.js",

"sanitize-filename": "*",
"fs-extra": "*"
"fs-extra": "*",
"strip-ansi": "*"
},

@@ -54,0 +64,0 @@ "devDependencies": {

@@ -5,5 +5,8 @@ # XIBLE

## Installation
Once you have Node.js installed, simply run;
1. `sudo npm install -g xible`
See the [installation documentation](https://xible.io/docs/installation) for details.
Once you have Node.js installed;
- On Linux run: `sudo npm install xible -g`
- On Windows run: `npm install xible -g`
## Start XIBLE

@@ -20,4 +23,4 @@ After installation is completed;

## Browser support
The browser based graphical editor which comes with XIBLE is currently only supported by the Google Chrome browser; versions 53 and up. Opera, which is based on the same engine as Chrome, is also supported starting from version 44.
The browser based [graphical editor](http://xible.io/docs/editor/) which comes with XIBLE is currently only supported by the Google Chrome browser; versions 53 and up. Opera, which is based on the same engine as Chrome, is also supported starting from version 44.
Other browsers may work, but some editor functionality is unavailable if Shadow DOM v1 is not implemented. It will be possible to start, stop and delete flows, but deploying and saving is disabled. Also, the detail settings of nodes are not visible.
Other browsers may work, but some editor functionality is unavailable if [Shadow DOM v1](http://caniuse.com/#search=shadow%20dom%20v1) is not implemented. It will be possible to start, stop and delete flows, but deploying and saving is disabled. Also, the detail settings of nodes are not visible.

@@ -5,3 +5,5 @@ 'use strict';

EXPRESS_APP.get('/api/validateFlowPermissions', (req, res) => {
XIBLE.Flow.validatePermissions().then((result) => {
XIBLE.Flow
.validatePermissions()
.then((result) => {
res.json(result);

@@ -8,0 +10,0 @@ });

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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