From 277147acc064b6ed2a14dcee8d2d0934268e95f3 Mon Sep 17 00:00:00 2001 From: Adriano Rogowski Date: Tue, 14 Jan 2020 22:03:54 -0300 Subject: [PATCH 01/87] Test file for bug-783 --- test/bug/783.js | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 test/bug/783.js diff --git a/test/bug/783.js b/test/bug/783.js new file mode 100644 index 00000000..ebbf19fe --- /dev/null +++ b/test/bug/783.js @@ -0,0 +1,46 @@ + +///// bug-783 + +describe('Gun', function(){ + var root; + (function(){ + var env; + if(typeof global !== 'undefined'){ env = global } + if(typeof window !== 'undefined'){ env = window } + root = env.window? env.window : global; + try{ env.window && root.localStorage && root.localStorage.clear() }catch(e){} + try{ localStorage.clear() }catch(e){} + try{ indexedDB.deleteDatabase('radatatest') }catch(e){} + try{ require('fs').unlinkSync('data.json') }catch(e){} + try{ require('../../lib/fsrm')('radatatest') }catch(e){} + try{ var expect = global.expect = require("../expect") }catch(e){} + + //root.Gun = root.Gun || require('../gun'); + if(root.Gun){ + root.Gun = root.Gun; + root.Gun.TESTING = true; + } else { + root.Gun = require('../../gun'); + root.Gun.TESTING = true; + Gun.serve = require('../../lib/serve'); + //require('../lib/file'); + require('../../lib/store'); + require('../../lib/rfs'); + require('../../sea.js'); + } + }(this)); + + describe('erro sea', function(){ + it('verbose console.log debugging', function(done) { + var gun = Gun({multicast:false, axe:false}); + var ref = gun.get('test').get('1'); + var vput = 'SEA{}'; + ref.put(vput, function(ack, yay){ console.log('ACK: ', ack); /// must ack all + ref.once(function(v,k) { console.log('SALVOU k:%s, v:', k, v); + expect(v===vput).to.be(true); + done(); + }); + }); + }); + } ); +}); From de85106c427852fa9e6d73dc9b32e4a10cd9c56f Mon Sep 17 00:00:00 2001 From: Adriano Rogowski Date: Tue, 21 Jan 2020 20:37:36 -0300 Subject: [PATCH 02/87] Test for bug-322: modify returned node in callback leaks thru --- test/bug/322.js | 50 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100755 test/bug/322.js diff --git a/test/bug/322.js b/test/bug/322.js new file mode 100755 index 00000000..3b05ae57 --- /dev/null +++ b/test/bug/322.js @@ -0,0 +1,50 @@ +describe('Gun', function(){ + var root; + (function(){ + var env; + if(typeof global !== 'undefined'){ env = global } + if(typeof window !== 'undefined'){ env = window } + root = env.window? env.window : global; + try{ env.window && root.localStorage && root.localStorage.clear() }catch(e){} + try{ localStorage.clear() }catch(e){} + try{ indexedDB.deleteDatabase('radatatest') }catch(e){} + try{ require('fs').unlinkSync('data.json') }catch(e){} + try{ require('../../lib/fsrm')('radatatest') }catch(e){} + try{ var expect = global.expect = require("../expect") }catch(e){} + + //root.Gun = root.Gun || require('../gun'); + if(root.Gun){ + root.Gun = root.Gun; + root.Gun.TESTING = true; + } else { + root.Gun = require('../../gun'); + root.Gun.TESTING = true; + Gun.serve = require('../../lib/serve'); +// require('../../lib/file'); + require('../../lib/store'); + require('../../lib/rfs'); +// require('../../sea.js'); + } + }(this)); + + var opt = { file: 'radatatest' }; + + describe('API - map', function(){ + it('Save example data', function(done) { + var gun = Gun(opt); + gun.get('users').set({u:1}); + gun.get('users').set({u:2}); + gun.get('users').set({u:2}); + gun.get('users').map().on(function(user) { user.index = 'someIndex'; }); + setTimeout(function() { done(); }, 200); + }); + it('Make sure the value "someIndex" not be saved in storage', function(done) { + var gun = Gun(opt), values=[]; + gun.get('users').map().once(function(v) { values.push(v.index); }); + setTimeout(function() { + expect(values.indexOf('someIndex')===-1).to.be(true); + done(); + }, 200); + }); + }); +}); From 9f446a08d49afd6567d37b0163f0e546154b8eab Mon Sep 17 00:00:00 2001 From: Adriano Rogowski Date: Tue, 21 Jan 2020 20:46:13 -0300 Subject: [PATCH 03/87] Test for bug-686: Cannot put string 'null' as value in put. SEA error thrown --- test/bug/686.js | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100755 test/bug/686.js diff --git a/test/bug/686.js b/test/bug/686.js new file mode 100755 index 00000000..4d6e9560 --- /dev/null +++ b/test/bug/686.js @@ -0,0 +1,59 @@ +describe('Gun', function(){ + var root; + (function(){ + var env; + if(typeof global !== 'undefined'){ env = global } + if(typeof window !== 'undefined'){ env = window } + root = env.window? env.window : global; + try{ env.window && root.localStorage && root.localStorage.clear() }catch(e){} + try{ localStorage.clear() }catch(e){} + try{ indexedDB.deleteDatabase('radatatest') }catch(e){} + try{ require('fs').unlinkSync('data.json') }catch(e){} + try{ require('../../lib/fsrm')('radatatest') }catch(e){} + try{ var expect = global.expect = require("../expect") }catch(e){} + + //root.Gun = root.Gun || require('../gun'); + if(root.Gun){ + root.Gun = root.Gun; + root.Gun.TESTING = true; + } else { + root.Gun = require('../../gun'); + root.Gun.TESTING = true; + Gun.serve = require('../../lib/serve'); + //require('../lib/file'); + require('../../lib/store'); + require('../../lib/rfs'); + require('../../sea.js'); + } + }(this)); + var opt = { file: 'radatatest' }; + describe('SEA', function() { + it('put null string', function(done) { + var gun = Gun(opt); + gun.get('test').get('key').put('null', function(ack) { + if (ack.err) { expect(!ack.err).to.be(true); done(); } + gun.get('test').get('key').once(function(v) { + expect(v === 'null').to.be(true); + done(); + }); + }); + }); + it('put null string in user land', function(done) { + var gun = Gun(opt); + var user = gun.user(); + var u={a:'usr', p:'pass'}; + var value = 'null'; + user.create(u.a, u.p, function(ack) { + usr = user.auth(u.a, u.p, function() { + usr.get('test').get('key').put(value, function(ack) { + if (ack.err) { expect(!ack.err).to.be(true); done(); } + usr.get('test').get('key').once(function(v) { + expect(v === value).to.be(true); /// must be null string. + done(); + }); + }); + }); + }); + }); + }); +}); From faa776a8e50da9e24c14ccde5c26f9fcb909d073 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Fri, 24 Jan 2020 12:02:17 -0800 Subject: [PATCH 04/87] cache remote files, quick ugly test experiment? --- lib/rfsmix.js | 20 ++++++++++++++++++++ lib/rs3.js | 1 + 2 files changed, 21 insertions(+) create mode 100644 lib/rfsmix.js diff --git a/lib/rfsmix.js b/lib/rfsmix.js new file mode 100644 index 00000000..6b6c126d --- /dev/null +++ b/lib/rfsmix.js @@ -0,0 +1,20 @@ +module.exports = function(opt, store){ + var rfs = require('./rfs')(opt); + var p = store.put; + var g = store.get; + store.put = function(file, data, cb){ + rfs.put(file, data, function(err, ok){ + if(err){ return cb(err) } + console.log("rfs3 cached", file); + p(file, data, cb); + }); + } + store.get = function(file, cb){ + rfs.get(file, function(err, data){ + console.log("rfs3 hijacked", file); + if(data){ return cb(err, data) } + g(file, cb); + }); + } + return store; +} \ No newline at end of file diff --git a/lib/rs3.js b/lib/rs3.js index e4f57f7d..2ad03e8b 100644 --- a/lib/rs3.js +++ b/lib/rs3.js @@ -98,6 +98,7 @@ function Store(opt){ }); }; //store.list(function(){ return true }); + require('./rfsmix')(opt, store); // ugly, but gotta move fast for now. return store; } From 958d736e0caea8cb71b2973e50ca8b9e0537af33 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 28 Jan 2020 17:15:50 -0800 Subject: [PATCH 05/87] IF email ENV CONFIG set, report slow parse --- examples/stats.html | 3 ++- lib/evict.js | 4 ++-- lib/radisk.js | 6 ++++-- lib/radix.js | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/stats.html b/examples/stats.html index e6e53e67..3f61233b 100644 --- a/examples/stats.html +++ b/examples/stats.html @@ -83,12 +83,13 @@ } // create a new Series for this key // add it into the map - chart = Stats[key] = new SmoothieChart({responsive: true, minValue: 0, grid:{strokeStyle:'rgba(100%,100%,100%,0.2)'},labels:{fontSize:20}}); + chart = Stats[key] = new SmoothieChart({millisPerPixel:500, limitFPS: 16, responsive: true, minValue: 0, grid:{strokeStyle:'rgba(100%,100%,100%,0.2)'},labels:{fontSize:20}, grid: {verticalSections: 0, millisPerLine: 15000 * 4 /*, strokeStyle:'rgb(125, 0, 0)'*/}}); chart.line = new TimeSeries(); chart.addTimeSeries(chart.line,{ strokeStyle:'rgb('+Math.random()*255+', '+Math.random()*255+','+Math.random()*255+')', lineWidth:5 }); chart.canvas = $('.model').find('.chart').clone(true).appendTo('.charts'); chart.canvas.find('span').text(key); chart.streamTo(chart.canvas.find('canvas').get(0), 15 * 1000); + chart.line.append(0, 0); // check first two characters of key to determine other charts to add this in // tbd later return chart; diff --git a/lib/evict.js b/lib/evict.js index 8e0023bf..48e69437 100644 --- a/lib/evict.js +++ b/lib/evict.js @@ -16,8 +16,8 @@ function check(){ var used = util().rss / 1024 / 1024; var hused = heap().used_heap_size / 1024 / 1024; - //if(hused < ev.max && used < ev.max){ return } - if(used < ev.max){ return } + if(hused < ev.max && used < ev.max){ return } + //if(used < ev.max){ return } console.LOG && Gun.log('evict memory:', hused.toFixed(), used.toFixed(), ev.max.toFixed()); GC();//setTimeout(GC, 1); } diff --git a/lib/radisk.js b/lib/radisk.js index 8c873546..cc3539b3 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -20,6 +20,7 @@ function atomic(v){ return u !== v && (!v || 'object' != typeof v) } var map = Gun.obj.map; var LOG = console.LOG; + var ST = 0; if(!opt.store){ return opt.log("ERROR: Radisk needs `opt.store` interface with `{get: fn, put: fn (, list: fn)}`!"); @@ -319,7 +320,7 @@ LOG && opt.log(S, +new Date - S, 'rad read in, ack', disk.length); S = +new Date; var STMP = disk.length; // TMP STATS! DELETE! map(disk, g.ack); - LOG && opt.log(S, +new Date - S, 'rad read acked', STMP, JSON.stringify(g.file)); + LOG && opt.log(S, +new Date - S, 'rad read acked', STMP, JSON.stringify(g.file)); // this grows before spike? } g.ack = function(as){ if(!as.ack){ return } @@ -431,8 +432,9 @@ try{ var json = JSON.parse(data); // TODO: this caused a out-of-memory crash! p.disk.$ = json; - LOG && opt.log(S, +new Date - S, 'rad parsed JSON'); + LOG && opt.log(S, ST = +new Date - S, 'rad parsed JSON'); map(q, p.ack); + LOG && (ST > 500) && require('./email').send({text: ""+ST+"ms "+file, from: "mark@gun.eco", to: "mark@gun.eco", subject: "RAD JSON parse"}, noop); // this is ONLY turned on if ENV CONFIGS have email/password to send out from. return; }catch(e){ tmp = e } if('{' === data[0]){ diff --git a/lib/radix.js b/lib/radix.js index 441f9540..a3523f3e 100644 --- a/lib/radix.js +++ b/lib/radix.js @@ -51,7 +51,7 @@ return radix; }; - Radix.map = function map(radix, cb, opt, pre){ pre = pre || []; + Radix.map = function map(radix, cb, opt, pre){ pre = pre || []; // TODO: BUG: most out-of-memory crashes come from here. var t = ('function' == typeof radix)? radix.$ || {} : radix; if(!t){ return } var keys = (t[_]||no).sort || (t[_] = function $(){ $.sort = Object.keys(t).sort(); return $ }()).sort, rev; From 6593844ed0abdfa011b9e6bd49916cd8fd793acd Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 28 Jan 2020 21:36:39 -0800 Subject: [PATCH 06/87] IF email ENV CONFIG set, report slows --- axe.js | 8 ++++++++ examples/todo/index.html | 2 +- gun.js | 8 +++----- lib/radisk.js | 20 ++++++++++---------- lib/rfsmix.js | 4 ++-- lib/store.js | 28 ++++++++++++---------------- 6 files changed, 36 insertions(+), 34 deletions(-) diff --git a/axe.js b/axe.js index 8e3b6d4c..5058cacd 100644 --- a/axe.js +++ b/axe.js @@ -32,6 +32,7 @@ var AXE = USE('./root'), Gun = (AXE.window||{}).Gun || USE('./gun', 1); (Gun.AXE = AXE).GUN = AXE.Gun = Gun; + var LOG = console.LOG; Gun.on('opt', function(at){ start(at); @@ -78,6 +79,7 @@ console.log("AXE enabled."); function verify(dht, msg) { + var S = (+new Date); var puts = Object.keys(msg.put); var soul = puts[0]; /// TODO: verify all souls in puts. Copy the msg only with subscribed souls? var subs = dht(soul); @@ -93,6 +95,7 @@ if (opt.super) { dht(soul, tmp.join(',')); } + LOG && Gun.log(S, +new Date - S, 'axe verify'); } function route(get){ var tmp; if(!get){ return } @@ -163,6 +166,7 @@ if(peer){ mesh.say({dam: 'opt', ok: 1, '@': msg['#']}, peer) } } setInterval(function(tmp){ + LOG = console.LOG; // for stats, occasionally update cache. if(!(tmp = at.stats && at.stats.stay)){ return } (tmp.axe = tmp.axe || {}).up = Object.keys(axe.up||{}); },1000 * 60) @@ -189,6 +193,7 @@ var peers = routes[hash]; function chat(peers, old){ // what about optimizing for directed peers? if(!peers){ return chat(opt.peers) } + var S = (+new Date); // STATS! var ids = Object.keys(peers); // TODO: BUG! THIS IS BAD PERFORMANCE!!!! var meta = (msg._||yes); clearTimeout(meta.lack); @@ -198,6 +203,7 @@ meta.turn = (meta.turn || 0) + 1; if((old && old[id]) || false === mesh.say(msg, peer)){ ++c } } + LOG && Gun.log(S, +new Date - S, 'axe chat'); //console.log("AXE:", Gun.obj.copy(msg), meta.turn, c, ids, opt.peers === peers); if(0 < c){ if(peers === opt.peers){ return } // prevent infinite lack loop. @@ -215,6 +221,7 @@ } // TODO: PUTs need to only go to subs! if(msg.put){ + var S = (+new Date); // STATS! var routes = axe.routes || (axe.routes = {}); // USE RAD INSTEAD! TMP TESTING! var peers = {}; Gun.obj.map(msg.put, function(node, soul){ @@ -223,6 +230,7 @@ if(!to){ return } Gun.obj.to(to, peers); }); + LOG && Gun.log(S, +new Date - S, 'axe put'); mesh.say(msg, peers); return; } diff --git a/examples/todo/index.html b/examples/todo/index.html index 6f941d38..1bba2922 100644 --- a/examples/todo/index.html +++ b/examples/todo/index.html @@ -119,7 +119,7 @@ // for how to build a simplified version // of this example: https://scrimba.com/c/cW2Vsa var gun = Gun(location.origin + '/gun'); - var think = gun.get('think/' + location.hash.slice(1)); + var think = gun.get('think1/' + location.hash.slice(1)); var thoughtItemStr = function(id) { return '
  • '} var typing, throttle; $('.thought__add').on('click', function () { diff --git a/gun.js b/gun.js index 63452fe8..3db24c19 100644 --- a/gun.js +++ b/gun.js @@ -1977,14 +1977,12 @@ if('[' === tmp){ try{msg = JSON.parse(raw);}catch(e){opt.log('DAM JSON parse error', e)} if(!msg){ return } - LOG && opt.log(+new Date, msg.length, 'in hear batch'); - (function go(){ - var S; LOG && (S = +new Date); // STATS! + LOG && opt.log(+new Date, msg.length, '# on hear batch'); + (function go(){ // stats on single msg is 99% spike of batch stats. var m, c = 100; // hardcoded for now? while(c-- && (m = msg.shift())){ mesh.hear(m, peer); } - LOG && opt.log(S, +new Date - S, 'batch heard'); if(!msg.length){ return } puff(go, 0); }()); @@ -2013,7 +2011,7 @@ } var S, ST; LOG && (S = +new Date); root.on('in', msg); - LOG && !msg.nts && (ST = +new Date - S) > 9 && opt.log(S, ST, 'msg', msg['#']); + if(LOG && !msg.nts && (ST = +new Date - S) > 9){ opt.log(S, ST, 'msg', msg['#']); if(ST > 500){ try{ require('./lib/email').send({text: ""+ST+"ms "+JSON.stringify(msg), from: "mark@gun.eco", to: "mark@gun.eco", subject: "GUN MSG"}, noop); }catch(e){} } } // this is ONLY turned on if ENV CONFIGS have email/password to send out from. return; } } diff --git a/lib/radisk.js b/lib/radisk.js index cc3539b3..c9ba8196 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -173,10 +173,12 @@ return; } disk = disk || Radix(); + var S; LOG && (S = +new Date); Radix.map(mem, function(val, key){ // PLUGIN: consider adding HAM as an extra layer of protection disk(key, val); // merge batch[key] -> disk[key] }); + LOG && opt.log(S, +new Date - S, "rad merge mem & disk"); r.write(file, disk, s.pop); }) } @@ -221,7 +223,8 @@ var tmp = ename(file); var S; LOG && (S = +new Date); r.list.add(tmp, function(err){ - LOG && opt.log(S, +new Date - S, "wrote disk", tmp); + LOG && opt.log(S, ST = +new Date - S, "wrote disk", tmp); + LOG && (ST > 500) && require('./email').send({text: ""+ST+"ms "+tmp, from: "mark@gun.eco", to: "mark@gun.eco", subject: "RAD DISK WROTE"}, noop); // this is ONLY turned on if ENV CONFIGS have email/password to send out from. if(err){ return cb(err) } opt.store.put(tmp, f.text, cb); }); @@ -278,7 +281,7 @@ if(RAD && !o.next){ // cache var S; LOG && (S = +new Date); var val = RAD(key); - LOG && opt.log(S, +new Date - S, 'rad cached'); + LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'rad cached'); //if(u !== val){ //cb(u, val, o); if(atomic(val)){ cb(u, val, o); return } @@ -317,14 +320,13 @@ g.info = info; if(disk){ RAD = g.disk = disk } disk = Q[g.file]; delete Q[g.file]; - LOG && opt.log(S, +new Date - S, 'rad read in, ack', disk.length); S = +new Date; - var STMP = disk.length; // TMP STATS! DELETE! map(disk, g.ack); - LOG && opt.log(S, +new Date - S, 'rad read acked', STMP, JSON.stringify(g.file)); // this grows before spike? } g.ack = function(as){ if(!as.ack){ return } + var S; LOG && (S = +new Date); var key = as.key, o = as.opt, info = g.info, rad = g.disk || noop, data = r.range(rad(key), o), last = rad.last || Radix.map(rad, rev, revo); + LOG && opt.log(S, +new Date - S, "rad range loaded"); o.parsed = (o.parsed || 0) + (info.parsed||0); o.chunks = (o.chunks || 0) + 1; o.more = true; @@ -337,9 +339,7 @@ return } if(u !== data){ - var S = +new Date; as.ack(g.err, data, o); // more might be coming! - LOG && opt.log(S, +new Date - S, 'rad range ack.'); // 1.4s if(o.parsed >= o.limit){ return } // even if more, we've hit our limit, asking peer will need to make a new ask with a new starting point. } o.next = as.file; @@ -361,10 +361,10 @@ r.list(go); }); if(good){ return } - var id = Gun.text.random(3); console.log("MISLOCATED DATA", id); + var id = Gun.text.random(3); r.save(disk, function ack(err, ok){ if(err){ return r.save(disk, ack) } // ad infinitum??? - console.log("MISLOCATED CORRECTED", id); + console.log("MISLOCATED DATA CORRECTED", id); }); } /*g.check2 = function(err, disk, info){ @@ -434,7 +434,7 @@ p.disk.$ = json; LOG && opt.log(S, ST = +new Date - S, 'rad parsed JSON'); map(q, p.ack); - LOG && (ST > 500) && require('./email').send({text: ""+ST+"ms "+file, from: "mark@gun.eco", to: "mark@gun.eco", subject: "RAD JSON parse"}, noop); // this is ONLY turned on if ENV CONFIGS have email/password to send out from. + LOG && (ST > 500) && require('./email').send({text: ""+ST+"ms "+ename(file), from: "mark@gun.eco", to: "mark@gun.eco", subject: "RAD JSON parse"}, noop); // this is ONLY turned on if ENV CONFIGS have email/password to send out from. return; }catch(e){ tmp = e } if('{' === data[0]){ diff --git a/lib/rfsmix.js b/lib/rfsmix.js index 6b6c126d..dbe2cd97 100644 --- a/lib/rfsmix.js +++ b/lib/rfsmix.js @@ -5,13 +5,13 @@ module.exports = function(opt, store){ store.put = function(file, data, cb){ rfs.put(file, data, function(err, ok){ if(err){ return cb(err) } - console.log("rfs3 cached", file); + //console.log("rfs3 cached", file); p(file, data, cb); }); } store.get = function(file, cb){ rfs.get(file, function(err, data){ - console.log("rfs3 hijacked", file); + //console.log("rfs3 hijacked", file); if(data){ return cb(err, data) } g(file, cb); }); diff --git a/lib/store.js b/lib/store.js index 734ea585..c2b3fe74 100644 --- a/lib/store.js +++ b/lib/store.js @@ -16,7 +16,7 @@ Gun.on('create', function(root){ this.to.next(msg); var id = msg['#'] || Gun.text.random(3), track = !msg['@'], acks = track? 0 : u; // only ack non-acks. var got = (msg._||empty).rad, now = Gun.state(); - var S = (+new Date); // STATS! + var S = (+new Date), C = 0; // STATS! Gun.graph.is(msg.put, null, function(val, key, node, soul){ if(!track && got){ var at = (root.next||empty)[soul]; @@ -30,8 +30,10 @@ Gun.on('create', function(root){ //console.log('put:', soul, key, val); val = Radisk.encode(val, null, esc)+'>'+Radisk.encode(Gun.state.is(node, key), null, esc); rad(soul+esc+key, val, (track? ack : u)); + C++; }); - //LOG && Gun.log(S, +new Date - S, 'put loop'); + LOG && Gun.log(S, +new Date - S, 'put loop'); + LOG && Gun.log(S, C, 'put loop #'); function ack(err, ok){ acks--; if(ack.err){ return } @@ -44,9 +46,8 @@ Gun.on('create', function(root){ try{opt.store.stats.put.time[statp % 50] = (+new Date) - S; ++statp; opt.store.stats.put.count++; }catch(e){} // STATS! - //console.log(+new Date - S, 'put'); S = +new Date; + LOG && Gun.log(S, +new Date - S, 'put'); root.on('in', {'@': id, ok: 1}); - //console.log(S, +new Date - S, 'put sent'); } }); @@ -82,17 +83,11 @@ Gun.on('create', function(root){ var SPUT = tmp.put; if(o.atom){ tmp = (tmp.next||empty)[o.atom] ; - if(tmp && tmp.rad){ - LOG && Gun.log("still cached atom", JSON.stringify(get), Object.keys(SPUT||{}).length); - return; - } + if(tmp && tmp.rad){ return } } else - if(tmp && tmp.rad){ - LOG && Gun.log("still cached", JSON.stringify(get), Object.keys(SPUT||{}).length); - return; - } + if(tmp && tmp.rad){ return } } - var S = (+new Date), C = 0, CC = 0; // STATS! + var S = (+new Date), C = 0; // STATS! rad(key||'', function(err, data, o){ try{opt.store.stats.get.time[statg % 50] = (+new Date) - S; ++statg; opt.store.stats.get.count++; @@ -110,15 +105,16 @@ Gun.on('create', function(root){ } if(!graph && data){ each(data, '') } } - LOG && Gun.log(S, +new Date - S, 'got prep count', CC, C); S = +new Date; CC = 0; + LOG && Gun.log(S, +new Date - S, 'got prep time'); S = +new Date; + LOG && Gun.log(S, C, 'got prep #'); C = 0; var faith = function(){}; faith.faith = true; faith.rad = get; // HNPERF: We're testing performance improvement by skipping going through security again, but this should be audited. root.on('in', {'@': id, put: graph, '%': o.more? 1 : u, err: err? err : u, _: faith}); - LOG && Gun.log(S, +new Date - S, 'got sent nodes in graph', Object.keys(graph||{}).length); + LOG && Gun.log(S, +new Date - S, 'got emit', Object.keys(graph||{}).length); graph = u; // each is outside our scope, we have to reset graph to nothing! }, o); LOG && Gun.log(S, +new Date - S, 'get call'); function each(val, has, a,b){ // TODO: THIS CODE NEEDS TO BE FASTER!!!! - C++; ++CC; + C++; if(!val){ return } has = (key+has).split(esc); var soul = has.slice(0,1)[0]; From fa5fe8a325545def1bc0b54cb951d8119394a164 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Wed, 29 Jan 2020 19:05:52 -0800 Subject: [PATCH 07/87] refine health --- axe.js | 6 +++--- examples/stats.html | 10 ++++++++++ gun.js | 5 +++-- lib/radisk.js | 15 +++++++++------ lib/store.js | 10 ++++------ 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/axe.js b/axe.js index 5058cacd..2c5e32ba 100644 --- a/axe.js +++ b/axe.js @@ -32,7 +32,7 @@ var AXE = USE('./root'), Gun = (AXE.window||{}).Gun || USE('./gun', 1); (Gun.AXE = AXE).GUN = AXE.Gun = Gun; - var LOG = console.LOG; + var LOG = console.LOG, ST = 0; Gun.on('opt', function(at){ start(at); @@ -203,7 +203,7 @@ meta.turn = (meta.turn || 0) + 1; if((old && old[id]) || false === mesh.say(msg, peer)){ ++c } } - LOG && Gun.log(S, +new Date - S, 'axe chat'); + LOG && (ST = +new Date - S) > 9 && Gun.log(S, ST, 'axe chat'); //console.log("AXE:", Gun.obj.copy(msg), meta.turn, c, ids, opt.peers === peers); if(0 < c){ if(peers === opt.peers){ return } // prevent infinite lack loop. @@ -230,7 +230,7 @@ if(!to){ return } Gun.obj.to(to, peers); }); - LOG && Gun.log(S, +new Date - S, 'axe put'); + LOG && (ST = +new Date - S) > 9 && Gun.log(S, ST, 'axe put'); mesh.say(msg, peers); return; } diff --git a/examples/stats.html b/examples/stats.html index 3f61233b..a208286e 100644 --- a/examples/stats.html +++ b/examples/stats.html @@ -94,6 +94,16 @@ // tbd later return chart; } +/* + Notes to Self about Debugging: + 1. Read Disks can spike up to 1min, I suspect other operations are blocking it from resolving as fast as it otherwise would. + 2. JSON parsing/stringifying sometimes way slower than other times, why? + 3. Looks like RAD lex read is not optimized. + 4. got prep + got emit = non-RAD problems, compare against read disk & got differentials (should be same). + 5. Radix map/place ops could be slow? + 6. SINGLE MESSAGE PROCESS TIME occasionally is huge, should get emailed. + 7. Watch out for get/put loops times, maybe indicating (5) issues? +*/ \ No newline at end of file diff --git a/gun.js b/gun.js index 3db24c19..58699262 100644 --- a/gun.js +++ b/gun.js @@ -2017,6 +2017,7 @@ } var tomap = function(k,i,m){m(k,true)}; mesh.hear.c = mesh.hear.d = 0; + var noop = function(){}; ;(function(){ var SMIA = 0; @@ -2076,10 +2077,10 @@ peer.batch = peer.tail = null; if(!tmp){ return } if(!tmp.length){ return } // if(3 > tmp.length){ return } // TODO: ^ - var S; LOG && (S = +new Date); + var S, ST; LOG && (S = +new Date); try{tmp = (1 === tmp.length? tmp[0] : JSON.stringify(tmp)); }catch(e){return opt.log('DAM JSON stringify error', e)} - LOG && opt.log(S, +new Date - S, 'say stringify', tmp.length); + LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'say stringify', tmp.length); if(!tmp){ return } send(tmp, peer); } diff --git a/lib/radisk.js b/lib/radisk.js index c9ba8196..db8555a7 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -47,7 +47,7 @@ cb = val; var S; LOG && (S = +new Date); val = r.batch(key); - LOG && opt.log(S, +new Date - S, 'rad mem'); + LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'rad mem'); if(u !== val){ cb(u, r.range(val, o), o); if(atomic(val)){ return } @@ -223,10 +223,13 @@ var tmp = ename(file); var S; LOG && (S = +new Date); r.list.add(tmp, function(err){ - LOG && opt.log(S, ST = +new Date - S, "wrote disk", tmp); - LOG && (ST > 500) && require('./email').send({text: ""+ST+"ms "+tmp, from: "mark@gun.eco", to: "mark@gun.eco", subject: "RAD DISK WROTE"}, noop); // this is ONLY turned on if ENV CONFIGS have email/password to send out from. if(err){ return cb(err) } - opt.store.put(tmp, f.text, cb); + //opt.store.put(tmp, f.text, cb); // revert to this after stats done below: + opt.store.put(tmp, f.text, function(err,ok){ + LOG && opt.log(S, ST = +new Date - S, "wrote disk", tmp); + LOG && (ST > 500) && require('./email').send({text: ""+ST+"ms "+tmp, from: "mark@gun.eco", to: "mark@gun.eco", subject: "RAD DISK WROTE"}, noop); // this is ONLY turned on if ENV CONFIGS have email/password to send out from. + cb(err,ok); + }); }); } f.slice = function(val, key){ @@ -326,7 +329,7 @@ if(!as.ack){ return } var S; LOG && (S = +new Date); var key = as.key, o = as.opt, info = g.info, rad = g.disk || noop, data = r.range(rad(key), o), last = rad.last || Radix.map(rad, rev, revo); - LOG && opt.log(S, +new Date - S, "rad range loaded"); + LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, "rad range loaded"); o.parsed = (o.parsed || 0) + (info.parsed||0); o.chunks = (o.chunks || 0) + 1; o.more = true; @@ -432,7 +435,7 @@ try{ var json = JSON.parse(data); // TODO: this caused a out-of-memory crash! p.disk.$ = json; - LOG && opt.log(S, ST = +new Date - S, 'rad parsed JSON'); + LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'rad parsed JSON'); map(q, p.ack); LOG && (ST > 500) && require('./email').send({text: ""+ST+"ms "+ename(file), from: "mark@gun.eco", to: "mark@gun.eco", subject: "RAD JSON parse"}, noop); // this is ONLY turned on if ENV CONFIGS have email/password to send out from. return; diff --git a/lib/store.js b/lib/store.js index c2b3fe74..68af264c 100644 --- a/lib/store.js +++ b/lib/store.js @@ -7,7 +7,7 @@ Gun.on('create', function(root){ if(false === opt.radisk){ return } var Radisk = (Gun.window && Gun.window.Radisk) || require('./radisk'); var Radix = Radisk.Radix; - var LOG = console.LOG; + var LOG = console.LOG, ST = 0; opt.store = opt.store || (!Gun.window && require('./rfs')(opt)); var rad = Radisk(opt), esc = String.fromCharCode(27); @@ -32,8 +32,7 @@ Gun.on('create', function(root){ rad(soul+esc+key, val, (track? ack : u)); C++; }); - LOG && Gun.log(S, +new Date - S, 'put loop'); - LOG && Gun.log(S, C, 'put loop #'); + if(LOG && (ST = +new Date - S) > 9){ Gun.log(S, ST, 'put loop'); Gun.log(S, C, 'put loop #') } function ack(err, ok){ acks--; if(ack.err){ return } @@ -105,11 +104,10 @@ Gun.on('create', function(root){ } if(!graph && data){ each(data, '') } } - LOG && Gun.log(S, +new Date - S, 'got prep time'); S = +new Date; - LOG && Gun.log(S, C, 'got prep #'); C = 0; + if(LOG && (ST = +new Date - S) > 9){ Gun.log(S, ST, 'got prep time'); Gun.log(S, C, 'got prep #') } C = 0; S = +new Date; var faith = function(){}; faith.faith = true; faith.rad = get; // HNPERF: We're testing performance improvement by skipping going through security again, but this should be audited. root.on('in', {'@': id, put: graph, '%': o.more? 1 : u, err: err? err : u, _: faith}); - LOG && Gun.log(S, +new Date - S, 'got emit', Object.keys(graph||{}).length); + LOG && (ST = +new Date - S) > 9 && Gun.log(S, ST, 'got emit', Object.keys(graph||{}).length); graph = u; // each is outside our scope, we have to reset graph to nothing! }, o); LOG && Gun.log(S, +new Date - S, 'get call'); From e6b61f667e8a04c965d9049bea43f0374cee2136 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Thu, 30 Jan 2020 20:36:22 -0800 Subject: [PATCH 08/87] how long is 1ms in actuality? --- gun.js | 6 +++++- lib/radisk.js | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/gun.js b/gun.js index 58699262..549dd3a5 100644 --- a/gun.js +++ b/gun.js @@ -2069,7 +2069,11 @@ flush(peer); } peer.batch = []; // peer.batch = '['; // TODO: Prevent double JSON! - setTimeout(function(){flush(peer)}, opt.gap); + var S, ST; LOG && (S = +new Date); + setTimeout(function(){ + LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, '1ms TO'); + flush(peer) + }, opt.gap); send(raw, peer); } function flush(peer){ diff --git a/lib/radisk.js b/lib/radisk.js index db8555a7..b08a56e8 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -152,6 +152,7 @@ if(s.gone){ return } s.gone = true; s.seq = []; map(s.files, function(mem, file){ s.seq.push({file: file, mem: mem}) }); + LOG && opt.log(+new Date, s.seq.length, "rad files #"); s.files = null; s.c = 0; s.merge(s.c); From 9dfdf608dc3a30b672d86e93d6672e2337c54467 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Fri, 31 Jan 2020 05:41:26 -0800 Subject: [PATCH 09/87] skip saving in-mem acks? thrash socket 0? --- gun.js | 8 ++++---- lib/rfsmix.js | 13 ++++++++----- lib/serve.js | 17 +++++++---------- lib/store.js | 9 +++++++-- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/gun.js b/gun.js index 549dd3a5..9a165f46 100644 --- a/gun.js +++ b/gun.js @@ -819,7 +819,7 @@ } node = Gun.graph.node(node); tmp = (at||empty).ack; - var faith = function(){}; faith.faith = true; // HNPERF: We're testing performance improvement by skipping going through security again, but this should be audited. + var faith = function(){}; faith.ram = faith.faith = true; // HNPERF: We're testing performance improvement by skipping going through security again, but this should be audited. root.on('in', { '@': msg['#'], how: 'mem', @@ -1963,7 +1963,7 @@ var mesh = function(){}; var opt = root.opt || {}; opt.log = opt.log || console.log; - opt.gap = opt.gap || opt.wait || 1; + opt.gap = opt.gap || opt.wait || 0; opt.pack = opt.pack || (opt.memory? (opt.memory * 1000 * 1000) : 1399000000) * 0.3; // max_old_space_size defaults to 1400 MB. var dup = root.dup; @@ -2009,9 +2009,9 @@ } return; } - var S, ST; LOG && (S = +new Date); + var S, ST; LOG && (S = +new Date); console.STAT = {}; root.on('in', msg); - if(LOG && !msg.nts && (ST = +new Date - S) > 9){ opt.log(S, ST, 'msg', msg['#']); if(ST > 500){ try{ require('./lib/email').send({text: ""+ST+"ms "+JSON.stringify(msg), from: "mark@gun.eco", to: "mark@gun.eco", subject: "GUN MSG"}, noop); }catch(e){} } } // this is ONLY turned on if ENV CONFIGS have email/password to send out from. + if(LOG && !msg.nts && (ST = +new Date - S) > 9){ opt.log(S, ST, 'msg', msg['#'], JSON.stringify(console.STAT)); if(ST > 500){ try{ require('./lib/email').send({text: ""+ST+"ms "+JSON.stringify(msg)+" | "+JSON.stringify(console.STAT), from: "mark@gun.eco", to: "mark@gun.eco", subject: "GUN MSG"}, noop); }catch(e){} } } // this is ONLY turned on if ENV CONFIGS have email/password to send out from. return; } } diff --git a/lib/rfsmix.js b/lib/rfsmix.js index dbe2cd97..1c06c7b5 100644 --- a/lib/rfsmix.js +++ b/lib/rfsmix.js @@ -3,11 +3,14 @@ module.exports = function(opt, store){ var p = store.put; var g = store.get; store.put = function(file, data, cb){ - rfs.put(file, data, function(err, ok){ - if(err){ return cb(err) } - //console.log("rfs3 cached", file); - p(file, data, cb); - }); + var a, b, c = function(err, ok){ + if(b){ return cb(err || b) } + if(a){ return cb(err, ok) } + a = true; + b = err; + } + p(file, data, c); // parallel + rfs.put(file, data, c); // parallel } store.get = function(file, cb){ rfs.get(file, function(err, data){ diff --git a/lib/serve.js b/lib/serve.js index b315cf88..55d36257 100644 --- a/lib/serve.js +++ b/lib/serve.js @@ -8,10 +8,10 @@ function CDN(dir){ req.url = (req.url||'').replace(dot,'').replace(slash,'/'); if(serve(req, res)){ return } // filters GUN requests! fs.createReadStream(path.join(dir, req.url)).on('error',function(tmp){ // static files! - try{ tmp = fs.readFileSync(path.join(dir, 'index.html')) }catch(e){} - try{ res.writeHead(200, {'Content-Type': 'text/html'}); - res.end(tmp+''); }catch(e){} // or default to index - }).pipe(res); // stream + fs.readFile(path.join(dir, 'index.html'), function(err, tmp){ + try{ res.writeHead(200, {'Content-Type': 'text/html'}); + res.end(tmp+''); }catch(e){} // or default to index + })}).pipe(res); // stream } } @@ -28,12 +28,9 @@ function serve(req, res, next){ var tmp; } if(0 <= req.url.indexOf('gun/')){ res.writeHead(200, {'Content-Type': 'text/javascript'}); - var path = __dirname + '/../' + req.url.split('/').slice(2).join('/'), file; - try{file = require('fs').readFileSync(path)}catch(e){} - if(file){ - res.end(file); - return true; - } + var path = __dirname + '/../' + req.url.split('/').slice(2).join('/'); + fs.readFile(path, function(err, file){ res.end((file || (err && 404))+'') }); + return true; } if((tmp = req.socket) && (tmp = tmp.server) && (tmp = tmp.route)){ var url; if(tmp = tmp[(((req.url||'').slice(1)).split('/')[0]||'').split('.')[0]]){ diff --git a/lib/store.js b/lib/store.js index 68af264c..55a32487 100644 --- a/lib/store.js +++ b/lib/store.js @@ -15,8 +15,10 @@ Gun.on('create', function(root){ root.on('put', function(msg){ this.to.next(msg); var id = msg['#'] || Gun.text.random(3), track = !msg['@'], acks = track? 0 : u; // only ack non-acks. - var got = (msg._||empty).rad, now = Gun.state(); + var _ = (msg._||empty), got = _.rad; + if(_.ram){ return } // in-memory ACKs to GETs do not need to be written to disk again. var S = (+new Date), C = 0; // STATS! + var now = Gun.state(); Gun.graph.is(msg.put, null, function(val, key, node, soul){ if(!track && got){ var at = (root.next||empty)[soul]; @@ -33,6 +35,7 @@ Gun.on('create', function(root){ C++; }); if(LOG && (ST = +new Date - S) > 9){ Gun.log(S, ST, 'put loop'); Gun.log(S, C, 'put loop #') } + console.STAT && (console.STAT.radputloop = ST) && (console.STAT.radputcount = C); function ack(err, ok){ acks--; if(ack.err){ return } @@ -104,13 +107,15 @@ Gun.on('create', function(root){ } if(!graph && data){ each(data, '') } } + console.STAT && (console.STAT.radgetcount = C); if(LOG && (ST = +new Date - S) > 9){ Gun.log(S, ST, 'got prep time'); Gun.log(S, C, 'got prep #') } C = 0; S = +new Date; var faith = function(){}; faith.faith = true; faith.rad = get; // HNPERF: We're testing performance improvement by skipping going through security again, but this should be audited. root.on('in', {'@': id, put: graph, '%': o.more? 1 : u, err: err? err : u, _: faith}); LOG && (ST = +new Date - S) > 9 && Gun.log(S, ST, 'got emit', Object.keys(graph||{}).length); graph = u; // each is outside our scope, we have to reset graph to nothing! }, o); - LOG && Gun.log(S, +new Date - S, 'get call'); + LOG && (ST = +new Date - S) > 9 && Gun.log(S, ST, 'get call'); + console.STAT && (console.STAT.radget = ST); function each(val, has, a,b){ // TODO: THIS CODE NEEDS TO BE FASTER!!!! C++; if(!val){ return } From 328ae52c2c42f7be7e2c2cb9764237e2eca70f02 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 2 Feb 2020 01:09:48 -0800 Subject: [PATCH 10/87] begin --- gun.js | 21 +++++++++++++-------- lib/evict.js | 2 +- lib/radisk.js | 6 ++++-- lib/store.js | 2 +- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/gun.js b/gun.js index 9a165f46..b4f81ef9 100644 --- a/gun.js +++ b/gun.js @@ -1957,7 +1957,7 @@ ;USE(function(module){ var Type = USE('../type'); - var puff = (typeof setImmediate !== "undefined")? setImmediate : setTimeout; + var puff = setTimeout; //(typeof setImmediate !== "undefined")? setImmediate : setTimeout; function Mesh(root){ var mesh = function(){}; @@ -1976,15 +1976,18 @@ if('{' != raw[2]){ mesh.hear.d += raw.length||0; ++mesh.hear.c; } // STATS! // ugh, stupid double JSON encoding if('[' === tmp){ try{msg = JSON.parse(raw);}catch(e){opt.log('DAM JSON parse error', e)} + raw = ''; if(!msg){ return } LOG && opt.log(+new Date, msg.length, '# on hear batch'); (function go(){ // stats on single msg is 99% spike of batch stats. - var m, c = 100; // hardcoded for now? - while(c-- && (m = msg.shift())){ + var m, i = 0, c = 100; // hardcoded for now? + while(c-- && (m = msg[i++])){ mesh.hear(m, peer); } + msg = msg.slice(i); + // TODO: consider triggering peer flush to response times speedier! if(!msg.length){ return } - puff(go, 0); + puff(go, 1); }()); return; } @@ -1995,14 +1998,15 @@ if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } if(msg.DBG_s){ opt.log(+new Date - msg.DBG_s, 'to hear', id) } if(dup.check(id)){ return } - dup.track(id, true).it = it(msg); // GUN core also dedups, so `true` is needed. // Does GUN core need to dedup anymore? - if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } + dup.track(id, true); //.it = it(msg); // GUN core also dedups, so `true` is needed. // Does GUN core need to dedup anymore? + /*if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } if(hash && (tmp = msg['@'] || (msg.get && id))){ // Reduces backward daisy in case varying hashes at different daisy depths are the same. if(dup.check(tmp+hash)){ return } dup.track(tmp+hash, true).it = it(msg); // GUN core also dedups, so `true` is needed. // Does GUN core need to dedup anymore? } - (msg._ = function(){}).via = peer; if(tmp = msg['><']){ (msg._).to = Type.obj.map(tmp.split(','), tomap) } + */ // TOOD: COME BACK TO THIS LATER!!! IMPORTANT MESH STUFF!! + (msg._ = function(){}).via = peer; if(msg.dam){ if(tmp = mesh.hear[msg.dam]){ tmp(msg, peer, root); @@ -2010,7 +2014,8 @@ return; } var S, ST; LOG && (S = +new Date); console.STAT = {}; - root.on('in', msg); + //root.on('in', msg); + root.on('in2', msg); if(LOG && !msg.nts && (ST = +new Date - S) > 9){ opt.log(S, ST, 'msg', msg['#'], JSON.stringify(console.STAT)); if(ST > 500){ try{ require('./lib/email').send({text: ""+ST+"ms "+JSON.stringify(msg)+" | "+JSON.stringify(console.STAT), from: "mark@gun.eco", to: "mark@gun.eco", subject: "GUN MSG"}, noop); }catch(e){} } } // this is ONLY turned on if ENV CONFIGS have email/password to send out from. return; } diff --git a/lib/evict.js b/lib/evict.js index 48e69437..8647f95e 100644 --- a/lib/evict.js +++ b/lib/evict.js @@ -10,7 +10,7 @@ try{ heap = require('v8').getHeapStatistics }catch(e){} if(!heap){ return } - ev.max = parseFloat(root.opt.memory || (heap().heap_size_limit / 1024 / 1024) || process.env.WEB_MEMORY || 1399) * 0.8; // max_old_space_size defaults to 1400 MB. Note: old space !== memory space though. + ev.max = parseFloat(root.opt.memory || (heap().heap_size_limit / 1024 / 1024) || process.env.WEB_MEMORY || 1399) * 0.8; // max_old_space_size defaults to 1400 MB. Note: old space !== memory space though. // KEEPING USED_HEA_SIZE < HEAP_SIZE_LIMIT ONLY THING TO BE BELOW TO PREVENT CRASH! setInterval(check, 1000); function check(){ diff --git a/lib/radisk.js b/lib/radisk.js index b08a56e8..3e7ac2f0 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -174,12 +174,14 @@ return; } disk = disk || Radix(); - var S; LOG && (S = +new Date); + var S, C = 0; LOG && (S = +new Date); Radix.map(mem, function(val, key){ + C++; // PLUGIN: consider adding HAM as an extra layer of protection disk(key, val); // merge batch[key] -> disk[key] }); - LOG && opt.log(S, +new Date - S, "rad merge mem & disk"); + LOG && opt.log(S, +new Date - S, "rad merge"); + LOG && opt.log(S, C, "rad merge #"); r.write(file, disk, s.pop); }) } diff --git a/lib/store.js b/lib/store.js index 55a32487..be5c5b0a 100644 --- a/lib/store.js +++ b/lib/store.js @@ -96,7 +96,7 @@ Gun.on('create', function(root){ if(err){ opt.store.stats.get.err = err } }catch(e){} // STATS! //if(u === data && o.chunks > 1){ return } // if we already sent a chunk, ignore ending empty responses. // this causes tests to fail. - LOG && Gun.log(S, +new Date - S, 'got'); S = +new Date; + LOG && Gun.log(S, +new Date - S, 'got', JSON.stringify(key)); S = +new Date; if(data){ if(typeof data !== 'string'){ if(o.atom){ From d3e89c2adc24e56ca6c707306ba080eee1821535 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 2 Feb 2020 01:13:47 -0800 Subject: [PATCH 11/87] live debug ? --- Aptfile | 2 ++ Procfile | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Aptfile diff --git a/Aptfile b/Aptfile new file mode 100644 index 00000000..1b55cba9 --- /dev/null +++ b/Aptfile @@ -0,0 +1,2 @@ +linux-tools-common +linux-tools-generic \ No newline at end of file diff --git a/Procfile b/Procfile index 875fe822..f814922f 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: node --optimize_for_size --gc_interval=100 examples/http.js +web: node --inspect examples/http.js From c5d3ef47e723e6e584eeb7d5910aaa1bbbb6b063 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 2 Feb 2020 09:17:43 -0800 Subject: [PATCH 12/87] try live debug (chrome inspector) --- Procfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Procfile b/Procfile index f814922f..cbb01468 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: node --inspect examples/http.js +web: node --debug=9090 --inspect --perf-basic-prof-only-functions examples/http.js From cc6415fa444f56190802659bf9c00e50b46024f7 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 2 Feb 2020 09:24:37 -0800 Subject: [PATCH 13/87] Update Aptfile --- Aptfile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Aptfile b/Aptfile index 1b55cba9..8bac94ca 100644 --- a/Aptfile +++ b/Aptfile @@ -1,2 +1,6 @@ linux-tools-common -linux-tools-generic \ No newline at end of file +linux-tools-generic +linux-tools-4.4.0-1057-aws +linux-cloud-tools-4.4.0-1057-aws +linux-tools-aws +linux-cloud-tools-aws \ No newline at end of file From ebfd82eac6d7a8adb2e114317cd53e059f0d4625 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 2 Feb 2020 09:27:51 -0800 Subject: [PATCH 14/87] Update Aptfile --- Aptfile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Aptfile b/Aptfile index 8bac94ca..0d99b744 100644 --- a/Aptfile +++ b/Aptfile @@ -1,6 +1,4 @@ linux-tools-common linux-tools-generic -linux-tools-4.4.0-1057-aws -linux-cloud-tools-4.4.0-1057-aws linux-tools-aws linux-cloud-tools-aws \ No newline at end of file From 6281fed309509724595cbed4e044120a447f52f5 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 2 Feb 2020 09:31:26 -0800 Subject: [PATCH 15/87] Update Aptfile --- Aptfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Aptfile b/Aptfile index 0d99b744..844cac60 100644 --- a/Aptfile +++ b/Aptfile @@ -1,4 +1,3 @@ linux-tools-common linux-tools-generic -linux-tools-aws -linux-cloud-tools-aws \ No newline at end of file +linux-tools-aws \ No newline at end of file From cae82648321662d625fdbe3696ffaa4dfb1e528f Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 2 Feb 2020 09:40:49 -0800 Subject: [PATCH 16/87] Update Procfile --- Procfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Procfile b/Procfile index cbb01468..92d3c2f2 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: node --debug=9090 --inspect --perf-basic-prof-only-functions examples/http.js +web: node --inspect --perf-basic-prof-only-functions examples/http.js From c97526a36cea2ca1d46e4c1b94496be28338dbb2 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 2 Feb 2020 09:40:59 -0800 Subject: [PATCH 17/87] Update Procfile --- Procfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Procfile b/Procfile index 92d3c2f2..8006d00b 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: node --inspect --perf-basic-prof-only-functions examples/http.js +web: node --inspect=9090 --perf-basic-prof-only-functions examples/http.js From d8f3ed7edbb913a78f7220ec2518ea6ad99c59d5 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 2 Feb 2020 10:05:10 -0800 Subject: [PATCH 18/87] Update Procfile --- Procfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Procfile b/Procfile index 8006d00b..516fbc04 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: node --inspect=9090 --perf-basic-prof-only-functions examples/http.js +web: node --inspect=0.0.0.0:9090 --perf-basic-prof-only-functions examples/http.js From 75148ec5409ab5f19d8b5ed529421e0be8676fd4 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 2 Feb 2020 10:33:37 -0800 Subject: [PATCH 19/87] Update Procfile --- Procfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Procfile b/Procfile index 516fbc04..f814922f 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: node --inspect=0.0.0.0:9090 --perf-basic-prof-only-functions examples/http.js +web: node --inspect examples/http.js From a980f4efc176195ce7bdb791b0e5f68962bae87c Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 2 Feb 2020 22:30:13 -0800 Subject: [PATCH 20/87] ? trace ? tmp --- Procfile | 2 +- examples/http.js | 4 ++-- package.json | 1 + trace.js | 25 +++++++++++++++++++++++++ 4 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 trace.js diff --git a/Procfile b/Procfile index f814922f..49049048 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: node --inspect examples/http.js +web: node --inspect trace.js diff --git a/examples/http.js b/examples/http.js index 3ae161e1..dba51779 100644 --- a/examples/http.js +++ b/examples/http.js @@ -1,8 +1,8 @@ ;(function(){ - var cluster = require('cluster'); + /*var cluster = require('cluster'); if(cluster.isMaster){ return cluster.fork() && cluster.on('exit', function(){ cluster.fork() }); - } + }*/ var fs = require('fs'); var config = { port: process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765 }; diff --git a/package.json b/package.json index e31efe13..1f7cdc09 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "mocha": "^6.2.0", "panic-manager": "^1.2.0", "panic-server": "^1.1.1", + "0x": "^4.9.1", "uglify-js": "^3.6.0" } } diff --git a/trace.js b/trace.js new file mode 100644 index 00000000..8c07a085 --- /dev/null +++ b/trace.js @@ -0,0 +1,25 @@ +;(async function start(){ + var z; + try{ z = require('0x'); + } catch(e){ + return require('./examples/http.js'); + } + function go(){ + start(); + setTimeout(function(){try{ + var zip = require("child_process"); + zip.execSync('zip -r flame *', {cwd: './flame'}); + require('./lib/fsrm')('./flame'); + require('./lib/email').send({ + text: "zip attached", + from: "mark@gun.eco", + to: "mark@gun.eco", + subject: "TRACE GUN", + attachment:[{path:"./flame.zip", type:"application/zip", name:"flame.zip"}] + }, function(err){ + err && console.log("@@@@@@@@@@ EMAIL ERROR @@@@@@@@@@", err); + }) + }catch(err){ console.log("@@@@@@@@@@ TRACE ERROR @@@@@@@@@", err) }},5000); + } + require('0x')({argv: ['./examples/http.js'], outputDir: 'flame', workingDir: __dirname, onProcessExit: go}); +}()); \ No newline at end of file From 782750d7287831377536031df0cf083f88c82291 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 2 Feb 2020 22:57:06 -0800 Subject: [PATCH 21/87] Update trace.js --- trace.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/trace.js b/trace.js index 8c07a085..fe75e166 100644 --- a/trace.js +++ b/trace.js @@ -8,18 +8,18 @@ start(); setTimeout(function(){try{ var zip = require("child_process"); - zip.execSync('zip -r flame *', {cwd: './flame'}); - require('./lib/fsrm')('./flame'); + zip.execSync('zip -r flametracedata.zip flamedata/'); + require('./lib/fsrm')('./flamedata'); require('./lib/email').send({ text: "zip attached", from: "mark@gun.eco", to: "mark@gun.eco", subject: "TRACE GUN", - attachment:[{path:"./flame.zip", type:"application/zip", name:"flame.zip"}] + attachment:[{path: __dirname+"/flametracedata.zip", type:"application/zip", name:"flametracedata.zip"}] }, function(err){ err && console.log("@@@@@@@@@@ EMAIL ERROR @@@@@@@@@@", err); }) }catch(err){ console.log("@@@@@@@@@@ TRACE ERROR @@@@@@@@@", err) }},5000); } - require('0x')({argv: ['./examples/http.js'], outputDir: 'flame', workingDir: __dirname, onProcessExit: go}); + require('0x')({argv: ['./examples/http.js'], outputDir: 'flamedata', workingDir: __dirname, onProcessExit: go}); }()); \ No newline at end of file From a5a0eab24ccad99fa4c172cd4c66201c2ce4d471 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sun, 2 Feb 2020 22:59:48 -0800 Subject: [PATCH 22/87] Update trace.js --- trace.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/trace.js b/trace.js index fe75e166..e7d57879 100644 --- a/trace.js +++ b/trace.js @@ -17,7 +17,9 @@ subject: "TRACE GUN", attachment:[{path: __dirname+"/flametracedata.zip", type:"application/zip", name:"flametracedata.zip"}] }, function(err){ - err && console.log("@@@@@@@@@@ EMAIL ERROR @@@@@@@@@@", err); + if(!err){ return } + console.log("@@@@@@@@@@ EMAIL ERROR @@@@@@@@@@", err); + require('./lib/email').send({text: "check https://gunjs.herokuapp.com/gun/flametracedata.zip", from: "mark@gun.eco", to: "mark@gun.eco", subject: "TRACE GUN CHECK"}, function(err){}); }) }catch(err){ console.log("@@@@@@@@@@ TRACE ERROR @@@@@@@@@", err) }},5000); } From 827197dbb7be483852a4bbf70c41ab49a73f0c65 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 3 Feb 2020 10:27:49 -0800 Subject: [PATCH 23/87] only flamegraph emails --- gun.js | 2 +- lib/radisk.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/gun.js b/gun.js index 9a165f46..3b9860a2 100644 --- a/gun.js +++ b/gun.js @@ -2011,7 +2011,7 @@ } var S, ST; LOG && (S = +new Date); console.STAT = {}; root.on('in', msg); - if(LOG && !msg.nts && (ST = +new Date - S) > 9){ opt.log(S, ST, 'msg', msg['#'], JSON.stringify(console.STAT)); if(ST > 500){ try{ require('./lib/email').send({text: ""+ST+"ms "+JSON.stringify(msg)+" | "+JSON.stringify(console.STAT), from: "mark@gun.eco", to: "mark@gun.eco", subject: "GUN MSG"}, noop); }catch(e){} } } // this is ONLY turned on if ENV CONFIGS have email/password to send out from. + if(LOG && !msg.nts && (ST = +new Date - S) > 9){ opt.log(S, ST, 'msg', msg['#'], JSON.stringify(console.STAT)) } return; } } diff --git a/lib/radisk.js b/lib/radisk.js index b08a56e8..1efe678f 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -228,7 +228,6 @@ //opt.store.put(tmp, f.text, cb); // revert to this after stats done below: opt.store.put(tmp, f.text, function(err,ok){ LOG && opt.log(S, ST = +new Date - S, "wrote disk", tmp); - LOG && (ST > 500) && require('./email').send({text: ""+ST+"ms "+tmp, from: "mark@gun.eco", to: "mark@gun.eco", subject: "RAD DISK WROTE"}, noop); // this is ONLY turned on if ENV CONFIGS have email/password to send out from. cb(err,ok); }); }); @@ -438,7 +437,6 @@ p.disk.$ = json; LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'rad parsed JSON'); map(q, p.ack); - LOG && (ST > 500) && require('./email').send({text: ""+ST+"ms "+ename(file), from: "mark@gun.eco", to: "mark@gun.eco", subject: "RAD JSON parse"}, noop); // this is ONLY turned on if ENV CONFIGS have email/password to send out from. return; }catch(e){ tmp = e } if('{' === data[0]){ From efd055c2b07f9bceb5ed4e2f2477df0b693a2ac7 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 3 Feb 2020 14:25:41 -0800 Subject: [PATCH 24/87] notes & tests --- lib/radisk.js | 2 +- lib/radix.js | 13 +++--- lib/store.js | 2 +- test/mocha.html | 2 +- test/ptsd/radix.js | 102 +++++++++++++++++++++++++++++++++++++++++++-- test/rad/rad.js | 13 +++++- test/radix.js | 2 +- 7 files changed, 121 insertions(+), 15 deletions(-) diff --git a/lib/radisk.js b/lib/radisk.js index 3e7ac2f0..3e4fd152 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -274,7 +274,7 @@ if(u === o.start && u === o.end){ return tree } if(atomic(tree)){ return tree } var sub = Radix(); - Radix.map(tree, function(v,k){ + Radix.map(tree, function(v,k){ // ONLY PLACE THAT TAKES TREE, maybe reduce API for better perf? sub(k,v); }, o); return sub(''); diff --git a/lib/radix.js b/lib/radix.js index a3523f3e..e338e3fb 100644 --- a/lib/radix.js +++ b/lib/radix.js @@ -51,23 +51,24 @@ return radix; }; - Radix.map = function map(radix, cb, opt, pre){ pre = pre || []; // TODO: BUG: most out-of-memory crashes come from here. + Radix.map = function rap(radix, cb, opt, pre){ pre = pre || []; // TODO: BUG: most out-of-memory crashes come from here. var t = ('function' == typeof radix)? radix.$ || {} : radix; + //!opt && console.log("WHAT IS T?", JSON.stringify(t).length); if(!t){ return } - var keys = (t[_]||no).sort || (t[_] = function $(){ $.sort = Object.keys(t).sort(); return $ }()).sort, rev; + var keys = (t[_]||no).sort || (t[_] = function $(){ $.sort = Object.keys(t).sort(); return $ }()).sort, rev; // ONLY 17% of ops are pre-sorted! //var keys = Object.keys(t).sort(); opt = (true === opt)? {branch: true} : (opt || {}); - if(rev = opt.reverse){ keys = keys.slice().reverse() } + if(rev = opt.reverse){ keys = keys.slice(0).reverse() } var start = opt.start, end = opt.end, END = '\uffff'; var i = 0, l = keys.length; for(;i < l; i++){ var key = keys[i], tree = t[key], tmp, p, pt; if(!tree || '' === key || _ === key){ continue } - p = pre.slice(); p.push(key); + p = pre.slice(0); p.push(key); pt = p.join(''); if(u !== start && pt < (start||'').slice(0,pt.length)){ continue } if(u !== end && (end || END) < pt){ continue } if(rev){ // children must be checked first when going in reverse. - tmp = map(tree, cb, opt, p); + tmp = rap(tree, cb, opt, p); if(u !== tmp){ return tmp } } if(u !== (tmp = tree[''])){ @@ -85,7 +86,7 @@ } pre = p; if(!rev){ - tmp = map(tree, cb, opt, pre); + tmp = rap(tree, cb, opt, pre); if(u !== tmp){ return tmp } } pre.pop(); diff --git a/lib/store.js b/lib/store.js index be5c5b0a..80c26c36 100644 --- a/lib/store.js +++ b/lib/store.js @@ -102,7 +102,7 @@ Gun.on('create', function(root){ if(o.atom){ data = u; } else { - Radix.map(data, each) + Radix.map(data, each); // IS A RADIX TREE, NOT FUNCTION! } } if(!graph && data){ each(data, '') } diff --git a/test/mocha.html b/test/mocha.html index 229040e6..13bcf7a4 100644 --- a/test/mocha.html +++ b/test/mocha.html @@ -38,7 +38,7 @@ console.log('async?', Gun.debug); } var run = mocha.run(function(a,b,c){ - //document.body.prepend("MARK! REMEMBER TO REMOVE RETURN!");return; + document.body.prepend("MARK! REMEMBER TO REMOVE RETURN!");return; var yes = confirm("REFRESH BROWSER FOR ASYNC TESTS?"); if(yes){ if(location.search){ diff --git a/test/ptsd/radix.js b/test/ptsd/radix.js index 81a8227d..4e4d5f79 100644 --- a/test/ptsd/radix.js +++ b/test/ptsd/radix.js @@ -16,11 +16,105 @@ stool.run(); },1); stool.setup(window.setup = function(){ - window.BigText = Gun.text.random(1024, 'abcdef'); - window.MedText = Gun.text.random(200, 'abcdef'); - window.jsonText = JSON.stringify(window.BigText); - window.radText = Radisk.encode(window.BigText); + //window.BigText = Gun.text.random(1024, 'abcdef'); + //window.MedText = Gun.text.random(200, 'abcdef'); + //window.jsonText = JSON.stringify(window.BigText); + //window.radText = Radisk.encode(window.BigText); + + window.namez = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammamaria","Andy","Anselme","Ardeen","Armand","Ashelman","Aube","Averyl","Baker","Barger","Baten","Bee","Benia","Bernat","Bevers","Bittner","Bobbe","Bonny","Boyce","Breech","Brittaney","Bryn","Burkitt","Cadmann","Campagna","Carlee","Carver","Cavallaro","Chainey","Chaunce","Ching","Cianca","Claudina","Clyve","Colon","Cooke","Corrina","Crawley","Cullie","Dacy","Daniela","Daryn","Deedee","Denie","Devland","Dimitri","Dolphin","Dorinda","Dream","Dunham","Eachelle","Edina","Eisenstark","Elish","Elvis","Eng","Erland","Ethan","Evelyn","Fairman","Faus","Fenner","Fillander","Flip","Foskett","Fredette","Fullerton","Gamali","Gaspar","Gemina","Germana","Gilberto","Giuditta","Goer","Gotcher","Greenstein","Grosvenor","Guthrey","Haldane","Hankins","Harriette","Hayman","Heise","Hepsiba","Hewie","Hiroshi","Holtorf","Howlond","Hurless","Ieso","Ingold","Isidora","Jacoba","Janelle","Jaye","Jennee","Jillana","Johnson","Josy","Justinian","Kannan","Kast","Keeley","Kennett","Kho","Kiran","Knowles","Koser","Kroll","LaMori","Lanctot","Lasky","Laverna","Leff","Leonanie","Lewert","Lilybel","Lissak","Longerich","Lou","Ludeman","Lyman","Madai","Maia","Malvina","Marcy","Maris","Martens","Mathilda","Maye","McLain","Melamie","Meras","Micco","Millburn","Mittel","Montfort","Moth","Mutz","Nananne","Nazler","Nesta","Nicolina","Noellyn","Nuli","Ody","Olympie","Orlena","Other","Pain","Parry","Paynter","Pentheas","Pettifer","Phyllida","Plath","Posehn","Proulx","Quinlan","Raimes","Ras","Redmer","Renelle","Ricard","Rior","Rocky","Ron","Rosetta","Rubia","Ruttger","Salbu","Sandy","Saw","Scholz","Secor","September","Shanleigh","Shenan","Sholes","Sig","Sisely","Soble","Spanos","Stanwinn","Stevie","Stu","Suzanne","Tacy","Tanney","Tekla","Thackeray","Thomasin","Tilla","Tomas","Tracay","Tristis","Ty","Urana","Valdis","Vasta","Vezza","Vitoria","Wait","Warring","Weissmann","Whetstone","Williamson","Wittenburg","Wymore","Yoho","Zamir","Zimmermann"]; + window.radiz = window.radiz || Radix(); + window.arr = []; var i = 1000; while(--i){ arr.push(Math.random()) } + window.arrs = arr.slice(0).sort(); }); + /* TEMPORARY COPY OF RADIX UNIT TESTS TO BOOST SPEED */ + /* THESE ARE PROBABLY STALE AND NEED TO BE COPIED FROM UNIT TESTS AGAIN */ + stool.add('1', function(){ + var rad = Radix(); + rad('asdf.pub', 'yum'); + rad('ablah', 'cool'); + rad('node/circle.bob', 'awesome'); + + (rad('asdf.').pub[''] !== 'yum') && bad1; + (rad('nv/foo.bar') !== undefined) && bad2; + }); + stool.add('2', function(){ + var all = {}; + namez.forEach(function(v,i){ + v = v.toLowerCase(); + all[v] = v; + radiz(v, i) + }); + (Gun.obj.empty(all) === true) && bad3; + Radix.map(radiz, function(v,k){ + delete all[k]; + }); + (Gun.obj.empty(all) !== true) && bad4; + }); + stool.add('3', function(){ + var all = {}; + namez.forEach(function(v,i){ + v = v.toLowerCase(); + all[v] = v; + //rad(v, i) + }); + (Gun.obj.empty(all) === true) && bad5; + Radix.map(radiz, function(v,k){ + delete all[k]; + }); + (Gun.obj.empty(all) !== true) && bad6; + }); + stool.add('4', function(){ + var all = {}, start = 'Warring'.toLowerCase(), end = 'Zamir'.toLowerCase(); + namez.forEach(function(v,i){ + v = v.toLowerCase(); + if(v < start){ return } + if(end < v){ return } + all[v] = v; + //rad(v, i) + }); + (Gun.obj.empty(all) === true) && bad7; + Radix.map(radiz, function(v,k, a,b){ + //if(!all[k]){ throw "out of range!" } + delete all[k]; + }, {start: start, end: end}); + (Gun.obj.empty(all) !== true) && bad8; + }); + stool.add('5', function(){ + var all = {}, start = 'Warrinf'.toLowerCase(), end = 'Zamis'.toLowerCase(); + namez.forEach(function(v,i){ + v = v.toLowerCase(); + if(v < start){ return } + if(end < v){ return } + all[v] = v; + //rad(v, i) + }); + (Gun.obj.empty(all) === true) && bad9; + Radix.map(radiz, function(v,k, a,b){ + //if(!all[k]){ throw "out of range!" } + delete all[k]; + }, {start: start, end: end}); + (Gun.obj.empty(all) !== true) && bad10; + }); + stool.add('6', function(){ + var r = Radix(), tmp; + r('alice', 1);r('bob', 2);r('carl', 3);r('carlo',4); + r('dave', 5);r('zach',6);r('zachary',7); + var by = ['alice','bob','carl','carlo','dave','zach','zachary']; + Gun.obj.map(by, function(k,i){ + r(k,i); + }); + Radix.map(r, function(v,k, a,b){ + (by.pop() !== k) && bad11; + tmp = v; + }, {reverse: 1}); + (tmp !== 1) && bad12; + (by.length !== 0) && bad13; + Radix.map(r, function(v,k, a,b){ + tmp = v; + }); + (tmp !== 7) && bad14; + }); + return; stool.add('JSON encode string', function(){ JSON.stringify(window.BigText); }); diff --git a/test/rad/rad.js b/test/rad/rad.js index d1a638d2..28ccda24 100644 --- a/test/rad/rad.js +++ b/test/rad/rad.js @@ -43,8 +43,19 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam //console.log("HYPER TEST");var z = 10000; while(--z){ names.push(Gun.text.random(7)) }this.timeout(9000); - describe('Radix', function(){ + describe.only('Radix', function(){ var radix = Radix(); + + it('unit', function(){ + var rad = Radix(); + rad('asdf.pub', 'yum'); + rad('ablah', 'cool'); + rad('node/circle.bob', 'awesome'); + + expect(rad('asdf.')).to.be.eql({pub: {'': 'yum'}}); + expect(rad('nv/foo.bar')).to.be(undefined); + }); + it('radix write read', function(done){ var all = {}; names.forEach(function(v,i){ diff --git a/test/radix.js b/test/radix.js index 38450c1e..7ec5f37e 100644 --- a/test/radix.js +++ b/test/radix.js @@ -3,7 +3,7 @@ var expect = global.expect = require("./expect"); var Radix = require('../lib/radix'); var _ = String.fromCharCode(29); -describe('Radix', function(){ +describe('Radix', function(){ // moved to ./rad/rad.js it('read', function(){ var rad = Radix(); rad('asdf.pub', 'yum'); From fa8a63606c14bdd993cc2dca811c7cfcb99c72c2 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 3 Feb 2020 14:26:01 -0800 Subject: [PATCH 25/87] TODO SPAM, REMEMBER TO UNCOMMIT --- examples/todo/index.html | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/examples/todo/index.html b/examples/todo/index.html index 1bba2922..e1061c57 100644 --- a/examples/todo/index.html +++ b/examples/todo/index.html @@ -114,6 +114,30 @@ +

    `! + */ + path?(path: string | string[]): ChainReference; + /** + * Handle cases where data can't be found. + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/not.js')` or + * ``! + */ + not?(callback: (key: ReferenceKey) => void): ChainReference; + /** + * Open behaves very similarly to gun.on, except it gives you the **full depth of a document** on every update. + * It also works with graphs, tables, or other data structures. Think of it as opening up a live connection to a document. + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/open.js')` or + * ``! + */ + open?(callback: (data: ArrayAsRecord) => void): ChainReference; + /** + * Loads the full object once. It is the same as `open` but with the behavior of `once`. + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/load.js')` or + * ``! + */ + load?(callback: (data: ArrayAsRecord) => void): ChainReference; + /** + * Returns a promise for you to use. + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/then.js')` or + * ``! + */ + then?>( + onfulfilled?: (value: TResult1) => TResult1 | PromiseLike + ): Promise; + /** + * Returns a promise for you to use. + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/then.js')` or + * ``! + */ + promise?< + TResult1 = { put: ArrayAsRecord; key: ReferenceKey; gun: ChainReference } + >( + onfulfilled?: (value: TResult1) => TResult1 | PromiseLike + ): Promise; + /** + * bye lets you change data after that browser peer disconnects. + * This is useful for games and status messages, + * that if a player leaves you can remove them from the game or set a user's status to "away". + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/bye.js')` or + * ``! + */ + bye?(): { + put(data: DisallowArray>): void; + }; + /** + * Say you save some data, but want to do something with it later, like expire it or refresh it. + * Well, then `later` is for you! You could use this to easily implement a TTL or similar behavior. + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/later.js')` or + * ``! + */ + later?( + callback: ( + this: ChainReference, + data: ArrayAsRecord, + key: ReferenceKey + ) => void, + seconds: number + ): ChainReference; + /** + * After you save some data in an unordered list, you may need to remove it. + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/unset.js')` or + * ``! + */ + unset?(data: ArrayOf): ChainReference; + /** + * Subscribes to all future events that occur on the Timegraph and retrieve a specified number of old events + * + * **Warning**: The Timegraph extension isn't required by default, you would need to include at "gun/lib/time.js" + */ + time?( + callback: (data: ArrayOf, key: ReferenceKey, time: number) => void, + alsoReceiveNOldEvents?: number + ): ChainReference; + /** Pushes data to a Timegraph with it's time set to Gun.state()'s time */ + time?(data: ArrayOf): void; + //#endregion + //#region User + /** + * Creates a new user and calls callback upon completion. + * @param alias Username or Alias which can be used to find a user. + * @param pass Passphrase that will be extended with PBKDF2 to make it a secure way to login. + * @param cb Callback that is to be called upon creation of the user. + * @param opt Option Object containing options for creation. (In gun options are added at end of syntax. opt is rarely used, hence is added at the end.) + */ + create( + alias: string, + pass: string, + cb?: (ack: { ok: 0; pub: string } | { err: string }) => void, + opt?: {} + ): ChainReference; + /** + * Authenticates a user, previously created via User.create. + * @param alias Username or Alias which can be used to find a user. + * @param pass Passphrase for the user + * @param cb Callback that is to be called upon authentication of the user. + * @param opt Option Object containing options for authentiaction. (In gun options are added at end of syntax. opt is rarely used, hence is added at the end.) + */ + auth( + alias: string, + pass: string, + cb?: ( + ack: + | { + ack: 2; + get: string; + on: (...args: [unknown, unknown, unknown]) => unknown; + put: { alias: string; auth: any; epub: string; pub: string }; + sea: CryptoKeyPair; + soul: string; + } + | { err: string } + ) => void, + opt?: {} + ): ChainReference; + /** + * Returns the key pair in the form of an object as below. + */ + pair(): CryptoKeyPair; + /** + * Log out currently authenticated user. Parameters are unused in the current implementation. + * @param opt unused in current implementation. + * @param cb unused in current implementation. + */ + leave(opt?: never, cb?: never): ChainReference; + /** + * Deletes a user from the current gun instance and propagates the delete to other peers. + * @param alias Username or alias. + * @param pass Passphrase for the user. + * @param cb Callback that is called when the user was successfully deleted. + */ + delete(alias: string, pass: string, cb?: (ack: { ok: 0 }) => void): Promise; + /** + * Recall saves a users credentials in sessionStorage of the browser. As long as the tab of your app is not closed the user stays logged in, even through page refreshes and reloads. + * @param opt option object If you want to use browser sessionStorage to allow users to stay logged in as long as the session is open, set opt.sessionStorage to true + * @param cb internally the callback is passed on to the user.auth function to logged the user back in. Refer to user.auth for callback documentation. + */ + recall(opt?: { sessionStorage: boolean }, cb?: Parameters[2]): ChainReference; + /** + * @param publicKey If you know a users publicKey you can get their user graph and see any unencrypted data they may have stored there. + */ + user(publicKey?: string): ChainReference; + //#endregion + } + + type CryptoKeyPair = Record<'pub' | 'priv' | 'epub' | 'epriv', string>; + interface Constructor { + /** + * @description + * no parameters creates a local datastore using the default persistence layer, either localStorage or Radisk. + * @param options + * passing a URL creates the above local datastore that also tries to sync with the URL. + * + * or you can pass in an array of URLs to sync with multiple peers. + */ + (options?: string | string[] | ConstructorOptions): ChainReference; + new (options?: string | string[] | ConstructorOptions): ChainReference< + DataType, + any, + 'pre_root' + >; + node: { + /** Returns true if data is a gun node, otherwise false. */ + is(anything: any): anything is ChainReference; + /** + * Returns data's gun ID (instead of manually grabbing its metadata i.e. data["_"]["#"], which is faster but could change in the future) + * + * Returns undefined if data is not correct gun data. + */ + soul(data: ChainReference): string; + /** Returns a "gun-ified" variant of the json input by injecting a new gun ID into the metadata field. */ + ify(json: any): any; + }; + /** @see https://gun.eco/docs/SEA */ + SEA: { + /** If you want SEA to throw while in development, turn SEA.throw = true on, but please do not use this in production. */ + throw?: boolean; + /** Last known error */ + err?: Error; + /** + * This gives you a Proof of Work (POW) / Hashing of Data + * @param data The data to be hashed, work to be performed on. + * @param pair (salt) You can pass pair of keys to use as salt. Salt will prevent others to pre-compute the work, + * so using your public key is not a good idea. If it is not specified, it will be random, + * which ruins your chance of ever being able to re-derive the work deterministically + * @param callback function to executed upon execution of proof + * @param opt default: {name: 'PBKDF2', encode: 'base64'} + */ + work( + data: any, + pair?: any, + callback?: (data: string | undefined) => void, + opt?: Partial<{ + name: 'SHA-256' | 'PBKDF2'; + encode: 'base64' | 'base32' | 'base16'; + /** iterations to use on subtle.deriveBits */ + iterations: number; + salt: any; + hash: string; + length: any; + }> + ): Promise; + /** + * This generates a cryptographically secure public/private key pair - be careful not to leak the private keys! + * Note: API subject to change we may change the parameters to accept data and work, in addition to generation. + * You will need this for most of SEA's API, see those method's examples. + * The default cryptographic primitives for the asymmetric keys are ECDSA for signing and ECDH for encryption. + */ + pair(cb: (data: CryptoKeyPair) => void, opt?: {}): Promise; + /** + * Adds a signature to a message, for data that you want to prevent attackers tampering with. + * @param data is the content that you want to prove is authorized. + * @param pair is from .pair. + */ + sign(data: any, pair: CryptoKeyPair): Promise; + /** + * Gets the data if and only if the message can be verified as coming from the person you expect. + * @param message is what comes from .sign. + * @param pair from .pair or its public key text (pair.pub). + */ + verify(message: any, pair: CryptoKeyPair | string): Promise; + /** + * Takes some data that you want to keep secret and encrypts it so nobody else can read it. + * @param data is the content that you want to encrypt. + * @param pair from .pair or a passphrase you want to use as a cypher to encrypt with. + */ + encrypt(data: any, pair: CryptoKeyPair | string): Promise; + /** + * Read the secret data, if and only if you are allowed to. + * @param message is what comes from .encrypt. + * @param pair from .pair or the passphrase to decypher the message. + */ + decrypt(message: any, pair: CryptoKeyPair | string): Promise; + }; + } +} +declare const Gun: Gun.Constructor; From 248e09c57337e4250be302d7a4daacdbd53739ff Mon Sep 17 00:00:00 2001 From: bluelovers Date: Wed, 5 Feb 2020 08:06:20 +0800 Subject: [PATCH 27/87] split @types/gun --- .gitignore | 5 +- .npmignore | 1 + gun.d.ts | 459 +-------------------------------------------- tsconfig.json | 6 + types/chain.d.ts | 249 ++++++++++++++++++++++++ types/options.d.ts | 30 +++ types/static.d.ts | 82 ++++++++ types/types.d.ts | 25 +++ 8 files changed, 400 insertions(+), 457 deletions(-) create mode 100644 .npmignore create mode 100644 tsconfig.json create mode 100644 types/chain.d.ts create mode 100644 types/options.d.ts create mode 100644 types/static.d.ts create mode 100644 types/types.d.ts diff --git a/.gitignore b/.gitignore index 74fb92eb..51e0d945 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,7 @@ yarn.lock *.DS_store .esm-cache .sessionStorage -.localStorage \ No newline at end of file +.localStorage +/types/*.ts +!/types/*.d.ts +/gun.ts diff --git a/.npmignore b/.npmignore new file mode 100644 index 00000000..6461deec --- /dev/null +++ b/.npmignore @@ -0,0 +1 @@ +*.ts diff --git a/gun.d.ts b/gun.d.ts index 4a9a05f9..b583b1cd 100644 --- a/gun.d.ts +++ b/gun.d.ts @@ -1,456 +1,3 @@ -// Type definitions for gun 0.9 -// Project: https://github.com/amark/gun#readme -// Definitions by: Jack Works -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 3.1 - -declare const cons: Gun.Constructor; -export = cons; - -declare namespace Gun { - type ArrayOf = T extends Array ? U : never; - /** Gun does not accept Array value, so we need extract to make types correct */ - type AllowArray = ArrayOf extends never ? T : ArrayOf; - type DisallowArray = ArrayOf extends never ? T : never; - /** These types cannot be stored on Gun */ - - type AlwaysDisallowedType = T extends (...args: any[]) => void - ? never - : T extends { new (...args: any[]): any } - ? never - : AccessObject; - type AccessObject = T extends object - ? { [key in keyof T]: (AlwaysDisallowedType extends never ? never : AccessObject) } - : T; - /** These types cannot be stored on Gun's root level */ - type DisallowPrimitives = Open extends false - ? T - : T extends string - ? never - : T extends number - ? never - : T extends boolean - ? never - : T extends null - ? never - : T extends undefined - ? never - : T; - type ArrayAsRecord = ArrayOf extends never ? DataType : Record; - /** - * options['module name'] allows you to pass options to a 3rd party module. - * Their project README will likely list the exposed options - * https://github.com/amark/gun/wiki/Modules - */ - type ConstructorOptions = Partial<{ - /** Undocumented but mentioned. Write data to a JSON. */ - file: string; - /** Undocumented but mentioned. Create a websocket server */ - web: any; - /** Undocumented but mentioned. Amazon S3 */ - s3: { - key: any; - secret: any; - bucket: any; - }; - /** the URLs are properties, and the value is an empty object. */ - peers: Record; - /** default: true, creates and persists local (nodejs) data using Radisk. */ - radisk: boolean; - /** default: true, persists local (browser) data to localStorage. */ - localStorage: boolean; - /** uuid allows you to override the default 24 random alphanumeric soul generator with your own function. */ - uuid(): string; - /** - * allows you to pass options to a 3rd party module. Their project README will likely list the exposed options - * @see https://github.com/amark/gun/wiki/Modules - */ - [key: string]: any; - }>; - type Saveable = Partial | string | number | boolean | null | ChainReference; - type AckCallback = (ack: { err: Error; ok: any } | { err: undefined; ok: string }) => void; - type Parameters any> = T extends (...args: infer P) => any ? P : never; - interface ChainReference { - //#region API - /** - * Save data into gun, syncing it with your connected peers. - * - * * You cannot save primitive values at the root level. - * - * @param data You do not need to re-save the entire object every time, - * gun will automatically merge your data into what already exists as a "partial" update. - * - * * `undefined`, `NaN`, `Infinity`, `array`, will be rejected. - * * Traditional arrays are dangerous in real-time apps. Use `gun.set` instead. - * - * @param callback invoked on each acknowledgment - */ - put( - data: Partial>>>, - callback?: AckCallback - ): ChainReference; - /** - * Where to read data from. - * @param key The key is the ID or property name of the data that you saved from earlier - * (or that will be saved later). - * * Note that if you use .put at any depth after a get it first reads the data and then writes, merging the data as a partial update. - * @param callback You will usually be using gun.on or gun.once to actually retrieve your data, - * not this callback (it is intended for more low level control, for module and extensions). - * - * **Avoid use callback. The type in the document may be wrong.** - * - * **Here the type of callback respect to the actual behavior** - */ - get( - key: ArrayOf extends never ? K : never, - callback?: ( - /** the raw data. Internal node of gun. Will not typed here. */ - paramA: Record< - 'gun' | '$' | 'root' | 'id' | 'back' | 'on' | 'tag' | 'get' | 'soul' | 'ack' | 'put', - any - >, - /** the key, ID, or property name of the data. */ - paramB: Record<'off' | 'to' | 'next' | 'the' | 'on' | 'as' | 'back' | 'rid' | 'id', any> - ) => void - ): ChainReference; - /** - * Change the configuration of the gun database instance. - * @param options The options argument is the same object you pass to the constructor. - * - * The options's properties replace those in the instance's configuration but options.peers are **added** to peers known to the gun instance. - * @returns No mention in the document, behavior as `ChainReference` - */ - opt(options: ConstructorOptions): ChainReference; - /** - * Move up to the parent context on the chain. - * - * Every time a new chain is created, a reference to the old context is kept to go back to. - * @param amount The number of times you want to go back up the chain. - * `-1` or `Infinity` will take you to the root. - * @returns Impossible to determinate final type. You must cast it by yourself. - */ - back(amount?: number): ChainReference; - - // Main API - /** - * Subscribe to updates and changes on a node or property in realtime. - * @param option Currently, the only option is to filter out old data, and just be given the changes. - * If you're listening to a node with 100 fields, and just one changes, - * you'll instead be passed a node with a single property representing that change rather than the full node every time. - * @param callback - * Once initially and whenever the property or node you're focused on changes, this callback is immediately fired with the data as it is at that point in time. - * - * Since gun streams data, the callback will probably be called multiple times as new chunk comes in. - * To remove a listener call .off() on the same property or node. - */ - on( - callback: ( - data: DisallowPrimitives>>, - key: ReferenceKey - ) => void, - option?: { change: boolean } | boolean - ): ChainReference; - /** - * Get the current data without subscribing to updates. Or `undefined` if it cannot be found. - * @returns In the document, it said the return value may change in the future. Don't rely on it. - */ - once( - callback?: ( - data: (DisallowPrimitives>>) | undefined, - key: ReferenceKey - ) => void, - option?: { wait: number } - ): ChainReference; - /** - * **.set does not means 'set data', it means a Mathematical Set** - * - * Add a unique item to an unordered list. - * `gun.set` works like a mathematical set, where each item in the list is unique. - * If the item is added twice, it will be merged. - * - * **This means only objects, for now, are supported.** - */ - set( - data: AlwaysDisallowedType< - DataType extends Array - ? U extends { [key: string]: any; [key: number]: any } - ? ArrayOf - : never - : never - >, - callback?: AckCallback - ): ChainReference>; - /** - * Map iterates over each property and item on a node, passing it down the chain, - * behaving like a forEach on your data. - * It also subscribes to every item as well and listens for newly inserted items. - */ - map( - callback?: (value: ArrayOf, key: DataType) => ArrayOf | undefined - ): ChainReference, ReferenceKey>; - /** - * Undocumented, but extremely useful and mentioned in the document - * - * Remove **all** listener on this node. - */ - off(): void; - //#endregion - //#region Extended API - /** - * - * Path does the same thing as `.get` but has some conveniences built in. - * @deprecated This is not friendly with type system. - * - * **Warning**: This extension was removed from core, you probably shouldn't be using it! - * - * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/path.js')` or - * ``! - */ - path?(path: string | string[]): ChainReference; - /** - * Handle cases where data can't be found. - * - * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/not.js')` or - * ``! - */ - not?(callback: (key: ReferenceKey) => void): ChainReference; - /** - * Open behaves very similarly to gun.on, except it gives you the **full depth of a document** on every update. - * It also works with graphs, tables, or other data structures. Think of it as opening up a live connection to a document. - * - * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/open.js')` or - * ``! - */ - open?(callback: (data: ArrayAsRecord) => void): ChainReference; - /** - * Loads the full object once. It is the same as `open` but with the behavior of `once`. - * - * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/load.js')` or - * ``! - */ - load?(callback: (data: ArrayAsRecord) => void): ChainReference; - /** - * Returns a promise for you to use. - * - * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/then.js')` or - * ``! - */ - then?>( - onfulfilled?: (value: TResult1) => TResult1 | PromiseLike - ): Promise; - /** - * Returns a promise for you to use. - * - * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/then.js')` or - * ``! - */ - promise?< - TResult1 = { put: ArrayAsRecord; key: ReferenceKey; gun: ChainReference } - >( - onfulfilled?: (value: TResult1) => TResult1 | PromiseLike - ): Promise; - /** - * bye lets you change data after that browser peer disconnects. - * This is useful for games and status messages, - * that if a player leaves you can remove them from the game or set a user's status to "away". - * - * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/bye.js')` or - * ``! - */ - bye?(): { - put(data: DisallowArray>): void; - }; - /** - * Say you save some data, but want to do something with it later, like expire it or refresh it. - * Well, then `later` is for you! You could use this to easily implement a TTL or similar behavior. - * - * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/later.js')` or - * ``! - */ - later?( - callback: ( - this: ChainReference, - data: ArrayAsRecord, - key: ReferenceKey - ) => void, - seconds: number - ): ChainReference; - /** - * After you save some data in an unordered list, you may need to remove it. - * - * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/unset.js')` or - * ``! - */ - unset?(data: ArrayOf): ChainReference; - /** - * Subscribes to all future events that occur on the Timegraph and retrieve a specified number of old events - * - * **Warning**: The Timegraph extension isn't required by default, you would need to include at "gun/lib/time.js" - */ - time?( - callback: (data: ArrayOf, key: ReferenceKey, time: number) => void, - alsoReceiveNOldEvents?: number - ): ChainReference; - /** Pushes data to a Timegraph with it's time set to Gun.state()'s time */ - time?(data: ArrayOf): void; - //#endregion - //#region User - /** - * Creates a new user and calls callback upon completion. - * @param alias Username or Alias which can be used to find a user. - * @param pass Passphrase that will be extended with PBKDF2 to make it a secure way to login. - * @param cb Callback that is to be called upon creation of the user. - * @param opt Option Object containing options for creation. (In gun options are added at end of syntax. opt is rarely used, hence is added at the end.) - */ - create( - alias: string, - pass: string, - cb?: (ack: { ok: 0; pub: string } | { err: string }) => void, - opt?: {} - ): ChainReference; - /** - * Authenticates a user, previously created via User.create. - * @param alias Username or Alias which can be used to find a user. - * @param pass Passphrase for the user - * @param cb Callback that is to be called upon authentication of the user. - * @param opt Option Object containing options for authentiaction. (In gun options are added at end of syntax. opt is rarely used, hence is added at the end.) - */ - auth( - alias: string, - pass: string, - cb?: ( - ack: - | { - ack: 2; - get: string; - on: (...args: [unknown, unknown, unknown]) => unknown; - put: { alias: string; auth: any; epub: string; pub: string }; - sea: CryptoKeyPair; - soul: string; - } - | { err: string } - ) => void, - opt?: {} - ): ChainReference; - /** - * Returns the key pair in the form of an object as below. - */ - pair(): CryptoKeyPair; - /** - * Log out currently authenticated user. Parameters are unused in the current implementation. - * @param opt unused in current implementation. - * @param cb unused in current implementation. - */ - leave(opt?: never, cb?: never): ChainReference; - /** - * Deletes a user from the current gun instance and propagates the delete to other peers. - * @param alias Username or alias. - * @param pass Passphrase for the user. - * @param cb Callback that is called when the user was successfully deleted. - */ - delete(alias: string, pass: string, cb?: (ack: { ok: 0 }) => void): Promise; - /** - * Recall saves a users credentials in sessionStorage of the browser. As long as the tab of your app is not closed the user stays logged in, even through page refreshes and reloads. - * @param opt option object If you want to use browser sessionStorage to allow users to stay logged in as long as the session is open, set opt.sessionStorage to true - * @param cb internally the callback is passed on to the user.auth function to logged the user back in. Refer to user.auth for callback documentation. - */ - recall(opt?: { sessionStorage: boolean }, cb?: Parameters[2]): ChainReference; - /** - * @param publicKey If you know a users publicKey you can get their user graph and see any unencrypted data they may have stored there. - */ - user(publicKey?: string): ChainReference; - //#endregion - } - - type CryptoKeyPair = Record<'pub' | 'priv' | 'epub' | 'epriv', string>; - interface Constructor { - /** - * @description - * no parameters creates a local datastore using the default persistence layer, either localStorage or Radisk. - * @param options - * passing a URL creates the above local datastore that also tries to sync with the URL. - * - * or you can pass in an array of URLs to sync with multiple peers. - */ - (options?: string | string[] | ConstructorOptions): ChainReference; - new (options?: string | string[] | ConstructorOptions): ChainReference< - DataType, - any, - 'pre_root' - >; - node: { - /** Returns true if data is a gun node, otherwise false. */ - is(anything: any): anything is ChainReference; - /** - * Returns data's gun ID (instead of manually grabbing its metadata i.e. data["_"]["#"], which is faster but could change in the future) - * - * Returns undefined if data is not correct gun data. - */ - soul(data: ChainReference): string; - /** Returns a "gun-ified" variant of the json input by injecting a new gun ID into the metadata field. */ - ify(json: any): any; - }; - /** @see https://gun.eco/docs/SEA */ - SEA: { - /** If you want SEA to throw while in development, turn SEA.throw = true on, but please do not use this in production. */ - throw?: boolean; - /** Last known error */ - err?: Error; - /** - * This gives you a Proof of Work (POW) / Hashing of Data - * @param data The data to be hashed, work to be performed on. - * @param pair (salt) You can pass pair of keys to use as salt. Salt will prevent others to pre-compute the work, - * so using your public key is not a good idea. If it is not specified, it will be random, - * which ruins your chance of ever being able to re-derive the work deterministically - * @param callback function to executed upon execution of proof - * @param opt default: {name: 'PBKDF2', encode: 'base64'} - */ - work( - data: any, - pair?: any, - callback?: (data: string | undefined) => void, - opt?: Partial<{ - name: 'SHA-256' | 'PBKDF2'; - encode: 'base64' | 'base32' | 'base16'; - /** iterations to use on subtle.deriveBits */ - iterations: number; - salt: any; - hash: string; - length: any; - }> - ): Promise; - /** - * This generates a cryptographically secure public/private key pair - be careful not to leak the private keys! - * Note: API subject to change we may change the parameters to accept data and work, in addition to generation. - * You will need this for most of SEA's API, see those method's examples. - * The default cryptographic primitives for the asymmetric keys are ECDSA for signing and ECDH for encryption. - */ - pair(cb: (data: CryptoKeyPair) => void, opt?: {}): Promise; - /** - * Adds a signature to a message, for data that you want to prevent attackers tampering with. - * @param data is the content that you want to prove is authorized. - * @param pair is from .pair. - */ - sign(data: any, pair: CryptoKeyPair): Promise; - /** - * Gets the data if and only if the message can be verified as coming from the person you expect. - * @param message is what comes from .sign. - * @param pair from .pair or its public key text (pair.pub). - */ - verify(message: any, pair: CryptoKeyPair | string): Promise; - /** - * Takes some data that you want to keep secret and encrypts it so nobody else can read it. - * @param data is the content that you want to encrypt. - * @param pair from .pair or a passphrase you want to use as a cypher to encrypt with. - */ - encrypt(data: any, pair: CryptoKeyPair | string): Promise; - /** - * Read the secret data, if and only if you are allowed to. - * @param message is what comes from .encrypt. - * @param pair from .pair or the passphrase to decypher the message. - */ - decrypt(message: any, pair: CryptoKeyPair | string): Promise; - }; - } -} -declare const Gun: Gun.Constructor; +import { Constructor } from './types/static'; +declare const cons: Constructor; +export = cons; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..df49bce7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "emitDeclarationOnly": true, + "declaration": true + } +} diff --git a/types/chain.d.ts b/types/chain.d.ts new file mode 100644 index 00000000..a3790b3a --- /dev/null +++ b/types/chain.d.ts @@ -0,0 +1,249 @@ +import { AlwaysDisallowedType, DisallowPrimitives, DisallowArray, AckCallback, ArrayOf, ArrayAsRecord, Saveable } from './types'; +import { ConstructorOptions } from './options'; +export interface ChainReference { + /** + * Save data into gun, syncing it with your connected peers. + * + * * You cannot save primitive values at the root level. + * + * @param data You do not need to re-save the entire object every time, + * gun will automatically merge your data into what already exists as a "partial" update. + * + * * `undefined`, `NaN`, `Infinity`, `array`, will be rejected. + * * Traditional arrays are dangerous in real-time apps. Use `gun.set` instead. + * + * @param callback invoked on each acknowledgment + */ + put(data: Partial>>>, callback?: AckCallback): ChainReference; + /** + * Where to read data from. + * @param key The key is the ID or property name of the data that you saved from earlier + * (or that will be saved later). + * * Note that if you use .put at any depth after a get it first reads the data and then writes, merging the data as a partial update. + * @param callback You will usually be using gun.on or gun.once to actually retrieve your data, + * not this callback (it is intended for more low level control, for module and extensions). + * + * **Avoid use callback. The type in the document may be wrong.** + * + * **Here the type of callback respect to the actual behavior** + */ + get(key: ArrayOf extends never ? K : never, callback?: ( + /** the raw data. Internal node of gun. Will not typed here. */ + paramA: Record<'gun' | '$' | 'root' | 'id' | 'back' | 'on' | 'tag' | 'get' | 'soul' | 'ack' | 'put', any>, + /** the key, ID, or property name of the data. */ + paramB: Record<'off' | 'to' | 'next' | 'the' | 'on' | 'as' | 'back' | 'rid' | 'id', any>) => void): ChainReference; + /** + * Change the configuration of the gun database instance. + * @param options The options argument is the same object you pass to the constructor. + * + * The options's properties replace those in the instance's configuration but options.peers are **added** to peers known to the gun instance. + * @returns No mention in the document, behavior as `ChainReference` + */ + opt(options: ConstructorOptions): ChainReference; + /** + * Move up to the parent context on the chain. + * + * Every time a new chain is created, a reference to the old context is kept to go back to. + * @param amount The number of times you want to go back up the chain. + * `-1` or `Infinity` will take you to the root. + * @returns Impossible to determinate final type. You must cast it by yourself. + */ + back(amount?: number): ChainReference; + /** + * Subscribe to updates and changes on a node or property in realtime. + * @param option Currently, the only option is to filter out old data, and just be given the changes. + * If you're listening to a node with 100 fields, and just one changes, + * you'll instead be passed a node with a single property representing that change rather than the full node every time. + * @param callback + * Once initially and whenever the property or node you're focused on changes, this callback is immediately fired with the data as it is at that point in time. + * + * Since gun streams data, the callback will probably be called multiple times as new chunk comes in. + * To remove a listener call .off() on the same property or node. + */ + on(callback: (data: DisallowPrimitives>>, key: ReferenceKey) => void, option?: { + change: boolean; + } | boolean): ChainReference; + /** + * Get the current data without subscribing to updates. Or `undefined` if it cannot be found. + * @returns In the document, it said the return value may change in the future. Don't rely on it. + */ + once(callback?: (data: (DisallowPrimitives>>) | undefined, key: ReferenceKey) => void, option?: { + wait: number; + }): ChainReference; + /** + * **.set does not means 'set data', it means a Mathematical Set** + * + * Add a unique item to an unordered list. + * `gun.set` works like a mathematical set, where each item in the list is unique. + * If the item is added twice, it will be merged. + * + * **This means only objects, for now, are supported.** + */ + set(data: AlwaysDisallowedType ? U extends { + [key: string]: any; + [key: number]: any; + } ? ArrayOf : never : never>, callback?: AckCallback): ChainReference>; + /** + * Map iterates over each property and item on a node, passing it down the chain, + * behaving like a forEach on your data. + * It also subscribes to every item as well and listens for newly inserted items. + */ + map(callback?: (value: ArrayOf, key: DataType) => ArrayOf | undefined): ChainReference, ReferenceKey>; + /** + * Undocumented, but extremely useful and mentioned in the document + * + * Remove **all** listener on this node. + */ + off(): void; + /** + * + * Path does the same thing as `.get` but has some conveniences built in. + * @deprecated This is not friendly with type system. + * + * **Warning**: This extension was removed from core, you probably shouldn't be using it! + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/path.js')` or + * ``! + */ + path?(path: string | string[]): ChainReference; + /** + * Handle cases where data can't be found. + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/not.js')` or + * ``! + */ + not?(callback: (key: ReferenceKey) => void): ChainReference; + /** + * Open behaves very similarly to gun.on, except it gives you the **full depth of a document** on every update. + * It also works with graphs, tables, or other data structures. Think of it as opening up a live connection to a document. + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/open.js')` or + * ``! + */ + open?(callback: (data: ArrayAsRecord) => void): ChainReference; + /** + * Loads the full object once. It is the same as `open` but with the behavior of `once`. + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/load.js')` or + * ``! + */ + load?(callback: (data: ArrayAsRecord) => void): ChainReference; + /** + * Returns a promise for you to use. + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/then.js')` or + * ``! + */ + then?>(onfulfilled?: (value: TResult1) => TResult1 | PromiseLike): Promise; + /** + * Returns a promise for you to use. + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/then.js')` or + * ``! + */ + promise?; + key: ReferenceKey; + gun: ChainReference; + }>(onfulfilled?: (value: TResult1) => TResult1 | PromiseLike): Promise; + /** + * bye lets you change data after that browser peer disconnects. + * This is useful for games and status messages, + * that if a player leaves you can remove them from the game or set a user's status to "away". + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/bye.js')` or + * ``! + */ + bye?(): { + put(data: DisallowArray>): void; + }; + /** + * Say you save some data, but want to do something with it later, like expire it or refresh it. + * Well, then `later` is for you! You could use this to easily implement a TTL or similar behavior. + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/later.js')` or + * ``! + */ + later?(callback: (this: ChainReference, data: ArrayAsRecord, key: ReferenceKey) => void, seconds: number): ChainReference; + /** + * After you save some data in an unordered list, you may need to remove it. + * + * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/unset.js')` or + * ``! + */ + unset?(data: ArrayOf): ChainReference; + /** + * Subscribes to all future events that occur on the Timegraph and retrieve a specified number of old events + * + * **Warning**: The Timegraph extension isn't required by default, you would need to include at "gun/lib/time.js" + */ + time?(callback: (data: ArrayOf, key: ReferenceKey, time: number) => void, alsoReceiveNOldEvents?: number): ChainReference; + /** Pushes data to a Timegraph with it's time set to Gun.state()'s time */ + time?(data: ArrayOf): void; + /** + * Creates a new user and calls callback upon completion. + * @param alias Username or Alias which can be used to find a user. + * @param pass Passphrase that will be extended with PBKDF2 to make it a secure way to login. + * @param cb Callback that is to be called upon creation of the user. + * @param opt Option Object containing options for creation. (In gun options are added at end of syntax. opt is rarely used, hence is added at the end.) + */ + create(alias: string, pass: string, cb?: (ack: { + ok: 0; + pub: string; + } | { + err: string; + }) => void, opt?: {}): ChainReference; + /** + * Authenticates a user, previously created via User.create. + * @param alias Username or Alias which can be used to find a user. + * @param pass Passphrase for the user + * @param cb Callback that is to be called upon authentication of the user. + * @param opt Option Object containing options for authentiaction. (In gun options are added at end of syntax. opt is rarely used, hence is added at the end.) + */ + auth(alias: string, pass: string, cb?: (ack: { + ack: 2; + get: string; + on: (...args: [unknown, unknown, unknown]) => unknown; + put: { + alias: string; + auth: any; + epub: string; + pub: string; + }; + sea: CryptoKeyPair; + soul: string; + } | { + err: string; + }) => void, opt?: {}): ChainReference; + /** + * Returns the key pair in the form of an object as below. + */ + pair(): CryptoKeyPair; + /** + * Log out currently authenticated user. Parameters are unused in the current implementation. + * @param opt unused in current implementation. + * @param cb unused in current implementation. + */ + leave(opt?: never, cb?: never): ChainReference; + /** + * Deletes a user from the current gun instance and propagates the delete to other peers. + * @param alias Username or alias. + * @param pass Passphrase for the user. + * @param cb Callback that is called when the user was successfully deleted. + */ + delete(alias: string, pass: string, cb?: (ack: { + ok: 0; + }) => void): Promise; + /** + * Recall saves a users credentials in sessionStorage of the browser. As long as the tab of your app is not closed the user stays logged in, even through page refreshes and reloads. + * @param opt option object If you want to use browser sessionStorage to allow users to stay logged in as long as the session is open, set opt.sessionStorage to true + * @param cb internally the callback is passed on to the user.auth function to logged the user back in. Refer to user.auth for callback documentation. + */ + recall(opt?: { + sessionStorage: boolean; + }, cb?: Parameters[2]): ChainReference; + /** + * @param publicKey If you know a users publicKey you can get their user graph and see any unencrypted data they may have stored there. + */ + user(publicKey?: string): ChainReference; +} diff --git a/types/options.d.ts b/types/options.d.ts new file mode 100644 index 00000000..90d60488 --- /dev/null +++ b/types/options.d.ts @@ -0,0 +1,30 @@ +/** + * options['module name'] allows you to pass options to a 3rd party module. + * Their project README will likely list the exposed options + * https://github.com/amark/gun/wiki/Modules + */ +export declare type ConstructorOptions = Partial<{ + /** Undocumented but mentioned. Write data to a JSON. */ + file: string; + /** Undocumented but mentioned. Create a websocket server */ + web: any; + /** Undocumented but mentioned. Amazon S3 */ + s3: { + key: any; + secret: any; + bucket: any; + }; + /** the URLs are properties, and the value is an empty object. */ + peers: Record; + /** default: true, creates and persists local (nodejs) data using Radisk. */ + radisk: boolean; + /** default: true, persists local (browser) data to localStorage. */ + localStorage: boolean; + /** uuid allows you to override the default 24 random alphanumeric soul generator with your own function. */ + uuid(): string; + /** + * allows you to pass options to a 3rd party module. Their project README will likely list the exposed options + * @see https://github.com/amark/gun/wiki/Modules + */ + [key: string]: any; +}>; diff --git a/types/static.d.ts b/types/static.d.ts new file mode 100644 index 00000000..266826b3 --- /dev/null +++ b/types/static.d.ts @@ -0,0 +1,82 @@ +import { ChainReference } from './chain'; +import { ConstructorOptions } from './options'; +export interface Constructor { + /** + * @description + * no parameters creates a local datastore using the default persistence layer, either localStorage or Radisk. + * @param options + * passing a URL creates the above local datastore that also tries to sync with the URL. + * + * or you can pass in an array of URLs to sync with multiple peers. + */ + (options?: string | string[] | ConstructorOptions): ChainReference; + new (options?: string | string[] | ConstructorOptions): ChainReference; + node: { + /** Returns true if data is a gun node, otherwise false. */ + is(anything: any): anything is ChainReference; + /** + * Returns data's gun ID (instead of manually grabbing its metadata i.e. data["_"]["#"], which is faster but could change in the future) + * + * Returns undefined if data is not correct gun data. + */ + soul(data: ChainReference): string; + /** Returns a "gun-ified" variant of the json input by injecting a new gun ID into the metadata field. */ + ify(json: any): any; + }; + /** @see https://gun.eco/docs/SEA */ + SEA: { + /** If you want SEA to throw while in development, turn SEA.throw = true on, but please do not use this in production. */ + throw?: boolean; + /** Last known error */ + err?: Error; + /** + * This gives you a Proof of Work (POW) / Hashing of Data + * @param data The data to be hashed, work to be performed on. + * @param pair (salt) You can pass pair of keys to use as salt. Salt will prevent others to pre-compute the work, + * so using your public key is not a good idea. If it is not specified, it will be random, + * which ruins your chance of ever being able to re-derive the work deterministically + * @param callback function to executed upon execution of proof + * @param opt default: {name: 'PBKDF2', encode: 'base64'} + */ + work(data: any, pair?: any, callback?: (data: string | undefined) => void, opt?: Partial<{ + name: 'SHA-256' | 'PBKDF2'; + encode: 'base64' | 'base32' | 'base16'; + /** iterations to use on subtle.deriveBits */ + iterations: number; + salt: any; + hash: string; + length: any; + }>): Promise; + /** + * This generates a cryptographically secure public/private key pair - be careful not to leak the private keys! + * Note: API subject to change we may change the parameters to accept data and work, in addition to generation. + * You will need this for most of SEA's API, see those method's examples. + * The default cryptographic primitives for the asymmetric keys are ECDSA for signing and ECDH for encryption. + */ + pair(cb: (data: CryptoKeyPair) => void, opt?: {}): Promise; + /** + * Adds a signature to a message, for data that you want to prevent attackers tampering with. + * @param data is the content that you want to prove is authorized. + * @param pair is from .pair. + */ + sign(data: any, pair: CryptoKeyPair): Promise; + /** + * Gets the data if and only if the message can be verified as coming from the person you expect. + * @param message is what comes from .sign. + * @param pair from .pair or its public key text (pair.pub). + */ + verify(message: any, pair: CryptoKeyPair | string): Promise; + /** + * Takes some data that you want to keep secret and encrypts it so nobody else can read it. + * @param data is the content that you want to encrypt. + * @param pair from .pair or a passphrase you want to use as a cypher to encrypt with. + */ + encrypt(data: any, pair: CryptoKeyPair | string): Promise; + /** + * Read the secret data, if and only if you are allowed to. + * @param message is what comes from .encrypt. + * @param pair from .pair or the passphrase to decypher the message. + */ + decrypt(message: any, pair: CryptoKeyPair | string): Promise; + }; +} diff --git a/types/types.d.ts b/types/types.d.ts new file mode 100644 index 00000000..9fdc2dd1 --- /dev/null +++ b/types/types.d.ts @@ -0,0 +1,25 @@ +import { ChainReference } from './chain'; +export declare type ArrayOf = T extends Array ? U : never; +/** Gun does not accept Array value, so we need extract to make types correct */ +export declare type AllowArray = ArrayOf extends never ? T : ArrayOf; +export declare type DisallowArray = ArrayOf extends never ? T : never; +/** These types cannot be stored on Gun */ +export declare type AlwaysDisallowedType = T extends (...args: any[]) => void ? never : T extends { + new (...args: any[]): any; +} ? never : AccessObject; +export declare type AccessObject = T extends object ? { + [key in keyof T]: (AlwaysDisallowedType extends never ? never : AccessObject); +} : T; +/** These types cannot be stored on Gun's root level */ +export declare type DisallowPrimitives = Open extends false ? T : T extends string ? never : T extends number ? never : T extends boolean ? never : T extends null ? never : T extends undefined ? never : T; +export declare type ArrayAsRecord = ArrayOf extends never ? DataType : Record; +export declare type Saveable = Partial | string | number | boolean | null | ChainReference; +export declare type AckCallback = (ack: { + err: Error; + ok: any; +} | { + err: undefined; + ok: string; +}) => void; +export declare type Parameters any> = T extends (...args: infer P) => any ? P : never; +export declare type CryptoKeyPair = Record<'pub' | 'priv' | 'epub' | 'epriv', string>; From c93149a3a07fc21baa9216757882806f6404ae14 Mon Sep 17 00:00:00 2001 From: bluelovers Date: Wed, 5 Feb 2020 08:37:00 +0800 Subject: [PATCH 28/87] refactor: update types for better extendable --- .gitignore | 1 + .npmignore | 1 + global.d.ts | 4 ++++ gun.d.ts | 6 +++--- index.d.ts | 3 +++ package.json | 1 + types/chain.d.ts | 48 +++++++++++++++++++++++----------------------- types/options.d.ts | 7 ++++--- types/static.d.ts | 14 +++++++------- types/types.d.ts | 5 ++--- 10 files changed, 50 insertions(+), 40 deletions(-) create mode 100644 global.d.ts create mode 100644 index.d.ts diff --git a/.gitignore b/.gitignore index 51e0d945..31b50576 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ yarn.lock /types/*.ts !/types/*.d.ts /gun.ts +/temp/ diff --git a/.npmignore b/.npmignore index 6461deec..6dafed9c 100644 --- a/.npmignore +++ b/.npmignore @@ -1 +1,2 @@ *.ts +/temp/ diff --git a/global.d.ts b/global.d.ts new file mode 100644 index 00000000..e23dbe2d --- /dev/null +++ b/global.d.ts @@ -0,0 +1,4 @@ +import { IGunStatic } from './types/static'; +declare global { + var Gun: IGunStatic; +} diff --git a/gun.d.ts b/gun.d.ts index b583b1cd..7bbe17cd 100644 --- a/gun.d.ts +++ b/gun.d.ts @@ -1,3 +1,3 @@ -import { Constructor } from './types/static'; -declare const cons: Constructor; -export = cons; +import { IGunStatic } from './types/static'; +declare const Gun: IGunStatic; +export = Gun; diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 00000000..1ce189c2 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,3 @@ +import { IGunStatic } from './types/static'; +declare const Gun: IGunStatic; +export = Gun; diff --git a/package.json b/package.json index e31efe13..32601190 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "gun", "version": "0.2020.116", "description": "A realtime, decentralized, offline-first, graph data synchronization engine.", + "types": "index.d.ts", "main": "index.js", "browser": "browser.js", "ios": "browser.ios.js", diff --git a/types/chain.d.ts b/types/chain.d.ts index a3790b3a..ce6c0ae2 100644 --- a/types/chain.d.ts +++ b/types/chain.d.ts @@ -1,6 +1,6 @@ import { AlwaysDisallowedType, DisallowPrimitives, DisallowArray, AckCallback, ArrayOf, ArrayAsRecord, Saveable } from './types'; -import { ConstructorOptions } from './options'; -export interface ChainReference { +import { IGunConstructorOptions } from './options'; +export interface IGunChainReference, ReferenceKey = any, IsTop extends 'pre_root' | 'root' | false = false> { /** * Save data into gun, syncing it with your connected peers. * @@ -14,7 +14,7 @@ export interface ChainReference>>>, callback?: AckCallback): ChainReference; + put(data: Partial>>>, callback?: AckCallback): IGunChainReference; /** * Where to read data from. * @param key The key is the ID or property name of the data that you saved from earlier @@ -27,11 +27,11 @@ export interface ChainReference(key: ArrayOf extends never ? K : never, callback?: ( + get(key: ArrayOf extends never ? K : ArrayOf, callback?: ( /** the raw data. Internal node of gun. Will not typed here. */ paramA: Record<'gun' | '$' | 'root' | 'id' | 'back' | 'on' | 'tag' | 'get' | 'soul' | 'ack' | 'put', any>, /** the key, ID, or property name of the data. */ - paramB: Record<'off' | 'to' | 'next' | 'the' | 'on' | 'as' | 'back' | 'rid' | 'id', any>) => void): ChainReference; + paramB: Record<'off' | 'to' | 'next' | 'the' | 'on' | 'as' | 'back' | 'rid' | 'id', any>) => void): IGunChainReference; /** * Change the configuration of the gun database instance. * @param options The options argument is the same object you pass to the constructor. @@ -39,7 +39,7 @@ export interface ChainReference` */ - opt(options: ConstructorOptions): ChainReference; + opt(options: IGunConstructorOptions): IGunChainReference; /** * Move up to the parent context on the chain. * @@ -48,7 +48,7 @@ export interface ChainReference>>, key: ReferenceKey) => void, option?: { change: boolean; - } | boolean): ChainReference; + } | boolean): IGunChainReference; /** * Get the current data without subscribing to updates. Or `undefined` if it cannot be found. * @returns In the document, it said the return value may change in the future. Don't rely on it. */ once(callback?: (data: (DisallowPrimitives>>) | undefined, key: ReferenceKey) => void, option?: { wait: number; - }): ChainReference; + }): IGunChainReference; /** * **.set does not means 'set data', it means a Mathematical Set** * @@ -82,13 +82,13 @@ export interface ChainReference ? U extends { [key: string]: any; [key: number]: any; - } ? ArrayOf : never : never>, callback?: AckCallback): ChainReference>; + } ? ArrayOf : never : never>, callback?: AckCallback): IGunChainReference>; /** * Map iterates over each property and item on a node, passing it down the chain, * behaving like a forEach on your data. * It also subscribes to every item as well and listens for newly inserted items. */ - map(callback?: (value: ArrayOf, key: DataType) => ArrayOf | undefined): ChainReference, ReferenceKey>; + map(callback?: (value: ArrayOf, key: DataType) => ArrayOf | undefined): IGunChainReference, ReferenceKey>; /** * Undocumented, but extremely useful and mentioned in the document * @@ -105,14 +105,14 @@ export interface ChainReference`! */ - path?(path: string | string[]): ChainReference; + path?(path: string | string[]): IGunChainReference; /** * Handle cases where data can't be found. * * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/not.js')` or * ``! */ - not?(callback: (key: ReferenceKey) => void): ChainReference; + not?(callback: (key: ReferenceKey) => void): IGunChainReference; /** * Open behaves very similarly to gun.on, except it gives you the **full depth of a document** on every update. * It also works with graphs, tables, or other data structures. Think of it as opening up a live connection to a document. @@ -120,14 +120,14 @@ export interface ChainReference`! */ - open?(callback: (data: ArrayAsRecord) => void): ChainReference; + open?(callback: (data: ArrayAsRecord) => void): IGunChainReference; /** * Loads the full object once. It is the same as `open` but with the behavior of `once`. * * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/load.js')` or * ``! */ - load?(callback: (data: ArrayAsRecord) => void): ChainReference; + load?(callback: (data: ArrayAsRecord) => void): IGunChainReference; /** * Returns a promise for you to use. * @@ -144,7 +144,7 @@ export interface ChainReference; key: ReferenceKey; - gun: ChainReference; + gun: IGunChainReference; }>(onfulfilled?: (value: TResult1) => TResult1 | PromiseLike): Promise; /** * bye lets you change data after that browser peer disconnects. @@ -164,20 +164,20 @@ export interface ChainReference`! */ - later?(callback: (this: ChainReference, data: ArrayAsRecord, key: ReferenceKey) => void, seconds: number): ChainReference; + later?(callback: (this: IGunChainReference, data: ArrayAsRecord, key: ReferenceKey) => void, seconds: number): IGunChainReference; /** * After you save some data in an unordered list, you may need to remove it. * * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/unset.js')` or * ``! */ - unset?(data: ArrayOf): ChainReference; + unset?(data: ArrayOf): IGunChainReference; /** * Subscribes to all future events that occur on the Timegraph and retrieve a specified number of old events * * **Warning**: The Timegraph extension isn't required by default, you would need to include at "gun/lib/time.js" */ - time?(callback: (data: ArrayOf, key: ReferenceKey, time: number) => void, alsoReceiveNOldEvents?: number): ChainReference; + time?(callback: (data: ArrayOf, key: ReferenceKey, time: number) => void, alsoReceiveNOldEvents?: number): IGunChainReference; /** Pushes data to a Timegraph with it's time set to Gun.state()'s time */ time?(data: ArrayOf): void; /** @@ -192,7 +192,7 @@ export interface ChainReference void, opt?: {}): ChainReference; + }) => void, opt?: {}): IGunChainReference; /** * Authenticates a user, previously created via User.create. * @param alias Username or Alias which can be used to find a user. @@ -214,7 +214,7 @@ export interface ChainReference void, opt?: {}): ChainReference; + }) => void, opt?: {}): IGunChainReference; /** * Returns the key pair in the form of an object as below. */ @@ -224,7 +224,7 @@ export interface ChainReference[2]): ChainReference; + }, cb?: Parameters[2]): IGunChainReference; /** * @param publicKey If you know a users publicKey you can get their user graph and see any unencrypted data they may have stored there. */ - user(publicKey?: string): ChainReference; + user(publicKey?: string): IGunChainReference; } diff --git a/types/options.d.ts b/types/options.d.ts index 90d60488..3c6a0d73 100644 --- a/types/options.d.ts +++ b/types/options.d.ts @@ -3,7 +3,7 @@ * Their project README will likely list the exposed options * https://github.com/amark/gun/wiki/Modules */ -export declare type ConstructorOptions = Partial<{ +export interface IGunConstructorOptions extends Partial<{ /** Undocumented but mentioned. Write data to a JSON. */ file: string; /** Undocumented but mentioned. Create a websocket server */ @@ -15,7 +15,7 @@ export declare type ConstructorOptions = Partial<{ bucket: any; }; /** the URLs are properties, and the value is an empty object. */ - peers: Record; + peers: string[] | Record; /** default: true, creates and persists local (nodejs) data using Radisk. */ radisk: boolean; /** default: true, persists local (browser) data to localStorage. */ @@ -27,4 +27,5 @@ export declare type ConstructorOptions = Partial<{ * @see https://github.com/amark/gun/wiki/Modules */ [key: string]: any; -}>; +}> { +} diff --git a/types/static.d.ts b/types/static.d.ts index 266826b3..82e8832b 100644 --- a/types/static.d.ts +++ b/types/static.d.ts @@ -1,6 +1,6 @@ -import { ChainReference } from './chain'; -import { ConstructorOptions } from './options'; -export interface Constructor { +import { IGunChainReference } from './chain'; +import { IGunConstructorOptions } from './options'; +export interface IGunStatic { /** * @description * no parameters creates a local datastore using the default persistence layer, either localStorage or Radisk. @@ -9,17 +9,17 @@ export interface Constructor { * * or you can pass in an array of URLs to sync with multiple peers. */ - (options?: string | string[] | ConstructorOptions): ChainReference; - new (options?: string | string[] | ConstructorOptions): ChainReference; + (options?: string | string[] | IGunConstructorOptions): IGunChainReference; + new (options?: string | string[] | IGunConstructorOptions): IGunChainReference; node: { /** Returns true if data is a gun node, otherwise false. */ - is(anything: any): anything is ChainReference; + is(anything: any): anything is IGunChainReference; /** * Returns data's gun ID (instead of manually grabbing its metadata i.e. data["_"]["#"], which is faster but could change in the future) * * Returns undefined if data is not correct gun data. */ - soul(data: ChainReference): string; + soul(data: IGunChainReference): string; /** Returns a "gun-ified" variant of the json input by injecting a new gun ID into the metadata field. */ ify(json: any): any; }; diff --git a/types/types.d.ts b/types/types.d.ts index 9fdc2dd1..a7e78399 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -1,4 +1,4 @@ -import { ChainReference } from './chain'; +import { IGunChainReference } from './chain'; export declare type ArrayOf = T extends Array ? U : never; /** Gun does not accept Array value, so we need extract to make types correct */ export declare type AllowArray = ArrayOf extends never ? T : ArrayOf; @@ -13,7 +13,7 @@ export declare type AccessObject = T extends object ? { /** These types cannot be stored on Gun's root level */ export declare type DisallowPrimitives = Open extends false ? T : T extends string ? never : T extends number ? never : T extends boolean ? never : T extends null ? never : T extends undefined ? never : T; export declare type ArrayAsRecord = ArrayOf extends never ? DataType : Record; -export declare type Saveable = Partial | string | number | boolean | null | ChainReference; +export declare type Saveable = Partial | string | number | boolean | null | IGunChainReference; export declare type AckCallback = (ack: { err: Error; ok: any; @@ -21,5 +21,4 @@ export declare type AckCallback = (ack: { err: undefined; ok: string; }) => void; -export declare type Parameters any> = T extends (...args: infer P) => any ? P : never; export declare type CryptoKeyPair = Record<'pub' | 'priv' | 'epub' | 'epriv', string>; From 4e94d7f04e40c361fa9ec0842f94e49885189841 Mon Sep 17 00:00:00 2001 From: bluelovers Date: Wed, 5 Feb 2020 08:38:51 +0800 Subject: [PATCH 29/87] chore: .npmignore --- .npmignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.npmignore b/.npmignore index 6dafed9c..bb580d92 100644 --- a/.npmignore +++ b/.npmignore @@ -1,2 +1,3 @@ *.ts /temp/ +!*.d.ts From 4d252a96f7c64d069af7bfa52ff47b1f9b903689 Mon Sep 17 00:00:00 2001 From: bluelovers Date: Wed, 5 Feb 2020 09:02:32 +0800 Subject: [PATCH 30/87] fix: types chain.then --- package.json | 10 ++++++++-- types/chain.d.ts | 11 +++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 32601190..08bd3b3d 100644 --- a/package.json +++ b/package.json @@ -59,16 +59,22 @@ "ws": "^7.1.2" }, "optionalDependencies": { - "text-encoding": "^0.7.0", + "emailjs": "^2.2.0", "isomorphic-webcrypto": "^2.3.2", - "emailjs": "^2.2.0" + "text-encoding": "^0.7.0" }, "devDependencies": { + "@types/ip": "^1.1.0", + "@types/mocha": "^7.0.1", + "@types/node": "^13.7.0", + "@types/uglify-js": "^3.0.4", + "@types/ws": "^7.2.1", "aws-sdk": "^2.528.0", "ip": "^1.1.5", "mocha": "^6.2.0", "panic-manager": "^1.2.0", "panic-server": "^1.1.1", + "ts-type": "^1.2.13", "uglify-js": "^3.6.0" } } diff --git a/types/chain.d.ts b/types/chain.d.ts index ce6c0ae2..9a625473 100644 --- a/types/chain.d.ts +++ b/types/chain.d.ts @@ -1,5 +1,6 @@ import { AlwaysDisallowedType, DisallowPrimitives, DisallowArray, AckCallback, ArrayOf, ArrayAsRecord, Saveable } from './types'; import { IGunConstructorOptions } from './options'; +import { ITSResolvable } from 'ts-type'; export interface IGunChainReference, ReferenceKey = any, IsTop extends 'pre_root' | 'root' | false = false> { /** * Save data into gun, syncing it with your connected peers. @@ -134,18 +135,24 @@ export interface IGunChainReference, ReferenceKey * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/then.js')` or * ``! */ - then?>(onfulfilled?: (value: TResult1) => TResult1 | PromiseLike): Promise; + then?>(onfulfilled: (value: TResult1) => ITSResolvable): Promise; + then?>(): Promise; /** * Returns a promise for you to use. * * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/then.js')` or * ``! */ + promise?; + key: ReferenceKey; + gun: IGunChainReference; + }>(onfulfilled: (value: TResult1) => ITSResolvable): Promise; promise?; key: ReferenceKey; gun: IGunChainReference; - }>(onfulfilled?: (value: TResult1) => TResult1 | PromiseLike): Promise; + }>(): Promise; /** * bye lets you change data after that browser peer disconnects. * This is useful for games and status messages, From 4a42a4f1ce73d7389a0cb112b725550eb8625f04 Mon Sep 17 00:00:00 2001 From: bluelovers Date: Wed, 5 Feb 2020 09:24:50 +0800 Subject: [PATCH 31/87] refactor: split types `node` , `SEA` --- .gitignore | 4 +-- types/static.d.ts | 73 ++++-------------------------------------- types/static/node.d.ts | 13 ++++++++ types/static/sea.d.ts | 56 ++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 69 deletions(-) create mode 100644 types/static/node.d.ts create mode 100644 types/static/sea.d.ts diff --git a/.gitignore b/.gitignore index 31b50576..ef773b4c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,7 @@ yarn.lock .esm-cache .sessionStorage .localStorage -/types/*.ts -!/types/*.d.ts +/types/**/*.ts +!/types/**/*.d.ts /gun.ts /temp/ diff --git a/types/static.d.ts b/types/static.d.ts index 82e8832b..939647fe 100644 --- a/types/static.d.ts +++ b/types/static.d.ts @@ -1,5 +1,7 @@ import { IGunChainReference } from './chain'; import { IGunConstructorOptions } from './options'; +import { IGunStaticNode } from './static/node'; +import { IGunStaticSEA } from './static/sea'; export interface IGunStatic { /** * @description @@ -11,72 +13,9 @@ export interface IGunStatic { */ (options?: string | string[] | IGunConstructorOptions): IGunChainReference; new (options?: string | string[] | IGunConstructorOptions): IGunChainReference; - node: { - /** Returns true if data is a gun node, otherwise false. */ - is(anything: any): anything is IGunChainReference; - /** - * Returns data's gun ID (instead of manually grabbing its metadata i.e. data["_"]["#"], which is faster but could change in the future) - * - * Returns undefined if data is not correct gun data. - */ - soul(data: IGunChainReference): string; - /** Returns a "gun-ified" variant of the json input by injecting a new gun ID into the metadata field. */ - ify(json: any): any; - }; + node: IGunStaticNode; /** @see https://gun.eco/docs/SEA */ - SEA: { - /** If you want SEA to throw while in development, turn SEA.throw = true on, but please do not use this in production. */ - throw?: boolean; - /** Last known error */ - err?: Error; - /** - * This gives you a Proof of Work (POW) / Hashing of Data - * @param data The data to be hashed, work to be performed on. - * @param pair (salt) You can pass pair of keys to use as salt. Salt will prevent others to pre-compute the work, - * so using your public key is not a good idea. If it is not specified, it will be random, - * which ruins your chance of ever being able to re-derive the work deterministically - * @param callback function to executed upon execution of proof - * @param opt default: {name: 'PBKDF2', encode: 'base64'} - */ - work(data: any, pair?: any, callback?: (data: string | undefined) => void, opt?: Partial<{ - name: 'SHA-256' | 'PBKDF2'; - encode: 'base64' | 'base32' | 'base16'; - /** iterations to use on subtle.deriveBits */ - iterations: number; - salt: any; - hash: string; - length: any; - }>): Promise; - /** - * This generates a cryptographically secure public/private key pair - be careful not to leak the private keys! - * Note: API subject to change we may change the parameters to accept data and work, in addition to generation. - * You will need this for most of SEA's API, see those method's examples. - * The default cryptographic primitives for the asymmetric keys are ECDSA for signing and ECDH for encryption. - */ - pair(cb: (data: CryptoKeyPair) => void, opt?: {}): Promise; - /** - * Adds a signature to a message, for data that you want to prevent attackers tampering with. - * @param data is the content that you want to prove is authorized. - * @param pair is from .pair. - */ - sign(data: any, pair: CryptoKeyPair): Promise; - /** - * Gets the data if and only if the message can be verified as coming from the person you expect. - * @param message is what comes from .sign. - * @param pair from .pair or its public key text (pair.pub). - */ - verify(message: any, pair: CryptoKeyPair | string): Promise; - /** - * Takes some data that you want to keep secret and encrypts it so nobody else can read it. - * @param data is the content that you want to encrypt. - * @param pair from .pair or a passphrase you want to use as a cypher to encrypt with. - */ - encrypt(data: any, pair: CryptoKeyPair | string): Promise; - /** - * Read the secret data, if and only if you are allowed to. - * @param message is what comes from .encrypt. - * @param pair from .pair or the passphrase to decypher the message. - */ - decrypt(message: any, pair: CryptoKeyPair | string): Promise; - }; + SEA: IGunStaticSEA; + version: string; + readonly chain: IGunChainReference; } diff --git a/types/static/node.d.ts b/types/static/node.d.ts new file mode 100644 index 00000000..17c3696f --- /dev/null +++ b/types/static/node.d.ts @@ -0,0 +1,13 @@ +import { IGunChainReference } from '../chain'; +export interface IGunStaticNode { + /** Returns true if data is a gun node, otherwise false. */ + is(anything: any): anything is IGunChainReference; + /** + * Returns data's gun ID (instead of manually grabbing its metadata i.e. data["_"]["#"], which is faster but could change in the future) + * + * Returns undefined if data is not correct gun data. + */ + soul(data: IGunChainReference): string; + /** Returns a "gun-ified" variant of the json input by injecting a new gun ID into the metadata field. */ + ify(json: any): any; +} diff --git a/types/static/sea.d.ts b/types/static/sea.d.ts new file mode 100644 index 00000000..bd183021 --- /dev/null +++ b/types/static/sea.d.ts @@ -0,0 +1,56 @@ +/** @see https://gun.eco/docs/SEA */ +export interface IGunStaticSEA { + /** If you want SEA to throw while in development, turn SEA.throw = true on, but please do not use this in production. */ + throw?: boolean; + /** Last known error */ + err?: Error; + /** + * This gives you a Proof of Work (POW) / Hashing of Data + * @param data The data to be hashed, work to be performed on. + * @param pair (salt) You can pass pair of keys to use as salt. Salt will prevent others to pre-compute the work, + * so using your public key is not a good idea. If it is not specified, it will be random, + * which ruins your chance of ever being able to re-derive the work deterministically + * @param callback function to executed upon execution of proof + * @param opt default: {name: 'PBKDF2', encode: 'base64'} + */ + work(data: any, pair?: any, callback?: (data: string | undefined) => void, opt?: Partial<{ + name: 'SHA-256' | 'PBKDF2'; + encode: 'base64' | 'base32' | 'base16'; + /** iterations to use on subtle.deriveBits */ + iterations: number; + salt: any; + hash: string; + length: any; + }>): Promise; + /** + * This generates a cryptographically secure public/private key pair - be careful not to leak the private keys! + * Note: API subject to change we may change the parameters to accept data and work, in addition to generation. + * You will need this for most of SEA's API, see those method's examples. + * The default cryptographic primitives for the asymmetric keys are ECDSA for signing and ECDH for encryption. + */ + pair(cb: (data: CryptoKeyPair) => void, opt?: {}): Promise; + /** + * Adds a signature to a message, for data that you want to prevent attackers tampering with. + * @param data is the content that you want to prove is authorized. + * @param pair is from .pair. + */ + sign(data: any, pair: CryptoKeyPair): Promise; + /** + * Gets the data if and only if the message can be verified as coming from the person you expect. + * @param message is what comes from .sign. + * @param pair from .pair or its public key text (pair.pub). + */ + verify(message: any, pair: CryptoKeyPair | string): Promise; + /** + * Takes some data that you want to keep secret and encrypts it so nobody else can read it. + * @param data is the content that you want to encrypt. + * @param pair from .pair or a passphrase you want to use as a cypher to encrypt with. + */ + encrypt(data: any, pair: CryptoKeyPair | string): Promise; + /** + * Read the secret data, if and only if you are allowed to. + * @param message is what comes from .encrypt. + * @param pair from .pair or the passphrase to decypher the message. + */ + decrypt(message: any, pair: CryptoKeyPair | string): Promise; +} From 90ca38ee7e8c5a20e18f9cfec242ecfe0a5ea54d Mon Sep 17 00:00:00 2001 From: bluelovers Date: Wed, 5 Feb 2020 09:32:00 +0800 Subject: [PATCH 32/87] chore: yarn-tool lockfile --npm --overwrite --- package-lock.json | 3438 +++++++++++++++++++-------------------------- 1 file changed, 1472 insertions(+), 1966 deletions(-) diff --git a/package-lock.json b/package-lock.json index aff7ee5f..35cb6e66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,1968 +1,1474 @@ { - "name": "gun", - "version": "0.2019.1211", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@peculiar/asn1-schema": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-1.0.3.tgz", - "integrity": "sha512-Tfgj9eNJ6cTKEtEuidKenLHMx/Q5M8KEE9hnohHqvdpqHJXWYr5RlT3GjAHPjGXy5+mr7sSfuXfzE6aAkEGN7A==", - "optional": true, - "requires": { - "asn1js": "^2.0.22", - "tslib": "^1.9.3" - } - }, - "@peculiar/json-schema": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.5.tgz", - "integrity": "sha512-y5XYA3pf9+c+YKVpWnPtQbNmlNCs2ehNHyMLJvq4K5Fjwc1N64YGy7MNecKW3uYLga+sqbGTQSUdOdlnaRRbpA==", - "optional": true, - "requires": { - "tslib": "^1.9.3" - } - }, - "@peculiar/webcrypto": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.0.19.tgz", - "integrity": "sha512-+lF69A18LJBLp0/gJIQatCARLah6cTUmLwY0Cdab0zsk+Z53BcpjKQyyP4LIN8oW601ZXv28mWEQ4Cm7MllF6w==", - "optional": true, - "requires": { - "@peculiar/asn1-schema": "^1.0.3", - "@peculiar/json-schema": "^1.1.5", - "asn1js": "^2.0.26", - "pvtsutils": "^1.0.6", - "tslib": "^1.10.0", - "webcrypto-core": "^1.0.14" - } - }, - "@types/node": { - "version": "10.14.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.18.tgz", - "integrity": "sha512-ryO3Q3++yZC/+b8j8BdKd/dn9JlzlHBPdm80656xwYUdmPkpTGTjkAdt6BByiNupGPE8w0FhBgvYy/fX9hRNGQ==", - "optional": true - }, - "@unimodules/core": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@unimodules/core/-/core-3.0.2.tgz", - "integrity": "sha512-EMZjVp+yrtoPKpDBPvj4+hyDWALl7gvpWeUsDz2Nb9MMBPLnhag1uNk3KC98StJdnjbSXKSdKrCMMidOXnyKcg==", - "optional": true, - "requires": { - "compare-versions": "^3.4.0" - } - }, - "@unimodules/react-native-adapter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@unimodules/react-native-adapter/-/react-native-adapter-3.0.0.tgz", - "integrity": "sha512-zkFFE0HQ2Flfx/aY3hBKDgMvQ1meUm3H6vMIacY1KywexCuKW8ivBobkOsHIet4jf7km0Eklt6WtB3LqQVw5yw==", - "optional": true, - "requires": { - "invariant": "^2.2.4", - "lodash": "^4.5.0", - "prop-types": "^15.6.1" - } - }, - "addressparser": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-0.3.2.tgz", - "integrity": "sha1-WYc/Nej89sc2HBAjkmHXbhU0i7I=", - "optional": true - }, - "after": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", - "dev": true - }, - "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arraybuffer.slice": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", - "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=", - "dev": true - }, - "asmcrypto.js": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/asmcrypto.js/-/asmcrypto.js-0.22.0.tgz", - "integrity": "sha512-usgMoyXjMbx/ZPdzTSXExhMPur2FTdz/Vo5PVx2gIaBcdAAJNOFlsdgqveM8Cff7W0v+xrf9BwjOV26JSAF9qA==", - "optional": true - }, - "asn1js": { - "version": "2.0.26", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-2.0.26.tgz", - "integrity": "sha512-yG89F0j9B4B0MKIcFyWWxnpZPLaNTjCj4tkE3fjbAoo0qmpGw0PYYqSbX/4ebnd9Icn8ZgK4K1fvDyEtW1JYtQ==", - "optional": true, - "requires": { - "pvutils": "^1.0.17" - } - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, - "aws-sdk": { - "version": "2.528.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.528.0.tgz", - "integrity": "sha512-WBgavPqKHvYcIhD7LhmLLYOKtG/SUdNY6hMB0N/Jxaolzx4sOa7xegiZ8sdkAUq/vUEs1frnBF9hNmeIszUWCg==", - "dev": true, - "requires": { - "buffer": "4.9.1", - "events": "1.1.1", - "ieee754": "1.1.8", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.3.2", - "xml2js": "0.4.19" - }, - "dependencies": { - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "dev": true, - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - } - } - }, - "b64-lite": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/b64-lite/-/b64-lite-1.3.1.tgz", - "integrity": "sha512-A3n/YWszeQeUeKKy+XRfsDW/s/+1cvD110HYA4uXtkNswNLd1MxrNblYt2lgKisUS3UfPPTaXhvFegD+l4YuOA==", - "requires": { - "base-64": "^0.1.0" - } - }, - "b64u-lite": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/b64u-lite/-/b64u-lite-1.0.1.tgz", - "integrity": "sha512-4E6rqyrCnrAdzayWUS8XwFC/vRTBbmR7fgqb/IuHXRM2z63VH/tNxtzDWZhgCXCORTiwy2mIhCtmHyc9TMBj7Q==", - "optional": true, - "requires": { - "b64-lite": "^1.1.1" - } - }, - "backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base-64": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", - "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=" - }, - "base64-arraybuffer": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", - "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", - "dev": true - }, - "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" - }, - "base64id": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", - "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", - "dev": true - }, - "better-assert": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", - "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", - "dev": true, - "requires": { - "callsite": "1.0.0" - } - }, - "blob": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", - "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=", - "dev": true - }, - "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "buffer": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", - "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "callsite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "compare-versions": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.5.1.tgz", - "integrity": "sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg==", - "optional": true - }, - "component-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", - "dev": true - }, - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true - }, - "component-inherit": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", - "dev": true - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "emailjs": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/emailjs/-/emailjs-2.2.0.tgz", - "integrity": "sha1-ulsj5KSwpFEPZS6HOxVOlAe2ygM=", - "optional": true, - "requires": { - "addressparser": "^0.3.2", - "emailjs-mime-codec": "^2.0.7" - } - }, - "emailjs-base64": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/emailjs-base64/-/emailjs-base64-1.1.4.tgz", - "integrity": "sha512-4h0xp1jgVTnIQBHxSJWXWanNnmuc5o+k4aHEpcLXSToN8asjB5qbXAexs7+PEsUKcEyBteNYsSvXUndYT2CGGA==", - "optional": true - }, - "emailjs-mime-codec": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/emailjs-mime-codec/-/emailjs-mime-codec-2.0.9.tgz", - "integrity": "sha512-7qJo4pFGcKlWh/kCeNjmcgj34YoJWY0ekZXEHYtluWg4MVBnXqGM4CRMtZQkfYwitOhUgaKN5EQktJddi/YIDQ==", - "optional": true, - "requires": { - "emailjs-base64": "^1.1.4", - "ramda": "^0.26.1", - "text-encoding": "^0.7.0" - } - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "engine.io": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.5.tgz", - "integrity": "sha512-j1DWIcktw4hRwrv6nWx++5nFH2X64x16MAG2P0Lmi5Dvdfi3I+Jhc7JKJIdAmDJa+5aZ/imHV7dWRPy2Cqjh3A==", - "dev": true, - "requires": { - "accepts": "1.3.3", - "base64id": "1.0.0", - "cookie": "0.3.1", - "debug": "2.3.3", - "engine.io-parser": "1.3.2", - "ws": "~1.1.5" - }, - "dependencies": { - "accepts": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", - "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", - "dev": true, - "requires": { - "mime-types": "~2.1.11", - "negotiator": "0.6.1" - } - }, - "debug": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", - "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", - "dev": true, - "requires": { - "ms": "0.7.2" - } - }, - "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", - "dev": true - }, - "ultron": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", - "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", - "dev": true - }, - "ws": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", - "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", - "dev": true, - "requires": { - "options": ">=0.0.5", - "ultron": "1.0.x" - } - } - } - }, - "engine.io-client": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.5.tgz", - "integrity": "sha512-AYTgHyeVUPitsseqjoedjhYJapNVoSPShbZ+tEUX9/73jgZ/Z3sUlJf9oYgdEBBdVhupUpUqSxH0kBCXlQnmZg==", - "dev": true, - "requires": { - "component-emitter": "1.2.1", - "component-inherit": "0.0.3", - "debug": "2.3.3", - "engine.io-parser": "1.3.2", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "parsejson": "0.0.3", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "ws": "~1.1.5", - "xmlhttprequest-ssl": "1.5.3", - "yeast": "0.1.2" - }, - "dependencies": { - "debug": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", - "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", - "dev": true, - "requires": { - "ms": "0.7.2" - } - }, - "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", - "dev": true - }, - "ultron": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", - "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", - "dev": true - }, - "ws": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", - "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", - "dev": true, - "requires": { - "options": ">=0.0.5", - "ultron": "1.0.x" - } - } - } - }, - "engine.io-parser": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz", - "integrity": "sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo=", - "dev": true, - "requires": { - "after": "0.8.2", - "arraybuffer.slice": "0.0.6", - "base64-arraybuffer": "0.1.5", - "blob": "0.0.4", - "has-binary": "0.1.7", - "wtf-8": "1.0.0" - } - }, - "es-abstract": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.2.tgz", - "integrity": "sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.0", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-inspect": "^1.6.0", - "object-keys": "^1.1.1", - "string.prototype.trimleft": "^2.0.0", - "string.prototype.trimright": "^2.0.0" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", - "dev": true - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "expo-random": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/expo-random/-/expo-random-6.0.0.tgz", - "integrity": "sha512-nXWmopErqgwkGGfaKPG8v4BNqTXZH4oA/4aAnn6zkTVFdeWBDpWn+Ena3/jnM3raMR3pMNI39YNLqNrut81HvA==", - "optional": true, - "requires": { - "base64-js": "^1.3.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "flat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", - "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", - "dev": true, - "requires": { - "is-buffer": "~2.0.3" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-binary": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", - "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=", - "dev": true, - "requires": { - "isarray": "0.0.1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - } - } - }, - "has-cors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "ieee754": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", - "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" - }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "optional": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true - }, - "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", - "dev": true - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, - "requires": { - "has": "^1.0.1" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isomorphic-webcrypto": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/isomorphic-webcrypto/-/isomorphic-webcrypto-2.3.2.tgz", - "integrity": "sha512-XbUC6ZwVvJfts2FYfAuNRU99tt89EzTknZcKZjxx6/6hxNeLgF6sIDbA/RdA3spbcNrXYyPOHa90khbUgZWarw==", - "optional": true, - "requires": { - "@peculiar/webcrypto": "^1.0.19", - "@unimodules/core": "*", - "@unimodules/react-native-adapter": "*", - "asmcrypto.js": "^0.22.0", - "b64-lite": "^1.3.1", - "b64u-lite": "^1.0.1", - "expo-random": "*", - "msrcrypto": "^1.5.6", - "react-native-securerandom": "^0.1.1", - "str2buf": "^1.3.0", - "webcrypto-shim": "^0.1.4" - } - }, - "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "json3": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", - "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", - "dev": true - }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "optional": true - }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, - "requires": { - "p-defer": "^1.0.0" - } - }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - } - }, - "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", - "dev": true - }, - "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", - "dev": true, - "requires": { - "mime-db": "~1.33.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "mocha": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.0.tgz", - "integrity": "sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ==", - "dev": true, - "requires": { - "ansi-colors": "3.2.3", - "browser-stdout": "1.3.1", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "2.2.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "ms": "2.1.1", - "node-environment-flags": "1.0.5", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", - "wide-align": "1.1.3", - "yargs": "13.2.2", - "yargs-parser": "13.0.0", - "yargs-unparser": "1.5.0" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, - "msrcrypto": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/msrcrypto/-/msrcrypto-1.5.7.tgz", - "integrity": "sha512-vH/uVdMPgdtLrDCdR2gWps2fB10EYWjXYi67W9RzNSd5Jch3noWGUvNUXSIJA87VTDaE+wvjS7yRSN4gALTslg==", - "optional": true - }, - "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "object-assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", - "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=", - "dev": true - }, - "object-component": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", - "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", - "dev": true - }, - "object-inspect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "options": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", - "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", - "dev": true - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "panic-client": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/panic-client/-/panic-client-1.0.2.tgz", - "integrity": "sha1-4+yr3DQn6vELowviJZAaehGasXM=", - "dev": true, - "requires": { - "bluebird": "^3.4.6", - "is-promise": "^2.1.0", - "platform": "1.3.1", - "socket.io-client": "^1.4.5" - } - }, - "panic-manager": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/panic-manager/-/panic-manager-1.2.0.tgz", - "integrity": "sha1-0tvHdgIAMsWwEw0QW/vqewZnMh4=", - "dev": true, - "requires": { - "isarray": "^2.0.0", - "panic-client": "^1.0.0", - "socket.io": "^1.4.8", - "socket.io-client": "^1.4.8" - }, - "dependencies": { - "isarray": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz", - "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA==", - "dev": true - } - } - }, - "panic-server": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/panic-server/-/panic-server-1.1.1.tgz", - "integrity": "sha512-TcR6M4LaqKjHvAKoAi46w2Y11KPJiMchAEqu00+tlOBxHR8AYvUCBvDLw4+j3MymApVHHWtluOzDaWxEYeGuVw==", - "dev": true, - "requires": { - "bluebird": "^3.3.5", - "panic-client": "^1.0.0", - "socket.io": "^1.4.5" - } - }, - "parsejson": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz", - "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=", - "dev": true, - "requires": { - "better-assert": "~1.0.0" - } - }, - "parseqs": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", - "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", - "dev": true, - "requires": { - "better-assert": "~1.0.0" - } - }, - "parseuri": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", - "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", - "dev": true, - "requires": { - "better-assert": "~1.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "platform": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.1.tgz", - "integrity": "sha1-SSIQiSM1vTExwKCN2i2T7DVD5CM=", - "dev": true - }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "optional": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - }, - "dependencies": { - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "optional": true - } - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - }, - "pvtsutils": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.0.6.tgz", - "integrity": "sha512-0yNrOdJyLE7FZzmeEHTKanwBr5XbmDAd020cKa4ZiTYuGMBYBZmq7vHOhcOqhVllh6gghDBbaz1lnVdOqiB7cw==", - "optional": true, - "requires": { - "@types/node": "^10.14.17", - "tslib": "^1.10.0" - } - }, - "pvutils": { - "version": "1.0.17", - "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.0.17.tgz", - "integrity": "sha512-wLHYUQxWaXVQvKnwIDWFVKDJku9XDCvyhhxoq8dc5MFdIlRenyPI9eSfEtcvgHgD7FlvCyGAlWgOzRnZD99GZQ==", - "optional": true - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, - "ramda": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", - "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==", - "optional": true - }, - "react-is": { - "version": "16.9.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.9.0.tgz", - "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==", - "optional": true - }, - "react-native-securerandom": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/react-native-securerandom/-/react-native-securerandom-0.1.1.tgz", - "integrity": "sha1-8TBiOkEsM4sK+t7bwgTFy7i/IHA=", - "optional": true, - "requires": { - "base64-js": "*" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "socket.io": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.4.tgz", - "integrity": "sha1-L37O3DORvy1cc+KR/iM+bjTU3QA=", - "dev": true, - "requires": { - "debug": "2.3.3", - "engine.io": "~1.8.4", - "has-binary": "0.1.7", - "object-assign": "4.1.0", - "socket.io-adapter": "0.5.0", - "socket.io-client": "1.7.4", - "socket.io-parser": "2.3.1" - }, - "dependencies": { - "debug": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", - "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", - "dev": true, - "requires": { - "ms": "0.7.2" - } - }, - "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", - "dev": true - } - } - }, - "socket.io-adapter": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz", - "integrity": "sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s=", - "dev": true, - "requires": { - "debug": "2.3.3", - "socket.io-parser": "2.3.1" - }, - "dependencies": { - "debug": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", - "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", - "dev": true, - "requires": { - "ms": "0.7.2" - } - }, - "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", - "dev": true - } - } - }, - "socket.io-client": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.4.tgz", - "integrity": "sha1-7J+CA1btme9tNX8HVtZIcXvdQoE=", - "dev": true, - "requires": { - "backo2": "1.0.2", - "component-bind": "1.0.0", - "component-emitter": "1.2.1", - "debug": "2.3.3", - "engine.io-client": "~1.8.4", - "has-binary": "0.1.7", - "indexof": "0.0.1", - "object-component": "0.0.3", - "parseuri": "0.0.5", - "socket.io-parser": "2.3.1", - "to-array": "0.1.4" - }, - "dependencies": { - "debug": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", - "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", - "dev": true, - "requires": { - "ms": "0.7.2" - } - }, - "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", - "dev": true - } - } - }, - "socket.io-parser": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz", - "integrity": "sha1-3VMgJRA85Clpcya+/WQAX8/ltKA=", - "dev": true, - "requires": { - "component-emitter": "1.1.2", - "debug": "2.2.0", - "isarray": "0.0.1", - "json3": "3.3.2" - }, - "dependencies": { - "component-emitter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", - "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=", - "dev": true - }, - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "dev": true, - "requires": { - "ms": "0.7.1" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", - "dev": true - } - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "str2buf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/str2buf/-/str2buf-1.3.0.tgz", - "integrity": "sha512-xIBmHIUHYZDP4HyoXGHYNVmxlXLXDrtFHYT0eV6IOdEj3VO9ccaF1Ejl9Oq8iFjITllpT8FhaXb4KsNmw+3EuA==", - "optional": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "string.prototype.trimleft": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", - "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - } - }, - "string.prototype.trimright": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", - "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "text-encoding": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.7.0.tgz", - "integrity": "sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==", - "optional": true - }, - "to-array": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", - "dev": true - }, - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "optional": true - }, - "uglify-js": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", - "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", - "dev": true, - "requires": { - "commander": "~2.20.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true - } - } - }, - "url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true - }, - "webcrypto-core": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.0.14.tgz", - "integrity": "sha512-iGZQcH/o3Jv6mpvCbzan6uAcUcLTTnUCil6RVYakcNh5/QXIKRRC06EFxHru9lHgVKucZy3gG4OBiup0IsOr0g==", - "optional": true, - "requires": { - "pvtsutils": "^1.0.4", - "tslib": "^1.10.0" - } - }, - "webcrypto-shim": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/webcrypto-shim/-/webcrypto-shim-0.1.4.tgz", - "integrity": "sha512-I2lnL+K2oPNE9ryVHwo42oDnt8XQ9E1KKMGCmcT7OXaAKPmUeCi/G0nUgLR6M6Ztj05ZCxLMGf5bXNaSo+wURg==", - "optional": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "ws": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.1.2.tgz", - "integrity": "sha512-gftXq3XI81cJCgkUiAVixA0raD9IVmXqsylCrjRygw4+UOOGzPoxnQ6r/CnVL9i+mDncJo94tSkyrtuuQVBmrg==", - "requires": { - "async-limiter": "^1.0.0" - } - }, - "wtf-8": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz", - "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=", - "dev": true - }, - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "dev": true, - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", - "dev": true - }, - "xmlhttprequest-ssl": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", - "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=", - "dev": true - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yargs": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", - "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "os-locale": "^3.1.0", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "yargs-parser": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", - "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yargs-unparser": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", - "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", - "dev": true, - "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.11", - "yargs": "^12.0.5" - }, - "dependencies": { - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" - } - }, - "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "yeast": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", - "dev": true - } - } + "name": "gun", + "version": "0.2020.116", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", + "requires": { + "mime-types": "2.1.26", + "negotiator": "0.6.1" + } + }, + "addressparser": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-0.3.2.tgz", + "integrity": "sha1-WYc/Nej89sc2HBAjkmHXbhU0i7I=" + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha1-V9NbhoboUeLMBMQD8cACA5dqGBM=" + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "requires": { + "color-convert": "1.9.3" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", + "requires": { + "sprintf-js": "1.0.3" + } + }, + "arraybuffer.slice": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", + "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=" + }, + "asmcrypto.js": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/asmcrypto.js/-/asmcrypto.js-0.22.0.tgz", + "integrity": "sha1-OPwUQIhNgCx7030dI8KyalzV0tI=" + }, + "asn1js": { + "version": "2.0.26", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-2.0.26.tgz", + "integrity": "sha1-Cm1DUAD1VqlsYBKWnZcE2YG3ElE=", + "requires": { + "pvutils": "1.0.17" + } + }, + "aws-sdk": { + "version": "2.611.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.611.0.tgz", + "integrity": "sha1-sdo7xidANHIBsfpTtwCbMGsWJ94=", + "requires": { + "buffer": "4.9.1", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.15.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "uuid": "3.3.2", + "xml2js": "0.4.19" + }, + "dependencies": { + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "requires": { + "base64-js": "1.3.1", + "ieee754": "1.1.13", + "isarray": "1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + } + } + }, + "b64-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/b64-lite/-/b64-lite-1.4.0.tgz", + "integrity": "sha1-5iRC3hHx8hxg44t08RGsAkIoPT0=", + "requires": { + "base-64": "0.1.0" + } + }, + "b64u-lite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/b64u-lite/-/b64u-lite-1.1.0.tgz", + "integrity": "sha1-pYG335TL1L7Xy7Gf6ugWZU8LG/A=", + "requires": { + "b64-lite": "1.4.0" + } + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha1-WOzoy3XdB+ce0IxzarxfrE2/jfE=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha1-nyKcFb4nJFT/qXOs4NvueaGww28=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha1-uqVZ7hTO1zRSIputcyZGfGH6vWA=" + }, + "buffer": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", + "integrity": "sha1-P7ycaetxPTI+P8Gole7gcQwHIRU=", + "requires": { + "base64-js": "1.3.1", + "ieee754": "1.1.13" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha1-3u/P2y6AB4SqNPRvoI4GhRx7u8U=", + "requires": { + "string-width": "3.1.0", + "strip-ansi": "5.2.0", + "wrap-ansi": "5.1.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha1-/UhehMA+tIgcIHIrpIA16FMa6zM=" + }, + "compare-versions": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.5.1.tgz", + "integrity": "sha1-JuH1zw1Ip37O1QRrn2e2thB1o5M=" + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "requires": { + "ms": "0.7.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE=", + "requires": { + "object-keys": "1.1.1" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI=" + }, + "emailjs": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/emailjs/-/emailjs-2.2.0.tgz", + "integrity": "sha1-ulsj5KSwpFEPZS6HOxVOlAe2ygM=", + "requires": { + "addressparser": "0.3.2", + "emailjs-mime-codec": "2.0.9" + } + }, + "emailjs-base64": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/emailjs-base64/-/emailjs-base64-1.1.4.tgz", + "integrity": "sha1-OS+jjLaqNdzNOvNjf/wUwcfOlhI=" + }, + "emailjs-mime-codec": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/emailjs-mime-codec/-/emailjs-mime-codec-2.0.9.tgz", + "integrity": "sha1-0YRFG28uVcWGiw8KgtGP4rgvDJc=", + "requires": { + "emailjs-base64": "1.1.4", + "ramda": "0.26.1", + "text-encoding": "0.7.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY=" + }, + "engine.io": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.5.tgz", + "integrity": "sha1-Tr5edcbcEj3uSv3Obl/c7SHrk/Y=", + "requires": { + "accepts": "1.3.3", + "base64id": "1.0.0", + "debug": "2.3.3", + "engine.io-parser": "1.3.2", + "ws": "1.1.5", + "cookie": "0.3.1" + }, + "dependencies": { + "ws": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", + "integrity": "sha1-y9nm514J/F0skAFfIfDECHXg3VE=", + "requires": { + "options": "0.0.6", + "ultron": "1.0.2" + } + } + } + }, + "engine.io-client": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.5.tgz", + "integrity": "sha1-/n+2DLDc8vooWUiTKctZaN7esR8=", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "2.3.3", + "engine.io-parser": "1.3.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parsejson": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "1.1.5", + "xmlhttprequest-ssl": "1.5.3", + "yeast": "0.1.2" + }, + "dependencies": { + "ws": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", + "integrity": "sha1-y9nm514J/F0skAFfIfDECHXg3VE=", + "requires": { + "options": "0.0.6", + "ultron": "1.0.2" + } + } + } + }, + "engine.io-parser": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz", + "integrity": "sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo=", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "0.0.6", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary": "0.1.7", + "wtf-8": "1.0.0" + } + }, + "es-abstract": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha1-467fGXBrIOfCWUw1/A1XYFp54YQ=", + "requires": { + "es-to-primitive": "1.2.1", + "function-bind": "1.1.1", + "has": "1.0.3", + "has-symbols": "1.0.1", + "is-callable": "1.1.5", + "is-regex": "1.0.5", + "object-inspect": "1.7.0", + "object-keys": "1.1.1", + "object.assign": "4.1.0", + "string.prototype.trimleft": "2.1.1", + "string.prototype.trimright": "2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha1-5VzUyc3BiLzvsDs2bHNjI/xciYo=", + "requires": { + "is-callable": "1.1.5", + "is-date-object": "1.0.2", + "is-symbol": "1.0.3" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=" + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + }, + "expo-random": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/expo-random/-/expo-random-8.0.0.tgz", + "integrity": "sha1-u8x6GJ0prptwmzamz4QlbCLMFvY=", + "requires": { + "base64-js": "1.3.1" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha1-SRafHXmTQwZG2mHsxa41XCHJe3M=", + "requires": { + "locate-path": "3.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha1-CQvsiwXjnLowl0fx1YjwTbr5jbI=", + "requires": { + "is-buffer": "2.0.4" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha1-T5RBKoLbMvNuOwuXQfipf+sDH34=" + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha1-OWCDLT8VdBCDQtr9OmezMsCWnfE=", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.4", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha1-8nNdwig2dPpnR4sQGBBZNVw2nl4=" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", + "requires": { + "function-bind": "1.1.1" + } + }, + "has-binary": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", + "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=", + "requires": { + "isarray": "0.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha1-n1IUdYpEGWxAbZvXbOv4HsLdMeg=" + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha1-hK5l+n6vsWX922FWauFLrwVmTw8=" + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha1-7BaFWOlaoYH9h9N/VcMrvLZwi4Q=" + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=" + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", + "requires": { + "loose-envify": "1.4.0" + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha1-PlcvI8hBGlz9lVfISeNmXgspBiM=" + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha1-9+RrWWiQRW23Tn9ul2yzJz0G+qs=" + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha1-vac28s2P0G0yhE53Q7+nSUw7/X4=" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha1-OdWJo1i/GJZ/cmlnEguPwa7XTq4=", + "requires": { + "has": "1.0.3" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha1-OOEBS55jKb4N6dJKQU/XRB7GGTc=", + "requires": { + "has-symbols": "1.0.1" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isomorphic-webcrypto": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/isomorphic-webcrypto/-/isomorphic-webcrypto-2.3.4.tgz", + "integrity": "sha1-bRjuf3lasvXp/XpbSJq6+e4uavU=", + "requires": { + "@peculiar/webcrypto": "1.0.22", + "asmcrypto.js": "0.22.0", + "b64-lite": "1.4.0", + "b64u-lite": "1.1.0", + "msrcrypto": "1.5.8", + "str2buf": "1.3.0", + "webcrypto-shim": "0.1.5" + } + }, + "jmespath": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", + "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=" + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha1-r/FRswv9+o5J4F2iLnQV6d+jeEc=", + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.1" + } + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=" + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4=", + "requires": { + "p-locate": "3.0.0", + "path-exists": "3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha1-tEf2ZwoEVbv+7dETku/zMOoJdUg=" + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha1-V0Dhxdbw39pK2TI7UzIQfva0xAo=", + "requires": { + "chalk": "2.4.2" + } + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8=", + "requires": { + "js-tokens": "4.0.0" + } + }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha1-ChLgUCZQ5HPXNVNQUOfI9OtPrlg=" + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha1-nJIfwJt+FJpl39wNpNIJlyALCgY=", + "requires": { + "mime-db": "1.43.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.2.tgz", + "integrity": "sha1-XYmH4olAyviVen12ZLkQ3Fsv6iA=", + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "2.2.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "ms": "2.1.1", + "node-environment-flags": "1.0.5", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.0", + "yargs-parser": "13.1.1", + "yargs-unparser": "1.6.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=" + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=" + } + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" + }, + "msrcrypto": { + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/msrcrypto/-/msrcrypto-1.5.8.tgz", + "integrity": "sha1-vkGb5JRb8TTYr1Lp1Dvn+iYfShw=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-environment-flags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", + "integrity": "sha1-+pMCdfW/Xa4YjWGSsktMi7rD12o=", + "requires": { + "object.getownpropertydescriptors": "2.1.0", + "semver": "5.7.1" + } + }, + "object-assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", + "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha1-9Pa9GBrXfwBrXs5gvQtvOY/3Smc=" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha1-HEfyct8nfzsdrwYWd9nILiMixg4=" + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha1-lovxEA15Vrs8oIbwBvhGs7xACNo=", + "requires": { + "define-properties": "1.1.3", + "function-bind": "1.1.1", + "has-symbols": "1.0.1", + "object-keys": "1.1.1" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha1-Npvx+VktiridcS3O1cuBx8U1Jkk=", + "requires": { + "define-properties": "1.1.3", + "es-abstract": "1.17.4" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha1-YSebZ3IfUoeqHBOpp/u8SMkpGx4=", + "requires": { + "p-try": "2.2.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ=", + "requires": { + "p-limit": "2.2.2" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha1-yyhoVA4xPWHeWPr741zpAE1VQOY=" + }, + "panic-client": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/panic-client/-/panic-client-1.0.2.tgz", + "integrity": "sha1-4+yr3DQn6vELowviJZAaehGasXM=", + "requires": { + "bluebird": "3.7.2", + "is-promise": "2.1.0", + "platform": "1.3.1", + "socket.io-client": "1.7.4" + } + }, + "panic-manager": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/panic-manager/-/panic-manager-1.2.0.tgz", + "integrity": "sha1-0tvHdgIAMsWwEw0QW/vqewZnMh4=", + "requires": { + "isarray": "2.0.5", + "panic-client": "1.0.2", + "socket.io": "1.7.4", + "socket.io-client": "1.7.4" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha1-ivHkwSISRMxiRZ+vOJQNTmRKVyM=" + } + } + }, + "panic-server": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/panic-server/-/panic-server-1.1.1.tgz", + "integrity": "sha1-RNCZ04p8R17yekTxsgMmYRCydpY=", + "requires": { + "bluebird": "3.7.2", + "panic-client": "1.0.2", + "socket.io": "1.7.4" + } + }, + "parsejson": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz", + "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=", + "requires": { + "better-assert": "1.0.2" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "1.0.2" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "1.0.2" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "platform": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.1.tgz", + "integrity": "sha1-SSIQiSM1vTExwKCN2i2T7DVD5CM=" + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha1-UsQedbjIfnK52TYOAga5ncv/psU=", + "requires": { + "loose-envify": "1.4.0", + "object-assign": "4.1.1", + "react-is": "16.12.0" + }, + "dependencies": { + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + } + } + }, + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + }, + "pvtsutils": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.0.9.tgz", + "integrity": "sha1-DrYQbyeHjMqlXn379r0sda9GHe4=", + "requires": { + "tslib": "1.10.0" + } + }, + "pvutils": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.0.17.tgz", + "integrity": "sha1-rePHTf5xeJRP5EgGYmvS4knZlr8=" + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "ramda": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", + "integrity": "sha1-jUE1HrgRHFU1Nhf8O7/62OTTXQY=" + }, + "react-is": { + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", + "integrity": "sha1-LMD+D7p0LZf9UnxCoTvsTusGJBw=" + }, + "react-native-securerandom": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/react-native-securerandom/-/react-native-securerandom-0.1.1.tgz", + "integrity": "sha1-8TBiOkEsM4sK+t7bwgTFy7i/IHA=", + "requires": { + "base64-js": "1.3.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha1-0LMp7MfMD2Fkn2IhW+aa9UqomJs=" + }, + "sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "socket.io": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.4.tgz", + "integrity": "sha1-L37O3DORvy1cc+KR/iM+bjTU3QA=", + "requires": { + "debug": "2.3.3", + "engine.io": "1.8.5", + "has-binary": "0.1.7", + "object-assign": "4.1.0", + "socket.io-adapter": "0.5.0", + "socket.io-client": "1.7.4", + "socket.io-parser": "2.3.1" + } + }, + "socket.io-adapter": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz", + "integrity": "sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s=", + "requires": { + "debug": "2.3.3", + "socket.io-parser": "2.3.1" + } + }, + "socket.io-client": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.4.tgz", + "integrity": "sha1-7J+CA1btme9tNX8HVtZIcXvdQoE=", + "requires": { + "backo2": "1.0.2", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "2.3.3", + "engine.io-client": "1.8.5", + "has-binary": "0.1.7", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseuri": "0.0.5", + "socket.io-parser": "2.3.1", + "to-array": "0.1.4" + } + }, + "socket.io-parser": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz", + "integrity": "sha1-3VMgJRA85Clpcya+/WQAX8/ltKA=", + "requires": { + "debug": "2.2.0", + "json3": "3.3.2", + "component-emitter": "1.1.2", + "isarray": "0.0.1" + }, + "dependencies": { + "component-emitter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", + "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=" + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "str2buf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/str2buf/-/str2buf-1.3.0.tgz", + "integrity": "sha1-pBcq//QxDmcjUXjnOKLbtXOr6tA=" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", + "requires": { + "emoji-regex": "7.0.3", + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "5.2.0" + } + }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha1-m9uKxqvW1gKxek7TIYcNL43O/HQ=", + "requires": { + "define-properties": "1.1.3", + "function-bind": "1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha1-RAMUsVmWyGbOigNBiU1FGGIAxdk=", + "requires": { + "define-properties": "1.1.3", + "function-bind": "1.1.1" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "requires": { + "ansi-regex": "4.1.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha1-ds/nQs8fQbubHCmtAwaMBbTA5Ao=", + "requires": { + "has-flag": "3.0.0" + } + }, + "text-encoding": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.7.0.tgz", + "integrity": "sha1-+JXoNuRZkGJAhmAXmOqY6PNu5kM=" + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "ts-toolbelt": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.1.13.tgz", + "integrity": "sha1-EpNbyLgQUuXiHq3dNTcucTINfuM=" + }, + "ts-type": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/ts-type/-/ts-type-1.2.13.tgz", + "integrity": "sha1-668v0DgmNY3uXyDniiLWqW2x95E=", + "requires": { + "ts-toolbelt": "6.1.13", + "typedarray-dts": "1.0.0" + } + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha1-w8GflZc/sKYpc/sJ2Q2WHuQ+XIo=" + }, + "typedarray-dts": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typedarray-dts/-/typedarray-dts-1.0.0.tgz", + "integrity": "sha1-neyYEThtv7qWTClcJgbPmmuYLQY=" + }, + "uglify-js": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.7.tgz", + "integrity": "sha1-IeUsfczagKU7983mliin5RGuyck=", + "requires": { + "commander": "2.20.3", + "source-map": "0.6.1" + } + }, + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" + }, + "url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha1-G0r0lV6zB3xQHCOHL8ZROBFYcTE=" + }, + "webcrypto-core": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.0.17.tgz", + "integrity": "sha1-qTVLwLG6ZzXogvQTft4sQ2bmrZs=", + "requires": { + "pvtsutils": "1.0.9", + "tslib": "1.10.0" + } + }, + "webcrypto-shim": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/webcrypto-shim/-/webcrypto-shim-0.1.5.tgz", + "integrity": "sha1-E+NKAQzMVE7ez+iiZCIEUChBvPA=" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", + "requires": { + "isexe": "2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha1-rgdOa9wMFKQx6ATmJFScYzsABFc=", + "requires": { + "string-width": "2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha1-H9H2cjXVttD+54EFYAG/tpTAOwk=", + "requires": { + "ansi-styles": "3.2.1", + "string-width": "3.1.0", + "strip-ansi": "5.2.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.1.tgz", + "integrity": "sha1-A+1SQjzXRAhLLPQu0ZfItlqTa44=" + }, + "wtf-8": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz", + "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=" + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha1-aGwg8hMgnpSr8NG88e+qKRx4J6c=", + "requires": { + "sax": "1.2.4", + "xmlbuilder": "9.0.7" + }, + "dependencies": { + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=" + } + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + }, + "xmlhttprequest-ssl": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", + "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=" + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha1-le+U+F7MgdAHwmThkKEg8KPIVms=" + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha1-TGV6VeB+Xyz5R/ijZlZ8BKDe3IM=", + "requires": { + "cliui": "5.0.0", + "find-up": "3.0.0", + "get-caller-file": "2.0.5", + "require-directory": "2.1.1", + "require-main-filename": "2.0.0", + "set-blocking": "2.0.0", + "string-width": "3.1.0", + "which-module": "2.0.0", + "y18n": "4.0.0", + "yargs-parser": "13.1.1" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha1-0mBYUyqgbTZf4JH2ofwGsvfl7KA=", + "requires": { + "camelcase": "5.3.1", + "decamelize": "1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha1-7yXCx2n/a9CeSw+dfGBfsnhG6p8=", + "requires": { + "flat": "4.1.0", + "lodash": "4.17.15", + "yargs": "13.3.0" + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + }, + "@peculiar/asn1-schema": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-1.0.3.tgz", + "integrity": "sha1-5V/56Yoc8xgyYpqrrPhb4+3xOkg=", + "requires": { + "tslib": "1.10.0", + "asn1js": "2.0.26" + } + }, + "@peculiar/json-schema": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.9.tgz", + "integrity": "sha1-t0bgRreHYHobKAT2RDf9olJ7PmI=", + "requires": { + "tslib": "1.10.0" + } + }, + "@peculiar/webcrypto": { + "version": "1.0.22", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.0.22.tgz", + "integrity": "sha1-na5lL85rrNnfFbyRlleXzuM632c=", + "requires": { + "@peculiar/asn1-schema": "1.0.3", + "@peculiar/json-schema": "1.1.9", + "asn1js": "2.0.26", + "pvtsutils": "1.0.9", + "tslib": "1.10.0", + "webcrypto-core": "1.0.17" + } + }, + "@types/ip": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/ip/-/ip-1.1.0.tgz", + "integrity": "sha1-rsT1v9SeSkxTtZDYjDbrB4gnp8A=", + "requires": { + "@types/node": "13.7.0" + } + }, + "@types/mocha": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.1.tgz", + "integrity": "sha1-XX7Cp4mh93xZt60HG51Qvxq7/J4=" + }, + "@types/node": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.0.tgz", + "integrity": "sha1-tBfe2hjPhADyeHM0ma1VR+0avsQ=" + }, + "@types/uglify-js": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.0.4.tgz", + "integrity": "sha1-lr6uI99vVhhiqDC0KIpJ6GuqwII=", + "requires": { + "source-map": "0.6.1" + } + }, + "@types/ws": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.2.1.tgz", + "integrity": "sha1-uADyuK7mlOK1gRE2Q+INed07hVY=", + "requires": { + "@types/node": "13.7.0" + } + }, + "@unimodules/core": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@unimodules/core/-/core-5.0.0.tgz", + "integrity": "sha1-4ePKP5Hz0n28k8buvAOkDHEdp1U=", + "requires": { + "compare-versions": "3.5.1" + } + }, + "@unimodules/react-native-adapter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@unimodules/react-native-adapter/-/react-native-adapter-5.0.0.tgz", + "integrity": "sha1-r5g1ghor84OQufCfMjHAt1Ru5RA=", + "requires": { + "invariant": "2.2.4", + "lodash": "4.17.15", + "prop-types": "15.7.2" + } + } + } } From d2512f2842e781ab1061ffd4537ee4669a50b93e Mon Sep 17 00:00:00 2001 From: bluelovers Date: Wed, 5 Feb 2020 11:00:16 +0800 Subject: [PATCH 33/87] chore: fix log --- lib/radisk.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/radisk.js b/lib/radisk.js index 8c873546..c4793e01 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -299,7 +299,7 @@ Q[g.file] = [{key: key, ack: cb, file: g.file, opt: o}]; if(!g.file){ g.it(null, u, {}); - return true; + return true; } r.parse(g.file, g.check); return true; @@ -333,14 +333,14 @@ ){ o.more = u; as.ack(g.err, data, o); - return + return } if(u !== data){ var S = +new Date; as.ack(g.err, data, o); // more might be coming! LOG && opt.log(S, +new Date - S, 'rad range ack.'); // 1.4s if(o.parsed >= o.limit){ return } // even if more, we've hit our limit, asking peer will need to make a new ask with a new starting point. - } + } o.next = as.file; r.read(key, as.ack, o); } @@ -360,10 +360,10 @@ r.list(go); }); if(good){ return } - var id = Gun.text.random(3); console.log("MISLOCATED DATA", id); + var id = Gun.text.random(3); opt.log("MISLOCATED DATA", id); r.save(disk, function ack(err, ok){ if(err){ return r.save(disk, ack) } // ad infinitum??? - console.log("MISLOCATED CORRECTED", id); + opt.log("MISLOCATED CORRECTED", id); }); } /*g.check2 = function(err, disk, info){ @@ -478,7 +478,7 @@ l[2] = t.slice(i + o.i); return l; } - p.ack = function(cb){ + p.ack = function(cb){ if(!cb){ return } if(p.err || p.not){ return cb(p.err, u, info) } cb(u, p.disk, info); @@ -618,7 +618,7 @@ var Gun = window.Gun; var Radix = window.Radix; window.Radisk = Radisk; - } else { + } else { var Gun = require('../gun'); var Radix = require('./radix'); //var Radix = require('./radix2'); Radisk = require('./radisk2'); @@ -627,4 +627,4 @@ Radisk.Radix = Radix; -}()); \ No newline at end of file +}()); From 89b8f01cdafdf22565c894924717623a079ea1b8 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Wed, 5 Feb 2020 01:57:11 -0800 Subject: [PATCH 34/87] because yeah! --- examples/todo/index.html | 2 +- gun.js | 128 ++++++++-- lib/radiskip.js | 528 +++++++++++++++++++++++++++++++++++++++ lib/radix.js | 13 +- lib/store.js | 10 + sea.js | 110 +++++++- test/ptsd/radix.js | 51 +++- test/rad/rad.js | 15 +- 8 files changed, 817 insertions(+), 40 deletions(-) create mode 100644 lib/radiskip.js diff --git a/examples/todo/index.html b/examples/todo/index.html index e1061c57..c8a5d305 100644 --- a/examples/todo/index.html +++ b/examples/todo/index.html @@ -120,7 +120,7 @@ var w = 2; function go(i){ var S = +new Date; - var ref = gun.get(Gun.text.random(12)).put({data: Math.random()}, function(ack){ + var ref = gun.get(Gun.text.random(12)).put({data: Math.random(), ah: Math.random()}, function(ack){ console.log((+new Date - S)/1000, ack.err, ack.ok); ref.off(); }); diff --git a/gun.js b/gun.js index b4f81ef9..7831f053 100644 --- a/gun.js +++ b/gun.js @@ -359,7 +359,7 @@ /*if(perf){ t = start + perf.now(); // Danger: Accuracy decays significantly over time, even if precise. } else {*/ - t = time(); + t = +new Date; //} if(last < t){ return N = 0, last = t + State.drift; @@ -368,10 +368,10 @@ } var time = Type.time.is, last = -Infinity, N = 0, D = 1000; // WARNING! In the future, on machines that are D times faster than 2016AD machines, you will want to increase D by another several orders of magnitude so the processing speed never out paces the decimal resolution (increasing an integer effects the state accuracy). var perf = (typeof performance !== 'undefined')? (performance.timing && performance) : false, start = (perf && perf.timing && perf.timing.navigationStart) || (perf = false); - State._ = '>'; + var S_ = State._ = '>'; State.drift = 0; State.is = function(n, k, o){ // convenience function to get the state on a key on a node and return it. - var tmp = (k && n && n[N_] && n[N_][State._]) || o; + var tmp = (k && n && n[N_] && n[N_][S_]) || o; if(!tmp){ return } return num_is(tmp = tmp[k])? tmp : -Infinity; } @@ -383,7 +383,7 @@ } n = Node.soul.ify(n, soul); // then make it so! } - var tmp = obj_as(n[N_], State._); // grab the states data. + var tmp = obj_as(n[N_], S_); // grab the states data. if(u !== k && k !== N_){ if(num_is(s)){ tmp[k] = s; // add the valid state. @@ -618,40 +618,37 @@ ;USE(function(module){ var Type = USE('./type'); function Dup(opt){ - var dup = {s:{}}; + var dup = {s:{}}, s = dup.s; opt = opt || {max: 1000, age: /*1000 * 9};//*/ 1000 * 9 * 3}; - dup.check = function(id){ var tmp; - if(!(tmp = dup.s[id])){ return false } - if(tmp.pass){ return tmp.pass = false } + dup.check = function(id){ + if(!s[id]){ return false } return dup.track(id); } - dup.track = function(id, pass){ - var it = dup.s[id] || (dup.s[id] = {}); - it.was = time_is(); - if(pass){ it.pass = true } + dup.track = function(id){ + var it = s[id] || (s[id] = {}); + it.was = +new Date; if(!dup.to){ dup.to = setTimeout(dup.drop, opt.age + 9) } return it; } dup.drop = function(age){ - var now = time_is(); - Type.obj.map(dup.s, function(it, id){ + var now = +new Date; + Type.obj.map(s, function(it, id){ if(it && (age || opt.age) > (now - it.was)){ return } - Type.obj.del(dup.s, id); + delete s[id]; }); dup.to = null; } return dup; } - var time_is = Type.time.is; module.exports = Dup; })(USE, './dup'); ;USE(function(module){ function Gun(o){ - if(o instanceof Gun){ return (this._ = {gun: this, $: this}).$ } + if(o instanceof Gun){ return (this._ = {$: this}).$ } if(!(this instanceof Gun)){ return new Gun(o) } - return Gun.create(this._ = {gun: this, $: this, opt: o}); + return Gun.create(this._ = {$: this, opt: o}); } Gun.is = function($){ return ($ instanceof Gun) || ($ && $._ && ($ === $._.$)) || false } @@ -682,7 +679,9 @@ var gun = at.$.opt(at.opt); if(!at.once){ at.on('in', root, at); + at.on('in2', root2, at); at.on('out', root, {at: at, out: root}); + at.on('put2', cache, at); Gun.on('create', at); at.on('create', at); } @@ -716,8 +715,89 @@ at.on('out', msg); } } + function root2(msg){ + if(!msg){ return } + var eve = this, as = eve.as, at = as.at || as, gun = at.$, dup = at.dup, tmp; + if(!(tmp = msg['#'])){ tmp = msg['#'] = text_rand(9) } + if(dup.check(tmp)){ return } dup.track(tmp); + tmp = msg._; msg._ = ('function' == typeof msg._)? msg._ : function(){}; + if(msg.get){ Gun.on.get(msg, gun) } + if(msg.put){ PUT(msg, gun) } + eve.to.next(msg); + } }()); + ;(function(){ + Gun.on.put2 = function(msg, gun){ + var ctx = msg._, root = ctx.root = gun._, id = msg['#']; + var ack = ctx.ack = function(put){ put = put || {}; + if(ack.err = ack.err || (put||{}).err){ + if(ack.s){ root.on('in', {'@': id, err: Gun.log(ack.err)}) } + return ack.s = u; + } + var soul = put['#'], key = put['.'], val = put[':'], state = put['>'], tmp; + if((tmp = ack.s||{})[soul+key]){ + delete tmp[soul+key]; + root.on('put2', {put: put}); + } + if(!obj_empty(ack.s)){ return } // keep waiting + console.log("I'm all done!!!"); + } + ack.err = obj_map(msg.put, nodes, msg); + msg = ctx = u; + if(ack.err){ return ack() } + } + function nodes(node, soul){ + if(!node){ return ERR+cut(soul)+"no node." } + var ctx = this._, tmp; + if(!(tmp = node._)){ return ERR+cut(soul)+"no meta." } + ctx.node = node; + if(soul !== tmp[_soul]){ return ERR+cut(soul)+"soul not same." } + ctx.soul = soul; + if(!(ctx.states = tmp[state_])){ return ERR+cut(soul)+"no state." } + return obj_map(node, souls, this); + } + function souls(val, key){ + if(node_ === key){ return } + var ctx = this._, node = ctx.node, soul = ctx.soul, state = ctx.states[key]; + if(u === state){ return ERR+cut(key)+"on"+cut(soul)+"no state." } + if(!val_is(val)){ return ERR+cut(key)+"on"+cut(soul)+"bad "+(typeof val)+cut(val) } + ham(ctx.root.graph, soul, key, val, state, ctx.ack); // TODO: HANDLE CALLBACK WHERE ALL DAY IS HISTORIC? + } + function ham(graph, soul, key, val, state, ack){ + (ack.s || (ack.s = {}))[soul+key] = 1; + var vertex = graph[soul] || empty, was = state_is(vertex, key, 1), known = vertex[key]; + var machine = State(), is = HAM(machine, state, was, val, known), u; + if(!is.incoming){ + if(is.defer){ + var to = is.defer - machine; + setTimeout(function(){ + ham(graph, soul, key, val, state, cb); + }, to > MD? MD : to); // setTimeout Max Defer 32bit :( + return; + } + if(ack){ ack({'#': soul, '.': key}) } + return; + } + if(ack){ ack({'#': soul, '.': key, ':': val, '>': state}) } + } + var cut = function(s){ return " '"+(''+s).slice(0,9)+"...' " } + var ERR = "Error: Invalid graph!"; + }()); + var PUT = Gun.on.put2; + var HAM = Gun.HAM, MD = 2147483647, State = Gun.state; + function cache(msg){ + var eve = this, root = eve.as, graph = root.graph; + var put = msg.put, soul = put['#'], key = put['.'], val = put[':'], state = put['>']; + graph[soul] = state_ify(graph[soul], key, state, val, soul); + // trigger chains // trigger after all individual values cached? + if(eve.to.last === eve.to.next){ + console.log("THE END, reply back"); + return; + } + eve.to.next(msg); + } + ;(function(){ Gun.on.put = function(msg, gun){ var at = gun._, ctx = {$: gun, graph: at.graph, put: {}, map: {}, souls: {}, machine: Gun.state(), ack: msg['@'], cat: at, stop: {}}; @@ -735,7 +815,6 @@ if(!ctx.diff){ return } at.on('put', obj_to(msg, {put: ctx.diff})); }; - var MD = 2147483647; function verify(val, key, node, soul){ var ctx = this; var state = Gun.state.is(node, key), tmp; if(!state){ return ctx.err = "Error: No state on '"+key+"' in node '"+soul+"'!" } @@ -860,8 +939,8 @@ var list_is = Gun.list.is; var text = Gun.text, text_is = text.is, text_rand = text.random; - var obj = Gun.obj, obj_is = obj.is, obj_has = obj.has, obj_to = obj.to, obj_map = obj.map, obj_copy = obj.copy; - var state_lex = Gun.state.lex, _soul = Gun.val.link._, _has = '.', node_ = Gun.node._, rel_is = Gun.val.link.is; + var obj = Gun.obj, obj_empty = obj.empty, obj_is = obj.is, obj_has = obj.has, obj_to = obj.to, obj_map = obj.map, obj_copy = obj.copy; + var state_lex = Gun.state.lex, state_ify = Gun.state.ify, state_is = Gun.state.is, _soul = Gun.val.link._, _has = '.', node_ = Gun.node._, val_is = Gun.val.is, rel_is = Gun.val.link.is, state_ = Gun.state._; var empty = {}, u; console.only = function(i, s){ return (console.only.i && i === console.only.i && console.only.i++) && (console.log.apply(console, arguments) || s) }; @@ -1331,7 +1410,7 @@ if(eve.seen && at.id && eve.seen[at.id]){ return eve.to.next(msg) } //if((tmp = root.stop)){ if(tmp[at.id]){ return } tmp[at.id] = msg.root; } // temporary fix till a better solution? if((tmp = data) && tmp[rel._] && (tmp = rel.is(tmp))){ - tmp = ((msg.$$ = at.root.gun.get(tmp))._); + tmp = ((msg.$$ = at.root.$.get(tmp))._); if(u !== tmp.put){ msg = obj_to(msg, {put: data = tmp.put}); } @@ -1995,10 +2074,9 @@ try{msg = msg || JSON.parse(raw); }catch(e){return opt.log('DAM JSON parse error', e)} if(!msg){ return } + if(msg.DBG_s){ opt.log(+new Date - msg.DBG_s, 'to hear', msg['#']) } if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } - if(msg.DBG_s){ opt.log(+new Date - msg.DBG_s, 'to hear', id) } if(dup.check(id)){ return } - dup.track(id, true); //.it = it(msg); // GUN core also dedups, so `true` is needed. // Does GUN core need to dedup anymore? /*if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } if(hash && (tmp = msg['@'] || (msg.get && id))){ // Reduces backward daisy in case varying hashes at different daisy depths are the same. if(dup.check(tmp+hash)){ return } @@ -2011,11 +2089,13 @@ if(tmp = mesh.hear[msg.dam]){ tmp(msg, peer, root); } + dup.track(id); return; } var S, ST; LOG && (S = +new Date); console.STAT = {}; //root.on('in', msg); root.on('in2', msg); + dup.track(id); if(LOG && !msg.nts && (ST = +new Date - S) > 9){ opt.log(S, ST, 'msg', msg['#'], JSON.stringify(console.STAT)); if(ST > 500){ try{ require('./lib/email').send({text: ""+ST+"ms "+JSON.stringify(msg)+" | "+JSON.stringify(console.STAT), from: "mark@gun.eco", to: "mark@gun.eco", subject: "GUN MSG"}, noop); }catch(e){} } } // this is ONLY turned on if ENV CONFIGS have email/password to send out from. return; } diff --git a/lib/radiskip.js b/lib/radiskip.js new file mode 100644 index 00000000..70c86c7b --- /dev/null +++ b/lib/radiskip.js @@ -0,0 +1,528 @@ +;(function(){ + + function Radisk(opt){ + + opt = opt || {}; + opt.log = opt.log || console.log; + opt.file = String(opt.file || 'radata'); + var has = (Radisk.has || (Radisk.has = {}))[opt.file]; + if(has){ return has } + + opt.pack = opt.pack || (opt.memory? (opt.memory * 1000 * 1000) : 1399000000) * 0.3; // max_old_space_size defaults to 1400 MB. + opt.until = opt.until || opt.wait || 250; + opt.batch = opt.batch || (10 * 1000); + opt.chunk = opt.chunk || (1024 * 1024 * 1); // 1MB + opt.code = opt.code || {}; + opt.code.from = opt.code.from || '!'; + opt.jsonify = true; + + function ename(t){ return encodeURIComponent(t).replace(/\*/g, '%2A') } + function atomic(v){ return u !== v && (!v || 'object' != typeof v) } + var map = Gun.obj.map; + var LOG = console.LOG; + var ST = 0; + + if(!opt.store){ + return opt.log("ERROR: Radisk needs `opt.store` interface with `{get: fn, put: fn (, list: fn)}`!"); + } + if(!opt.store.put){ + return opt.log("ERROR: Radisk needs `store.put` interface with `(file, data, cb)`!"); + } + if(!opt.store.get){ + return opt.log("ERROR: Radisk needs `store.get` interface with `(file, cb)`!"); + } + if(!opt.store.list){ + //opt.log("WARNING: `store.list` interface might be needed!"); + } + + /* + Any and all storage adapters should... + 1. Because writing to disk takes time, we should batch data to disk. This improves performance, and reduces potential disk corruption. + 2. If a batch exceeds a certain number of writes, we should immediately write to disk when physically possible. This caps total performance, but reduces potential loss. + */ + var r = function(key, data, cb){ + if('function' === typeof data){ + var o = cb || {}; + cb = val; + return; + } + //var tmp = (tmp = r.batch = r.batch || {})[key] = tmp[key] || {}; + //var tmp = (tmp = r.batch = r.batch || {})[key] = data; + r.save(key, data, cb); + } + r.save = function(key, data, cb){ + var s = {key: key}; + s.find = function(file){ var tmp; + s.file = file = file || opt.code.from; + if(tmp = r.disk[file]){ return s.mix(null, tmp) } + r.parse(file, s.mix); + } + s.mix = function(err, disk){ + if(err){ return cb(err) } + s.file = (disk||noop).file || s.file; + ((disk = r.disk[s.file] || disk)||noop).file = s.file; + if(!disk && s.file !== opt.code.from){ // corrupt file? + r.find.bad(s.file); // remove from dir list + r.save(key, data, cb); // try again + return; + } + (r.disk[s.file] = disk = disk || Radix()).file = s.file; + if(opt.compare){ + data = opt.compare(disk(key), data, key, s.file); + if(u === data){ return cb(err, -1) } + } + // check if still in same r.find? + (s.disk = disk)(key, data); + if(disk.Q){ return disk.Q.push(cb) } disk.Q = [cb]; + disk.to = setTimeout(s.write, opt.until); + } + s.write = function(){ + var q = s.disk.Q; + delete s.disk.Q; + delete r.disk[s.file]; + r.write(s.file, s.disk, function(err, ok){ + Gun.obj.map(q, function(ack){ ack(err, ok) }); + }); + } + r.find(key, s.find); + } + r.disk = {}; + + /* + Any storage engine at some point will have to do a read in order to write. + This is true of even systems that use an append only log, if they support updates. + Therefore it is unavoidable that a read will have to happen, + the question is just how long you delay it. + */ + r.write = function(file, rad, cb, o){ + if(!rad){ return cb('No radix!') } + o = ('object' == typeof o)? o : {force: o}; + var f = function Fractal(){}, a, b; + f.text = ''; + f.file = file = rad.file = rad.file || file; + if(!file){ return cb('What file?') } + f.write = function(){ + var S; LOG && (S = +new Date); + r.disk[file = rad.file || f.file || file] = rad; + r.find.add(file, function(err){ + if(err){ return cb(err) } + opt.store.put(ename(file), f.text, function(err, ok){ + LOG && opt.log(S, ST = +new Date - S, "wrote disk", JSON.stringify(file)); + cb(err, ok); + delete r.disk[file]; + }); + }); + } + f.split = function(){ + f.text = ''; + if(!f.count){ f.count = 0; + Radix.map(rad, function(){ f.count++ }); // TODO: Perf? Any faster way to get total length? + } + f.limit = Math.ceil(f.count/2); + f.count = 0; + f.sub = Radix(); + Radix.map(rad, f.slice, {reverse: 1}); // IMPORTANT: DO THIS IN REVERSE, SO LAST HALF OF DATA MOVED TO NEW FILE BEFORE DROPPING FROM CURRENT FILE. + r.write(f.end, f.sub, f.both, o); + f.hub = Radix(); + Radix.map(rad, f.stop); + r.write(rad.file, f.hub, f.both, o); + return true; + } + f.slice = function(val, key){ + f.sub(f.end = key, val); + if(f.limit <= (++f.count)){ return true } + } + f.stop = function(val, key){ + if(key >= f.end){ return true } + f.hub(key, val); + } + f.both = function(err, ok){ + if(b){ return cb(err || b) } + if(a){ return cb(err, ok) } + a = true; + b = err; + } + f.each = function(val, key, k, pre){ + //console.log("RAD:::", JSON.stringify([val, key, k, pre])); + if(u !== val){ f.count++ } + if(opt.pack <= (val||'').length){ return cb("Record too big!"), true } + var enc = Radisk.encode(pre.length) +'#'+ Radisk.encode(k) + (u === val? '' : ':'+ Radisk.encode(val)) +'\n'; + if((opt.chunk < f.text.length + enc.length) && (1 < f.count) && !o.force){ + return f.split(); + } + f.text += enc; + } + if(opt.jsonify){ return r.write.jsonify(f, rad, cb, o) } // temporary testing idea + if(!Radix.map(rad, f.each, true)){ f.write() } + } + + r.write.jsonify = function(f, rad, cb, o){ + var raw; + var S; LOG && (S = +new Date); + try{raw = JSON.stringify(rad.$); + }catch(e){ return cb("Cannot radisk!") } + LOG && opt.log(S, +new Date - S, "rad stringified JSON"); + if(opt.chunk < raw.length && !o.force){ + return f.split(); + //if(Radix.map(rad, f.each, true)){ return } + } + f.text = raw; + f.write(); + } + + r.range = function(tree, o){ + if(!tree || !o){ return } + if(u === o.start && u === o.end){ return tree } + if(atomic(tree)){ return tree } + var sub = Radix(); + Radix.map(tree, function(v,k){ // ONLY PLACE THAT TAKES TREE, maybe reduce API for better perf? + sub(k,v); + }, o); + return sub(''); + } + + ;(function(){ + var Q = {}; + r.read = function(key, cb, o){ + o = o || {}; + if(RAD && !o.next){ // cache + var S; LOG && (S = +new Date); + var val = RAD(key); + LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'rad cached'); + //if(u !== val){ + //cb(u, val, o); + if(atomic(val)){ cb(u, val, o); return } + // if a node is requested and some of it is cached... the other parts might not be. + //} + } + o.span = (u !== o.start) || (u !== o.end); // is there a start or end? + var g = function Get(){}; + g.lex = function(file){ var tmp; // // TODO: this had a out-of-memory crash! + file = (u === file)? u : decodeURIComponent(file); + tmp = o.next || key || (o.reverse? o.end || '\uffff' : o.start || ''); + if(!file || (o.reverse? file < tmp : file > tmp)){ + LOG && opt.log(S, +new Date - S, 'rad read lex'); S = +new Date; + if(o.next || o.reverse){ g.file = file } + if(tmp = Q[g.file]){ + tmp.push({key: key, ack: cb, file: g.file, opt: o}); + return true; + } + Q[g.file] = [{key: key, ack: cb, file: g.file, opt: o}]; + if(!g.file){ + g.it(null, u, {}); + return true; + } + r.parse(g.file, g.check); + return true; + } + g.file = file; + } + g.it = function(err, disk, info){ + if(g.err = err){ opt.log('err', err) } + if(!disk && g.file){ // corrupt file? + r.find.bad(g.file); // remove from dir list + r.read(key, cb, o); // look again + return; + } + g.info = info; + if(disk){ RAD = g.disk = disk } + disk = Q[g.file]; delete Q[g.file]; + map(disk, g.ack); + } + g.ack = function(as){ + if(!as.ack){ return } + var S; LOG && (S = +new Date); + var key = as.key, o = as.opt, info = g.info, rad = g.disk || noop, data = r.range(rad(key), o), last = rad.last || Radix.map(rad, rev, revo); + LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, "rad range loaded"); + o.parsed = (o.parsed || 0) + (info.parsed||0); + o.chunks = (o.chunks || 0) + 1; + o.more = true; + if((!as.file) // if no more places to look + || (!o.span && last === key) // if our key exactly matches the very last atomic record + || (!o.span && last && last > key && 0 != last.indexOf(key)) // 'zach' may be lexically larger than 'za', but there still might be more, like 'zane' in the 'za' prefix bucket so do not end here. + ){ + o.more = u; + as.ack(g.err, data, o); + return + } + if(u !== data){ + as.ack(g.err, data, o); // more might be coming! + if(o.parsed >= o.limit){ return } // even if more, we've hit our limit, asking peer will need to make a new ask with a new starting point. + } + o.next = as.file; + r.read(key, as.ack, o); + } + g.check = function(err, disk, info){ + g.it(err, disk, info); + var good = true; + Radix.map(disk, function(val, key){ + // assume in memory for now, since both write/read already call r.find which will init it. + var go = function(file){ + if(info.file !== file){ + good = false + } + return true; + } + go.reverse = 1; + go.end = key; + r.list(go); + }); + if(good){ return } + var id = Gun.text.random(3); + r.save(disk, function ack(err, ok){ + if(err){ return r.save(disk, ack) } // ad infinitum??? + console.log("MISLOCATED DATA CORRECTED", id); + }); + } + /*g.check2 = function(err, disk, info){ + if(err || !disk){ return g.it(err, disk, info) } + var good = true; + Radix.map(disk, function(val, key){ + // assume in memory for now, since both write/read already call r.find which will init it. + var go = function(file){ + if(info.file !== file){ good = false } + return true; + } + go.reverse = 1; + go.end = key; + r.list(go); + }); + if(good){ return g.it(err, disk, info) } + var id = Gun.text.random(3); console.log("MISLOCATED DATA", id); + r.save(disk, function ack(err, ok){ + if(err){ return r.save(disk, ack) } // ad infinitum??? + console.log("MISLOCATED CORRECTED", id); + r.read(key, cb, o); + }); + }*/ + if(o.reverse){ g.lex.reverse = true } + LOG && (S = +new Date); + r.find(key, g.lex); + } + function rev(a,b){ return b } + var revo = {reverse: true}; + }()); + + ;(function(){ + /* + Let us start by assuming we are the only process that is + changing the directory or bucket. Not because we do not want + to be multi-process/machine, but because we want to experiment + with how much performance and scale we can get out of only one. + Then we can work on the harder problem of being multi-process. + */ + var Q = {}, s = String.fromCharCode(31); + r.parse = function(file, cb, raw){ var q; + if(q = Q[file]){ return q.push(cb) } q = Q[file] = [cb]; + var p = function Parse(){}, info = {file: file}; + (p.disk = Radix()).file = file; + p.read = function(err, data){ var tmp; + LOG && opt.log(S, +new Date - S, 'read disk', JSON.stringify(file)); + delete Q[file]; + if((p.err = err) || (p.not = !data)){ return map(q, p.ack) } + if('string' !== typeof data){ + try{ + if(opt.pack <= data.length){ + p.err = "Chunk too big!"; + } else { + data = data.toString(); // If it crashes, it crashes here. How!?? We check size first! + } + }catch(e){ p.err = e } + if(p.err){ return map(q, p.ack) } + } + info.parsed = data.length; + LOG && (S = +new Date); + if(opt.jsonify || '{' === data[0]){ + try{ + var json = JSON.parse(data); // TODO: this caused a out-of-memory crash! + p.disk.$ = json; + LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'rad parsed JSON'); + map(q, p.ack); + return; + }catch(e){ tmp = e } + if('{' === data[0]){ + p.err = tmp || "JSON error!"; + return map(q, p.ack); + } + } + return p.radec(err, data); + } + p.ack = function(cb){ + if(!cb){ return } + if(p.err || p.not){ return cb(p.err, u, info) } + cb(u, p.disk, info); + } + p.radec = function(err, data){ + LOG && (S = +new Date); + var tmp = p.split(data), pre = [], i, k, v; + if(!tmp || 0 !== tmp[1]){ + p.err = "File '"+file+"' does not have root radix! "; + return map(q, p.ack); + } + while(tmp){ + k = v = u; + i = tmp[1]; + tmp = p.split(tmp[2])||''; + if('#' == tmp[0]){ + k = tmp[1]; + pre = pre.slice(0,i); + if(i <= pre.length){ + pre.push(k); + } + } + tmp = p.split(tmp[2])||''; + if('\n' == tmp[0]){ continue } + if('=' == tmp[0] || ':' == tmp[0]){ v = tmp[1] } + if(u !== k && u !== v){ p.disk(pre.join(''), v) } + tmp = p.split(tmp[2]); + } + LOG && opt.log(S, +new Date - S, 'parsed RAD'); + map(q, p.ack); + }; + p.split = function(t){ + if(!t){ return } + var l = [], o = {}, i = -1, a = '', b, c; + i = t.indexOf(s); + if(!t[i]){ return } + a = t.slice(0, i); + l[0] = a; + l[1] = b = Radisk.decode(t.slice(i), o); + l[2] = t.slice(i + o.i); + return l; + } + var S; LOG && (S = +new Date); + if(raw){ return p.read(null, raw) } + opt.store.get(ename(file), p.read); + } + }()); + + ;(function(){ + var dir, f = String.fromCharCode(28), Q; + r.find = function(key, cb){ + if(!dir){ + if(Q){ return Q.push([key, cb]) } Q = [[key, cb]]; + return r.parse(f, init); + } + Radix.map(dir, function(val, key){ + if(!val){ return } + return cb(key) || true; + }, {reverse: 1, end: key}) || cb(); + } + r.find.add = function(file, cb){ + var has = dir(file); + if(has || file === f){ return cb(u, 1) } + dir(file, 1); + cb.found = (cb.found || 0) + 1; + r.write(f, dir, function(err, ok){ + if(err){ return cb(err) } + cb.found = (cb.found || 0) - 1; + if(0 !== cb.found){ return } + cb(u, 1); + }, true); + } + r.find.bad = function(file, cb){ + dir(file, 0); + r.write(f, dir, cb||noop); + } + function init(err, disk){ + if(err){ + opt.log('list', err); + setTimeout(function(){ r.parse(f, init) }, 1000); + return; + } + if(disk){ return drain(disk) } + if(!opt.store.list){ return drain(disk || dir || Radix()) } + // import directory. + opt.store.list(function(file){ + dir = dir || Radix(); + if(!file){ return drain(dir) } + r.find.add(file, noop); + }); + } + function drain(rad, tmp){ + dir = dir || rad; + dir.file = f; + tmp = Q; Q = null; + Gun.list.map(tmp, function(arg){ + r.find(arg[0], arg[1]); + }); + } + }()); + + var noop = function(){}, RAD, u; + Radisk.has[opt.file] = r; + return r; + } + + + + ;(function(){ + var _ = String.fromCharCode(31), u; + Radisk.encode = function(d, o, s){ s = s || _; + var t = s, tmp; + if(typeof d == 'string'){ + var i = d.indexOf(s); + while(i != -1){ t += s; i = d.indexOf(s, i+1) } + return t + '"' + d + s; + } else + if(d && d['#'] && (tmp = Gun.val.link.is(d))){ + return t + '#' + tmp + t; + } else + if(Gun.num.is(d)){ + return t + '+' + (d||0) + t; + } else + if(null === d){ + return t + ' ' + t; + } else + if(true === d){ + return t + '+' + t; + } else + if(false === d){ + return t + '-' + t; + }// else + //if(binary){} + } + Radisk.decode = function(t, o, s){ s = s || _; + var d = '', i = -1, n = 0, c, p; + if(s !== t[0]){ return } + while(s === t[++i]){ ++n } + p = t[c = n] || true; + while(--n >= 0){ i = t.indexOf(s, i+1) } + if(i == -1){ i = t.length } + d = t.slice(c+1, i); + if(o){ o.i = i+1 } + if('"' === p){ + return d; + } else + if('#' === p){ + return Gun.val.link.ify(d); + } else + if('+' === p){ + if(0 === d.length){ + return true; + } + return parseFloat(d); + } else + if(' ' === p){ + return null; + } else + if('-' === p){ + return false; + } + } + }()); + + if(typeof window !== "undefined"){ + var Gun = window.Gun; + var Radix = window.Radix; + window.Radisk = Radisk; + } else { + var Gun = require('../gun'); + var Radix = require('./radix'); + //var Radix = require('./radix2'); Radisk = require('./radisk2'); + try{ module.exports = Radisk }catch(e){} + } + + Radisk.Radix = Radix; + +}()); \ No newline at end of file diff --git a/lib/radix.js b/lib/radix.js index e338e3fb..ffd13c72 100644 --- a/lib/radix.js +++ b/lib/radix.js @@ -2,13 +2,13 @@ function Radix(){ var radix = function(key, val, t){ - key = ''+key; if(!t && u !== val){ - radix.last = (key < radix.last)? radix.last : key; + radix.last = (''+key < radix.last)? radix.last : ''+key; delete (radix.$||{})[_]; } t = t || radix.$ || (radix.$ = {}); if(!key && Object.keys(t).length){ return t } + key = ''+key; var i = 0, l = key.length-1, k = key[i], at, tmp; while(!(at = t[k]) && i < l){ k += key[++i]; @@ -22,19 +22,24 @@ if(kk){ if(u === val){ if(ii <= l){ return } - return (tmp || (tmp = {}))[s.slice(ii)] = r; + (tmp || (tmp = {}))[s.slice(ii)] = r; + //(tmp[_] = function $(){ $.sort = Object.keys(tmp).sort(); return $ }()); // get rid of this one, cause it is on read? + return r; } var __ = {}; __[s.slice(ii)] = r; ii = key.slice(ii); ('' === ii)? (__[''] = val) : ((__[ii] = {})[''] = val); + //(__[_] = function $(){ $.sort = Object.keys(__).sort(); return $ }()); t[kk] = __; delete t[s]; + //(t[_] = function $(){ $.sort = Object.keys(t).sort(); return $ }()); return true; } })){ if(u === val){ return; } (t[k] || (t[k] = {}))[''] = val; + //(t[_] = function $(){ $.sort = Object.keys(t).sort(); return $ }()); } if(u === val){ return tmp; @@ -43,8 +48,10 @@ if(i == l){ if(u === val){ return (u === (tmp = at['']))? at : tmp } at[''] = val; + //(at[_] = function $(){ $.sort = Object.keys(at).sort(); return $ }()); } else { if(u !== val){ delete at[_] } + //at && (at[_] = function $(){ $.sort = Object.keys(at).sort(); return $ }()); return radix(key.slice(++i), val, at || (at = {})); } } diff --git a/lib/store.js b/lib/store.js index 80c26c36..260fd77b 100644 --- a/lib/store.js +++ b/lib/store.js @@ -6,12 +6,22 @@ Gun.on('create', function(root){ var opt = root.opt, empty = {}, u; if(false === opt.radisk){ return } var Radisk = (Gun.window && Gun.window.Radisk) || require('./radisk'); + var Radiskip = (Gun.window && Gun.window.Radisk) || require('./radiskip'); var Radix = Radisk.Radix; var LOG = console.LOG, ST = 0; opt.store = opt.store || (!Gun.window && require('./rfs')(opt)); var rad = Radisk(opt), esc = String.fromCharCode(27); + var dare = Radiskip(opt); + root.on('put2', function(msg){ + this.to.next(msg); + var id = msg['#'], put = msg.put, soul = put['#'], key = put['.'], val = put[':'], state = put['>'], tmp; + dare(soul+key, {':': val, '>': state}, function(err, ok){ + console.log("SAVED", soul, key, val, id); + }); + }); + root.on('put', function(msg){ this.to.next(msg); var id = msg['#'] || Gun.text.random(3), track = !msg['@'], acks = track? 0 : u; // only ack non-acks. diff --git a/sea.js b/sea.js index 213fe57f..c653daf1 100644 --- a/sea.js +++ b/sea.js @@ -275,13 +275,13 @@ cb = salt; salt = u; } - salt = salt || shim.random(9); data = (typeof data == 'string')? data : JSON.stringify(data); if('sha' === (opt.name||'').toLowerCase().slice(0,3)){ var rsha = shim.Buffer.from(await sha(data, opt.name), 'binary').toString(opt.encode || 'base64') if(cb){ try{ cb(rsha) }catch(e){console.log(e)} } return rsha; } + salt = salt || shim.random(9); var key = await (shim.ossl || shim.subtle).importKey('raw', new shim.TextEncoder().encode(data), {name: opt.name || 'PBKDF2'}, false, ['deriveBits']); var work = await (shim.ossl || shim.subtle).deriveBits({ name: opt.name || 'PBKDF2', @@ -1090,8 +1090,8 @@ })(USE, './create'); ;USE(function(module){ - const SEA = USE('./sea') - const Gun = SEA.Gun; + var SEA = USE('./sea') + var Gun = SEA.Gun; // After we have a GUN extension to make user registration/login easy, we then need to handle everything else. // We do this with a GUN adapter, we first listen to when a gun instance is created (and when its options change) @@ -1101,6 +1101,7 @@ at.on('in', security, at); // now listen to all input data, acting as a firewall. at.on('out', signature, at); // and output listeners, to encrypt outgoing data. at.on('node', each, at); + at.on('put2', check, at); } this.to.next(at); // make sure to call the "next" middleware adapter. }); @@ -1149,6 +1150,102 @@ security.call(this, msg); } + var u; + function check(msg){ + var eve = this, at = eve.as, put = msg.put, soul = put['#'], key = put['.'], val = put[':'], state = put['>'], id = msg['#'], tmp; + //console.log("security check", msg); + var no = function(why){ at.on('in', {'@': id, err: why}) } + if('#' === soul){ // special case for content addressing immutable hashed data. + check.hash(eve, msg, val, key, soul, at, no); return; + } + if('~@' === soul){ // special case for shared system data, the list of aliases. + check.alias(eve, msg, val, key, soul, at, no); return; + } + if('~@' === soul.slice(0,2)){ // special case for shared system data, the list of public keys for an alias. + check.pubs(eve, msg, val, key, soul, at, no); return; + } + if('~' === soul.slice(0,1) && 2 === (tmp = soul.slice(1)).split('.').length){ // special case, account data for a public key. + check.pub(eve, msg, val, key, soul, at, no, (msg._||noop).user, tmp); return; + } + check.any(eve, msg, val, key, soul, at, no, (msg._||noop).user); return; + eve.to.next(msg); // not handled + } + check.hash = function(eve, msg, val, key, soul, at, no){ + SEA.work(val, null, function(data){ + if(data === key){ return eve.to.next(msg) } + no("Data hash not same as hash!"); + }, {name: 'SHA-256'}); + } + check.alias = function(eve, msg, val, key, soul, at, no){ // Example: {_:#~@, ~@alice: {#~@alice}} + if(!val){ return no("Data must exist!") } // data MUST exist + if('~@'+key === link_is(val)){ return eve.to.next(msg) } // in fact, it must be EXACTLY equal to itself + no("Alias not same!"); // if it isn't, reject. + }; + check.pubs = function(eve, msg, val, key, soul, at, no){ // Example: {_:#~@alice, ~asdf: {#~asdf}} + if(!val){ return no("Alias must exist!") } // data MUST exist + if(key === link_is(val)){ return eve.to.next(msg) } // and the ID must be EXACTLY equal to its property + no("Alias not same!"); // that way nobody can tamper with the list of public keys. + }; + check.pub = function(eve, msg, val, key, soul, at, no, user, pub){ var tmp; // Example: {_:#~asdf, hello:'world'~fdsa}} + if('pub' === key){ + if(val === pub){ return eve.to.next(msg) } // the account MUST match `pub` property that equals the ID of the public key. + return no("Account not same!"); + } + check['user'+soul+key] = 1; + if(Gun.is(msg.$) && user && user.is && pub === user.is.pub){ + SEA.sign(msg.put, (user._).sea, function(data){ var rel; + if(u === data){ return no(SEA.err || 'Signature fail.') } + if(rel = link_is(val)){ (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = 1 } + console.log("WHAT HAPPENS HERE?", data.m, SEA.opt.unpack(data.m), key, soul); + msg.put[':'] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); + //node[key] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); + eve.to.next(msg); + }, {check: msg.put, raw: 1}); + return; + } + SEA.verify(msg.put, pub, function(data){ var rel, tmp; + console.log("WHAT VERIFIES HERE?", data, SEA.opt.unpack(data, key), key, soul); + data = SEA.opt.unpack(data, key); + if(u === data){ return no("Unverified data.") } // make sure the signature matches the account it claims to be on. // reject any updates that are signed with a mismatched account. + if((rel = link_is(data)) && pub === SEA.opt.pub(rel)){ + (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = 1; + } + eve.to.next(msg); + }); + }; + check.any = function(eve, msg, val, key, soul, at, no, user){ var tmp, pub; + if(!(pub = SEA.opt.pub(soul))){ + if(at.opt.secure){ return no("Soul missing public key at '" + key + "'.") } + // TODO: Ask community if should auto-sign non user-graph data. + at.on('secure', function(msg){ this.off(); + if(!at.opt.secure){ return eve.to.next(msg) } + no("Data cannot be changed."); + }).on.on('secure', msg); + return; + } + // TODO: DEDUP WITH check.pub ??? + if(Gun.is(msg.$) && user && user.is && pub === user.is.pub){ + SEA.sign(mgs.put, (user._).sea, function(data){ + if(u === data){ return no('User signature fail.') } + console.log("WHAT HAPPENS HERE??", data.m, SEA.opt.unpack(data.m), key, soul); + msg.put[':'] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); + //node[key] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); + eve.to.next(msg); + }, {check: msg.put, raw: 1}); + return; + } + SEA.verify(msg.put, pub, function(data){ var rel; + console.log("WHAT VERIFIES HERE?", data, SEA.opt.unpack(data, key), key, soul); + data = SEA.opt.unpack(data, key); + if(u === data){ return no("Not owner on '" + key + "'.") } // thanks @rogowski ! + if((rel = link_is(data)) && pub === SEA.opt.pub(rel)){ + (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = 1; + } + eve.to.next(msg); + }); + } + var link_is = Gun.val.link.is; + // okay! The security function handles all the heavy lifting. // It needs to deal read and write of input and output of system data, account/public key data, and regular data. // This is broken down into some pretty clear edge cases, let's go over them: @@ -1174,6 +1271,11 @@ } } if(msg.put){ + /* + NOTICE: THIS IS OLD AND GETTING DEPRECATED. + ANY SECURITY CHANGES SHOULD HAPPEN ABOVE FIRST + THEN PORTED TO HERE. + */ // potentially parallel async operations!!! var check = {}, each = {}, u; each.node = function(node, soul){ @@ -1260,9 +1362,11 @@ return; }*/ check['any'+soul+key] = 1; + console.log(val, key, node, soul, '...', SEA.opt.prep(tmp = SEA.opt.parse(val), key, node, soul)); SEA.sign(SEA.opt.prep(tmp = SEA.opt.parse(val), key, node, soul), (user._).sea, function(data){ if(u === data){ return each.end({err: 'My signature fail.'}) } node[key] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); + console.log(key, node[key], '...', data); check['any'+soul+key] = 0; each.end({ok: 1}); }, {check: SEA.opt.pack(tmp, key, node, soul), raw: 1}); diff --git a/test/ptsd/radix.js b/test/ptsd/radix.js index 4e4d5f79..c0514b76 100644 --- a/test/ptsd/radix.js +++ b/test/ptsd/radix.js @@ -22,34 +22,62 @@ //window.radText = Radisk.encode(window.BigText); window.namez = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammamaria","Andy","Anselme","Ardeen","Armand","Ashelman","Aube","Averyl","Baker","Barger","Baten","Bee","Benia","Bernat","Bevers","Bittner","Bobbe","Bonny","Boyce","Breech","Brittaney","Bryn","Burkitt","Cadmann","Campagna","Carlee","Carver","Cavallaro","Chainey","Chaunce","Ching","Cianca","Claudina","Clyve","Colon","Cooke","Corrina","Crawley","Cullie","Dacy","Daniela","Daryn","Deedee","Denie","Devland","Dimitri","Dolphin","Dorinda","Dream","Dunham","Eachelle","Edina","Eisenstark","Elish","Elvis","Eng","Erland","Ethan","Evelyn","Fairman","Faus","Fenner","Fillander","Flip","Foskett","Fredette","Fullerton","Gamali","Gaspar","Gemina","Germana","Gilberto","Giuditta","Goer","Gotcher","Greenstein","Grosvenor","Guthrey","Haldane","Hankins","Harriette","Hayman","Heise","Hepsiba","Hewie","Hiroshi","Holtorf","Howlond","Hurless","Ieso","Ingold","Isidora","Jacoba","Janelle","Jaye","Jennee","Jillana","Johnson","Josy","Justinian","Kannan","Kast","Keeley","Kennett","Kho","Kiran","Knowles","Koser","Kroll","LaMori","Lanctot","Lasky","Laverna","Leff","Leonanie","Lewert","Lilybel","Lissak","Longerich","Lou","Ludeman","Lyman","Madai","Maia","Malvina","Marcy","Maris","Martens","Mathilda","Maye","McLain","Melamie","Meras","Micco","Millburn","Mittel","Montfort","Moth","Mutz","Nananne","Nazler","Nesta","Nicolina","Noellyn","Nuli","Ody","Olympie","Orlena","Other","Pain","Parry","Paynter","Pentheas","Pettifer","Phyllida","Plath","Posehn","Proulx","Quinlan","Raimes","Ras","Redmer","Renelle","Ricard","Rior","Rocky","Ron","Rosetta","Rubia","Ruttger","Salbu","Sandy","Saw","Scholz","Secor","September","Shanleigh","Shenan","Sholes","Sig","Sisely","Soble","Spanos","Stanwinn","Stevie","Stu","Suzanne","Tacy","Tanney","Tekla","Thackeray","Thomasin","Tilla","Tomas","Tracay","Tristis","Ty","Urana","Valdis","Vasta","Vezza","Vitoria","Wait","Warring","Weissmann","Whetstone","Williamson","Wittenburg","Wymore","Yoho","Zamir","Zimmermann"]; - window.radiz = window.radiz || Radix(); + window.radix = window.radix || Radix(); window.arr = []; var i = 1000; while(--i){ arr.push(Math.random()) } window.arrs = arr.slice(0).sort(); + window.ALLZ = window.ALLZ || {}; + window.namez.forEach(function(v,i){ ALLZ[v] = i }); }); /* TEMPORARY COPY OF RADIX UNIT TESTS TO BOOST SPEED */ /* THESE ARE PROBABLY STALE AND NEED TO BE COPIED FROM UNIT TESTS AGAIN */ + /*stool.add('map', function(){ + Gun.obj.map(ALLZ, function(v,i){ + v; + }); + }); + stool.add('for', function(){ + for(var k in ALLZ){ + ALLZ[k]; + } + }); + stool.add('for', function(){ + Object.keys(ALLZ).forEach(function(k){ + ALLZ[k]; + }) + }); + return;*/ stool.add('1', function(){ var rad = Radix(); rad('asdf.pub', 'yum'); rad('ablah', 'cool'); + rad('ab', {yes: 1}); rad('node/circle.bob', 'awesome'); - (rad('asdf.').pub[''] !== 'yum') && bad1; - (rad('nv/foo.bar') !== undefined) && bad2; + (JSON.stringify(rad('asdf.')) !== JSON.stringify({pub: {'': 'yum'}})) && bada; + (rad('nv/foo.bar') != undefined) && badb; + (JSON.stringify(rad('ab')) != JSON.stringify({yes: 1})) && badc + (JSON.stringify(rad()) != JSON.stringify({"a":{"sdf.pub":{"":"yum"},"b":{"lah":{"":"cool"},"":{"yes":1}}},"node/circle.bob":{"":"awesome"}})) && badd; }); stool.add('2', function(){ var all = {}; namez.forEach(function(v,i){ v = v.toLowerCase(); all[v] = v; - radiz(v, i) + ALLZ[v] = i; + radix(v, i) }); (Gun.obj.empty(all) === true) && bad3; - Radix.map(radiz, function(v,k){ + Radix.map(radix, function(v,k){ delete all[k]; }); (Gun.obj.empty(all) !== true) && bad4; }); + stool.add('fast?', function(){ + ALLZ['rubia']; + }); + stool.add('fastest?', function(){ + namez.indexOf('Rubia'); + }); stool.add('3', function(){ var all = {}; namez.forEach(function(v,i){ @@ -58,7 +86,7 @@ //rad(v, i) }); (Gun.obj.empty(all) === true) && bad5; - Radix.map(radiz, function(v,k){ + Radix.map(radix, function(v,k){ delete all[k]; }); (Gun.obj.empty(all) !== true) && bad6; @@ -73,7 +101,7 @@ //rad(v, i) }); (Gun.obj.empty(all) === true) && bad7; - Radix.map(radiz, function(v,k, a,b){ + Radix.map(radix, function(v,k, a,b){ //if(!all[k]){ throw "out of range!" } delete all[k]; }, {start: start, end: end}); @@ -89,12 +117,19 @@ //rad(v, i) }); (Gun.obj.empty(all) === true) && bad9; - Radix.map(radiz, function(v,k, a,b){ + Radix.map(radix, function(v,k, a,b){ //if(!all[k]){ throw "out of range!" } delete all[k]; }, {start: start, end: end}); (Gun.obj.empty(all) !== true) && bad10; }); + stool.add('reverse item', function(){ + Radix.map(radix, function(v,k, a,b){ + (k !== 'ieso') && badri; + (v !== 96) && badri2; + return true; + }, {reverse: 1, end: 'iesogon'}); + }); stool.add('6', function(){ var r = Radix(), tmp; r('alice', 1);r('bob', 2);r('carl', 3);r('carlo',4); diff --git a/test/rad/rad.js b/test/rad/rad.js index 28ccda24..c367def3 100644 --- a/test/rad/rad.js +++ b/test/rad/rad.js @@ -50,10 +50,13 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam var rad = Radix(); rad('asdf.pub', 'yum'); rad('ablah', 'cool'); + rad('ab', {yes: 1}); rad('node/circle.bob', 'awesome'); - expect(rad('asdf.')).to.be.eql({pub: {'': 'yum'}}); + expect(Gun.obj.copy(rad('asdf.'))).to.be.eql({pub: {'': 'yum'}}); expect(rad('nv/foo.bar')).to.be(undefined); + expect(rad('ab')).to.eql({yes: 1}); + expect(Gun.obj.copy(rad())).to.be.eql({"a":{"sdf.pub":{"":"yum"},"b":{"lah":{"":"cool"},"":{"yes":1}}},"node/circle.bob":{"":"awesome"}}); }); it('radix write read', function(done){ @@ -121,6 +124,16 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam expect(Gun.obj.empty(all)).to.be.ok(); done(); }); + + it('radix reverse item', function(done){ + var opt = {reverse: 1, end: 'iesogon'}; + Radix.map(radix, function(v,k, a,b){ + expect(k).to.be('ieso'); + expect(v).to.be(96); + return true; + }, opt); + done(); + }); it('radix reverse', function(done){ var r = Radix(), tmp; From 16f911e126d69cecc2d98a7fbdea2bd1bd9b4c47 Mon Sep 17 00:00:00 2001 From: bluelovers Date: Thu, 6 Feb 2020 20:54:42 +0800 Subject: [PATCH 35/87] fix: bug when import 'lib/then' --- lib/then.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/then.js b/lib/then.js index 731454a8..85d32116 100644 --- a/lib/then.js +++ b/lib/then.js @@ -11,11 +11,12 @@ Gun.chain.promise = function(cb) { }; // Returns a promise for the data, key of the gun call -Gun.chain.then = function() { +Gun.chain.then = function(cb) { var gun = this; - return (new Promise((res, rej)=>{ + var p = (new Promise((res, rej)=>{ gun.once(function (data, key) { res(data, key); //call resolve when data is returned }) })) + return cb ? p.then(cb) : p; }; From 273f7fce8d59ca50981d7921d1af47a4b7738993 Mon Sep 17 00:00:00 2001 From: bluelovers Date: Thu, 6 Feb 2020 21:08:38 +0800 Subject: [PATCH 36/87] chore: update type Gun.log --- types/static.d.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/types/static.d.ts b/types/static.d.ts index 939647fe..8cf7b9bd 100644 --- a/types/static.d.ts +++ b/types/static.d.ts @@ -13,9 +13,14 @@ export interface IGunStatic { */ (options?: string | string[] | IGunConstructorOptions): IGunChainReference; new (options?: string | string[] | IGunConstructorOptions): IGunChainReference; - node: IGunStaticNode; + readonly node: IGunStaticNode; /** @see https://gun.eco/docs/SEA */ - SEA: IGunStaticSEA; - version: string; + readonly SEA: IGunStaticSEA; + readonly version: string; readonly chain: IGunChainReference; + readonly log: { + (...argv: any[]): void; + once(...argv: any[]): void; + off: boolean; + }; } From c59e0e95f92779ce6bb3aab823d318bc16b20c33 Mon Sep 17 00:00:00 2001 From: bluelovers Date: Thu, 6 Feb 2020 21:40:07 +0800 Subject: [PATCH 37/87] fix: type `CryptoKeyPair` and rename to `IGunCryptoKeyPair` --- types/chain.d.ts | 6 +++--- types/types.d.ts | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/types/chain.d.ts b/types/chain.d.ts index 9a625473..b2b45593 100644 --- a/types/chain.d.ts +++ b/types/chain.d.ts @@ -1,4 +1,4 @@ -import { AlwaysDisallowedType, DisallowPrimitives, DisallowArray, AckCallback, ArrayOf, ArrayAsRecord, Saveable } from './types'; +import { AlwaysDisallowedType, DisallowPrimitives, DisallowArray, AckCallback, ArrayOf, ArrayAsRecord, Saveable, IGunCryptoKeyPair } from './types'; import { IGunConstructorOptions } from './options'; import { ITSResolvable } from 'ts-type'; export interface IGunChainReference, ReferenceKey = any, IsTop extends 'pre_root' | 'root' | false = false> { @@ -217,7 +217,7 @@ export interface IGunChainReference, ReferenceKey epub: string; pub: string; }; - sea: CryptoKeyPair; + sea: IGunCryptoKeyPair; soul: string; } | { err: string; @@ -225,7 +225,7 @@ export interface IGunChainReference, ReferenceKey /** * Returns the key pair in the form of an object as below. */ - pair(): CryptoKeyPair; + pair(): IGunCryptoKeyPair; /** * Log out currently authenticated user. Parameters are unused in the current implementation. * @param opt unused in current implementation. diff --git a/types/types.d.ts b/types/types.d.ts index a7e78399..fbe24c08 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -21,4 +21,17 @@ export declare type AckCallback = (ack: { err: undefined; ok: string; }) => void; -export declare type CryptoKeyPair = Record<'pub' | 'priv' | 'epub' | 'epriv', string>; +export declare type IGunCryptoKeyPair = Record<'pub' | 'priv' | 'epub' | 'epriv', string>; +export interface IGunRecordNodeRawBase { + '#': string; +} +export interface IGunRecordNodeRawExtra extends IGunRecordNodeRawBase { + '>': Record; +} +export interface IGunRecordNodeRaw { + '_': IGunRecordNodeRawExtra; +} +export declare type IGunRecordNode = { + [K in keyof DataType]: IGunRecordNodeRawBase; +} & IGunRecordNodeRaw; +export declare type IGunRecordData = DataType & IGunRecordNodeRaw; From 7cf2d42dcd8dc1bfe9ed485c42c9476944c178c0 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Thu, 6 Feb 2020 14:05:27 -0800 Subject: [PATCH 38/87] yet another day. --- gun.js | 55 ++++++------ lib/radiskip.js | 199 +++++++++++++++++++++++++++++------------- lib/store.js | 5 +- sea.js | 4 +- test/rad/bench.js | 96 ++++++++++++++++++++ test/rad/browser.html | 86 +----------------- 6 files changed, 270 insertions(+), 175 deletions(-) create mode 100644 test/rad/bench.js diff --git a/gun.js b/gun.js index 7831f053..a99c137e 100644 --- a/gun.js +++ b/gun.js @@ -622,9 +622,9 @@ opt = opt || {max: 1000, age: /*1000 * 9};//*/ 1000 * 9 * 3}; dup.check = function(id){ if(!s[id]){ return false } - return dup.track(id); + return dt(id); } - dup.track = function(id){ + var dt = dup.track = function(id){ var it = s[id] || (s[id] = {}); it.was = +new Date; if(!dup.to){ dup.to = setTimeout(dup.drop, opt.age + 9) } @@ -720,7 +720,7 @@ var eve = this, as = eve.as, at = as.at || as, gun = at.$, dup = at.dup, tmp; if(!(tmp = msg['#'])){ tmp = msg['#'] = text_rand(9) } if(dup.check(tmp)){ return } dup.track(tmp); - tmp = msg._; msg._ = ('function' == typeof msg._)? msg._ : function(){}; + tmp = msg._; msg._ = ('function' == typeof tmp)? tmp : function(){}; if(msg.get){ Gun.on.get(msg, gun) } if(msg.put){ PUT(msg, gun) } eve.to.next(msg); @@ -730,22 +730,22 @@ ;(function(){ Gun.on.put2 = function(msg, gun){ var ctx = msg._, root = ctx.root = gun._, id = msg['#']; - var ack = ctx.ack = function(put){ put = put || {}; - if(ack.err = ack.err || (put||{}).err){ + var ack = ctx.ack = function(soul, key, val, state){ + if(ack.err){ if(ack.s){ root.on('in', {'@': id, err: Gun.log(ack.err)}) } return ack.s = u; } - var soul = put['#'], key = put['.'], val = put[':'], state = put['>'], tmp; - if((tmp = ack.s||{})[soul+key]){ - delete tmp[soul+key]; - root.on('put2', {put: put}); + var acks, tmp; + if((acks = ack.s||'')[tmp = soul+key]){ + delete acks[tmp]; + root.on('put2', {put: {'#': soul, '.': key, ':': val, '>': state}}); } - if(!obj_empty(ack.s)){ return } // keep waiting + if(!obj_empty(acks)){ return } // keep waiting console.log("I'm all done!!!"); } ack.err = obj_map(msg.put, nodes, msg); msg = ctx = u; - if(ack.err){ return ack() } + if(ack.err){ ack(); return } } function nodes(node, soul){ if(!node){ return ERR+cut(soul)+"no node." } @@ -759,13 +759,13 @@ } function souls(val, key){ if(node_ === key){ return } - var ctx = this._, node = ctx.node, soul = ctx.soul, state = ctx.states[key]; + var ctx = this._, soul = ctx.soul, state = ctx.states[key], tmp; if(u === state){ return ERR+cut(key)+"on"+cut(soul)+"no state." } if(!val_is(val)){ return ERR+cut(key)+"on"+cut(soul)+"bad "+(typeof val)+cut(val) } - ham(ctx.root.graph, soul, key, val, state, ctx.ack); // TODO: HANDLE CALLBACK WHERE ALL DAY IS HISTORIC? + ((tmp = ctx.ack).s || (tmp.s = {}))[soul+key] = 1; + ham(ctx.root.graph, soul, key, val, state, tmp); // TODO: HANDLE CALLBACK WHERE ALL DAY IS HISTORIC? } function ham(graph, soul, key, val, state, ack){ - (ack.s || (ack.s = {}))[soul+key] = 1; var vertex = graph[soul] || empty, was = state_is(vertex, key, 1), known = vertex[key]; var machine = State(), is = HAM(machine, state, was, val, known), u; if(!is.incoming){ @@ -776,10 +776,10 @@ }, to > MD? MD : to); // setTimeout Max Defer 32bit :( return; } - if(ack){ ack({'#': soul, '.': key}) } + if(ack){ ack(soul, key) } return; } - if(ack){ ack({'#': soul, '.': key, ':': val, '>': state}) } + if(ack){ ack(soul, key, val, state) } } var cut = function(s){ return " '"+(''+s).slice(0,9)+"...' " } var ERR = "Error: Invalid graph!"; @@ -2045,7 +2045,7 @@ opt.gap = opt.gap || opt.wait || 0; opt.pack = opt.pack || (opt.memory? (opt.memory * 1000 * 1000) : 1399000000) * 0.3; // max_old_space_size defaults to 1400 MB. - var dup = root.dup; + var dup = root.dup, dup_check = dup.check, dup_track = dup.track; // TODO: somewhere in here caused a out-of-memory crash! How? It is inbound! mesh.hear = function(raw, peer){ @@ -2054,29 +2054,27 @@ if(opt.pack <= raw.length){ return mesh.say({dam: '!', err: "Message too big!"}, peer) } if('{' != raw[2]){ mesh.hear.d += raw.length||0; ++mesh.hear.c; } // STATS! // ugh, stupid double JSON encoding if('[' === tmp){ - try{msg = JSON.parse(raw);}catch(e){opt.log('DAM JSON parse error', e)} + try{msg = JSON.parse(raw)}catch(e){opt.log('DAM JSON parse error', e)} raw = ''; if(!msg){ return } LOG && opt.log(+new Date, msg.length, '# on hear batch'); (function go(){ // stats on single msg is 99% spike of batch stats. var m, i = 0, c = 100; // hardcoded for now? - while(c-- && (m = msg[i++])){ - mesh.hear(m, peer); - } - msg = msg.slice(i); + while(c-- && (m = msg[i++])){ mesh.hear(m, peer) } + msg = msg.slice(i); // slicing after is faster than shifting during. // TODO: consider triggering peer flush to response times speedier! if(!msg.length){ return } puff(go, 1); }()); return; } - if('{' === tmp || (Type.obj.is(raw) && (msg = raw))){ + if('{' === tmp || (obj_is(raw) && (msg = raw))){ try{msg = msg || JSON.parse(raw); }catch(e){return opt.log('DAM JSON parse error', e)} if(!msg){ return } if(msg.DBG_s){ opt.log(+new Date - msg.DBG_s, 'to hear', msg['#']) } if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } - if(dup.check(id)){ return } + if(dup_check(id)){ return } /*if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } if(hash && (tmp = msg['@'] || (msg.get && id))){ // Reduces backward daisy in case varying hashes at different daisy depths are the same. if(dup.check(tmp+hash)){ return } @@ -2085,17 +2083,17 @@ if(tmp = msg['><']){ (msg._).to = Type.obj.map(tmp.split(','), tomap) } */ // TOOD: COME BACK TO THIS LATER!!! IMPORTANT MESH STUFF!! (msg._ = function(){}).via = peer; - if(msg.dam){ - if(tmp = mesh.hear[msg.dam]){ + if(tmp = msg.dam){ + if(tmp = mesh.hear[tmp]){ tmp(msg, peer, root); } - dup.track(id); + dup_track(id); return; } var S, ST; LOG && (S = +new Date); console.STAT = {}; //root.on('in', msg); root.on('in2', msg); - dup.track(id); + dup_track(id); if(LOG && !msg.nts && (ST = +new Date - S) > 9){ opt.log(S, ST, 'msg', msg['#'], JSON.stringify(console.STAT)); if(ST > 500){ try{ require('./lib/email').send({text: ""+ST+"ms "+JSON.stringify(msg)+" | "+JSON.stringify(console.STAT), from: "mark@gun.eco", to: "mark@gun.eco", subject: "GUN MSG"}, noop); }catch(e){} } } // this is ONLY turned on if ENV CONFIGS have email/password to send out from. return; } @@ -2316,6 +2314,7 @@ var empty = {}, ok = true, u; var LOG = console.LOG; + var obj_is = Type.obj.is, obj_map = Type.obj.map; try{ module.exports = Mesh }catch(e){} diff --git a/lib/radiskip.js b/lib/radiskip.js index 70c86c7b..90ec0a47 100644 --- a/lib/radiskip.js +++ b/lib/radiskip.js @@ -44,45 +44,54 @@ if('function' === typeof data){ var o = cb || {}; cb = val; + r.read(key, cb); return; } //var tmp = (tmp = r.batch = r.batch || {})[key] = tmp[key] || {}; //var tmp = (tmp = r.batch = r.batch || {})[key] = data; + //console.only(1, key, data); r.save(key, data, cb); } r.save = function(key, data, cb){ var s = {key: key}; s.find = function(file){ var tmp; - s.file = file = file || opt.code.from; - if(tmp = r.disk[file]){ return s.mix(null, tmp) } + //console.only(4, 'find', file); + s.file = file || (file = opt.code.from); + if(tmp = r.disk[file]){ s.mix(null, tmp); return } r.parse(file, s.mix); } s.mix = function(err, disk){ - if(err){ return cb(err) } - s.file = (disk||noop).file || s.file; - ((disk = r.disk[s.file] || disk)||noop).file = s.file; - if(!disk && s.file !== opt.code.from){ // corrupt file? - r.find.bad(s.file); // remove from dir list + if(err){ cb(err); return } + var file = s.file = (disk||'').file || s.file; + if(!disk && file !== opt.code.from){ // corrupt file? + r.find.bad(file); // remove from dir list r.save(key, data, cb); // try again return; } - (r.disk[s.file] = disk = disk || Radix()).file = s.file; + (disk = r.disk[file] || (r.disk[file] = disk || Radix())).file || (disk.file = file); if(opt.compare){ - data = opt.compare(disk(key), data, key, s.file); - if(u === data){ return cb(err, -1) } + data = opt.compare(disk(key), data, key, file); + if(u === data){ cb(err, -1); return } } - // check if still in same r.find? (s.disk = disk)(key, data); - if(disk.Q){ return disk.Q.push(cb) } disk.Q = [cb]; + //console.only(7, key, data, disk.$, disk.Q); + if(disk.Q){ disk.Q.push(cb); return } disk.Q = [cb]; + //console.only(6, key, data, disk.$); disk.to = setTimeout(s.write, opt.until); } s.write = function(){ - var q = s.disk.Q; - delete s.disk.Q; - delete r.disk[s.file]; - r.write(s.file, s.disk, function(err, ok){ - Gun.obj.map(q, function(ack){ ack(err, ok) }); - }); + var file = s.file, disk = s.disk; + s.q = disk.Q; + delete disk.Q; + delete r.disk[file]; + //console.only(8, s.file, q.length); + r.write(file, disk, s.ack); + } + s.ack = function(err, ok){ + var q = s.q || [], i = 0, ack; + //var S = +new Date; + while(ack = q[i++]){ ack(err, ok) } + //console.log('acks:', +new Date - S, s.file, q.length); } r.find(key, s.find); } @@ -94,29 +103,31 @@ Therefore it is unavoidable that a read will have to happen, the question is just how long you delay it. */ + var RWC = 0; r.write = function(file, rad, cb, o){ - if(!rad){ return cb('No radix!') } + if(!rad){ cb('No radix!'); return } o = ('object' == typeof o)? o : {force: o}; var f = function Fractal(){}, a, b; f.text = ''; - f.file = file = rad.file = rad.file || file; - if(!file){ return cb('What file?') } + f.file = file = rad.file || (rad.file = file); + if(!file){ cb('What file?'); return } f.write = function(){ var S; LOG && (S = +new Date); + var text = f.text; r.disk[file = rad.file || f.file || file] = rad; - r.find.add(file, function(err){ - if(err){ return cb(err) } - opt.store.put(ename(file), f.text, function(err, ok){ - LOG && opt.log(S, ST = +new Date - S, "wrote disk", JSON.stringify(file)); + r.find.add(file, function add(err){ + if(err){ cb(err); return } + opt.store.put(ename(file), text, function safe(err, ok){ + LOG && opt.log(S, ST = +new Date - S, "wrote disk", JSON.stringify(file), ++RWC, 'total all writes.'); cb(err, ok); - delete r.disk[file]; + if(!rad.Q){ delete r.disk[file] } // VERY IMPORTANT! Clean up memory, but not if there is already queued writes on it! }); }); } f.split = function(){ f.text = ''; if(!f.count){ f.count = 0; - Radix.map(rad, function(){ f.count++ }); // TODO: Perf? Any faster way to get total length? + Radix.map(rad, function count(){ f.count++ }); // TODO: Perf? Any faster way to get total length? } f.limit = Math.ceil(f.count/2); f.count = 0; @@ -137,8 +148,8 @@ f.hub(key, val); } f.both = function(err, ok){ - if(b){ return cb(err || b) } - if(a){ return cb(err, ok) } + if(b){ cb(err || b); return } + if(a){ cb(err, ok); return } a = true; b = err; } @@ -152,7 +163,7 @@ } f.text += enc; } - if(opt.jsonify){ return r.write.jsonify(f, rad, cb, o) } // temporary testing idea + if(opt.jsonify){ r.write.jsonify(f, rad, cb, o); return } // temporary testing idea if(!Radix.map(rad, f.each, true)){ f.write() } } @@ -160,12 +171,9 @@ var raw; var S; LOG && (S = +new Date); try{raw = JSON.stringify(rad.$); - }catch(e){ return cb("Cannot radisk!") } + }catch(e){ cb("Cannot radisk!"); return } LOG && opt.log(S, +new Date - S, "rad stringified JSON"); - if(opt.chunk < raw.length && !o.force){ - return f.split(); - //if(Radix.map(rad, f.each, true)){ return } - } + if(opt.chunk < raw.length && !o.force){ return f.split() } f.text = raw; f.write(); } @@ -175,9 +183,7 @@ if(u === o.start && u === o.end){ return tree } if(atomic(tree)){ return tree } var sub = Radix(); - Radix.map(tree, function(v,k){ // ONLY PLACE THAT TAKES TREE, maybe reduce API for better perf? - sub(k,v); - }, o); + Radix.map(tree, function(v,k){ sub(k,v) }, o); // ONLY PLACE THAT TAKES TREE, maybe reduce API for better perf? return sub(''); } @@ -243,7 +249,7 @@ ){ o.more = u; as.ack(g.err, data, o); - return + return; } if(u !== data){ as.ack(g.err, data, o); // more might be coming! @@ -270,12 +276,12 @@ if(good){ return } var id = Gun.text.random(3); r.save(disk, function ack(err, ok){ - if(err){ return r.save(disk, ack) } // ad infinitum??? + if(err){ r.save(disk, ack); return } // ad infinitum??? console.log("MISLOCATED DATA CORRECTED", id); }); } /*g.check2 = function(err, disk, info){ - if(err || !disk){ return g.it(err, disk, info) } + if(err || !disk){ g.it(err, disk, info); return } var good = true; Radix.map(disk, function(val, key){ // assume in memory for now, since both write/read already call r.find which will init it. @@ -287,10 +293,10 @@ go.end = key; r.list(go); }); - if(good){ return g.it(err, disk, info) } + if(good){ g.it(err, disk, info); return } var id = Gun.text.random(3); console.log("MISLOCATED DATA", id); r.save(disk, function ack(err, ok){ - if(err){ return r.save(disk, ack) } // ad infinitum??? + if(err){ r.save(disk, ack); return } // ad infinitum??? console.log("MISLOCATED CORRECTED", id); r.read(key, cb, o); }); @@ -299,6 +305,69 @@ LOG && (S = +new Date); r.find(key, g.lex); } + + r.read = function(key, cb, o){ + var g = {key: key}; + g.find = function(file){ var tmp; + g.file = file || (file = opt.code.from); // this may not be true for reads? Hit "end of dir"? + if(tmp = r.disk[file]){ g.check(null, tmp); return } + r.parse(file, g.check); + } + g.get = function(err, disk, info){ + if(err){ cb(err); return } + var file = g.file = (disk||'').file || g.file; + if(!disk && file !== opt.code.from){ // corrupt file? + r.find.bad(file); // remove from dir list + r.save(key, cb); // try again + return; + } + disk = r.disk[file] || (r.disk[file] = disk); + if(!disk){ cb(null); return } + disk.file || (disk.file = file); + // ---------------------------- + var data = disk(key); + if(u !== data){ cb(null, data); return } + // ---------------------------- + return; + var S; LOG && (S = +new Date); + var rad = disk || noop, data = r.range(rad(key), o), last = rad.last || Radix.map(rad, rev, revo); + LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, "rad range loaded"); + o.parsed = (o.parsed || 0) + (info.parsed||0); + o.chunks = (o.chunks || 0) + 1; + o.more = true; + if((!as.file) // if no more places to look + || (!o.span && last === key) // if our key exactly matches the very last atomic record + || (!o.span && last && last > key && 0 != last.indexOf(key)) // 'zach' may be lexically larger than 'za', but there still might be more, like 'zane' in the 'za' prefix bucket so do not end here. + ){ + o.more = u; + as.ack(g.err, data, o); + return; + } + if(u !== data){ + as.ack(g.err, data, o); // more might be coming! + if(o.parsed >= o.limit){ return } // even if more, we've hit our limit, asking peer will need to make a new ask with a new starting point. + } + o.next = as.file; + r.read(key, as.ack, o); + } + r.find(key, g.find); + g.check = function(err, disk, info){ + g.get(err, disk, info); + (info || (info = {})).file || (info.file = g.file); + Radix.map(disk, function(val, key){ + // assume in memory for now, since both write/read already call r.find which will init it. + r.find(key, function(file){ + if(file === info.file){ return } + var id = Gun.text.random(3); + console.log("MISLOCATED DATA", id, key, info.file, file); + r.save(key, val, function ack(err, ok){ + if(err){ r.save(key, val, ack); return } // ad infinitum??? + console.log("MISLOCATED DATA CORRECTED", id); + }); + }) + }); + } + } function rev(a,b){ return b } var revo = {reverse: true}; }()); @@ -311,15 +380,17 @@ with how much performance and scale we can get out of only one. Then we can work on the harder problem of being multi-process. */ + var RPC = 0; var Q = {}, s = String.fromCharCode(31); r.parse = function(file, cb, raw){ var q; - if(q = Q[file]){ return q.push(cb) } q = Q[file] = [cb]; + if(q = Q[file]){ q.push(cb); return } q = Q[file] = [cb]; var p = function Parse(){}, info = {file: file}; (p.disk = Radix()).file = file; p.read = function(err, data){ var tmp; - LOG && opt.log(S, +new Date - S, 'read disk', JSON.stringify(file)); + LOG && opt.log(S, +new Date - S, 'read disk', JSON.stringify(file), ++RPC, 'total all parses.'); delete Q[file]; - if((p.err = err) || (p.not = !data)){ return map(q, p.ack) } + //console.only(5, 'parse', file, data, q.length); + if((p.err = err) || (p.not = !data)){ map(q, p.ack); return } if('string' !== typeof data){ try{ if(opt.pack <= data.length){ @@ -328,7 +399,7 @@ data = data.toString(); // If it crashes, it crashes here. How!?? We check size first! } }catch(e){ p.err = e } - if(p.err){ return map(q, p.ack) } + if(p.err){ map(q, p.ack); return } } info.parsed = data.length; LOG && (S = +new Date); @@ -342,14 +413,18 @@ }catch(e){ tmp = e } if('{' === data[0]){ p.err = tmp || "JSON error!"; - return map(q, p.ack); + map(q, p.ack); + return; } } - return p.radec(err, data); + p.radec(err, data); } p.ack = function(cb){ if(!cb){ return } - if(p.err || p.not){ return cb(p.err, u, info) } + if(p.err || p.not){ + cb(p.err, u, info); + return; + } cb(u, p.disk, info); } p.radec = function(err, data){ @@ -357,7 +432,8 @@ var tmp = p.split(data), pre = [], i, k, v; if(!tmp || 0 !== tmp[1]){ p.err = "File '"+file+"' does not have root radix! "; - return map(q, p.ack); + map(q, p.ack); + return; } while(tmp){ k = v = u; @@ -400,8 +476,10 @@ var dir, f = String.fromCharCode(28), Q; r.find = function(key, cb){ if(!dir){ - if(Q){ return Q.push([key, cb]) } Q = [[key, cb]]; - return r.parse(f, init); + if(Q){ Q.push([key, cb]); return } Q = [[key, cb]]; + //console.only(2, 'find', key); + r.parse(f, init); + return; } Radix.map(dir, function(val, key){ if(!val){ return } @@ -410,11 +488,11 @@ } r.find.add = function(file, cb){ var has = dir(file); - if(has || file === f){ return cb(u, 1) } + if(has || file === f){ cb(u, 1); return } dir(file, 1); cb.found = (cb.found || 0) + 1; r.write(f, dir, function(err, ok){ - if(err){ return cb(err) } + if(err){ cb(err); return } cb.found = (cb.found || 0) - 1; if(0 !== cb.found){ return } cb(u, 1); @@ -430,12 +508,13 @@ setTimeout(function(){ r.parse(f, init) }, 1000); return; } - if(disk){ return drain(disk) } - if(!opt.store.list){ return drain(disk || dir || Radix()) } + if(disk){ drain(disk); return } + //console.only(3, 'init', err, disk); + dir = dir || disk || Radix(); + if(!opt.store.list){ drain(dir); return } // import directory. opt.store.list(function(file){ - dir = dir || Radix(); - if(!file){ return drain(dir) } + if(!file){ drain(dir); return } r.find.add(file, noop); }); } @@ -454,8 +533,6 @@ return r; } - - ;(function(){ var _ = String.fromCharCode(31), u; Radisk.encode = function(d, o, s){ s = s || _; diff --git a/lib/store.js b/lib/store.js index 260fd77b..77d19468 100644 --- a/lib/store.js +++ b/lib/store.js @@ -18,7 +18,7 @@ Gun.on('create', function(root){ this.to.next(msg); var id = msg['#'], put = msg.put, soul = put['#'], key = put['.'], val = put[':'], state = put['>'], tmp; dare(soul+key, {':': val, '>': state}, function(err, ok){ - console.log("SAVED", soul, key, val, id); + console.log("STORE PAT:", soul, key, val, id, err, ok); }); }); @@ -100,6 +100,9 @@ Gun.on('create', function(root){ if(tmp && tmp.rad){ return } } var S = (+new Date), C = 0; // STATS! + dare(key, function(err, data, o){ + console.log("STORE GOT:", err, data, o); + }, o); rad(key||'', function(err, data, o){ try{opt.store.stats.get.time[statg % 50] = (+new Date) - S; ++statg; opt.store.stats.get.count++; diff --git a/sea.js b/sea.js index c653daf1..bd8dbd9c 100644 --- a/sea.js +++ b/sea.js @@ -1165,9 +1165,9 @@ check.pubs(eve, msg, val, key, soul, at, no); return; } if('~' === soul.slice(0,1) && 2 === (tmp = soul.slice(1)).split('.').length){ // special case, account data for a public key. - check.pub(eve, msg, val, key, soul, at, no, (msg._||noop).user, tmp); return; + check.pub(eve, msg, val, key, soul, at, no, (msg._||'').user, tmp); return; } - check.any(eve, msg, val, key, soul, at, no, (msg._||noop).user); return; + check.any(eve, msg, val, key, soul, at, no, (msg._||'').user); return; eve.to.next(msg); // not handled } check.hash = function(eve, msg, val, key, soul, at, no){ diff --git a/test/rad/bench.js b/test/rad/bench.js new file mode 100644 index 00000000..d9c00b6e --- /dev/null +++ b/test/rad/bench.js @@ -0,0 +1,96 @@ +var Gun = (typeof window !== "undefined")? window.Gun : require('../../../gun/gun'); + +var Radisk = (Gun.window && window.Radisk) || require('../../../gun/lib/radiskip'); +Gun.TESTING = true; +try{localStorage.clear()}catch(e){} +try{indexedDB.deleteDatabase('radatatest');}catch(e){} +try{indexedDB.deleteDatabase('radata');}catch(e){} + +var opt = {localStorage: false}; +//opt.chunk = 1024; +opt.store = (Gun.window && window.RindexedDB(opt)) || require('../../../gun/lib/rfs')(opt) +var rad = Radisk(opt); +var gun = Gun(opt); + +Gun.window && (wait.onchange = function(){ spam.wait = this.value }) +Gun.window && (burst.onchange = function(){ spam.burst = this.value }) +//setTimeout(spam, 1); +function spam(){ + //spam.max = 100000; spam.left = spam.max; spam.wait = 1; spam.burst = 250; spam.c = 0; spam.s = (+new Date); + //spam.max = 1000000; spam.left = spam.max; spam.wait = 0; spam.burst = 100; spam.c = 0; spam.s = (+new Date); + //spam.max = 300000; spam.left = spam.max; spam.wait = 1; spam.burst = 5; spam.c = 0; spam.s = (+new Date); + spam.max = 100000; spam.left = spam.max; spam.wait = 0; spam.burst = 2; spam.c = 0; spam.s = (+new Date); + //spam.max = 100000; spam.left = spam.max; spam.wait = 20; spam.burst = 2; spam.c = 0; spam.s = (+new Date); + //spam.max = 100; spam.left = spam.max; spam.wait = 1; spam.burst = 1; spam.c = 0; spam.s = (+new Date); + var S = +new Date, slow = 0; console.only.i = 1; + var to = setInterval(function(){ var b = spam.burst; + if(spam.c >= spam.max){ clearTimeout(to); return; } + //console.log('spam', +new Date - S, spam.c); S = +new Date; + if(!b){ b = burst = 1 } + while(b--){ go(++spam.c) } + function go(i){ var d = 0, s = +new Date; + i = Math.random().toString(32).slice(2); + //console.log('go', spam.c, i); + //setTimeout(function(){ var ack = {err: 0, ok: 1}; + //loc.put(i, {test: i}, function(err, ok){ var ack = {err: err, ok: ok}; + //ind.put(i, {test: i}, function(err, ok){ var ack = {err: err, ok: ok}; + rad(i, {test: i}, function(err, ok){ var ack = {err: err, ok: ok}; + //var ref = gun.get(i).put({test: i}, function(ack){ + var t = (+new Date - s)/1000; if(1 < t){ ++slow; } + if(ack.err){ console.log(ack); } + if(d++){ return } + if(--spam.left){ return } + spam.end = (+new Date) - spam.s; + console.log('DONE!\n', spam.max, 'in', spam.end/1000, 'seconds\n', Math.round(spam.max / (spam.end/1000)), 'per second. Slow:' + slow); + Gun.window && (document.body.style.backgroundColor = 'lime'); + }); + } + },spam.wait); + setInterval(function(){ + if(spam.end === true){ return } + if(spam.end){ spam.end = true } + var t = (+new Date) - spam.s, tmp, sec; + var status = 'saved\n'+ (tmp = (spam.max - spam.left)) +' in '+ (sec = (t/1000)) +' seconds\n'+ Math.round(tmp / sec) +' per second'; + (Gun.window && (debugs.innerText = status)) || console.log(status.replace(/\n/ig,' ')); + }, 500); +} +!Gun.window && setTimeout(spam,1); + +;(function(){ +if(!Gun.window){ return } +;(function(){ +var f = 'index'; +indexedDB.deleteDatabase(f); +var o = indexedDB.open(f, 1), ind = {}, db; +o.onupgradeneeded = function(eve){ (eve.target.result).createObjectStore(f) } +o.onsuccess = function(){ db = o.result } +o.onerror = function(eve){ console.log(eve||1); } +ind.put = function(key, data, cb){ + if(!db){ setTimeout(function(){ ind.put(key, data, cb) },9); return } + var tx = db.transaction([f], 'readwrite'); + var obj = tx.objectStore(f); + var req = obj.put(data, ''+key); + req.onsuccess = obj.onsuccess = tx.onsuccess = function(){ cb(null, 1) } + req.onabort = obj.onabort = tx.onabort = function(eve){ cb(eve||2) } + req.onerror = obj.onerror = tx.onerror = function(eve){ cb(eve||3) } +} +ind.get = function(key, cb){ + if(!db){ setTimeout(function(){ ind.get(key, cb) },9); return } + var tx = db.transaction([f], 'readwrite'); + var obj = tx.objectStore(f); + var req = obj.get(''+key); + req.onsuccess = function(){ cb(null, req.result) } + req.onabort = function(eve){ cb(eve||4) } + req.onerror = function(eve){ cb(eve||5) } +} +window.ind = ind; +}()); + +;(function(){ +localStorage.clear(); +var ls = localStorage, loc = {}; +loc.put = function(key, data, cb){ ls[''+key] = data; cb(null, 1) } +loc.get = function(key, cb){ cb(null, ls[''+key]) } +window.loc = loc; +}()); +}()); \ No newline at end of file diff --git a/test/rad/browser.html b/test/rad/browser.html index d864fa0e..087c3cfd 100644 --- a/test/rad/browser.html +++ b/test/rad/browser.html @@ -4,7 +4,8 @@ - + + @@ -16,87 +17,6 @@
    - - - - + \ No newline at end of file From 9b188dea726d37d706cd555a2e7e768774666211 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Thu, 6 Feb 2020 14:11:47 -0800 Subject: [PATCH 39/87] Update .gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 74fb92eb..393802ed 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,10 @@ yarn.lock .idea/ *.bak *.new +*.log +v8.json *.DS_store +isolate*.log .esm-cache .sessionStorage -.localStorage \ No newline at end of file +.localStorage From 3127b41f38a29704ee929c423c195bf3523abf76 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Sat, 8 Feb 2020 02:02:36 -0800 Subject: [PATCH 40/87] full circuit --- Aptfile | 3 - Procfile | 2 +- axe.js | 33 +++------ gun.js | 179 +++++++++++++++++++++++++---------------------- lib/multicast.js | 2 +- lib/radiskip.js | 33 ++++----- lib/radix.js | 6 +- lib/rfs.js | 8 ++- lib/rs3.js | 27 +++---- lib/store.js | 52 +++++++++----- package.json | 3 +- sea.js | 8 +-- 12 files changed, 188 insertions(+), 168 deletions(-) delete mode 100644 Aptfile diff --git a/Aptfile b/Aptfile deleted file mode 100644 index 844cac60..00000000 --- a/Aptfile +++ /dev/null @@ -1,3 +0,0 @@ -linux-tools-common -linux-tools-generic -linux-tools-aws \ No newline at end of file diff --git a/Procfile b/Procfile index 49049048..d18ab5df 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: node --inspect trace.js +web: node --prof trace.js \ No newline at end of file diff --git a/axe.js b/axe.js index 2c5e32ba..19594d2c 100644 --- a/axe.js +++ b/axe.js @@ -102,11 +102,14 @@ if('string' != typeof (tmp = get['#'])){ return } return tmp; } + // TODO: AXE NEEDS TO BE CHECKED FOR NEW CODE SYSTEM!!!!!!!!!! var Rad = (Gun.window||{}).Radix || USE('./lib/radix', 1); at.opt.dht = Rad(); - at.on('in', function input(msg){ - var to = this.to, peer = (msg._||{}).via; + at.on('in', input); + at.on('in2', input); + function input(msg){ + var to = this.to, peer = (msg._||'').via || mesh.leap; // warning! mesh.leap could be buggy! var dht = opt.dht; var routes = axe.routes || (axe.routes = {}); // USE RAD INSTEAD! TMP TESTING! var get = msg.get, hash, tmp; @@ -131,8 +134,8 @@ } }*/ } - if((tmp = msg['@']) && (tmp = at.dup.s[tmp]) && (tmp = tmp.it)){ - (tmp = (tmp._||{})).ack = (tmp.ack || 0) + 1; // count remote ACKs to GET. + if((tmp = msg['@']) && (tmp = at.dup.s[tmp])){ + tmp.ack = (tmp.ack || 0) + 1; // count remote ACKs to GET. } to.next(msg); @@ -147,7 +150,7 @@ }); }); } - }); + }; //try{console.log(req.connection.remoteAddress)}catch(e){}; mesh.hear['opt'] = function(msg, peer){ @@ -209,7 +212,7 @@ if(peers === opt.peers){ return } // prevent infinite lack loop. return meta.turn = 0, chat(opt.peers, peers) } - var hash = msg['##'], ack = meta.ack; + var hash = msg['##'], ack = meta.ack || at.dup.s[msg['#']]; meta.lack = setTimeout(function(){ if(ack && hash && hash === msg['##']){ return } if(meta.turn >= (axe.turns || 3)){ return } // variable for later! Also consider ACK based turn limit. @@ -254,24 +257,6 @@ } }); }; - /*var connections = 0; // THIS HAS BEEN MOVED TO CORE NOW! - at.on('hi', function(opt) { - this.to.next(opt); - //console.log('AXE PEER [HI]', new Date(), opt); - connections++; - /// The first connection don't need to resubscribe the nodes. - if (connections === 1) { return; } - /// Resubscribe all nodes. - setTimeout(function() { - var souls = Object.keys(at.graph); - for (var i=0; i < souls.length; ++i) { - //at.gun.get(souls[i]).off(); - at.next[souls[i]].ack = 0; - at.gun.get(souls[i]).once(function(){}); - } - //location.reload(); - }, 500); - }, at);*/ } axe.up = {}; at.on('hi', function(peer){ diff --git a/gun.js b/gun.js index 8d2388ed..ece88877 100644 --- a/gun.js +++ b/gun.js @@ -596,9 +596,9 @@ USE('./onto'); // depends upon onto! module.exports = function ask(cb, as){ if(!this.on){ return } - if(!(cb instanceof Function)){ + if(!('function' == typeof cb)){ if(!cb || !as){ return } - var id = cb['#'] || cb, tmp = (this.tag||empty)[id]; + var id = cb['#'] || cb, tmp = (this.tag||'')[id]; if(!tmp){ return } tmp = this.on(id, as); clearTimeout(tmp.err); @@ -653,7 +653,7 @@ Gun.is = function($){ return ($ instanceof Gun) || ($ && $._ && ($ === $._.$)) || false } - Gun.version = 0.9; + Gun.version = 0.2020; Gun.chain = Gun.prototype; Gun.chain.toJSON = function(){}; @@ -680,8 +680,8 @@ if(!at.once){ at.on('in', root, at); at.on('in2', root2, at); + at.on('put2', map, at); at.on('out', root, {at: at, out: root}); - at.on('put2', cache, at); Gun.on('create', at); at.on('create', at); } @@ -689,6 +689,7 @@ return gun; } function root(msg){ + if(msg.out === root2){ this.to.next(msg); return } //add to.next(at); // TODO: MISSING FEATURE!!! var ev = this, as = ev.as, at = as.at || as, gun = at.$, dup, tmp; if(!(tmp = msg['#'])){ tmp = msg['#'] = text_rand(9) } @@ -722,81 +723,92 @@ if(dup.check(tmp)){ return } dup.track(tmp); tmp = msg._; msg._ = ('function' == typeof tmp)? tmp : function(){}; if(msg.get){ Gun.on.get(msg, gun) } - if(msg.put){ PUT(msg, gun) } + if(msg.put){ put(msg, gun) } eve.to.next(msg); + msg.out = root2; at.on('out', msg); // EXPERIMENTAL! } - }()); - - ;(function(){ - Gun.on.put2 = function(msg, gun){ - var ctx = msg._, root = ctx.root = gun._, id = msg['#']; - var ack = ctx.ack = function(soul, key, val, state){ - if(ack.err){ - if(ack.s){ root.on('in', {'@': id, err: Gun.log(ack.err)}) } - return ack.s = u; + function put(msg, gun){ + var ctx = msg._, root = ctx.root = gun._, put = msg.put, id = msg['#'], mid = 1; + if(put['#']){ root.on('put2', msg); return } + var all = ctx.all = function(err, ok){ + if(!id){ return } + if(all.err = all.err || err){ + root.on('in', {'@': id, err: Gun.log(all.err)}); + return id = u; } - var acks, tmp; - if((acks = ack.s||'')[tmp = soul+key]){ - delete acks[tmp]; - root.on('put2', {put: {'#': soul, '.': key, ':': val, '>': state}}); - } - if(!obj_empty(acks)){ return } // keep waiting - console.log("I'm all done!!!"); - } - ack.err = obj_map(msg.put, nodes, msg); - msg = ctx = u; - if(ack.err){ ack(); return } + if(mid){ return } + if(!obj_empty(all.s)){ return } // keep waiting + root.on('in', {'@': id, ok: ok || 1}); + id = u; + }; + all.err = obj_map(put, valid, msg); + ctx.node = ctx.state = u; + mid = msg = ctx = u; + all(); } - function nodes(node, soul){ + function valid(node, soul){ if(!node){ return ERR+cut(soul)+"no node." } var ctx = this._, tmp; + (ctx.root.opt||'').super && ctx.root.$.get(soul); // I think we need super for now, but since we are rewriting, should consider getting rid of it. if(!(tmp = node._)){ return ERR+cut(soul)+"no meta." } ctx.node = node; if(soul !== tmp[_soul]){ return ERR+cut(soul)+"soul not same." } ctx.soul = soul; if(!(ctx.states = tmp[state_])){ return ERR+cut(soul)+"no state." } - return obj_map(node, souls, this); + return obj_map(node, mix, this); } - function souls(val, key){ + function mix(val, key){ if(node_ === key){ return } var ctx = this._, soul = ctx.soul, state = ctx.states[key], tmp; if(u === state){ return ERR+cut(key)+"on"+cut(soul)+"no state." } if(!val_is(val)){ return ERR+cut(key)+"on"+cut(soul)+"bad "+(typeof val)+cut(val) } - ((tmp = ctx.ack).s || (tmp.s = {}))[soul+key] = 1; - ham(ctx.root.graph, soul, key, val, state, tmp); // TODO: HANDLE CALLBACK WHERE ALL DAY IS HISTORIC? + ham(val, key, soul, state, ctx); // TODO: HANDLE CALLBACK WHERE ALL DAY IS HISTORIC? } - function ham(graph, soul, key, val, state, ack){ + function ham(val, key, soul, state, ctx){ + var root = ctx.root, graph = root.graph, id = soul+key, all = ctx.all, alls; var vertex = graph[soul] || empty, was = state_is(vertex, key, 1), known = vertex[key]; var machine = State(), is = HAM(machine, state, was, val, known), u; + (alls = all.s || (all.s = {}))[id] = 1; if(!is.incoming){ if(is.defer){ var to = is.defer - machine; setTimeout(function(){ - ham(graph, soul, key, val, state, cb); + ham(val, key, soul, state, ctx); }, to > MD? MD : to); // setTimeout Max Defer 32bit :( return; } - if(ack){ ack(soul, key) } + delete alls[id]; + all(u, -1); return; } - if(ack){ ack(soul, key, val, state) } + root.on('put2', {put: {'#': soul, '.': key, ':': val, '>': state}, ack: function(err, ok){ + delete alls[id]; + all(err, ok); + }}); + } + function map(msg){ + var eve = this, root = eve.as, graph = root.graph, put = msg.put, soul = put['#'], key = put['.'], val = put[':'], state = put['>'], id = msg['#'], tmp; + graph[soul] = state_ify(graph[soul], key, state, val, soul); + debounce(root, soul, key,val, state); // TODO: This should NOT be how the API works, this should be done at an extension layer, but hacky solution to migrate with old code for now. + eve.to.next(msg); + } + function debounce(root, soul, key,val, state){ var tmp; + if(!(tmp = root.next[soul]) || !tmp.$){ return } + tmp.change = state_ify(tmp.change, key, state, val, soul); + tmp.put = state_ify(tmp.put, key, state, val, soul); + if(tmp.wait){ return } + tmp.wait = setTimeout(function(){ + var change = tmp.change; tmp.change = tmp.wait = null; + root.stop = this.stop; // temporary fix till a better solution? + tmp.on('in', {$: tmp.$, get: soul, put: change}); + root.stop = null; // temporary fix till a better solution? + },0); + } - var cut = function(s){ return " '"+(''+s).slice(0,9)+"...' " } var ERR = "Error: Invalid graph!"; + var cut = function(s){ return " '"+(''+s).slice(0,9)+"...' " } + var HAM = Gun.HAM, MD = 2147483647, State = Gun.state; }()); - var PUT = Gun.on.put2; - var HAM = Gun.HAM, MD = 2147483647, State = Gun.state; - function cache(msg){ - var eve = this, root = eve.as, graph = root.graph; - var put = msg.put, soul = put['#'], key = put['.'], val = put[':'], state = put['>']; - graph[soul] = state_ify(graph[soul], key, state, val, soul); - // trigger chains // trigger after all individual values cached? - if(eve.to.last === eve.to.next){ - console.log("THE END, reply back"); - return; - } - eve.to.next(msg); - } ;(function(){ Gun.on.put = function(msg, gun){ @@ -901,8 +913,8 @@ var faith = function(){}; faith.ram = faith.faith = true; // HNPERF: We're testing performance improvement by skipping going through security again, but this should be audited. root.on('in', { '@': msg['#'], - how: 'mem', put: node, + ram: 1, $: gun, _: faith }); @@ -1926,7 +1938,7 @@ } root.on('out', function(msg){ - if(msg.lS){ return } // TODO: for IndexedDB and others, shouldn't send to peers ACKs to our own GETs. + if(msg.lS){ return } // TODO: for IndexedDB and others, shouldn't send to peers ACKs to our own GETs. // THIS IS BLOCKING BROWSERS REPLYING TO REQUESTS, NO??? CHANGE THIS SOON!! UNDER CONTROLLED CIRCUMSTANCES!! Or maybe in-memory already doe sit? if(Gun.is(msg.$) && msg.put && !msg['@']){ id = msg['#']; Gun.graph.is(msg.put, null, map); @@ -2000,7 +2012,7 @@ data = Gun.state.to(data, has); } //if(!data && !Gun.obj.empty(opt.peers)){ return } // if data not found, don't ack if there are peers. // Hmm, what if we have peers but we are disconnected? - root.on('in', {'@': msg['#'], put: Gun.graph.node(data), how: 'lS', lS: msg.$});// || root.$}); + root.on('in', {'@': msg['#'], put: Gun.graph.node(data), lS:1});// || root.$}); }; Gun.debug? setTimeout(to,1) : to(); }); @@ -2062,7 +2074,7 @@ var m, i = 0, c = 100; // hardcoded for now? while(c-- && (m = msg[i++])){ mesh.hear(m, peer) } msg = msg.slice(i); // slicing after is faster than shifting during. - // TODO: consider triggering peer flush to response times speedier! + flush(peer); // TODO: consider triggering peer flush to response times speedier! if(!msg.length){ return } puff(go, 1); }()); @@ -2074,7 +2086,7 @@ if(!msg){ return } if(msg.DBG_s){ opt.log(+new Date - msg.DBG_s, 'to hear', msg['#']) } if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } - if(dup_check(id)){ return } + if(tmp = dup_check(id)){ return } /*if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } if(hash && (tmp = msg['@'] || (msg.get && id))){ // Reduces backward daisy in case varying hashes at different daisy depths are the same. if(dup.check(tmp+hash)){ return } @@ -2082,7 +2094,7 @@ } if(tmp = msg['><']){ (msg._).to = Type.obj.map(tmp.split(','), tomap) } */ // TOOD: COME BACK TO THIS LATER!!! IMPORTANT MESH STUFF!! - (msg._ = function(){}).via = peer; + (msg._ = function(){}).via = mesh.leap = peer; if(tmp = msg.dam){ if(tmp = mesh.hear[tmp]){ tmp(msg, peer, root); @@ -2091,9 +2103,9 @@ return; } var S, ST; LOG && (S = +new Date); console.STAT = {}; - //root.on('in', msg); - root.on('in2', msg); - dup_track(id); + msg.put? root.on('in2', msg) : root.on('in', msg); // come on, pretty epic live upgrade path for tens of millions of users, no? Oh boy, this is a TEMPORARY hack, make sure future versions are stable. // REMEMBER!!! When you "finish" this, check all adapters, especially RAD, SEA, AXE, UDP & others!!! + dup_track(id).via = peer; + mesh.leap = null; // warning! mesh.leap could be buggy. if(LOG && !msg.nts && (ST = +new Date - S) > 9){ opt.log(S, ST, 'msg', msg['#'], JSON.stringify(console.STAT)) } return; } @@ -2113,20 +2125,20 @@ var S; LOG && (S = +new Date); //msg.DBG_s = msg.DBG_s || +new Date; var meta = msg._||(msg._=function(){}); if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } - if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } + //if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } if(!(raw = meta.raw)){ raw = mesh.raw(msg); - if(hash && (tmp = msg['@'])){ + /*if(hash && (tmp = msg['@'])){ dup.track(tmp+hash).it = it(msg); if(tmp = (dup.s[tmp]||ok).it){ if(hash === tmp['##']){ return false } tmp['##'] = hash; } - } + }*/ } //LOG && opt.log(S, +new Date - S, 'say prep'); - dup.track(id).it = it(msg); // track for 9 seconds, default. Earth<->Mars would need more! - if(!peer){ peer = (tmp = dup.s[msg['@']]) && (tmp = tmp.it) && (tmp = tmp._) && (tmp = tmp.via) } + dup_track(id);//.it = it(msg); // track for 9 seconds, default. Earth<->Mars would need more! + if(!peer){ peer = ((tmp = dup.s[msg['@']]) && (tmp.via || ((tmp = tmp.it) && (tmp = tmp._) && tmp.via))) || mesh.leap } // warning! mesh.leap could be buggy! if(!peer && msg['@']){ LOG && opt.log(+new Date, ++SMIA, 'total no peer to ack to'); return false; @@ -2141,39 +2153,42 @@ } if(!peer.wire && mesh.wire){ mesh.wire(peer) } if(id === peer.last){ return } peer.last = id; // was it just sent? - if(peer === meta.via){ return false } + if(peer === meta.via){ return false } // don't send back to self. if((tmp = meta.to) && (tmp[peer.url] || tmp[peer.pid] || tmp[peer.id]) /*&& !o*/){ return false } if(peer.batch){ peer.tail = (tmp = peer.tail || 0) + raw.length; if(peer.tail <= opt.pack){ - peer.batch.push(raw); // peer.batch += (tmp?'':',')+raw; // TODO: Prevent double JSON! // FOR v1.0 !? + //peer.batch.push(raw); + peer.batch += (tmp?',':'')+raw; // TODO: Prevent double JSON! // FOR v1.0 !? return; } flush(peer); } - peer.batch = []; // peer.batch = '['; // TODO: Prevent double JSON! + //peer.batch = []; + peer.batch = '['; // TODO: Prevent double JSON! var S, ST; LOG && (S = +new Date); setTimeout(function(){ LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, '1ms TO'); - flush(peer) + flush(peer); }, opt.gap); send(raw, peer); } - function flush(peer){ - var tmp = peer.batch; // var tmp = peer.batch + ']'; // TODO: Prevent double JSON! - peer.batch = peer.tail = null; - if(!tmp){ return } - if(!tmp.length){ return } // if(3 > tmp.length){ return } // TODO: ^ - var S, ST; LOG && (S = +new Date); - try{tmp = (1 === tmp.length? tmp[0] : JSON.stringify(tmp)); - }catch(e){return opt.log('DAM JSON stringify error', e)} - LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'say stringify', tmp.length); - if(!tmp){ return } - send(tmp, peer); - } mesh.say.c = mesh.say.d = 0; }()); - + + function flush(peer){ + var tmp = peer.batch, t = 'string' == typeof tmp, l; + if(t){ tmp += ']' }// TODO: Prevent double JSON! + peer.batch = peer.tail = null; + if(!tmp){ return } + if(t? 3 > tmp.length : !tmp.length){ return } // TODO: ^ + var S, ST; LOG && (S = +new Date); + if(!t){try{tmp = (1 === tmp.length? tmp[0] : JSON.stringify(tmp)); + }catch(e){return opt.log('DAM JSON stringify error', e)}} + LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'say stringify', tmp.length); + if(!tmp){ return } + send(tmp, peer); + } // for now - find better place later. function send(raw, peer){ try{ var wire = peer.wire; @@ -2196,12 +2211,12 @@ if(!msg){ return '' } var meta = (msg._) || {}, put, hash, tmp; if(tmp = meta.raw){ return tmp } - if(typeof msg === 'string'){ return msg } - if(!msg.dam){ + if('string' == typeof msg){ return msg } + /*if(!msg.dam){ // TOOD: COME BACK TO THIS LATER!!! IMPORTANT MESH STUFF!! var i = 0, to = []; Type.obj.map(opt.peers, function(p){ to.push(p.url || p.pid || p.id); if(++i > 3){ return true } // limit server, fast fix, improve later! // For "tower" peer, MUST include 6 surrounding ids. // REDUCED THIS TO 3 for temporary relay peer performance, towers still should list neighbors. }); if(i > 1){ msg['><'] = to.join() } - } + }*/ // TOOD: COME BACK TO THIS LATER!!! IMPORTANT MESH STUFF!! var raw = $(msg); // optimize by reusing put = the JSON.stringify from .hash? /*if(u !== put){ tmp = raw.indexOf(_, raw.indexOf('put')); diff --git a/lib/multicast.js b/lib/multicast.js index d4023b22..5fcb1dd3 100644 --- a/lib/multicast.js +++ b/lib/multicast.js @@ -83,7 +83,7 @@ Gun.on('create', function(root){ } if((tmp = root.stats) && (tmp = tmp.gap) && info){ (tmp.near || (tmp.near = {}))[info.address] = info.port || 1 } // STATS! if(check.on || id === pid){ return } - root.on('out', check.on = say); + root.on('out', check.on = say); // TODO: MULTICAST NEEDS TO BE CHECKED FOR NEW CODE SYSTEM!!!!!!!!!! } setInterval(check, 1000 * 1); diff --git a/lib/radiskip.js b/lib/radiskip.js index 90ec0a47..325bbf3c 100644 --- a/lib/radiskip.js +++ b/lib/radiskip.js @@ -43,21 +43,19 @@ var r = function(key, data, cb){ if('function' === typeof data){ var o = cb || {}; - cb = val; + cb = data; r.read(key, cb); return; } //var tmp = (tmp = r.batch = r.batch || {})[key] = tmp[key] || {}; //var tmp = (tmp = r.batch = r.batch || {})[key] = data; - //console.only(1, key, data); r.save(key, data, cb); } r.save = function(key, data, cb){ var s = {key: key}; s.find = function(file){ var tmp; - //console.only(4, 'find', file); s.file = file || (file = opt.code.from); - if(tmp = r.disk[file]){ s.mix(null, tmp); return } + if(tmp = r.disk[file]){ s.mix(u, tmp); return } r.parse(file, s.mix); } s.mix = function(err, disk){ @@ -74,9 +72,7 @@ if(u === data){ cb(err, -1); return } } (s.disk = disk)(key, data); - //console.only(7, key, data, disk.$, disk.Q); if(disk.Q){ disk.Q.push(cb); return } disk.Q = [cb]; - //console.only(6, key, data, disk.$); disk.to = setTimeout(s.write, opt.until); } s.write = function(){ @@ -84,7 +80,6 @@ s.q = disk.Q; delete disk.Q; delete r.disk[file]; - //console.only(8, s.file, q.length); r.write(file, disk, s.ack); } s.ack = function(err, ok){ @@ -112,14 +107,14 @@ f.file = file = rad.file || (rad.file = file); if(!file){ cb('What file?'); return } f.write = function(){ - var S; LOG && (S = +new Date); - var text = f.text; + var text = rad.raw = f.text; r.disk[file = rad.file || f.file || file] = rad; + var S; LOG && (S = +new Date); r.find.add(file, function add(err){ if(err){ cb(err); return } opt.store.put(ename(file), text, function safe(err, ok){ LOG && opt.log(S, ST = +new Date - S, "wrote disk", JSON.stringify(file), ++RWC, 'total all writes.'); - cb(err, ok); + cb(err, ok || 1); if(!rad.Q){ delete r.disk[file] } // VERY IMPORTANT! Clean up memory, but not if there is already queued writes on it! }); }); @@ -215,7 +210,7 @@ } Q[g.file] = [{key: key, ack: cb, file: g.file, opt: o}]; if(!g.file){ - g.it(null, u, {}); + g.it(u, u, {}); return true; } r.parse(g.file, g.check); @@ -310,7 +305,7 @@ var g = {key: key}; g.find = function(file){ var tmp; g.file = file || (file = opt.code.from); // this may not be true for reads? Hit "end of dir"? - if(tmp = r.disk[file]){ g.check(null, tmp); return } + if(tmp = r.disk[file]){ g.check(u, tmp); return } r.parse(file, g.check); } g.get = function(err, disk, info){ @@ -322,11 +317,13 @@ return; } disk = r.disk[file] || (r.disk[file] = disk); - if(!disk){ cb(null); return } + if(!disk){ cb(); return } disk.file || (disk.file = file); // ---------------------------- + info = info || {}; var data = disk(key); - if(u !== data){ cb(null, data); return } + info.atom = disk.atom; + if(u !== data){ cb(u, data, info); return } // ---------------------------- return; var S; LOG && (S = +new Date); @@ -350,7 +347,6 @@ o.next = as.file; r.read(key, as.ack, o); } - r.find(key, g.find); g.check = function(err, disk, info){ g.get(err, disk, info); (info || (info = {})).file || (info.file = g.file); @@ -367,6 +363,7 @@ }) }); } + r.find(key, g.find); } function rev(a,b){ return b } var revo = {reverse: true}; @@ -389,7 +386,6 @@ p.read = function(err, data){ var tmp; LOG && opt.log(S, +new Date - S, 'read disk', JSON.stringify(file), ++RPC, 'total all parses.'); delete Q[file]; - //console.only(5, 'parse', file, data, q.length); if((p.err = err) || (p.not = !data)){ map(q, p.ack); return } if('string' !== typeof data){ try{ @@ -467,7 +463,8 @@ return l; } var S; LOG && (S = +new Date); - if(raw){ return p.read(null, raw) } + if(r.disk){ raw || (raw = (r.disk[file]||'').raw) } + if(raw){ return p.read(u, raw) } opt.store.get(ename(file), p.read); } }()); @@ -477,7 +474,6 @@ r.find = function(key, cb){ if(!dir){ if(Q){ Q.push([key, cb]); return } Q = [[key, cb]]; - //console.only(2, 'find', key); r.parse(f, init); return; } @@ -509,7 +505,6 @@ return; } if(disk){ drain(disk); return } - //console.only(3, 'init', err, disk); dir = dir || disk || Radix(); if(!opt.store.list){ drain(dir); return } // import directory. diff --git a/lib/radix.js b/lib/radix.js index ffd13c72..f33bc4b3 100644 --- a/lib/radix.js +++ b/lib/radix.js @@ -2,12 +2,13 @@ function Radix(){ var radix = function(key, val, t){ + radix.atom = 0; if(!t && u !== val){ radix.last = (''+key < radix.last)? radix.last : ''+key; delete (radix.$||{})[_]; } t = t || radix.$ || (radix.$ = {}); - if(!key && Object.keys(t).length){ return t } + if(!key && Object.keys(t).length){ console.log('wat?', t, key); return t } key = ''+key; var i = 0, l = key.length-1, k = key[i], at, tmp; while(!(at = t[k]) && i < l){ @@ -46,7 +47,8 @@ } } else if(i == l){ - if(u === val){ return (u === (tmp = at['']))? at : tmp } + //if(u === val){ return (u === (tmp = at['']))? at : tmp } // THIS CODE IS CORRECT, below is + if(u === val){ return (u === (tmp = at['']))? at : ((radix.atom = 1) && tmp) } // temporary help?? at[''] = val; //(at[_] = function $(){ $.sort = Object.keys(at).sort(); return $ }()); } else { diff --git a/lib/rfs.js b/lib/rfs.js index 8a2e805b..705ae88a 100644 --- a/lib/rfs.js +++ b/lib/rfs.js @@ -10,20 +10,24 @@ function Store(opt){ return Store[opt.file]; } Store[opt.file] = store; + var puts = {}; store.put = function(file, data, cb){ + puts[file] = data; var random = Math.random().toString(36).slice(-3); var tmp = opt.file+'-'+file+'-'+random+'.tmp'; fs.writeFile(tmp, data, function(err, ok){ + delete puts[file]; if(err){ return cb(err) } move(tmp, opt.file+'/'+file, cb); }); }; - store.get = function(file, cb){ + store.get = function(file, cb){ var tmp; + if(tmp = puts[file]){ cb(u, tmp); return } fs.readFile(opt.file+'/'+file, function(err, data){ if(err){ if('ENOENT' === (err.code||'').toUpperCase()){ - return cb(null); + return cb(); } opt.log("ERROR:", err) } diff --git a/lib/rs3.js b/lib/rs3.js index 2ad03e8b..25a5ad19 100644 --- a/lib/rs3.js +++ b/lib/rs3.js @@ -52,24 +52,25 @@ function Store(opt){ store.put = function(file, data, cb){ var params = {Bucket: opts.bucket, Key: file, Body: data}; //console.log("RS3 PUT ---->", (data||"").slice(0,20)); - Gun.obj.del(c.g, file); - Gun.obj.del(c.l, 1); - s3.putObject(params, cb); + c.p[file] = data; + delete c.g[file];//Gun.obj.del(c.g, file); + delete c.l[1];//Gun.obj.del(c.l, 1); + s3.putObject(params, function(err, ok){ + delete c.p[file]; + cb(err, 's3'); + }); }; - store.get = function(file, cb){ - if(c.g[file]){ return c.g[file].push(cb) } + store.get = function(file, cb){ var tmp; + if(tmp = c.p[file]){ cb(u, tmp); return } + if(tmp = c.g[file]){ tmp.push(cb); return } var cbs = c.g[file] = [cb]; var params = {Bucket: opts.bucket, Key: file||''}; //console.log("RS3 GET ---->", file); - s3.getObject(params, function(err, ack){ + s3.getObject(params, function got(err, ack){ //console.log("RS3 GOT <----", err, file, cbs.length, ((ack||{}).Body||'').toString().slice(0,20)); - Gun.obj.del(c.g, file); - var data, cbe = function(cb){ - if(!ack){ cb(null); return; } - cb(err, data); - }; - data = (ack||{}).Body; //if(data = (ack||{}).Body){ data = data.toString() } - Gun.obj.map(cbs, cbe); + delete c.g[file];//Gun.obj.del(c.g, file); + var data, data = (ack||'').Body; + var i = 0, cba; while(cba = cbs[i++]){ cba && cba(err, data) }//Gun.obj.map(cbs, cbe); }); }; store.list = function(cb, match, params, cbs){ diff --git a/lib/store.js b/lib/store.js index 77d19468..1ca48d89 100644 --- a/lib/store.js +++ b/lib/store.js @@ -17,23 +17,29 @@ Gun.on('create', function(root){ root.on('put2', function(msg){ this.to.next(msg); var id = msg['#'], put = msg.put, soul = put['#'], key = put['.'], val = put[':'], state = put['>'], tmp; - dare(soul+key, {':': val, '>': state}, function(err, ok){ - console.log("STORE PAT:", soul, key, val, id, err, ok); + tmp = soul+esc+key; // soul+key; // be nice to move away from escaping + dare(tmp, {':': val, '>': state}, function(err, ok){ + if(msg.ack){ msg.ack(err, ok || 1) } return; // REVISE THIS IN FUTURE!!! + if(err){ root.on('in', {'@': id, err: err}); return } + root.on('in', {'@': id, ok: ok}); }); }); root.on('put', function(msg){ this.to.next(msg); var id = msg['#'] || Gun.text.random(3), track = !msg['@'], acks = track? 0 : u; // only ack non-acks. - var _ = (msg._||empty), got = _.rad; + var _ = (msg._||''), got = _.rad; + if(got){ return } // RAD's own ACKs to GETs do not need to be written to disk again. if(_.ram){ return } // in-memory ACKs to GETs do not need to be written to disk again. + root.on('in', {'@': msg['#'], err: 'Migration not done, please report this to & complain at Mark in http://chat.gun.eco !'}); + return; var S = (+new Date), C = 0; // STATS! var now = Gun.state(); Gun.graph.is(msg.put, null, function(val, key, node, soul){ if(!track && got){ - var at = (root.next||empty)[soul]; + var at = (root.next||'')[soul]; if(!at){ return } - if(u !== got['.']){ at = (at.next||empty)[key] } + if(u !== got['.']){ at = (at.next||'')[key] } if(!at){ return } at.rad = now; return; @@ -91,26 +97,32 @@ Gun.on('create', function(root){ o.limit = (tmp <= (o.pack || (1000 * 100)))? tmp : 1; } if(has['-'] || (soul||{})['-']){ o.reverse = true } - if((tmp = (root.next||empty)[soul]) && tmp.put){ - var SPUT = tmp.put; + if((tmp = (root.next||'')[soul]) && tmp.put){ if(o.atom){ - tmp = (tmp.next||empty)[o.atom] ; + tmp = (tmp.next||'')[o.atom] ; if(tmp && tmp.rad){ return } } else if(tmp && tmp.rad){ return } } + var now = Gun.state(); var S = (+new Date), C = 0; // STATS! - dare(key, function(err, data, o){ - console.log("STORE GOT:", err, data, o); - }, o); - rad(key||'', function(err, data, o){ + //rad(key||'', function(err, data, o){ + dare(key||'', function(err, data, info){ try{opt.store.stats.get.time[statg % 50] = (+new Date) - S; ++statg; opt.store.stats.get.count++; if(err){ opt.store.stats.get.err = err } }catch(e){} // STATS! - //if(u === data && o.chunks > 1){ return } // if we already sent a chunk, ignore ending empty responses. // this causes tests to fail. + //if(u === data && info.chunks > 1){ return } // if we already sent a chunk, ignore ending empty responses. // this causes tests to fail. LOG && Gun.log(S, +new Date - S, 'got', JSON.stringify(key)); S = +new Date; - if(data){ + info = info || {}; + var va, ve; + if(info.atom && data && u !== (va = data[':']) && u !== (ve = data['>'])){ // new format + var tmp = key.split(esc), so = tmp[0], ha = tmp[1]; + (graph = graph || {})[so] = Gun.state.ify(graph[so], ha, ve, va, so); + root.$.get(so).get(ha)._.rad = now; + // REMEMBER TO ADD _rad TO NODE/SOUL QUERY! + } else + if(data){ // old code path if(typeof data !== 'string'){ if(o.atom){ data = u; @@ -122,8 +134,9 @@ Gun.on('create', function(root){ } console.STAT && (console.STAT.radgetcount = C); if(LOG && (ST = +new Date - S) > 9){ Gun.log(S, ST, 'got prep time'); Gun.log(S, C, 'got prep #') } C = 0; S = +new Date; + //console.log("STORE GOT:", graph); var faith = function(){}; faith.faith = true; faith.rad = get; // HNPERF: We're testing performance improvement by skipping going through security again, but this should be audited. - root.on('in', {'@': id, put: graph, '%': o.more? 1 : u, err: err? err : u, _: faith}); + root.on('in', {'@': id, put: graph, '%': info.more? 1 : u, err: err? err : u, _: faith}); LOG && (ST = +new Date - S) > 9 && Gun.log(S, ST, 'got emit', Object.keys(graph||{}).length); graph = u; // each is outside our scope, we have to reset graph to nothing! }, o); @@ -135,15 +148,22 @@ Gun.on('create', function(root){ has = (key+has).split(esc); var soul = has.slice(0,1)[0]; has = has.slice(-1)[0]; + if(o.limit && o.limit <= o.count){ return true } + var va, ve, so = soul, ha = has; + if((va = val[':']) && (ve = val['>'])){ // THIS HANDLES NEW CODE! + (graph = graph || {})[so] = Gun.state.ify(graph[so], ha, ve, va, so); + o.count = (o.count || 0) + ((va||'').length || 9); + return; + } o.count = (o.count || 0) + val.length; var tmp = val.lastIndexOf('>'); var state = Radisk.decode(val.slice(tmp+1), null, esc); val = Radisk.decode(val.slice(0,tmp), null, esc); (graph = graph || {})[soul] = Gun.state.ify(graph[soul], has, state, val, soul); - if(o.limit && o.limit <= o.count){ return true } } LOG = console.LOG; }); + var val_is = Gun.val.is opt.store.stats = {get:{time:{}, count:0}, put: {time:{}, count:0}}; // STATS! var statg = 0, statp = 0; // STATS! }); \ No newline at end of file diff --git a/package.json b/package.json index 1f7cdc09..e10efe53 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "ios": "browser.ios.js", "android": "browser.android.js", "scripts": { - "start": "node examples/http.js", + "start": "node --prof examples/http.js", + "debug": "node --prof-process --preprocess -j isolate*.log > v8.json && rm isolate*.log && echo 'drag & drop ./v8.json into https://mapbox.github.io/flamebearer/'", "https": "HTTPS_KEY=test/https/server.key HTTPS_CERT=test/https/server.crt npm start", "prepublishOnly": "npm run unbuild", "test": "mocha", diff --git a/sea.js b/sea.js index bd8dbd9c..3730fc21 100644 --- a/sea.js +++ b/sea.js @@ -1151,10 +1151,11 @@ } var u; - function check(msg){ + function check(msg){ // REVISE / IMPROVE, NO NEED TO PASS MSG/EVE EACH SUB? var eve = this, at = eve.as, put = msg.put, soul = put['#'], key = put['.'], val = put[':'], state = put['>'], id = msg['#'], tmp; //console.log("security check", msg); - var no = function(why){ at.on('in', {'@': id, err: why}) } + //var no = function(why){ at.on('in', {'@': id, err: why}) } + var no = function(why){ msg.ack(why) } if('#' === soul){ // special case for content addressing immutable hashed data. check.hash(eve, msg, val, key, soul, at, no); return; } @@ -1167,7 +1168,7 @@ if('~' === soul.slice(0,1) && 2 === (tmp = soul.slice(1)).split('.').length){ // special case, account data for a public key. check.pub(eve, msg, val, key, soul, at, no, (msg._||'').user, tmp); return; } - check.any(eve, msg, val, key, soul, at, no, (msg._||'').user); return; + check.any(eve, msg, val, key, soul, at, no, (msg._||'noop').user); return; eve.to.next(msg); // not handled } check.hash = function(eve, msg, val, key, soul, at, no){ @@ -1191,7 +1192,6 @@ if(val === pub){ return eve.to.next(msg) } // the account MUST match `pub` property that equals the ID of the public key. return no("Account not same!"); } - check['user'+soul+key] = 1; if(Gun.is(msg.$) && user && user.is && pub === user.is.pub){ SEA.sign(msg.put, (user._).sea, function(data){ var rel; if(u === data){ return no(SEA.err || 'Signature fail.') } From 0936c326f8031c5fcd9426b80a7c63ac3ffc6eac Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 10 Feb 2020 15:13:37 -0800 Subject: [PATCH 41/87] unit tests passing --- gun.js | 86 ++++-- lib/radisk.js | 559 ++++++++++++++------------------------- lib/radiskip.js | 600 ------------------------------------------ lib/radix.js | 6 +- lib/rfs.js | 3 +- lib/store.js | 25 +- sea.js | 87 +++--- test/common.js | 193 ++++++-------- test/mocha.html | 7 +- test/rad/bench.js | 2 +- test/rad/browser.html | 3 +- test/rad/rad.js | 14 +- test/sea/sea.js | 38 ++- 13 files changed, 443 insertions(+), 1180 deletions(-) delete mode 100644 lib/radiskip.js diff --git a/gun.js b/gun.js index ece88877..fdced091 100644 --- a/gun.js +++ b/gun.js @@ -97,9 +97,9 @@ return !o? o : JSON.parse(JSON.stringify(o)); // is shockingly faster than anything else, and our data has to be a subset of JSON anyways! } ;(function(){ - function empty(v,i){ var n = this.n; + function empty(v,i){ var n = this.n, u; if(n && (i === n || (obj_is(n) && obj_has(n, i)))){ return } - if(i){ return true } + if(u !== i){ return true } } Type.obj.empty = function(o, n){ if(!o){ return true } @@ -115,20 +115,21 @@ } t.r = t.r || []; t.r.push(k); }; - var keys = Object.keys, map; + var keys = Object.keys, map, u; Object.keys = Object.keys || function(o){ return map(o, function(v,k,t){t(k)}) } Type.obj.map = map = function(l, c, _){ - var u, i = 0, x, r, ll, lle, f = fn_is(c); - t.r = null; + var u, i = 0, x, r, ll, lle, f = 'function' == typeof c; + t.r = u; if(keys && obj_is(l)){ ll = keys(l); lle = true; } + _ = _ || {}; if(list_is(l) || ll){ x = (ll || l).length; for(;i < x; i++){ var ii = (i + Type.list.index); if(f){ - r = lle? c.call(_ || this, l[ll[i]], ll[i], t) : c.call(_ || this, l[i], ii, t); + r = lle? c.call(_, l[ll[i]], ll[i], t) : c.call(_, l[i], ii, t); if(r !== u){ return r } } else { //if(Type.test.is(c,l[i])){ return ii } // should implement deep equality testing! @@ -171,7 +172,7 @@ tmp.next(arg); }} }}); - if(arg instanceof Function){ + if('function' == typeof arg){ var be = { off: onto.off || (onto.off = function(){ @@ -323,7 +324,7 @@ Node.ify = function(obj, o, as){ // returns a node from a shallow object. if(!o){ o = {} } else if(typeof o === 'string'){ o = {soul: o} } - else if(o instanceof Function){ o = {map: o} } + else if('function' == typeof o){ o = {map: o} } if(o.map){ o.node = o.map.call(as, obj, u, o.node || {}) } if(o.node = Node.soul.ify(o.node || {}, o)){ obj_map(obj, map, {o:o,as:as}); @@ -464,9 +465,13 @@ if(typeof env === 'string'){ env = {soul: env}; } else - if(env instanceof Function){ + if('function' == typeof env){ env.map = env; } + if(typeof as === 'string'){ + env.soul = env.soul || as; + as = u; + } if(env.soul){ at.link = Val.link.ify(env.soul); } @@ -681,7 +686,8 @@ at.on('in', root, at); at.on('in2', root2, at); at.on('put2', map, at); - at.on('out', root, {at: at, out: root}); + //at.on('out', root, {at: at, out: root}); + at.on('out', root2, at); Gun.on('create', at); at.on('create', at); } @@ -704,10 +710,10 @@ if(tmp = msg['@']){ dup.track(tmp) } // HNPERF: Bump original request's liveliness. if(!at.ask(tmp, msg)){ if(msg.get){ - Gun.on.get(msg, gun); //at.on('get', get(msg)); + Gun.on._get(msg, gun); //at.on('get', get(msg)); } if(msg.put){ - Gun.on.put(msg, gun); //at.on('put', put(msg)); + //Gun.on._put(msg, gun); //at.on('put', put(msg)); } } ev.to.next(msg); @@ -718,6 +724,7 @@ } function root2(msg){ if(!msg){ return } + if(msg.out === root2 || msg.out === root){ this.to.next(msg); return } var eve = this, as = eve.as, at = as.at || as, gun = at.$, dup = at.dup, tmp; if(!(tmp = msg['#'])){ tmp = msg['#'] = text_rand(9) } if(dup.check(tmp)){ return } dup.track(tmp); @@ -741,15 +748,16 @@ root.on('in', {'@': id, ok: ok || 1}); id = u; }; + var set = root.set || (root.set = {'':1}); all.err = obj_map(put, valid, msg); ctx.node = ctx.state = u; mid = msg = ctx = u; - all(); - } + all(); // if synchronous + fire(root, ''); // if synchronous + } Gun.on.put = put; function valid(node, soul){ if(!node){ return ERR+cut(soul)+"no node." } var ctx = this._, tmp; - (ctx.root.opt||'').super && ctx.root.$.get(soul); // I think we need super for now, but since we are rewriting, should consider getting rid of it. if(!(tmp = node._)){ return ERR+cut(soul)+"no meta." } ctx.node = node; if(soul !== tmp[_soul]){ return ERR+cut(soul)+"soul not same." } @@ -769,6 +777,7 @@ var vertex = graph[soul] || empty, was = state_is(vertex, key, 1), known = vertex[key]; var machine = State(), is = HAM(machine, state, was, val, known), u; (alls = all.s || (all.s = {}))[id] = 1; + (root.set || (root.set = {}))[id] = 1; // tmp code; if(!is.incoming){ if(is.defer){ var to = is.defer - machine; @@ -789,29 +798,46 @@ function map(msg){ var eve = this, root = eve.as, graph = root.graph, put = msg.put, soul = put['#'], key = put['.'], val = put[':'], state = put['>'], id = msg['#'], tmp; graph[soul] = state_ify(graph[soul], key, state, val, soul); - debounce(root, soul, key,val, state); // TODO: This should NOT be how the API works, this should be done at an extension layer, but hacky solution to migrate with old code for now. + chain(root, soul, key, (u !== (tmp = put['=']))? tmp : val, state); // TODO: This should NOT be how the API works, this should be done at an extension layer, but hacky solution to migrate with old code for now. + fire(root, soul+key); // ^ eve.to.next(msg); } - function debounce(root, soul, key,val, state){ var tmp; - if(!(tmp = root.next[soul]) || !tmp.$){ return } - tmp.change = state_ify(tmp.change, key, state, val, soul); + function chain(root, soul, key,val, state){ var tmp, put; + (root.opt||'').super && root.$.get(soul); // I think we need super for now, but since we are rewriting, should consider getting rid of it. + if(!root || !(tmp = root.next) || !(tmp = tmp[soul]) || !tmp.$){ return } + (put = root.put || (root.put = {}))[soul] = state_ify(put[soul], key, state, val, soul); tmp.put = state_ify(tmp.put, key, state, val, soul); + return; + tmp.change = state_ify(tmp.change, key, state, val, soul); if(tmp.wait){ return } + var stop = {}; tmp.wait = setTimeout(function(){ var change = tmp.change; tmp.change = tmp.wait = null; - root.stop = this.stop; // temporary fix till a better solution? + root.stop = stop; // temporary fix till a better solution? tmp.on('in', {$: tmp.$, get: soul, put: change}); root.stop = null; // temporary fix till a better solution? },0); } + function fire(root, id){ var set; + if(set = root.set){ delete set[id] } + if(!obj_empty(set)){ return } + var stop = {}; + var next = root.next||'', put = root.put; root.put = root.set = null; + Gun.graph.is(put, function(node,soul){ var tmp; + if(!(tmp = next[soul]) || !tmp.$){ return } + root.stop = stop; // temporary fix till a better solution? + tmp.on('in', {$: tmp.$, get: soul, put: node}); + root.stop = null; // temporary fix till a better solution? + }) + } var ERR = "Error: Invalid graph!"; var cut = function(s){ return " '"+(''+s).slice(0,9)+"...' " } var HAM = Gun.HAM, MD = 2147483647, State = Gun.state; }()); ;(function(){ - Gun.on.put = function(msg, gun){ + Gun.on._put = function(msg, gun){ var at = gun._, ctx = {$: gun, graph: at.graph, put: {}, map: {}, souls: {}, machine: Gun.state(), ack: msg['@'], cat: at, stop: {}}; if(!Gun.obj.map(msg.put, perf, ctx)){ return } // HNPERF: performance test, not core code, do not port. if(!Gun.graph.is(msg.put, null, verify, ctx)){ ctx.err = "Error: Invalid graph!" } @@ -821,7 +847,7 @@ if(u !== ctx.defer){ var to = ctx.defer - ctx.machine; setTimeout(function(){ - Gun.on.put(msg, gun); + Gun.on._put(msg, gun); }, to > MD? MD : to ); // setTimeout Max Defer 32bit :( } if(!ctx.diff){ return } @@ -894,7 +920,7 @@ } function perf(node, soul){ if(node !== this.graph[soul]){ return true } } // HNPERF: do not port! - Gun.on.get = function(msg, gun){ + Gun.on._get = function(msg, gun){ var root = gun._, get = msg.get, soul = get[_soul], node = root.graph[soul], has = get[_has], tmp; var next = root.next || (root.next = {}), at = next[soul]; // queue concurrent GETs? @@ -1008,7 +1034,7 @@ } return; } - if(n instanceof Function){ + if('function' == typeof n){ var yes, tmp = {back: at}; while((tmp = tmp.back) && u === (yes = n(tmp, opt))){} @@ -1081,6 +1107,12 @@ put._ = meta; back.on('in', {$: back.$, put: put, get: back.get}) } + if(tmp = at.lex){ + tmp = (tmp._) || (tmp._ = function(){}); + if(back.ack < tmp.ask){ tmp.ask = back.ack } + if(tmp.ask){ return } + tmp.ask = 1; + } } root.ask(ack, msg); return root.on('in', msg); @@ -1311,7 +1343,7 @@ at.on('in', {get: at.get, put: Gun.val.link.ify(get['#']), $: at.$, '@': msg['@']}); return; } - Gun.on.put(msg, at.root.$); + Gun.on._put(msg, at.root.$); } var empty = {}, u; var obj = Gun.obj, obj_has = obj.has, obj_put = obj.put, obj_del = obj.del, obj_to = obj.to, obj_map = obj.map; @@ -1331,7 +1363,7 @@ } gun = gun.$; } else - if(key instanceof Function){ + if('function' == typeof key){ if(true === cb){ return soul(this, key, cb, as), this } gun = this; var at = gun._, root = at.root, tmp = root.now, ev; @@ -1367,7 +1399,7 @@ if(tmp = this._.stun){ // TODO: Refactor? gun._.stun = gun._.stun || tmp; } - if(cb && cb instanceof Function){ + if(cb && 'function' == typeof cb){ gun.get(cb, as); } return gun; diff --git a/lib/radisk.js b/lib/radisk.js index 2a1fa2a6..712b5b7c 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -40,159 +40,57 @@ 1. Because writing to disk takes time, we should batch data to disk. This improves performance, and reduces potential disk corruption. 2. If a batch exceeds a certain number of writes, we should immediately write to disk when physically possible. This caps total performance, but reduces potential loss. */ - var r = function(key, val, cb){ - key = ''+key; - if(val instanceof Function){ + var r = function(key, data, cb){ + if('function' === typeof data){ var o = cb || {}; - cb = val; - var S; LOG && (S = +new Date); - val = r.batch(key); - LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'rad mem'); - if(u !== val){ - cb(u, r.range(val, o), o); - if(atomic(val)){ return } - // if a node is requested and some of it is cached... the other parts might not be. - } - if(r.thrash.at){ - val = r.thrash.at(key); - if(u !== val){ - cb(u, r.range(val, o), o); - if(atomic(val)){ cb(u, val, o); return } - // if a node is requested and some of it is cached... the other parts might not be. - } - } - return r.read(key, cb, o); - } - r.batch(key, val); - if(cb){ r.batch.acks.push(cb) } - if(++r.batch.ed >= opt.batch){ return r.thrash() } // (2) - if(r.batch.to){ return } - //clearTimeout(r.batch.to); // (1) // THIS LINE IS EVIL! NEVER USE IT! ALSO NEVER DELETE THIS SO WE NEVER MAKE THE SAME MISTAKE AGAIN! - r.batch.to = setTimeout(r.thrash, opt.until || 1); - } - - r.batch = Radix(); - r.batch.acks = []; - r.batch.ed = 0; - - r.thrash = function(){ - var thrash = r.thrash; - if(thrash.ing){ return thrash.more = true } - LOG = console.LOG; // dirty place to cheaply update LOG settings over time. - thrash.more = false; - thrash.ing = true; - var batch = thrash.at = r.batch, i = 0; - clearTimeout(r.batch.to); - r.batch = null; - r.batch = Radix(); - r.batch.acks = []; - r.batch.ed = 0; - //console.debug(99); var ID = Gun.text.random(2), S = (+new Date); console.log("[[[[[[[[", ID, batch.acks.length); - r.save(batch, function(err, ok){ - if(++i > 1){ opt.log('RAD ERR: Radisk has callbacked multiple times, please report this as a BUG at github.com/amark/gun/issues ! ' + i); return } - if(err){ opt.log('err', err) } - //console.debug(99); var TMP; console.log("]]]]]]]]", ID, batch.acks.length, (TMP = +new Date) - S, 'more?', thrash.more); - map(batch.acks, function(cb){ cb(err, ok) }); - //console.log("][", +new Date - TMP, thrash.more); - thrash.at = null; - thrash.ing = false; - if(thrash.more){ thrash() } - }); - } - - /* - 1. Find the first radix item in memory. - 2. Use that as the starting index in the directory of files. - 3. Find the first file that is lexically larger than it, - 4. Read the previous file to that into memory - 5. Scan through the in memory radix for all values lexically less than the limit. - 6. Merge and write all of those to the in-memory file and back to disk. - 7. If file too large, split. More details needed here. - */ - /* NEW APPROACH: - 1. For each item in radix memory - 2. Add it to a radix bucket corresponding to directory of files - 3. Iterate over each bucket - 4. Resume old approach. - */ - r.save = function(rad, cb){ - if(r.save.ing){ - r.save.ing.push({rad: rad, ack: cb}); + cb = data; + r.read(key, cb, o); return; } - //console.only(99); var ID = Gun.text.random(2), S = (+new Date); console.log("[[[[[[[[", ID); - r.save.ing = []; - var ack = cb; - var s = function Span(err, ok){ - var tmp = r.save.ing; - //console.only(99); var TMP; console.log("]]]]]]]]", ID, (TMP = +new Date) - S, 'more?', !!tmp); - r.save.ing = null; - map(tmp, function(q){ // if many, not the most efficient to requeue, but works for now. - if(!q || !q.rad || !q.ack){ return } - r.save(q.rad, q.ack); - }) - ack(err, ok); - }; - cb = s; - s.files = {}; - s.i = 0; // TODO: revise? Using counter for critical path not my favorite. - s.place = function(tree, key){ - var go = function(file, last){ - file = decodeURIComponent(file || last || opt.code.from); - (s.files[file] || (s.files[file] = Radix()))(key, tree); - if(!(--s.i)){ s.go() } // TODO: See above, revise? - return true; - } - go.reverse = 1; - go.end = key; - r.list(go); - ++s.i; // TODO: See above, revise? - } - s.go = function(){ - if(s.gone){ return } s.gone = true; - s.seq = []; - map(s.files, function(mem, file){ s.seq.push({file: file, mem: mem}) }); - LOG && opt.log(+new Date, s.seq.length, "rad files #"); - s.files = null; - s.c = 0; - s.merge(s.c); - } - s.merge = function(i){ - i = i || 0; - //var at = s.seq[i]; - var at = s.seq.shift(); - if(!at){ - if(s.ok){ return cb(null, s.ok) } - return cb("No file to save data to."); - } - var file = at.file, mem = at.mem; - r.parse(file, function(err, disk){ - if(err){ return cb(err) } - if(!disk && file !== opt.code.from){ // corrupt file? - r.list.bad(file); // remove from dir list - r.save(rad, cb); // try again - return; - } - disk = disk || Radix(); - var S, C = 0; LOG && (S = +new Date); - Radix.map(mem, function(val, key){ - C++; - // PLUGIN: consider adding HAM as an extra layer of protection - disk(key, val); // merge batch[key] -> disk[key] - }); - LOG && opt.log(S, +new Date - S, "rad merge"); - LOG && opt.log(S, C, "rad merge #"); - r.write(file, disk, s.pop); - }) - } - s.pop = function(err, ok){ - if(s.err = err || s.err){ return cb(err) } - s.ok = ok || s.ok || 1; - s.merge(++s.c); - } - Radix.map(rad, s.place); - if(!s.i){ s.go() }; // TODO: See above, revise? + //var tmp = (tmp = r.batch = r.batch || {})[key] = tmp[key] || {}; + //var tmp = (tmp = r.batch = r.batch || {})[key] = data; + r.save(key, data, cb); } + r.save = function(key, data, cb){ + var s = {key: key}; + s.find = function(file){ var tmp; + s.file = file || (file = opt.code.from); + if(tmp = r.disk[file]){ s.mix(u, tmp); return } + r.parse(file, s.mix); + } + s.mix = function(err, disk){ + if(s.err = err || s.err){ cb(err); return } + var file = s.file = (disk||'').file || s.file; + if(!disk && file !== opt.code.from){ // corrupt file? + r.find.bad(file); // remove from dir list + r.save(key, data, cb); // try again + return; + } + (disk = r.disk[file] || (r.disk[file] = disk || Radix())).file || (disk.file = file); + if(opt.compare){ + data = opt.compare(disk(key), data, key, file); + if(u === data){ cb(err, -1); return } + } + (s.disk = disk)(key, data); + if(disk.Q){ disk.Q.push(cb); return } disk.Q = [cb]; + disk.to = setTimeout(s.write, opt.until); + } + s.write = function(){ + var file = s.file, disk = s.disk; + s.q = disk.Q; + delete disk.Q; + delete r.disk[file]; + r.write(file, disk, s.ack); + } + s.ack = function(err, ok){ + var q = s.q || [], i = 0, ack; + //var S = +new Date; + while(ack = q[i++]){ ack(err, ok) } + //console.log('acks:', +new Date - S, s.file, q.length); + } + r.find(key, s.find); + } + r.disk = {}; /* Any storage engine at some point will have to do a read in order to write. @@ -200,70 +98,77 @@ Therefore it is unavoidable that a read will have to happen, the question is just how long you delay it. */ + var RWC = 0; r.write = function(file, rad, cb, o){ + if(!rad){ cb('No radix!'); return } o = ('object' == typeof o)? o : {force: o}; - var f = function Fractal(){}; + var f = function Fractal(){}, a, b; f.text = ''; - f.count = 0; - f.file = file; - f.each = function(val, key, k, pre){ - //console.log("RAD:::", JSON.stringify([val, key, k, pre])); - if(u !== val){ f.count++ } - if(opt.pack <= (val||'').length){ return cb("Record too big!"), true } - var enc = Radisk.encode(pre.length) +'#'+ Radisk.encode(k) + (u === val? '' : ':'+ Radisk.encode(val)) +'\n'; - if((opt.chunk < f.text.length + enc.length) && (1 < f.count) && !o.force){ - f.text = ''; - f.limit = Math.ceil(f.count/2); - f.count = 0; - f.sub = Radix(); - // IMPORTANT: DO THIS IN REVERSE, SO LAST HALF OF DATA MOVED TO NEW FILE BEFORE DROPPING FROM CURRENT FILE. - Radix.map(rad, f.slice, {reverse: true}); - return true; - } - f.text += enc; - } + f.file = file = rad.file || (rad.file = file); + if(!file){ cb('What file?'); return } f.write = function(){ - var tmp = ename(file); + var text = rad.raw = f.text; + r.disk[file = rad.file || f.file || file] = rad; var S; LOG && (S = +new Date); - r.list.add(tmp, function(err){ - if(err){ return cb(err) } - //opt.store.put(tmp, f.text, cb); // revert to this after stats done below: - opt.store.put(tmp, f.text, function(err,ok){ - LOG && opt.log(S, ST = +new Date - S, "wrote disk", tmp); - cb(err,ok); + r.find.add(file, function add(err){ + if(err){ cb(err); return } + opt.store.put(ename(file), text, function safe(err, ok){ + LOG && opt.log(S, ST = +new Date - S, "wrote disk", JSON.stringify(file), ++RWC, 'total all writes.'); + cb(err, ok || 1); + if(!rad.Q){ delete r.disk[file] } // VERY IMPORTANT! Clean up memory, but not if there is already queued writes on it! }); }); } + f.split = function(){ + f.text = ''; + if(!f.count){ f.count = 0; + Radix.map(rad, function count(){ f.count++ }); // TODO: Perf? Any faster way to get total length? + } + f.limit = Math.ceil(f.count/2); + f.count = 0; + f.sub = Radix(); + Radix.map(rad, f.slice, {reverse: 1}); // IMPORTANT: DO THIS IN REVERSE, SO LAST HALF OF DATA MOVED TO NEW FILE BEFORE DROPPING FROM CURRENT FILE. + r.write(f.end, f.sub, f.both, o); + f.hub = Radix(); + Radix.map(rad, f.stop); + r.write(rad.file, f.hub, f.both, o); + return true; + } f.slice = function(val, key){ f.sub(f.end = key, val); - if(f.limit <= (++f.count)){ - r.write(key, f.sub, f.swap, o); - return true; - } - } - f.swap = function(err){ - if(err){ return cb(err) } - f.sub = Radix(); - Radix.map(rad, f.stop); - r.write(f.file, f.sub, cb, o); + if(f.limit <= (++f.count)){ return true } } f.stop = function(val, key){ if(key >= f.end){ return true } - f.sub(key, val); + f.hub(key, val); } - if(opt.jsonify){ return r.write.jsonify(f, file, rad, cb, o) } // temporary testing idea + f.both = function(err, ok){ + if(b){ cb(err || b); return } + if(a){ cb(err, ok); return } + a = true; + b = err; + } + f.each = function(val, key, k, pre){ + //console.log("RAD:::", JSON.stringify([val, key, k, pre])); + if(u !== val){ f.count++ } + if(opt.pack <= (val||'').length){ return cb("Data too big!"), true } + var enc = Radisk.encode(pre.length) +'#'+ Radisk.encode(k) + (u === val? '' : ':'+ Radisk.encode(val)) +'\n'; + if((opt.chunk < f.text.length + enc.length) && (1 < f.count) && !o.force){ + return f.split(); + } + f.text += enc; + } + if(opt.jsonify){ r.write.jsonify(f, rad, cb, o); return } // temporary testing idea if(!Radix.map(rad, f.each, true)){ f.write() } } - r.write.jsonify = function(f, file, rad, cb, o){ + r.write.jsonify = function(f, rad, cb, o){ var raw; var S; LOG && (S = +new Date); try{raw = JSON.stringify(rad.$); - }catch(e){ return cb("Record too big!") } + }catch(e){ cb("Cannot radisk!"); return } LOG && opt.log(S, +new Date - S, "rad stringified JSON"); - if(opt.chunk < raw.length && !o.force){ - if(Radix.map(rad, f.each, true)){ return } - } + if(opt.chunk < raw.length && !o.force){ return f.split() } f.text = raw; f.write(); } @@ -273,129 +178,68 @@ if(u === o.start && u === o.end){ return tree } if(atomic(tree)){ return tree } var sub = Radix(); - Radix.map(tree, function(v,k){ // ONLY PLACE THAT TAKES TREE, maybe reduce API for better perf? - sub(k,v); - }, o); + Radix.map(tree, function(v,k){ sub(k,v) }, o); // ONLY PLACE THAT TAKES TREE, maybe reduce API for better perf? return sub(''); } ;(function(){ - var Q = {}; r.read = function(key, cb, o){ o = o || {}; - if(RAD && !o.next){ // cache - var S; LOG && (S = +new Date); - var val = RAD(key); - LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'rad cached'); - //if(u !== val){ - //cb(u, val, o); - if(atomic(val)){ cb(u, val, o); return } - // if a node is requested and some of it is cached... the other parts might not be. - //} + var g = {key: key}; + g.find = function(file){ var tmp; + g.file = file || (file = opt.code.from); + if(tmp = r.disk[g.file = file]){ g.check(u, tmp); return } + r.parse(file, g.check); } - o.span = (u !== o.start) || (u !== o.end); // is there a start or end? - var g = function Get(){}; - g.lex = function(file){ var tmp; // // TODO: this had a out-of-memory crash! - file = (u === file)? u : decodeURIComponent(file); - tmp = o.next || key || (o.reverse? o.end || '\uffff' : o.start || ''); - if(!file || (o.reverse? file < tmp : file > tmp)){ - LOG && opt.log(S, +new Date - S, 'rad read lex'); S = +new Date; - if(o.next || o.reverse){ g.file = file } - if(tmp = Q[g.file]){ - tmp.push({key: key, ack: cb, file: g.file, opt: o}); - return true; - } - Q[g.file] = [{key: key, ack: cb, file: g.file, opt: o}]; - if(!g.file){ - g.it(null, u, {}); - return true; - } - r.parse(g.file, g.check); - return true; - } - g.file = file; - } - g.it = function(err, disk, info){ - if(g.err = err){ opt.log('err', err) } - if(!disk && g.file){ // corrupt file? - r.list.bad(g.file); // remove from dir list - r.read(key, cb, o); // look again + g.get = function(err, disk, info){ + if(g.err = err || g.err){ cb(err); return } + var file = g.file = (disk||'').file || g.file; + if(!disk && file !== opt.code.from){ // corrupt file? + r.find.bad(file); // remove from dir list + r.read(key, cb, o); // try again return; } - g.info = info; - if(disk){ RAD = g.disk = disk } - disk = Q[g.file]; delete Q[g.file]; - map(disk, g.ack); - } - g.ack = function(as){ - if(!as.ack){ return } - var S; LOG && (S = +new Date); - var key = as.key, o = as.opt, info = g.info, rad = g.disk || noop, data = r.range(rad(key), o), last = rad.last || Radix.map(rad, rev, revo); - LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, "rad range loaded"); - o.parsed = (o.parsed || 0) + (info.parsed||0); + disk = r.disk[file] || (r.disk[file] = disk); + if(!disk){ cb("No file!"); return } + disk.file || (disk.file = file); + var data = r.range(disk(key), o); + o.unit = disk.unit; o.chunks = (o.chunks || 0) + 1; - o.more = true; - if((!as.file) // if no more places to look - || (!o.span && last === key) // if our key exactly matches the very last atomic record - || (!o.span && last && last > key && 0 != last.indexOf(key)) // 'zach' may be lexically larger than 'za', but there still might be more, like 'zane' in the 'za' prefix bucket so do not end here. - ){ - o.more = u; - as.ack(g.err, data, o); - return + o.parsed = (o.parsed || 0) + ((info||'').parsed||(o.chunks*opt.chunk)); + o.more = 1; + o.next = u; + Radix.map(r.list, function next(v,f){ + if(!v || file === f){ return } + o.next = f; + return 1; + }, o.reverse? {reverse: 1, end: file} : {start: file}); + if(!o.next){ o.more = 0 } + if(o.next){ + if(!o.reverse && (key < o.next && 0 != o.next.indexOf(key)) || (u !== o.end && (o.end || '\uffff') < o.next)){ o.more = 0 } + if(o.reverse && (key > o.next && 0 != key.indexOf(o.next)) || (u !== o.start && (o.start || '') > o.next)){ o.more = 0 } } - if(u !== data){ - as.ack(g.err, data, o); // more might be coming! - if(o.parsed >= o.limit){ return } // even if more, we've hit our limit, asking peer will need to make a new ask with a new starting point. - } - o.next = as.file; - r.read(key, as.ack, o); + if(!o.more){ cb(g.err, data, o); return } + if(data){ cb(g.err, data, o) } + if(o.parsed >= o.limit){ return } + r.parse(o.next, g.check); } g.check = function(err, disk, info){ - g.it(err, disk, info); - var good = true; + g.get(err, disk, info); + (info || (info = {})).file || (info.file = g.file); Radix.map(disk, function(val, key){ - // assume in memory for now, since both write/read already call r.list which will init it. - var go = function(file){ - if(info.file !== file){ - good = false - } - return true; - } - go.reverse = 1; - go.end = key; - r.list(go); - }); - if(good){ return } - var id = Gun.text.random(3); - r.save(disk, function ack(err, ok){ - if(err){ return r.save(disk, ack) } // ad infinitum??? - console.log("MISLOCATED DATA CORRECTED", id); + // assume in memory for now, since both write/read already call r.find which will init it. + r.find(key, function(file){ + if((file || (file = opt.code.from)) === info.file){ return } + var id = Gun.text.random(3); + console.log("MISLOCATED DATA", id, key, info.file, file); + r.save(key, val, function ack(err, ok){ + if(err){ r.save(key, val, ack); return } // ad infinitum??? + console.log("MISLOCATED DATA CORRECTED", id); + }); + }) }); } - /*g.check2 = function(err, disk, info){ - if(err || !disk){ return g.it(err, disk, info) } - var good = true; - Radix.map(disk, function(val, key){ - // assume in memory for now, since both write/read already call r.list which will init it. - var go = function(file){ - if(info.file !== file){ good = false } - return true; - } - go.reverse = 1; - go.end = key; - r.list(go); - }); - if(good){ return g.it(err, disk, info) } - var id = Gun.text.random(3); console.log("MISLOCATED DATA", id); - r.save(disk, function ack(err, ok){ - if(err){ return r.save(disk, ack) } // ad infinitum??? - console.log("MISLOCATED CORRECTED", id); - r.read(key, cb, o); - }); - }*/ - if(o.reverse){ g.lex.reverse = true } - LOG && (S = +new Date); - r.list(g.lex); + r.find(key, g.find); } function rev(a,b){ return b } var revo = {reverse: true}; @@ -409,18 +253,18 @@ with how much performance and scale we can get out of only one. Then we can work on the harder problem of being multi-process. */ + var RPC = 0; var Q = {}, s = String.fromCharCode(31); r.parse = function(file, cb, raw){ var q; - if(q = Q[file]){ return q.push(cb) } q = Q[file] = [cb]; - var p = function Parse(){}, info = {file: ename(file)}; - p.disk = Radix(); + if(!file){ return cb(); } + if(q = Q[file]){ q.push(cb); return } q = Q[file] = [cb]; + var p = function Parse(){}, info = {file: file}; + (p.disk = Radix()).file = file; p.read = function(err, data){ var tmp; - LOG && opt.log(S, +new Date - S, 'read disk', ename(file)); + LOG && opt.log(S, +new Date - S, 'read disk', JSON.stringify(file), ++RPC, 'total all parses.'); delete Q[file]; - if((p.err = err) || (p.not = !data)){ - return map(q, p.ack); - } - if(typeof data !== 'string'){ + if((p.err = err) || (p.not = !data)){ map(q, p.ack); return } + if('string' !== typeof data){ try{ if(opt.pack <= data.length){ p.err = "Chunk too big!"; @@ -428,12 +272,11 @@ data = data.toString(); // If it crashes, it crashes here. How!?? We check size first! } }catch(e){ p.err = e } - if(p.err){ return map(q, p.ack) } + if(p.err){ map(q, p.ack); return } } info.parsed = data.length; - LOG && (S = +new Date); - if(opt.jsonify || '{' === data[0]){ // temporary testing idea + if(opt.jsonify || '{' === data[0]){ try{ var json = JSON.parse(data); // TODO: this caused a out-of-memory crash! p.disk.$ = json; @@ -443,14 +286,27 @@ }catch(e){ tmp = e } if('{' === data[0]){ p.err = tmp || "JSON error!"; - return map(q, p.ack); + map(q, p.ack); + return; } } + p.radec(err, data); + } + p.ack = function(cb){ + if(!cb){ return } + if(p.err || p.not){ + cb(p.err, u, info); + return; + } + cb(u, p.disk, info); + } + p.radec = function(err, data){ LOG && (S = +new Date); var tmp = p.split(data), pre = [], i, k, v; if(!tmp || 0 !== tmp[1]){ p.err = "File '"+file+"' does not have root radix! "; - return map(q, p.ack); + map(q, p.ack); + return; } while(tmp){ k = v = u; @@ -470,7 +326,6 @@ tmp = p.split(tmp[2]); } LOG && opt.log(S, +new Date - S, 'parsed RAD'); - //cb(err, p.disk); map(q, p.ack); }; p.split = function(t){ @@ -484,75 +339,63 @@ l[2] = t.slice(i + o.i); return l; } - p.ack = function(cb){ - if(!cb){ return } - if(p.err || p.not){ return cb(p.err, u, info) } - cb(u, p.disk, info); - } var S; LOG && (S = +new Date); - if(raw){ return p.read(null, raw) } + if(r.disk){ raw || (raw = (r.disk[file]||'').raw) } + if(raw){ return p.read(u, raw) } opt.store.get(ename(file), p.read); } }()); ;(function(){ - var dir, q, f = String.fromCharCode(28), ef = ename(f); - r.list = function(cb){ - if(dir){ - var last, tmp = {reverse: (cb.reverse)? 1 : 0, start: cb.start, end: cb.end}; - Radix.map(dir, function(val, key){ - if(!val){ return } - return cb(last = key); - }, tmp) || cb(u, last); + var dir, f = String.fromCharCode(28), Q; + r.find = function(key, cb){ + if(!dir){ + if(Q){ Q.push([key, cb]); return } Q = [[key, cb]]; + r.parse(f, init); return; } - if(q){ return q.push(cb) } q = [cb]; - r.parse(f, r.list.init); + Radix.map(r.list = dir, function(val, key){ + if(!val){ return } + return cb(key) || true; + }, {reverse: 1, end: key}) || cb(opt.code.from); } - r.list.add = function(file, cb){ + r.find.add = function(file, cb){ var has = dir(file); - if(has || file === ef){ - return cb(u, 1); - } + if(has || file === f){ cb(u, 1); return } dir(file, 1); - cb.listed = (cb.listed || 0) + 1; + cb.found = (cb.found || 0) + 1; r.write(f, dir, function(err, ok){ - if(err){ return cb(err) } - cb.listed = (cb.listed || 0) - 1; - if(cb.listed !== 0){ return } + if(err){ cb(err); return } + cb.found = (cb.found || 0) - 1; + if(0 !== cb.found){ return } cb(u, 1); }, true); } - r.list.bad = function(file, cb){ - dir(ename(file), 0); + r.find.bad = function(file, cb){ + dir(file, 0); r.write(f, dir, cb||noop); } - r.list.init = function(err, disk){ + function init(err, disk){ if(err){ opt.log('list', err); - setTimeout(function(){ r.parse(f, r.list.init) }, 1000); - return; - } - if(disk){ - r.list.drain(disk); - return; - } - if(!opt.store.list){ - r.list.drain(Radix()); + setTimeout(function(){ r.parse(f, init) }, 1000); return; } + if(disk){ drain(disk); return } + dir = dir || disk || Radix(); + if(!opt.store.list){ drain(dir); return } // import directory. opt.store.list(function(file){ - dir = dir || Radix(); - if(!file){ return r.list.drain(dir) } - r.list.add(file, noop); + if(!file){ drain(dir); return } + r.find.add(file, noop); }); } - r.list.drain = function(rad, tmp){ - r.list.dir = dir = rad; - tmp = q; q = null; - Gun.list.map(tmp, function(cb){ - r.list(cb); + function drain(rad, tmp){ + dir = dir || rad; + dir.file = f; + tmp = Q; Q = null; + Gun.list.map(tmp, function(arg){ + r.find(arg[0], arg[1]); }); } }()); @@ -562,8 +405,6 @@ return r; } - - ;(function(){ var _ = String.fromCharCode(31), u; Radisk.encode = function(d, o, s){ s = s || _; diff --git a/lib/radiskip.js b/lib/radiskip.js deleted file mode 100644 index 325bbf3c..00000000 --- a/lib/radiskip.js +++ /dev/null @@ -1,600 +0,0 @@ -;(function(){ - - function Radisk(opt){ - - opt = opt || {}; - opt.log = opt.log || console.log; - opt.file = String(opt.file || 'radata'); - var has = (Radisk.has || (Radisk.has = {}))[opt.file]; - if(has){ return has } - - opt.pack = opt.pack || (opt.memory? (opt.memory * 1000 * 1000) : 1399000000) * 0.3; // max_old_space_size defaults to 1400 MB. - opt.until = opt.until || opt.wait || 250; - opt.batch = opt.batch || (10 * 1000); - opt.chunk = opt.chunk || (1024 * 1024 * 1); // 1MB - opt.code = opt.code || {}; - opt.code.from = opt.code.from || '!'; - opt.jsonify = true; - - function ename(t){ return encodeURIComponent(t).replace(/\*/g, '%2A') } - function atomic(v){ return u !== v && (!v || 'object' != typeof v) } - var map = Gun.obj.map; - var LOG = console.LOG; - var ST = 0; - - if(!opt.store){ - return opt.log("ERROR: Radisk needs `opt.store` interface with `{get: fn, put: fn (, list: fn)}`!"); - } - if(!opt.store.put){ - return opt.log("ERROR: Radisk needs `store.put` interface with `(file, data, cb)`!"); - } - if(!opt.store.get){ - return opt.log("ERROR: Radisk needs `store.get` interface with `(file, cb)`!"); - } - if(!opt.store.list){ - //opt.log("WARNING: `store.list` interface might be needed!"); - } - - /* - Any and all storage adapters should... - 1. Because writing to disk takes time, we should batch data to disk. This improves performance, and reduces potential disk corruption. - 2. If a batch exceeds a certain number of writes, we should immediately write to disk when physically possible. This caps total performance, but reduces potential loss. - */ - var r = function(key, data, cb){ - if('function' === typeof data){ - var o = cb || {}; - cb = data; - r.read(key, cb); - return; - } - //var tmp = (tmp = r.batch = r.batch || {})[key] = tmp[key] || {}; - //var tmp = (tmp = r.batch = r.batch || {})[key] = data; - r.save(key, data, cb); - } - r.save = function(key, data, cb){ - var s = {key: key}; - s.find = function(file){ var tmp; - s.file = file || (file = opt.code.from); - if(tmp = r.disk[file]){ s.mix(u, tmp); return } - r.parse(file, s.mix); - } - s.mix = function(err, disk){ - if(err){ cb(err); return } - var file = s.file = (disk||'').file || s.file; - if(!disk && file !== opt.code.from){ // corrupt file? - r.find.bad(file); // remove from dir list - r.save(key, data, cb); // try again - return; - } - (disk = r.disk[file] || (r.disk[file] = disk || Radix())).file || (disk.file = file); - if(opt.compare){ - data = opt.compare(disk(key), data, key, file); - if(u === data){ cb(err, -1); return } - } - (s.disk = disk)(key, data); - if(disk.Q){ disk.Q.push(cb); return } disk.Q = [cb]; - disk.to = setTimeout(s.write, opt.until); - } - s.write = function(){ - var file = s.file, disk = s.disk; - s.q = disk.Q; - delete disk.Q; - delete r.disk[file]; - r.write(file, disk, s.ack); - } - s.ack = function(err, ok){ - var q = s.q || [], i = 0, ack; - //var S = +new Date; - while(ack = q[i++]){ ack(err, ok) } - //console.log('acks:', +new Date - S, s.file, q.length); - } - r.find(key, s.find); - } - r.disk = {}; - - /* - Any storage engine at some point will have to do a read in order to write. - This is true of even systems that use an append only log, if they support updates. - Therefore it is unavoidable that a read will have to happen, - the question is just how long you delay it. - */ - var RWC = 0; - r.write = function(file, rad, cb, o){ - if(!rad){ cb('No radix!'); return } - o = ('object' == typeof o)? o : {force: o}; - var f = function Fractal(){}, a, b; - f.text = ''; - f.file = file = rad.file || (rad.file = file); - if(!file){ cb('What file?'); return } - f.write = function(){ - var text = rad.raw = f.text; - r.disk[file = rad.file || f.file || file] = rad; - var S; LOG && (S = +new Date); - r.find.add(file, function add(err){ - if(err){ cb(err); return } - opt.store.put(ename(file), text, function safe(err, ok){ - LOG && opt.log(S, ST = +new Date - S, "wrote disk", JSON.stringify(file), ++RWC, 'total all writes.'); - cb(err, ok || 1); - if(!rad.Q){ delete r.disk[file] } // VERY IMPORTANT! Clean up memory, but not if there is already queued writes on it! - }); - }); - } - f.split = function(){ - f.text = ''; - if(!f.count){ f.count = 0; - Radix.map(rad, function count(){ f.count++ }); // TODO: Perf? Any faster way to get total length? - } - f.limit = Math.ceil(f.count/2); - f.count = 0; - f.sub = Radix(); - Radix.map(rad, f.slice, {reverse: 1}); // IMPORTANT: DO THIS IN REVERSE, SO LAST HALF OF DATA MOVED TO NEW FILE BEFORE DROPPING FROM CURRENT FILE. - r.write(f.end, f.sub, f.both, o); - f.hub = Radix(); - Radix.map(rad, f.stop); - r.write(rad.file, f.hub, f.both, o); - return true; - } - f.slice = function(val, key){ - f.sub(f.end = key, val); - if(f.limit <= (++f.count)){ return true } - } - f.stop = function(val, key){ - if(key >= f.end){ return true } - f.hub(key, val); - } - f.both = function(err, ok){ - if(b){ cb(err || b); return } - if(a){ cb(err, ok); return } - a = true; - b = err; - } - f.each = function(val, key, k, pre){ - //console.log("RAD:::", JSON.stringify([val, key, k, pre])); - if(u !== val){ f.count++ } - if(opt.pack <= (val||'').length){ return cb("Record too big!"), true } - var enc = Radisk.encode(pre.length) +'#'+ Radisk.encode(k) + (u === val? '' : ':'+ Radisk.encode(val)) +'\n'; - if((opt.chunk < f.text.length + enc.length) && (1 < f.count) && !o.force){ - return f.split(); - } - f.text += enc; - } - if(opt.jsonify){ r.write.jsonify(f, rad, cb, o); return } // temporary testing idea - if(!Radix.map(rad, f.each, true)){ f.write() } - } - - r.write.jsonify = function(f, rad, cb, o){ - var raw; - var S; LOG && (S = +new Date); - try{raw = JSON.stringify(rad.$); - }catch(e){ cb("Cannot radisk!"); return } - LOG && opt.log(S, +new Date - S, "rad stringified JSON"); - if(opt.chunk < raw.length && !o.force){ return f.split() } - f.text = raw; - f.write(); - } - - r.range = function(tree, o){ - if(!tree || !o){ return } - if(u === o.start && u === o.end){ return tree } - if(atomic(tree)){ return tree } - var sub = Radix(); - Radix.map(tree, function(v,k){ sub(k,v) }, o); // ONLY PLACE THAT TAKES TREE, maybe reduce API for better perf? - return sub(''); - } - - ;(function(){ - var Q = {}; - r.read = function(key, cb, o){ - o = o || {}; - if(RAD && !o.next){ // cache - var S; LOG && (S = +new Date); - var val = RAD(key); - LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'rad cached'); - //if(u !== val){ - //cb(u, val, o); - if(atomic(val)){ cb(u, val, o); return } - // if a node is requested and some of it is cached... the other parts might not be. - //} - } - o.span = (u !== o.start) || (u !== o.end); // is there a start or end? - var g = function Get(){}; - g.lex = function(file){ var tmp; // // TODO: this had a out-of-memory crash! - file = (u === file)? u : decodeURIComponent(file); - tmp = o.next || key || (o.reverse? o.end || '\uffff' : o.start || ''); - if(!file || (o.reverse? file < tmp : file > tmp)){ - LOG && opt.log(S, +new Date - S, 'rad read lex'); S = +new Date; - if(o.next || o.reverse){ g.file = file } - if(tmp = Q[g.file]){ - tmp.push({key: key, ack: cb, file: g.file, opt: o}); - return true; - } - Q[g.file] = [{key: key, ack: cb, file: g.file, opt: o}]; - if(!g.file){ - g.it(u, u, {}); - return true; - } - r.parse(g.file, g.check); - return true; - } - g.file = file; - } - g.it = function(err, disk, info){ - if(g.err = err){ opt.log('err', err) } - if(!disk && g.file){ // corrupt file? - r.find.bad(g.file); // remove from dir list - r.read(key, cb, o); // look again - return; - } - g.info = info; - if(disk){ RAD = g.disk = disk } - disk = Q[g.file]; delete Q[g.file]; - map(disk, g.ack); - } - g.ack = function(as){ - if(!as.ack){ return } - var S; LOG && (S = +new Date); - var key = as.key, o = as.opt, info = g.info, rad = g.disk || noop, data = r.range(rad(key), o), last = rad.last || Radix.map(rad, rev, revo); - LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, "rad range loaded"); - o.parsed = (o.parsed || 0) + (info.parsed||0); - o.chunks = (o.chunks || 0) + 1; - o.more = true; - if((!as.file) // if no more places to look - || (!o.span && last === key) // if our key exactly matches the very last atomic record - || (!o.span && last && last > key && 0 != last.indexOf(key)) // 'zach' may be lexically larger than 'za', but there still might be more, like 'zane' in the 'za' prefix bucket so do not end here. - ){ - o.more = u; - as.ack(g.err, data, o); - return; - } - if(u !== data){ - as.ack(g.err, data, o); // more might be coming! - if(o.parsed >= o.limit){ return } // even if more, we've hit our limit, asking peer will need to make a new ask with a new starting point. - } - o.next = as.file; - r.read(key, as.ack, o); - } - g.check = function(err, disk, info){ - g.it(err, disk, info); - var good = true; - Radix.map(disk, function(val, key){ - // assume in memory for now, since both write/read already call r.find which will init it. - var go = function(file){ - if(info.file !== file){ - good = false - } - return true; - } - go.reverse = 1; - go.end = key; - r.list(go); - }); - if(good){ return } - var id = Gun.text.random(3); - r.save(disk, function ack(err, ok){ - if(err){ r.save(disk, ack); return } // ad infinitum??? - console.log("MISLOCATED DATA CORRECTED", id); - }); - } - /*g.check2 = function(err, disk, info){ - if(err || !disk){ g.it(err, disk, info); return } - var good = true; - Radix.map(disk, function(val, key){ - // assume in memory for now, since both write/read already call r.find which will init it. - var go = function(file){ - if(info.file !== file){ good = false } - return true; - } - go.reverse = 1; - go.end = key; - r.list(go); - }); - if(good){ g.it(err, disk, info); return } - var id = Gun.text.random(3); console.log("MISLOCATED DATA", id); - r.save(disk, function ack(err, ok){ - if(err){ r.save(disk, ack); return } // ad infinitum??? - console.log("MISLOCATED CORRECTED", id); - r.read(key, cb, o); - }); - }*/ - if(o.reverse){ g.lex.reverse = true } - LOG && (S = +new Date); - r.find(key, g.lex); - } - - r.read = function(key, cb, o){ - var g = {key: key}; - g.find = function(file){ var tmp; - g.file = file || (file = opt.code.from); // this may not be true for reads? Hit "end of dir"? - if(tmp = r.disk[file]){ g.check(u, tmp); return } - r.parse(file, g.check); - } - g.get = function(err, disk, info){ - if(err){ cb(err); return } - var file = g.file = (disk||'').file || g.file; - if(!disk && file !== opt.code.from){ // corrupt file? - r.find.bad(file); // remove from dir list - r.save(key, cb); // try again - return; - } - disk = r.disk[file] || (r.disk[file] = disk); - if(!disk){ cb(); return } - disk.file || (disk.file = file); - // ---------------------------- - info = info || {}; - var data = disk(key); - info.atom = disk.atom; - if(u !== data){ cb(u, data, info); return } - // ---------------------------- - return; - var S; LOG && (S = +new Date); - var rad = disk || noop, data = r.range(rad(key), o), last = rad.last || Radix.map(rad, rev, revo); - LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, "rad range loaded"); - o.parsed = (o.parsed || 0) + (info.parsed||0); - o.chunks = (o.chunks || 0) + 1; - o.more = true; - if((!as.file) // if no more places to look - || (!o.span && last === key) // if our key exactly matches the very last atomic record - || (!o.span && last && last > key && 0 != last.indexOf(key)) // 'zach' may be lexically larger than 'za', but there still might be more, like 'zane' in the 'za' prefix bucket so do not end here. - ){ - o.more = u; - as.ack(g.err, data, o); - return; - } - if(u !== data){ - as.ack(g.err, data, o); // more might be coming! - if(o.parsed >= o.limit){ return } // even if more, we've hit our limit, asking peer will need to make a new ask with a new starting point. - } - o.next = as.file; - r.read(key, as.ack, o); - } - g.check = function(err, disk, info){ - g.get(err, disk, info); - (info || (info = {})).file || (info.file = g.file); - Radix.map(disk, function(val, key){ - // assume in memory for now, since both write/read already call r.find which will init it. - r.find(key, function(file){ - if(file === info.file){ return } - var id = Gun.text.random(3); - console.log("MISLOCATED DATA", id, key, info.file, file); - r.save(key, val, function ack(err, ok){ - if(err){ r.save(key, val, ack); return } // ad infinitum??? - console.log("MISLOCATED DATA CORRECTED", id); - }); - }) - }); - } - r.find(key, g.find); - } - function rev(a,b){ return b } - var revo = {reverse: true}; - }()); - - ;(function(){ - /* - Let us start by assuming we are the only process that is - changing the directory or bucket. Not because we do not want - to be multi-process/machine, but because we want to experiment - with how much performance and scale we can get out of only one. - Then we can work on the harder problem of being multi-process. - */ - var RPC = 0; - var Q = {}, s = String.fromCharCode(31); - r.parse = function(file, cb, raw){ var q; - if(q = Q[file]){ q.push(cb); return } q = Q[file] = [cb]; - var p = function Parse(){}, info = {file: file}; - (p.disk = Radix()).file = file; - p.read = function(err, data){ var tmp; - LOG && opt.log(S, +new Date - S, 'read disk', JSON.stringify(file), ++RPC, 'total all parses.'); - delete Q[file]; - if((p.err = err) || (p.not = !data)){ map(q, p.ack); return } - if('string' !== typeof data){ - try{ - if(opt.pack <= data.length){ - p.err = "Chunk too big!"; - } else { - data = data.toString(); // If it crashes, it crashes here. How!?? We check size first! - } - }catch(e){ p.err = e } - if(p.err){ map(q, p.ack); return } - } - info.parsed = data.length; - LOG && (S = +new Date); - if(opt.jsonify || '{' === data[0]){ - try{ - var json = JSON.parse(data); // TODO: this caused a out-of-memory crash! - p.disk.$ = json; - LOG && (ST = +new Date - S) > 9 && opt.log(S, ST, 'rad parsed JSON'); - map(q, p.ack); - return; - }catch(e){ tmp = e } - if('{' === data[0]){ - p.err = tmp || "JSON error!"; - map(q, p.ack); - return; - } - } - p.radec(err, data); - } - p.ack = function(cb){ - if(!cb){ return } - if(p.err || p.not){ - cb(p.err, u, info); - return; - } - cb(u, p.disk, info); - } - p.radec = function(err, data){ - LOG && (S = +new Date); - var tmp = p.split(data), pre = [], i, k, v; - if(!tmp || 0 !== tmp[1]){ - p.err = "File '"+file+"' does not have root radix! "; - map(q, p.ack); - return; - } - while(tmp){ - k = v = u; - i = tmp[1]; - tmp = p.split(tmp[2])||''; - if('#' == tmp[0]){ - k = tmp[1]; - pre = pre.slice(0,i); - if(i <= pre.length){ - pre.push(k); - } - } - tmp = p.split(tmp[2])||''; - if('\n' == tmp[0]){ continue } - if('=' == tmp[0] || ':' == tmp[0]){ v = tmp[1] } - if(u !== k && u !== v){ p.disk(pre.join(''), v) } - tmp = p.split(tmp[2]); - } - LOG && opt.log(S, +new Date - S, 'parsed RAD'); - map(q, p.ack); - }; - p.split = function(t){ - if(!t){ return } - var l = [], o = {}, i = -1, a = '', b, c; - i = t.indexOf(s); - if(!t[i]){ return } - a = t.slice(0, i); - l[0] = a; - l[1] = b = Radisk.decode(t.slice(i), o); - l[2] = t.slice(i + o.i); - return l; - } - var S; LOG && (S = +new Date); - if(r.disk){ raw || (raw = (r.disk[file]||'').raw) } - if(raw){ return p.read(u, raw) } - opt.store.get(ename(file), p.read); - } - }()); - - ;(function(){ - var dir, f = String.fromCharCode(28), Q; - r.find = function(key, cb){ - if(!dir){ - if(Q){ Q.push([key, cb]); return } Q = [[key, cb]]; - r.parse(f, init); - return; - } - Radix.map(dir, function(val, key){ - if(!val){ return } - return cb(key) || true; - }, {reverse: 1, end: key}) || cb(); - } - r.find.add = function(file, cb){ - var has = dir(file); - if(has || file === f){ cb(u, 1); return } - dir(file, 1); - cb.found = (cb.found || 0) + 1; - r.write(f, dir, function(err, ok){ - if(err){ cb(err); return } - cb.found = (cb.found || 0) - 1; - if(0 !== cb.found){ return } - cb(u, 1); - }, true); - } - r.find.bad = function(file, cb){ - dir(file, 0); - r.write(f, dir, cb||noop); - } - function init(err, disk){ - if(err){ - opt.log('list', err); - setTimeout(function(){ r.parse(f, init) }, 1000); - return; - } - if(disk){ drain(disk); return } - dir = dir || disk || Radix(); - if(!opt.store.list){ drain(dir); return } - // import directory. - opt.store.list(function(file){ - if(!file){ drain(dir); return } - r.find.add(file, noop); - }); - } - function drain(rad, tmp){ - dir = dir || rad; - dir.file = f; - tmp = Q; Q = null; - Gun.list.map(tmp, function(arg){ - r.find(arg[0], arg[1]); - }); - } - }()); - - var noop = function(){}, RAD, u; - Radisk.has[opt.file] = r; - return r; - } - - ;(function(){ - var _ = String.fromCharCode(31), u; - Radisk.encode = function(d, o, s){ s = s || _; - var t = s, tmp; - if(typeof d == 'string'){ - var i = d.indexOf(s); - while(i != -1){ t += s; i = d.indexOf(s, i+1) } - return t + '"' + d + s; - } else - if(d && d['#'] && (tmp = Gun.val.link.is(d))){ - return t + '#' + tmp + t; - } else - if(Gun.num.is(d)){ - return t + '+' + (d||0) + t; - } else - if(null === d){ - return t + ' ' + t; - } else - if(true === d){ - return t + '+' + t; - } else - if(false === d){ - return t + '-' + t; - }// else - //if(binary){} - } - Radisk.decode = function(t, o, s){ s = s || _; - var d = '', i = -1, n = 0, c, p; - if(s !== t[0]){ return } - while(s === t[++i]){ ++n } - p = t[c = n] || true; - while(--n >= 0){ i = t.indexOf(s, i+1) } - if(i == -1){ i = t.length } - d = t.slice(c+1, i); - if(o){ o.i = i+1 } - if('"' === p){ - return d; - } else - if('#' === p){ - return Gun.val.link.ify(d); - } else - if('+' === p){ - if(0 === d.length){ - return true; - } - return parseFloat(d); - } else - if(' ' === p){ - return null; - } else - if('-' === p){ - return false; - } - } - }()); - - if(typeof window !== "undefined"){ - var Gun = window.Gun; - var Radix = window.Radix; - window.Radisk = Radisk; - } else { - var Gun = require('../gun'); - var Radix = require('./radix'); - //var Radix = require('./radix2'); Radisk = require('./radisk2'); - try{ module.exports = Radisk }catch(e){} - } - - Radisk.Radix = Radix; - -}()); \ No newline at end of file diff --git a/lib/radix.js b/lib/radix.js index f33bc4b3..1d28b46a 100644 --- a/lib/radix.js +++ b/lib/radix.js @@ -2,13 +2,13 @@ function Radix(){ var radix = function(key, val, t){ - radix.atom = 0; + radix.unit = 0; if(!t && u !== val){ radix.last = (''+key < radix.last)? radix.last : ''+key; delete (radix.$||{})[_]; } t = t || radix.$ || (radix.$ = {}); - if(!key && Object.keys(t).length){ console.log('wat?', t, key); return t } + if(!key && Object.keys(t).length){ return t } key = ''+key; var i = 0, l = key.length-1, k = key[i], at, tmp; while(!(at = t[k]) && i < l){ @@ -48,7 +48,7 @@ } else if(i == l){ //if(u === val){ return (u === (tmp = at['']))? at : tmp } // THIS CODE IS CORRECT, below is - if(u === val){ return (u === (tmp = at['']))? at : ((radix.atom = 1) && tmp) } // temporary help?? + if(u === val){ return (u === (tmp = at['']))? at : ((radix.unit = 1) && tmp) } // temporary help?? at[''] = val; //(at[_] = function $(){ $.sort = Object.keys(at).sort(); return $ }()); } else { diff --git a/lib/rfs.js b/lib/rfs.js index 705ae88a..f66ddb4c 100644 --- a/lib/rfs.js +++ b/lib/rfs.js @@ -12,6 +12,7 @@ function Store(opt){ Store[opt.file] = store; var puts = {}; + // TODO!!! ADD ZLIB INFLATE / DEFLATE COMPRESSION! store.put = function(file, data, cb){ puts[file] = data; var random = Math.random().toString(36).slice(-3); @@ -29,7 +30,7 @@ function Store(opt){ if('ENOENT' === (err.code||'').toUpperCase()){ return cb(); } - opt.log("ERROR:", err) + opt.log("ERROR:", err); } cb(err, data); }); diff --git a/lib/store.js b/lib/store.js index 1ca48d89..4e17c809 100644 --- a/lib/store.js +++ b/lib/store.js @@ -6,13 +6,11 @@ Gun.on('create', function(root){ var opt = root.opt, empty = {}, u; if(false === opt.radisk){ return } var Radisk = (Gun.window && Gun.window.Radisk) || require('./radisk'); - var Radiskip = (Gun.window && Gun.window.Radisk) || require('./radiskip'); var Radix = Radisk.Radix; var LOG = console.LOG, ST = 0; opt.store = opt.store || (!Gun.window && require('./rfs')(opt)); - var rad = Radisk(opt), esc = String.fromCharCode(27); - var dare = Radiskip(opt); + var dare = Radisk(opt), esc = String.fromCharCode(27); root.on('put2', function(msg){ this.to.next(msg); @@ -31,8 +29,7 @@ Gun.on('create', function(root){ var _ = (msg._||''), got = _.rad; if(got){ return } // RAD's own ACKs to GETs do not need to be written to disk again. if(_.ram){ return } // in-memory ACKs to GETs do not need to be written to disk again. - root.on('in', {'@': msg['#'], err: 'Migration not done, please report this to & complain at Mark in http://chat.gun.eco !'}); - return; + if(true || !Gun.TESTING){ root.on('in', {'@': msg['#'], err: console.log('Migration not done, please report this to & complain at Mark in http://chat.gun.eco !')}); return } var S = (+new Date), C = 0; // STATS! var now = Gun.state(); Gun.graph.is(msg.put, null, function(val, key, node, soul){ @@ -45,9 +42,9 @@ Gun.on('create', function(root){ return; } if(track){ ++acks } - //console.log('put:', soul, key, val); - val = Radisk.encode(val, null, esc)+'>'+Radisk.encode(Gun.state.is(node, key), null, esc); - rad(soul+esc+key, val, (track? ack : u)); + dare(soul+esc+key, {':': val, '>': Gun.state.is(node, key)}, (track? ack : u)); + //val = Radisk.encode(val, null, esc)+'>'+Radisk.encode(Gun.state.is(node, key), null, esc); + //rad(soul+esc+key, val, (track? ack : u)); C++; }); if(LOG && (ST = +new Date - S) > 9){ Gun.log(S, ST, 'put loop'); Gun.log(S, C, 'put loop #') } @@ -107,16 +104,18 @@ Gun.on('create', function(root){ var now = Gun.state(); var S = (+new Date), C = 0; // STATS! //rad(key||'', function(err, data, o){ + //console.log("STORE GET:", JSON.stringify(key||''), o); dare(key||'', function(err, data, info){ + //console.log("STORE GOT:", data); try{opt.store.stats.get.time[statg % 50] = (+new Date) - S; ++statg; opt.store.stats.get.count++; if(err){ opt.store.stats.get.err = err } }catch(e){} // STATS! //if(u === data && info.chunks > 1){ return } // if we already sent a chunk, ignore ending empty responses. // this causes tests to fail. LOG && Gun.log(S, +new Date - S, 'got', JSON.stringify(key)); S = +new Date; - info = info || {}; + info = info || ''; var va, ve; - if(info.atom && data && u !== (va = data[':']) && u !== (ve = data['>'])){ // new format + if(info.unit && data && u !== (va = data[':']) && u !== (ve = data['>'])){ // new format var tmp = key.split(esc), so = tmp[0], ha = tmp[1]; (graph = graph || {})[so] = Gun.state.ify(graph[so], ha, ve, va, so); root.$.get(so).get(ha)._.rad = now; @@ -134,7 +133,6 @@ Gun.on('create', function(root){ } console.STAT && (console.STAT.radgetcount = C); if(LOG && (ST = +new Date - S) > 9){ Gun.log(S, ST, 'got prep time'); Gun.log(S, C, 'got prep #') } C = 0; S = +new Date; - //console.log("STORE GOT:", graph); var faith = function(){}; faith.faith = true; faith.rad = get; // HNPERF: We're testing performance improvement by skipping going through security again, but this should be audited. root.on('in', {'@': id, put: graph, '%': info.more? 1 : u, err: err? err : u, _: faith}); LOG && (ST = +new Date - S) > 9 && Gun.log(S, ST, 'got emit', Object.keys(graph||{}).length); @@ -150,8 +148,11 @@ Gun.on('create', function(root){ has = has.slice(-1)[0]; if(o.limit && o.limit <= o.count){ return true } var va, ve, so = soul, ha = has; - if((va = val[':']) && (ve = val['>'])){ // THIS HANDLES NEW CODE! + //if(u !== (va = val[':']) && u !== (ve = val['>'])){ // THIS HANDLES NEW CODE! + if('string' != typeof val){ // THIS HANDLES NEW CODE! + va = val[':']; ve = val['>']; (graph = graph || {})[so] = Gun.state.ify(graph[so], ha, ve, va, so); + //root.$.get(so).get(ha)._.rad = now; o.count = (o.count || 0) + ((va||'').length || 9); return; } diff --git a/sea.js b/sea.js index 3730fc21..7c062d12 100644 --- a/sea.js +++ b/sea.js @@ -439,7 +439,7 @@ opt = opt || {}; // SEA.I // verify is free! Requires no user permission. var pub = pair.pub || pair; - var key = SEA.opt.slow_leak? await SEA.opt.slow_leak(pub) : await (shim.ossl || shim.subtle).importKey('jwk', jwk, {name: 'ECDSA', namedCurve: 'P-256'}, false, ['verify']); + var key = SEA.opt.slow_leak? await SEA.opt.slow_leak(pub) : await (shim.ossl || shim.subtle).importKey('jwk', S.jwk(pub), {name: 'ECDSA', namedCurve: 'P-256'}, false, ['verify']); var hash = await sha(json.m); var buf, sig, check, tmp; try{ buf = shim.Buffer.from(json.s, opt.encode || 'base64'); // NEW DEFAULT! @@ -474,9 +474,11 @@ return knownKeys[pair]; }; - + var O = SEA.opt; SEA.opt.fall_verify = async function(data, pair, cb, opt, f){ if(f === SEA.opt.fallback){ throw "Signature did not match" } f = f || 1; + var tmp = data||''; + data = SEA.opt.unpack(data) || data; var json = S.parse(data), pub = pair.pub || pair, key = await SEA.opt.slow_leak(pub); var hash = (f <= SEA.opt.fallback)? shim.Buffer.from(await shim.subtle.digest({name: 'SHA-256'}, new shim.TextEncoder().encode(S.parse(json.m)))) : await sha(json.m); // this line is old bad buggy code but necessary for old compatibility. var buf; var sig; var check; try{ @@ -491,6 +493,7 @@ if(!check){ throw "Signature did not match." } } var r = check? S.parse(json.m) : u; + O.fall_soul = tmp['#']; O.fall_key = tmp['.']; O.fall_val = data; O.fall_state = tmp['>']; if(cb){ try{ cb(r) }catch(e){console.log(e)} } return r; } @@ -1099,7 +1102,7 @@ if(!at.sea){ // only add SEA once per instance, on the "at" context. at.sea = {own: {}}; at.on('in', security, at); // now listen to all input data, acting as a firewall. - at.on('out', signature, at); // and output listeners, to encrypt outgoing data. + //at.on('out', signature, at); // and output listeners, to encrypt outgoing data. at.on('node', each, at); at.on('put2', check, at); } @@ -1165,10 +1168,11 @@ if('~@' === soul.slice(0,2)){ // special case for shared system data, the list of public keys for an alias. check.pubs(eve, msg, val, key, soul, at, no); return; } - if('~' === soul.slice(0,1) && 2 === (tmp = soul.slice(1)).split('.').length){ // special case, account data for a public key. - check.pub(eve, msg, val, key, soul, at, no, (msg._||'').user, tmp); return; + //if('~' === soul.slice(0,1) && 2 === (tmp = soul.slice(1)).split('.').length){ // special case, account data for a public key. + if(tmp = SEA.opt.pub(soul)){ // special case, account data for a public key. + check.pub(eve, msg, val, key, soul, at, no, at.user||'', tmp); return; } - check.any(eve, msg, val, key, soul, at, no, (msg._||'noop').user); return; + check.any(eve, msg, val, key, soul, at, no, at.user||''); return; eve.to.next(msg); // not handled } check.hash = function(eve, msg, val, key, soul, at, no){ @@ -1192,59 +1196,34 @@ if(val === pub){ return eve.to.next(msg) } // the account MUST match `pub` property that equals the ID of the public key. return no("Account not same!"); } - if(Gun.is(msg.$) && user && user.is && pub === user.is.pub){ - SEA.sign(msg.put, (user._).sea, function(data){ var rel; + if((tmp = user.is) && pub === tmp.pub){ + SEA.sign(SEA.opt.pack(msg.put), (user._).sea, function(data){ if(u === data){ return no(SEA.err || 'Signature fail.') } - if(rel = link_is(val)){ (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = 1 } - console.log("WHAT HAPPENS HERE?", data.m, SEA.opt.unpack(data.m), key, soul); - msg.put[':'] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); - //node[key] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); + if(tmp = link_is(val)){ (at.sea.own[tmp] = at.sea.own[tmp] || {})[pub] = 1 } + msg.put[':'] = JSON.stringify({':': tmp = SEA.opt.unpack(data.m), '~': data.s}); + msg.put['='] = tmp; eve.to.next(msg); - }, {check: msg.put, raw: 1}); + }, {raw: 1}); return; } - SEA.verify(msg.put, pub, function(data){ var rel, tmp; - console.log("WHAT VERIFIES HERE?", data, SEA.opt.unpack(data, key), key, soul); - data = SEA.opt.unpack(data, key); + SEA.verify(SEA.opt.pack(msg.put), pub, function(data){ var tmp; + data = SEA.opt.unpack(data); if(u === data){ return no("Unverified data.") } // make sure the signature matches the account it claims to be on. // reject any updates that are signed with a mismatched account. - if((rel = link_is(data)) && pub === SEA.opt.pub(rel)){ - (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = 1; - } + if((tmp = link_is(data)) && pub === SEA.opt.pub(tmp)){ (at.sea.own[tmp] = at.sea.own[tmp] || {})[pub] = 1 } + msg.put['='] = data; eve.to.next(msg); }); }; check.any = function(eve, msg, val, key, soul, at, no, user){ var tmp, pub; - if(!(pub = SEA.opt.pub(soul))){ - if(at.opt.secure){ return no("Soul missing public key at '" + key + "'.") } - // TODO: Ask community if should auto-sign non user-graph data. - at.on('secure', function(msg){ this.off(); - if(!at.opt.secure){ return eve.to.next(msg) } - no("Data cannot be changed."); - }).on.on('secure', msg); - return; - } - // TODO: DEDUP WITH check.pub ??? - if(Gun.is(msg.$) && user && user.is && pub === user.is.pub){ - SEA.sign(mgs.put, (user._).sea, function(data){ - if(u === data){ return no('User signature fail.') } - console.log("WHAT HAPPENS HERE??", data.m, SEA.opt.unpack(data.m), key, soul); - msg.put[':'] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); - //node[key] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); - eve.to.next(msg); - }, {check: msg.put, raw: 1}); - return; - } - SEA.verify(msg.put, pub, function(data){ var rel; - console.log("WHAT VERIFIES HERE?", data, SEA.opt.unpack(data, key), key, soul); - data = SEA.opt.unpack(data, key); - if(u === data){ return no("Not owner on '" + key + "'.") } // thanks @rogowski ! - if((rel = link_is(data)) && pub === SEA.opt.pub(rel)){ - (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = 1; - } - eve.to.next(msg); - }); + if(at.opt.secure){ return no("Soul missing public key at '" + key + "'.") } + // TODO: Ask community if should auto-sign non user-graph data. + at.on('secure', function(msg){ this.off(); + if(!at.opt.secure){ return eve.to.next(msg) } + no("Data cannot be changed."); + }).on.on('secure', msg); + return; } - var link_is = Gun.val.link.is; + var link_is = Gun.val.link.is, state_ify = Gun.state.ify; // okay! The security function handles all the heavy lifting. // It needs to deal read and write of input and output of system data, account/public key data, and regular data. @@ -1408,6 +1387,7 @@ if(!s || !(s = s[1])){ return } s = s.split('.'); if(!s || 2 > s.length){ return } + if('@' === (s[0]||'')[0]){ return } // TODO: Should check ~X.Y. are alphanumeric, not just not @. s = s.slice(0,2).join('.'); return s; } @@ -1416,16 +1396,18 @@ } SEA.opt.pack = function(d,k, n,s){ // pack for verifying if(SEA.opt.check(d)){ return d } - var meta = (Gun.obj.ify(d)||noop), sig = meta['~']; - return sig? {m: {'#':s,'.':k,':':meta[':'],'>':Gun.state.is(n, k)}, s: sig} : d; + var meta = (Gun.obj.ify(d)||''), sig = meta['~']; + return sig? {m: {'#':s||d['#'],'.':k||d['.'],':':meta[':'],'>':d['>']||Gun.state.is(n, k)}, s: sig} : d; } + var O = SEA.opt; SEA.opt.unpack = function(d, k, n){ var tmp; if(u === d){ return } if(d && (u !== (tmp = d[':']))){ return tmp } + k = k || O.fall_key; if(!n && O.fall_val){ n = {}; n[k] = O.fall_val } if(!k || !n){ return } if(d === n[k]){ return d } if(!SEA.opt.check(n[k])){ return d } - var soul = Gun.node.soul(n), s = Gun.state.is(n, k); + var soul = Gun.node.soul(n) || O.fall_soul, s = Gun.state.is(n, k) || O.fall_state; if(d && 4 === d.length && soul === d[0] && k === d[1] && fl(s) === fl(d[3])){ return d[2]; } @@ -1437,6 +1419,7 @@ var noop = function(){}, u; var fl = Math.floor; // TODO: Still need to fix inconsistent state issue. var rel_is = Gun.val.rel.is; + var obj_ify = Gun.obj.ify; // TODO: Potential bug? If pub/priv key starts with `-`? IDK how possible. })(USE, './index'); diff --git a/test/common.js b/test/common.js index 91f6615b..1cf70726 100644 --- a/test/common.js +++ b/test/common.js @@ -1279,6 +1279,14 @@ describe('Gun', function(){ this.to.next(root); });*/ } + Gun.on('create', function(root){ + root.on('test', function(msg){ + var put = msg.put; + this.to.next(msg); + root.on('out', msg); + Gun.graph.is(put, function(n,s){ root.$.get(s).off() }); + }) + }) var gun = Gun(); it.skip('gun chain separation', function(done){ // TODO: UNDO! @@ -1397,8 +1405,7 @@ describe('Gun', function(){ - Performant read lock on write contexts. - Proxying event across maps. */ - var s = Gun.state.map();s.soul = 'u/m'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: { age: 26, name: "Alice", @@ -1409,7 +1416,7 @@ describe('Gun', function(){ name: "Bob!", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m')}); var check = {}, count = {}; gun.get('u/m').map().on(function(v,f){ check[f] = v; @@ -1433,8 +1440,7 @@ describe('Gun', function(){ }); it('uncached synchronous map get on', function(done){ - var s = Gun.state.map();s.soul = 'u/m/p'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: { age: 26, name: "alice", @@ -1445,7 +1451,7 @@ describe('Gun', function(){ name: "bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/p')}); var check = {}, count = {}; gun.get('u/m/p').map().get('name').on(function(v,f){ //console.log("*****************", f, v); @@ -1465,8 +1471,7 @@ describe('Gun', function(){ }); it('uncached synchronous map get on node', function(done){ - var s = Gun.state.map();s.soul = 'u/m/p/n'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: { age: 26, name: "alice", @@ -1477,7 +1482,7 @@ describe('Gun', function(){ name: "bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/p/n')}); var check = {}, count = {}; gun.get('u/m/p/n').map().get('pet').on(function(v,f){ //console.log("********************", f,v); @@ -1500,8 +1505,7 @@ describe('Gun', function(){ it('uncached synchronous map get on node get', function(done){ var gun = Gun(); - var s = Gun.state.map();s.soul = 'u/m/p/n/p'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: { age: 26, name: "alice", @@ -1512,7 +1516,7 @@ describe('Gun', function(){ name: "bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/p/n/p')}); var check = {}, count = {}; //console.debug.i=1;console.log('-------------------'); gun.get('u/m/p/n/p').map().get('pet').get('name').on(function(v,f){ @@ -1539,8 +1543,7 @@ describe('Gun', function(){ }); it('uncached synchronous map on mutate', function(done){ - var s = Gun.state.map();s.soul = 'u/m/mutate'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: { age: 26, name: "Alice", @@ -1551,7 +1554,7 @@ describe('Gun', function(){ name: "Bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/mutate')}); var check = {}, count = {}; gun.get('u/m/mutate').map().get('name').get(function(at,ev){ var e = at.err, v = at.put, f = at.get; @@ -1575,8 +1578,7 @@ describe('Gun', function(){ }); it('uncached synchronous map on mutate node', function(done){ - var s = Gun.state.map();s.soul = 'u/m/mutate/n'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: {_:{'#':'umaliceo'}, age: 26, name: "Alice", @@ -1587,7 +1589,7 @@ describe('Gun', function(){ name: "Bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/mutate/n')}); var check = {}, count = {}; gun.get('u/m/mutate/n').map().get('name').get(function(at,ev){ var e = at.err, v = at.put, f = at.get; @@ -1622,8 +1624,7 @@ describe('Gun', function(){ }); it('uncached synchronous map on mutate node uncached', function(done){ - var s = Gun.state.map();s.soul = 'u/m/mutate/n/u'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: {_:{'#':'umaliceo1'}, age: 26, name: "Alice", @@ -1634,7 +1635,7 @@ describe('Gun', function(){ name: "Bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/mutate/n/u')}); var check = {}, count = {}; gun.get('u/m/mutate/n/u').map().on(function(v,f){ check[v.name] = f; @@ -1654,10 +1655,9 @@ describe('Gun', function(){ } }); setTimeout(function(){ - var s = Gun.state.map();s.soul = 'u/m/m/n/u/soul'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ name: 'Alice Zzxyz' - }, s)}); + }, Gun.state.map(), 'u/m/m/n/u/soul')}); //console.debug.i=1;console.log("---------------"); gun.get('u/m/mutate/n/u').put({ alice: {'#':'u/m/m/n/u/soul'}, @@ -1679,8 +1679,7 @@ describe('Gun', function(){ }); it('uncached synchronous map on get mutate node uncached', function(done){ - var s = Gun.state.map();s.soul = 'u/m/p/mutate/n/u'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: {_:{'#':'umaliceo2'}, age: 26, name: "Alice", @@ -1691,7 +1690,7 @@ describe('Gun', function(){ name: "Bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/p/mutate/n/u')}); var check = {}, count = {}; gun.get('u/m/p/mutate/n/u').map().get('name').on(function(v,f){ check[v] = f; @@ -1712,10 +1711,9 @@ describe('Gun', function(){ } }); setTimeout(function(){ - var s = Gun.state.map();s.soul = 'u/m/p/m/n/u/soul'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ name: 'Alice Zzxyz', age: 34 - }, s)}); + }, Gun.state.map(), 'u/m/p/m/n/u/soul')}); gun.get('u/m/p/mutate/n/u').put({ alice: {'#':'u/m/p/m/n/u/soul'}, }); @@ -1729,8 +1727,7 @@ describe('Gun', function(){ }); it('uncached synchronous map on get node mutate node uncached', function(done){ - var s = Gun.state.map();s.soul = 'u/m/p/n/mutate/n/u'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alice: {_:{'#':'umaliceo3'}, age: 26, name: "Alice", @@ -1741,7 +1738,7 @@ describe('Gun', function(){ name: "Bob", pet: {b:2, name: "Frisky"} } - }, s)}); + }, Gun.state.map(), 'u/m/p/n/mutate/n/u')}); var check = {}, count = {}; gun.get('u/m/p/n/mutate/n/u').map().get('pet').on(function(v,f){ check[v.name] = f; @@ -1760,11 +1757,10 @@ describe('Gun', function(){ } }); setTimeout(function(){ - var s = Gun.state.map();s.soul = 'alice/fuzz/soul'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ name: 'Alice Zzxyz', age: 34, pet: {c:3, name: "Fuzzball"} - }, s)}); + }, Gun.state.map(), 'alice/fuzz/soul')}); gun.get('u/m/p/n/mutate/n/u').put({ alice: {'#':'alice/fuzz/soul'}, }); @@ -2844,15 +2840,13 @@ describe('Gun', function(){ }); it('get node after recursive field', function(done){ - var s = Gun.state.map();s.soul = 'node/circle'; var bob = {age: 29, name: "Bob!"}; var cat = {name: "Fluffy", species: "kitty"}; var user = {bob: bob}; bob.pet = cat; cat.slave = bob; - gun.on('put', {$: gun, put: Gun.graph.ify(user, s)}); - //console.debug.i=1;console.log("-------------"); - gun.get(s.soul).get('bob').get('pet').get('slave').once(function(data){ + gun.on('test', {$: gun, put: Gun.graph.ify(user, Gun.state.map(), 'node/circle')}); + gun.get('node/circle').get('bob').get('pet').get('slave').once(function(data){ //clearTimeout(done.to); //setTimeout(function(){ //console.log("*****************", data);return; @@ -2945,7 +2939,9 @@ describe('Gun', function(){ list.set(gun.get('dave').put({name: "Dave", group: "awesome", married: true})); var check = {}, count = {}; - list.map().once(function(data, id){ + //console.log("==============================="); + //console.only.i=1; + list.map().on(function(data, id){ //console.log("***************", id, data); check[id] = data; count[id] = (count[id] || 0) + 1; @@ -3090,13 +3086,12 @@ describe('Gun', function(){ }); it('get get get any parallel', function(done){ - var s = Gun.state.map();s.soul = 'parallel'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!" } - }, s)}); + }, Gun.state.map(), 'parallel')}); gun.get('parallel').get('bob').get('age').get(function(at, ev){ var err = at.err, data = at.put, field = at.get; //console.log("***** age", data, at.$._.ack);//return; @@ -3117,13 +3112,12 @@ describe('Gun', function(){ }); it('get get get any later', function(done){ - var s = Gun.state.map();s.soul = 'parallel/later'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ bob: {_:{'#':'ddfsa'}, age: 29, name: "Bob!" } - }, s)}); + }, Gun.state.map(), 'parallel/later')}); gun.get('parallel/later').get('bob').get('age').get(function(at, ev){ var err = at.err, data = at.put, field = at.get; //console.log("***** age", data); @@ -3189,11 +3183,10 @@ describe('Gun', function(){ }); it('get any any', function(done){ - var s = Gun.state.map();s.soul = 'full'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ hello: 'world', goodbye: 'mars' - }, s)}); + }, Gun.state.map(), 'full')}); gun.get('full').get(function(at, ev){ var err = at.err, data = at.$._.put || at.put, field = at.get; //console.log("*****1", data); @@ -3211,11 +3204,10 @@ describe('Gun', function(){ }); it('get any any later', function(done){ - var s = Gun.state.map();s.soul = 'full/later'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ hello: 'world', goodbye: 'mars' - }, s)}); + }, Gun.state.map(), 'full/later')}); gun.get('full/later').get(function(at, ev){ var err = at.err, data = at.$._.put || at.put, field = at.get; //console.log("*****", data); @@ -3303,8 +3295,7 @@ describe('Gun', function(){ it('multiple times partial', function(done){ var gun = Gun(); - var s = Gun.state.map();s.soul = 'mult/times/part'; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ alias: { mark: { pub: {_:{'#':'PUB'}, @@ -3314,9 +3305,9 @@ describe('Gun', function(){ } } } - }, s)}); + }, Gun.state.map(), 'mult/times/part')}); - var app = gun.get(s.soul); + var app = gun.get('mult/times/part'); //console.debug.i=1;console.log("==================="); app.get('alias').get('mark').map().once(function(alias){ @@ -3457,6 +3448,7 @@ describe('Gun', function(){ list.get('message').put('hello world'); // outputs "message: hello world" list.get('message').put(null); // throws Uncaught TypeError: Cannot read property '#' of null }); + return; it('Check multi instance message passing', function(done){ try{ require('fs').unlinkSync('bdata') }catch(e){} @@ -3541,10 +3533,10 @@ describe('Gun', function(){ it('If chain cannot be called, ack', function(done){ var gun = Gun(), u; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ wat: 1, a: true - }, 'nl/app')}); + }, Gun.state.map(), 'nl/app')}); // prev had no state_map? var app = gun.get('nl/app'); @@ -3565,11 +3557,11 @@ describe('Gun', function(){ it('Chain on known nested object should ack', function(done){ var gun = Gun(), u; - gun.on('put', {$: gun, put: Gun.graph.ify({ + gun.on('test', {$: gun, put: Gun.graph.ify({ bar: { wat: 1 } - }, 'nl/app')}); + }, Gun.state.map(), 'nl/app')}); var app = gun.get('nl/app').get('bar'); @@ -3953,13 +3945,12 @@ describe('Gun', function(){ });return; it('get get any parallel', function(done){ - var s = Gun.state.map();s.soul = 'parallel/get/get'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!" } - }, s)}); + }, Gun.state.map(), 'parallel/get/get')}); gun.get('parallel/get/get').path('bob').any(function(err, data, field, at, ev){ //console.log("***** 1", data); expect(data.age).to.be(29); @@ -3974,13 +3965,12 @@ describe('Gun', function(){ }); it('get get any parallel later', function(done){ - var s = Gun.state.map();s.soul = 'parallel/get/get/later'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!" } - }, s)}); + }, Gun.state.map(), 'parallel/get/get/later')}); gun.get('parallel/get/get/later').path('bob').any(function(err, data, field, at, ev){ //console.log("***** 1", data); expect(data.age).to.be(29); @@ -3997,13 +3987,12 @@ describe('Gun', function(){ }); it('get get any none', function(done){ - var s = Gun.state.map();s.soul = 'get/get/none'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ alice: { age: 31, name: "alice" } - }, s)}); + }, Gun.state.map(), 'get/get/none')}); var c = 0, s = 0; gun.get('get/get/none').path('bob').any(function(err, data, field, at, ev){ //console.log("***** 1", data); @@ -4025,13 +4014,12 @@ describe('Gun', function(){ }); it('get get any none later', function(done){ - var s = Gun.state.map();s.soul = 'get/get/none/later'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ alice: { age: 31, name: "alice" } - }, s)}); + }, Gun.state.map(), 'get/get/none/later')}); var c = 0; gun.get('get/get/none/later').path('bob').any(function(err, data, field, at, ev){ //console.log("***** 1", data); @@ -4051,10 +4039,9 @@ describe('Gun', function(){ }); it('get get primitive get any', function(done){ - var s = Gun.state.map();s.soul = 'get/get/prim'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: "is awesome" - }, s)}); + }, Gun.state.map(), 'get/get/prim')}); gun.get('get/get/prim').path('bob').path('age').any(function(err, data, field, at, ev){ //console.log("***** 1", data); expect(data).to.be(undefined); @@ -4067,10 +4054,9 @@ describe('Gun', function(){ }); it('get put any', function(done){ - var s = Gun.state.map();s.soul = 'get/put/any'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ here: "we go" - }, s)}); + }, Gun.state.map(), 'get/put/any')}); //console.debug.i=1;console.log("---------------"); gun.get('get/put/any') .put({}) @@ -4081,10 +4067,9 @@ describe('Gun', function(){ }); return; it('get any, get put any', function(done){ - var s = Gun.state.map();s.soul = 'get/any/get/put/any'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ here: "we go" - }, s)}); + }, Gun.state.map(), 'get/any/get/put/any')}); gun.get('get/any/get/put/any') .any(function(err, data, field, at, ev){ if(done.first){ return } // it is okay for `any` to get called multiple times. @@ -4110,8 +4095,7 @@ describe('Gun', function(){ }); it('mutate pointer to primitive deep on', function(done){ - var s = Gun.state.map();s.soul = 'change/pointer'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4120,7 +4104,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'change/pointer')}); gun.get('change/pointer').path('bob').path('pet').any(function(err, data, f, at, ev){ //console.log("***", data);return setTimeout(function(){asdf},500); if(done.c){ @@ -4159,8 +4143,7 @@ describe('Gun', function(){ }); it('get only soul', function(done){ - var s = Gun.state.map();s.soul = 'only/soul'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4169,7 +4152,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'only/soul')}); gun.get('only/soul')/*.path('bob')*/.any(function(err, data){ expect(Gun.obj.empty(data, '_')).to.be.ok(); done(); @@ -4177,8 +4160,7 @@ describe('Gun', function(){ }); it('get path only soul', function(done){ - var s = Gun.state.map();s.soul = 'only/p/soul'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4187,7 +4169,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'only/p/soul')}); gun.get('only/p/soul').path('bob').any(function(err, data){ //console.log("*********", err, data); expect(Gun.val.link.is(data)).to.be.ok(); @@ -4197,8 +4179,7 @@ describe('Gun', function(){ }); it('mutate pointer to self', function(done){ - var s = Gun.state.map();s.soul = 'change/pointer/point'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4207,7 +4188,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'change/pointer/point')}); gun.get('change/pointer/point').path('bob').any(function(err, data){ if(done.c){ expect(data.age).to.be(30); @@ -4228,8 +4209,7 @@ describe('Gun', function(){ },400); }); it('mutate pointer to self deep', function(done){ - var s = Gun.state.map();s.soul = 'change/pointer/point/deep'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4238,7 +4218,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'change/pointer/point/deep')}); gun.get('change/pointer/point/deep').path('bob').any(function(err, data){ //console.log("***", data); if(done.c){ @@ -4259,8 +4239,7 @@ describe('Gun', function(){ }); it('mutate pointer to primitive after any', function(done){ - var s = Gun.state.map();s.soul = 'change/pointer/to/prime'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: {_: {'#': 'asdffdsa'}, age: 29, name: "Bob!", @@ -4269,7 +4248,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'change/pointer/to/prime')}); var bob = gun.get('asdffdsa').any(function(err, data){ //console.log("***", data); }); @@ -4294,8 +4273,7 @@ describe('Gun', function(){ }); it('mutate pointer to primitive after any deep', function(done){ - var s = Gun.state.map();s.soul = 'change/pointer/to/prime/deep'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: { age: 29, name: "Bob!", @@ -4304,7 +4282,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'change/pointer/to/prime/deep')}); var cat = gun.get('sadffads').any(function(err, data){ //console.log("***", data); }); @@ -4328,8 +4306,7 @@ describe('Gun', function(){ }); return; it.only('mutate pointer to another pointer after any', function(done){ - var s = Gun.state.map();s.soul = 'change/pointer/to/pointer'; - Gun.on('put', {$: gun, put: Gun.graph.ify({ + Gun.on('test', {$: gun, put: Gun.graph.ify({ bob: {_: {'#': 'dafssfad'}, age: 29, name: "Bob!", @@ -4338,7 +4315,7 @@ describe('Gun', function(){ species: "kitty" } } - }, s)}); + }, Gun.state.map(), 'change/pointer/to/pointer')}); var bob = gun.get('dafssfad').any(function(err, data){ console.log("***", data); }); @@ -4929,9 +4906,7 @@ describe('Gun', function(){ }); it('get get not', function(done){ - var s = Gun.state.map(); - s.soul = 'a'; - Gun.on('put', {$: gun, put: Gun.graph.ify({b: 1, c: 2}, s)}); + Gun.on('test', {$: gun, put: Gun.graph.ify({b: 1, c: 2}, Gun.state.map(), 'a')}); function cb(e,d,f,a){ if('b' === f && 1 === d){ done.b = true; diff --git a/test/mocha.html b/test/mocha.html index 13bcf7a4..e5af40c4 100644 --- a/test/mocha.html +++ b/test/mocha.html @@ -17,12 +17,7 @@ - - + diff --git a/test/rad/bench.js b/test/rad/bench.js index d9c00b6e..c03a6a80 100644 --- a/test/rad/bench.js +++ b/test/rad/bench.js @@ -1,6 +1,6 @@ var Gun = (typeof window !== "undefined")? window.Gun : require('../../../gun/gun'); -var Radisk = (Gun.window && window.Radisk) || require('../../../gun/lib/radiskip'); +var Radisk = (Gun.window && window.Radisk) || require('../../../gun/lib/radisk'); Gun.TESTING = true; try{localStorage.clear()}catch(e){} try{indexedDB.deleteDatabase('radatatest');}catch(e){} diff --git a/test/rad/browser.html b/test/rad/browser.html index 087c3cfd..3821b567 100644 --- a/test/rad/browser.html +++ b/test/rad/browser.html @@ -4,8 +4,7 @@ - - + diff --git a/test/rad/rad.js b/test/rad/rad.js index eef442aa..28c91dba 100644 --- a/test/rad/rad.js +++ b/test/rad/rad.js @@ -43,7 +43,7 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam //console.log("HYPER TEST");var z = 10000; while(--z){ names.push(Gun.text.random(7)) }this.timeout(9000); - describe.only('Radix', function(){ + describe('Radix', function(){ var radix = Radix(); it('unit', function(){ @@ -264,6 +264,7 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam if(v.indexOf(find) == 0){ all[v] = true } }); rad(find, function(err, data, info){ + expect(data).to.be.ok(); Radix.map(data, function(v,k){ delete all[find+k]; }); @@ -312,12 +313,22 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam }) }); + it('read one', function(done){ + //gun.get('names').get({'.': {'*': find}, '%': 1000 * 100}).once().map().once(function(data, key){ + gun.get('names').get('stu').once(function(data, key){ + expect(data.name).to.be.ok(); + expect(data.age).to.be.ok(); + done(); + }); + }); + it('read contacts', function(done){ var all = {}, find = 'm', to; names.forEach(function(v){ v = v.toLowerCase(); if(v.indexOf(find) == 0){ all[v] = true } }); + //console.log("<<<<<<<<<"); gun.get('names').get({'.': {'*': find}, '%': 1000 * 100}).once().map().once(function(data, key){ expect(data.name).to.be.ok(); expect(data.age).to.be.ok(); @@ -328,6 +339,7 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam done(); },100); }); + //console.log(">>>>>>>>>"); }); it('read contacts again', function(done){ diff --git a/test/sea/sea.js b/test/sea/sea.js index 1a166804..dca8f6fd 100644 --- a/test/sea/sea.js +++ b/test/sea/sea.js @@ -197,20 +197,20 @@ describe('SEA', function(){ expect(dec.priv).to.be(okey.priv); expect(dec.epriv).to.be(okey.epriv); - var gun = Gun(), tmp = Gun.node.soul(old); + var gun = Gun({super: true}), tmp = Gun.node.soul(old); var graph = {}; graph[tmp] = old; var alias = await SEA.verify(old.alias, false); expect(alias).to.be('bob'); alias = Gun.state.ify({}, tmp, 1, Gun.val.rel.ify(tmp), tmp = '~@'+alias); graph[tmp] = alias; - gun.on('put', {$: gun, put: graph}); + gun.on('test', {$: gun, put: graph}); var use = gun.user(); use.auth('bob', 'test123', function(ack){ expect(ack.err).to.not.be.ok(); done(); }); - }())}) + }())}); it('legacy []', function(done){ (async function(){ var pw = 'test123'; @@ -218,14 +218,14 @@ describe('SEA', function(){ var old = JSON.parse(atob("eyJfIjp7IiMiOiJ+VThkS0dySFJhX01sMFZ1YlR5OUZBYTlQS1ZlYlh0eTFjS05zWWxnYjduNC5QeVd5cUVVb0ZpYVduUElOV0Nad0xBbzFobjN1MldPWTU3SzZHZnpsNjhVIiwiPiI6eyJwdWIiOjE1NDY5MDI1MDQ5NzksImFsaWFzIjoxNTQ2OTAyNTA0OTc5LCJlcHViIjoxNTQ2OTAyNTA0OTc5LCJhdXRoIjoxNTQ2OTAyNTA0OTc5fX0sInB1YiI6IlU4ZEtHckhSYV9NbDBWdWJUeTlGQWE5UEtWZWJYdHkxY0tOc1lsZ2I3bjQuUHlXeXFFVW9GaWFXblBJTldDWndMQW8xaG4zdTJXT1k1N0s2R2Z6bDY4VSIsImFsaWFzIjoiU0VBe1wibVwiOltcIn5VOGRLR3JIUmFfTWwwVnViVHk5RkFhOVBLVmViWHR5MWNLTnNZbGdiN240LlB5V3lxRVVvRmlhV25QSU5XQ1p3TEFvMWhuM3UyV09ZNTdLNkdmemw2OFVcIixcImFsaWFzXCIsXCJhbGljZVwiLDE1NDY5MDI1MDQ5NzldLFwic1wiOlwienpuaGtIZjhZdFpZM2lGd3FVd0lJUldMTjhZMmlHbmNkcnVTaStGNDNmU1BLYWpSZlI0VzhXVHM4bElSMDBndGJmTWJxS0NjQkpGN3VNSkdGRC9WV2c9PVwifSIsImVwdWIiOiJTRUF7XCJtXCI6W1wiflU4ZEtHckhSYV9NbDBWdWJUeTlGQWE5UEtWZWJYdHkxY0tOc1lsZ2I3bjQuUHlXeXFFVW9GaWFXblBJTldDWndMQW8xaG4zdTJXT1k1N0s2R2Z6bDY4VVwiLFwiZXB1YlwiLFwiRkRzM1VvNTNFZEp6eFNocEpDaVctRGZPQ3lUS0M2U3cxeS1PZVJxam5ZRS5xVGdyYTlFQk1maEpNdVlMVmNaejRZYklLRm85enNBMHpMcV82dEVPMHI0XCIsMTU0NjkwMjUwNDk3OV0sXCJzXCI6XCJPZzRVVjY4OTluSjE4dC9ybWVnV0lkdnNqN01KaEpFc29ranZYQmdteVVRUXVNVjFTdnh4cXJqOFoyV1o2Q25XSkZnTlVDbEVYYWxuMURjUFE3M1R6UT09XCJ9IiwiYXV0aCI6IlNFQXtcIm1cIjpbXCJ+VThkS0dySFJhX01sMFZ1YlR5OUZBYTlQS1ZlYlh0eTFjS05zWWxnYjduNC5QeVd5cUVVb0ZpYVduUElOV0Nad0xBbzFobjN1MldPWTU3SzZHZnpsNjhVXCIsXCJhdXRoXCIsXCJ7XFxcImVrXFxcIjpcXFwiU0VBe1xcXFxcXFwiY3RcXFxcXFxcIjpcXFxcXFxcIi94ZnNPdVNkQUtrNkJiR00zbUV6MnVlSjI3Y0tJNThYMEtUL1FsaExSZXpWcjRkNzVZb2M5QlZNRjkzejl4QXI4N080S2FDNjJUWGVoeERQN0FFa2V4N1paaEpYL2hsVm9kK1FIcVFaaUZMK2lVQzFvL2hpUEJGWElBZmtINGRrcklGOFdqcEVaU3NIVmRSOVRhY2ZzbTB3aHN5NGJXN1ZLSEUySGc9PVxcXFxcXFwiLFxcXFxcXFwiaXZcXFxcXFxcIjpcXFxcXFxcIjhWekduTStEc1lTUktIU3Z4cSszTGc9PVxcXFxcXFwiLFxcXFxcXFwic1xcXFxcXFwiOlxcXFxcXFwibVVSSlJ4TzUvdXM9XFxcXFxcXCJ9XFxcIixcXFwic1xcXCI6XFxcImE1SlA3VFpuVE9jYjEwMGJOejlscEU4dnpqcUE3TWl0NHcwN3pjQTdIOFV0bml1WnVHSmdpZnNNQlFNSGdRdE5cXFwifVwiLDE1NDY5MDI1MDQ5NzldLFwic1wiOlwiSGFzMytJaHFEZTYyN016cElXZVE1cVFrZ2NOMlk3WHRpNGw0TFU3T2JyaktxSlBnSllrVWE2bk9YdlRmQkFzV1BPVzVnemh4Q2RPVGNFQm5icWlpWXc9PVwifSJ9")); var okey = {"pub":"U8dKGrHRa_Ml0VubTy9FAa9PKVebXty1cKNsYlgb7n4.PyWyqEUoFiaWnPINWCZwLAo1hn3u2WOY57K6Gfzl68U","epub":"FDs3Uo53EdJzxShpJCiW-DfOCyTKC6Sw1y-OeRqjnYE.qTgra9EBMfhJMuYLVcZz4YbIKFo9zsA0zLq_6tEO0r4","priv":"jMy7WfcldJ4esZEijAj4LTb99smtY_H0yKJLemJl2HI","epriv":"1DszMh-85pGTPLYtRunG-Q-xB78AE4k07PPkbedYYwk"} - var gun = Gun(), tmp = Gun.node.soul(old); + var gun = Gun({super: true}), tmp = Gun.node.soul(old); var graph = {}; graph[tmp] = old; var alias = SEA.opt.unpack(await SEA.verify(old.alias, false), 'alias', old); expect(alias).to.be('alice'); alias = Gun.state.ify({}, tmp, 1, Gun.val.rel.ify(tmp), tmp = '~@'+alias); graph[tmp] = alias; - gun.on('put', {$: gun, put: graph}); + gun.on('test', {$: gun, put: graph}); var use = gun.user(); use.auth('alice', 'test123', function(ack){ expect(ack.err).to.not.be.ok(); @@ -277,8 +277,30 @@ describe('SEA', function(){ }); describe('User', function(){ + var gun = Gun(), gtmp; + + it('test', function(done){ + var g = Gun(); + user = g.user(); + var gid; + SEA.pair(function(p){ + user.is = user._.sea = p; + gtmp = gid = 'test~'+p.pub; + g.get(gid).put({yo: 'hi'}, function(ack){ + var data = SEA.opt.parse(g._.graph[gid].yo); + expect(data[':']).to.be('hi'); + expect(data['~']).to.be.ok(); + g.get(gid).get('yo').once(function(r){ + expect(r).to.be('hi'); + user.leave(); + done(); + }) + }) + }) + }); + it('is instantiable', function(done){ - gun = Gun(); + user.leave(); user = gun.user(); done(); }) @@ -289,7 +311,7 @@ describe('SEA', function(){ expect(ack.err).to.not.be.ok(); done(); }) - }) + }); it('login users', function(done){ user.auth('carl', 'test123', function(ack){ @@ -347,6 +369,7 @@ describe('SEA', function(){ var ref = user.get('who').get('all').set(msg); user.get('who').get('said').set(ref); user.get('who').get('said').map().once(function(data){ + //console.log("*****", data); expect(data.what).to.be.ok(); done(); }) @@ -356,6 +379,7 @@ describe('SEA', function(){ it('set user ref null override', function(done){ this.timeout(9000); var gun = Gun(); + //user.leave(); var user = gun.user(); var msg = {what: 'hello world'}; user.create('xavier', 'password'); From d6dae4871e0166555b7885dca10c32e8b7c420fb Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 10 Feb 2020 15:22:07 -0800 Subject: [PATCH 42/87] p v b --- package-lock.json | 10 +++++++--- package.json | 3 +-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index aff7ee5f..1d114ffc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.2019.1211", + "version": "0.2020.116", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -165,6 +165,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/b64-lite/-/b64-lite-1.3.1.tgz", "integrity": "sha512-A3n/YWszeQeUeKKy+XRfsDW/s/+1cvD110HYA4uXtkNswNLd1MxrNblYt2lgKisUS3UfPPTaXhvFegD+l4YuOA==", + "optional": true, "requires": { "base-64": "^0.1.0" } @@ -193,7 +194,8 @@ "base-64": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", - "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=" + "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=", + "optional": true }, "base64-arraybuffer": { "version": "0.1.5", @@ -897,7 +899,8 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "optional": true }, "js-yaml": { "version": "3.13.1", @@ -953,6 +956,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "optional": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } diff --git a/package.json b/package.json index e10efe53..4154ae90 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.2020.116", + "version": "0.2020.201", "description": "A realtime, decentralized, offline-first, graph data synchronization engine.", "main": "index.js", "browser": "browser.js", @@ -69,7 +69,6 @@ "mocha": "^6.2.0", "panic-manager": "^1.2.0", "panic-server": "^1.1.1", - "0x": "^4.9.1", "uglify-js": "^3.6.0" } } From bc40109e614955a78c1e1be21cf9793e54bdc8bb Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 10 Feb 2020 17:48:39 -0800 Subject: [PATCH 43/87] fixup --- axe.js | 2 +- examples/http.js | 6 +++--- examples/todo/index.html | 25 ------------------------- gun.js | 2 +- lib/crashed.js | 32 ++++++++++++++++++++++++++++++++ trace.js | 27 --------------------------- 6 files changed, 37 insertions(+), 57 deletions(-) create mode 100644 lib/crashed.js delete mode 100644 trace.js diff --git a/axe.js b/axe.js index 19594d2c..16566f0f 100644 --- a/axe.js +++ b/axe.js @@ -109,7 +109,7 @@ at.on('in', input); at.on('in2', input); function input(msg){ - var to = this.to, peer = (msg._||'').via || mesh.leap; // warning! mesh.leap could be buggy! + var to = this.to, peer = (msg._||'').via; // warning! mesh.leap could be buggy! var dht = opt.dht; var routes = axe.routes || (axe.routes = {}); // USE RAD INSTEAD! TMP TESTING! var get = msg.get, hash, tmp; diff --git a/examples/http.js b/examples/http.js index dba51779..9c011f49 100644 --- a/examples/http.js +++ b/examples/http.js @@ -1,8 +1,8 @@ ;(function(){ - /*var cluster = require('cluster'); + var cluster = require('cluster'); if(cluster.isMaster){ - return cluster.fork() && cluster.on('exit', function(){ cluster.fork() }); - }*/ + return cluster.fork() && cluster.on('exit', function(){ cluster.fork(); require('../lib/crashed'); }); + } var fs = require('fs'); var config = { port: process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765 }; diff --git a/examples/todo/index.html b/examples/todo/index.html index c8a5d305..3764edc4 100644 --- a/examples/todo/index.html +++ b/examples/todo/index.html @@ -113,31 +113,6 @@ - -