unbuild fixes & shim temporary deprecations for publication

This commit is contained in:
Mark Nadal 2021-08-23 00:59:58 -07:00
parent dac9e8d059
commit 6cb7261ac2
9 changed files with 482 additions and 20 deletions

453
gun.js
View File

@ -1758,4 +1758,457 @@
});
})(USE, './localStorage');
}());
/* BELOW IS TEMPORARY FOR OLD INTERNAL COMPATIBILITY, THEY ARE IMMEDIATELY DEPRECATED AND WILL BE REMOVED IN NEXT VERSION */
;(function(){
var u;
if(''+u == typeof Gun){ return }
var DEP = function(n){ console.log("Warning! Deprecated internal utility will break in next version:", n) }
// Generic javascript utilities.
var Type = Gun;
//Type.fns = Type.fn = {is: function(fn){ return (!!fn && fn instanceof Function) }}
Type.fn = Type.fn || {is: function(fn){ DEP('fn'); return (!!fn && 'function' == typeof fn) }}
Type.bi = Type.bi || {is: function(b){ DEP('bi');return (b instanceof Boolean || typeof b == 'boolean') }}
Type.num = Type.num || {is: function(n){ DEP('num'); return !list_is(n) && ((n - parseFloat(n) + 1) >= 0 || Infinity === n || -Infinity === n) }}
Type.text = Type.text || {is: function(t){ DEP('text'); return (typeof t == 'string') }}
Type.text.ify = Type.text.ify || function(t){ DEP('text.ify');
if(Type.text.is(t)){ return t }
if(typeof JSON !== "undefined"){ return JSON.stringify(t) }
return (t && t.toString)? t.toString() : t;
}
Type.text.random = Type.text.random || function(l, c){ DEP('text.random');
var s = '';
l = l || 24; // you are not going to make a 0 length random number, so no need to check type
c = c || '0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz';
while(l > 0){ s += c.charAt(Math.floor(Math.random() * c.length)); l-- }
return s;
}
Type.text.match = Type.text.match || function(t, o){ var tmp, u; DEP('text.match');
if('string' !== typeof t){ return false }
if('string' == typeof o){ o = {'=': o} }
o = o || {};
tmp = (o['='] || o['*'] || o['>'] || o['<']);
if(t === tmp){ return true }
if(u !== o['=']){ return false }
tmp = (o['*'] || o['>'] || o['<']);
if(t.slice(0, (tmp||'').length) === tmp){ return true }
if(u !== o['*']){ return false }
if(u !== o['>'] && u !== o['<']){
return (t >= o['>'] && t <= o['<'])? true : false;
}
if(u !== o['>'] && t >= o['>']){ return true }
if(u !== o['<'] && t <= o['<']){ return true }
return false;
}
Type.text.hash = Type.text.hash || function(s, c){ // via SO
DEP('text.hash');
if(typeof s !== 'string'){ return }
c = c || 0;
if(!s.length){ return c }
for(var i=0,l=s.length,n; i<l; ++i){
n = s.charCodeAt(i);
c = ((c<<5)-c)+n;
c |= 0;
}
return c;
}
Type.list = Type.list || {is: function(l){ DEP('list'); return (l instanceof Array) }}
Type.list.slit = Type.list.slit || Array.prototype.slice;
Type.list.sort = Type.list.sort || function(k){ // creates a new sort function based off some key
DEP('list.sort');
return function(A,B){
if(!A || !B){ return 0 } A = A[k]; B = B[k];
if(A < B){ return -1 }else if(A > B){ return 1 }
else { return 0 }
}
}
Type.list.map = Type.list.map || function(l, c, _){ DEP('list.map'); return obj_map(l, c, _) }
Type.list.index = 1; // change this to 0 if you want non-logical, non-mathematical, non-matrix, non-convenient array notation
Type.obj = Type.boj || {is: function(o){ DEP('obj'); return o? (o instanceof Object && o.constructor === Object) || Object.prototype.toString.call(o).match(/^\[object (\w+)\]$/)[1] === 'Object' : false }}
Type.obj.put = Type.obj.put || function(o, k, v){ DEP('obj.put'); return (o||{})[k] = v, o }
Type.obj.has = Type.obj.has || function(o, k){ DEP('obj.has'); return o && Object.prototype.hasOwnProperty.call(o, k) }
Type.obj.del = Type.obj.del || function(o, k){ DEP('obj.del');
if(!o){ return }
o[k] = null;
delete o[k];
return o;
}
Type.obj.as = Type.obj.as || function(o, k, v, u){ DEP('obj.as'); return o[k] = o[k] || (u === v? {} : v) }
Type.obj.ify = Type.obj.ify || function(o){ DEP('obj.ify');
if(obj_is(o)){ return o }
try{o = JSON.parse(o);
}catch(e){o={}};
return o;
}
;(function(){ var u;
function map(v,k){
if(obj_has(this,k) && u !== this[k]){ return }
this[k] = v;
}
Type.obj.to = Type.obj.to || function(from, to){ DEP('obj.to');
to = to || {};
obj_map(from, map, to);
return to;
}
}());
Type.obj.copy = Type.obj.copy || function(o){ DEP('obj.copy'); // because http://web.archive.org/web/20140328224025/http://jsperf.com/cloning-an-object/2
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, u;
if(n && (i === n || (obj_is(n) && obj_has(n, i)))){ return }
if(u !== i){ return true }
}
Type.obj.empty = Type.obj.empty || function(o, n){ DEP('obj.empty');
if(!o){ return true }
return obj_map(o,empty,{n:n})? false : true;
}
}());
;(function(){
function t(k,v){
if(2 === arguments.length){
t.r = t.r || {};
t.r[k] = v;
return;
} t.r = t.r || [];
t.r.push(k);
};
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 = Type.obj.map || function(l, c, _){ DEP('obj.map');
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(_, 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!
if(c === l[lle? ll[i] : i]){ return ll? ll[i] : ii } // use this for now
}
}
} else {
for(i in l){
if(f){
if(obj_has(l,i)){
r = _? c.call(_, l[i], i, t) : c(l[i], i, t);
if(r !== u){ return r }
}
} else {
//if(a.test.is(c,l[i])){ return i } // should implement deep equality testing!
if(c === l[i]){ return i } // use this for now
}
}
}
return f? t.r : Type.list.index? 0 : -1;
}
}());
Type.time = Type.time || {};
Type.time.is = Type.time.is || function(t){ DEP('time'); return t? t instanceof Date : (+new Date().getTime()) }
var fn_is = Type.fn.is;
var list_is = Type.list.is;
var obj = Type.obj, obj_is = obj.is, obj_has = obj.has, obj_map = obj.map;
var Val = {};
Val.is = function(v){ DEP('val.is'); // Valid values are a subset of JSON: null, binary, number (!Infinity), text, or a soul relation. Arrays need special algorithms to handle concurrency, so they are not supported directly. Use an extension that supports them if needed but research their problems first.
if(v === u){ return false }
if(v === null){ return true } // "deletes", nulling out keys.
if(v === Infinity){ return false } // we want this to be, but JSON does not support it, sad face.
if(text_is(v) // by "text" we mean strings.
|| bi_is(v) // by "binary" we mean boolean.
|| num_is(v)){ // by "number" we mean integers or decimals.
return true; // simple values are valid.
}
return Val.link.is(v) || false; // is the value a soul relation? Then it is valid and return it. If not, everything else remaining is an invalid data type. Custom extensions can be built on top of these primitives to support other types.
}
Val.link = Val.rel = {_: '#'};
;(function(){
Val.link.is = function(v){ DEP('val.link.is'); // this defines whether an object is a soul relation or not, they look like this: {'#': 'UUID'}
if(v && v[rel_] && !v._ && obj_is(v)){ // must be an object.
var o = {};
obj_map(v, map, o);
if(o.id){ // a valid id was found.
return o.id; // yay! Return it.
}
}
return false; // the value was not a valid soul relation.
}
function map(s, k){ var o = this; // map over the object...
if(o.id){ return o.id = false } // if ID is already defined AND we're still looping through the object, it is considered invalid.
if(k == rel_ && text_is(s)){ // the key should be '#' and have a text value.
o.id = s; // we found the soul!
} else {
return o.id = false; // if there exists anything else on the object that isn't the soul, then it is considered invalid.
}
}
}());
Val.link.ify = function(t){ DEP('val.link.ify'); return obj_put({}, rel_, t) } // convert a soul into a relation and return it.
Type.obj.has._ = '.';
var rel_ = Val.link._, u;
var bi_is = Type.bi.is;
var num_is = Type.num.is;
var text_is = Type.text.is;
var obj = Type.obj, obj_is = obj.is, obj_put = obj.put, obj_map = obj.map;
Type.val = Type.val || Val;
var Node = {_: '_'};
Node.soul = function(n, o){ DEP('node.soul'); return (n && n._ && n._[o || soul_]) } // convenience function to check to see if there is a soul on a node and return it.
Node.soul.ify = function(n, o){ DEP('node.soul.ify'); // put a soul on an object.
o = (typeof o === 'string')? {soul: o} : o || {};
n = n || {}; // make sure it exists.
n._ = n._ || {}; // make sure meta exists.
n._[soul_] = o.soul || n._[soul_] || text_random(); // put the soul on it.
return n;
}
Node.soul._ = Val.link._;
;(function(){
Node.is = function(n, cb, as){ DEP('node.is'); var s; // checks to see if an object is a valid node.
if(!obj_is(n)){ return false } // must be an object.
if(s = Node.soul(n)){ // must have a soul on it.
return !obj_map(n, map, {as:as,cb:cb,s:s,n:n});
}
return false; // nope! This was not a valid node.
}
function map(v, k){ // we invert this because the way we check for this is via a negation.
if(k === Node._){ return } // skip over the metadata.
if(!Val.is(v)){ return true } // it is true that this is an invalid node.
if(this.cb){ this.cb.call(this.as, v, k, this.n, this.s) } // optionally callback each key/value.
}
}());
;(function(){
Node.ify = function(obj, o, as){ DEP('node.ify'); // returns a node from a shallow object.
if(!o){ o = {} }
else if(typeof o === 'string'){ o = {soul: 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});
}
return o.node; // This will only be a valid node if the object wasn't already deep!
}
function map(v, k){ var o = this.o, tmp, u; // iterate over each key/value.
if(o.map){
tmp = o.map.call(this.as, v, ''+k, o.node);
if(u === tmp){
obj_del(o.node, k);
} else
if(o.node){ o.node[k] = tmp }
return;
}
if(Val.is(v)){
o.node[k] = v;
}
}
}());
var obj = Type.obj, obj_is = obj.is, obj_del = obj.del, obj_map = obj.map;
var text = Type.text, text_random = text.random;
var soul_ = Node.soul._;
var u;
Type.node = Type.node || Node;
var State = Type.state;
State.lex = function(){ DEP('state.lex'); return State().toString(36).replace('.','') }
State.to = function(from, k, to){ DEP('state.to');
var val = (from||{})[k];
if(obj_is(val)){
val = obj_copy(val);
}
return State.ify(to, k, State.is(from, k), val, Node.soul(from));
}
;(function(){
State.map = function(cb, s, as){ DEP('state.map'); var u; // for use with Node.ify
var o = obj_is(o = cb || s)? o : null;
cb = fn_is(cb = cb || s)? cb : null;
if(o && !cb){
s = num_is(s)? s : State();
o[N_] = o[N_] || {};
obj_map(o, map, {o:o,s:s});
return o;
}
as = as || obj_is(s)? s : u;
s = num_is(s)? s : State();
return function(v, k, o, opt){
if(!cb){
map.call({o: o, s: s}, v,k);
return v;
}
cb.call(as || this || {}, v, k, o, opt);
if(obj_has(o,k) && u === o[k]){ return }
map.call({o: o, s: s}, v,k);
}
}
function map(v,k){
if(N_ === k){ return }
State.ify(this.o, k, this.s) ;
}
}());
var obj = Type.obj, obj_as = obj.as, obj_has = obj.has, obj_is = obj.is, obj_map = obj.map, obj_copy = obj.copy;
var num = Type.num, num_is = num.is;
var fn = Type.fn, fn_is = fn.is;
var N_ = Node._, u;
var Graph = {};
;(function(){
Graph.is = function(g, cb, fn, as){ DEP('graph.is'); // checks to see if an object is a valid graph.
if(!g || !obj_is(g) || obj_empty(g)){ return false } // must be an object.
return !obj_map(g, map, {cb:cb,fn:fn,as:as}); // makes sure it wasn't an empty object.
}
function map(n, s){ // we invert this because the way'? we check for this is via a negation.
if(!n || s !== Node.soul(n) || !Node.is(n, this.fn, this.as)){ return true } // it is true that this is an invalid graph.
if(!this.cb){ return }
nf.n = n; nf.as = this.as; // sequential race conditions aren't races.
this.cb.call(nf.as, n, s, nf);
}
function nf(fn){ // optional callback for each node.
if(fn){ Node.is(nf.n, fn, nf.as) } // where we then have an optional callback for each key/value.
}
}());
;(function(){
Graph.ify = function(obj, env, as){ DEP('graph.ify');
var at = {path: [], obj: obj};
if(!env){
env = {};
} else
if(typeof env === 'string'){
env = {soul: env};
} else
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);
}
env.shell = (as||{}).shell;
env.graph = env.graph || {};
env.seen = env.seen || [];
env.as = env.as || as;
node(env, at);
env.root = at.node;
return env.graph;
}
function node(env, at){ var tmp;
if(tmp = seen(env, at)){ return tmp }
at.env = env;
at.soul = soul;
if(Node.ify(at.obj, map, at)){
at.link = at.link || Val.link.ify(Node.soul(at.node));
if(at.obj !== env.shell){
env.graph[Val.link.is(at.link)] = at.node;
}
}
return at;
}
function map(v,k,n){
var at = this, env = at.env, is, tmp;
if(Node._ === k && obj_has(v,Val.link._)){
return n._; // TODO: Bug?
}
if(!(is = valid(v,k,n, at,env))){ return }
if(!k){
at.node = at.node || n || {};
if(obj_has(v, Node._) && Node.soul(v)){ // ? for safety ?
at.node._ = obj_copy(v._);
}
at.node = Node.soul.ify(at.node, Val.link.is(at.link));
at.link = at.link || Val.link.ify(Node.soul(at.node));
}
if(tmp = env.map){
tmp.call(env.as || {}, v,k,n, at);
if(obj_has(n,k)){
v = n[k];
if(u === v){
obj_del(n, k);
return;
}
if(!(is = valid(v,k,n, at,env))){ return }
}
}
if(!k){ return at.node }
if(true === is){
return v;
}
tmp = node(env, {obj: v, path: at.path.concat(k)});
if(!tmp.node){ return }
return tmp.link; //{'#': Node.soul(tmp.node)};
}
function soul(id){ var at = this;
var prev = Val.link.is(at.link), graph = at.env.graph;
at.link = at.link || Val.link.ify(id);
at.link[Val.link._] = id;
if(at.node && at.node[Node._]){
at.node[Node._][Val.link._] = id;
}
if(obj_has(graph, prev)){
graph[id] = graph[prev];
obj_del(graph, prev);
}
}
function valid(v,k,n, at,env){ var tmp;
if(Val.is(v)){ return true }
if(obj_is(v)){ return 1 }
if(tmp = env.invalid){
v = tmp.call(env.as || {}, v,k,n);
return valid(v,k,n, at,env);
}
env.err = "Invalid value at '" + at.path.concat(k).join('.') + "'!";
if(Type.list.is(v)){ env.err += " Use `.set(item)` instead of an Array." }
}
function seen(env, at){
var arr = env.seen, i = arr.length, has;
while(i--){ has = arr[i];
if(at.obj === has.obj){ return has }
}
arr.push(at);
}
}());
Graph.node = function(node){ DEP('graph.node');
var soul = Node.soul(node);
if(!soul){ return }
return obj_put({}, soul, node);
}
;(function(){
Graph.to = function(graph, root, opt){ DEP('graph.to');
if(!graph){ return }
var obj = {};
opt = opt || {seen: {}};
obj_map(graph[root], map, {obj:obj, graph: graph, opt: opt});
return obj;
}
function map(v,k){ var tmp, obj;
if(Node._ === k){
if(obj_empty(v, Val.link._)){
return;
}
this.obj[k] = obj_copy(v);
return;
}
if(!(tmp = Val.link.is(v))){
this.obj[k] = v;
return;
}
if(obj = this.opt.seen[tmp]){
this.obj[k] = obj;
return;
}
this.obj[k] = this.opt.seen[tmp] = Graph.to(this.graph, tmp, this.opt);
}
}());
var fn_is = Type.fn.is;
var obj = Type.obj, obj_is = obj.is, obj_del = obj.del, obj_has = obj.has, obj_empty = obj.empty, obj_put = obj.put, obj_map = obj.map, obj_copy = obj.copy;
var u;
Type.graph = Type.graph || Graph;
}());

2
gun.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,7 @@ module.exports = function ask(cb, as){
}
return true;
}
var id = (as && as['#']) || Math.random().toString(36).slice(2);
var id = (as && as['#']) || random(9);
if(!cb){ return id }
var to = this.on(id, cb, as);
to.err = to.err || setTimeout(function(){ to.off();
@ -23,4 +23,5 @@ module.exports = function ask(cb, as){
}, lack);
return id;
}
var random = String.random || function(){ return Math.random().toString(36).slice(2) }

View File

@ -67,6 +67,7 @@ Gun.chain.get = function(key, cb, as){
}; wait = {}; // end quick hack.
}
// call:
if(root.pass){ if(root.pass[id+at.id]){ return } root.pass[id+at.id] = 1 }
if(opt.on){ opt.ok.call(at.$, data, at.get, msg, eve || any); return } // TODO: Also consider breaking `this` since a lot of people do `=>` these days and `.call(` has slower performance.
if(opt.v2020){ opt.ok(msg, eve || any); return }
Object.keys(msg).forEach(function(k){ tmp[k] = msg[k] }, tmp = {}); msg = tmp; msg.put = data; // 2019 COMPATIBILITY! TODO: GET RID OF THIS!

View File

@ -35,6 +35,7 @@ Gun.on('create', function lg(root){
disk[soul] = Gun.state.ify(disk[soul], key, put['>'], put[':'], soul); // merge into disk object
if(!msg['@']){ acks.push(msg['#']) } // then ack any non-ack write. // TODO: use batch id.
if(to){ return }
//flush();return;
to = setTimeout(flush, opt.wait || 1); // that gets saved as a whole to disk every 1ms
});
function flush(){

View File

@ -17,6 +17,7 @@ Gun.chain.put = function(data, cb, as){ // I rewrote it :)
as.todo = [{it: as.data, ref: as.$}];
as.turn = as.turn || turn;
as.ran = as.ran || ran;
//var path = []; as.via.back(at => { at.get && path.push(at.get.slice(0,9)) }); path = path.reverse().join('.');
// TODO: Perf! We only need to stun chains that are being modified, not necessarily written to.
(function walk(){
var to = as.todo, at = to.pop(), d = at.it, cid = at.ref && at.ref._.id, v, k, cat, tmp, g;
@ -41,12 +42,13 @@ Gun.chain.put = function(data, cb, as){ // I rewrote it :)
(as.wait || (as.wait = {}))[id] = '';
tmp = (cat.ref = (g? d : k? at.ref.get(k) : at.ref))._;
(tmp = (d && (d._||'')['#']) || tmp.soul || tmp.link)? resolve({soul: tmp}) : cat.ref.get(resolve, {run: as.run, /*hatch: 0,*/ v2020:1, out:{get:{'.':' '}}}); // TODO: BUG! This should be resolve ONLY soul to prevent full data from being loaded. // Fixed now?
//setTimeout(function(){ if(F){ return } console.log("I HAVE NOT BEEN CALLED!", path, id, cat.ref._.id, k) }, 9000); var F; // MAKE SURE TO ADD F = 1 below!
function resolve(msg, eve){
if(cat.link['#']){ return as.ran(as) }
var end = cat.link['#'];
if(eve){ eve.off(); eve.rid(msg) } // TODO: Too early! Check all peers ack not found.
// TODO: BUG maybe? Make sure this does not pick up a link change wipe, that it uses the changign link instead.
var soul = msg.soul || (tmp = (msg.$$||msg.$)._||'').soul || tmp.link || ((tmp = tmp.put||'')._||'')['#'] || tmp['#'] || (((tmp = msg.put||'') && msg.$$)? tmp['#'] : (tmp['=']||tmp[':']||'')['#']);
stun(as, msg.$);
var soul = end || msg.soul || (tmp = (msg.$$||msg.$)._||'').soul || tmp.link || ((tmp = tmp.put||'')._||'')['#'] || tmp['#'] || (((tmp = msg.put||'') && msg.$$)? tmp['#'] : (tmp['=']||tmp[':']||'')['#']);
!end && stun(as, msg.$);
if(!soul && !at.link['#']){ // check soul link above us
(at.wait || (at.wait = [])).push(function(){ resolve(msg, eve) }) // wait
return;
@ -108,7 +110,6 @@ function ran(as){
(tmp = function(){ // this is not official yet, but quick solution to hack in for now.
if(!stun){ return }
ran.end(stun, root);
//console.log("PUT HATCH END", as.run, Object.keys(stun.add||''));
setTimeout.each(Object.keys(stun = stun.add||''), function(cb){ if(cb = stun[cb]){cb()} }); // resume the stunned reads // Any perf reasons to CPU schedule this .keys( ?
}).hatch = tmp; // this is not official yet ^
//console.log(1, "PUT", as.run, as.graph);

View File

@ -39,6 +39,7 @@ Gun.ask = require('./ask');
return gun;
}
function universe(msg){
//if(!F){ var eve = this; setTimeout(function(){ universe.call(eve, msg,1) },Math.random() * 100);return; } // ADD F TO PARAMS!
if(!msg){ return }
if(msg.out === universe){ this.to.next(msg); return }
var eve = this, as = eve.as, at = as.at || as, gun = at.$, dup = at.dup, tmp, DBG = msg.DBG;
@ -139,8 +140,8 @@ Gun.ask = require('./ask');
if((tmp = ctx.msg) && (tmp = tmp.put) && (tmp = tmp[soul])){ state_ify(tmp, key, state, val, soul) } // necessary! or else out messages do not get SEA transforms.
graph[soul] = state_ify(graph[soul], key, state, val, soul);
if(tmp = (root.next||'')[soul]){ tmp.on('in', msg) }
eve.to.next(msg);
fire(ctx);
eve.to.next(msg);
}
function fire(ctx, msg){ var root;
if(ctx.stop){ return }
@ -156,19 +157,20 @@ Gun.ask = require('./ask');
ctx.root.on('out', msg);
}
function ack(msg){ // aggregate ACKs.
var id = msg['@'] || '', root = (msg.$._||'').root, tmp;
// TODO: check for the sharded message err and transfer it onto the original batch?
if(!(tmp = id._)){ /*console.log("TODO: handle ack id.");*/ return }
tmp.acks = (tmp.acks||0) + 1;
if(tmp.err = msg.err){
msg['@'] = tmp['#'];
--tmp.stun;
}
if(0 == tmp.stun && tmp.acks == tmp.all){ // TODO: if ack is synchronous this may not work?
root && root.on('in', {'@': tmp['#'], err: msg.err, ok: msg.err? u : 'shard'});
msg.err && fire(tmp);
return;
var id = msg['@'] || '', ctx;
if(!(ctx = id._)){ return }
ctx.acks = (ctx.acks||0) + 1;
if(ctx.err = msg.err){
msg['@'] = ctx['#'];
fire(ctx); // TODO: BUG? How it skips/stops propagation of msg if any 1 item is error, this would assume a whole batch/resync has same malicious intent.
}
if(!ctx.stop && !ctx.crack){ ctx.crack = ctx.match && ctx.match.push(function(){back(ctx)}) } // handle synchronous acks
back(ctx);
}
function back(ctx){
if(!ctx || !ctx.root){ return }
if(ctx.stun || ctx.acks !== ctx.all){ return }
ctx.root.on('in', {'@': ctx['#'], err: ctx.err, ok: ctx.err? u : {'':1}});
}
var ERR = "Error: Invalid graph!";

View File

@ -48,7 +48,7 @@ Object.keys = Object.keys || function(o){
}
;(function(){ // max ~1ms or before stack overflow
var u, sT = setTimeout, l = 0, c = 0, sI = (typeof setImmediate !== ''+u && setImmediate) || sT; // queueMicrotask faster but blocks UI
sT.poll = sT.poll || function(f){
sT.poll = sT.poll || function(f){ //f(); return; // for testing
if((1 >= (+new Date - l)) && c++ < 3333){ f(); return }
sI(function(){ l = +new Date; f() },c=0)
}

View File

@ -2,6 +2,9 @@
var Gun = require('../index');
Gun.Mesh = require('./mesh');
// TODO: resync upon reconnect online/offline
//window.ononline = window.onoffline = function(){ console.log('online?', navigator.onLine) }
Gun.on('opt', function(root){
this.to.next(root);
if(root.once){ return }