From 8bbb1c655254c73a8a00aabbfb3a1bc0b5abff61 Mon Sep 17 00:00:00 2001 From: sevenbitbyte Date: Mon, 23 Oct 2023 13:24:39 +0000 Subject: [PATCH 01/14] update sandbox compiler, ncc. --- examples/test-service-host.js | 2 +- jsdoc.json | 4 ++-- package.json | 9 +++------ public/example.html | 8 ++++---- src/sandbox/endpoint-info-sandbox.js | 9 +++++---- src/sandbox/middleware-exec-sandbox.js | 5 +++-- src/sandbox/middleware-info-sandbox.js | 11 ++++++----- src/sandbox/sandbox.js | 3 ++- src/service/iservice.js | 10 +++++++--- src/service/service-runner-node.js | 11 ++++++++--- 10 files changed, 41 insertions(+), 31 deletions(-) diff --git a/examples/test-service-host.js b/examples/test-service-host.js index fdf52d3..b6d8e2a 100644 --- a/examples/test-service-host.js +++ b/examples/test-service-host.js @@ -28,7 +28,7 @@ async function main(){ //const uri = 'mongodb://localhost:27017/server-party-test' //debug('db location', uri) - const path = '/data/datparty/srv-party' + const path = '/data/dataparty/example-host-party' let party = new Dataparty.TingoParty({ path, diff --git a/jsdoc.json b/jsdoc.json index 21e4669..cf446b5 100644 --- a/jsdoc.json +++ b/jsdoc.json @@ -26,7 +26,7 @@ { "title": "Github", "id": "github", - "link": "https://github.com/datapartyjs/api" + "link": "https://github.com/datapartyjs/dataparty-api" }, { "title": "npm", @@ -59,4 +59,4 @@ "hardwrap": false, "idInHeadings": true } -} \ No newline at end of file +} diff --git a/package.json b/package.json index a5318eb..3e4e527 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,9 @@ "frontend": { "context": "browser", "source": "src/index-browser.js", - "optimize": false, + "optimize": true, "outputFormat": "global", + "includeNodeModules": true, "engines": { "browsers": "Chrome 80" } @@ -63,11 +64,9 @@ "@dataparty/tasker": "^0.0.2", "@diva.exchange/i2p-sam": "^4.1.8", "@markwylde/liferaft": "^1.3.4", - "@vercel/ncc": "^0.36.1", - "@zeit/ncc": "^0.22.3", + "@sevenbitbyte/ncc": "0.0.2", "ajv": "6.9.1", "axios": "^0.27.2", - "bleno": "npm:@abandonware/bleno@^0.5.1-4", "body-parser": "^1.19.0", "bson": "^4.6.1", "bson-objectid": "^1.3.0", @@ -91,7 +90,6 @@ "morgan": "^1.10.0", "multer": "^1.4.5-lts.1", "nconf": "^0.10.0", - "noble": "npm:@abandonware/noble@^1.9.2-20", "node-mocks-http": "^1.12.1", "node-persist": "^3.0.1", "origin-router": "^1.6.4", @@ -127,7 +125,6 @@ "https-browserify": "^1.0.0", "jsdoc": "^3.6.2", "minami": "^1.2.3", - "mongodb-client-encryption": "^2.2.1", "parcel": "^2.3.1", "path-browserify": "^1.0.1", "process": "^0.11.10", diff --git a/public/example.html b/public/example.html index 17ba6ac..9f2aa79 100644 --- a/public/example.html +++ b/public/example.html @@ -28,7 +28,7 @@ config = new Dataparty.Config.MemoryConfig({ basePath:'demo', cloud: { - uri: 'http://172.16.3.1:4001' + uri: 'http://10.10.10.201:4000' } }) @@ -40,14 +40,14 @@ })*/ - const remoteIdentity = await Dataparty.Comms.RestComms.HttpGet( config.read('cloud.uri') + '/identity') + const remoteIdentity = await Dataparty.Comms.RestComms.HttpGet( await config.read('cloud.uri') + '/identity') console.log('cloud.uri -',config.read('cloud.uri')) console.log('\tremoteIdentity', remoteIdentity) let party = new Dataparty.PeerParty({ comms: new Dataparty.Comms.WebsocketComms({ - uri:'ws://172.16.3.1:4001/ws', + uri:'ws://10.10.10.201:4001/ws', discoverRemoteIdentity: false, remoteIdentity: remoteIdentity, session: Math.random().toString(36).slice(2) @@ -68,7 +68,7 @@ }) timeTopic.subscribe((msg)=>{ - console.log(name, msg) + console.log(timeTopic.name, msg) }) diff --git a/src/sandbox/endpoint-info-sandbox.js b/src/sandbox/endpoint-info-sandbox.js index 159d575..0553a62 100644 --- a/src/sandbox/endpoint-info-sandbox.js +++ b/src/sandbox/endpoint-info-sandbox.js @@ -16,12 +16,13 @@ module.exports = async ()=>{ } try{ - let Lib = ${code} + var self = {} + ${code} return { - Name: Lib.Name, - Description: Lib.Description, - MiddlewareConfig: Lib.MiddlewareConfig + Name: self.Lib.Name, + Description: self.Lib.Description, + MiddlewareConfig: self.Lib.MiddlewareConfig } } catch(err){ diff --git a/src/sandbox/middleware-exec-sandbox.js b/src/sandbox/middleware-exec-sandbox.js index 2e60322..a07dc14 100644 --- a/src/sandbox/middleware-exec-sandbox.js +++ b/src/sandbox/middleware-exec-sandbox.js @@ -16,9 +16,10 @@ module.exports = async (ctx, static_ctx)=>{ } try{ - let Lib = ${code} + var self = {} + ${code} - return await Lib.${func}(ctx, static_ctx) + return await self.Lib.${func}(ctx, static_ctx) } catch(err){ diff --git a/src/sandbox/middleware-info-sandbox.js b/src/sandbox/middleware-info-sandbox.js index 2c8c3be..12a68fe 100644 --- a/src/sandbox/middleware-info-sandbox.js +++ b/src/sandbox/middleware-info-sandbox.js @@ -16,13 +16,14 @@ module.exports = async ()=>{ } try{ - let Lib = ${code} + var self = {} + ${code} return { - Name: Lib.Name, - Type: Lib.Type, - Description: Lib.Description, - ConfigSchema: Lib.ConfigSchema + Name: self.Lib.Name, + Type: self.Lib.Type, + Description: self.Lib.Description, + ConfigSchema: self.Lib.ConfigSchema } } catch(err){ diff --git a/src/sandbox/sandbox.js b/src/sandbox/sandbox.js index d07f8d7..80b4206 100644 --- a/src/sandbox/sandbox.js +++ b/src/sandbox/sandbox.js @@ -15,6 +15,7 @@ class Sandbox { this.offsetToken = offsetToken this.offset = code.split(this.offsetToken)[0].split('\n').length-1 this.script = new VMScript(code).compile() + debug(code) } async loadSourceMap(){ @@ -26,7 +27,7 @@ class Sandbox { } async run(context, sandbox){ - //debug('running') + debug('running') try{ let vm = new NodeVM({ diff --git a/src/service/iservice.js b/src/service/iservice.js index a218242..f76bdd7 100644 --- a/src/service/iservice.js +++ b/src/service/iservice.js @@ -1,7 +1,7 @@ const fs = require('fs') const Path = require('path') -//const NCC = require('@vercel/ncc') -const NCC = require('@zeit/ncc') +const NCC = require('@sevenbitbyte/ncc') +//const NCC = require('@zeit/ncc') const Hoek = require('@hapi/hoek') const {JSONPath} = require('jsonpath-plus') const gitRepoInfo = require('git-repo-info') @@ -92,7 +92,11 @@ module.exports = class IService { watch: false, // default v8cache: false, // default quiet: false, // default - debugLog: false // default + debugLog: false, // default + //target: 'es2015' + esm: false, + moduleType: 'self', + libraryName: 'Lib' } if(build){ diff --git a/src/service/service-runner-node.js b/src/service/service-runner-node.js index 2c7990a..48b0260 100644 --- a/src/service/service-runner-node.js +++ b/src/service/service-runner-node.js @@ -151,8 +151,11 @@ class ServiceRunnerNode { if(!this.useNative){ const build = Hoek.reach(this.service, `compiled.endpoints.${name}`) - //debug('build', build) - endpoint = eval(build.code/*, build.map*/) + debug('build', build.code) + var self={} + eval(build.code, build.map) + endpoint = self.Lib + debug('obj Lib', self) } else{ endpoint = this.service.constructors.endpoints[name] @@ -218,7 +221,9 @@ class ServiceRunnerNode { let middle=null if(!this.useNative){ - middle = eval(build.code/*, build.map*/) + let self={} + eval(build.code, build.map) + middle = self.Lib } else{ middle = this.service.constructors.middleware[type][name] From 9b36ea22f1d77442925d82df0da20f95dfb38535 Mon Sep 17 00:00:00 2001 From: Alan Meekins Date: Sun, 5 Nov 2023 00:44:45 +0000 Subject: [PATCH 02/14] closes #82 --- package.json | 2 +- public/app.js | 10 +++++----- src/bouncer/db/zango-db.js | 2 +- src/index-browser.js | 2 ++ src/index-embedded.js | 4 ++++ src/index.js | 4 ++++ 6 files changed, 17 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 3e4e527..230db80 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ }, "dependencies": { "@dataparty/bouncer-db": "1.0.1", - "@dataparty/crypto": "^1.1.2", + "@dataparty/crypto": "file:../dataparty-crypto", "@dataparty/tasker": "^0.0.2", "@diva.exchange/i2p-sam": "^4.1.8", "@markwylde/liferaft": "^1.3.4", diff --git a/public/app.js b/public/app.js index b1f970c..4ec1c93 100644 --- a/public/app.js +++ b/public/app.js @@ -1,10 +1,10 @@ -const config = new DataParty.Config.LocalStorageConfig({ +const config = new Dataparty.Config.LocalStorageConfig({ cloud: { - uri: 'http://localhost:4001' + uri: `http://${window.location.hostname}:4000` } }) -const party = new DataParty.CloudParty({ +const party = new Dataparty.CloudParty({ config, }) @@ -77,7 +77,7 @@ async function main(){ const text = `call deltaMs=${callTime2.deltaMs}ms complete ${complete}` document.getElementById("secure-echo-speed").innerHTML = text - }, 250) + }, 100) setInterval(async ()=>{ @@ -100,7 +100,7 @@ async function main(){ const text = `call deltaMs=${callTime2.deltaMs}ms complete ${complete}` document.getElementById("echo-speed").innerHTML = text - }, 100) + }, 10000) } diff --git a/src/bouncer/db/zango-db.js b/src/bouncer/db/zango-db.js index 70653ee..25bf3eb 100644 --- a/src/bouncer/db/zango-db.js +++ b/src/bouncer/db/zango-db.js @@ -39,7 +39,7 @@ module.exports = class ZangoDb extends IDb { for(const name of this.factory.getValidators()){ debug('creating collection', name) - const indexSettings = reach(this.factory, 'model.IndexSettings.'+name) + const indexSettings = reach(this.factory, 'schemas.IndexSettings.'+name) const indices = ['$meta.id'].concat(indexSettings.unique).concat(indexSettings.indices) diff --git a/src/index-browser.js b/src/index-browser.js index 9bc6368..a1f8002 100644 --- a/src/index-browser.js +++ b/src/index-browser.js @@ -12,8 +12,10 @@ const Config = { SecureConfig } +const Crypto = require('@dataparty/crypto') let lib = { + Crypto, Comms, Config, ...Party, diff --git a/src/index-embedded.js b/src/index-embedded.js index c6f7dc9..dc0afbc 100644 --- a/src/index-embedded.js +++ b/src/index-embedded.js @@ -4,7 +4,11 @@ const Party = require('./party/index-embedded') const Topics = require('./topics') const Bouncer = require('./bouncer') +const Crypto = require('@dataparty/crypto') + + module.exports = { + Crypto, Comms, Config, Bouncer, diff --git a/src/index.js b/src/index.js index aeeaaa0..05c05c2 100644 --- a/src/index.js +++ b/src/index.js @@ -6,7 +6,11 @@ const Bouncer = require('./bouncer') const Service = require('./service') const Sandbox = require('./sandbox') +const Crypto = require('@dataparty/crypto') + + module.exports = { + Crypto, Comms, Config, Bouncer, From 72f6507b01849a3a45e73775d443872a0c2f41fb Mon Sep 17 00:00:00 2001 From: Alan Meekins Date: Sat, 3 Feb 2024 01:34:58 +0000 Subject: [PATCH 03/14] closes #78 --- src/config/secure-config.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/config/secure-config.js b/src/config/secure-config.js index 939685a..b6c2073 100644 --- a/src/config/secure-config.js +++ b/src/config/secure-config.js @@ -181,10 +181,6 @@ class SecureConfig extends IConfig { argonType } - if(!this.argon){ - this.argon = argon - } - key = await dataparty_crypto.Routines.createKeyFromPasswordArgon2( this.argon, password, From a491782f7db0b0c2b025d1dd45822dab983fcc57 Mon Sep 17 00:00:00 2001 From: Alan Meekins Date: Sat, 3 Feb 2024 01:54:10 +0000 Subject: [PATCH 04/14] closes #84 --- src/topics/peer-node.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/topics/peer-node.js b/src/topics/peer-node.js index 8d00f7b..ae56df4 100644 --- a/src/topics/peer-node.js +++ b/src/topics/peer-node.js @@ -33,7 +33,7 @@ class PeerNode { op: 'publish', id: 'publish:'+this.peer.opId, topic: topic.path, - sender: { uuid: this.uuid, identity: this.peer.remoteIdentity }, + sender: { uuid: this.peer.uuid, identity: this.peer.remoteIdentity }, msg: data })) From c28a243736bf72b66a89e4fd289b44456ac3bfb7 Mon Sep 17 00:00:00 2001 From: Alan Meekins Date: Sat, 3 Feb 2024 02:06:43 +0000 Subject: [PATCH 05/14] closes #88 --- examples/test-service-tasks.js | 4 ++-- src/venue/schema/venue_service.js | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/examples/test-service-tasks.js b/examples/test-service-tasks.js index 8e79e88..4391bae 100644 --- a/examples/test-service-tasks.js +++ b/examples/test-service-tasks.js @@ -20,12 +20,12 @@ async function main(){ debug('built', Object.keys(build)) - const path = '/data/datparty/srv-party' + const path = '/data/dataparty/srv-party' let party = new Dataparty.TingoParty({ path, model: build, - config: new Dataparty.Config.JsonFileConfig({basePath: '/data/datparty/'}) + config: new Dataparty.Config.JsonFileConfig({basePath: path}) }) diff --git a/src/venue/schema/venue_service.js b/src/venue/schema/venue_service.js index 40f23a1..4855b44 100644 --- a/src/venue/schema/venue_service.js +++ b/src/venue/schema/venue_service.js @@ -30,11 +30,11 @@ class VenueSrv extends Dataparty.ISchema { branch: String }, schemas: { - Package: {}, IndexSettings: {}, JSONSchema: {}, Permissions: {} }, + documents: {}, endpoints: {}, middleware: { pre: {}, @@ -43,6 +43,21 @@ class VenueSrv extends Dataparty.ISchema { middleware_order: { pre: [String], post: [String] + }, + tasks: {}, + compileSettings: { + cache: Boolean, + externals: [String], + minify: Boolean, + sourceMap: Boolean, + sourceMapRegister: Boolean, + watch: Boolean, + v8cache: Boolean, + quite: Boolean, + debugLog: Boolean, + esm: Boolean, + moduleType: Boolean, + libraryName: Boolean } } } From 9f1a97c245ac23d6a4913b547c3cbc21cbe6cf7d Mon Sep 17 00:00:00 2001 From: Alan Meekins Date: Sat, 3 Feb 2024 05:27:21 +0000 Subject: [PATCH 06/14] closes #85 and #86 --- src/service/service-runner-node.js | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/service/service-runner-node.js b/src/service/service-runner-node.js index 52805ac..d10769f 100644 --- a/src/service/service-runner-node.js +++ b/src/service/service-runner-node.js @@ -40,6 +40,8 @@ class ServiceRunnerNode { this.taskRunner = new Runner() this.started = false + + this.taskCounter = 0 } async start(){ @@ -80,6 +82,12 @@ class ServiceRunnerNode { } } + assertTaskIsValid(name){ + if(!this.tasks[name]){ + throw new Error('invalid task ['+name+']') + } + } + async loadTask(name){ if(this.tasks[name]){ return @@ -124,12 +132,56 @@ class ServiceRunnerNode { debug('loaded task',name,'in',dt.deltaMs,'ms') } + async spawnTask(type, context){ + this.assertTaskIsValid(type) + + debug('spawnTask', type, 'useNative =',this.useNative) + + let dt = new DeltaTime().start() + + + "use strict" + let task=null + + let TaskClass = null + + if(!this.useNative){ + const build = Hoek.reach(this.service, `compiled.tasks.${type}`) + TaskClass = eval(build.code/*, build.map*/) + } + else{ + TaskClass = this.service.constructors.tasks[type] + } + + task = new TaskClass({ + context:{ + party: this.party, + serviceRunner: this, + ...context + } + }) + + task.name = task.name + '-' + this.taskCounter++ + + + debug('task info', TaskClass.info) + + this.taskRunner.addTask(task) + + + dt.end() + debug('spawned task',task.name,'in',dt.deltaMs,'ms') + + return task + } + /** * Add a named task to the run queue * @see https://github.com/datapartyjs/tasker * @param {string} name */ runTask(name){ + this.assertTaskIsValid(name) const task = this.tasks[name] this.taskRunner.addTask(task) From 8f292aa03ac20329c42e9eece879a77923b3c689 Mon Sep 17 00:00:00 2001 From: Alan Meekins Date: Sat, 3 Feb 2024 07:30:12 +0000 Subject: [PATCH 07/14] closes #79 and addes uuid document id's by default --- examples/test-local-lokidb.js | 23 +++++++++++++++------- examples/test-local-tingodb.js | 28 +++++++++++++++++++-------- package.json | 1 + src/bouncer/db/loki-db.js | 35 +++++++++++++++++++++++++++------- src/bouncer/db/tingo-db.js | 25 ++++++++++++++++++++---- src/bouncer/db/zango-db.js | 12 ++++++++++-- src/party/idocument.js | 14 +++++++++++++- src/party/loki-cache.js | 9 ++++++++- 8 files changed, 117 insertions(+), 30 deletions(-) diff --git a/examples/test-local-lokidb.js b/examples/test-local-lokidb.js index 63c7798..1f8613b 100644 --- a/examples/test-local-lokidb.js +++ b/examples/test-local-lokidb.js @@ -3,7 +3,6 @@ const debug = require('debug')('example.loki-db') const BouncerModel = require('@dataparty/bouncer-model/dist/bouncer-model.json') const Dataparty = require('../src/index.js') - let local=null async function getUser(name) { @@ -18,6 +17,7 @@ async function main(){ const dbPath = (await fs.mkdtemp('/tmp/loki-party')) + '/loki.db' debug('db location', dbPath) + console.log(dbPath) local = new Dataparty.LokiParty({ path: dbPath, @@ -32,31 +32,40 @@ async function main(){ if(!user){ - debug('creating document') + console.log('creating document') user = await local.createDocument('user', {name: 'tester', created: (new Date()).toISOString() }) } else{ - debug('loaded document') + console.log('loaded document') } console.log(user.data) + console.log('hash',user.hash) - user.on('update', (obj)=>{ console.log('update') }) - user.on('value', (obj)=>{ console.log('value') }) + user.on('update', (obj)=>{ console.log('event [document.on(update)]') }) + user.on('value', (obj)=>{ console.log('event [document.on(value)]') }) + user.on('remove', (obj)=>{ console.log('event [document.on(remove)]') }) + console.log('\nchanging document field') user.data.name = 'renamed-tester' await user.save() console.log(user.data) + console.log('hash',user.hash) + console.log('find document by new field value') let userFind = await getUser('renamed-tester') console.log(userFind.data) + console.log('hash',userFind.hash) + console.log('\nchanging document field') + userFind.data.name = 'renamed-tester' + await userFind.save() - console.log(dbPath) - + + console.log('delete document') await userFind.remove() diff --git a/examples/test-local-tingodb.js b/examples/test-local-tingodb.js index f7ad8be..38f0389 100644 --- a/examples/test-local-tingodb.js +++ b/examples/test-local-tingodb.js @@ -31,32 +31,44 @@ async function main(){ if(!user){ - debug('creating document') + console.log('creating document') user = await local.createDocument('user', {name: 'tester', created: (new Date()).toISOString() }) } else{ - debug('loaded document') + console.log('loaded document') } - console.log('before', user.data) + console.log(user.data) + console.log('hash',user.hash) + user.on('update', (obj)=>{ console.log('event [document.on(update)]') }) + user.on('value', (obj)=>{ console.log('event [document.on(value)]') }) + user.on('remove', (obj)=>{ console.log('event [document.on(remove)]') }) + + console.log('\nchanging document field') user.data.name = 'renamed-tester' - //user.data.invalideField = true await user.save() - console.log('after', user.data) + console.log(user.data) + console.log('hash',user.hash) + console.log('find document by new field value') let userFind = await getUser('renamed-tester') console.log(userFind.data) + console.log('hash',userFind.hash) + + console.log('\nchanging document field') + userFind.data.name = 'renamed-tester' + await userFind.save() - process.exit() + + console.log('delete document') + await userFind.remove() - await user.remove() console.log(await getUser('renamed-tester')) - } diff --git a/package.json b/package.json index 230db80..3ce2b14 100644 --- a/package.json +++ b/package.json @@ -91,6 +91,7 @@ "multer": "^1.4.5-lts.1", "nconf": "^0.10.0", "node-mocks-http": "^1.12.1", + "node-object-hash": "^3.0.0", "node-persist": "^3.0.1", "origin-router": "^1.6.4", "parse-url": "^5.0.1", diff --git a/src/bouncer/db/loki-db.js b/src/bouncer/db/loki-db.js index c1384ba..79ac551 100644 --- a/src/bouncer/db/loki-db.js +++ b/src/bouncer/db/loki-db.js @@ -6,6 +6,7 @@ const Loki = require('lokijs') const LokiFS = Loki.LokiFsAdapter const LFSA = require('lokijs/src/loki-fs-structured-adapter') const ObjectId = require('bson-objectid') +const uuidv4 = require('uuid/v4') const MongoQuery = require('../mongo-query') const { promisfy } = require('promisfy') @@ -26,7 +27,7 @@ const debug = require('debug')('bouncer.db.loki-db') */ module.exports = class LokiDb extends IDb { - constructor ({path, factory, dbAdapter, lokiOptions}) { + constructor ({path, factory, dbAdapter, lokiOptions, useUuid}) { super(factory) debug('constructor') this.loki = null @@ -34,6 +35,7 @@ module.exports = class LokiDb extends IDb { this.path = path this.dbAdapter = dbAdapter || new LFSA() this.error = null + this.useUuid = (useUuid==undefined) ? true : useUuid } static get LokiLocalStorageAdapter(){ @@ -142,7 +144,13 @@ module.exports = class LokiDb extends IDb { ensureId(obj){ let temp = {...obj} if(!reach(temp,'$meta.id')){ - temp.$meta.id = (new ObjectId()).toHexString() + + if(this.useUuid){ + temp.$meta.id = uuidv4() + } + else{ + temp.$meta.id = (new ObjectId()).toHexString() + } } let dbDoc = this.documentFromObject(temp) @@ -232,7 +240,19 @@ module.exports = class LokiDb extends IDb { for(let obj of docs){ let temp = {...obj} - if(temp._id===undefined){ temp._id = (new ObjectId()).toString(); temp.$meta.id=temp._id; } + if(temp._id===undefined){ + + if(this.useUuid){ + temp._id = uuidv4() + } + else{ + temp._id = (new ObjectId()).toHexString() + } + + temp.$meta.id=temp._id; + } + + let dbDoc = this.documentFromObject(temp) @@ -311,15 +331,16 @@ module.exports = class LokiDb extends IDb { const dbDoc = collection.findAndRemove( { '$meta.id': obj.$meta.id } ) - debug('dbDoc', dbDoc) - - let finalObj = this.documentToObject(dbDoc) + let finalObj = { + $meta: obj.$meta + } finalObj.$meta.removed = true this.emitChange(finalObj, 'remove') - debug('obj', finalObj) + debug('finalObj', finalObj) + debug('obj', obj) await promisfy(this.loki.saveDatabase.bind(this.loki)) return finalObj diff --git a/src/bouncer/db/tingo-db.js b/src/bouncer/db/tingo-db.js index 03c026b..69dcb4c 100644 --- a/src/bouncer/db/tingo-db.js +++ b/src/bouncer/db/tingo-db.js @@ -3,10 +3,10 @@ const IDb = require('../idb') const Hoek = require('@hapi/hoek') +const uuidv4 = require('uuid/v4') const {promisfy} = require('promisfy') - const debug = require('debug')('bouncer.db.tingo-db') @@ -20,13 +20,14 @@ const debug = require('debug')('bouncer.db.tingo-db') */ module.exports = class TingoDb extends IDb { - constructor ({path, factory, tingoOptions, prefix}) { + constructor ({path, factory, tingoOptions, prefix, useUuid}) { super(factory, prefix) debug('constructor path=',path, tingoOptions) this.tingo = null this.path = path this.tingoOptions = tingoOptions || {nativeObjectID: true} this.error = null + this.useUuid = (useUuid==undefined) ? true : useUuid } @@ -92,7 +93,13 @@ module.exports = class TingoDb extends IDb { ensureId(obj){ let temp = {...obj} if(!reach(temp,'$meta.id')){ - temp.$meta.id = new this.tingo.ObjectID().valueOf() + + if(this.useUuid){ + temp.$meta.id = uuidv4() + } + else{ + temp.$meta.id = new this.tingo.ObjectID().valueOf() + } } let dbDoc = this.documentFromObject(temp) @@ -196,7 +203,17 @@ module.exports = class TingoDb extends IDb { for(let obj of docs){ let temp = {...obj} - if(temp._id===undefined){ temp._id = (new this.tingo.ObjectID()).toString(); temp.$meta.id=temp._id; } + if(temp._id===undefined){ + + if(this.useUuid){ + temp._id = uuidv4() + } + else{ + temp._id = (new this.tingo.ObjectID()).toString(); + } + + temp.$meta.id=temp._id; + } let dbDoc = this.documentFromObject(temp) diff --git a/src/bouncer/db/zango-db.js b/src/bouncer/db/zango-db.js index 25bf3eb..5066583 100644 --- a/src/bouncer/db/zango-db.js +++ b/src/bouncer/db/zango-db.js @@ -5,6 +5,7 @@ const Hoek = require('@hapi/hoek') const zango = require('zangodb') const reach = require('../../utils/reach') const ObjectId = require('bson-objectid') +const uuidv4 = require('uuid/v4') const MongoQuery = require('../mongo-query') const { promisfy } = require('promisfy') @@ -20,12 +21,13 @@ const debug = require('debug')('bouncer.db.zango-db') */ module.exports = class ZangoDb extends IDb { - constructor ({dbname, factory}) { + constructor ({dbname, factory, useUuid}) { super(factory) debug('constructor') this.zango = null this.dbname = dbname this.error = null + this.useUuid = (useUuid==undefined) ? true : useUuid } @@ -105,7 +107,13 @@ module.exports = class ZangoDb extends IDb { ensureId(obj){ let temp = {...obj} if(!reach(temp,'$meta.id')){ - temp.$meta.id = (new ObjectId()).toHexString() + + if(this.useUuid){ + temp.$meta.id = uuidv4() + } + else{ + temp.$meta.id = (new ObjectId()).toHexString() + } } let dbDoc = this.documentFromObject(temp) diff --git a/src/party/idocument.js b/src/party/idocument.js index 77bb6ab..0c90cbf 100644 --- a/src/party/idocument.js +++ b/src/party/idocument.js @@ -3,6 +3,7 @@ const reach = require('../utils/reach') const debug = require('debug')('dataparty.idocument') const EventEmitter = require('eventemitter3') +const objectHasher = require('node-object-hash').hasher() class IDocument extends EventEmitter { @@ -116,6 +117,15 @@ class IDocument extends EventEmitter { return obj } + /** + * hash of `document.data` using sha256 + * @member module:Party.IDocument.hash + * @type {object} + */ + get hash(){ + return objectHasher.hash(this.data) + } + /** * @async * Merge fields into document @@ -193,7 +203,9 @@ class IDocument extends EventEmitter { * */ async remove(){ - debug('removing document ', this.data.type, this.data.id) + debug('removing document ', this.type, this.id) + + //this.emit('remove', this) return this.party.remove(this.data) } diff --git a/src/party/loki-cache.js b/src/party/loki-cache.js index 8211fd7..9a5810c 100644 --- a/src/party/loki-cache.js +++ b/src/party/loki-cache.js @@ -32,6 +32,7 @@ module.exports = class LokiCache extends EventEmitter { } remove(type, id){ + console('cache remove') debug('remove', type, id) var collection = this.db.getCollection(type) @@ -51,6 +52,10 @@ module.exports = class LokiCache extends EventEmitter { debug('remove CATCH -', exception) collection.findAndRemove({'$meta.id': id}) } + + debug('remove found', found) + + this._emitChange(found, 'remove') } var item = this.findById(type, id) @@ -115,9 +120,11 @@ module.exports = class LokiCache extends EventEmitter { catch(err){ debug('WARN', err) } - this._emitChange(msg, 'remove') } + debug('emit remove', msg) + this._emitChange(msg, 'remove') + // otherwise insert new message (remove old message if it exists) } else { From 007b6e96e55ca11fbece49b669fdf832725cec51 Mon Sep 17 00:00:00 2001 From: Alan Meekins Date: Sat, 3 Feb 2024 23:22:31 +0000 Subject: [PATCH 08/14] fix remote document change notifications --- examples/test-loopback-party.js | 47 +++++++++++++++++++++++++----- src/bouncer/idb.js | 1 + src/comms/isocket-comms.js | 8 +++-- src/comms/loopback-channel-port.js | 2 +- src/comms/loopback-channel.js | 2 +- src/comms/ros-shim.js | 2 -- src/party/idocument.js | 9 ++++-- src/party/loki-cache.js | 1 - src/topics/host-topic.js | 2 +- src/topics/local-topic-host.js | 8 +++-- src/topics/peer-node.js | 2 +- 11 files changed, 63 insertions(+), 21 deletions(-) diff --git a/examples/test-loopback-party.js b/examples/test-loopback-party.js index 6cef807..63e0f2d 100644 --- a/examples/test-loopback-party.js +++ b/examples/test-loopback-party.js @@ -4,6 +4,15 @@ const WRTC = require('wrtc') const BouncerModel = require('@dataparty/bouncer-model/dist/bouncer-model.json') const Dataparty = require('../src') + +async function getUser(party, name) { + return (await party.find() + .type('user') + .where('name').equals(name) + .exec())[0] +} + + async function main(){ const dbPath = await fs.mkdtemp('/tmp/tingo-party') const configPath = await fs.mkdtemp('/tmp/tingo-party-config') @@ -18,11 +27,13 @@ async function main(){ config }) + hostLocal.topics = new Dataparty.LocalTopicHost() + let loopback = new Dataparty.Comms.LoopbackChannel() let comms1 = new Dataparty.Comms.LoopbackComms({ host: true, - channel: loopback.peer1 + channel: loopback.port1 }) let peer1 = new Dataparty.PeerParty({ @@ -33,7 +44,9 @@ async function main(){ }) - let comms2 = new Dataparty.Comms.LoopbackComms({ channel: loopback.peer2, session: 'foobar' }) + + + let comms2 = new Dataparty.Comms.LoopbackComms({ channel: loopback.port2, session: 'foobar' }) let peer2 = new Dataparty.PeerParty({ comms: comms2, @@ -71,16 +84,36 @@ async function main(){ if(!user){ - debug('creating document') + console.log('peer2 creating document') user = await peer2.createDocument('user', {name: 'tester', created: (new Date()).toISOString() }) } else{ - debug('loaded document') + console.log('peer2 loaded document') } - + + console.log(user.data) + console.log('hash',user.hash) + + console.log('peer1 find document by new field value') + let userFind = await getUser(peer1,'tester') + console.log(userFind.data) + console.log('hash',userFind.hash) + + user.on('change', (obj)=>{ console.log('peer2 remote event [document.on(change)]', obj ) }) + user.on('update', (obj)=>{ console.log('peer2 event [document.on(update)]')}) + user.on('value', (doc)=>{ console.log('peer2 event [document.on(value)]') }) + user.on('remove', (obj)=>{ console.log('peer2 event [document.on(remove)]') }) + + await user.watch() + + console.log('\npeer1 changing document field') + userFind.data.name = 'renamed-tester' + await userFind.save() + + console.log(userFind.data) + console.log('hash',userFind.hash) - console.log(user.data) - process.exit() + await userFind.remove() } diff --git a/src/bouncer/idb.js b/src/bouncer/idb.js index a52b8c6..2cdbda9 100644 --- a/src/bouncer/idb.js +++ b/src/bouncer/idb.js @@ -60,6 +60,7 @@ class IDb extends EventEmitter { emitChange(msg, change){ const { type, id, revision } = msg.$meta + debug('emitChange', `${type}:${id}`) this.emit( `${type}:${id}`, { diff --git a/src/comms/isocket-comms.js b/src/comms/isocket-comms.js index 9379d14..2106097 100644 --- a/src/comms/isocket-comms.js +++ b/src/comms/isocket-comms.js @@ -126,7 +126,7 @@ class ISocketComms extends EventEmitter { debug(msg.id) if(msg.op != 'publish'){ - debug('emit id') + debug('emit id', msg.id) comm.emit(msg.id, msg) } else { debug('emit message') @@ -136,7 +136,11 @@ class ISocketComms extends EventEmitter { } send(input){ - debug('send - ', input) + debug('send - ', typeof input, input) + + if(typeof input != 'object'){ + input = JSON.parse(input) + } const content = new Message({msg: input}) diff --git a/src/comms/loopback-channel-port.js b/src/comms/loopback-channel-port.js index a033188..10bfcbe 100644 --- a/src/comms/loopback-channel-port.js +++ b/src/comms/loopback-channel-port.js @@ -1,5 +1,5 @@ const debug=require('debug')('dataparty.comms.loopback-channel-port') - +const EventEmitter = require("eventemitter3") class LoopbackChannelPort { constructor(peer, name){ diff --git a/src/comms/loopback-channel.js b/src/comms/loopback-channel.js index 0f455b6..5e43327 100644 --- a/src/comms/loopback-channel.js +++ b/src/comms/loopback-channel.js @@ -17,7 +17,7 @@ module.exports = class LoopbackChannel { this.port1 = new LoopbackChannelPort(undefined, '1') //! The second channel peer - this.peer2 = new LoopbackChannelPort(this.port1, '2') + this.port2 = new LoopbackChannelPort(this.port1, '2') this.port1.peer = this.port2 } diff --git a/src/comms/ros-shim.js b/src/comms/ros-shim.js index dd58a40..11e4524 100644 --- a/src/comms/ros-shim.js +++ b/src/comms/ros-shim.js @@ -27,8 +27,6 @@ class RosShim extends ROSLIB.Ros { handleMessage(message) { - console.log(message) - if (message.op === 'publish') { debug('publish op') this.emit(message.topic, message.msg); diff --git a/src/party/idocument.js b/src/party/idocument.js index 0c90cbf..de60e12 100644 --- a/src/party/idocument.js +++ b/src/party/idocument.js @@ -239,6 +239,10 @@ class IDocument extends EventEmitter { .id(this.id) .exec() .then(docs => { + if(docs.length==0){ + return + } + this._data = docs[0].data debug('pull found', docs) @@ -268,8 +272,7 @@ class IDocument extends EventEmitter { if (this.watchSub){ return } - const socket = await this.party.socket() - const ros = socket.ros + const ros = this.party.comms.ros const watchPath = '/dataparty/document/' + this.type + '/' + this.id debug('watch document', watchPath) @@ -355,7 +358,7 @@ class IDocument extends EventEmitter { case 'update': case 'create': - if(this.followcache){ + if(this.followcache && event.event !== 'remove'){ this._data = newMsg /** diff --git a/src/party/loki-cache.js b/src/party/loki-cache.js index 9a5810c..4f47d8a 100644 --- a/src/party/loki-cache.js +++ b/src/party/loki-cache.js @@ -32,7 +32,6 @@ module.exports = class LokiCache extends EventEmitter { } remove(type, id){ - console('cache remove') debug('remove', type, id) var collection = this.db.getCollection(type) diff --git a/src/topics/host-topic.js b/src/topics/host-topic.js index 5ea2615..588758f 100644 --- a/src/topics/host-topic.js +++ b/src/topics/host-topic.js @@ -1,7 +1,7 @@ 'use strict' const Path = require('path') -const debug = require('debug')('dataparty.topics.peer-node') +const debug = require('debug')('dataparty.topics.host-topic') class HostTopic { constructor(path, type){ diff --git a/src/topics/local-topic-host.js b/src/topics/local-topic-host.js index b708275..48aa80a 100644 --- a/src/topics/local-topic-host.js +++ b/src/topics/local-topic-host.js @@ -77,16 +77,20 @@ class LocalTopicHost { if(topic.path.indexOf('/dataparty/document/') != -1 && !exists){ const [arg0, arg1, docType, docId] = topic.path.substr(1).split('/') + debug('is document watcher', docType+':'+docId) - peer.hostParty.db.on(docType+':'+docId, async (event)=>{ + peer.party.hostParty.db.on(docType+':'+docId, async (event)=>{ await this.handleDocChange(topic.path, event) }) } } async handleDocChange(path, event){ + debug('handleDocChange', path) const topic = this.getTopic(path,false) + debug('\ttopic',topic) + if(!topic){return} const [arg0, arg1, docType, docId] = topic.path.substr(1).split('/') @@ -96,7 +100,7 @@ class LocalTopicHost { id: event.msg.id, type: event.msg.type, revision: event.msg.revision, - operationType: event.change + operationType: event.event }) } } diff --git a/src/topics/peer-node.js b/src/topics/peer-node.js index ae56df4..f7bf418 100644 --- a/src/topics/peer-node.js +++ b/src/topics/peer-node.js @@ -29,7 +29,7 @@ class PeerNode { msg: data })*/ - await this.peer.socket.send(JSON.stringify({ + await this.peer.send(JSON.stringify({ op: 'publish', id: 'publish:'+this.peer.opId, topic: topic.path, From c340e34e54ebc8c818059b6ed3f6869b585c87ef Mon Sep 17 00:00:00 2001 From: Alan Meekins Date: Sun, 4 Feb 2024 01:10:10 +0000 Subject: [PATCH 09/14] close #41 --- src/comms/isocket-comms.js | 8 +++++++- src/comms/peer-comms.js | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/comms/isocket-comms.js b/src/comms/isocket-comms.js index 2106097..903c599 100644 --- a/src/comms/isocket-comms.js +++ b/src/comms/isocket-comms.js @@ -7,16 +7,22 @@ const {Message, Routines} = require('@dataparty/crypto') const AuthOp = require('./op/auth-op') const RosShim = require('./ros-shim') +const IParty = require('../party/iparty') /** * @interface module:Comms.ISocketComms * @link module:Comms * @extends EventEmitter + * + * @param {string} session + * @param {module:Party.IParty} party + * @param {module:Dataparty_Crypto.IIdentityProps} remoteIdentity + * @param {boolean} discoverRemoteIdentity Set to true if ANY remote identity can connect. When set to `true` the remoteIdentity will be populated from the client. */ class ISocketComms extends EventEmitter { - constructor({session, uri, party, remoteIdentity, discoverRemoteIdentity}){ + constructor({session, party, remoteIdentity, discoverRemoteIdentity}){ super() this.uri = uri this.session = session diff --git a/src/comms/peer-comms.js b/src/comms/peer-comms.js index 823a863..19b1be8 100644 --- a/src/comms/peer-comms.js +++ b/src/comms/peer-comms.js @@ -42,6 +42,9 @@ function truncateString(str, num) { * @extends {module:Comms.ISocketComms} * @link module:Comms * + * + * @param {boolean} host Set to `true` to make this peer act as the protocol host + * @param {Object} socket Already connected peer socket */ class PeerComms extends ISocketComms { constructor({remoteIdentity, discoverRemoteIdentity, host, party, socket, ...options}){ From 7075530982687433ba944e6d458dcfc7041e5171 Mon Sep 17 00:00:00 2001 From: Alan Meekins Date: Sun, 4 Feb 2024 14:37:08 +0000 Subject: [PATCH 10/14] closes #87 --- examples/test-unix-socket-peer.js | 162 ++++++++++++++++++++++++++++++ package.json | 2 +- src/comms/isocket-comms.js | 2 +- src/comms/websocket-shim.js | 2 + src/party/iparty.js | 4 + src/service/service-host.js | 31 ++++-- 6 files changed, 193 insertions(+), 10 deletions(-) create mode 100644 examples/test-unix-socket-peer.js diff --git a/examples/test-unix-socket-peer.js b/examples/test-unix-socket-peer.js new file mode 100644 index 0000000..a5ae5d9 --- /dev/null +++ b/examples/test-unix-socket-peer.js @@ -0,0 +1,162 @@ +const Path = require('path') +const debug = require('debug')('test.server-db') +const Dataparty = require('../src') +const dataparty_crypto = require('@dataparty/crypto') + +class ExampleService extends Dataparty.IService { + constructor(opts){ + super(opts) + + this.addMiddleware(Dataparty.middleware_paths.pre.decrypt) + this.addMiddleware(Dataparty.middleware_paths.pre.validate) + + this.addMiddleware(Dataparty.middleware_paths.post.validate) + this.addMiddleware(Dataparty.middleware_paths.post.encrypt) + + this.addEndpoint(Dataparty.endpoint_paths.echo) + this.addEndpoint(Dataparty.endpoint_paths.secureecho) + this.addEndpoint(Dataparty.endpoint_paths.identity) + this.addEndpoint(Dataparty.endpoint_paths.version) + + this.addSchema(Path.join(__dirname, './party/schema/basic_types.js')) + this.addSchema(Path.join(__dirname, './party/schema/user.js')) + } + +} + +async function main(){ + + const socketFilePath = '/tmp/party.sock' + + + const service = new ExampleService({ name: '@dataparty/example', version: '0.0.1' }) + const build = await service.compile(Path.join(__dirname,'/dataparty'), true) + + const serviceName = build.package.name + const basePath = '/data/dataparty/' + const servicePath = Path.join(basePath, serviceName.replace('/','-')) + + let config = new Dataparty.Config.JsonFileConfig({ basePath: servicePath }) + config.touchDir('/tingo') + + const dbPath = Path.join(servicePath, '/tingo') + + let party = new Dataparty.TingoParty({ + config, + path: dbPath, + model: build + }) + + const live = new Dataparty.IService(build.package, build) + + + const runner = new Dataparty.ServiceRunnerNode({ + party, + service: live, + sendFullErrors: false, + useNative: false + }) + + const runnerRouter = new Dataparty.RunnerRouter(runner) + + + const host = new Dataparty.ServiceHost({ + runner: runnerRouter, + trust_proxy: true, + wsEnabled: true, + listenUri: 'file://'+socketFilePath, + wsUpgradePath: '/' + }) + + debug(runner.party.identity) + await party.start() + await runnerRouter.start() + await host.start() + + console.log('started') + + + const remoteIdentity = party.identity + + debug('remoteIdentity', remoteIdentity) + + let clientParty = new Dataparty.PeerParty({ + comms: new Dataparty.Comms.WebsocketComms({ + uri: 'ws+unix://'+socketFilePath, + remoteIdentity, + session: 'foobar' + }), + model: build, + config: new Dataparty.Config.MemoryConfig() + }) + + async function exitHandler(){ + + //! We must explictly stop server to clean up socket file + + await clientParty.stop() + + await host.stop() + process.exit() + } + + process.on('exit', exitHandler) + process.on('SIGINT', exitHandler) + + + + await clientParty.start() + + debug('client waiting for auth') + await clientParty.comms.authorized() + debug('client authorized') + + const remoteVersion = await clientParty.comms.call('version') + const remoteId = await clientParty.comms.call('identity') + + debug('version', remoteVersion) + debug('identity', remoteId) + + let user = (await clientParty.find() + .type('user') + .where('name').equals('tester') + .exec())[0] + + + if(!user){ + debug('client creating document') + user = await clientParty.createDocument('user', {name: 'tester', created: (new Date()).toISOString() }) + } + else{ + debug('client loaded document') + } + + console.log(user.data) + + user.on('change', (obj)=>{ console.log('client remote event [document.on(change)]', obj.operationType ) }) + user.on('update', (obj)=>{ console.log('client event [document.on(update)]')}) + user.on('value', (doc)=>{ console.log('client event [document.on(value)]') }) + user.on('remove', (obj)=>{ console.log('client event [document.on(remove)]') }) + + await user.watch() + + let localUser = (await party.find() + .type('user') + .where('name').equals('tester') + .exec())[0] + + console.log('\nserver changing document field') + localUser.data.name = 'renamed-tester' + await localUser.save() + + console.log(localUser.data) + console.log('hash',localUser.hash) + + await localUser.remove() +} + + + +main().catch(err=>{ + console.error(err) +}) diff --git a/package.json b/package.json index 3ce2b14..49d323d 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "dom-storage": "^2.1.0", "eventemitter3": "^4.0.7", "express": "^4.17.1", - "express-list-routes": "^0.1.4", + "express-list-routes": "^1.1.9", "git-repo-info": "^2.1.1", "joi": "^17.9.1", "joi-objectid": "^4.0.2", diff --git a/src/comms/isocket-comms.js b/src/comms/isocket-comms.js index 903c599..111eaa5 100644 --- a/src/comms/isocket-comms.js +++ b/src/comms/isocket-comms.js @@ -22,7 +22,7 @@ const IParty = require('../party/iparty') */ class ISocketComms extends EventEmitter { - constructor({session, party, remoteIdentity, discoverRemoteIdentity}){ + constructor({session, uri, party, remoteIdentity, discoverRemoteIdentity}){ super() this.uri = uri this.session = session diff --git a/src/comms/websocket-shim.js b/src/comms/websocket-shim.js index d84040d..363073a 100644 --- a/src/comms/websocket-shim.js +++ b/src/comms/websocket-shim.js @@ -2,6 +2,8 @@ const debug = require('debug')('dataparty.comms.websocket-shim') const EventEmitter = require('eventemitter3') +const WebSocket = global.WebSocket ? global.WebSocket : require('ws') + class WebsocketShim extends EventEmitter { constructor(conn){ super() diff --git a/src/party/iparty.js b/src/party/iparty.js index 0894eaa..b3245da 100644 --- a/src/party/iparty.js +++ b/src/party/iparty.js @@ -70,6 +70,10 @@ class IParty { debug('\tDocument Classes', this.factory.getTypes()) } + async stop(){ + this.comms.close() + } + /** * @async * @method module:Party.IParty.createDocument diff --git a/src/service/service-host.js b/src/service/service-host.js index 8f8c7c5..bf252de 100644 --- a/src/service/service-host.js +++ b/src/service/service-host.js @@ -12,8 +12,10 @@ const reach = require('../utils/reach') const ServiceHostWebsocket = require('./service-host-websocket') -const Pify = async (p)=>{ - return await p +const Pify = (p)=>{ + return new Promise((resolve,reject)=>{ + p(resolve) + }) } class ServiceHost { @@ -140,24 +142,31 @@ class ServiceHost { //Setup router this.apiApp.use(this.runner.onRequest.bind(this.runner)) - if(debug.enabled){ expressListRoutes('API:', this.router ) } + if(debug.enabled){ expressListRoutes(this.router ) } } + let backlog = 511 let listenPort = this.apiServerUri.port let listenHost = this.apiServerUri.hostname if(this.apiServerUri.protocol == 'http:'){ + debug('http server') + //! Handle http this.apiServer = http.createServer(this.apiApp) } else if(this.apiServerUri.protocol == 'https:'){ + debug('http server') + //! Handle https this.apiServer = https.createServer(this.apiApp) } else if(this.apiServerUri.protocol == 'file:'){ + debug('unix socket server') + //! Handle unix socket listenHost = null listenPort = this.apiServerUri.pathname @@ -167,7 +176,10 @@ class ServiceHost { await new Promise((resolve,reject)=>{ - this.apiServer.listen(listenPort, listenHost, resolve) + + debug('listening', this.apiServerUri.toString()) + + this.apiServer.listen(listenPort, listenHost==null ? backlog : listenHost, resolve) }) clearTimeout(this.errorHandlerTimer) @@ -217,16 +229,19 @@ class ServiceHost { * @async */ async stop(){ - debug('stopping server') - + if(!this.apiServer || !this.apiServer.listening){ return } - + + debug('stopping server') + clearTimeout(this.errorHandlerTimer) this.errorHandlerTimer = null - await (Pify(this.apiServer.close)()) + await new Promise((resolve,reject)=>{ + this.apiServer.close(resolve) + }) debug('stopped server') } From ec7b5e6bd3f3f98c4f77897e7487c045605e33c6 Mon Sep 17 00:00:00 2001 From: Alan Meekins Date: Sun, 4 Feb 2024 14:53:31 +0000 Subject: [PATCH 11/14] comments --- examples/test-unix-socket-peer.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/test-unix-socket-peer.js b/examples/test-unix-socket-peer.js index a5ae5d9..b50fab6 100644 --- a/examples/test-unix-socket-peer.js +++ b/examples/test-unix-socket-peer.js @@ -138,13 +138,16 @@ async function main(){ user.on('value', (doc)=>{ console.log('client event [document.on(value)]') }) user.on('remove', (obj)=>{ console.log('client event [document.on(remove)]') }) + //! watch remote changes await user.watch() + //! The server finds the document let localUser = (await party.find() .type('user') .where('name').equals('tester') .exec())[0] + //! The server changes the document console.log('\nserver changing document field') localUser.data.name = 'renamed-tester' await localUser.save() @@ -152,6 +155,7 @@ async function main(){ console.log(localUser.data) console.log('hash',localUser.hash) + //! The server deletes the document await localUser.remove() } From cde034b4f017fa44f7cc950d27c865c03e990c1c Mon Sep 17 00:00:00 2001 From: Alan Meekins Date: Sun, 4 Feb 2024 18:33:03 +0000 Subject: [PATCH 12/14] closes #83 --- package.json | 1 + src/service/service-host.js | 56 +++++++++++++++++++++++++++++++------ 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 49d323d..efd5fe6 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ "last-eventemitter": "^1.1.1", "lodash": "^4.17.21", "lokijs": "1.5.6", + "mdns": "^2.7.2", "mkdirp": "^0.5.1", "moment": "^2.29.4", "morgan": "^1.10.0", diff --git a/src/service/service-host.js b/src/service/service-host.js index bf252de..9cd2dbf 100644 --- a/src/service/service-host.js +++ b/src/service/service-host.js @@ -1,5 +1,6 @@ const CORS = require('cors') const {URL} = require('url') +const mdns = require('mdns') const http = require('http') const https = require('https') const morgan = require('morgan') @@ -7,6 +8,7 @@ const express = require('express') const bodyParser = require('body-parser') const expressListRoutes = require('express-list-routes') const debug = require('debug')('dataparty.service.host') +const objectHasher = require('node-object-hash').hasher() const reach = require('../utils/reach') @@ -24,17 +26,18 @@ class ServiceHost { * @class module:Service.ServiceHost * @link module:Service * @param {Object} options.cors Cors to be passed to express via the `cors` package - * @param {boolean} options.trust_proxy When true, the server will parse forwarding headers. This should be set when running behind a load-balancer for accurate error messages and logging - * @param {string} options.listenUri The uri of the host interface to tell express to listen on. Defaults to `http://0.0.0.0:4001 - * @param {boolean} options.i2pEnabled When true, this server will be available over i2p - * @param {string} options.i2pSamHost The hostname of the i2p SAM control API. Defaults to `127.0.0.1` - * @param {Integer} options.i2pSamPort The port of the i2p SAM control API. Defaults to `7656` - * @param {string} options.i2pForwardHost Override i2p forward host. This defaults to `localhost` and typically doesn't need to be changed + * @param {boolean} [options.trust_proxy=false] When true, the server will parse forwarding headers. This should be set when running behind a load-balancer for accurate error messages and logging + * @param {string} [options.listenUri=http://0.0.0.0:4000] The uri of the host interface to tell express to listen on. Defaults to `http://0.0.0.0:4001 + * @param {boolean} [options.i2pEnabled=false] When true, this server will be available over i2p + * @param {string} [options.i2pSamHost=127.0.0.1] The hostname of the i2p SAM control API. Defaults to `127.0.0.1` + * @param {Integer} [options.i2pSamPort=7656] The port of the i2p SAM control API. Defaults to `7656` + * @param {string} [options.i2pForwardHost=localhost] Override i2p forward host. This defaults to `localhost` and typically doesn't need to be changed * @param {Integer} options.i2pForwardPort Override i2p forward post. This defaults to the port supplied in `options.listenUri`. * @param {string} options.i2pKey When set this i2p key will be used to host the service. If not set a new i2p key will be generated. Defaults to `null` - * @param {boolean} options.wsEnabled When true the server will host a dataparty websocket service. Defaults to `true` + * @param {boolean} [options.wsEnabled=true] When true the server will host a dataparty websocket service. Defaults to `true` * @param {Integer} options.wsPort Port for the websocket service to listen on. Defaults to `null`, using the same port as the http server. - * @param {string} options.wsUpgradePath The path within the http server to host an upgradeable websocket. Defaults to `/ws` + * @param {string} [options.wsUpgradePath=/ws] The path within the http server to host an upgradeable websocket. Defaults to `/ws` + * @param {boolean} [options.mdnsEnabled=true] When true, the server will publish mDNS records advertising the service and party identity * @param {module:Service.ServiceRunner} options.runner A pre-configured runner */ @@ -51,6 +54,7 @@ class ServiceHost { wsEnabled = true, wsPort = null, wsUpgradePath = '/ws', + mdnsEnabled = true, runner }={}){ @@ -121,6 +125,8 @@ class ServiceHost { } } + this.mdnsEnabled = mdnsEnabled + this.started = false } @@ -221,6 +227,40 @@ class ServiceHost { debug('\t', 'address', this.i2pUri) debug('\t', 'key', this.i2p.getPublicKey()) } + + if(this.mdnsEnabled && this.apiServer && this.apiServerUri.protocol != 'file:'){ + + let servicePkg = null + let partyIdentity = null + const routerClass = this.runner.constructor.name + + switch(routerClass){ + case 'ServiceRunner': + case 'ServiceRunnerNode': + partyIdentity = this.runner.party.identity + servicePkg = this.runner.service.compiled.package + break + case 'RunnerRouter': + partyIdentity = this.runner.defaultRunner.party.identity + servicePkg = this.runner.defaultRunner.service.compiled.package + break + } + + + const idHash = objectHasher.hash( + partyIdentity.toJSON() + ) + + + const txt_record = { + partyhash: idHash, + pkgname: servicePkg.name + } + + console.log('mdns', servicePkg.name, idHash) + this.mdnsAd = mdns.createAdvertisement(mdns.tcp('party'), parseInt(listenPort), {txtRecord: txt_record}) + } + } /** From 77ca950214e07ed3b7defc51ae6b181da389124e Mon Sep 17 00:00:00 2001 From: Alan Meekins Date: Sun, 4 Feb 2024 18:41:26 +0000 Subject: [PATCH 13/14] tweak venue host --- src/venue/schema/venue_service.js | 13 ++++--------- src/venue/venue-host.js | 2 +- src/venue/venue-service.js | 2 +- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/venue/schema/venue_service.js b/src/venue/schema/venue_service.js index 4855b44..6e732b2 100644 --- a/src/venue/schema/venue_service.js +++ b/src/venue/schema/venue_service.js @@ -1,19 +1,14 @@ 'use strict' -const Hoek = require('hoek') -//const BouncerDb = require('@dataparty/bouncer-db') -/* -require('mongoose-schema-jsonschema')(BouncerDb.mongoose()) -BouncerDb.mongoose().plugin(require("mongoose-ajv-plugin")) -*/ const debug = require('debug')('venue.venue_srv') -const Dataparty = require('../../service') -const Utils = Dataparty.ISchema.Utils +const ISchema = require('../../index').Bouncer.ISchema +const Utils = ISchema.Utils -class VenueSrv extends Dataparty.ISchema { + +class VenueSrv extends ISchema { static get Type () { return 'venue_srv' } diff --git a/src/venue/venue-host.js b/src/venue/venue-host.js index 737c906..10a85ca 100644 --- a/src/venue/venue-host.js +++ b/src/venue/venue-host.js @@ -34,7 +34,7 @@ async function main(){ Model: BouncerServerModels.Model, Types: { ...BouncerServerModels.Types, - BanList: require('./schema/ban_list'), + //BanList: require('./schema/ban_list'), VenueSrv: require('./schema/venue_service') } } diff --git a/src/venue/venue-service.js b/src/venue/venue-service.js index ca05155..dc1840e 100644 --- a/src/venue/venue-service.js +++ b/src/venue/venue-service.js @@ -7,7 +7,7 @@ class VenueService extends DatapartySrv.IService { constructor(opts){ super(opts) - this.addSchema(Path.join(__dirname, './schema/ban_list.js')) + //this.addSchema(Path.join(__dirname, './schema/ban_list.js')) this.addSchema(Path.join(__dirname, './schema/venue_service.js')) this.addMiddleware(DatapartySrv.middleware_paths.pre.decrypt) From 750dab22171ea50bf40930cfe01d95f69c22999a Mon Sep 17 00:00:00 2001 From: Alan Meekins Date: Sun, 4 Feb 2024 18:43:58 +0000 Subject: [PATCH 14/14] update docs --- docs/CloudDocument.html | 2 +- docs/LokiQuery.html | 2 +- docs/MongoQuery.html | 2 +- docs/bouncer_db_loki-db.js.html | 39 ++++++-- docs/bouncer_db_tingo-db.js.html | 29 ++++-- docs/bouncer_db_zango-db.js.html | 18 +++- docs/bouncer_icrufler.js.html | 4 +- docs/bouncer_idb.js.html | 5 +- docs/bouncer_index.js.html | 4 +- docs/bouncer_ischema.js.html | 4 +- docs/bouncer_mongo-query.js.html | 4 +- docs/comms_ble-socket.js.html | 4 +- docs/comms_i2p-socket-comms.js.html | 4 +- docs/comms_index.js.html | 4 +- docs/comms_isocket-comms.js.html | 18 +++- docs/comms_loopback-channel.js.html | 6 +- docs/comms_loopback-comms.js.html | 4 +- docs/comms_loopback-socket.js.html | 4 +- docs/comms_peer-comms.js.html | 7 +- docs/comms_rest-comms.js.html | 4 +- docs/comms_rtc-socket-comms.js.html | 4 +- docs/comms_websocket-comms.js.html | 4 +- docs/config_iconfig.js.html | 4 +- docs/config_index.js.html | 4 +- docs/config_json-file.js.html | 4 +- docs/config_local-storage.js.html | 4 +- docs/config_memory.js.html | 4 +- docs/config_nconf.js.html | 4 +- docs/config_secure-config.js.html | 8 +- docs/data/search.json | 2 +- docs/global.html | 2 +- docs/index.html | 4 +- docs/module-Comms.BLEPeerClient.html | 2 +- docs/module-Comms.I2pSocketComms.html | 2 +- docs/module-Comms.ISocketComms.html | 2 +- docs/module-Comms.LoopbackChannel.html | 2 +- docs/module-Comms.LoopbackComms.html | 2 +- docs/module-Comms.LoopbackSocket.html | 2 +- docs/module-Comms.PeerComms.html | 2 +- docs/module-Comms.RTCSocketComms.html | 2 +- docs/module-Comms.RestComms.html | 2 +- docs/module-Comms.WebsocketComms.html | 2 +- docs/module-Comms.html | 2 +- docs/module-Config.IConfig.html | 2 +- docs/module-Config.JsonFileConfig.html | 2 +- docs/module-Config.LocalStorageConfig.html | 2 +- docs/module-Config.MemoryConfig.html | 2 +- docs/module-Config.NconfConfig.html | 2 +- docs/module-Config.SecureConfig.html | 2 +- docs/module-Config.html | 2 +- docs/module-Db.IDb.html | 2 +- docs/module-Db.ISchema.html | 2 +- docs/module-Db.LokiDb.html | 2 +- docs/module-Db.TingoDb.html | 2 +- docs/module-Db.ZangoDb.html | 2 +- docs/module-Db.html | 2 +- docs/module-Party.CloudParty.html | 2 +- docs/module-Party.DocumentFactory.html | 2 +- docs/module-Party.IDocument.html | 2 +- docs/module-Party.IParty.html | 2 +- docs/module-Party.LokiCache.html | 2 +- docs/module-Party.LokiParty.html | 2 +- docs/module-Party.MongoParty.html | 2 +- docs/module-Party.PeerParty.html | 2 +- docs/module-Party.Query.html | 2 +- docs/module-Party.TingoParty.html | 2 +- docs/module-Party.ZangoParty.html | 2 +- docs/module-Party.html | 2 +- docs/module-Service.EndpointContext.html | 2 +- docs/module-Service.IEndpoint.html | 2 +- docs/module-Service.IMiddleware.html | 2 +- docs/module-Service.ISandboxRunner.html | 2 +- docs/module-Service.IService.html | 2 +- docs/module-Service.ITask.html | 2 +- docs/module-Service.RunnerRouter.html | 2 +- docs/module-Service.ServiceHost.html | 2 +- docs/module-Service.ServiceRunner.html | 2 +- docs/module-Service.ServiceRunnerNode.html | 2 +- docs/module-Service.html | 2 +- docs/module-Topics.LocalTopicHost.html | 2 +- docs/module-Topics.html | 2 +- docs/party_cloud_cloud-document.js.html | 4 +- docs/party_cloud_cloud-party.js.html | 4 +- docs/party_document-factory.js.html | 4 +- docs/party_idocument.js.html | 27 +++-- docs/party_index.js.html | 4 +- docs/party_iparty.js.html | 8 +- docs/party_local_loki-party.js.html | 4 +- docs/party_local_loki-query.js.html | 4 +- docs/party_local_tingo-party.js.html | 4 +- docs/party_local_zango-party.js.html | 4 +- docs/party_loki-cache.js.html | 12 ++- docs/party_mongo_mongo-party.js.html | 4 +- docs/party_peer_peer-party.js.html | 4 +- docs/party_query.js.html | 4 +- docs/scripts/core.js | 111 +++++++++++++++------ docs/scripts/core.min.js | 4 +- docs/service_endpoint-context.js.html | 4 +- docs/service_iendpoint.js.html | 4 +- docs/service_imiddleware.js.html | 4 +- docs/service_index.js.html | 4 +- docs/service_isandbox-runner.js.html | 4 +- docs/service_ischema.js.html | 4 +- docs/service_iservice.js.html | 14 ++- docs/service_itask.js.html | 4 +- docs/service_runner-router.js.html | 4 +- docs/service_service-host.js.html | 91 +++++++++++++---- docs/service_service-runner-node.js.html | 68 +++++++++++-- docs/service_service-runner.js.html | 8 +- docs/topics_index.js.html | 4 +- docs/topics_local-topic-host.js.html | 12 ++- docs/tutorial-implementing-services.html | 4 +- docs/tutorial-local-party.html | 4 +- docs/tutorial-peer-to-peer.html | 4 +- docs/tutorial-service-task.html | 4 +- 115 files changed, 508 insertions(+), 257 deletions(-) diff --git a/docs/CloudDocument.html b/docs/CloudDocument.html index 52b6a3c..b15950c 100644 --- a/docs/CloudDocument.html +++ b/docs/CloudDocument.html @@ -1,3 +1,3 @@ Interface: CloudDocument
On this page

CloudDocument

Represents a cloud document with cloud change notifications, multi-tenant ownership and ganular access controls

Members

owner :IdObj

CloudDocument owner as an IdObj

Type:

Methods

(async) acl() → {Acl}

Get this document's Acl

Returns:
Type: 
Acl

(async) grantAccess(action, actor, field, allowed)

Allow access to this document or a subfield

Parameters:
NameTypeDefaultDescription
actionstring

CRUFL operation

actorIdObj

Actor object

fieldstring

Document subfield

allowedstringtrue

Allow/deny named actor access

\ No newline at end of file +
On this page

CloudDocument

Represents a cloud document with cloud change notifications, multi-tenant ownership and ganular access controls

Members

owner :IdObj

CloudDocument owner as an IdObj

Type:

Methods

(async) acl() → {Acl}

Get this document's Acl

Returns:
Type: 
Acl

(async) grantAccess(action, actor, field, allowed)

Allow access to this document or a subfield

Parameters:
NameTypeDefaultDescription
actionstring

CRUFL operation

actorIdObj

Actor object

fieldstring

Document subfield

allowedstringtrue

Allow/deny named actor access

\ No newline at end of file diff --git a/docs/LokiQuery.html b/docs/LokiQuery.html index cf63915..e64d226 100644 --- a/docs/LokiQuery.html +++ b/docs/LokiQuery.html @@ -1,3 +1,3 @@ Class: LokiQuery
On this page

LokiQuery

new LokiQuery(spec)

generates a mongodb query doc from a dataparty query spec

Parameters:
NameTypeDescription
spec

dataparty query spec (wire format for data party queries)

Methods

getQueryDoc()

build mongo query doc from spec match tree

  • explicitly 'and' top level of match tree
  • search only returns msg metadata
\ No newline at end of file +
On this page

LokiQuery

new LokiQuery(spec)

generates a mongodb query doc from a dataparty query spec

Parameters:
NameTypeDescription
spec

dataparty query spec (wire format for data party queries)

Methods

getQueryDoc()

build mongo query doc from spec match tree

  • explicitly 'and' top level of match tree
  • search only returns msg metadata
\ No newline at end of file diff --git a/docs/MongoQuery.html b/docs/MongoQuery.html index ce73592..e86b791 100644 --- a/docs/MongoQuery.html +++ b/docs/MongoQuery.html @@ -1,3 +1,3 @@ Class: MongoQuery
On this page

MongoQuery

new MongoQuery(spec)

generates a mongodb query doc from a dataparty query spec

Parameters:
NameTypeDescription
spec

dataparty query spec (wire format for data party queries)

Methods

getQueryDoc()

build mongo query doc from spec match tree

  • explicitly 'and' top level of match tree
  • search only returns msg metadata
\ No newline at end of file +
On this page

MongoQuery

new MongoQuery(spec)

generates a mongodb query doc from a dataparty query spec

Parameters:
NameTypeDescription
spec

dataparty query spec (wire format for data party queries)

Methods

getQueryDoc()

build mongo query doc from spec match tree

  • explicitly 'and' top level of match tree
  • search only returns msg metadata
\ No newline at end of file diff --git a/docs/bouncer_db_loki-db.js.html b/docs/bouncer_db_loki-db.js.html index 3f00c22..48fb19d 100644 --- a/docs/bouncer_db_loki-db.js.html +++ b/docs/bouncer_db_loki-db.js.html @@ -1,6 +1,6 @@ Source: bouncer/db/loki-db.js
On this page

bouncer_db_loki-db.js

'use strict'
+    
On this page

bouncer_db_loki-db.js

'use strict'
 
 const IDb = require('../idb')
 const Hoek = require('@hapi/hoek')
@@ -8,6 +8,7 @@
 const LokiFS = Loki.LokiFsAdapter
 const LFSA = require('lokijs/src/loki-fs-structured-adapter')
 const ObjectId = require('bson-objectid')
+const uuidv4 = require('uuid/v4')
 
 const MongoQuery = require('../mongo-query')
 const { promisfy } = require('promisfy')
@@ -28,7 +29,7 @@
  */
 module.exports = class LokiDb extends IDb {
 
-  constructor ({path, factory, dbAdapter, lokiOptions}) {
+  constructor ({path, factory, dbAdapter, lokiOptions, useUuid}) {
     super(factory)
     debug('constructor')
     this.loki = null
@@ -36,6 +37,7 @@
     this.path = path
     this.dbAdapter = dbAdapter || new LFSA()
     this.error = null
+    this.useUuid = (useUuid==undefined) ? true : useUuid
   }
 
   static get LokiLocalStorageAdapter(){
@@ -144,7 +146,13 @@
   ensureId(obj){
     let temp = {...obj}
     if(!reach(temp,'$meta.id')){
-      temp.$meta.id = (new ObjectId()).toHexString()
+
+      if(this.useUuid){
+        temp.$meta.id = uuidv4()
+      }
+      else{
+        temp.$meta.id = (new ObjectId()).toHexString()
+      }
     }
 
     let dbDoc = this.documentFromObject(temp)
@@ -234,7 +242,19 @@
 
     for(let obj of docs){
       let temp = {...obj}
-      if(temp._id===undefined){ temp._id = (new ObjectId()).toString(); temp.$meta.id=temp._id;  }
+      if(temp._id===undefined){
+
+        if(this.useUuid){
+          temp._id = uuidv4()
+        }
+        else{
+          temp._id = (new ObjectId()).toHexString()
+        }
+
+        temp.$meta.id=temp._id;
+      }
+
+      
 
       let dbDoc = this.documentFromObject(temp)
 
@@ -313,15 +333,16 @@
 
     const dbDoc = collection.findAndRemove( { '$meta.id': obj.$meta.id } )
 
-    debug('dbDoc', dbDoc)
-
-    let finalObj = this.documentToObject(dbDoc)
+    let finalObj = {
+      $meta: obj.$meta
+    }
 
     finalObj.$meta.removed = true
 
     this.emitChange(finalObj, 'remove')
 
-    debug('obj', finalObj)
+    debug('finalObj', finalObj)
+    debug('obj', obj)
 
     await promisfy(this.loki.saveDatabase.bind(this.loki))
     return finalObj
@@ -418,4 +439,4 @@
   }
   */
 }
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/bouncer_db_tingo-db.js.html b/docs/bouncer_db_tingo-db.js.html index 9d29df2..2759691 100644 --- a/docs/bouncer_db_tingo-db.js.html +++ b/docs/bouncer_db_tingo-db.js.html @@ -1,14 +1,14 @@ Source: bouncer/db/tingo-db.js
On this page

bouncer_db_tingo-db.js

'use strict'
+    
On this page

bouncer_db_tingo-db.js

'use strict'
 
 
 const IDb = require('../idb')
 const Hoek = require('@hapi/hoek')
+const uuidv4 = require('uuid/v4')
 
 const {promisfy} = require('promisfy')
 
-
 const debug = require('debug')('bouncer.db.tingo-db')
 
 
@@ -22,13 +22,14 @@
  */
 module.exports = class TingoDb extends IDb {
 
-  constructor ({path, factory, tingoOptions, prefix}) {
+  constructor ({path, factory, tingoOptions, prefix, useUuid}) {
     super(factory, prefix)
     debug('constructor path=',path, tingoOptions)
     this.tingo = null
     this.path = path
     this.tingoOptions = tingoOptions || {nativeObjectID: true}
     this.error = null
+    this.useUuid = (useUuid==undefined) ? true : useUuid
   }
 
 
@@ -94,7 +95,13 @@
   ensureId(obj){
     let temp = {...obj}
     if(!reach(temp,'$meta.id')){
-      temp.$meta.id = new this.tingo.ObjectID().valueOf()
+      
+      if(this.useUuid){
+        temp.$meta.id = uuidv4()
+      }
+      else{
+        temp.$meta.id = new this.tingo.ObjectID().valueOf()
+      }
     }
 
     let dbDoc = this.documentFromObject(temp)
@@ -198,7 +205,17 @@
 
     for(let obj of docs){
       let temp = {...obj}
-      if(temp._id===undefined){ temp._id = (new this.tingo.ObjectID()).toString(); temp.$meta.id=temp._id;  }
+      if(temp._id===undefined){
+        
+        if(this.useUuid){
+          temp._id = uuidv4()
+        }
+        else{
+          temp._id = (new this.tingo.ObjectID()).toString();
+        }
+      
+        temp.$meta.id=temp._id;
+      }
 
       let dbDoc = this.documentFromObject(temp)
 
@@ -304,4 +321,4 @@
     return finalObj
   }
 }
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/bouncer_db_zango-db.js.html b/docs/bouncer_db_zango-db.js.html index b094f3d..00c63ee 100644 --- a/docs/bouncer_db_zango-db.js.html +++ b/docs/bouncer_db_zango-db.js.html @@ -1,12 +1,13 @@ Source: bouncer/db/zango-db.js
On this page

bouncer_db_zango-db.js

'use strict'
+    
On this page

bouncer_db_zango-db.js

'use strict'
 
 const IDb = require('../idb')
 const Hoek = require('@hapi/hoek')
 const zango = require('zangodb')
 const reach = require('../../utils/reach')
 const ObjectId = require('bson-objectid')
+const uuidv4 = require('uuid/v4')
 
 const MongoQuery = require('../mongo-query')
 const { promisfy } = require('promisfy')
@@ -22,12 +23,13 @@
 */
 module.exports = class ZangoDb extends IDb {
 
-  constructor ({dbname, factory}) {
+  constructor ({dbname, factory, useUuid}) {
     super(factory)
     debug('constructor')
     this.zango = null
     this.dbname = dbname
     this.error = null
+    this.useUuid = (useUuid==undefined) ? true : useUuid
   }
 
 
@@ -41,7 +43,7 @@
     for(const name of this.factory.getValidators()){
       debug('creating collection', name)
 
-      const indexSettings = reach(this.factory, 'model.IndexSettings.'+name)
+      const indexSettings = reach(this.factory, 'schemas.IndexSettings.'+name)
 
       const indices = ['$meta.id'].concat(indexSettings.unique).concat(indexSettings.indices)
 
@@ -107,7 +109,13 @@
   ensureId(obj){
     let temp = {...obj}
     if(!reach(temp,'$meta.id')){
-      temp.$meta.id = (new ObjectId()).toHexString()
+
+      if(this.useUuid){
+        temp.$meta.id = uuidv4()
+      }
+      else{
+        temp.$meta.id = (new ObjectId()).toHexString()
+      }
     }
 
     let dbDoc = this.documentFromObject(temp)
@@ -239,4 +247,4 @@
     return finalObj
   }
 }
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/bouncer_icrufler.js.html b/docs/bouncer_icrufler.js.html index 7902fbb..75b7d27 100644 --- a/docs/bouncer_icrufler.js.html +++ b/docs/bouncer_icrufler.js.html @@ -1,6 +1,6 @@ Source: bouncer/icrufler.js
On this page

bouncer_icrufler.js


+    
On this page

bouncer_icrufler.js


 module.exports = class ICrufler {
   constructor({db, context}){
     this.db = db
@@ -20,4 +20,4 @@
   async applyRemove(crufl){ throw new Error('not implemented') }
   async applyUpdate(crufl){ throw new Error('not implemented') }
   async applyFind(crufl, includeData = false){ throw new Error('not implemented') }
-}
\ No newline at end of file +}
\ No newline at end of file diff --git a/docs/bouncer_idb.js.html b/docs/bouncer_idb.js.html index c5e099b..1436403 100644 --- a/docs/bouncer_idb.js.html +++ b/docs/bouncer_idb.js.html @@ -1,6 +1,6 @@ Source: bouncer/idb.js
On this page

bouncer_idb.js


+    
On this page

bouncer_idb.js


 const reach = require('../utils/reach')
 const debug = require('debug')('bouncer.idb')
 const EventEmitter = require('eventemitter3')
@@ -62,6 +62,7 @@
 
   emitChange(msg, change){
     const { type, id, revision } = msg.$meta
+    debug('emitChange', `${type}:${id}`)
     this.emit(
       `${type}:${id}`,
       {
@@ -102,4 +103,4 @@
 
 }
 
-module.exports = IDb
\ No newline at end of file +module.exports = IDb
\ No newline at end of file diff --git a/docs/bouncer_index.js.html b/docs/bouncer_index.js.html index 096b8ac..b49488b 100644 --- a/docs/bouncer_index.js.html +++ b/docs/bouncer_index.js.html @@ -1,6 +1,6 @@ Source: bouncer/index.js
On this page

bouncer_index.js

/**
+    
On this page

bouncer_index.js

/**
  * @module Db
  */
 
@@ -13,4 +13,4 @@
 exports.ZangoDb= require('./db/zango-db')
 
 
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/bouncer_ischema.js.html b/docs/bouncer_ischema.js.html index b6208e3..77998c8 100644 --- a/docs/bouncer_ischema.js.html +++ b/docs/bouncer_ischema.js.html @@ -1,6 +1,6 @@ Source: bouncer/ischema.js
On this page

bouncer_ischema.js

const debug = require('debug')('bouncer.ISchema')
+    
On this page

bouncer_ischema.js

const debug = require('debug')('bouncer.ISchema')
 const MgoUtils = require('../utils/mongoose-scheme-utils')
 
 module.exports = class ISchema {
@@ -105,4 +105,4 @@
     }
   }
 }
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/bouncer_mongo-query.js.html b/docs/bouncer_mongo-query.js.html index 55f8c2d..d7e9bf1 100644 --- a/docs/bouncer_mongo-query.js.html +++ b/docs/bouncer_mongo-query.js.html @@ -1,6 +1,6 @@ Source: bouncer/mongo-query.js
On this page

bouncer_mongo-query.js

'use strict'
+    
On this page

bouncer_mongo-query.js

'use strict'
 
 const ObjectId = require('bson-objectid')
 const debug = require('debug')('bouncer.mongo-query')
@@ -194,4 +194,4 @@
   throw new Error(`unrecognized query op: ${node.op}`)
 }
 
-module.exports = MongoQuery
\ No newline at end of file +module.exports = MongoQuery
\ No newline at end of file diff --git a/docs/comms_ble-socket.js.html b/docs/comms_ble-socket.js.html index 8c1ff22..bd9e63f 100644 --- a/docs/comms_ble-socket.js.html +++ b/docs/comms_ble-socket.js.html @@ -1,6 +1,6 @@ Source: comms/ble-socket.js
On this page

comms_ble-socket.js

'use strict'
+    
On this page

comms_ble-socket.js

'use strict'
 
 const debug = require('debug')('dataparty.comms.ble-peer')
 const EventEmitter = require('eventemitter3')
@@ -261,4 +261,4 @@
 }
 
 module.exports = BLEPeerClient
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/comms_i2p-socket-comms.js.html b/docs/comms_i2p-socket-comms.js.html index 251abf8..48f6c23 100644 --- a/docs/comms_i2p-socket-comms.js.html +++ b/docs/comms_i2p-socket-comms.js.html @@ -1,6 +1,6 @@ Source: comms/i2p-socket-comms.js
On this page

comms_i2p-socket-comms.js

const debug = require('debug')('dataparty.comms.i2psocket')
+    
On this page

comms_i2p-socket-comms.js

const debug = require('debug')('dataparty.comms.i2psocket')
 const debugShim = require('debug')('dataparty.comms.i2psocket-shim')
 
 const SAM = require('@diva.exchange/i2p-sam')
@@ -127,4 +127,4 @@
 
 
 module.exports = I2pSocketComms
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/comms_index.js.html b/docs/comms_index.js.html index e286d1b..cfe941b 100644 --- a/docs/comms_index.js.html +++ b/docs/comms_index.js.html @@ -1,6 +1,6 @@ Source: comms/index.js
On this page

comms_index.js


+    
On this page

comms_index.js


 /**
  *  @module Comms 
  */
@@ -18,4 +18,4 @@
 exports.RTCSocketComms = require('./rtc-socket-comms')
 exports.I2pSocketComms = require('./i2p-socket-comms')
 exports.SocketOp = require('./isocket-comms')
-exports.WebsocketOp = require('./websocket-op')
\ No newline at end of file +exports.WebsocketOp = require('./websocket-op')
\ No newline at end of file diff --git a/docs/comms_isocket-comms.js.html b/docs/comms_isocket-comms.js.html index 150662c..f5432c8 100644 --- a/docs/comms_isocket-comms.js.html +++ b/docs/comms_isocket-comms.js.html @@ -1,6 +1,6 @@ Source: comms/isocket-comms.js
On this page

comms_isocket-comms.js

'use strict'
+    
On this page

comms_isocket-comms.js

'use strict'
 
 const debug = require('debug')('dataparty.comms.socketcomms')
 const EventEmitter = require('eventemitter3')
@@ -9,12 +9,18 @@
 
 const AuthOp = require('./op/auth-op')
 const RosShim = require('./ros-shim')
+const IParty = require('../party/iparty')
 
 
 /**
  * @interface module:Comms.ISocketComms
  * @link module:Comms
  * @extends EventEmitter
+ * 
+ * @param {string}                  session
+ * @param {module:Party.IParty}     party
+ * @param {module:Dataparty_Crypto.IIdentityProps}  remoteIdentity
+ * @param {boolean}                 discoverRemoteIdentity  Set to true if ANY remote identity can connect. When set to `true` the remoteIdentity will be populated from the client.
  */
 
 class ISocketComms extends EventEmitter {
@@ -128,7 +134,7 @@
             debug(msg.id)
 
             if(msg.op != 'publish'){
-                debug('emit id')
+                debug('emit id', msg.id)
                 comm.emit(msg.id, msg)
             } else {
                 debug('emit message')
@@ -138,7 +144,11 @@
     }
 
     send(input){
-        debug('send - ', input)
+        debug('send - ', typeof input, input)
+
+        if(typeof input != 'object'){
+            input = JSON.parse(input)
+        }
 
         const content = new Message({msg: input})
 
@@ -158,4 +168,4 @@
     }
 }
 
-module.exports = ISocketComms
\ No newline at end of file +module.exports = ISocketComms
\ No newline at end of file diff --git a/docs/comms_loopback-channel.js.html b/docs/comms_loopback-channel.js.html index 3b2f70c..6fbc0aa 100644 --- a/docs/comms_loopback-channel.js.html +++ b/docs/comms_loopback-channel.js.html @@ -1,6 +1,6 @@ Source: comms/loopback-channel.js
On this page

comms_loopback-channel.js

const debug = require('debug')('dataparty.comms.loopback-channel')
+    
On this page

comms_loopback-channel.js

const debug = require('debug')('dataparty.comms.loopback-channel')
 const EventEmitter = require("eventemitter3")
 
 
@@ -19,8 +19,8 @@
     this.port1 = new LoopbackChannelPort(undefined, '1')
 
     //! The second channel peer
-    this.peer2 = new LoopbackChannelPort(this.port1, '2')
+    this.port2 = new LoopbackChannelPort(this.port1, '2')
 
     this.port1.peer = this.port2
   }
-}
\ No newline at end of file +}
\ No newline at end of file diff --git a/docs/comms_loopback-comms.js.html b/docs/comms_loopback-comms.js.html index 7cf11b7..f5ce9cf 100644 --- a/docs/comms_loopback-comms.js.html +++ b/docs/comms_loopback-comms.js.html @@ -1,6 +1,6 @@ Source: comms/loopback-comms.js
On this page

comms_loopback-comms.js

const debug = require('debug')('dataparty.comms.loopback-comms')
+    
On this page

comms_loopback-comms.js

const debug = require('debug')('dataparty.comms.loopback-comms')
 
 const PeerComms = require('./peer-comms')
 const LoopbackSocket = require('./loopback-socket')
@@ -34,4 +34,4 @@
 }
 
 
-module.exports = LoopbackComms
\ No newline at end of file +module.exports = LoopbackComms
\ No newline at end of file diff --git a/docs/comms_loopback-socket.js.html b/docs/comms_loopback-socket.js.html index 33fcce1..a6de8f6 100644 --- a/docs/comms_loopback-socket.js.html +++ b/docs/comms_loopback-socket.js.html @@ -1,6 +1,6 @@ Source: comms/loopback-socket.js
On this page

comms_loopback-socket.js

const debug = require('debug')('dataparty.comms.loopback-socket')
+    
On this page

comms_loopback-socket.js

const debug = require('debug')('dataparty.comms.loopback-socket')
 const EventEmitter = require('eventemitter3')
 
 /**
@@ -96,4 +96,4 @@
       this.channel.post('close', true)
     }
   }
-}
\ No newline at end of file +}
\ No newline at end of file diff --git a/docs/comms_peer-comms.js.html b/docs/comms_peer-comms.js.html index f6e743d..06d496d 100644 --- a/docs/comms_peer-comms.js.html +++ b/docs/comms_peer-comms.js.html @@ -1,6 +1,6 @@ Source: comms/peer-comms.js
On this page

comms_peer-comms.js

const debug = require('debug')('dataparty.comms.peercomms')
+    
On this page

comms_peer-comms.js

const debug = require('debug')('dataparty.comms.peercomms')
 const uuidv4 = require('uuid/v4')
 const HttpMocks = require('node-mocks-http')
 
@@ -44,6 +44,9 @@
  * @extends {module:Comms.ISocketComms}
  * @link module:Comms
  * 
+ * 
+ * @param {boolean}     host    Set to `true` to make this peer act as the protocol host
+ * @param {Object}      socket  Already connected peer socket
  */
 class PeerComms extends ISocketComms {
   constructor({remoteIdentity, discoverRemoteIdentity, host, party, socket, ...options}){
@@ -380,4 +383,4 @@
 }
 
 
-module.exports = PeerComms
\ No newline at end of file +module.exports = PeerComms
\ No newline at end of file diff --git a/docs/comms_rest-comms.js.html b/docs/comms_rest-comms.js.html index 6019558..c39d8ff 100644 --- a/docs/comms_rest-comms.js.html +++ b/docs/comms_rest-comms.js.html @@ -1,6 +1,6 @@ Source: comms/rest-comms.js
On this page

comms_rest-comms.js

const axios = require('axios')
+    
On this page

comms_rest-comms.js

const axios = require('axios')
 const EventEmitter = require('eventemitter3')
 const debug = require('debug')('dataparty.comms.rest')
 
@@ -383,4 +383,4 @@
 }
 
 module.exports = RestComms
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/comms_rtc-socket-comms.js.html b/docs/comms_rtc-socket-comms.js.html index f386f56..799c54c 100644 --- a/docs/comms_rtc-socket-comms.js.html +++ b/docs/comms_rtc-socket-comms.js.html @@ -1,6 +1,6 @@ Source: comms/rtc-socket-comms.js
On this page

comms_rtc-socket-comms.js

const debug = require('debug')('dataparty.comms.rtcsocketcomms')
+    
On this page

comms_rtc-socket-comms.js

const debug = require('debug')('dataparty.comms.rtcsocketcomms')
 
 const SimplePeer = require('simple-peer')
 const PeerComms = require('./peer-comms')
@@ -31,4 +31,4 @@
 }
 
 
-module.exports = RTCSocketComms
\ No newline at end of file +module.exports = RTCSocketComms
\ No newline at end of file diff --git a/docs/comms_websocket-comms.js.html b/docs/comms_websocket-comms.js.html index 2f7d4fd..7876012 100644 --- a/docs/comms_websocket-comms.js.html +++ b/docs/comms_websocket-comms.js.html @@ -1,6 +1,6 @@ Source: comms/websocket-comms.js
On this page

comms_websocket-comms.js

const debug = require('debug')('dataparty.comms.websocket')
+    
On this page

comms_websocket-comms.js

const debug = require('debug')('dataparty.comms.websocket')
 
 const WebSocket = global.WebSocket ? global.WebSocket : require('ws')
 
@@ -45,4 +45,4 @@
 }
 
 
-module.exports = WebsocketComms
\ No newline at end of file +module.exports = WebsocketComms
\ No newline at end of file diff --git a/docs/config_iconfig.js.html b/docs/config_iconfig.js.html index 070fc39..854c13b 100644 --- a/docs/config_iconfig.js.html +++ b/docs/config_iconfig.js.html @@ -1,6 +1,6 @@ Source: config/iconfig.js
On this page

config_iconfig.js

const EventEmitter = require('eventemitter3')
+    
On this page

config_iconfig.js

const EventEmitter = require('eventemitter3')
 
 /**
  * @interface module:Config.IConfig
@@ -57,4 +57,4 @@
     async save(){ throw 'not implemented' }
 }
 
-module.exports = IConfig
\ No newline at end of file +module.exports = IConfig
\ No newline at end of file diff --git a/docs/config_index.js.html b/docs/config_index.js.html index 59d0f0d..0802a9c 100644 --- a/docs/config_index.js.html +++ b/docs/config_index.js.html @@ -1,6 +1,6 @@ Source: config/index.js
On this page

config_index.js


+    
On this page

config_index.js


 
 /**
 * @module Config
@@ -11,4 +11,4 @@
 exports.JsonFileConfig = require('./json-file')
 exports.LocalStorageConfig = require('./local-storage')
 
-exports.SecureConfig = require('./secure-config')
\ No newline at end of file +exports.SecureConfig = require('./secure-config')
\ No newline at end of file diff --git a/docs/config_json-file.js.html b/docs/config_json-file.js.html index 7d39fc3..d9b3b9b 100644 --- a/docs/config_json-file.js.html +++ b/docs/config_json-file.js.html @@ -1,6 +1,6 @@ Source: config/json-file.js
On this page

config_json-file.js

'use strict';
+    
On this page

config_json-file.js

'use strict';
 
 const fs = require('fs')
 const Path = require('path')
@@ -102,4 +102,4 @@
   }
 }
 
-module.exports = JsonFileConfig
\ No newline at end of file +module.exports = JsonFileConfig
\ No newline at end of file diff --git a/docs/config_local-storage.js.html b/docs/config_local-storage.js.html index 1b86b94..9a33af6 100644 --- a/docs/config_local-storage.js.html +++ b/docs/config_local-storage.js.html @@ -1,6 +1,6 @@ Source: config/local-storage.js
On this page

config_local-storage.js

'use strict';
+    
On this page

config_local-storage.js

'use strict';
 
 const deepSet = require('lodash').set
 const reach = require('../utils/reach')
@@ -72,4 +72,4 @@
   }
 }
 
-module.exports = LocalStorageConfig
\ No newline at end of file +module.exports = LocalStorageConfig
\ No newline at end of file diff --git a/docs/config_memory.js.html b/docs/config_memory.js.html index ba1f24e..684f534 100644 --- a/docs/config_memory.js.html +++ b/docs/config_memory.js.html @@ -1,6 +1,6 @@ Source: config/memory.js
On this page

config_memory.js

'use strict';
+    
On this page

config_memory.js

'use strict';
 
 const deepSet = require('lodash').set
 const reach = require('../utils/reach')
@@ -63,4 +63,4 @@
   }
 }
 
-module.exports = MemoryConfig
\ No newline at end of file +module.exports = MemoryConfig
\ No newline at end of file diff --git a/docs/config_nconf.js.html b/docs/config_nconf.js.html index 18ef95e..c4d8dad 100644 --- a/docs/config_nconf.js.html +++ b/docs/config_nconf.js.html @@ -1,6 +1,6 @@ Source: config/nconf.js
On this page

config_nconf.js

'use strict';
+    
On this page

config_nconf.js

'use strict';
 
 const fs = require('fs')
 const os = require('os')
@@ -189,4 +189,4 @@
   }
 }
 
-module.exports = NconfConfig
\ No newline at end of file +module.exports = NconfConfig
\ No newline at end of file diff --git a/docs/config_secure-config.js.html b/docs/config_secure-config.js.html index 99d1e9e..7af682a 100644 --- a/docs/config_secure-config.js.html +++ b/docs/config_secure-config.js.html @@ -1,6 +1,6 @@ Source: config/secure-config.js
On this page

config_secure-config.js

const dataparty_crypto = require('@dataparty/crypto')
+    
On this page

config_secure-config.js

const dataparty_crypto = require('@dataparty/crypto')
 
 const debug = require('debug')('dataparty.config.secure-config')
 const deepSet = require('lodash').set
@@ -183,10 +183,6 @@
                 argonType
             }
 
-            if(!this.argon){
-                this.argon = argon
-            }
-
             key = await dataparty_crypto.Routines.createKeyFromPasswordArgon2(
                 this.argon,
                 password,
@@ -535,4 +531,4 @@
     }
 }
 
-module.exports = SecureConfig
\ No newline at end of file +module.exports = SecureConfig
\ No newline at end of file diff --git a/docs/data/search.json b/docs/data/search.json index 4057c04..03c365e 100644 --- a/docs/data/search.json +++ b/docs/data/search.json @@ -1 +1 @@ -{"list":[{"title":"implementing-services","link":"tutorial-implementing-services.html","description":" File: ./example-service.js const Dataparty = require('@dataparty/api') const debug = require('debug"},{"title":"local-party","link":"tutorial-local-party.html","description":" File: ./local-party.js const fs = require('fs/promises') const debug = require('debug')('example.ti"},{"title":"peer-to-peer","link":"tutorial-peer-to-peer.html","description":" File: ./example-service.js const Dataparty = require('@dataparty/api') const debug = require('debug"},{"title":"service-task","link":"tutorial-service-task.html","description":" File: ./service-host.js const Path = require('path') const debug = require('debug')('test.server-db"},{"title":"CloudDocument","link":"CloudDocument"},{"title":"CloudDocument#acl","link":"acl","description":"

Get this document's Acl

"},{"title":"CloudDocument#grantAccess","link":"grantAccess","description":"

Allow access to this document or a subfield

"},{"title":"CloudDocument#owner","link":"owner","description":"

CloudDocument owner as an IdObj

"},{"title":"CloudParty#call","link":"call"},{"title":"CloudParty#create","link":"create"},{"title":"CloudParty#find","link":"find"},{"title":"CloudParty#remove","link":"remove"},{"title":"CloudParty#socket","link":"socket"},{"title":"CloudParty#start","link":"start"},{"title":"CloudParty#update","link":"update"},{"title":"IDb#createCollection","link":"createCollection","description":"

Create collection with prefixed name

"},{"title":"IDb#documentFromObject","link":"documentFromObject","description":"

convert object with $meta field to db representation

"},{"title":"IDb#documentToObject","link":"documentToObject","description":"

convert db documnet to plain object with $meta field

"},{"title":"IDb#getCollection","link":"getCollection","description":"

Get native collection instance by prefixed name

"},{"title":"IDb#getCollectionNames","link":"getCollectionNames","description":"

Return non-prefixed collection names

"},{"title":"IdObj","link":"IdObj"},{"title":"IParty#socket","link":"socket"},{"title":"LokiQuery","link":"LokiQuery","description":"

generates a mongodb query doc from a dataparty query spec

"},{"title":"LokiQuery#getQueryDoc","link":"getQueryDoc","description":"

build mongo query doc from spec match tree

\n
    \n
  • explicitly 'and' top level of match tree
  • \n
  • search only returns msg metadata
  • \n
"},{"title":"module.exports#documentFromObject","link":"documentFromObject","description":"

convert object with $meta field to db representation

"},{"title":"module.exports#documentFromObject","link":"documentFromObject","description":"

convert object with $meta field to db representation

"},{"title":"module.exports#documentFromObject","link":"documentFromObject","description":"

convert object with $meta field to db representation

"},{"title":"module.exports#documentToObject","link":"documentToObject","description":"

convert db documnet to plain object with $meta field

"},{"title":"module.exports#documentToObject","link":"documentToObject","description":"

convert db documnet to plain object with $meta field

"},{"title":"module.exports#documentToObject","link":"documentToObject","description":"

convert db documnet to plain object with $meta field

"},{"title":"module.exports#handleCall","link":"handleCall","description":"

override these functions in subclass

"},{"title":"module.exports#permissions","link":"permissions","description":"

Collection level read/new/change permissions

"},{"title":"module.exports#redactRead","link":"redactRead","description":"

Collection level read redaction

"},{"title":"module.exports#redactWrite","link":"redactWrite","description":"

Collection level read redaction

"},{"title":"module:Comms","link":"Comms"},{"title":"module:Comms.BLEPeerClient","link":"BLEPeerClient","description":"

A simple BLE socket\n⚠️ Warning: This class maybe significantly refactored in future releases

"},{"title":"module:Comms.I2pSocketComms","link":"I2pSocketComms","description":"

A peer comms based on i2p using the SAM module from diva.exchange

"},{"title":"module:Comms.ISocketComms","link":"ISocketComms"},{"title":"module:Comms.LoopbackChannel","link":"LoopbackChannel"},{"title":"module:Comms.LoopbackComms","link":"LoopbackComms"},{"title":"module:Comms.LoopbackSocket","link":"LoopbackSocket"},{"title":"module:Comms.PeerComms","link":"PeerComms"},{"title":"module:Comms.RestComms","link":"RestComms"},{"title":"module:Comms.RTCSocketComms","link":"RTCSocketComms"},{"title":"module:Comms.WebsocketComms","link":"WebsocketComms"},{"title":"module:Config","link":"Config"},{"title":"module:Config.IConfig","link":"IConfig"},{"title":"module:Config.IConfig.clear","link":"clear"},{"title":"module:Config.IConfig.exists","link":"exists"},{"title":"module:Config.IConfig.read","link":"read"},{"title":"module:Config.IConfig.readAll","link":"readAll"},{"title":"module:Config.IConfig.save","link":"save"},{"title":"module:Config.IConfig.start","link":"start"},{"title":"module:Config.IConfig.write","link":"write"},{"title":"module:Config.JsonFileConfig","link":"JsonFileConfig"},{"title":"module:Config.LocalStorageConfig","link":"LocalStorageConfig"},{"title":"module:Config.MemoryConfig","link":"MemoryConfig"},{"title":"module:Config.NconfConfig","link":"NconfConfig"},{"title":"module:Config.SecureConfig","link":"SecureConfig","description":"

A secure configuration. This uses an underlying IConfig for storage. Multiple\nsecure configs can be placed within the same IConfig so long as different id\nis set. By default pbkdf2 is used to generate NaCl keys. If argon is provided\nthen argon2 will be used to generate the NaCl keys. Applications should\nuse argon2.

"},{"title":"module:Config.SecureConfig.clear","link":"clear"},{"title":"module:Config.SecureConfig.isInitialized","link":"isInitialized","description":"

Checks if the secure config has initialized with a password or key

"},{"title":"module:Config.SecureConfig.isLocked","link":"isLocked","description":"

Checks if the secure config is locked. If not locked the secure config\ncan be used without blocking waiting for user to unlock.

"},{"title":"module:Config.SecureConfig.lock","link":"lock","description":"

Locks the secure config

"},{"title":"module:Config.SecureConfig.read","link":"read"},{"title":"module:Config.SecureConfig.readAll","link":"readAll"},{"title":"module:Config.SecureConfig.save","link":"save"},{"title":"module:Config.SecureConfig.setIdentity","link":"setIdentity","description":"

Initialize the secure config with a key

"},{"title":"module:Config.SecureConfig.setPassword","link":"setPassword","description":"

Initialize the secure config with a password

"},{"title":"module:Config.SecureConfig.start","link":"start","description":"

Start the secure storage

"},{"title":"module:Config.SecureConfig.unlock","link":"unlock","description":"

Unlocks the secure config

"},{"title":"module:Config.SecureConfig.waitForUnlocked","link":"waitForUnlocked","description":"

Wait for config to be unlocked

"},{"title":"module:Config.SecureConfig.write","link":"write"},{"title":"module:Config.SecureConfig#event:blocked","link":"blocked","description":"

An read/write operation has been blocked due to the secure config\nbeing locked.

"},{"title":"module:Config.SecureConfig#event:intialized","link":"intialized","description":"

The secure config has been successfully initialized with a passowrd\nor key.

"},{"title":"module:Config.SecureConfig#event:locked","link":"locked","description":"

The secure config has been locked

"},{"title":"module:Config.SecureConfig#event:ready","link":"ready","description":"

Ready event. The secure config is ready to be unlocked and have\nconfiguration values read or written.

"},{"title":"module:Config.SecureConfig#event:setup-required","link":"setup-required","description":"

Setup required event. The secure config has not yet has a password\nor key configured.

"},{"title":"module:Config.SecureConfig#event:unlocked","link":"unlocked","description":"

The secure config has been unlocked

"},{"title":"module:Db","link":"Db"},{"title":"module:Db.IDb","link":"IDb"},{"title":"module:Db.ISchema","link":"ISchema"},{"title":"module:Db.ISchema.install","link":"install"},{"title":"module:Db.ISchema.permissions","link":"permissions","description":"

Collection level read/new/change permissions

"},{"title":"module:Db.ISchema.setupSchema","link":"setupSchema"},{"title":"module:Db.LokiDb","link":"LokiDb","description":"

A db implementation based on LokiJS.

\n

Ideal for frontend apps with small datasets (smaller than total RAM). This is an in-memory db so it trades RAM efficiency for access speed.

"},{"title":"module:Db.TingoDb","link":"TingoDb","description":"

Ideal for extremely large datasets with frequent document additions. Has a very efficient append-only file system driver which is ideal for embedded platforms. All database indexes must fit into RAM and are re-computed at db load time.

"},{"title":"module:Db.ZangoDb","link":"ZangoDb","description":"

Ideal for frontend apps with large datasets (larger then total RAM). This is an IndexedDb based driver so it span to nearly 1/3 of total system storage spave available to the browser/app.

"},{"title":"module:Party","link":"Party"},{"title":"module:Party.CloudParty","link":"CloudParty"},{"title":"module:Party.DocumentFactory","link":"DocumentFactory","description":"

Represents document schemas mapped to contructor claasses which extend IDocument

"},{"title":"module:Party.DocumentFactory.addFactory","link":"addFactory"},{"title":"module:Party.DocumentFactory.getDocument","link":"getDocument"},{"title":"module:Party.DocumentFactory.getFactories","link":"getFactories"},{"title":"module:Party.DocumentFactory.getFactory","link":"getFactory"},{"title":"module:Party.DocumentFactory.getTypes","link":"getTypes"},{"title":"module:Party.DocumentFactory.getValidators","link":"getValidators"},{"title":"module:Party.DocumentFactory.hydrate","link":"hydrate"},{"title":"module:Party.DocumentFactory.validate","link":"validate"},{"title":"module:Party.IDocument","link":"IDocument","description":"

Represents a document with caching and local+remote change notifications

"},{"title":"module:Party.IDocument.cleanData","link":"cleanData","description":"

document data with no library added fields

"},{"title":"module:Party.IDocument.create","link":"create"},{"title":"module:Party.IDocument.data","link":"data","description":"

entire document

"},{"title":"module:Party.IDocument.Document","link":"Document"},{"title":"module:Party.IDocument.getData","link":"getData"},{"title":"module:Party.IDocument.id","link":"id","description":"

Document mongo-id

"},{"title":"module:Party.IDocument.idObj","link":"idObj","description":"

Document id object

"},{"title":"module:Party.IDocument.idString","link":"idString","description":"

Document id string in format <type>:<mongo-id>

"},{"title":"module:Party.IDocument.mergeData","link":"mergeData"},{"title":"module:Party.IDocument.pull","link":"pull"},{"title":"module:Party.IDocument.remove","link":"remove"},{"title":"module:Party.IDocument.revision","link":"revision","description":"

Document revision string

"},{"title":"module:Party.IDocument.save","link":"save"},{"title":"module:Party.IDocument.setData","link":"setData"},{"title":"module:Party.IDocument.type","link":"type","description":"

Document type string

"},{"title":"module:Party.IDocument.unwatch","link":"unwatch","description":"

Stop watching for remote document changes

"},{"title":"module:Party.IDocument.watch","link":"watch"},{"title":"module:Party.IDocument.watchField","link":"watchField","description":"

Watch a field for changes. If value is supplied watches\nfor field and value to match.

"},{"title":"module:Party.IDocument#event:change","link":"change","description":"

Document change Event - This is event is triggered when a document has been\nmodified on the remote service

"},{"title":"module:Party.IDocument#event:create","link":"create","description":"

Document create Event - This event is triggered after a document has been created and\napplied to the backing cache of Document.data. If Document.followcache\nis true the document doc has also accepted the change.

"},{"title":"module:Party.IDocument#event:field","link":"field","description":"

Field change event. This is emitted as field.[FIELD_PATH]

"},{"title":"module:Party.IDocument#event:remove","link":"remove","description":"

Document remove Event - This event is triggered after a document has been removed and\napplied to the backing cache of Document.data. If Document.followcache\nis true the document doc has also accepted the change.

"},{"title":"module:Party.IDocument#event:update","link":"update","description":"

Document update Event - This event is triggered after a change has been\napplied to the backing cache of Document.data. If Document.followcache\nis true the document doc has also accepted the change.

"},{"title":"module:Party.IDocument#event:value","link":"value","description":"

Document value Event - This event is triggered after a change has been\napplied to the backing cache of Document.data. Only fired when Document.followcache\nis true.

"},{"title":"module:Party.IParty","link":"IParty"},{"title":"module:Party.IParty.actor","link":"actor"},{"title":"module:Party.IParty.actors","link":"actors"},{"title":"module:Party.IParty.call","link":"call"},{"title":"module:Party.IParty.create","link":"create"},{"title":"module:Party.IParty.createDocument","link":"createDocument"},{"title":"module:Party.IParty.decrypt","link":"decrypt"},{"title":"module:Party.IParty.Document","link":"Document"},{"title":"module:Party.IParty.encrypt","link":"encrypt"},{"title":"module:Party.IParty.factory","link":"factory"},{"title":"module:Party.IParty.find","link":"find","description":"

Starts a query

"},{"title":"module:Party.IParty.hasActor","link":"hasActor"},{"title":"module:Party.IParty.hasIdentity","link":"hasIdentity"},{"title":"module:Party.IParty.identity","link":"identity"},{"title":"module:Party.IParty.loadActor","link":"loadActor"},{"title":"module:Party.IParty.loadIdentity","link":"loadIdentity"},{"title":"module:Party.IParty.privateIdentity","link":"privateIdentity"},{"title":"module:Party.IParty.remove","link":"remove"},{"title":"module:Party.IParty.resetIdentity","link":"resetIdentity"},{"title":"module:Party.IParty.ROSLIB","link":"ROSLIB"},{"title":"module:Party.IParty.start","link":"start"},{"title":"module:Party.IParty.types","link":"types"},{"title":"module:Party.IParty.update","link":"update"},{"title":"module:Party.LokiCache","link":"LokiCache"},{"title":"module:Party.LokiParty","link":"LokiParty","description":"

A local party based on LokiJS.

\n

Works great for front end. Doesn't scale well for centralized server use and\ndoes not have efficient file system representation for many embedded\napplications. Overall this driver is RAM bound holds the entire DB in\nmemory. When running on filesystems this driver re-writes the entire\ncollection during save operations.

"},{"title":"module:Party.LokiParty.handleCall","link":"handleCall"},{"title":"module:Party.LokiParty.start","link":"start"},{"title":"module:Party.MongoParty","link":"MongoParty","description":"

A party implementation based on Mongodb and mongoose.

\n

The humongouse database we all know all love. If you need a multi-region HA database, this is the one.

"},{"title":"module:Party.PeerParty","link":"PeerParty"},{"title":"module:Party.Query","link":"Query"},{"title":"module:Party.Query.all","link":"all","description":"

matches a list that is a superset of given list

"},{"title":"module:Party.Query.and","link":"and","description":"

following path segments will be anded (default behavior)

"},{"title":"module:Party.Query.contains","link":"contains","description":"

Check if field contains value

"},{"title":"module:Party.Query.dna","link":"dna","description":"

Closes scope of most recent and

"},{"title":"module:Party.Query.elem","link":"elem","description":"

list operators\n-> subtype of match tree nodes\n-> most recent .where('param') path must be list for these to match\nsearches for a single element of list matching all following conditions\nbetween elem .. mele nodes where('path') calls are relative to\nparam path scope at opening of element match

"},{"title":"module:Party.Query.equals","link":"equals","description":"

Check if field equals value

"},{"title":"module:Party.Query.exec","link":"exec","description":"

return a promise resolving to result of query

"},{"title":"module:Party.Query.exists","link":"exists","description":"

Check if field exists

"},{"title":"module:Party.Query.gt","link":"gt","description":"

Check if field is greater than value

"},{"title":"module:Party.Query.id","link":"id","description":"

query for single msg by given id\nprereq -> type (not types)\nall other query ops (except type) will be ignored

"},{"title":"module:Party.Query.ids","link":"ids","description":"

query for a list of msgs by given ids\nprereq -> type (not types)\nall other query ops (except type) will be ignored

"},{"title":"module:Party.Query.in","link":"in","description":"

Check if field is in list of values

"},{"title":"module:Party.Query.limit","link":"limit","description":"

limit # of msgs returned by query to a maximum of count

"},{"title":"module:Party.Query.lt","link":"lt","description":"

Check if field is less than value

"},{"title":"module:Party.Query.mele","link":"mele","description":"

Close elem function stack

"},{"title":"module:Party.Query.or","link":"or","description":"

The following path segments will be or'ed

"},{"title":"module:Party.Query.owner","link":"owner","description":"

restrict query to msgs with owner matching given type, id pair

"},{"title":"module:Party.Query.regex","link":"regex","description":"

Check if field is matched by regex

"},{"title":"module:Party.Query.ro","link":"ro","description":"

Close scope of most recent or

"},{"title":"module:Party.Query.seelct","link":"seelct","description":"

filter fields from parameters of returned msgs

"},{"title":"module:Party.Query.size","link":"size","description":"

matches list with exactly count items

"},{"title":"module:Party.Query.sort","link":"sort","description":"

sort returned msgs on given param path (leading '-' reverses sort)

"},{"title":"module:Party.Query.toJSON","link":"toJSON"},{"title":"module:Party.Query.type","link":"type","description":"

restrict query to msgs of given type

"},{"title":"module:Party.Query.types","link":"types","description":"

restrict query to msgs of given types\nnot compatible with type

"},{"title":"module:Party.Query.where","link":"where","description":"

sets context for following operations to given param path

"},{"title":"module:Party.TingoParty","link":"TingoParty","description":"

A local party implementation based on TingoDB\nIdeal for extremely large datasets with frequent document additions. Has a very efficient append-only file system driver which is ideal for embedded platforms. All database indexes must fit into RAM and are re-computed at db load time.

"},{"title":"module:Party.TingoParty.handleCall","link":"handleCall"},{"title":"module:Party.TingoParty.start","link":"start"},{"title":"module:Party.ZangoParty","link":"ZangoParty","description":"

A local party implementation based on IndexedDb via ZangoDB

\n

Ideal for frontend apps with large datasets (larger then total RAM). This is an IndexedDb based driver so it span to nearly 1/3 of total system storage spave available to the browser/app.

"},{"title":"module:Party.ZangoParty.handleCall","link":"handleCall"},{"title":"module:Party.ZangoParty.start","link":"start"},{"title":"module:Service","link":"Service"},{"title":"module:Service.EndpointContext","link":"EndpointContext"},{"title":"module:Service.EndpointContext.actor","link":"actor"},{"title":"module:Service.EndpointContext.debug","link":"debug"},{"title":"module:Service.EndpointContext.debug","link":"debug"},{"title":"module:Service.EndpointContext.endpoint","link":"endpoint"},{"title":"module:Service.EndpointContext.identity","link":"identity","description":"

Effective root of trust

"},{"title":"module:Service.EndpointContext.input","link":"input"},{"title":"module:Service.EndpointContext.MiddlewareConfig","link":"MiddlewareConfig"},{"title":"module:Service.EndpointContext.output","link":"output"},{"title":"module:Service.EndpointContext.req","link":"req"},{"title":"module:Service.EndpointContext.res","link":"res"},{"title":"module:Service.EndpointContext.senderKey","link":"senderKey","description":"

Key used to encrypt content. This may be an ephermal key or a long lived key.

"},{"title":"module:Service.EndpointContext.session","link":"session"},{"title":"module:Service.EndpointContext.setSendFullErrors","link":"setSendFullErrors"},{"title":"module:Service.EndpointContext.stats","link":"stats"},{"title":"module:Service.IEndpoint","link":"IEndpoint"},{"title":"module:Service.IEndpoint.Description","link":"Description"},{"title":"module:Service.IEndpoint.EndpointInfo","link":"EndpointInfo"},{"title":"module:Service.IEndpoint.info","link":"info"},{"title":"module:Service.IEndpoint.MiddlewareConfig","link":"MiddlewareConfig","description":"

A collection of pre and post middleware configurations

"},{"title":"module:Service.IEndpoint.Name","link":"Name"},{"title":"module:Service.IEndpoint.run","link":"run"},{"title":"module:Service.IEndpoint.start","link":"start"},{"title":"module:Service.IMiddleware","link":"IMiddleware"},{"title":"module:Service.IMiddleware.ConfigSchema","link":"ConfigSchema","description":"

Joi validator that describes any expected config for this middleware

"},{"title":"module:Service.IMiddleware.Description","link":"Description"},{"title":"module:Service.IMiddleware.info","link":"info"},{"title":"module:Service.IMiddleware.MiddlewareInfo","link":"MiddlewareInfo"},{"title":"module:Service.IMiddleware.Name","link":"Name"},{"title":"module:Service.IMiddleware.run","link":"run"},{"title":"module:Service.IMiddleware.start","link":"start"},{"title":"module:Service.IMiddleware.Type","link":"Type","description":"

Type of middleware. Allowed values are pre or post

"},{"title":"module:Service.ISandboxRunner","link":"ISandboxRunner"},{"title":"module:Service.ISandboxRunner.getInfo","link":"getInfo"},{"title":"module:Service.ISandboxRunner.run","link":"run"},{"title":"module:Service.ISandboxRunner.self","link":"self"},{"title":"module:Service.ISandboxRunner.start","link":"start"},{"title":"module:Service.ISandboxRunner.start","link":"start"},{"title":"module:Service.IService","link":"IService","description":"

A service with schema, documents, endpoints, middleware and tasks.\nProvide either paths to source files for compilation or provided a\npre-built service to import.

"},{"title":"module:Service.IService.addDocument","link":"addDocument","description":"

Add a document class implementation to the service

"},{"title":"module:Service.IService.addEndpoint","link":"addEndpoint","description":"

Add a dataparty endpoint to the service by pather

"},{"title":"module:Service.IService.addEndpoint","link":"addEndpoint","description":"

Add a middleware to this service

"},{"title":"module:Service.IService.addSchema","link":"addSchema","description":"

Add a dataparty schema implementation to the service

"},{"title":"module:Service.IService.addTask","link":"addTask","description":"

Add a tasker task implementation to the service

"},{"title":"module:Service.IService.compile","link":"compile","description":"

Compile a service. This will build two output files, one for host usage -service.json\nand another for client usage -schema.json.

"},{"title":"module:Service.IService.importBuild","link":"importBuild","description":"

Import a pre-build service

"},{"title":"module:Service.ITask","link":"ITask","description":"

Interface class for supporting tasker tasks in dataparty.\nTo add a task to dataparty service extend this class and implement\nthe Name, Description and Config members.

"},{"title":"module:Service.ITask.Config","link":"Config"},{"title":"module:Service.ITask.Description","link":"Description"},{"title":"module:Service.ITask.info","link":"info","description":"

Returns the task's Name, Description, and Config

"},{"title":"module:Service.ITask.Name","link":"Name"},{"title":"module:Service.ITask.TaskConfig","link":"TaskConfig"},{"title":"module:Service.ITask.TaskInfo","link":"TaskInfo"},{"title":"module:Service.RouterRunner.onRequest","link":"onRequest","description":"

Expressjs style way of calling an endpoint. The req will be passed to the router to select the appropritate endpoint

"},{"title":"module:Service.RunnerRouter","link":"RunnerRouter","description":"

A multi-domain drop in replacement for anywhere we use origin-router.Router.\nBy creating multiple dataparty ServiceRunners you can manage multiple parties\nand multiple services and merge them into either a single combined service. Or\nhost them as multiple seperate domains. Essentially, this allows the ServiceHost\nto be multi-tenant.

"},{"title":"module:Service.RunnerRouter.addRunner","link":"addRunner"},{"title":"module:Service.RunnerRouter.getRunnerByDomain","link":"getRunnerByDomain"},{"title":"module:Service.RunnerRouter.getRunnerByHostIdentity","link":"getRunnerByHostIdentity"},{"title":"module:Service.RunnerRouter.start","link":"start"},{"title":"module:Service.ServiceHost","link":"ServiceHost"},{"title":"module:Service.ServiceHost.apiApp","link":"apiApp","description":"

Express app

"},{"title":"module:Service.ServiceHost.router","link":"router","description":"

The router

"},{"title":"module:Service.ServiceHost.runner","link":"runner","description":"

Dataparty service runner

"},{"title":"module:Service.ServiceHost.start","link":"start","description":"

Start hosting services

"},{"title":"module:Service.ServiceHost.stop","link":"stop","description":"

Stop hosting services

"},{"title":"module:Service.ServiceRunner","link":"ServiceRunner","description":"

Sandboxed service runner. This runner uses the vm2 package to run end points in a fully isolated context.\nEndpoints, pre-middleware and post-middleware all run as independant precompiled VMScripts.

"},{"title":"module:Service.ServiceRunner.onRequest","link":"onRequest","description":"

Expressjs style way of calling an endpoint. The req will be passed to the router to select the appropritate endpoint

"},{"title":"module:Service.ServiceRunnerNode","link":"ServiceRunnerNode","description":"

Unsafe service runner. This service runner uses eval to run services, endpoints and tasks.\nThis provides only simple context seperation and does not do effective context isolation.\nThis should only be used where the service is knwon trustworthy. When the useNative option\nis set to true the service will run in the same context as this class with no isolation at all.

"},{"title":"module:Service.ServiceRunnerNode.onRequest","link":"onRequest","description":"

Expressjs style way of calling an endpoint. The req will be passed to the router to select the appropritate endpoint

"},{"title":"module:Topics","link":"Topics"},{"title":"module:Topics.LocalTopicHost","link":"LocalTopicHost","description":"

Implementation of ROS style pub/sub topics. This runs on a\nsingle thread/peer and can be shared to other peers. However,\nthis is a centralized implementation. So if the hosting node\nstops all topic traffic will halt as well.

"},{"title":"MongoQuery","link":"MongoQuery","description":"

generates a mongodb query doc from a dataparty query spec

"},{"title":"MongoQuery#getQueryDoc","link":"getQueryDoc","description":"

build mongo query doc from spec match tree

\n
    \n
  • explicitly 'and' top level of match tree
  • \n
  • search only returns msg metadata
  • \n
"},{"title":"ServiceRunnerNode#runTask","link":"runTask","description":"

Add a named task to the run queue

"}]} \ No newline at end of file +{"list":[{"title":"CloudDocument","link":"CloudDocument"},{"title":"CloudDocument#acl","link":"acl","description":"

Get this document's Acl

"},{"title":"CloudDocument#grantAccess","link":"grantAccess","description":"

Allow access to this document or a subfield

"},{"title":"CloudDocument#owner","link":"owner","description":"

CloudDocument owner as an IdObj

"},{"title":"CloudParty#call","link":"call"},{"title":"CloudParty#create","link":"create"},{"title":"CloudParty#find","link":"find"},{"title":"CloudParty#remove","link":"remove"},{"title":"CloudParty#socket","link":"socket"},{"title":"CloudParty#start","link":"start"},{"title":"CloudParty#update","link":"update"},{"title":"IDb#createCollection","link":"createCollection","description":"

Create collection with prefixed name

"},{"title":"IDb#documentFromObject","link":"documentFromObject","description":"

convert object with $meta field to db representation

"},{"title":"IDb#documentToObject","link":"documentToObject","description":"

convert db documnet to plain object with $meta field

"},{"title":"IDb#getCollection","link":"getCollection","description":"

Get native collection instance by prefixed name

"},{"title":"IDb#getCollectionNames","link":"getCollectionNames","description":"

Return non-prefixed collection names

"},{"title":"IdObj","link":"IdObj"},{"title":"IParty#socket","link":"socket"},{"title":"LokiQuery","link":"LokiQuery","description":"

generates a mongodb query doc from a dataparty query spec

"},{"title":"LokiQuery#getQueryDoc","link":"getQueryDoc","description":"

build mongo query doc from spec match tree

\n
    \n
  • explicitly 'and' top level of match tree
  • \n
  • search only returns msg metadata
  • \n
"},{"title":"module.exports#documentFromObject","link":"documentFromObject","description":"

convert object with $meta field to db representation

"},{"title":"module.exports#documentFromObject","link":"documentFromObject","description":"

convert object with $meta field to db representation

"},{"title":"module.exports#documentFromObject","link":"documentFromObject","description":"

convert object with $meta field to db representation

"},{"title":"module.exports#documentToObject","link":"documentToObject","description":"

convert db documnet to plain object with $meta field

"},{"title":"module.exports#documentToObject","link":"documentToObject","description":"

convert db documnet to plain object with $meta field

"},{"title":"module.exports#documentToObject","link":"documentToObject","description":"

convert db documnet to plain object with $meta field

"},{"title":"module.exports#handleCall","link":"handleCall","description":"

override these functions in subclass

"},{"title":"module.exports#permissions","link":"permissions","description":"

Collection level read/new/change permissions

"},{"title":"module.exports#redactRead","link":"redactRead","description":"

Collection level read redaction

"},{"title":"module.exports#redactWrite","link":"redactWrite","description":"

Collection level read redaction

"},{"title":"module:Comms","link":"Comms"},{"title":"module:Comms.BLEPeerClient","link":"BLEPeerClient","description":"

A simple BLE socket\n⚠️ Warning: This class maybe significantly refactored in future releases

"},{"title":"module:Comms.I2pSocketComms","link":"I2pSocketComms","description":"

A peer comms based on i2p using the SAM module from diva.exchange

"},{"title":"module:Comms.ISocketComms","link":"ISocketComms"},{"title":"module:Comms.LoopbackChannel","link":"LoopbackChannel"},{"title":"module:Comms.LoopbackComms","link":"LoopbackComms"},{"title":"module:Comms.LoopbackSocket","link":"LoopbackSocket"},{"title":"module:Comms.PeerComms","link":"PeerComms"},{"title":"module:Comms.RestComms","link":"RestComms"},{"title":"module:Comms.RTCSocketComms","link":"RTCSocketComms"},{"title":"module:Comms.WebsocketComms","link":"WebsocketComms"},{"title":"module:Config","link":"Config"},{"title":"module:Config.IConfig","link":"IConfig"},{"title":"module:Config.IConfig.clear","link":"clear"},{"title":"module:Config.IConfig.exists","link":"exists"},{"title":"module:Config.IConfig.read","link":"read"},{"title":"module:Config.IConfig.readAll","link":"readAll"},{"title":"module:Config.IConfig.save","link":"save"},{"title":"module:Config.IConfig.start","link":"start"},{"title":"module:Config.IConfig.write","link":"write"},{"title":"module:Config.JsonFileConfig","link":"JsonFileConfig"},{"title":"module:Config.LocalStorageConfig","link":"LocalStorageConfig"},{"title":"module:Config.MemoryConfig","link":"MemoryConfig"},{"title":"module:Config.NconfConfig","link":"NconfConfig"},{"title":"module:Config.SecureConfig","link":"SecureConfig","description":"

A secure configuration. This uses an underlying IConfig for storage. Multiple\nsecure configs can be placed within the same IConfig so long as different id\nis set. By default pbkdf2 is used to generate NaCl keys. If argon is provided\nthen argon2 will be used to generate the NaCl keys. Applications should\nuse argon2.

"},{"title":"module:Config.SecureConfig.clear","link":"clear"},{"title":"module:Config.SecureConfig.isInitialized","link":"isInitialized","description":"

Checks if the secure config has initialized with a password or key

"},{"title":"module:Config.SecureConfig.isLocked","link":"isLocked","description":"

Checks if the secure config is locked. If not locked the secure config\ncan be used without blocking waiting for user to unlock.

"},{"title":"module:Config.SecureConfig.lock","link":"lock","description":"

Locks the secure config

"},{"title":"module:Config.SecureConfig.read","link":"read"},{"title":"module:Config.SecureConfig.readAll","link":"readAll"},{"title":"module:Config.SecureConfig.save","link":"save"},{"title":"module:Config.SecureConfig.setIdentity","link":"setIdentity","description":"

Initialize the secure config with a key

"},{"title":"module:Config.SecureConfig.setPassword","link":"setPassword","description":"

Initialize the secure config with a password

"},{"title":"module:Config.SecureConfig.start","link":"start","description":"

Start the secure storage

"},{"title":"module:Config.SecureConfig.unlock","link":"unlock","description":"

Unlocks the secure config

"},{"title":"module:Config.SecureConfig.waitForUnlocked","link":"waitForUnlocked","description":"

Wait for config to be unlocked

"},{"title":"module:Config.SecureConfig.write","link":"write"},{"title":"module:Config.SecureConfig#event:blocked","link":"blocked","description":"

An read/write operation has been blocked due to the secure config\nbeing locked.

"},{"title":"module:Config.SecureConfig#event:intialized","link":"intialized","description":"

The secure config has been successfully initialized with a passowrd\nor key.

"},{"title":"module:Config.SecureConfig#event:locked","link":"locked","description":"

The secure config has been locked

"},{"title":"module:Config.SecureConfig#event:ready","link":"ready","description":"

Ready event. The secure config is ready to be unlocked and have\nconfiguration values read or written.

"},{"title":"module:Config.SecureConfig#event:setup-required","link":"setup-required","description":"

Setup required event. The secure config has not yet has a password\nor key configured.

"},{"title":"module:Config.SecureConfig#event:unlocked","link":"unlocked","description":"

The secure config has been unlocked

"},{"title":"module:Db","link":"Db"},{"title":"module:Db.IDb","link":"IDb"},{"title":"module:Db.ISchema","link":"ISchema"},{"title":"module:Db.ISchema.install","link":"install"},{"title":"module:Db.ISchema.permissions","link":"permissions","description":"

Collection level read/new/change permissions

"},{"title":"module:Db.ISchema.setupSchema","link":"setupSchema"},{"title":"module:Db.LokiDb","link":"LokiDb","description":"

A db implementation based on LokiJS.

\n

Ideal for frontend apps with small datasets (smaller than total RAM). This is an in-memory db so it trades RAM efficiency for access speed.

"},{"title":"module:Db.TingoDb","link":"TingoDb","description":"

Ideal for extremely large datasets with frequent document additions. Has a very efficient append-only file system driver which is ideal for embedded platforms. All database indexes must fit into RAM and are re-computed at db load time.

"},{"title":"module:Db.ZangoDb","link":"ZangoDb","description":"

Ideal for frontend apps with large datasets (larger then total RAM). This is an IndexedDb based driver so it span to nearly 1/3 of total system storage spave available to the browser/app.

"},{"title":"module:Party","link":"Party"},{"title":"module:Party.CloudParty","link":"CloudParty"},{"title":"module:Party.DocumentFactory","link":"DocumentFactory","description":"

Represents document schemas mapped to contructor claasses which extend IDocument

"},{"title":"module:Party.DocumentFactory.addFactory","link":"addFactory"},{"title":"module:Party.DocumentFactory.getDocument","link":"getDocument"},{"title":"module:Party.DocumentFactory.getFactories","link":"getFactories"},{"title":"module:Party.DocumentFactory.getFactory","link":"getFactory"},{"title":"module:Party.DocumentFactory.getTypes","link":"getTypes"},{"title":"module:Party.DocumentFactory.getValidators","link":"getValidators"},{"title":"module:Party.DocumentFactory.hydrate","link":"hydrate"},{"title":"module:Party.DocumentFactory.validate","link":"validate"},{"title":"module:Party.IDocument","link":"IDocument","description":"

Represents a document with caching and local+remote change notifications

"},{"title":"module:Party.IDocument.cleanData","link":"cleanData","description":"

document data with no library added fields

"},{"title":"module:Party.IDocument.create","link":"create"},{"title":"module:Party.IDocument.data","link":"data","description":"

entire document

"},{"title":"module:Party.IDocument.Document","link":"Document"},{"title":"module:Party.IDocument.getData","link":"getData"},{"title":"module:Party.IDocument.hash","link":"hash","description":"

hash of document.data using sha256

"},{"title":"module:Party.IDocument.id","link":"id","description":"

Document mongo-id

"},{"title":"module:Party.IDocument.idObj","link":"idObj","description":"

Document id object

"},{"title":"module:Party.IDocument.idString","link":"idString","description":"

Document id string in format <type>:<mongo-id>

"},{"title":"module:Party.IDocument.mergeData","link":"mergeData"},{"title":"module:Party.IDocument.pull","link":"pull"},{"title":"module:Party.IDocument.remove","link":"remove"},{"title":"module:Party.IDocument.revision","link":"revision","description":"

Document revision string

"},{"title":"module:Party.IDocument.save","link":"save"},{"title":"module:Party.IDocument.setData","link":"setData"},{"title":"module:Party.IDocument.type","link":"type","description":"

Document type string

"},{"title":"module:Party.IDocument.unwatch","link":"unwatch","description":"

Stop watching for remote document changes

"},{"title":"module:Party.IDocument.watch","link":"watch"},{"title":"module:Party.IDocument.watchField","link":"watchField","description":"

Watch a field for changes. If value is supplied watches\nfor field and value to match.

"},{"title":"module:Party.IDocument#event:change","link":"change","description":"

Document change Event - This is event is triggered when a document has been\nmodified on the remote service

"},{"title":"module:Party.IDocument#event:create","link":"create","description":"

Document create Event - This event is triggered after a document has been created and\napplied to the backing cache of Document.data. If Document.followcache\nis true the document doc has also accepted the change.

"},{"title":"module:Party.IDocument#event:field","link":"field","description":"

Field change event. This is emitted as field.[FIELD_PATH]

"},{"title":"module:Party.IDocument#event:remove","link":"remove","description":"

Document remove Event - This event is triggered after a document has been removed and\napplied to the backing cache of Document.data. If Document.followcache\nis true the document doc has also accepted the change.

"},{"title":"module:Party.IDocument#event:update","link":"update","description":"

Document update Event - This event is triggered after a change has been\napplied to the backing cache of Document.data. If Document.followcache\nis true the document doc has also accepted the change.

"},{"title":"module:Party.IDocument#event:value","link":"value","description":"

Document value Event - This event is triggered after a change has been\napplied to the backing cache of Document.data. Only fired when Document.followcache\nis true.

"},{"title":"module:Party.IParty","link":"IParty"},{"title":"module:Party.IParty.actor","link":"actor"},{"title":"module:Party.IParty.actors","link":"actors"},{"title":"module:Party.IParty.call","link":"call"},{"title":"module:Party.IParty.create","link":"create"},{"title":"module:Party.IParty.createDocument","link":"createDocument"},{"title":"module:Party.IParty.decrypt","link":"decrypt"},{"title":"module:Party.IParty.Document","link":"Document"},{"title":"module:Party.IParty.encrypt","link":"encrypt"},{"title":"module:Party.IParty.factory","link":"factory"},{"title":"module:Party.IParty.find","link":"find","description":"

Starts a query

"},{"title":"module:Party.IParty.hasActor","link":"hasActor"},{"title":"module:Party.IParty.hasIdentity","link":"hasIdentity"},{"title":"module:Party.IParty.identity","link":"identity"},{"title":"module:Party.IParty.loadActor","link":"loadActor"},{"title":"module:Party.IParty.loadIdentity","link":"loadIdentity"},{"title":"module:Party.IParty.privateIdentity","link":"privateIdentity"},{"title":"module:Party.IParty.remove","link":"remove"},{"title":"module:Party.IParty.resetIdentity","link":"resetIdentity"},{"title":"module:Party.IParty.ROSLIB","link":"ROSLIB"},{"title":"module:Party.IParty.start","link":"start"},{"title":"module:Party.IParty.types","link":"types"},{"title":"module:Party.IParty.update","link":"update"},{"title":"module:Party.LokiCache","link":"LokiCache"},{"title":"module:Party.LokiParty","link":"LokiParty","description":"

A local party based on LokiJS.

\n

Works great for front end. Doesn't scale well for centralized server use and\ndoes not have efficient file system representation for many embedded\napplications. Overall this driver is RAM bound holds the entire DB in\nmemory. When running on filesystems this driver re-writes the entire\ncollection during save operations.

"},{"title":"module:Party.LokiParty.handleCall","link":"handleCall"},{"title":"module:Party.LokiParty.start","link":"start"},{"title":"module:Party.MongoParty","link":"MongoParty","description":"

A party implementation based on Mongodb and mongoose.

\n

The humongouse database we all know all love. If you need a multi-region HA database, this is the one.

"},{"title":"module:Party.PeerParty","link":"PeerParty"},{"title":"module:Party.Query","link":"Query"},{"title":"module:Party.Query.all","link":"all","description":"

matches a list that is a superset of given list

"},{"title":"module:Party.Query.and","link":"and","description":"

following path segments will be anded (default behavior)

"},{"title":"module:Party.Query.contains","link":"contains","description":"

Check if field contains value

"},{"title":"module:Party.Query.dna","link":"dna","description":"

Closes scope of most recent and

"},{"title":"module:Party.Query.elem","link":"elem","description":"

list operators\n-> subtype of match tree nodes\n-> most recent .where('param') path must be list for these to match\nsearches for a single element of list matching all following conditions\nbetween elem .. mele nodes where('path') calls are relative to\nparam path scope at opening of element match

"},{"title":"module:Party.Query.equals","link":"equals","description":"

Check if field equals value

"},{"title":"module:Party.Query.exec","link":"exec","description":"

return a promise resolving to result of query

"},{"title":"module:Party.Query.exists","link":"exists","description":"

Check if field exists

"},{"title":"module:Party.Query.gt","link":"gt","description":"

Check if field is greater than value

"},{"title":"module:Party.Query.id","link":"id","description":"

query for single msg by given id\nprereq -> type (not types)\nall other query ops (except type) will be ignored

"},{"title":"module:Party.Query.ids","link":"ids","description":"

query for a list of msgs by given ids\nprereq -> type (not types)\nall other query ops (except type) will be ignored

"},{"title":"module:Party.Query.in","link":"in","description":"

Check if field is in list of values

"},{"title":"module:Party.Query.limit","link":"limit","description":"

limit # of msgs returned by query to a maximum of count

"},{"title":"module:Party.Query.lt","link":"lt","description":"

Check if field is less than value

"},{"title":"module:Party.Query.mele","link":"mele","description":"

Close elem function stack

"},{"title":"module:Party.Query.or","link":"or","description":"

The following path segments will be or'ed

"},{"title":"module:Party.Query.owner","link":"owner","description":"

restrict query to msgs with owner matching given type, id pair

"},{"title":"module:Party.Query.regex","link":"regex","description":"

Check if field is matched by regex

"},{"title":"module:Party.Query.ro","link":"ro","description":"

Close scope of most recent or

"},{"title":"module:Party.Query.seelct","link":"seelct","description":"

filter fields from parameters of returned msgs

"},{"title":"module:Party.Query.size","link":"size","description":"

matches list with exactly count items

"},{"title":"module:Party.Query.sort","link":"sort","description":"

sort returned msgs on given param path (leading '-' reverses sort)

"},{"title":"module:Party.Query.toJSON","link":"toJSON"},{"title":"module:Party.Query.type","link":"type","description":"

restrict query to msgs of given type

"},{"title":"module:Party.Query.types","link":"types","description":"

restrict query to msgs of given types\nnot compatible with type

"},{"title":"module:Party.Query.where","link":"where","description":"

sets context for following operations to given param path

"},{"title":"module:Party.TingoParty","link":"TingoParty","description":"

A local party implementation based on TingoDB\nIdeal for extremely large datasets with frequent document additions. Has a very efficient append-only file system driver which is ideal for embedded platforms. All database indexes must fit into RAM and are re-computed at db load time.

"},{"title":"module:Party.TingoParty.handleCall","link":"handleCall"},{"title":"module:Party.TingoParty.start","link":"start"},{"title":"module:Party.ZangoParty","link":"ZangoParty","description":"

A local party implementation based on IndexedDb via ZangoDB

\n

Ideal for frontend apps with large datasets (larger then total RAM). This is an IndexedDb based driver so it span to nearly 1/3 of total system storage spave available to the browser/app.

"},{"title":"module:Party.ZangoParty.handleCall","link":"handleCall"},{"title":"module:Party.ZangoParty.start","link":"start"},{"title":"module:Service","link":"Service"},{"title":"module:Service.EndpointContext","link":"EndpointContext"},{"title":"module:Service.EndpointContext.actor","link":"actor"},{"title":"module:Service.EndpointContext.debug","link":"debug"},{"title":"module:Service.EndpointContext.debug","link":"debug"},{"title":"module:Service.EndpointContext.endpoint","link":"endpoint"},{"title":"module:Service.EndpointContext.identity","link":"identity","description":"

Effective root of trust

"},{"title":"module:Service.EndpointContext.input","link":"input"},{"title":"module:Service.EndpointContext.MiddlewareConfig","link":"MiddlewareConfig"},{"title":"module:Service.EndpointContext.output","link":"output"},{"title":"module:Service.EndpointContext.req","link":"req"},{"title":"module:Service.EndpointContext.res","link":"res"},{"title":"module:Service.EndpointContext.senderKey","link":"senderKey","description":"

Key used to encrypt content. This may be an ephermal key or a long lived key.

"},{"title":"module:Service.EndpointContext.session","link":"session"},{"title":"module:Service.EndpointContext.setSendFullErrors","link":"setSendFullErrors"},{"title":"module:Service.EndpointContext.stats","link":"stats"},{"title":"module:Service.IEndpoint","link":"IEndpoint"},{"title":"module:Service.IEndpoint.Description","link":"Description"},{"title":"module:Service.IEndpoint.EndpointInfo","link":"EndpointInfo"},{"title":"module:Service.IEndpoint.info","link":"info"},{"title":"module:Service.IEndpoint.MiddlewareConfig","link":"MiddlewareConfig","description":"

A collection of pre and post middleware configurations

"},{"title":"module:Service.IEndpoint.Name","link":"Name"},{"title":"module:Service.IEndpoint.run","link":"run"},{"title":"module:Service.IEndpoint.start","link":"start"},{"title":"module:Service.IMiddleware","link":"IMiddleware"},{"title":"module:Service.IMiddleware.ConfigSchema","link":"ConfigSchema","description":"

Joi validator that describes any expected config for this middleware

"},{"title":"module:Service.IMiddleware.Description","link":"Description"},{"title":"module:Service.IMiddleware.info","link":"info"},{"title":"module:Service.IMiddleware.MiddlewareInfo","link":"MiddlewareInfo"},{"title":"module:Service.IMiddleware.Name","link":"Name"},{"title":"module:Service.IMiddleware.run","link":"run"},{"title":"module:Service.IMiddleware.start","link":"start"},{"title":"module:Service.IMiddleware.Type","link":"Type","description":"

Type of middleware. Allowed values are pre or post

"},{"title":"module:Service.ISandboxRunner","link":"ISandboxRunner"},{"title":"module:Service.ISandboxRunner.getInfo","link":"getInfo"},{"title":"module:Service.ISandboxRunner.run","link":"run"},{"title":"module:Service.ISandboxRunner.self","link":"self"},{"title":"module:Service.ISandboxRunner.start","link":"start"},{"title":"module:Service.ISandboxRunner.start","link":"start"},{"title":"module:Service.IService","link":"IService","description":"

A service with schema, documents, endpoints, middleware and tasks.\nProvide either paths to source files for compilation or provided a\npre-built service to import.

"},{"title":"module:Service.IService.addDocument","link":"addDocument","description":"

Add a document class implementation to the service

"},{"title":"module:Service.IService.addEndpoint","link":"addEndpoint","description":"

Add a dataparty endpoint to the service by pather

"},{"title":"module:Service.IService.addEndpoint","link":"addEndpoint","description":"

Add a middleware to this service

"},{"title":"module:Service.IService.addSchema","link":"addSchema","description":"

Add a dataparty schema implementation to the service

"},{"title":"module:Service.IService.addTask","link":"addTask","description":"

Add a tasker task implementation to the service

"},{"title":"module:Service.IService.compile","link":"compile","description":"

Compile a service. This will build two output files, one for host usage -service.json\nand another for client usage -schema.json.

"},{"title":"module:Service.IService.importBuild","link":"importBuild","description":"

Import a pre-build service

"},{"title":"module:Service.ITask","link":"ITask","description":"

Interface class for supporting tasker tasks in dataparty.\nTo add a task to dataparty service extend this class and implement\nthe Name, Description and Config members.

"},{"title":"module:Service.ITask.Config","link":"Config"},{"title":"module:Service.ITask.Description","link":"Description"},{"title":"module:Service.ITask.info","link":"info","description":"

Returns the task's Name, Description, and Config

"},{"title":"module:Service.ITask.Name","link":"Name"},{"title":"module:Service.ITask.TaskConfig","link":"TaskConfig"},{"title":"module:Service.ITask.TaskInfo","link":"TaskInfo"},{"title":"module:Service.RouterRunner.onRequest","link":"onRequest","description":"

Expressjs style way of calling an endpoint. The req will be passed to the router to select the appropritate endpoint

"},{"title":"module:Service.RunnerRouter","link":"RunnerRouter","description":"

A multi-domain drop in replacement for anywhere we use origin-router.Router.\nBy creating multiple dataparty ServiceRunners you can manage multiple parties\nand multiple services and merge them into either a single combined service. Or\nhost them as multiple seperate domains. Essentially, this allows the ServiceHost\nto be multi-tenant.

"},{"title":"module:Service.RunnerRouter.addRunner","link":"addRunner"},{"title":"module:Service.RunnerRouter.getRunnerByDomain","link":"getRunnerByDomain"},{"title":"module:Service.RunnerRouter.getRunnerByHostIdentity","link":"getRunnerByHostIdentity"},{"title":"module:Service.RunnerRouter.start","link":"start"},{"title":"module:Service.ServiceHost","link":"ServiceHost"},{"title":"module:Service.ServiceHost.apiApp","link":"apiApp","description":"

Express app

"},{"title":"module:Service.ServiceHost.router","link":"router","description":"

The router

"},{"title":"module:Service.ServiceHost.runner","link":"runner","description":"

Dataparty service runner

"},{"title":"module:Service.ServiceHost.start","link":"start","description":"

Start hosting services

"},{"title":"module:Service.ServiceHost.stop","link":"stop","description":"

Stop hosting services

"},{"title":"module:Service.ServiceRunner","link":"ServiceRunner","description":"

Sandboxed service runner. This runner uses the vm2 package to run end points in a fully isolated context.\nEndpoints, pre-middleware and post-middleware all run as independant precompiled VMScripts.

"},{"title":"module:Service.ServiceRunner.onRequest","link":"onRequest","description":"

Expressjs style way of calling an endpoint. The req will be passed to the router to select the appropritate endpoint

"},{"title":"module:Service.ServiceRunnerNode","link":"ServiceRunnerNode","description":"

Unsafe service runner. This service runner uses eval to run services, endpoints and tasks.\nThis provides only simple context seperation and does not do effective context isolation.\nThis should only be used where the service is knwon trustworthy. When the useNative option\nis set to true the service will run in the same context as this class with no isolation at all.

"},{"title":"module:Service.ServiceRunnerNode.onRequest","link":"onRequest","description":"

Expressjs style way of calling an endpoint. The req will be passed to the router to select the appropritate endpoint

"},{"title":"module:Topics","link":"Topics"},{"title":"module:Topics.LocalTopicHost","link":"LocalTopicHost","description":"

Implementation of ROS style pub/sub topics. This runs on a\nsingle thread/peer and can be shared to other peers. However,\nthis is a centralized implementation. So if the hosting node\nstops all topic traffic will halt as well.

"},{"title":"MongoQuery","link":"MongoQuery","description":"

generates a mongodb query doc from a dataparty query spec

"},{"title":"MongoQuery#getQueryDoc","link":"getQueryDoc","description":"

build mongo query doc from spec match tree

\n
    \n
  • explicitly 'and' top level of match tree
  • \n
  • search only returns msg metadata
  • \n
"},{"title":"ServiceRunnerNode#runTask","link":"runTask","description":"

Add a named task to the run queue

"}]} \ No newline at end of file diff --git a/docs/global.html b/docs/global.html index 50ce32c..f686d82 100644 --- a/docs/global.html +++ b/docs/global.html @@ -1,3 +1,3 @@ Global
On this page

Type Definitions

IdObj

Type:
  • Object
Properties
NameTypeDescription
idstring

mongo-id or UUID

typestring

Document type

\ No newline at end of file +
On this page

Type Definitions

IdObj

Type:
  • Object
Properties
NameTypeDescription
idstring

mongo-id or UUID

typestring

Document type

\ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 0d662ee..141d2f4 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,6 +1,6 @@ decentralized cloud framework for the web 3.0 generation
On this page

@dataparty/api

experimentallicense

decentralized cloud framework for the Web3.0 generation.

Design Goal

Dataparty services are able to run on servers, edge devices, or even directly in the browser or app. This means users of dataparty based apps can frequently run their own backend from within an app. By building this peer-to-peer functionality directly into the database ORM, dataparty/api saves significant effort for app makers.

Plugable

For many domains the exact performance characteristics of the database, communications and security matter a lot. All major systems are fairly pluggable so that additional drivers (db, comms etc) can be developed.

Features

Feature Roadmap 2023

A dataparty app/service typically consists of these parts:

  • Comms
    • We support everything from WebRTC, Websockets, HTTP to BLE and i2p/tor.
  • Config
    • Persist configuration in a number of ways.
  • Db
    • Select the database that makes sense for you, see database selection
    • Use one scheme across all db's
  • Party
    • The primary query interface. Abstracts the DBs into a common realtime-db interface. Partys can interact with local, remote and even peer-to-peer hosted DBs. Select the type of party that makes sense for you. See party selection
  • Service
    • RESTful endpoints and middleware, code once run everywhere. Expressjs style interface. Each endpoint can be run in its own sandbox, various types of isolation are supported and more are planned.
  • Topics
    • Streaming pub/sub that runs everywhere. Compatible with the ROS rosbridge 2.0 protocol.

Database Selection

DatabaseBrowserCordovaElectronEmbedded LinuxNode
LokijsyyyNR*NR*
ZangodbyyyP*P*
TingonP*yyy
MongonP*yyy

*NR - Not Recommended, but supported *P - Possibly. We're looking into it.

Example


+    
On this page

@dataparty/api

experimentallicense

decentralized cloud framework for the Web3.0 generation.

Design Goal

Dataparty services are able to run on servers, edge devices, or even directly in the browser or app. This means users of dataparty based apps can frequently run their own backend from within an app. By building this peer-to-peer functionality directly into the database ORM, dataparty/api saves significant effort for app makers.

Plugable

For many domains the exact performance characteristics of the database, communications and security matter a lot. All major systems are fairly pluggable so that additional drivers (db, comms etc) can be developed.

Features

Feature Roadmap 2023

A dataparty app/service typically consists of these parts:

  • Comms
    • We support everything from WebRTC, Websockets, HTTP to BLE and i2p/tor.
  • Config
    • Persist configuration in a number of ways.
  • Db
    • Select the database that makes sense for you, see database selection
    • Use one scheme across all db's
  • Party
    • The primary query interface. Abstracts the DBs into a common realtime-db interface. Partys can interact with local, remote and even peer-to-peer hosted DBs. Select the type of party that makes sense for you. See party selection
  • Service
    • RESTful endpoints and middleware, code once run everywhere. Expressjs style interface. Each endpoint can be run in its own sandbox, various types of isolation are supported and more are planned.
  • Topics
    • Streaming pub/sub that runs everywhere. Compatible with the ROS rosbridge 2.0 protocol.

Database Selection

DatabaseBrowserCordovaElectronEmbedded LinuxNode
LokijsyyyNR*NR*
ZangodbyyyP*P*
TingonP*yyy
MongonP*yyy

*NR - Not Recommended, but supported *P - Possibly. We're looking into it.

Example


 const Dataparty = require('@dataparty/api')
 
 
@@ -62,4 +62,4 @@
   console.log(await getUser('renamed-tester'))
 
 }
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/module-Comms.BLEPeerClient.html b/docs/module-Comms.BLEPeerClient.html index 39d5404..a26191c 100644 --- a/docs/module-Comms.BLEPeerClient.html +++ b/docs/module-Comms.BLEPeerClient.html @@ -1,3 +1,3 @@ Class: BLEPeerClient
On this page

Comms. BLEPeerClient

\ No newline at end of file +
On this page

Comms. BLEPeerClient

\ No newline at end of file diff --git a/docs/module-Comms.I2pSocketComms.html b/docs/module-Comms.I2pSocketComms.html index c6f7643..ba0fb60 100644 --- a/docs/module-Comms.I2pSocketComms.html +++ b/docs/module-Comms.I2pSocketComms.html @@ -1,3 +1,3 @@ Class: I2pSocketComms
On this page

Comms. I2pSocketComms

\ No newline at end of file +
On this page

Comms. I2pSocketComms

\ No newline at end of file diff --git a/docs/module-Comms.ISocketComms.html b/docs/module-Comms.ISocketComms.html index 9b03736..4c868ff 100644 --- a/docs/module-Comms.ISocketComms.html +++ b/docs/module-Comms.ISocketComms.html @@ -1,3 +1,3 @@ Interface: ISocketComms
On this page

Comms. ISocketComms

\ No newline at end of file +
On this page

Comms. ISocketComms

\ No newline at end of file diff --git a/docs/module-Comms.LoopbackChannel.html b/docs/module-Comms.LoopbackChannel.html index 35f7171..2de5014 100644 --- a/docs/module-Comms.LoopbackChannel.html +++ b/docs/module-Comms.LoopbackChannel.html @@ -1,3 +1,3 @@ Class: LoopbackChannel
On this page

Comms. LoopbackChannel

\ No newline at end of file +
On this page

Comms. LoopbackChannel

\ No newline at end of file diff --git a/docs/module-Comms.LoopbackComms.html b/docs/module-Comms.LoopbackComms.html index 0920636..195be61 100644 --- a/docs/module-Comms.LoopbackComms.html +++ b/docs/module-Comms.LoopbackComms.html @@ -1,3 +1,3 @@ Class: LoopbackComms
On this page

Comms. LoopbackComms

\ No newline at end of file +
On this page

Comms. LoopbackComms

\ No newline at end of file diff --git a/docs/module-Comms.LoopbackSocket.html b/docs/module-Comms.LoopbackSocket.html index 2281c45..6fe6d98 100644 --- a/docs/module-Comms.LoopbackSocket.html +++ b/docs/module-Comms.LoopbackSocket.html @@ -1,3 +1,3 @@ Class: LoopbackSocket
On this page

Comms. LoopbackSocket

\ No newline at end of file +
On this page

Comms. LoopbackSocket

\ No newline at end of file diff --git a/docs/module-Comms.PeerComms.html b/docs/module-Comms.PeerComms.html index fc8aa22..647bedd 100644 --- a/docs/module-Comms.PeerComms.html +++ b/docs/module-Comms.PeerComms.html @@ -1,3 +1,3 @@ Class: PeerComms
On this page

Comms. PeerComms

\ No newline at end of file +
On this page

Comms. PeerComms

\ No newline at end of file diff --git a/docs/module-Comms.RTCSocketComms.html b/docs/module-Comms.RTCSocketComms.html index 1aca198..923beb4 100644 --- a/docs/module-Comms.RTCSocketComms.html +++ b/docs/module-Comms.RTCSocketComms.html @@ -1,3 +1,3 @@ Class: RTCSocketComms
On this page
\ No newline at end of file +
On this page
\ No newline at end of file diff --git a/docs/module-Comms.RestComms.html b/docs/module-Comms.RestComms.html index 3f5ce36..adc3ee5 100644 --- a/docs/module-Comms.RestComms.html +++ b/docs/module-Comms.RestComms.html @@ -1,3 +1,3 @@ Class: RestComms
On this page

Comms. RestComms

\ No newline at end of file +
On this page

Comms. RestComms

\ No newline at end of file diff --git a/docs/module-Comms.WebsocketComms.html b/docs/module-Comms.WebsocketComms.html index 81990db..bd1a694 100644 --- a/docs/module-Comms.WebsocketComms.html +++ b/docs/module-Comms.WebsocketComms.html @@ -1,3 +1,3 @@ Class: WebsocketComms
On this page
\ No newline at end of file +
On this page
\ No newline at end of file diff --git a/docs/module-Comms.html b/docs/module-Comms.html index 0262d9d..8b4a199 100644 --- a/docs/module-Comms.html +++ b/docs/module-Comms.html @@ -1,3 +1,3 @@ Module: Comms
On this page
\ No newline at end of file +
On this page
\ No newline at end of file diff --git a/docs/module-Config.IConfig.html b/docs/module-Config.IConfig.html index ddb9cd0..c2f24aa 100644 --- a/docs/module-Config.IConfig.html +++ b/docs/module-Config.IConfig.html @@ -1,3 +1,3 @@ Interface: IConfig
On this page

Config. IConfig

Methods

(async, static) clear()

(async, static) exists(key)

Parameters:
NameTypeDescription
keystring

(async, static) read(key)

Parameters:
NameTypeDescription
keystring

(async, static) readAll() → {object}

Returns:
Type: 
object

(async, static) save()

(async, static) start()

(async, static) write(key, data)

Parameters:
NameTypeDescription
keystring
dataobject
\ No newline at end of file +
On this page

Config. IConfig

Methods

(async, static) clear()

(async, static) exists(key)

Parameters:
NameTypeDescription
keystring

(async, static) read(key)

Parameters:
NameTypeDescription
keystring

(async, static) readAll() → {object}

Returns:
Type: 
object

(async, static) save()

(async, static) start()

(async, static) write(key, data)

Parameters:
NameTypeDescription
keystring
dataobject
\ No newline at end of file diff --git a/docs/module-Config.JsonFileConfig.html b/docs/module-Config.JsonFileConfig.html index 3c9ce52..046edd6 100644 --- a/docs/module-Config.JsonFileConfig.html +++ b/docs/module-Config.JsonFileConfig.html @@ -1,3 +1,3 @@ Class: JsonFileConfig
On this page

Config. JsonFileConfig

\ No newline at end of file +
On this page

Config. JsonFileConfig

\ No newline at end of file diff --git a/docs/module-Config.LocalStorageConfig.html b/docs/module-Config.LocalStorageConfig.html index 4ce6bec..c9c158d 100644 --- a/docs/module-Config.LocalStorageConfig.html +++ b/docs/module-Config.LocalStorageConfig.html @@ -1,3 +1,3 @@ Class: LocalStorageConfig
On this page

Config. LocalStorageConfig

\ No newline at end of file +
On this page

Config. LocalStorageConfig

\ No newline at end of file diff --git a/docs/module-Config.MemoryConfig.html b/docs/module-Config.MemoryConfig.html index 522117e..22a016f 100644 --- a/docs/module-Config.MemoryConfig.html +++ b/docs/module-Config.MemoryConfig.html @@ -1,3 +1,3 @@ Class: MemoryConfig
On this page

Config. MemoryConfig

\ No newline at end of file +
On this page

Config. MemoryConfig

\ No newline at end of file diff --git a/docs/module-Config.NconfConfig.html b/docs/module-Config.NconfConfig.html index 9124b0a..6a8f322 100644 --- a/docs/module-Config.NconfConfig.html +++ b/docs/module-Config.NconfConfig.html @@ -1,3 +1,3 @@ Class: NconfConfig
On this page

Config. NconfConfig

\ No newline at end of file +
On this page

Config. NconfConfig

\ No newline at end of file diff --git a/docs/module-Config.SecureConfig.html b/docs/module-Config.SecureConfig.html index de10596..96d2149 100644 --- a/docs/module-Config.SecureConfig.html +++ b/docs/module-Config.SecureConfig.html @@ -1,3 +1,3 @@ Class: SecureConfig
On this page

Config. SecureConfig

new SecureConfig(id, config, timeoutMs, includeActivity, argon)

A secure configuration. This uses an underlying IConfig for storage. Multiple secure configs can be placed within the same IConfig so long as different id is set. By default pbkdf2 is used to generate NaCl keys. If argon is provided then argon2 will be used to generate the NaCl keys. Applications should use argon2.

Parameters:
NameTypeDescription
idstring

The id of this secure config. Multiple secure configs can be stored within a single IConfig

configIConfig

The underlying IConfig to use for storage

timeoutMsnumber

Timeout since last unlock, after which the config will be locked. Defaults to 5 minutes.

includeActivityboolean

When set to true the timeout is reset after any read/write activity. Defaults to true

argonArgon2

Instance of argon2 from either npm:argon2 or npm:argon2-browser

Methods

(async, static) clear()

(async, static) isInitialized() → {boolean}

Checks if the secure config has initialized with a password or key

Returns:
Type: 
boolean

(static) isLocked() → {boolean}

Checks if the secure config is locked. If not locked the secure config can be used without blocking waiting for user to unlock.

Returns:
Type: 
boolean

(static) lock()

Locks the secure config

(async, static) read(key)

Parameters:
NameTypeDescription
keystring

(async, static) readAll() → {object}

Returns:
Type: 
object

(async, static) save()

(async, static) setIdentity(key, defaults)

Initialize the secure config with a key

Parameters:
NameTypeDescription
keydataparty_crypto/IKey
defaultsobject

(async, static) setPassword(password, defaults)

Initialize the secure config with a password

Parameters:
NameTypeDescription
passwordstring
defaultsobject

(async, static) start()

Start the secure storage

(async, static) unlock(password)

Unlocks the secure config

Parameters:
NameTypeDescription
passwordstring

(async, static) waitForUnlocked(reason)

Wait for config to be unlocked

Parameters:
NameTypeDescription
reasonstring

Optional reason message if config is locked

(async, static) write(key, data)

Parameters:
NameTypeDescription
keystring
dataobject

Events

blocked

An read/write operation has been blocked due to the secure config being locked.

intialized

The secure config has been successfully initialized with a passowrd or key.

locked

The secure config has been locked

ready

Ready event. The secure config is ready to be unlocked and have configuration values read or written.

setup-required

Setup required event. The secure config has not yet has a password or key configured.

unlocked

The secure config has been unlocked

\ No newline at end of file +
On this page

Config. SecureConfig

new SecureConfig(id, config, timeoutMs, includeActivity, argon)

A secure configuration. This uses an underlying IConfig for storage. Multiple secure configs can be placed within the same IConfig so long as different id is set. By default pbkdf2 is used to generate NaCl keys. If argon is provided then argon2 will be used to generate the NaCl keys. Applications should use argon2.

Parameters:
NameTypeDescription
idstring

The id of this secure config. Multiple secure configs can be stored within a single IConfig

configIConfig

The underlying IConfig to use for storage

timeoutMsnumber

Timeout since last unlock, after which the config will be locked. Defaults to 5 minutes.

includeActivityboolean

When set to true the timeout is reset after any read/write activity. Defaults to true

argonArgon2

Instance of argon2 from either npm:argon2 or npm:argon2-browser

Methods

(async, static) clear()

(async, static) isInitialized() → {boolean}

Checks if the secure config has initialized with a password or key

Returns:
Type: 
boolean

(static) isLocked() → {boolean}

Checks if the secure config is locked. If not locked the secure config can be used without blocking waiting for user to unlock.

Returns:
Type: 
boolean

(static) lock()

Locks the secure config

(async, static) read(key)

Parameters:
NameTypeDescription
keystring

(async, static) readAll() → {object}

Returns:
Type: 
object

(async, static) save()

(async, static) setIdentity(key, defaults)

Initialize the secure config with a key

Parameters:
NameTypeDescription
keydataparty_crypto/IKey
defaultsobject

(async, static) setPassword(password, defaults)

Initialize the secure config with a password

Parameters:
NameTypeDescription
passwordstring
defaultsobject

(async, static) start()

Start the secure storage

(async, static) unlock(password)

Unlocks the secure config

Parameters:
NameTypeDescription
passwordstring

(async, static) waitForUnlocked(reason)

Wait for config to be unlocked

Parameters:
NameTypeDescription
reasonstring

Optional reason message if config is locked

(async, static) write(key, data)

Parameters:
NameTypeDescription
keystring
dataobject

Events

blocked

An read/write operation has been blocked due to the secure config being locked.

intialized

The secure config has been successfully initialized with a passowrd or key.

locked

The secure config has been locked

ready

Ready event. The secure config is ready to be unlocked and have configuration values read or written.

setup-required

Setup required event. The secure config has not yet has a password or key configured.

unlocked

The secure config has been unlocked

\ No newline at end of file diff --git a/docs/module-Config.html b/docs/module-Config.html index 5c57b70..4bbf338 100644 --- a/docs/module-Config.html +++ b/docs/module-Config.html @@ -1,3 +1,3 @@ Module: Config
On this page
\ No newline at end of file +
On this page
\ No newline at end of file diff --git a/docs/module-Db.IDb.html b/docs/module-Db.IDb.html index ff0bd9d..3cd8e8a 100644 --- a/docs/module-Db.IDb.html +++ b/docs/module-Db.IDb.html @@ -1,3 +1,3 @@ Interface: IDb
On this page

Db. IDb

\ No newline at end of file +
On this page

Db. IDb

\ No newline at end of file diff --git a/docs/module-Db.ISchema.html b/docs/module-Db.ISchema.html index 3004060..afed51c 100644 --- a/docs/module-Db.ISchema.html +++ b/docs/module-Db.ISchema.html @@ -1,3 +1,3 @@ Interface: ISchema
On this page

Db. ISchema

\ No newline at end of file +
On this page

Db. ISchema

\ No newline at end of file diff --git a/docs/module-Db.LokiDb.html b/docs/module-Db.LokiDb.html index dedf6ff..89c6a6b 100644 --- a/docs/module-Db.LokiDb.html +++ b/docs/module-Db.LokiDb.html @@ -1,3 +1,3 @@ Class: LokiDb
On this page

Db. LokiDb

\ No newline at end of file +
On this page

Db. LokiDb

\ No newline at end of file diff --git a/docs/module-Db.TingoDb.html b/docs/module-Db.TingoDb.html index 5cd0745..699a766 100644 --- a/docs/module-Db.TingoDb.html +++ b/docs/module-Db.TingoDb.html @@ -1,3 +1,3 @@ Class: TingoDb
On this page

Db. TingoDb

new TingoDb()

Ideal for extremely large datasets with frequent document additions. Has a very efficient append-only file system driver which is ideal for embedded platforms. All database indexes must fit into RAM and are re-computed at db load time.

Extends

\ No newline at end of file +
On this page

Db. TingoDb

new TingoDb()

Ideal for extremely large datasets with frequent document additions. Has a very efficient append-only file system driver which is ideal for embedded platforms. All database indexes must fit into RAM and are re-computed at db load time.

Extends

\ No newline at end of file diff --git a/docs/module-Db.ZangoDb.html b/docs/module-Db.ZangoDb.html index 4456c4b..a179fad 100644 --- a/docs/module-Db.ZangoDb.html +++ b/docs/module-Db.ZangoDb.html @@ -1,3 +1,3 @@ Class: ZangoDb
On this page

Db. ZangoDb

\ No newline at end of file +
On this page

Db. ZangoDb

\ No newline at end of file diff --git a/docs/module-Db.html b/docs/module-Db.html index 965bd5e..21e59b9 100644 --- a/docs/module-Db.html +++ b/docs/module-Db.html @@ -1,3 +1,3 @@ Module: Db
On this page
\ No newline at end of file +
On this page
\ No newline at end of file diff --git a/docs/module-Party.CloudParty.html b/docs/module-Party.CloudParty.html index 7d9de3a..8d53525 100644 --- a/docs/module-Party.CloudParty.html +++ b/docs/module-Party.CloudParty.html @@ -1,3 +1,3 @@ Class: CloudParty
On this page

Party. CloudParty

\ No newline at end of file +
On this page

Party. CloudParty

\ No newline at end of file diff --git a/docs/module-Party.DocumentFactory.html b/docs/module-Party.DocumentFactory.html index 12ab88f..8dae718 100644 --- a/docs/module-Party.DocumentFactory.html +++ b/docs/module-Party.DocumentFactory.html @@ -1,3 +1,3 @@ Class: DocumentFactory
On this page

Party. DocumentFactory

new DocumentFactory()

Represents document schemas mapped to contructor claasses which extend IDocument

Extends

  • EventEmitter

Methods

(static) addFactory(type, factory)

Parameters:
NameTypeDescription
type*
factory*

(static) getDocument(type, id, data) → {module:Party.IDocument}

Parameters:
NameTypeDescription
typestring
idstring
dataObject
Returns:
Type: 
module:Party.IDocument

(static) getFactories()

(static) getFactory(type)

Parameters:
NameTypeDescription
type*

(static) getTypes()

(static) getValidators()

(async, static) hydrate(found)

Parameters:
NameTypeDescription
found*

(async, static) validate(type, data)

Parameters:
NameTypeDescription
type*
data*
\ No newline at end of file +
On this page

Party. DocumentFactory

new DocumentFactory()

Represents document schemas mapped to contructor claasses which extend IDocument

Extends

  • EventEmitter

Methods

(static) addFactory(type, factory)

Parameters:
NameTypeDescription
type*
factory*

(static) getDocument(type, id, data) → {module:Party.IDocument}

Parameters:
NameTypeDescription
typestring
idstring
dataObject
Returns:
Type: 
module:Party.IDocument

(static) getFactories()

(static) getFactory(type)

Parameters:
NameTypeDescription
type*

(static) getTypes()

(static) getValidators()

(async, static) hydrate(found)

Parameters:
NameTypeDescription
found*

(async, static) validate(type, data)

Parameters:
NameTypeDescription
type*
data*
\ No newline at end of file diff --git a/docs/module-Party.IDocument.html b/docs/module-Party.IDocument.html index a834806..fe02d05 100644 --- a/docs/module-Party.IDocument.html +++ b/docs/module-Party.IDocument.html @@ -1,3 +1,3 @@ Class: IDocument
On this page

Party. IDocument

new IDocument(options)

Represents a document with caching and local+remote change notifications

Parameters:
NameTypeDescription
optionsobject
Properties
NameTypeDescription
partyDataParty
idstring
typestring
dataobject
followcacheboolean

Extends

  • EventEmitter

Members

(static) cleanData :object

document data with no library added fields

Type:
  • object

(static) data :object

entire document

Type:
  • object

(static) Document :IDocument

Type:
  • IDocument

(static) id :string

Document mongo-id

Type:
  • string

(static) idObj :IdObj

Document id object

Type:

(static) idString :sting

Document id string in format <type>:<mongo-id>

Type:
  • sting

(static) revision :string

Document revision string

Type:
  • string

(static) type :string

Document type string

Type:
  • string

Methods

(async, static) create(party, document)

Parameters:
NameTypeDescription
partymoddule:Party.IParty
document*
Returns:

(static) getData()

(async, static) mergeData(input) → {object}

Parameters:
NameTypeDescription
inputobject
Returns:
Type: 
object

(async, static) pull(flushcache)

Parameters:
NameTypeDescription
flushcacheboolean

Update local cache as well

(async, static) remove()

(async, static) save()

(async, static) setData(input) → {object}

Parameters:
NameTypeDescription
inputobject
Returns:
Type: 
object

(static) unwatch(cbopt)

Stop watching for remote document changes

Parameters:
NameTypeAttributesDescription
cbfunction<optional>

Optional Change event callback function

(async, static) watch(autopull, flushcache, cbopt)

Parameters:
NameTypeAttributesDescription
autopullboolean
flushcacheboolean
cbfunction<optional>

Optional Change event callback function

(static) watchField(field, valueopt, cb)

Watch a field for changes. If value is supplied watches for field and value to match.

Parameters:
NameTypeAttributesDescription
fieldstring

Field path to watch for changes

value*<optional>

Match value

cbfunction

Callback function

Events

change

Document change Event - This is event is triggered when a document has been modified on the remote service

Type:
  • object

create

Document create Event - This event is triggered after a document has been created and applied to the backing cache of Document.data. If Document.followcache is true the document doc has also accepted the change.

Type:
  • module:Party.IDocument.Event

field

Field change event. This is emitted as field.[FIELD_PATH]

Type:
  • object
Properties
NameTypeDescription
doc

The changed document

field

The changed FIELDPATH

old

The old field value

new

The new field value

expected

The expected field value

remove

Document remove Event - This event is triggered after a document has been removed and applied to the backing cache of Document.data. If Document.followcache is true the document doc has also accepted the change.

Type:
  • module:Party.IDocument.Event

update

Document update Event - This event is triggered after a change has been applied to the backing cache of Document.data. If Document.followcache is true the document doc has also accepted the change.

Type:
  • module:Party.IDocument.Event

value

Document value Event - This event is triggered after a change has been applied to the backing cache of Document.data. Only fired when Document.followcache is true.

Type:
  • Document
\ No newline at end of file +
On this page

Party. IDocument

new IDocument(options)

Represents a document with caching and local+remote change notifications

Parameters:
NameTypeDescription
optionsobject
Properties
NameTypeDescription
partyDataParty
idstring
typestring
dataobject
followcacheboolean

Extends

  • EventEmitter

Members

(static) cleanData :object

document data with no library added fields

Type:
  • object

(static) data :object

entire document

Type:
  • object

(static) Document :IDocument

Type:
  • IDocument

(static) hash :object

hash of document.data using sha256

Type:
  • object

(static) id :string

Document mongo-id

Type:
  • string

(static) idObj :IdObj

Document id object

Type:

(static) idString :sting

Document id string in format <type>:<mongo-id>

Type:
  • sting

(static) revision :string

Document revision string

Type:
  • string

(static) type :string

Document type string

Type:
  • string

Methods

(async, static) create(party, document)

Parameters:
NameTypeDescription
partymoddule:Party.IParty
document*
Returns:

(static) getData()

(async, static) mergeData(input) → {object}

Parameters:
NameTypeDescription
inputobject
Returns:
Type: 
object

(async, static) pull(flushcache)

Parameters:
NameTypeDescription
flushcacheboolean

Update local cache as well

(async, static) remove()

(async, static) save()

(async, static) setData(input) → {object}

Parameters:
NameTypeDescription
inputobject
Returns:
Type: 
object

(static) unwatch(cbopt)

Stop watching for remote document changes

Parameters:
NameTypeAttributesDescription
cbfunction<optional>

Optional Change event callback function

(async, static) watch(autopull, flushcache, cbopt)

Parameters:
NameTypeAttributesDescription
autopullboolean
flushcacheboolean
cbfunction<optional>

Optional Change event callback function

(static) watchField(field, valueopt, cb)

Watch a field for changes. If value is supplied watches for field and value to match.

Parameters:
NameTypeAttributesDescription
fieldstring

Field path to watch for changes

value*<optional>

Match value

cbfunction

Callback function

Events

change

Document change Event - This is event is triggered when a document has been modified on the remote service

Type:
  • object

create

Document create Event - This event is triggered after a document has been created and applied to the backing cache of Document.data. If Document.followcache is true the document doc has also accepted the change.

Type:
  • module:Party.IDocument.Event

field

Field change event. This is emitted as field.[FIELD_PATH]

Type:
  • object
Properties
NameTypeDescription
doc

The changed document

field

The changed FIELDPATH

old

The old field value

new

The new field value

expected

The expected field value

remove

Document remove Event - This event is triggered after a document has been removed and applied to the backing cache of Document.data. If Document.followcache is true the document doc has also accepted the change.

Type:
  • module:Party.IDocument.Event

update

Document update Event - This event is triggered after a change has been applied to the backing cache of Document.data. If Document.followcache is true the document doc has also accepted the change.

Type:
  • module:Party.IDocument.Event

value

Document value Event - This event is triggered after a change has been applied to the backing cache of Document.data. Only fired when Document.followcache is true.

Type:
  • Document
\ No newline at end of file diff --git a/docs/module-Party.IParty.html b/docs/module-Party.IParty.html index 7e9bed7..e63d864 100644 --- a/docs/module-Party.IParty.html +++ b/docs/module-Party.IParty.html @@ -1,3 +1,3 @@ Class: IParty
On this page

Party. IParty

new IParty()

Parameters:
NameTypeDescription
options.configmodule:Config.IConfig
options.cachemodule:Party.LokiCache
options.noCacheboolean
options.commsmodule:Comms.ISocketComms
options.modelObject
options.factoriesObject
options.documentClassmodule:Party.IDocument
options.qbmodule:Party.Qb

Members

(static) actor :IdObj

Type:

(static) actors :Array.<IdObj>

Type:

(static) Document :IDocument

Type:
  • IDocument

(static) factory :DocumentFactory

Type:
  • DocumentFactory

(static) identity :module:dataparty/Types.Identity

Type:
  • module:dataparty/Types.Identity

(static) privateIdentity :module:dataparty/Types.Identity

Type:
  • module:dataparty/Types.Identity

(static) ROSLIB :ROSLIB

Type:
  • ROSLIB

(static) types

Methods

(async, static) call()

(async, static) create()

(async, static) createDocument()

(async, static) decrypt(reply, expectedSender, expectClearTextReply)

Parameters:
NameTypeDescription
replydataparty_crypto.Message
expectedSenderdataparty_crypto.Identity
expectClearTextReplyboolean

(async, static) encrypt(data, to) → {dataparty_crypto.Message}

Parameters:
NameTypeDescription
dataany
todataparty_crypto.Identity
Returns:
Type: 
dataparty_crypto.Message

(static) find() → {module:Party.Query}

Starts a query

Returns:
Type: 
module:Party.Query

(static) hasActor()

(static) hasIdentity()

(async, static) loadActor()

(async, static) loadIdentity()

(async, static) remove()

(async, static) resetIdentity()

(async, static) start()

(async, static) update()

\ No newline at end of file +
On this page

Party. IParty

new IParty()

Parameters:
NameTypeDescription
options.configmodule:Config.IConfig
options.cachemodule:Party.LokiCache
options.noCacheboolean
options.commsmodule:Comms.ISocketComms
options.modelObject
options.factoriesObject
options.documentClassmodule:Party.IDocument
options.qbmodule:Party.Qb

Members

(static) actor :IdObj

Type:

(static) actors :Array.<IdObj>

Type:

(static) Document :IDocument

Type:
  • IDocument

(static) factory :DocumentFactory

Type:
  • DocumentFactory

(static) identity :module:dataparty/Types.Identity

Type:
  • module:dataparty/Types.Identity

(static) privateIdentity :module:dataparty/Types.Identity

Type:
  • module:dataparty/Types.Identity

(static) ROSLIB :ROSLIB

Type:
  • ROSLIB

(static) types

Methods

(async, static) call()

(async, static) create()

(async, static) createDocument()

(async, static) decrypt(reply, expectedSender, expectClearTextReply)

Parameters:
NameTypeDescription
replydataparty_crypto.Message
expectedSenderdataparty_crypto.Identity
expectClearTextReplyboolean

(async, static) encrypt(data, to) → {dataparty_crypto.Message}

Parameters:
NameTypeDescription
dataany
todataparty_crypto.Identity
Returns:
Type: 
dataparty_crypto.Message

(static) find() → {module:Party.Query}

Starts a query

Returns:
Type: 
module:Party.Query

(static) hasActor()

(static) hasIdentity()

(async, static) loadActor()

(async, static) loadIdentity()

(async, static) remove()

(async, static) resetIdentity()

(async, static) start()

(async, static) update()

\ No newline at end of file diff --git a/docs/module-Party.LokiCache.html b/docs/module-Party.LokiCache.html index e7c71ae..e5e5138 100644 --- a/docs/module-Party.LokiCache.html +++ b/docs/module-Party.LokiCache.html @@ -1,3 +1,3 @@ Class: LokiCache
On this page

Party. LokiCache

\ No newline at end of file +
On this page

Party. LokiCache

\ No newline at end of file diff --git a/docs/module-Party.LokiParty.html b/docs/module-Party.LokiParty.html index 7210703..ae8a594 100644 --- a/docs/module-Party.LokiParty.html +++ b/docs/module-Party.LokiParty.html @@ -1,3 +1,3 @@ Class: LokiParty
On this page

Party. LokiParty

new LokiParty(path, dbAdapter, lokiOptions)

A local party based on LokiJS.

Works great for front end. Doesn't scale well for centralized server use and does not have efficient file system representation for many embedded applications. Overall this driver is RAM bound holds the entire DB in memory. When running on filesystems this driver re-writes the entire collection during save operations.

Parameters:
NameTypeDescription
pathstring

Path on filesystem to lokijs db file

dbAdapterLokiAdapater

Lokijs db adapter, see: http://techfort.github.io/LokiJS/tutorial-Persistence%20Adapters.html

lokiOptionsObject

Options to pass to lokijs see: http://techfort.github.io/LokiJS/Loki.html

Extends

Methods

(static) handleCall(ask)

Parameters:
NameTypeDescription
askObject
Returns:

(static) start()

\ No newline at end of file +
On this page

Party. LokiParty

new LokiParty(path, dbAdapter, lokiOptions)

A local party based on LokiJS.

Works great for front end. Doesn't scale well for centralized server use and does not have efficient file system representation for many embedded applications. Overall this driver is RAM bound holds the entire DB in memory. When running on filesystems this driver re-writes the entire collection during save operations.

Parameters:
NameTypeDescription
pathstring

Path on filesystem to lokijs db file

dbAdapterLokiAdapater

Lokijs db adapter, see: http://techfort.github.io/LokiJS/tutorial-Persistence%20Adapters.html

lokiOptionsObject

Options to pass to lokijs see: http://techfort.github.io/LokiJS/Loki.html

Extends

Methods

(static) handleCall(ask)

Parameters:
NameTypeDescription
askObject
Returns:

(static) start()

\ No newline at end of file diff --git a/docs/module-Party.MongoParty.html b/docs/module-Party.MongoParty.html index 6d54c1b..ba8cb09 100644 --- a/docs/module-Party.MongoParty.html +++ b/docs/module-Party.MongoParty.html @@ -1,3 +1,3 @@ Class: MongoParty
On this page

Party. MongoParty

\ No newline at end of file +
On this page

Party. MongoParty

\ No newline at end of file diff --git a/docs/module-Party.PeerParty.html b/docs/module-Party.PeerParty.html index 1403271..c06754f 100644 --- a/docs/module-Party.PeerParty.html +++ b/docs/module-Party.PeerParty.html @@ -1,3 +1,3 @@ Class: PeerParty
On this page

Party. PeerParty

new PeerParty()

Parameters:
NameTypeDescription
options.commsmodule:Comms.ISocketComms
options.hostPartyboolean

Is this instance the host of the peer connection?

options.hostRunnermodule:Service.HostRunner
options.qbOptions.debounceInteger

Amount of milliseconds to wait before sending a query. More than one query can be sent to the server in a single exchange. This defaults to 10ms.

options.qbOptions.find_dedupboolean

Set if duplicate queries should be merged into a single network request. Defaults to true

options.qbOptions.timeoutInteger

Time in milliseconds before a query is considered timedout. Defaults to 10seconds

Extends

\ No newline at end of file +
On this page

Party. PeerParty

new PeerParty()

Parameters:
NameTypeDescription
options.commsmodule:Comms.ISocketComms
options.hostPartyboolean

Is this instance the host of the peer connection?

options.hostRunnermodule:Service.HostRunner
options.qbOptions.debounceInteger

Amount of milliseconds to wait before sending a query. More than one query can be sent to the server in a single exchange. This defaults to 10ms.

options.qbOptions.find_dedupboolean

Set if duplicate queries should be merged into a single network request. Defaults to true

options.qbOptions.timeoutInteger

Time in milliseconds before a query is considered timedout. Defaults to 10seconds

Extends

\ No newline at end of file diff --git a/docs/module-Party.Query.html b/docs/module-Party.Query.html index c83f476..b8bab86 100644 --- a/docs/module-Party.Query.html +++ b/docs/module-Party.Query.html @@ -1,3 +1,3 @@ Class: Query
On this page

Party. Query

new Query(qb, model)

Parameters:
NameTypeDescription
qbmodule:Party.qb
modelmodule:Party.DocumentFactory

Methods

(static) all()

matches a list that is a superset of given list

Parameters:
TypeDescription

(static) and()

following path segments will be anded (default behavior)

Returns:

(static) contains(value)

Check if field contains value

Parameters:
NameTypeDescription
value*
Returns:

(static) dna()

Closes scope of most recent and

Returns:

(static) elem()

list operators -> subtype of match tree nodes -> most recent .where('param') path must be list for these to match searches for a single element of list matching all following conditions between elem .. mele nodes where('path') calls are relative to param path scope at opening of element match

(static) equals(value)

Check if field equals value

Parameters:
NameTypeDescription
value*
Returns:

(async, static) exec(hydrate)

return a promise resolving to result of query

Parameters:
NameTypeDescription
hydrateboolean
Returns:

(static) exists(flag)

Check if field exists

Parameters:
NameTypeDescription
flag*
Returns:

(static) gt(value)

Check if field is greater than value

Parameters:
NameTypeDescription
value*
Returns:

(static) id(id)

query for single msg by given id prereq -> type (not types) all other query ops (except type) will be ignored

Parameters:
NameTypeDescription
idstring

(static) ids(…ids)

query for a list of msgs by given ids prereq -> type (not types) all other query ops (except type) will be ignored

Parameters:
NameTypeAttributesDescription
idsany<repeatable>
Returns:

(static) in(…values)

Check if field is in list of values

Parameters:
NameTypeAttributesDescription
valuesany<repeatable>
Returns:

(static) limit(count)

limit # of msgs returned by query to a maximum of count

Parameters:
NameTypeDescription
count*
Returns:

(static) lt(value)

Check if field is less than value

Parameters:
NameTypeDescription
value*
Returns:

(static) mele()

Close elem function stack

(static) or()

The following path segments will be or'ed

Returns:

(static) owner(type, id)

restrict query to msgs with owner matching given type, id pair

Parameters:
NameTypeDescription
type*
id*
Returns:

(static) regex(value)

Check if field is matched by regex

Parameters:
NameTypeDescription
value*
Returns:

(static) ro()

Close scope of most recent or

Returns:

(static) seelct(filter)

filter fields from parameters of returned msgs

Parameters:
NameTypeDescription
filter*
Returns:

(static) size(count)

matches list with exactly count items

Parameters:
NameTypeDescription
countInteger

(static) sort(param, direction)

sort returned msgs on given param path (leading '-' reverses sort)

Parameters:
NameTypeDescription
param*
direction*
Returns:

(static) toJSON() → {Object}

Returns:
Type: 
Object

(static) type(type) → {module:Party.Query}

restrict query to msgs of given type

Parameters:
NameTypeDescription
typestring

Type name

Returns:
Type: 
module:Party.Query

(static) types(…types)

restrict query to msgs of given types not compatible with type

Parameters:
NameTypeAttributesDescription
typesstring<repeatable>
Returns:

(static) where(param)

sets context for following operations to given param path

Parameters:
NameTypeDescription
paramstring

Path to field

\ No newline at end of file +
On this page

Party. Query

new Query(qb, model)

Parameters:
NameTypeDescription
qbmodule:Party.qb
modelmodule:Party.DocumentFactory

Methods

(static) all()

matches a list that is a superset of given list

Parameters:
TypeDescription

(static) and()

following path segments will be anded (default behavior)

Returns:

(static) contains(value)

Check if field contains value

Parameters:
NameTypeDescription
value*
Returns:

(static) dna()

Closes scope of most recent and

Returns:

(static) elem()

list operators -> subtype of match tree nodes -> most recent .where('param') path must be list for these to match searches for a single element of list matching all following conditions between elem .. mele nodes where('path') calls are relative to param path scope at opening of element match

(static) equals(value)

Check if field equals value

Parameters:
NameTypeDescription
value*
Returns:

(async, static) exec(hydrate)

return a promise resolving to result of query

Parameters:
NameTypeDescription
hydrateboolean
Returns:

(static) exists(flag)

Check if field exists

Parameters:
NameTypeDescription
flag*
Returns:

(static) gt(value)

Check if field is greater than value

Parameters:
NameTypeDescription
value*
Returns:

(static) id(id)

query for single msg by given id prereq -> type (not types) all other query ops (except type) will be ignored

Parameters:
NameTypeDescription
idstring

(static) ids(…ids)

query for a list of msgs by given ids prereq -> type (not types) all other query ops (except type) will be ignored

Parameters:
NameTypeAttributesDescription
idsany<repeatable>
Returns:

(static) in(…values)

Check if field is in list of values

Parameters:
NameTypeAttributesDescription
valuesany<repeatable>
Returns:

(static) limit(count)

limit # of msgs returned by query to a maximum of count

Parameters:
NameTypeDescription
count*
Returns:

(static) lt(value)

Check if field is less than value

Parameters:
NameTypeDescription
value*
Returns:

(static) mele()

Close elem function stack

(static) or()

The following path segments will be or'ed

Returns:

(static) owner(type, id)

restrict query to msgs with owner matching given type, id pair

Parameters:
NameTypeDescription
type*
id*
Returns:

(static) regex(value)

Check if field is matched by regex

Parameters:
NameTypeDescription
value*
Returns:

(static) ro()

Close scope of most recent or

Returns:

(static) seelct(filter)

filter fields from parameters of returned msgs

Parameters:
NameTypeDescription
filter*
Returns:

(static) size(count)

matches list with exactly count items

Parameters:
NameTypeDescription
countInteger

(static) sort(param, direction)

sort returned msgs on given param path (leading '-' reverses sort)

Parameters:
NameTypeDescription
param*
direction*
Returns:

(static) toJSON() → {Object}

Returns:
Type: 
Object

(static) type(type) → {module:Party.Query}

restrict query to msgs of given type

Parameters:
NameTypeDescription
typestring

Type name

Returns:
Type: 
module:Party.Query

(static) types(…types)

restrict query to msgs of given types not compatible with type

Parameters:
NameTypeAttributesDescription
typesstring<repeatable>
Returns:

(static) where(param)

sets context for following operations to given param path

Parameters:
NameTypeDescription
paramstring

Path to field

\ No newline at end of file diff --git a/docs/module-Party.TingoParty.html b/docs/module-Party.TingoParty.html index 953ef7c..6aaa32d 100644 --- a/docs/module-Party.TingoParty.html +++ b/docs/module-Party.TingoParty.html @@ -1,3 +1,3 @@ Class: TingoParty
On this page

Party. TingoParty

new TingoParty(string, tingoOptions)

A local party implementation based on TingoDB Ideal for extremely large datasets with frequent document additions. Has a very efficient append-only file system driver which is ideal for embedded platforms. All database indexes must fit into RAM and are re-computed at db load time.

Parameters:
NameTypeDescription
string

path Path to a directory on the file system to store tingo db

tingoOptionsObject

O ptions to pass to tingodb. Defaults to {nativeObjectID: true}. See: https://github.com/sergeyksv/tingodb#requiretingodboptions

Methods

(static) handleCall(ask)

Parameters:
NameTypeDescription
askObject
Returns:

(static) start()

\ No newline at end of file +
On this page

Party. TingoParty

new TingoParty(string, tingoOptions)

A local party implementation based on TingoDB Ideal for extremely large datasets with frequent document additions. Has a very efficient append-only file system driver which is ideal for embedded platforms. All database indexes must fit into RAM and are re-computed at db load time.

Parameters:
NameTypeDescription
string

path Path to a directory on the file system to store tingo db

tingoOptionsObject

O ptions to pass to tingodb. Defaults to {nativeObjectID: true}. See: https://github.com/sergeyksv/tingodb#requiretingodboptions

Methods

(static) handleCall(ask)

Parameters:
NameTypeDescription
askObject
Returns:

(static) start()

\ No newline at end of file diff --git a/docs/module-Party.ZangoParty.html b/docs/module-Party.ZangoParty.html index 4501f87..d6409a1 100644 --- a/docs/module-Party.ZangoParty.html +++ b/docs/module-Party.ZangoParty.html @@ -1,3 +1,3 @@ Class: ZangoParty
On this page

Party. ZangoParty

new ZangoParty(string)

A local party implementation based on IndexedDb via ZangoDB

Ideal for frontend apps with large datasets (larger then total RAM). This is an IndexedDb based driver so it span to nearly 1/3 of total system storage spave available to the browser/app.

Parameters:
NameTypeDescription
string

dbName

Extends

Methods

(static) handleCall(ask)

Parameters:
NameTypeDescription
askObject
Returns:

(static) start()

\ No newline at end of file +
On this page

Party. ZangoParty

new ZangoParty(string)

A local party implementation based on IndexedDb via ZangoDB

Ideal for frontend apps with large datasets (larger then total RAM). This is an IndexedDb based driver so it span to nearly 1/3 of total system storage spave available to the browser/app.

Parameters:
NameTypeDescription
string

dbName

Extends

Methods

(static) handleCall(ask)

Parameters:
NameTypeDescription
askObject
Returns:

(static) start()

\ No newline at end of file diff --git a/docs/module-Party.html b/docs/module-Party.html index 79908d3..0ef7817 100644 --- a/docs/module-Party.html +++ b/docs/module-Party.html @@ -1,3 +1,3 @@ Module: Party
On this page
\ No newline at end of file +
On this page
\ No newline at end of file diff --git a/docs/module-Service.EndpointContext.html b/docs/module-Service.EndpointContext.html index 22aeb50..4f73a7d 100644 --- a/docs/module-Service.EndpointContext.html +++ b/docs/module-Service.EndpointContext.html @@ -1,3 +1,3 @@ Class: EndpointContext
On this page

Service. EndpointContext

new EndpointContext()

Parameters:
NameTypeDescription
options.partymodule:Party.IParty

The party handling the request

options.endpointmodule:Service.IEndpoint

The endpoint being executed

options.reqExpress.Request

Express js request object

options.resExpress.Response

Express js response object

options.input*

Raw input from client

options.debugDebug

Debug constructor (defaults to npm:Debug)

options.sendFullErrorsboolean

Enables sending full stack traces to client (defaults to false)

Members

(static) actor

(static) debug

(static) endpoint

(static) identity :dataparty_crypto.Identity

Effective root of trust

Type:
  • dataparty_crypto.Identity

(static) input :Object

Type:
  • Object

(static) MiddlewareConfig

(static) output

(static) req

(static) res

(static) senderKey :dataparty_crypto.Identity

Key used to encrypt content. This may be an ephermal key or a long lived key.

Type:
  • dataparty_crypto.Identity

(static) session

(static) stats

Methods

(static) debug(msg, …args)

Parameters:
NameTypeAttributesDescription
msg*
argsany<repeatable>

(static) setSendFullErrors(value)

Parameters:
NameTypeDescription
value*
\ No newline at end of file +
On this page

Service. EndpointContext

new EndpointContext()

Parameters:
NameTypeDescription
options.partymodule:Party.IParty

The party handling the request

options.endpointmodule:Service.IEndpoint

The endpoint being executed

options.reqExpress.Request

Express js request object

options.resExpress.Response

Express js response object

options.input*

Raw input from client

options.debugDebug

Debug constructor (defaults to npm:Debug)

options.sendFullErrorsboolean

Enables sending full stack traces to client (defaults to false)

Members

(static) actor

(static) debug

(static) endpoint

(static) identity :dataparty_crypto.Identity

Effective root of trust

Type:
  • dataparty_crypto.Identity

(static) input :Object

Type:
  • Object

(static) MiddlewareConfig

(static) output

(static) req

(static) res

(static) senderKey :dataparty_crypto.Identity

Key used to encrypt content. This may be an ephermal key or a long lived key.

Type:
  • dataparty_crypto.Identity

(static) session

(static) stats

Methods

(static) debug(msg, …args)

Parameters:
NameTypeAttributesDescription
msg*
argsany<repeatable>

(static) setSendFullErrors(value)

Parameters:
NameTypeDescription
value*
\ No newline at end of file diff --git a/docs/module-Service.IEndpoint.html b/docs/module-Service.IEndpoint.html index abbc09d..ace082d 100644 --- a/docs/module-Service.IEndpoint.html +++ b/docs/module-Service.IEndpoint.html @@ -1,3 +1,3 @@ Interface: IEndpoint
On this page

Service. IEndpoint

Members

(static) Description :string

Type:
  • string

(static) info :module:Service.IEndpoint.EndpointInfo

(static) MiddlewareConfig :Object

A collection of pre and post middleware configurations

Type:
  • Object
Properties
NameTypeDescription
preObject.<string, Object>

A collection of pre-middleware configuration by name

postObject.<string, Object>

A collection of post-middleware configuration by name

/** Collection of configurations to be passed to middleware. Any middleware that is to true or an Object will be enabled and will be passed the config assigned here.

(static) Name :string

Type:
  • string

Methods

(async, static) run(context)

Parameters:
NameTypeDescription
context*
options.Package*

(static) start(party)

Parameters:
NameTypeDescription
party*

Type Definitions

EndpointInfo

Type:
  • Object
Properties
NameTypeDescription
Namestring
Descriptionstring
MiddlewareConfigmodule:Service.IEndpoint.EndpointMiddlewareConfig
\ No newline at end of file +
On this page

Service. IEndpoint

Members

(static) Description :string

Type:
  • string

(static) info :module:Service.IEndpoint.EndpointInfo

(static) MiddlewareConfig :Object

A collection of pre and post middleware configurations

Type:
  • Object
Properties
NameTypeDescription
preObject.<string, Object>

A collection of pre-middleware configuration by name

postObject.<string, Object>

A collection of post-middleware configuration by name

/** Collection of configurations to be passed to middleware. Any middleware that is to true or an Object will be enabled and will be passed the config assigned here.

(static) Name :string

Type:
  • string

Methods

(async, static) run(context)

Parameters:
NameTypeDescription
context*
options.Package*

(static) start(party)

Parameters:
NameTypeDescription
party*

Type Definitions

EndpointInfo

Type:
  • Object
Properties
NameTypeDescription
Namestring
Descriptionstring
MiddlewareConfigmodule:Service.IEndpoint.EndpointMiddlewareConfig
\ No newline at end of file diff --git a/docs/module-Service.IMiddleware.html b/docs/module-Service.IMiddleware.html index 06bff38..42e5176 100644 --- a/docs/module-Service.IMiddleware.html +++ b/docs/module-Service.IMiddleware.html @@ -1,3 +1,3 @@ Interface: IMiddleware
On this page

Service. IMiddleware

Members

(static) ConfigSchema :Object

Joi validator that describes any expected config for this middleware

Type:
  • Object

(static) Description :string

Type:
  • string

(static) info :module:Service.IMiddleware.MiddlewareInfo

(static) Name :string

Type:
  • string

(static) Type

Type of middleware. Allowed values are pre or post

Methods

(async, static) run(context)

Parameters:
NameTypeDescription
contextmodule:Service.EndpointContext
options.Config*

The config options set for this instance of middleware

(async, static) start(party)

Parameters:
NameTypeDescription
partymodule:Party.IParty

Type Definitions

MiddlewareInfo

Type:
  • Object
Properties
NameTypeDescription
Namestring
Typestring
Descriptionstring
ConfigSchemaObject
\ No newline at end of file +
On this page

Service. IMiddleware

Members

(static) ConfigSchema :Object

Joi validator that describes any expected config for this middleware

Type:
  • Object

(static) Description :string

Type:
  • string

(static) info :module:Service.IMiddleware.MiddlewareInfo

(static) Name :string

Type:
  • string

(static) Type

Type of middleware. Allowed values are pre or post

Methods

(async, static) run(context)

Parameters:
NameTypeDescription
contextmodule:Service.EndpointContext
options.Config*

The config options set for this instance of middleware

(async, static) start(party)

Parameters:
NameTypeDescription
partymodule:Party.IParty

Type Definitions

MiddlewareInfo

Type:
  • Object
Properties
NameTypeDescription
Namestring
Typestring
Descriptionstring
ConfigSchemaObject
\ No newline at end of file diff --git a/docs/module-Service.ISandboxRunner.html b/docs/module-Service.ISandboxRunner.html index 47fd205..02cde15 100644 --- a/docs/module-Service.ISandboxRunner.html +++ b/docs/module-Service.ISandboxRunner.html @@ -1,3 +1,3 @@ Class: ISandboxRunner
On this page

Service. ISandboxRunner

new ISandboxRunner()

Parameters:
NameTypeDescription
options.info*
options.exec*
options.start*

Members

(static) start

Methods

(async, static) getInfo()

Returns:

(async, static) run(context, static_ctx)

Parameters:
NameTypeDescription
context*
static_ctx*
Returns:

(async, static) self()

Returns:

module:Serivce.ISandboxRunner

(async, static) start(serviceContext)

Parameters:
NameTypeDescription
serviceContext*
Returns:
\ No newline at end of file +
On this page

Service. ISandboxRunner

new ISandboxRunner()

Parameters:
NameTypeDescription
options.info*
options.exec*
options.start*

Members

(static) start

Methods

(async, static) getInfo()

Returns:

(async, static) run(context, static_ctx)

Parameters:
NameTypeDescription
context*
static_ctx*
Returns:

(async, static) self()

Returns:

module:Serivce.ISandboxRunner

(async, static) start(serviceContext)

Parameters:
NameTypeDescription
serviceContext*
Returns:
\ No newline at end of file diff --git a/docs/module-Service.IService.html b/docs/module-Service.IService.html index a6a0d40..92495db 100644 --- a/docs/module-Service.IService.html +++ b/docs/module-Service.IService.html @@ -1,3 +1,3 @@ Class: IService
On this page

Service. IService

new IService(build)

A service with schema, documents, endpoints, middleware and tasks. Provide either paths to source files for compilation or provided a pre-built service to import.

Parameters:
NameTypeDescription
options.name*
options.version*
options.githash*
options.branch*
build*

Methods

(static) addDocument(document_path)

Add a document class implementation to the service

Parameters:
NameTypeDescription
document_pathstring

(static) addEndpoint(endpoint_path)

Add a dataparty endpoint to the service by pather

Parameters:
NameTypeDescription
endpoint_pathstring

(static) addEndpoint(middleware_path)

Add a middleware to this service

Parameters:
NameTypeDescription
middleware_pathstring

(static) addSchema(schema_path)

Add a dataparty schema implementation to the service

Parameters:
NameTypeDescription
schema_pathmodule:Service.IService

(static) addTask(task_path)

Add a tasker task implementation to the service

Parameters:
NameTypeDescription
task_pathstring

(async, static) compile(outputPath, writeFile)

Compile a service. This will build two output files, one for host usage -service.json and another for client usage -schema.json.

Parameters:
NameTypeDescription
outputPathstring

Path where the built service should be written

writeFileboolean

When true, files will be written. Defaults to true

Returns:

(static) importBuild(buildOutput)

Import a pre-build service

Parameters:
NameTypeDescription
buildOutputObject
\ No newline at end of file +
On this page

Service. IService

new IService(build)

A service with schema, documents, endpoints, middleware and tasks. Provide either paths to source files for compilation or provided a pre-built service to import.

Parameters:
NameTypeDescription
options.name*
options.version*
options.githash*
options.branch*
build*

Methods

(static) addDocument(document_path)

Add a document class implementation to the service

Parameters:
NameTypeDescription
document_pathstring

(static) addEndpoint(endpoint_path)

Add a dataparty endpoint to the service by pather

Parameters:
NameTypeDescription
endpoint_pathstring

(static) addEndpoint(middleware_path)

Add a middleware to this service

Parameters:
NameTypeDescription
middleware_pathstring

(static) addSchema(schema_path)

Add a dataparty schema implementation to the service

Parameters:
NameTypeDescription
schema_pathmodule:Service.IService

(static) addTask(task_path)

Add a tasker task implementation to the service

Parameters:
NameTypeDescription
task_pathstring

(async, static) compile(outputPath, writeFile)

Compile a service. This will build two output files, one for host usage -service.json and another for client usage -schema.json.

Parameters:
NameTypeDescription
outputPathstring

Path where the built service should be written

writeFileboolean

When true, files will be written. Defaults to true

Returns:

(static) importBuild(buildOutput)

Import a pre-build service

Parameters:
NameTypeDescription
buildOutputObject
\ No newline at end of file diff --git a/docs/module-Service.ITask.html b/docs/module-Service.ITask.html index 8742c1d..24cf1ca 100644 --- a/docs/module-Service.ITask.html +++ b/docs/module-Service.ITask.html @@ -1,3 +1,3 @@ Interface: ITask
On this page

Service. ITask

Interface class for supporting tasker tasks in dataparty. To add a task to dataparty service extend this class and implement the Name, Description and Config members.

Extends

  • tasker.Task

Members

(static) Config :module:Service.ITask.TaskConfig

(static) Description :string

Type:
  • string

(static) info :module:Service.ITask.TaskInfo

Returns the task's Name, Description, and Config

(static) Name :string

Type:
  • string

Type Definitions

TaskConfig

Type:
  • Object
Properties
NameTypeDescription
backgroundboolean

Set to true if this is a background task

autostartboolean

Set to true if this task should be run at service start time

TaskInfo

Type:
  • Object
Properties
NameTypeDescription
Namestring
Descriptionstring
Configmodule:Service.ITask.TaskConfig
\ No newline at end of file +
On this page

Service. ITask

Interface class for supporting tasker tasks in dataparty. To add a task to dataparty service extend this class and implement the Name, Description and Config members.

Extends

  • tasker.Task

Members

(static) Config :module:Service.ITask.TaskConfig

(static) Description :string

Type:
  • string

(static) info :module:Service.ITask.TaskInfo

Returns the task's Name, Description, and Config

(static) Name :string

Type:
  • string

Type Definitions

TaskConfig

Type:
  • Object
Properties
NameTypeDescription
backgroundboolean

Set to true if this is a background task

autostartboolean

Set to true if this task should be run at service start time

TaskInfo

Type:
  • Object
Properties
NameTypeDescription
Namestring
Descriptionstring
Configmodule:Service.ITask.TaskConfig
\ No newline at end of file diff --git a/docs/module-Service.RunnerRouter.html b/docs/module-Service.RunnerRouter.html index d867112..63ae2e8 100644 --- a/docs/module-Service.RunnerRouter.html +++ b/docs/module-Service.RunnerRouter.html @@ -1,3 +1,3 @@ Class: RunnerRouter
On this page

Service. RunnerRouter

new RunnerRouter(defaultRunner)

A multi-domain drop in replacement for anywhere we use origin-router.Router. By creating multiple dataparty ServiceRunners you can manage multiple parties and multiple services and merge them into either a single combined service. Or host them as multiple seperate domains. Essentially, this allows the ServiceHost to be multi-tenant.

Parameters:
NameTypeDescription
defaultRunnermodule:Service.ServiceRunner

The default runner to use if no others match. Required

Methods

(static) addRunner()

Parameters:
NameTypeDescription
options.domainstring
options.runnermodule:Service.ServiceRunner

(static) getRunnerByDomain(domain) → {module:Service.ServiceRunner}

Parameters:
NameTypeDescription
domainstring

(static) getRunnerByHostIdentity(identity) → {module:Service.ServiceRunner}

Parameters:
NameTypeDescription
identitydataparty_crypto.Identity

(async, static) start()

Returns:
\ No newline at end of file +
On this page

Service. RunnerRouter

new RunnerRouter(defaultRunner)

A multi-domain drop in replacement for anywhere we use origin-router.Router. By creating multiple dataparty ServiceRunners you can manage multiple parties and multiple services and merge them into either a single combined service. Or host them as multiple seperate domains. Essentially, this allows the ServiceHost to be multi-tenant.

Parameters:
NameTypeDescription
defaultRunnermodule:Service.ServiceRunner

The default runner to use if no others match. Required

Methods

(static) addRunner()

Parameters:
NameTypeDescription
options.domainstring
options.runnermodule:Service.ServiceRunner

(static) getRunnerByDomain(domain) → {module:Service.ServiceRunner}

Parameters:
NameTypeDescription
domainstring

(static) getRunnerByHostIdentity(identity) → {module:Service.ServiceRunner}

Parameters:
NameTypeDescription
identitydataparty_crypto.Identity

(async, static) start()

Returns:
\ No newline at end of file diff --git a/docs/module-Service.ServiceHost.html b/docs/module-Service.ServiceHost.html index 022cc84..f86a2da 100644 --- a/docs/module-Service.ServiceHost.html +++ b/docs/module-Service.ServiceHost.html @@ -1,3 +1,3 @@ Class: ServiceHost
On this page

Service. ServiceHost

new ServiceHost()

Parameters:
NameTypeDescription
options.corsObject

Cors to be passed to express via the cors package

options.trust_proxyboolean

When true, the server will parse forwarding headers. This should be set when running behind a load-balancer for accurate error messages and logging

options.listenUristring

The uri of the host interface to tell express to listen on. Defaults to `http://0.0.0.0:4001

options.i2pEnabledboolean

When true, this server will be available over i2p

options.i2pSamHoststring

The hostname of the i2p SAM control API. Defaults to 127.0.0.1

options.i2pSamPortInteger

The port of the i2p SAM control API. Defaults to 7656

options.i2pForwardHoststring

Override i2p forward host. This defaults to localhost and typically doesn't need to be changed

options.i2pForwardPortInteger

Override i2p forward post. This defaults to the port supplied in options.listenUri.

options.i2pKeystring

When set this i2p key will be used to host the service. If not set a new i2p key will be generated. Defaults to null

options.wsEnabledboolean

When true the server will host a dataparty websocket service. Defaults to true

options.wsPortInteger

Port for the websocket service to listen on. Defaults to null, using the same port as the http server.

options.wsUpgradePathstring

The path within the http server to host an upgradeable websocket. Defaults to /ws

options.runnermodule:Service.ServiceRunner

A pre-configured runner

Members

(static) apiApp :Express

Express app

Type:
  • Express

(static) router :Router

The router

Type:
  • Router

(static) runner :module:Service.ServiceRunner

Dataparty service runner

Methods

(async, static) start()

Start hosting services

(async, static) stop()

Stop hosting services

\ No newline at end of file +
On this page

Service. ServiceHost

new ServiceHost()

Parameters:
NameTypeAttributesDefaultDescription
options.corsObject

Cors to be passed to express via the cors package

options.trust_proxyboolean<optional>
false

When true, the server will parse forwarding headers. This should be set when running behind a load-balancer for accurate error messages and logging

options.listenUristring<optional>
http://0.0.0.0:4000

The uri of the host interface to tell express to listen on. Defaults to `http://0.0.0.0:4001

options.i2pEnabledboolean<optional>
false

When true, this server will be available over i2p

options.i2pSamHoststring<optional>
127.0.0.1

The hostname of the i2p SAM control API. Defaults to 127.0.0.1

options.i2pSamPortInteger<optional>
7656

The port of the i2p SAM control API. Defaults to 7656

options.i2pForwardHoststring<optional>
localhost

Override i2p forward host. This defaults to localhost and typically doesn't need to be changed

options.i2pForwardPortInteger

Override i2p forward post. This defaults to the port supplied in options.listenUri.

options.i2pKeystring

When set this i2p key will be used to host the service. If not set a new i2p key will be generated. Defaults to null

options.wsEnabledboolean<optional>
true

When true the server will host a dataparty websocket service. Defaults to true

options.wsPortInteger

Port for the websocket service to listen on. Defaults to null, using the same port as the http server.

options.wsUpgradePathstring<optional>
/ws

The path within the http server to host an upgradeable websocket. Defaults to /ws

options.mdnsEnabledboolean<optional>
true

When true, the server will publish mDNS records advertising the service and party identity

options.runnermodule:Service.ServiceRunner

A pre-configured runner

Members

(static) apiApp :Express

Express app

Type:
  • Express

(static) router :Router

The router

Type:
  • Router

(static) runner :module:Service.ServiceRunner

Dataparty service runner

Methods

(async, static) start()

Start hosting services

(async, static) stop()

Stop hosting services

\ No newline at end of file diff --git a/docs/module-Service.ServiceRunner.html b/docs/module-Service.ServiceRunner.html index cbeedea..8bd49c4 100644 --- a/docs/module-Service.ServiceRunner.html +++ b/docs/module-Service.ServiceRunner.html @@ -1,3 +1,3 @@ Class: ServiceRunner
On this page

Service. ServiceRunner

new ServiceRunner()

Sandboxed service runner. This runner uses the vm2 package to run end points in a fully isolated context. Endpoints, pre-middleware and post-middleware all run as independant precompiled VMScripts.

Parameters:
NameTypeDescription
options.servicemodule:Service.IService

The service to load endpoints from

options.partymodule:Party.IParty

The party to pass to the endpoints

options.sendFullErrorsboolean

If true send full stack traces to clients. Defaults to false

options.prefixstring

A prefix to apply to all endpoint paths

options.routerRouter

Router, defaults to origin-router

Methods

(static) onRequest(req, res)

Expressjs style way of calling an endpoint. The req will be passed to the router to select the appropritate endpoint

Parameters:
NameTypeDescription
reqExpress.Request
resExpress.Response
Returns:
\ No newline at end of file +
On this page

Service. ServiceRunner

new ServiceRunner()

Sandboxed service runner. This runner uses the vm2 package to run end points in a fully isolated context. Endpoints, pre-middleware and post-middleware all run as independant precompiled VMScripts.

Parameters:
NameTypeDescription
options.servicemodule:Service.IService

The service to load endpoints from

options.partymodule:Party.IParty

The party to pass to the endpoints

options.sendFullErrorsboolean

If true send full stack traces to clients. Defaults to false

options.prefixstring

A prefix to apply to all endpoint paths

options.routerRouter

Router, defaults to origin-router

Methods

(static) onRequest(req, res)

Expressjs style way of calling an endpoint. The req will be passed to the router to select the appropritate endpoint

Parameters:
NameTypeDescription
reqExpress.Request
resExpress.Response
Returns:
\ No newline at end of file diff --git a/docs/module-Service.ServiceRunnerNode.html b/docs/module-Service.ServiceRunnerNode.html index 189c2e3..48f04d5 100644 --- a/docs/module-Service.ServiceRunnerNode.html +++ b/docs/module-Service.ServiceRunnerNode.html @@ -1,3 +1,3 @@ Class: ServiceRunnerNode
On this page

Service. ServiceRunnerNode

new ServiceRunnerNode()

Unsafe service runner. This service runner uses eval to run services, endpoints and tasks. This provides only simple context seperation and does not do effective context isolation. This should only be used where the service is knwon trustworthy. When the useNative option is set to true the service will run in the same context as this class with no isolation at all.

Parameters:
NameTypeDescription
options.servicemodule:Service.IService

The service to load endpoints from

options.partymodule:Party.IParty

The party to pass to the endpoints

options.sendFullErrorsboolean

If true send full stack traces to clients. Defaults to false

options.prefixstring

A prefix to apply to all endpoint paths

options.routerRouter

Router, defaults to origin-router

options.useNativeboolean

Methods

(static) onRequest(req, res)

Expressjs style way of calling an endpoint. The req will be passed to the router to select the appropritate endpoint

Parameters:
NameTypeDescription
reqExpress.Request
resExpress.Response
Returns:
\ No newline at end of file +
On this page

Service. ServiceRunnerNode

new ServiceRunnerNode()

Unsafe service runner. This service runner uses eval to run services, endpoints and tasks. This provides only simple context seperation and does not do effective context isolation. This should only be used where the service is knwon trustworthy. When the useNative option is set to true the service will run in the same context as this class with no isolation at all.

Parameters:
NameTypeDescription
options.servicemodule:Service.IService

The service to load endpoints from

options.partymodule:Party.IParty

The party to pass to the endpoints

options.sendFullErrorsboolean

If true send full stack traces to clients. Defaults to false

options.prefixstring

A prefix to apply to all endpoint paths

options.routerRouter

Router, defaults to origin-router

options.useNativeboolean

Methods

(static) onRequest(req, res)

Expressjs style way of calling an endpoint. The req will be passed to the router to select the appropritate endpoint

Parameters:
NameTypeDescription
reqExpress.Request
resExpress.Response
Returns:
\ No newline at end of file diff --git a/docs/module-Service.html b/docs/module-Service.html index 9c019c1..eb723a9 100644 --- a/docs/module-Service.html +++ b/docs/module-Service.html @@ -1,3 +1,3 @@ Module: Service
On this page
\ No newline at end of file +
On this page
\ No newline at end of file diff --git a/docs/module-Topics.LocalTopicHost.html b/docs/module-Topics.LocalTopicHost.html index 1da0101..745ee89 100644 --- a/docs/module-Topics.LocalTopicHost.html +++ b/docs/module-Topics.LocalTopicHost.html @@ -1,3 +1,3 @@ Class: LocalTopicHost
On this page

Topics. LocalTopicHost

new LocalTopicHost()

Implementation of ROS style pub/sub topics. This runs on a single thread/peer and can be shared to other peers. However, this is a centralized implementation. So if the hosting node stops all topic traffic will halt as well.

\ No newline at end of file +
On this page

Topics. LocalTopicHost

new LocalTopicHost()

Implementation of ROS style pub/sub topics. This runs on a single thread/peer and can be shared to other peers. However, this is a centralized implementation. So if the hosting node stops all topic traffic will halt as well.

\ No newline at end of file diff --git a/docs/module-Topics.html b/docs/module-Topics.html index 53fc0a6..17d1f8e 100644 --- a/docs/module-Topics.html +++ b/docs/module-Topics.html @@ -1,3 +1,3 @@ Module: Topics
On this page
\ No newline at end of file +
On this page
\ No newline at end of file diff --git a/docs/party_cloud_cloud-document.js.html b/docs/party_cloud_cloud-document.js.html index 836139a..ccb4e83 100644 --- a/docs/party_cloud_cloud-document.js.html +++ b/docs/party_cloud_cloud-document.js.html @@ -1,6 +1,6 @@ Source: party/cloud/cloud-document.js
On this page

party_cloud_cloud-document.js

'use strict'
+    
On this page

party_cloud_cloud-document.js

'use strict'
 
 const reach = require('../../utils/reach')
 const debug = require('debug')('dataparty.cloud.document')
@@ -92,4 +92,4 @@
 }
 
 module.exports = CloudDocument
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/party_cloud_cloud-party.js.html b/docs/party_cloud_cloud-party.js.html index caea56f..60441d4 100644 --- a/docs/party_cloud_cloud-party.js.html +++ b/docs/party_cloud_cloud-party.js.html @@ -1,6 +1,6 @@ Source: party/cloud/cloud-party.js
On this page

party_cloud_cloud-party.js

const debug = require('debug')('dataparty.cloud-party')
+    
On this page

party_cloud_cloud-party.js

const debug = require('debug')('dataparty.cloud-party')
 
 const Qb = require('../qb')
 const Query = require('../query')
@@ -148,4 +148,4 @@
 }
 
 module.exports = CloudParty
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/party_document-factory.js.html b/docs/party_document-factory.js.html index feea742..3aed796 100644 --- a/docs/party_document-factory.js.html +++ b/docs/party_document-factory.js.html @@ -1,6 +1,6 @@ Source: party/document-factory.js
On this page

party_document-factory.js

const Ajv = require('ajv')
+    
On this page

party_document-factory.js

const Ajv = require('ajv')
 const debug = require('debug')('dataparty.document-factory')
 const IDocument = require('./idocument')
 
@@ -162,4 +162,4 @@
 }
 
 module.exports = DocumentFactory
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/party_idocument.js.html b/docs/party_idocument.js.html index 77f63af..bb14e89 100644 --- a/docs/party_idocument.js.html +++ b/docs/party_idocument.js.html @@ -1,10 +1,11 @@ Source: party/idocument.js
On this page

party_idocument.js

'use strict'
+    
On this page

party_idocument.js

'use strict'
 
 const reach = require('../utils/reach')
 const debug = require('debug')('dataparty.idocument')
 const EventEmitter = require('eventemitter3')
+const objectHasher = require('node-object-hash').hasher()
 
 class IDocument extends EventEmitter {
 
@@ -118,6 +119,15 @@
     return obj
   }
 
+  /**
+   * hash of `document.data` using sha256
+   * @member module:Party.IDocument.hash
+   * @type {object}
+   */
+  get hash(){
+    return objectHasher.hash(this.data)
+  }
+
   /**
    * @async
    * Merge fields into document
@@ -195,7 +205,9 @@
    * 
    */
   async remove(){
-    debug('removing document ', this.data.type, this.data.id)
+    debug('removing document ', this.type, this.id)
+
+    //this.emit('remove', this)
 
     return this.party.remove(this.data)
   }
@@ -229,6 +241,10 @@
       .id(this.id)
       .exec()
       .then(docs => {
+        if(docs.length==0){
+          return
+        }
+
         this._data = docs[0].data
 
         debug('pull found', docs)
@@ -258,8 +274,7 @@
 
     if (this.watchSub){ return }
 
-    const socket = await this.party.socket()
-    const ros = socket.ros
+    const ros = this.party.comms.ros
     const watchPath = '/dataparty/document/' + this.type + '/' + this.id
 
     debug('watch document', watchPath)
@@ -345,7 +360,7 @@
       case 'update':
       case 'create':
 
-        if(this.followcache){ 
+        if(this.followcache && event.event !== 'remove'){ 
           this._data = newMsg 
 
           /**
@@ -440,4 +455,4 @@
 }
 
 module.exports = IDocument
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/party_index.js.html b/docs/party_index.js.html index c29de66..0539fb6 100644 --- a/docs/party_index.js.html +++ b/docs/party_index.js.html @@ -1,6 +1,6 @@ Source: party/index.js
On this page

party_index.js

/** @module Party */
+    
On this page

party_index.js

/** @module Party */
 exports.IParty = require('./iparty')
 exports.PeerParty = require('./peer/peer-party')
 exports.CloudParty = require('./cloud/cloud-party')
@@ -11,4 +11,4 @@
 exports.IDocument = require('./idocument')
 exports.DocumentFactory = require('./document-factory')
 exports.CloudDocument = require('./cloud/cloud-document')
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/party_iparty.js.html b/docs/party_iparty.js.html index dfbebe3..55f717b 100644 --- a/docs/party_iparty.js.html +++ b/docs/party_iparty.js.html @@ -1,6 +1,6 @@ Source: party/iparty.js
On this page

party_iparty.js

const debug = require('debug')('dataparty.iparty')
+    
On this page

party_iparty.js

const debug = require('debug')('dataparty.iparty')
 const dataparty_crypto = require('@dataparty/crypto')
 
 const ROSLIB = require('roslib')
@@ -72,6 +72,10 @@
     debug('\tDocument Classes', this.factory.getTypes())
   }
 
+  async stop(){
+    this.comms.close()
+  }
+
   /**
    * @async
    * @method module:Party.IParty.createDocument
@@ -345,4 +349,4 @@
   }
 }
 
-module.exports = IParty
\ No newline at end of file +module.exports = IParty
\ No newline at end of file diff --git a/docs/party_local_loki-party.js.html b/docs/party_local_loki-party.js.html index 28c7a21..f501537 100644 --- a/docs/party_local_loki-party.js.html +++ b/docs/party_local_loki-party.js.html @@ -1,6 +1,6 @@ Source: party/local/loki-party.js
On this page

party_local_loki-party.js

'use strict'
+    
On this page

party_local_loki-party.js

'use strict'
 
 const debug = require('debug')('dataparty.loki-party')
 
@@ -70,4 +70,4 @@
   }
 }
 
-module.exports = LokiParty
\ No newline at end of file +module.exports = LokiParty
\ No newline at end of file diff --git a/docs/party_local_loki-query.js.html b/docs/party_local_loki-query.js.html index 36a36f1..37d1df5 100644 --- a/docs/party_local_loki-query.js.html +++ b/docs/party_local_loki-query.js.html @@ -1,6 +1,6 @@ Source: party/local/loki-query.js
On this page

party_local_loki-query.js

'use strict'
+    
On this page

party_local_loki-query.js

'use strict'
 
 const ObjectId = require('bson-objectid')
 const debug = require('debug')('bouncer-db.loki-query')
@@ -190,4 +190,4 @@
   throw new Error(`unrecognized query op: ${node.op}`)
 }
 
-module.exports = LokiQuery
\ No newline at end of file +module.exports = LokiQuery
\ No newline at end of file diff --git a/docs/party_local_tingo-party.js.html b/docs/party_local_tingo-party.js.html index 040d109..2c2c6c0 100644 --- a/docs/party_local_tingo-party.js.html +++ b/docs/party_local_tingo-party.js.html @@ -1,6 +1,6 @@ Source: party/local/tingo-party.js
On this page

party_local_tingo-party.js

'use strict'
+    
On this page

party_local_tingo-party.js

'use strict'
 
 const debug = require('debug')('dataparty.tingo-party')
 
@@ -61,4 +61,4 @@
   }
 }
 
-module.exports = TingoParty
\ No newline at end of file +module.exports = TingoParty
\ No newline at end of file diff --git a/docs/party_local_zango-party.js.html b/docs/party_local_zango-party.js.html index 72a533e..0a4eb89 100644 --- a/docs/party_local_zango-party.js.html +++ b/docs/party_local_zango-party.js.html @@ -1,6 +1,6 @@ Source: party/local/zango-party.js
On this page

party_local_zango-party.js

 
+    
On this page

party_local_zango-party.js

 
 'use strict'
 
 const debug = require('debug')('dataparty.zango-party')
@@ -65,4 +65,4 @@
 }
 
 module.exports = ZangoParty
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/party_loki-cache.js.html b/docs/party_loki-cache.js.html index 580eedc..cbe1c5f 100644 --- a/docs/party_loki-cache.js.html +++ b/docs/party_loki-cache.js.html @@ -1,6 +1,6 @@ Source: party/loki-cache.js
On this page

party_loki-cache.js

'use strict'
+    
On this page

party_loki-cache.js

'use strict'
 
 const cloneDeep = require('lodash/cloneDeep')
 const Loki = require('lokijs')
@@ -53,6 +53,10 @@
         debug('remove CATCH -', exception)
         collection.findAndRemove({'$meta.id': id})
       }
+
+      debug('remove found', found)
+
+      this._emitChange(found, 'remove')
     }
 
     var item = this.findById(type, id)
@@ -117,9 +121,11 @@
             catch(err){
               debug('WARN', err)
             }
-            this._emitChange(msg, 'remove')
           }
 
+          debug('emit remove', msg)
+          this._emitChange(msg, 'remove')
+
         // otherwise insert new message (remove old message if it exists)
         } else {
 
@@ -192,4 +198,4 @@
     })
   }
 }
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/party_mongo_mongo-party.js.html b/docs/party_mongo_mongo-party.js.html index d5b561a..b4bc4a4 100644 --- a/docs/party_mongo_mongo-party.js.html +++ b/docs/party_mongo_mongo-party.js.html @@ -1,6 +1,6 @@ Source: party/mongo/mongo-party.js
On this page

party_mongo_mongo-party.js

'use strict'
+    
On this page

party_mongo_mongo-party.js

'use strict'
 
 const BouncerDb = require('@dataparty/bouncer-db')
 const debug = require('debug')('dataparty.mongo-party')
@@ -55,4 +55,4 @@
   }
 }
 
-module.exports = MongoParty
\ No newline at end of file +module.exports = MongoParty
\ No newline at end of file diff --git a/docs/party_peer_peer-party.js.html b/docs/party_peer_peer-party.js.html index 42bef98..3690687 100644 --- a/docs/party_peer_peer-party.js.html +++ b/docs/party_peer_peer-party.js.html @@ -1,6 +1,6 @@ Source: party/peer/peer-party.js
On this page

party_peer_peer-party.js

'use strict'
+    
On this page

party_peer_peer-party.js

'use strict'
 
 const debug = require('debug')('dataparty.peer-party')
 
@@ -75,4 +75,4 @@
 }
 
 module.exports = PeerParty
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/party_query.js.html b/docs/party_query.js.html index 7f2f62c..9d6b0db 100644 --- a/docs/party_query.js.html +++ b/docs/party_query.js.html @@ -1,6 +1,6 @@ Source: party/query.js
On this page

party_query.js

'use strict'
+    
On this page

party_query.js

'use strict'
 
 const debug=require('debug')('dataparty.query')
 const cloneDeep = require('lodash/cloneDeep')
@@ -510,4 +510,4 @@
     return param.split('.')
   }
 }
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/scripts/core.js b/docs/scripts/core.js index d5e5a43..6344a3d 100644 --- a/docs/scripts/core.js +++ b/docs/scripts/core.js @@ -11,12 +11,46 @@ var MIN_FONT_SIZE = 10; var localStorage = window.localStorage; function getTheme() { - var body = document.body; + var theme = localStorage.getItem(themeLocalStorageKey); + + if (theme) return theme; + + theme = document.body.getAttribute('data-theme'); + + switch (theme) { + case 'dark': + case 'light': + return theme; + case 'fallback-dark': + if ( + // eslint-disable-next-line no-undef + window.matchMedia('(prefers-color-scheme)').matches && + // eslint-disable-next-line no-undef + window.matchMedia('(prefers-color-scheme: light)').matches + ) { + return 'light'; + } + + return 'dark'; - return body.getAttribute('data-theme'); + case 'fallback-light': + if ( + // eslint-disable-next-line no-undef + window.matchMedia('(prefers-color-scheme)').matches && + // eslint-disable-next-line no-undef + window.matchMedia('(prefers-color-scheme: dark)').matches + ) { + return 'dark'; + } + + return 'light'; + + default: + return 'dark'; + } } -function updateTheme(theme) { +function localUpdateTheme(theme) { var body = document.body; var svgUse = document.querySelectorAll('.theme-svg-use'); var iconID = theme === 'dark' ? '#light-theme-icon' : '#dark-theme-icon'; @@ -28,7 +62,10 @@ function updateTheme(theme) { svgUse.forEach(function (svg) { svg.setAttribute('xlink:href', iconID); }); +} +function updateTheme(theme) { + localUpdateTheme(theme); localStorage.setItem(themeLocalStorageKey, theme); } @@ -44,17 +81,7 @@ function toggleTheme() { (function () { var theme = getTheme(); - var themeStoredInLocalStorage = localStorage.getItem(themeLocalStorageKey); - - if (themeStoredInLocalStorage) { - if (theme === themeStoredInLocalStorage) { - return; - } - - updateTheme(themeStoredInLocalStorage); - } else { - localStorage.setItem(themeLocalStorageKey, theme); - } + updateTheme(theme); })(); /** @@ -145,12 +172,15 @@ function bringElementIntoView(element, updateHistory = true) { /** * tocbotInstance is defined in layout.tmpl * It is defined when we are initializing tocbot. - * + * */ // eslint-disable-next-line no-undef if (tocbotInstance) { - // eslint-disable-next-line no-undef - setTimeout(() => tocbotInstance.updateTocListActiveElement(element), 60) + setTimeout( + // eslint-disable-next-line no-undef + () => tocbotInstance.updateTocListActiveElement(element), + 60 + ); } var navbar = document.querySelector('.navbar-container'); var body = document.querySelector('.main-content'); @@ -249,7 +279,6 @@ function addAnchor() { * @param {string} value */ function copy(value) { - console.log(value); const el = document.createElement('textarea'); el.value = value; @@ -401,9 +430,9 @@ function getFontSize() { return currentFontSize; } -function updateFontSize(fontSize) { +function localUpdateFontSize(fontSize) { html.style.fontSize = fontSize + 'px'; - localStorage.setItem(fontSizeLocalStorageKey, fontSize); + var fontSizeText = document.querySelector( '#b77a68a492f343baabea06fad81f651e' ); @@ -413,6 +442,11 @@ function updateFontSize(fontSize) { } } +function updateFontSize(fontSize) { + localUpdateFontSize(fontSize); + localStorage.setItem(fontSizeLocalStorageKey, fontSize); +} + (function () { var fontSize = getFontSize(); var fontSizeInLocalStorage = localStorage.getItem(fontSizeLocalStorageKey); @@ -452,8 +486,9 @@ function fontSizeTooltip() { return `
- ";return'
'+('
'+t.toLocaleUpperCase()+"
")+e+"
"}function getPreDiv(){var e=document.createElement("div");return e.classList.add("pre-div"),e}function processAllPre(){var e=document.querySelectorAll("pre"),t=document.querySelector("#PeOAagUepe"),o=document.querySelector("#VuAckcnZhf"),n=0,i=0,c=(t&&(i=t.getBoundingClientRect().height),o&&(n=o.getBoundingClientRect().height),window.innerHeight-n-i-250);e.forEach(function(e,t){var o,n=e.parentNode;n&&"true"===n.getAttribute("data-skip-pre-process")||(n=getPreDiv(),o=getPreTopBar(t="ScDloZOMdL"+t,e.getAttribute("data-lang")||"code"),n.innerHTML=o,e.style.maxHeight=c+"px",e.id=t,e.classList.add("prettyprint"),e.parentNode.insertBefore(n,e),n.appendChild(e))})}function highlightAndBringLineIntoView(){var e=window.location.hash.replace("#line","");try{var t='[data-line-number="'+e+'"',o=document.querySelector(t);o.scrollIntoView(),o.parentNode.classList.add("selected")}catch(e){console.error(e)}}function getFontSize(){var e=16;try{e=Number.parseInt(html.style.fontSize.split("px")[0],10)}catch(e){console.log(e)}return e}function updateFontSize(e){html.style.fontSize=e+"px",localStorage.setItem(fontSizeLocalStorageKey,e);var t=document.querySelector("#b77a68a492f343baabea06fad81f651e");t&&(t.innerHTML=e)}function incrementFont(e){var t=getFontSize();ttocbotInstance.updateTocListActiveElement(e),60),o=document.querySelector(".navbar-container"),n=document.querySelector(".main-content"),i=e.getBoundingClientRect().top,c=16,o&&(c+=o.scrollHeight),n&&n.scrollBy(0,i-c),t&&history.pushState(null,null,"#"+e.id))}function bringLinkToView(e){e.preventDefault(),e.stopPropagation();var e=e.currentTarget.getAttribute("href");!e||(e=document.getElementById(e.slice(1)))&&bringElementIntoView(e)}function bringIdToViewOnMount(){var e,t;isSourcePage()||""!==(e=window.location.hash)&&((t=document.getElementById(e.slice(1)))||(e=decodeURI(e),t=document.getElementById(e.slice(1))),t&&bringElementIntoView(t,!1))}function createAnchorElement(e){var t=document.createElement("a");return t.textContent="#",t.href="#"+e,t.classList.add("link-anchor"),t.onclick=bringLinkToView,t}function addAnchor(){var e=document.querySelector(".main-content").querySelector("section");[e.querySelectorAll("h1"),e.querySelectorAll("h2"),e.querySelectorAll("h3"),e.querySelectorAll("h4")].forEach(function(e){e.forEach(function(e){var t=createAnchorElement(e.id);e.classList.add("has-anchor"),e.append(t)})})}function copy(e){const t=document.createElement("textarea");t.value=e,document.body.appendChild(t),t.select(),document.execCommand("copy"),document.body.removeChild(t)}function showTooltip(e){var t=document.getElementById(e);t.classList.add("show-tooltip"),setTimeout(function(){t.classList.remove("show-tooltip")},3e3)}function copyFunction(e){var t=document.getElementById(e);copy((t.querySelector(".linenums")||t.querySelector("code")).innerText.trim().replace(/(^\t)/gm,"")),showTooltip("tooltip-"+e)}function hideTocOnSourcePage(){isSourcePage()&&(document.querySelector(".toc-container").style.display="none")}function getPreTopBar(e,t=""){e='";return'
'+('
'+t.toLocaleUpperCase()+"
")+e+"
"}function getPreDiv(){var e=document.createElement("div");return e.classList.add("pre-div"),e}function processAllPre(){var e=document.querySelectorAll("pre"),t=document.querySelector("#PeOAagUepe"),o=document.querySelector("#VuAckcnZhf"),n=0,i=0,c=(t&&(i=t.getBoundingClientRect().height),o&&(n=o.getBoundingClientRect().height),window.innerHeight-n-i-250);e.forEach(function(e,t){var o,n=e.parentNode;n&&"true"===n.getAttribute("data-skip-pre-process")||(n=getPreDiv(),o=getPreTopBar(t="ScDloZOMdL"+t,e.getAttribute("data-lang")||"code"),n.innerHTML=o,e.style.maxHeight=c+"px",e.id=t,e.classList.add("prettyprint"),e.parentNode.insertBefore(n,e),n.appendChild(e))})}function highlightAndBringLineIntoView(){var e=window.location.hash.replace("#line","");try{var t='[data-line-number="'+e+'"',o=document.querySelector(t);o.scrollIntoView(),o.parentNode.classList.add("selected")}catch(e){console.error(e)}}function getFontSize(){var e=16;try{e=Number.parseInt(html.style.fontSize.split("px")[0],10)}catch(e){console.log(e)}return e}function localUpdateFontSize(e){html.style.fontSize=e+"px";var t=document.querySelector("#b77a68a492f343baabea06fad81f651e");t&&(t.innerHTML=e)}function updateFontSize(e){localUpdateFontSize(e),localStorage.setItem(fontSizeLocalStorageKey,e)}function incrementFont(e){var t=getFontSize();t
- `}function initTooltip(){tippy(".theme-toggle",{content:"Toggle Theme",delay:500}),tippy(".search-button",{content:"Search",delay:500}),tippy(".font-size",{content:"Change font size",delay:500}),tippy(".codepen-button",{content:"Open code in CodePen",placement:"left"}),tippy(".copy-code",{content:"Copy this code",placement:"left"}),tippy(".font-size",{content:fontSizeTooltip(),trigger:"click",interactive:!0,allowHTML:!0,placement:"left"})}function fixTable(){for(const t of document.querySelectorAll("table")){if(t.classList.contains("hljs-ln"))return;var e=document.createElement("div");e.classList.add("table-div"),t.parentNode.insertBefore(e,t),e.appendChild(t)}}function hideMobileMenu(){var e=document.querySelector("#mobile-sidebar"),t=document.querySelector("#mobile-menu"),o=t.querySelector("use");e&&e.classList.remove("show"),t&&t.setAttribute("data-isopen","false"),o&&o.setAttribute("xlink:href","#menu-icon")}function showMobileMenu(){var e=document.querySelector("#mobile-sidebar"),t=document.querySelector("#mobile-menu"),o=t.querySelector("use");e&&e.classList.add("show"),t&&t.setAttribute("data-isopen","true"),o&&o.setAttribute("xlink:href","#close-icon")}function onMobileMenuClick(){("true"===document.querySelector("#mobile-menu").getAttribute("data-isopen")?hideMobileMenu:showMobileMenu)()}function initMobileMenu(){var e=document.querySelector("#mobile-menu");e&&e.addEventListener("click",onMobileMenuClick)}function addHrefToSidebarTitle(){document.querySelectorAll(".sidebar-title-anchor").forEach(function(e){e.setAttribute("href",baseURL)})}function onDomContentLoaded(){var e=document.querySelectorAll(".theme-toggle");initMobileMenu(),e&&e.forEach(function(e){e.addEventListener("click",toggleTheme)}),hljs.addPlugin({"after:highlightElement":function(e){e.el.parentNode.setAttribute("data-lang","code")}}),hljs.highlightAll(),hljs.initLineNumbersOnLoad({singleLine:!0}),initAccordion(),addAnchor(),processAllPre(),hideTocOnSourcePage(),setTimeout(function(){bringIdToViewOnMount(),isSourcePage()&&highlightAndBringLineIntoView()},1e3),initTooltip(),fixTable(),addHrefToSidebarTitle()}!function(){var e=getTheme(),t=localStorage.getItem(themeLocalStorageKey);t?e!==t&&updateTheme(t):localStorage.setItem(themeLocalStorageKey,e)}(),function(){var e=getFontSize(),t=localStorage.getItem(fontSizeLocalStorageKey);t?(t=Number.parseInt(t,10))!==e&&updateFontSize(t):updateFontSize(e)}(),window.addEventListener("DOMContentLoaded",onDomContentLoaded),window.addEventListener("hashchange",e=>{e=new URL(e.newURL);""!==e.hash&&bringIdToViewOnMount(e.hash)}); \ No newline at end of file + `}function initTooltip(){tippy(".theme-toggle",{content:"Toggle Theme",delay:500}),tippy(".search-button",{content:"Search",delay:500}),tippy(".font-size",{content:"Change font size",delay:500}),tippy(".codepen-button",{content:"Open code in CodePen",placement:"left"}),tippy(".copy-code",{content:"Copy this code",placement:"left"}),tippy(".font-size",{content:fontSizeTooltip(),trigger:"click",interactive:!0,allowHTML:!0,placement:"left"})}function fixTable(){for(const t of document.querySelectorAll("table")){if(t.classList.contains("hljs-ln"))return;var e=document.createElement("div");e.classList.add("table-div"),t.parentNode.insertBefore(e,t),e.appendChild(t)}}function hideMobileMenu(){var e=document.querySelector("#mobile-sidebar"),t=document.querySelector("#mobile-menu"),o=t.querySelector("use");e&&e.classList.remove("show"),t&&t.setAttribute("data-isopen","false"),o&&o.setAttribute("xlink:href","#menu-icon")}function showMobileMenu(){var e=document.querySelector("#mobile-sidebar"),t=document.querySelector("#mobile-menu"),o=t.querySelector("use");e&&e.classList.add("show"),t&&t.setAttribute("data-isopen","true"),o&&o.setAttribute("xlink:href","#close-icon")}function onMobileMenuClick(){("true"===document.querySelector("#mobile-menu").getAttribute("data-isopen")?hideMobileMenu:showMobileMenu)()}function initMobileMenu(){var e=document.querySelector("#mobile-menu");e&&e.addEventListener("click",onMobileMenuClick)}function addHrefToSidebarTitle(){document.querySelectorAll(".sidebar-title-anchor").forEach(function(e){e.setAttribute("href",baseURL)})}function onDomContentLoaded(){var e=document.querySelectorAll(".theme-toggle");initMobileMenu(),e&&e.forEach(function(e){e.addEventListener("click",toggleTheme)}),hljs.addPlugin({"after:highlightElement":function(e){e.el.parentNode.setAttribute("data-lang","code")}}),hljs.highlightAll(),hljs.initLineNumbersOnLoad({singleLine:!0}),initAccordion(),addAnchor(),processAllPre(),hideTocOnSourcePage(),setTimeout(function(){bringIdToViewOnMount(),isSourcePage()&&highlightAndBringLineIntoView()},1e3),initTooltip(),fixTable(),addHrefToSidebarTitle()}updateTheme(getTheme()),function(){var e=getFontSize(),t=localStorage.getItem(fontSizeLocalStorageKey);t?(t=Number.parseInt(t,10))!==e&&updateFontSize(t):updateFontSize(e)}(),window.addEventListener("DOMContentLoaded",onDomContentLoaded),window.addEventListener("hashchange",e=>{e=new URL(e.newURL);""!==e.hash&&bringIdToViewOnMount(e.hash)}),window.addEventListener("storage",e=>{"undefined"!==e.newValue&&(initTooltip(),e.key===themeLocalStorageKey&&localUpdateTheme(e.newValue),e.key===fontSizeLocalStorageKey&&localUpdateFontSize(e.newValue))}); \ No newline at end of file diff --git a/docs/service_endpoint-context.js.html b/docs/service_endpoint-context.js.html index 9051286..7d6656f 100644 --- a/docs/service_endpoint-context.js.html +++ b/docs/service_endpoint-context.js.html @@ -1,6 +1,6 @@ Source: service/endpoint-context.js
On this page

service_endpoint-context.js

const Debug = require('debug')
+    
On this page

service_endpoint-context.js

const Debug = require('debug')
 
 const DeltaTime = require('../utils/delta-time')
 
@@ -180,4 +180,4 @@
   }
 }
 
-module.exports = EndpointContext
\ No newline at end of file +module.exports = EndpointContext
\ No newline at end of file diff --git a/docs/service_iendpoint.js.html b/docs/service_iendpoint.js.html index 3d7d49d..c248f5b 100644 --- a/docs/service_iendpoint.js.html +++ b/docs/service_iendpoint.js.html @@ -1,6 +1,6 @@ Source: service/iendpoint.js
On this page

service_iendpoint.js

const debug = require('debug')('dataparty.service.IEndpoint')
+    
On this page

service_iendpoint.js

const debug = require('debug')('dataparty.service.IEndpoint')
 
 /**
  * @interface module:Service.IEndpoint
@@ -79,4 +79,4 @@
       MiddlewareConfig: this.MiddlewareConfig
     }
   }
-}
\ No newline at end of file +}
\ No newline at end of file diff --git a/docs/service_imiddleware.js.html b/docs/service_imiddleware.js.html index 3878e79..d3ec25d 100644 --- a/docs/service_imiddleware.js.html +++ b/docs/service_imiddleware.js.html @@ -1,6 +1,6 @@ Source: service/imiddleware.js
On this page

service_imiddleware.js

const debug = require('debug')('dataparty.service.IMiddleware')
+    
On this page

service_imiddleware.js

const debug = require('debug')('dataparty.service.IMiddleware')
 
 /**
  * @interface module:Service.IMiddleware
@@ -82,4 +82,4 @@
       ConfigSchema: this.ConfigSchema
     }
   }
-}
\ No newline at end of file +}
\ No newline at end of file diff --git a/docs/service_index.js.html b/docs/service_index.js.html index 8e6e890..f4b3283 100644 --- a/docs/service_index.js.html +++ b/docs/service_index.js.html @@ -1,6 +1,6 @@ Source: service/index.js
On this page

service_index.js

const Path = require('path')
+    
On this page

service_index.js

const Path = require('path')
 
 /**
  * @module Service
@@ -53,4 +53,4 @@
   secureecho: Path.join(__dirname, './endpoints/secure-echo.js'),
   identity: Path.join(__dirname, './endpoints/service-identity.js'),
   version: Path.join(__dirname, './endpoints/service-version.js')
-}
\ No newline at end of file +}
\ No newline at end of file diff --git a/docs/service_isandbox-runner.js.html b/docs/service_isandbox-runner.js.html index 8542aab..3e72d3c 100644 --- a/docs/service_isandbox-runner.js.html +++ b/docs/service_isandbox-runner.js.html @@ -1,6 +1,6 @@ Source: service/isandbox-runner.js
On this page

service_isandbox-runner.js

const Hoek = require('@hapi/hoek')
+    
On this page

service_isandbox-runner.js

const Hoek = require('@hapi/hoek')
 const debug = require('debug')('dataparty.ISandboxRunner')
 
 class ISandboxRunner {
@@ -74,4 +74,4 @@
   }
 }
 
-module.exports = ISandboxRunner
\ No newline at end of file +module.exports = ISandboxRunner
\ No newline at end of file diff --git a/docs/service_ischema.js.html b/docs/service_ischema.js.html index 80d9bb3..34b1982 100644 --- a/docs/service_ischema.js.html +++ b/docs/service_ischema.js.html @@ -1,6 +1,6 @@ Source: service/ischema.js
On this page

service_ischema.js

const debug = require('debug')('dataparty.service.ISchema')
+    
On this page

service_ischema.js

const debug = require('debug')('dataparty.service.ISchema')
 const MgoUtils = require('../utils/mongoose-scheme-utils')
 
 module.exports = class ISchema {
@@ -71,4 +71,4 @@
     }
   }
 }
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/service_iservice.js.html b/docs/service_iservice.js.html index 6802b9c..aa0a014 100644 --- a/docs/service_iservice.js.html +++ b/docs/service_iservice.js.html @@ -1,9 +1,9 @@ Source: service/iservice.js
On this page

service_iservice.js

const fs = require('fs')
+    
On this page

service_iservice.js

const fs = require('fs')
 const Path = require('path')
-//const NCC = require('@vercel/ncc')
-const NCC = require('@zeit/ncc')
+const NCC = require('@sevenbitbyte/ncc')
+//const NCC = require('@zeit/ncc')
 const Hoek = require('@hapi/hoek')
 const {JSONPath} = require('jsonpath-plus')
 const gitRepoInfo = require('git-repo-info')
@@ -94,7 +94,11 @@
       watch: false, // default
       v8cache: false, // default
       quiet: false, // default
-      debugLog: false // default
+      debugLog: false, // default
+      //target: 'es2015'
+      esm: false,
+      moduleType: 'self',
+      libraryName: 'Lib'
     }
 
     if(build){
@@ -357,4 +361,4 @@
     if(buildTypeScript){ await Promise.all(tsWrites) }
   }
 }
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/service_itask.js.html b/docs/service_itask.js.html index fd54399..fce4341 100644 --- a/docs/service_itask.js.html +++ b/docs/service_itask.js.html @@ -1,6 +1,6 @@ Source: service/itask.js
On this page

service_itask.js

const debug = require('debug')('dataparty.service.ITask')
+    
On this page

service_itask.js

const debug = require('debug')('dataparty.service.ITask')
 const tasker = require('@dataparty/tasker')
 
 
@@ -70,4 +70,4 @@
       Config: this.Config
     }
   }
-}
\ No newline at end of file +}
\ No newline at end of file diff --git a/docs/service_runner-router.js.html b/docs/service_runner-router.js.html index 989c496..ce61326 100644 --- a/docs/service_runner-router.js.html +++ b/docs/service_runner-router.js.html @@ -1,6 +1,6 @@ Source: service/runner-router.js
On this page

service_runner-router.js

const Debug = require('debug')
+    
On this page

service_runner-router.js

const Debug = require('debug')
 const debug = Debug('dataparty.service.runner-router')
 
 class RunnerRouter {
@@ -109,4 +109,4 @@
   }
 }
 
-module.exports = RunnerRouter
\ No newline at end of file +module.exports = RunnerRouter
\ No newline at end of file diff --git a/docs/service_service-host.js.html b/docs/service_service-host.js.html index 8c04840..c180127 100644 --- a/docs/service_service-host.js.html +++ b/docs/service_service-host.js.html @@ -1,7 +1,8 @@ Source: service/service-host.js
On this page

service_service-host.js

const CORS = require('cors')
+    
On this page

service_service-host.js

const CORS = require('cors')
 const {URL} = require('url')
+const mdns = require('mdns')
 const http = require('http')
 const https = require('https')
 const morgan = require('morgan')
@@ -9,13 +10,16 @@
 const bodyParser = require('body-parser')
 const expressListRoutes = require('express-list-routes')
 const debug = require('debug')('dataparty.service.host')
+const objectHasher = require('node-object-hash').hasher()
 
 const reach = require('../utils/reach')
 
 const ServiceHostWebsocket = require('./service-host-websocket')
 
-const Pify = async (p)=>{
-  return await p
+const Pify = (p)=>{
+  return new Promise((resolve,reject)=>{
+    p(resolve)
+  })
 }
 
 class ServiceHost {
@@ -24,17 +28,18 @@
    * @class module:Service.ServiceHost
    * @link module:Service
    * @param {Object}  options.cors            Cors to be passed to express via the `cors` package
-   * @param {boolean} options.trust_proxy     When true, the server will parse forwarding headers. This should be set when running behind a load-balancer for accurate error messages and logging
-   * @param {string}  options.listenUri       The uri of the host interface to tell express to listen on. Defaults to `http://0.0.0.0:4001
-   * @param {boolean} options.i2pEnabled      When true, this server will be available over i2p
-   * @param {string}  options.i2pSamHost      The hostname of the i2p SAM control API. Defaults to `127.0.0.1`
-   * @param {Integer} options.i2pSamPort      The port of the i2p SAM control API. Defaults to `7656`
-   * @param {string}  options.i2pForwardHost  Override i2p forward host. This defaults to `localhost` and typically doesn't need to be changed
+   * @param {boolean} [options.trust_proxy=false]     When true, the server will parse forwarding headers. This should be set when running behind a load-balancer for accurate error messages and logging
+   * @param {string}  [options.listenUri=http://0.0.0.0:4000]       The uri of the host interface to tell express to listen on. Defaults to `http://0.0.0.0:4001
+   * @param {boolean} [options.i2pEnabled=false]      When true, this server will be available over i2p
+   * @param {string}  [options.i2pSamHost=127.0.0.1]      The hostname of the i2p SAM control API. Defaults to `127.0.0.1`
+   * @param {Integer} [options.i2pSamPort=7656]      The port of the i2p SAM control API. Defaults to `7656`
+   * @param {string}  [options.i2pForwardHost=localhost]  Override i2p forward host. This defaults to `localhost` and typically doesn't need to be changed
    * @param {Integer} options.i2pForwardPort  Override i2p forward post. This defaults to the port supplied in `options.listenUri`.
    * @param {string}  options.i2pKey          When set this i2p key will be used to host the service. If not set a new i2p key will be generated. Defaults to `null`
-   * @param {boolean} options.wsEnabled       When true the server will host a dataparty websocket service. Defaults to `true`
+   * @param {boolean} [options.wsEnabled=true]       When true the server will host a dataparty websocket service. Defaults to `true`
    * @param {Integer} options.wsPort          Port for the websocket service to listen on. Defaults to `null`, using the same port as the http server.
-   * @param {string}  options.wsUpgradePath   The path within the http server to host an upgradeable websocket. Defaults to `/ws`
+   * @param {string}  [options.wsUpgradePath=/ws]   The path within the http server to host an upgradeable websocket. Defaults to `/ws`
+   * @param {boolean} [options.mdnsEnabled=true]     When true, the server will publish mDNS records advertising the service and party identity
    * @param {module:Service.ServiceRunner}  options.runner  A pre-configured runner
    */
 
@@ -51,6 +56,7 @@
     wsEnabled = true,
     wsPort = null,
     wsUpgradePath = '/ws',
+    mdnsEnabled = true,
     runner
   }={}){
 
@@ -121,6 +127,8 @@
       }
     }
 
+    this.mdnsEnabled = mdnsEnabled
+
     this.started = false
   }
 
@@ -142,24 +150,31 @@
       //Setup router
       this.apiApp.use(this.runner.onRequest.bind(this.runner))
 
-      if(debug.enabled){ expressListRoutes('API:', this.router ) }
+      if(debug.enabled){ expressListRoutes(this.router ) }
     }
 
+    let backlog = 511
     let listenPort = this.apiServerUri.port
     let listenHost = this.apiServerUri.hostname
     
     if(this.apiServerUri.protocol == 'http:'){
 
+      debug('http server')
+
       //! Handle http
       this.apiServer = http.createServer(this.apiApp)
 
     } else if(this.apiServerUri.protocol == 'https:'){
 
+      debug('http server')
+
       //! Handle https
       this.apiServer = https.createServer(this.apiApp)
 
     } else if(this.apiServerUri.protocol == 'file:'){
 
+      debug('unix socket server')
+
       //! Handle unix socket
       listenHost = null
       listenPort = this.apiServerUri.pathname
@@ -169,7 +184,10 @@
 
 
     await new Promise((resolve,reject)=>{
-      this.apiServer.listen(listenPort, listenHost, resolve)
+
+      debug('listening', this.apiServerUri.toString())
+
+      this.apiServer.listen(listenPort, listenHost==null ? backlog : listenHost, resolve)
     })
 
     clearTimeout(this.errorHandlerTimer)
@@ -211,6 +229,40 @@
       debug('\t', 'address', this.i2pUri)
       debug('\t', 'key', this.i2p.getPublicKey())
     }
+
+    if(this.mdnsEnabled && this.apiServer && this.apiServerUri.protocol != 'file:'){
+
+      let servicePkg = null
+      let partyIdentity = null
+      const routerClass = this.runner.constructor.name
+
+      switch(routerClass){
+        case 'ServiceRunner':
+        case 'ServiceRunnerNode':
+          partyIdentity = this.runner.party.identity
+          servicePkg = this.runner.service.compiled.package
+          break
+        case 'RunnerRouter':
+          partyIdentity = this.runner.defaultRunner.party.identity
+          servicePkg = this.runner.defaultRunner.service.compiled.package
+          break
+      }
+
+
+      const idHash = objectHasher.hash(
+        partyIdentity.toJSON()
+      )
+
+      
+      const txt_record = {
+        partyhash: idHash,
+        pkgname: servicePkg.name
+      }
+      
+      console.log('mdns', servicePkg.name, idHash)
+      this.mdnsAd = mdns.createAdvertisement(mdns.tcp('party'), parseInt(listenPort), {txtRecord: txt_record})
+    }
+
   }
 
   /**
@@ -219,16 +271,19 @@
    * @async
    */
   async stop(){
-    debug('stopping server')
-
+    
     if(!this.apiServer || !this.apiServer.listening){
       return
     }
-
+    
+    debug('stopping server')
+    
     clearTimeout(this.errorHandlerTimer)
     this.errorHandlerTimer = null
 
-    await (Pify(this.apiServer.close)())
+    await new Promise((resolve,reject)=>{
+      this.apiServer.close(resolve)
+    })
 
     debug('stopped server')
   }
@@ -253,4 +308,4 @@
 
 
 module.exports = ServiceHost
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/service_service-runner-node.js.html b/docs/service_service-runner-node.js.html index a012079..7332b28 100644 --- a/docs/service_service-runner-node.js.html +++ b/docs/service_service-runner-node.js.html @@ -1,6 +1,6 @@ Source: service/service-runner-node.js
On this page

service_service-runner-node.js

const Path = require('path')
+    
On this page

service_service-runner-node.js

const Path = require('path')
 const Joi = require('joi')
 const Hoek = require('@hapi/hoek')
 const Debug = require('debug')
@@ -42,6 +42,8 @@
     this.taskRunner = new Runner()
 
     this.started = false
+
+    this.taskCounter = 0
   }
 
   async start(){
@@ -52,7 +54,6 @@
     this.started = true
 
     const taskMap = Hoek.reach(this.service, 'compiled.tasks')
-    //const endpointsLoading = []
     for(let name in taskMap){
       debug('\t',name)
       await this.loadTask(name)
@@ -83,6 +84,12 @@
     }
   }
 
+  assertTaskIsValid(name){
+    if(!this.tasks[name]){
+      throw new Error('invalid task ['+name+']')
+    }
+  }
+
   async loadTask(name){
     if(this.tasks[name]){
       return
@@ -127,12 +134,56 @@
     debug('loaded task',name,'in',dt.deltaMs,'ms')
   }
 
+  async spawnTask(type, context){
+    this.assertTaskIsValid(type)
+
+    debug('spawnTask', type, 'useNative =',this.useNative)
+
+    let dt = new DeltaTime().start()
+    
+
+    "use strict"
+    let task=null
+
+    let TaskClass = null
+
+    if(!this.useNative){
+      const build = Hoek.reach(this.service, `compiled.tasks.${type}`)
+      TaskClass = eval(build.code/*, build.map*/)
+    }
+    else{
+      TaskClass = this.service.constructors.tasks[type]
+    }
+
+    task = new TaskClass({
+      context:{
+        party: this.party,
+        serviceRunner: this,
+        ...context
+      }
+    })
+
+    task.name = task.name + '-' + this.taskCounter++
+
+
+    debug('task info', TaskClass.info)
+
+    this.taskRunner.addTask(task)
+
+
+    dt.end()
+    debug('spawned task',task.name,'in',dt.deltaMs,'ms')
+
+    return task
+  }
+
   /**
    * Add a named task to the run queue
    * @see https://github.com/datapartyjs/tasker
    * @param {string} name 
    */
   runTask(name){
+    this.assertTaskIsValid(name)
     const task = this.tasks[name]
 
     this.taskRunner.addTask(task)
@@ -153,8 +204,11 @@
 
     if(!this.useNative){
       const build = Hoek.reach(this.service, `compiled.endpoints.${name}`)
-      //debug('build', build)
-      endpoint = eval(build.code/*, build.map*/)
+      debug('build', build.code)
+      var self={}
+      eval(build.code, build.map)
+      endpoint = self.Lib
+      debug('obj Lib', self)
     }
     else{
       endpoint = this.service.constructors.endpoints[name]
@@ -220,7 +274,9 @@
       let middle=null
   
       if(!this.useNative){
-        middle = eval(build.code/*, build.map*/)
+        let self={}
+        eval(build.code, build.map)
+        middle = self.Lib
       }
       else{
         middle = this.service.constructors.middleware[type][name]
@@ -381,4 +437,4 @@
   }
 }
 
-module.exports = ServiceRunnerNode
\ No newline at end of file +module.exports = ServiceRunnerNode
\ No newline at end of file diff --git a/docs/service_service-runner.js.html b/docs/service_service-runner.js.html index 55dff24..1fe8dac 100644 --- a/docs/service_service-runner.js.html +++ b/docs/service_service-runner.js.html @@ -1,6 +1,6 @@ Source: service/service-runner.js
On this page

service_service-runner.js

const Path = require('path')
+    
On this page

service_service-runner.js

const Path = require('path')
 const Joi = require('joi')
 const Hoek = require('@hapi/hoek')
 const {VM, VMScript} = require('vm2')
@@ -13,6 +13,7 @@
 const DeltaTime = require('../utils/delta-time')
 
 const Router = require('origin-router').Router
+const Runner = require('@dataparty/tasker').Runner
 
 class ServiceRunner {
 
@@ -35,9 +36,12 @@
 
     this.middleware = { pre: {}, post: {} }
     this.endpoint = {}
+    this.tasks = {}
 
     this.prefix = prefix
     this.router = router
+    this.taskRunner = new Runner()
+
     this.started = false
   }
 
@@ -262,4 +266,4 @@
   }
 }
 
-module.exports = ServiceRunner
\ No newline at end of file +module.exports = ServiceRunner
\ No newline at end of file diff --git a/docs/topics_index.js.html b/docs/topics_index.js.html index e32ece4..9c9ff01 100644 --- a/docs/topics_index.js.html +++ b/docs/topics_index.js.html @@ -1,4 +1,4 @@ Source: topics/index.js
On this page

topics_index.js

/** @module Topics */
-exports.LocalTopicHost = require('./local-topic-host')
\ No newline at end of file +
On this page

topics_index.js

/** @module Topics */
+exports.LocalTopicHost = require('./local-topic-host')
\ No newline at end of file diff --git a/docs/topics_local-topic-host.js.html b/docs/topics_local-topic-host.js.html index 7c35979..c168f48 100644 --- a/docs/topics_local-topic-host.js.html +++ b/docs/topics_local-topic-host.js.html @@ -1,6 +1,6 @@ Source: topics/local-topic-host.js
On this page

topics_local-topic-host.js

'use strict'
+    
On this page

topics_local-topic-host.js

'use strict'
 
 const Path = require('path')
 const debug = require('debug')('dataparty.topics.LocalTopicHost')
@@ -79,16 +79,20 @@
 
     if(topic.path.indexOf('/dataparty/document/') != -1 && !exists){
       const [arg0, arg1, docType, docId] = topic.path.substr(1).split('/')
+      debug('is document watcher', docType+':'+docId)
 
-      peer.hostParty.db.on(docType+':'+docId, async (event)=>{
+      peer.party.hostParty.db.on(docType+':'+docId, async (event)=>{
         await this.handleDocChange(topic.path, event)
       })
     }
   }
 
   async handleDocChange(path, event){
+    debug('handleDocChange', path)
     const topic = this.getTopic(path,false)
 
+    debug('\ttopic',topic)
+
     if(!topic){return}
 
     const [arg0, arg1, docType, docId] = topic.path.substr(1).split('/')
@@ -98,7 +102,7 @@
         id: event.msg.id,
         type: event.msg.type,
         revision: event.msg.revision,
-        operationType: event.change
+        operationType: event.event
       })
     }
   }
@@ -155,4 +159,4 @@
   }
 }
 
-module.exports = LocalTopicHost
\ No newline at end of file +module.exports = LocalTopicHost
\ No newline at end of file diff --git a/docs/tutorial-implementing-services.html b/docs/tutorial-implementing-services.html index 8825ec9..47c7779 100644 --- a/docs/tutorial-implementing-services.html +++ b/docs/tutorial-implementing-services.html @@ -1,6 +1,6 @@ Tutorial: implementing-services
On this page

implementing-services

Example restful service implementation

File: ./example-service.js


+    
On this page

implementing-services

Example restful service implementation

File: ./example-service.js


 const Dataparty = require('@dataparty/api')
 const debug = require('debug')('example.service')
 
@@ -239,4 +239,4 @@
   console.error('CRASH')
   console.error(err)
 })
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tutorial-local-party.html b/docs/tutorial-local-party.html index 5a23006..630744c 100644 --- a/docs/tutorial-local-party.html +++ b/docs/tutorial-local-party.html @@ -1,6 +1,6 @@ Tutorial: local-party
On this page

local-party

Simple local party

File: ./local-party.js


+    
On this page

local-party

Simple local party

File: ./local-party.js


     const fs = require('fs/promises')
     const debug = require('debug')('example.tingo-db')
     const ExampleServiceBuild = require('./dataparty/example-service.json')
@@ -65,4 +65,4 @@
     main().catch(err=>{
       console.error(err)
     })
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tutorial-peer-to-peer.html b/docs/tutorial-peer-to-peer.html index 8d0e8d3..490b0b0 100644 --- a/docs/tutorial-peer-to-peer.html +++ b/docs/tutorial-peer-to-peer.html @@ -1,6 +1,6 @@ Tutorial: peer-to-peer
On this page

peer-to-peer

Simple peer-to-peer service

File: ./example-service.js


+    
On this page

peer-to-peer

Simple peer-to-peer service

File: ./example-service.js


 const Dataparty = require('@dataparty/api')
 const debug = require('debug')('example.service')
 
@@ -157,4 +157,4 @@
   main().catch(err=>{
     console.error(err)
   })
-
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/tutorial-service-task.html b/docs/tutorial-service-task.html index 8019b57..de839a1 100644 --- a/docs/tutorial-service-task.html +++ b/docs/tutorial-service-task.html @@ -1,6 +1,6 @@ Tutorial: service-task
On this page

service-task

Service task

File: ./service-host.js


+    
On this page

service-task

Service task

File: ./service-host.js


 const Path = require('path')
 const debug = require('debug')('test.server-db')
 const Dataparty = require('../src')
@@ -125,4 +125,4 @@
   }
   
   module.exports = StatusDisplayTask
-
\ No newline at end of file +
\ No newline at end of file