[](https://www.npmjs.com/package/gun)
[](https://travis-ci.org/amark/gun)
@@ -9,7 +6,9 @@
[](https://gitter.im/amark/gun)
[](https://www.jsdelivr.com/package/npm/gun)
-GUN is a realtime, distributed, offline-first, graph database engine. Doing **[20M+](https://github.com/amark/gun/wiki/100000-ops-sec-in-IE6-on-2GB-Atom-CPU) ops/sec** in just **~9KB** gzipped.
+**GUN** is an _ecosystem_ of tools that let you build tomorrow's dApps, today.
+
+Decentralized alternatives to [Reddit](https://notabug.io/t/whatever/comments/36588a16b9008da4e3f15663c2225e949eca4a15/gpu-bot-test), [YouTube](https://d.tube/), [Wikipedia](https://news.ycombinator.com/item?id=17685682), etc. are already pushing terabytes of daily P2P traffic on GUN. We are a [friendly community](https://gitter.im/amark/gun) creating a free fun future for freedom:
@@ -22,22 +21,16 @@ GUN is a realtime, distributed, offline-first, graph database engine. Doing **[2
-
-
-
-
-
+The ecosystem is one nice stack of technologies that looks like this:
-## Why?
+
+
- - **Realtime** - You might use Socket.IO for realtime updates, but what happens if you reload the page? GUN solves *state synchronization* for you, no matter what, on reloads, across all your users, and even on conflicting updates.
- - **Distributed** - GUN is peer-to-peer by design, meaning you have no centralized database server to maintain or that could crash. This lets you sleep through the night without worrying about database DevOps - we call it "NoDB". From there, you can build decentralized, federated, or centralized apps.
- - **Offline-first** - GUN works even if your internet or cell reception doesn't. Users can still plug away and save data as normal, and then when the network comes back online GUN will automatically synchronize all the changes and handle any conflicts for you.
- - **Graph** - Most databases force you to bend over backwards to match their storage constraints. But graphs are different, they let you have any data structure you want. Whether that be traditional tables with relations, document oriented trees, or tons of circular references. You choose.
+For now, it is best to start with GUN and _just use it_ to learn the basics, since it is _**so easy**_: (**or** want to read more? Skip ahead to the "[What is GUN?](#what-is-gun)" section.)
## Quickstart
- - Try the [interactive tutorial](https://gun.eco/think.html) in the browser (**5min** ~ average developer).
+ - Try the [interactive tutorial](https://gun.eco/docs/Todo-Dapp) in the browser (**5min** ~ average developer).
- Or `npm install gun` and run the examples with `cd node_modules/gun && npm start` (**5min** ~ average developer).
> **Note:** If you don't have [node](http://nodejs.org/) or [npm](https://www.npmjs.com/), read [this](https://github.com/amark/gun/blob/master/examples/install.sh) first.
@@ -62,7 +55,7 @@ gun.get('mark').on(function(data, key){
});
```
-- Or try something mind blowing, like saving circular references to a table of documents! ([play](http://jsbin.com/wefozepume/edit?js,console))
+- Or try something **mind blowing**, like saving circular references to a table of documents! ([play](http://jsbin.com/wefozepume/edit?js,console))
```javascript
var cat = {name: "Fluffy", species: "kitty"};
var mark = {boss: cat};
@@ -72,7 +65,7 @@ cat.slave = mark;
gun.get('mark').put(mark);
// access the data as if it is a document.
-gun.get('mark').get('boss').get('name').val(function(data, key){
+gun.get('mark').get('boss').get('name').once(function(data, key){
// `val` grabs the data once, no subscriptions.
console.log("Mark's boss is", data);
});
@@ -95,20 +88,32 @@ gun.get('list').map().once(function(data, key){
gun.get('list').set({type: "cucumber", goal: "scare cat"});
```
-## Support
+Want to keep building more? **Jump to [THE DOCUMENTATION](#documentation)!**
+
+# What is GUN?
+
+First & foremost, GUN is **a community of the nicest and most helpful people** out there. So [I want to invite you](https://gitter.im/amark/gun) to come tell us about what **you** are working on & wanting to build (new or old school alike! Just be nice as well.) and ask us your questions directly. :)
+
+On that note, let's get some official shout outs covered first:
+
+### Support
- Join others in sponsoring code: https://www.patreon.com/gunDB !
@@ -116,13 +121,26 @@ Thanks to:
- Found a bug? Report at: https://github.com/amark/gun/issues ;
- **Need help**? Chat with us: https://gitter.im/amark/gun .
+### History
+
+[GUN](https://gun.eco) was created by [Mark Nadal](https://twitter.com/marknadal) in 2014 after he had spent 4 years trying to get his collaborative web app to scale up with traditional databases.
+
+ After he realized [Master-Slave database architecture causes one big bottleneck](https://gun.eco/distributed/matters.html), he (as a complete newbie outsider) naively decided **to question the status quo** and shake things up with controversial, heretical, and contrarian experiments:
+
+**The NoDB** - no master, no servers, no "single source of truth", not built with a real programming language or real hardware, no DevOps, no locking, not *just* SQL or NoSQL but both (**all** - graphs, documents, tables, key/value).
+
+The goal was to build a P2P database that could survive living inside **any** browser, and could correctly sync data between **any** device after assuming **any** offline-first activity.
+
+
+
+Technically, **GUN is a graph synchronization protocol** with a *lightweight embedded engine*, capable of doing *[20M+ API ops/sec](https://gun.eco/docs/Performance)* in **just ~9KB gzipped size**.
## Documentation
This would not be possible without **community contributors**, big shout out to:
-**[anywhichway](https://github.com/anywhichway) ([Block Storage](https://github.com/anywhichway/gun-block))**; **[beebase](https://github.com/beebase) ([Quasar](https://github.com/beebase/gun-vuex-quasar))**; **[BrockAtkinson](https://github.com/BrockAtkinson) ([brunch config](https://github.com/BrockAtkinson/brunch-gun))**; **[Brysgo](https://github.com/brysgo) ([GraphQL](https://github.com/brysgo/graphql-gun))**; **[d3x0r](https://github.com/d3x0r) ([SQLite](https://github.com/d3x0r/gun-db))**; **[forrestjt](https://github.com/forrestjt) ([file.js](https://github.com/amark/gun/blob/master/lib/file.js))**; **[hillct](https://github.com/hillct) (Docker)**; **[JosePedroDias](https://github.com/josepedrodias) ([graph visualizer](http://acor.sl.pt:9966))**; **[JuniperChicago](https://github.com/JuniperChicago) ([cycle.js bindings](https://github.com/JuniperChicago/cycle-gun))**; **[jveres](https://github.com/jveres) ([todoMVC](https://github.com/jveres/todomvc))**; **[kristianmandrup](https://github.com/kristianmandrup) ([edge](https://github.com/kristianmandrup/gun-edge))**; **[lmangani](https://github.com/lmangani) ([Cytoscape Visualizer](https://github.com/lmangani/gun-scape), [Cassandra](https://github.com/lmangani/gun-cassandra), [Fastify](https://github.com/lmangani/fastify-gundb), [LetsEncrypt](https://github.com/lmangani/polyGun-letsencrypt))**; **[mhelander](https://github.com/mhelander) ([SEA](https://github.com/amark/gun/blob/master/sea.js))**; [omarzion](https://github.com/omarzion) ([Sticky Note App](https://github.com/omarzion/stickies)); [PsychoLlama](https://github.com/PsychoLlama) ([LevelDB](https://github.com/PsychoLlama/gun-level)); **[RangerMauve](https://github.com/RangerMauve) ([schema](https://github.com/gundb/gun-schema))**; **[robertheessels](https://github.com/swifty) ([gun-p2p-auth](https://github.com/swifty/gun-p2p-auth))**; [sbeleidy](https://github.com/sbeleidy); **[Sean Matheson](https://github.com/ctrlplusb) ([Observable/RxJS/Most.js bindings](https://github.com/ctrlplusb/gun-most))**; **[Stefdv](https://github.com/stefdv) (Polymer/web components)**; **[sjones6](https://github.com/sjones6) ([Flint](https://github.com/sjones6/gun-flint))**; **[zrrrzzt](https://github.com/zrrrzzt) ([JWT Auth](https://gist.github.com/zrrrzzt/6f88dc3cedee4ee18588236756d2cfce))**; **[88dev](https://github.com/88dev) ([Database Viewer](https://github.com/88dev/gun-show))**;
+**[ajmeyghani](https://github.com/ajmeyghani) ([Learn GUN Basics with Diagrams](https://medium.com/@ajmeyghani/gundb-a-graph-database-in-javascript-3860a08d873c))**; **[anywhichway](https://github.com/anywhichway) ([Block Storage](https://github.com/anywhichway/gun-block))**; **[beebase](https://github.com/beebase) ([Quasar](https://github.com/beebase/gun-vuex-quasar))**; **[BrockAtkinson](https://github.com/BrockAtkinson) ([brunch config](https://github.com/BrockAtkinson/brunch-gun))**; **[Brysgo](https://github.com/brysgo) ([GraphQL](https://github.com/brysgo/graphql-gun))**; **[d3x0r](https://github.com/d3x0r) ([SQLite](https://github.com/d3x0r/gun-db))**; **[forrestjt](https://github.com/forrestjt) ([file.js](https://github.com/amark/gun/blob/master/lib/file.js))**; **[hillct](https://github.com/hillct) (Docker)**; **[JosePedroDias](https://github.com/josepedrodias) ([graph visualizer](http://acor.sl.pt:9966))**; **[JuniperChicago](https://github.com/JuniperChicago) ([cycle.js bindings](https://github.com/JuniperChicago/cycle-gun))**; **[jveres](https://github.com/jveres) ([todoMVC](https://github.com/jveres/todomvc))**; **[kristianmandrup](https://github.com/kristianmandrup) ([edge](https://github.com/kristianmandrup/gun-edge))**; **[Lightnet](https://github.com/Lightnet)** ([Awesome Vue User Examples](https://glitch.com/edit/#!/jsvuegunui?path=README.md:1:0) & [User Kitchen Sink Playground](https://gdb-auth-vue-node.glitch.me/)); **[lmangani](https://github.com/lmangani) ([Cytoscape Visualizer](https://github.com/lmangani/gun-scape), [Cassandra](https://github.com/lmangani/gun-cassandra), [Fastify](https://github.com/lmangani/fastify-gundb), [LetsEncrypt](https://github.com/lmangani/polyGun-letsencrypt))**; **[mhelander](https://github.com/mhelander) ([SEA](https://github.com/amark/gun/blob/master/sea.js))**; [omarzion](https://github.com/omarzion) ([Sticky Note App](https://github.com/omarzion/stickies)); [PsychoLlama](https://github.com/PsychoLlama) ([LevelDB](https://github.com/PsychoLlama/gun-level)); **[RangerMauve](https://github.com/RangerMauve) ([schema](https://github.com/gundb/gun-schema))**; **[robertheessels](https://github.com/swifty) ([gun-p2p-auth](https://github.com/swifty/gun-p2p-auth))**; **[rogowski](https://github.com/rogowski) (AXE)**; [sbeleidy](https://github.com/sbeleidy); **[sbiaudet](https://github.com/sbiaudet) ([C# Port](https://github.com/sbiaudet/cs-gun))**; **[Sean Matheson](https://github.com/ctrlplusb) ([Observable/RxJS/Most.js bindings](https://github.com/ctrlplusb/gun-most))**; **[Shadyzpop](https://github.com/Shadyzpop) ([React Native example](https://github.com/amark/gun/tree/master/examples/react-native))**; **[sjones6](https://github.com/sjones6) ([Flint](https://github.com/sjones6/gun-flint))**; **[Stefdv](https://github.com/stefdv) (Polymer/web components)**; **[zrrrzzt](https://github.com/zrrrzzt) ([JWT Auth](https://gist.github.com/zrrrzzt/6f88dc3cedee4ee18588236756d2cfce))**; **[xmonader](https://github.com/xmonader) ([Python Port](https://github.com/xmonader/pygundb))**; **[88dev](https://github.com/88dev) ([Database Viewer](https://github.com/88dev/gun-show))**;
I am missing many others, apologies, will be adding them soon!
+## Testing
+
+Tests may be run with `npm test`. Tests will trigger persistent writes to the DB, so subsequent runs of the test will fail. You must clear the DB before running the tests again. This can be done by running the following command in the project directory.
+
+```bash
+rm -rf *data*
+```
+
+### Additional Cryptography Libraries
+
+To install with npm, first install `npm install gun -S`.
+For just the networking layer, import Gun:
+
+```javascript
+var Gun = require('gun/gun');
+```
+
+If you also need to install SEA for user auth and crypto, also install some of its dependencies like this:
+
+`npm install @trust/crypto text-encoding node-webcrypto-ossl --save`
+
+You will need to require it too (it will be automatically added to the Gun object):
+
+```javascript
+var Gun = require('gun/gun');
+var Sea = require('gun/sea');
+```
+
+
## Deploy
To quickly spin up a Gun test server for your development team, utilize either [Heroku](http://heroku.com) or [Docker](http://docker.com) or any variant thereof [Dokku](http://dokku.viewdocs.io/dokku/), [Flynn.io](http://flynn.io), [now.sh](https://zeit.co/now), etc. !
diff --git a/as.js b/as.js
index 94505c64..f6ac4f37 100644
--- a/as.js
+++ b/as.js
@@ -80,12 +80,11 @@
}, wait || 200);
}
}
- as.sort = function(sort, el) {
- var vs = $(el).find('.sort');
- vs = (vs[0] && u === vs[0].value)? vs.text() : vs.val();
- var id = sort;
- var test = id >= vs;
- return test ? el : as.sort(sort, el.prev());
+ as.sort = function sort(id, li){
+ var num = parseFloat(id);
+ var id = $(li).find('.sort').text() || -Infinity;
+ var at = num >= parseFloat(id);
+ return at ? li : sort(id, li.prev());
}
$(document).on('keyup', 'input, textarea, [contenteditable]', as.wait(function(){
var el = $(this);
diff --git a/axe.js b/axe.js
new file mode 100644
index 00000000..a950e363
--- /dev/null
+++ b/axe.js
@@ -0,0 +1,99 @@
+;(function(){
+
+ /* UNBUILD */
+ var root;
+ if(typeof window !== "undefined"){ root = window }
+ if(typeof global !== "undefined"){ root = global }
+ root = root || {};
+ var console = root.console || {log: function(){}};
+ function USE(arg, req){
+ return req? require(arg) : arg.slice? USE[R(arg)] : function(mod, path){
+ arg(mod = {exports: {}});
+ USE[R(path)] = mod.exports;
+ }
+ function R(p){
+ return p.split('/').slice(-1).toString().replace('.js','');
+ }
+ }
+ if(typeof module !== "undefined"){ var common = module }
+ /* UNBUILD */
+
+ ;USE(function(module){
+ if(typeof window !== "undefined"){ module.window = window }
+ var tmp = module.window || module;
+ var AXE = tmp.AXE || function(){};
+
+ if(AXE.window = module.window){ try{
+ AXE.window.AXE = AXE;
+ tmp = document.createEvent('CustomEvent');
+ tmp.initCustomEvent('extension', false, false, {type: "AXE"});
+ (window.dispatchEvent || window.fireEvent)(tmp);
+ window.postMessage({type: "AXE"}, '*');
+ } catch(e){} }
+
+ try{ if(typeof common !== "undefined"){ common.exports = AXE } }catch(e){}
+ module.exports = AXE;
+ })(USE, './root');
+
+ ;USE(function(module){
+
+ var AXE = USE('./root'), Gun = (AXE.window||{}).Gun || USE('./gun', 1);
+ (Gun.AXE = AXE).GUN = AXE.Gun = Gun;
+
+ Gun.on('opt', function(at){
+ if(!at.axe){
+ at.axe = {};
+ var p = at.opt.peers, tmp;
+ // 1. If any remembered peers or from last cache or extension
+ // 2. Fallback to use hard coded peers from dApp
+ // 3. Or any offered peers.
+ //if(Gun.obj.empty(p)){
+ // Gun.obj.map(['http://localhost:8765/gun'/*, 'https://guntest.herokuapp.com/gun'*/], function(url){
+ // p[url] = {url: url, axe: {}};
+ // });
+ //}
+ // Our current hypothesis is that it is most optimal
+ // to take peers in a common network, and align
+ // them in a line, where you only have left and right
+ // peers, so messages propagate left and right in
+ // a linear manner with reduced overlap, and
+ // with one common superpeer (with ready failovers)
+ // in case the p2p linear latency is high.
+ // Or there could be plenty of other better options.
+ console.log("axe", at.opt);
+ if(at.opt.super){
+ function verify(msg, send, at) {
+ var peers = Object.keys(p), puts = Object.keys(msg.put), i, j, peer;
+ var soul = puts[0]; /// TODO: verify all souls in puts. Copy the msg only with subscribed souls?
+ for (i=0; i < peers.length; ++i) {
+ peer = p[peers[i]];
+ //if (peer.url) {console.log('AXE do not reject superpeers'); send(msg, peer); continue;} /// always send to superpeers?
+ if (!peer.id) {console.log('AXE peer without id: ', peer); continue;}
+ if (!Gun.subscribe[soul] || !Gun.subscribe[soul][peer.id]) { console.log('AXE SAY reject msg to peer: %s, soul: %s', peer.id, soul); continue; }
+ send(msg, peer);
+ }
+ }
+ AXE.say = function(msg, send, at) {
+ if (!msg.put) { send(msg); return; }
+ console.log('AXE HOOK!! ', msg);
+ verify(msg, send, at);
+ };
+ /// TODO: remove peer from all Gun.subscribe. On `mesh.bye` event?
+ }
+ if(at.opt.super){
+ at.on('in', USE('./lib/super', 1), at);
+ } else {
+ //at.on('in', input, at);
+ }
+ }
+ this.to.next(at); // make sure to call the "next" middleware adapter.
+ });
+
+ function input(msg){
+ var at = this.as, to = this.to;
+ }
+
+ module.exports = AXE;
+ })(USE, './axe');
+
+}());
diff --git a/examples/axe.html b/examples/axe.html
new file mode 100644
index 00000000..40dade3b
--- /dev/null
+++ b/examples/axe.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+ Testing AXE
+
+
+
+
+
+
+
+
+
diff --git a/test/tmp/li.html b/examples/basic/private.html
similarity index 96%
rename from test/tmp/li.html
rename to examples/basic/private.html
index df801459..24325c8c 100644
--- a/test/tmp/li.html
+++ b/examples/basic/private.html
@@ -73,7 +73,6 @@
-
+
+
+
+
+
\ No newline at end of file
diff --git a/test/tmp/tables.html b/examples/basic/tables.html
similarity index 100%
rename from test/tmp/tables.html
rename to examples/basic/tables.html
diff --git a/test/tmp/user.html b/examples/basic/user.html
similarity index 52%
rename from test/tmp/user.html
rename to examples/basic/user.html
index a7f52dfb..873d517c 100644
--- a/test/tmp/user.html
+++ b/examples/basic/user.html
@@ -5,40 +5,42 @@
+