-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Think these docs could be improved? Contribute to the wiki! Or comment.
Core API
Main API
User API (authenticated)
- gun.user.create
- gun.user.auth TBD
- gun.user.leave TBD
- gun.user.delete TBD
- gun.user.recall TBD
- gun.user.alive TBD
- gun.user.trust TBD
- gun.user.grant TBD
- gun.user.secret TBD
Extended API
Utils
Used to create a new gun database instance.
var gun = Gun(options)
note:
Gun
works with or without thenew
operator.
-
no parameters
undefined
creates a local datastore using the default persistence layer, either localStorage or Radisk. -
passing a URL
string
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 within the options object. An array alone is also valid. e.g.
- or you can pass in an
var gun = Gun({peers: ['http://localhost:8765/gun', 'http://gun-manhattan.herokuapp.com/gun']})
var gun = Gun(['http://localhost:8765/gun', 'http://gun-manhattan.herokuapp.com/gun'])
-
the previous options are actually aggregated into an
object
, which you can pass in yourself.-
options.peers
is an object, where the URLs are properties, and the value is an empty object. -
options.radisk
(boolean, default:true
) creates and persists local (nodejs) data using Radisk. -
options.localStorage
(boolean, default:true
) persists local (browser) data to localStorage. -
options.uuid
allows you to override the default 24 random alphanumeric soul generator with your own function. -
option.web
allows to define a web socket server to which web pages can connect. This is can be used for Gun instances running as a Node server to provide access for web page clients under http://domainname/gun. -
options['module name']
allows you to pass options to a 3rd party module. Their project README will likely list the exposed options. Here is a list of such modules...
-
Sync with one peer
Gun('http://yourdomain.com/gun')
Sync with many peers
Gun({peers: ['http://server1.com/gun', 'http://server2.com/gun']})
Working with modules
Gun({
// Amazon S3 (comes bundled)
s3: {
key: '',
secret: '',
bucket: ''
},
// simple JSON persistence (bundled)
// meant for ease of getting started
// NOT meant for production
file: 'file/path.json',
// set your own UUID function
uuid: function () {...}
})
Start web socket server
const server = createServer()
const host = 'localhost'
const port = 9999
const gun = Gun({web: server});
server.listen(port, () => {
console.info(
'Gun server started on port ' + port + ' with /gun',
)
})
There's currently no single method provisioned to quickly check whether you're connected, or to how many peers. However, you can retrieve gun's backend list of peers, and then filter the list on specific parameters (which might change as Gun is currently reaching an alchemical state of transmutation).
const opt_peers = gun.back('opt.peers'); // get peers, as configured in the setup
let connectedPeers = _.filter(Object.values(opt_peers), (peer) => {
return peer
&& peer.wire
&& peer.wire.readyState === 1
&& peer.wire.OPEN === 1
&& peer.wire.constructor.name === 'WebSocket';
});
The length of connectedPeers
corresponds to the connected peers, which you can now use in your UI.
Here again, due to convoluted reasons which need high priority addressing, after going offline and then hopping back on, GUN doesn't reliably re-connect to its peers (unless you'd refresh the page/app). In some cases, the peers even get removed from the opt.peers
list which we've accessed above to count connected peers.
It's being debated how to approach this most reasonably. In the meantime you can trigger a reconnect by re-adding the peers to GUN's opt list using the following code:
gun.opt({peers: ['http://server1.com/gun', 'http://server2.com/gun']}); // re-add peers to GUN-options
gun.get('key').get('heartbeat').put('heartbeat') // optional: tell GUN to put something small, forcing GUN to establish connection, as GUN is lazy by nature to make it save on data transfer. necessary for receiving missing on() events.
In the case of counting your peers using the previous example, after reconnecting you'll see the peer count go back up.
Save data into gun, syncing it with your connected peers.
It has two parameters, and only the first is required:
- the
data
to save - an optional
callback
, invoked on each acknowledgment
gun.get('key').put({hello: "world"}, function(ack){})
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.
.put
restricts the input to a specific subset:
Other values, like undefined
, NaN
, Infinity
, arrays
, will be rejected.
Traditional arrays are dangerous in real-time apps. Use gun.set instead.
Note: when using
.put
, if any part of the chain does not exist yet, it will implicitly create it as an empty object.
gun.get('something').get('not').get('exist').get('yet').put("Hello World!");
// `.put` will if needed, backwards create a document
// so "Hello World!" has a place to be saved.
-
ack.err
, if there was an error during save. -
ack.ok
, if there was a success message (none is required though).
The callback
is fired for each peer that responds with an error or successful persistence message, including the local cache. Acknowledgement can be slow, but the write propagates across networks as fast as the pipes connecting them.
If the error property is undefined, then the operation succeeded, although the exact values are left up to the module developer.
Saving objects
gun.get('key').put({
property: 'value',
object: {
nested: true
}
})
Saving primitives
// strings
gun.get('person').get('name').put('Alice')
// numbers
gun.get('IoT').get('temperature').put(58.6)
// booleans
gun.get('player').get('alive').put(true)
Using the callback
gun.get('survey').get('submission').put(submission, function(ack){
if(ack.err){
return ui.show.error(ack.err)
}
ui.show.success(true)
})
gun.put
does not change the gun context.
gun.get('key').put(data) /* same context as */ gun.get('key')
You cannot save primitive values at the root level.
Gun().put("oops"); // error
Gun().get("odd").put("oops"); // error
All data is normalized to a parent node.
Gun().put({foo: 'bar'}); // internally becomes...
Gun().get(randomUUID).put({foo: 'bar'});
Gun().get('user').get('alice').put(data); // internally becomes...
Gun().get('user').put({'alice': data});
// An update to both user and alice happens, not just alice.
You can save a gun chain reference,
var ref = Gun().put({text: 'Hello world!'})
Gun().get('message').get('first').put(ref)
But you cannot save it inline, yet.
var sender = Gun().put({name: 'Tom'})
var msg = Gun().put({
text: 'Hello world!',
sender: sender // this will fail
})
// however
msg.get('sender').put(sender) // this will work
Be careful saving deeply nested objects,
Gun().put({
foo: {
bar: {
lol: {
yay: true
}
}
}
}):
For the most part, gun will handle this perfectly fine. It will attempt to automatically merge every nested object as a partial. However, if it cannot find data (due to a network failure, or a peer it has never spoken with) to merge with it will generate new random UUIDs. You are unlikely to see this in practice, because your apps will probably save data based on user interaction (with previously loaded data). But if you do have this problem, consider giving each one of your sub-objects a deterministic ID.
Where to read data from.
It takes two parameters:
key
callback
gun.get('key').get('property', function(ack){})
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).
The key
is the ID or property name of the data that you saved from earlier (or that will be saved later). It can also be a Lex expression allowing to filter, limit and paginate results.
Note that if you use
.put
at any depth after aget
it first reads the data and then writes, merging the data as a partial update.
gun.get('key').put({property: 'value'})
gun.get('key').on(function(data, key){
// {property: 'value'}, 'key'
})
-
ack.put
, the raw data. -
ack.get
, the key, ID, or property name of the data.
The callback is a listener for read errors, not found, and updates. It may be called multiple times for a single request, since gun uses a reactive streaming architecture. Generally, you'll find .not
, .on
, and .once
as more convenient for every day use. Skip to those!
gun.get(key, function(ack){
// called many times
})
Retrieving a key
// retrieve all available documents
gun.get('documents').map().on(ui.show.documents)
Using the callback
gun.get(key, function(ack){
if(ack.err){
server.log(error)
} else
if(!ack.put){
// not found
} else {
// data!
}
})
Chaining multiple get
s together changes the context of the chain, allowing you to access, traverse, and navigate a graph, node, table, or document.
Note: For users upgrading versions, prior to v0.5.x
get
used to always return a context from the absolute root of the database. If you want to go back to the root, either save a referencevar root = Gun();
or now use.back(-1)
.
gun.get('user').get('alice') /* same context as */ gun.get('users').get('alice')
Most callbacks in gun will be called multiple times.
Change the configuration of the gun database instance.
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.
Create the gun instance.
gun = Gun('http://yourdomain.com/gun')
Change UUID generator:
gun.opt({
uuid: function () {
return Math.floor(Math.random() * 4294967296);
}
});
Add more peers:
gun.opt({peers: ['http://anotherdomain.com/gun']})
/* Now gun syncs with ['http://yourdomain.com/gun', 'http://anotherdomain.com/gun']. */
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.
The number of times you want to go back up the chain. -1
or Infinity
will take you to the root.
Moving to a parent context
gun.get('users')
/* now change the context to alice */
.get('alice')
.put(data)
/* go back up the chain once, to 'users' */
.back().map(...)
Another example
gun.get('player').get('game').get('score').back(1)
// is the same as...
gun.get('player').get('game')
The context will always be different, returning you to the
gun.get('key').get('property')
/* is not the same as */
gun.get('key').get('property').back()
Subscribe to updates and changes on a node or property in realtime.
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. This removes all listeners. To remove a specific listener, the best current solution is as follows (more details here):
var ev = null
var listenerHandler = (value, key, _msg, _ev) => {
ev = _ev
//...
}
node.on(listenerHandler)
node.get('someValue').put(6) //trigger listener to set ev
ev.off() //remove listener
Note: If data is a node (object), it may have
_
meta property on it. If you delete an item, you might get anull
tombstone.
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.
Longhand syntax
// add listener to foo
gun.get('foo').on(callback, {
change: true
})
// remove listener to foo
gun.get('foo').off()
Shorthand syntax
// add listener to foo
gun.get('foo').on(callback, true)
// remove listener to foo
gun.get('foo').off()
Listening for updates on a key
gun.get('users').get(username).on(function(user){
// update in real-time
if (user.online) {
view.show.active(user.name)
} else {
view.show.offline(user.name)
}
})
Listening to updates on a field
gun.get('lights').get('living room').on(function(state, room){
// update the UI when the living room lights change state
view.lights[room].show(state)
})
❗ There's a 'bug' when dealing with multiple levels.
gun.get('home').get('lights').on(cb,true);
gun.get('home').get('lights').put({state:'on'}) // BAD fires twice
gun.get('home').get('lights').get('state').put('on') // GOOD fires once
gun.on
does not change the chain context.
gun.get(key).on(handler) /* is the same as */ gun.get(key)
Data is only 1 layer deep, a full document is not returned (see the gun.open extension for that), this helps keep things fast.
It will be called many times.
Get the current data without subscribing to updates. Or undefined
if it cannot be found.
-
wait
controls the asynchronous timing (see unexpected behavior, below).gun.get('foo').once(cb, {wait: 0})
The data is the value for that chain at that given point in time. And the key is the last property name or ID of the node.
Note: If data is a node (object), it may have
_
meta property on it. If you delete an item, you might get anull
tombstone. If the data cannot be found,undefined
may be called back.
gun.get('peer').get(userID).get('profile').once(function(profile){
// render it, but only once. No updates.
view.show.user(profile)
})
Reading a property
gun.get('IoT').get('temperature').once(function(number){
view.show.temp(number)
})
gun.once
does not currently change the context of the chain, but it is being discussed for future versions that it will - so try to avoid chaining off of .once
for now. This feature is now in experimental mode with v0.6.x
, but only if .once()
is not passed a callback. A useful example would be gun.get('users').once().map().on(cb)
this will tell gun to get the current users in the list and subscribe to each of them, but not any new ones. Please test this behavior and recommend suggestions.
.once
is synchronous and immediate (at extremely high performance) if the data has already been loaded.
.once
is asynchronous and on a debounce timeout while data is still being loaded - so it may be called completely out of order compared to other functions. This is intended because gun streams partials of data, so once
avoids firing immediately because it may not represent the "complete" data set yet. You can control this timeout with the wait
option.
once
fires again if you update that node from within it.
Example for once
firing again with an update from within:
node.once(function(data, key) {
node.get('something').put('something')
}
Data is only 1 layer deep, a full document is not returned (see the gun.load extension for that), this helps keep things fast.
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.
To remove items from a set, see gun.unset.
Data should be a gun reference or an object.
var user = gun.get('alice').put({name: "Alice"});
gun.get('users').set(user);
The callback is invoked exactly the same as .put
, since .set
is just a convenience wrapper around .put
.
var gun = Gun();
var bob = gun.get('bob').put({name: "Bob"});
var dave = gun.get('dave').put({name: "Dave"});
dave.get('friends').set(bob);
bob.get('friends').set(dave);
The "friends" example is perfect, since the set guarantees that you won't have duplicates in your list.
gun.set
changes the chain context, it returns the item reference.
gun.get('friends') /* is not the same as */ gun.get('friends').set(friend)
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. It accepts one argument:
- a
callback
function that transforms the data as it passes through. If the data is transformed toundefined
it gets filtered out of the chain. - the
callback
gets two arguments (value,key) and will be called once for each key value pair in the objects that are returned frommap
.
Note: As of
v0.6.x
the transform function is in experimental mode. Please play with it and report bugs or suggestions on how it could be improved to be more useful.
If your data is cyclic and has a lot of self-references, you may receive multiple callbacks with the same result. For example: "Alice is both the president of the company, the wife of Bob, and the friend to the cat." This would return 3 times:
key: president value: alice,
key: wife value: alice,
key: friend value: alice
.map does not exclude or unify nodes, because they exist in different contexts, it is up to you on either UI side or in structuring your data to take this into account.
Iterate over an object
/*
where `stats` are {
'new customers': 35,
'returning': 65
}
*/
gun.get('stats').map().on(function(percent, category) {
pie.chart(category, percent)
})
The first call to the above will be with (35,'new customers') and the second will be with (65,'returning').
Or forEach
ing through every user.
/*
{
user123: "Mark",
user456: "Dex",
user789: "Bob"
}
*/
gun.get('users').map().once(function(user, id){
ui.list.user(user);
});
The above will be called 3 times.
Here's a summary of .map() behavior depending on where it is on the chain:
- users.map().on(cb) subscribes to changes on every user and to users as they are added.
- users.map().once(cb) gets each user once, including ones that are added over time.
- users.once().map().on(cb) gets the user list once, but subscribes to changes on each of those users (not added ones).
- users.once().map().once(cb) gets the user list once, gets each of those users only once (not added ones).
Iterate over and only return matching property
/*
{
user123: "Mark",
user456: "Dex",
user789: "Bob"
}
*/
gun.get('users').map(user => user.name === 'Mark'? user : undefined).once(function(user, id){
ui.list.user(user);
});
Will only return user123: "Mark", as it was the only match.
.map
changes the context of the chain to hold many chains simultaneously. Check out this example:
gun.get('users').map().get('name').on(cb);
Everything after the map()
will be done for every item in the list, such that you'll get called with each name for every user in the list. This can be combined in really expressive and powerful ways.
gun.get('users').map().get('friends').map().get('pet').on(cb);
This will give you each pet of every friend of every user!
gun.get(key).map() /* is not the same as */ gun.get(key)
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<script src="https://cdn.jsdelivr.net/npm/gun/lib/path.js"></script>
!
Path does the same thing as get
but has some conveniences built in.
The key property
is the name of the field to move to.
// move to the "themes" field on the settings object
gun.get('settings').path('themes')
Once you've changed the context, you can read, write, and path
again from that field. While you can just chain one path
after another, it becomes verbose, so there are two shorthand styles:
- dot format
- array format
Here's dot notation in action:
// verbose
gun.get('settings').path('themes').path('active')
// shorthand
gun.get('settings').path('themes.active')
// which happens to be the the same as
gun.get('settings').get('themes').get('active')
And the array format, which really becomes useful when using variables instead of literal strings:
gun.get('settings').path(['themes', themeName])
The dot notation can do some strange things if you're not expecting it. Under the hood, everything is changed into a string, including floating point numbers. If you use a decimal in your path, it will split into two paths...
gun.path(30.5)
// interprets to
gun.path(30).path(5)
This can be especially confusing as the chain might never resolve to a value.
Note: For users upgrading from versions prior to v0.5.x,
path
used to be necessary - now it is purely a convenience wrapper aroundget
.
Navigating to a property
/*
where `user` is {
name: 'Bob'
}
*/
gun.get('user').path('name')
Once you've focused on the name
property, you can chain other methods like .put
or .on
to interact with it.
Moving through multiple properties
/*
where `user` is {
name: { first: 'bob' }
}
*/
gun.get('user').path('name').path('first')
// or the shorthand...
gun.get('user').path('name.first')
gun.path
creates a new context each time it's called, and is always a result of the previous context.
gun.get('API').path('path').path('chain')
/* is different from */
gun.get('API').path('path')
/* and is different from */
gun.get('API')
Warning: Not included by default! You must include it yourself via
require('gun/lib/not.js')
or<script src="https://cdn.jsdelivr.net/npm/gun/lib/not.js"></script>
! Handle cases where data can't be found.
If you need to know whether a property or key exists, you can check with .not
. It will consult the connected peers and invoke the callback if there's reasonable certainty that none of them have the data available.
Warning:
.not
has no guarantees, since data could theoretically exist on an unrelated peer that we have no knowledge of. If you only have one server, and data is synced through it, then you have a pretty reasonable assurance that anot
found means that the data doesn't exist yet. Just be mindful of how you use it.
If there's reason to believe the data doesn't exist, the callback will be invoked. This can be used as a check to prevent implicitly writing data (as described in .put
.
The name of the property or key that could not be found.
Providing defaults if they aren't found
// if not found
gun.get('players/3').not(function(key){
// put in an object and key it
gun.get(key).put({
active: false
});
}).on(handler)
// listen for changes on that key
Setting a property if it isn't found
gun.get('chat').get('enabled').not(function(key){
this.put(false)
})
.not
does not change the context of the chain.
gun.get(key).not(handler) /* is the same as */ gun.get(key)
Warning: Not included by default! You must include it yourself via
require('gun/lib/open.js')
or<script src="https://cdn.jsdelivr.net/npm/gun/lib/open.js"></script>
!
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.
Note: This will automatically load everything it can find on the context. This may sound convenient, but may be unnecessary and excessive - resulting in more bandwidth and slower load times for larger data. It could also result in your entire database being loaded, if your app is highly interconnected.
The callback has 1 parameter, and will get called every time an update happens anywhere in the full depth of the data.
-
data
. Unlike most of the API,open
does not give you a node. It gives you a copy of your data with all metadata removed. Updates to the callback will return the same data, with changes modified onto it.
// include .open
gun.get('person/mark').open(function(mark){
mark; // {name: "Mark Nadal", pet: {name: "Frizzles", species: "kitty", slave: {...}}}
});
var human = {
name: "Mark Nadal",
pet: {
name: "Frizzles",
species: "kitty" // for science!
}
};
human.pet.slave = human;
gun.get('person/mark').put(human);
.open
does not change the context.
gun.get('company/acme').open(cb).get('employees').map().once(cb)
If you do not use a schema with .open(cb)
it can only best guess and approximate whether the data is fully loaded or not. As a result, do not assume all the data will be available on the first callback - it may take several calls for things to fully load, so code defensively! By default, it waits 1ms after each piece of data it receives before triggering the callback. You can change the default by passing an option like .open(cb, {wait: 99})
which forces it to wait 99ms before triggering (which is the default gun.once has).
Warning: Not included by default! You must include it yourself via
require('gun/lib/load.js')
or<script src="https://cdn.jsdelivr.net/npm/gun/lib/open.js"></script><script src="https://cdn.jsdelivr.net/npm/gun/lib/load.js"></script>
!
Loads the full object once. It is the same as open
but with the behavior of once
.
Could be buggy until official!
Warning: Not included by default! You must include it yourself via
require('gun/lib/then.js')
or<script src="https://cdn.jsdelivr.net/npm/gun/lib/then.js"></script>
!
Returns a promise for you to use.
Note: a gun chain is not promises! You must include and call
.then()
to promisify a gun chain!
cb
is a function that has 1 parameter.
resolved
is the data.
Could be buggy until official!
.then(cb)
has a cousin of .promise(cb)
which behaves the same way except that resolved
is an object with:
resolved = {
put: data,
get: key,
gun: ref // if applicable
}
In case you need more context or metadata.
It is no longer a gun chain, but you can chain promises off of it!
Promise.race([
gun.get('alice').then(), // must be called!
gun.get('bob').then() // must be called!
])
Or use it with async
!
async function get(name) {
var node = await gun.get(name).then();
return node;
};
A gun chain is not already a promise, you must call then()
to make it a promise.
Warning: Consider this deprecated, or at least no longer supported! You must include it yourself via
require('gun/lib/bye.js')
or<script src="https://cdn.jsdelivr.net/npm/gun/lib/bye.js"></script>
!
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".
Note: This requires a server side component, and therefore must be included there as well in order for this to work. In the future it should be generalizable to P2P settings, however may not be as reliable.
It returns a special chain context with only 1 method on it of put
. It currently does not support chaining, however in the future we hope to make it more chainable. Keep this in mind until then.
gun.get('marknadal').get('status').put("I'm online!");
gun.get('marknadal').get('status').bye().put("I'm offline. :(");
Even though this is written entirely in the browser, the put
will get called on the server when this browser tab disconnects.
Note: A user might have multiple tabs open on your website, just because they close 1 tab does not mean they are now offline. We recommend you use
.bye()
for data related to browser tab sessions, and then aggregate those sessions together to determine if the the user as a whole is online or offline.
var player = gun.get('kittycommando1337');
gun.get('game').get('players').set(player);
gun.get('game').get('players').get('kittycommando1337').bye().put(null);
This deletes the player from the game when they go offline or disconnect from the server. It does not delete the player, just whether they are a player of the game or not.
bye()
is in experimental alpha, please report any problems or bugs you have with it. Note again that it does not fire immediately, and it does not get run from the browser. It makes the data change on the server when that browser tab disconnects.
Warning: Not included by default! You must include it yourself via
require('gun/lib/later.js')
or<script src="/gun/lib/open.js"></script><script src="https://cdn.jsdelivr.net/npm/gun/lib/later.js"></script>
!
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.
-
data
, is a safe snapshot of what you saved, including full depth documents or circular graphs, without any of the metadata. -
key
is the name of the data. -
this
is the gun reference that it was called with.
Is the number of seconds you want to wait before firing the callback.
It returns itself, as in gun.later() === gun
.
See a full working example here, at jsbin!
gun.get('foo').put(data).later(function(data, key){
this.get('session').put(null); // expire data!
}, 2); // 2 seconds!
-
Exact timing is not guaranteed! Because it uses
setTimeout
underneath. Further, after the timeout, it must then open and load the snapshot, this will likely add at least1
ms to the delay. Experimental: If this is problematic, please report it, as we can modify the implementation oflater
to be more precise.) -
If a process/browser has to restart, the timeout will not be called. Experimental: If this behavior is needed, please report it, as it could be added to the implementation.
Warning: Not included by default! You must include it yourself via
require('gun/lib/unset.js')
or<script src="https://cdn.jsdelivr.net/npm/gun/lib/unset.js"></script>
!
After you save some data in an unordered list, you may need to remove it.
let gun = new Gun();
let machines = gun.get('machines');
let machine = gun.get('machine/tesseract');
machine.put({faces: 24, cells: 8, edges: 32});
// let's add machine to the list of machines;
machines.set(machine);
// now let's remove machine from the list of machines
machines.unset(machine);
While running, Gun provides several high-level utility functions for querying and manipulating our components.
Note the capital "G" in Gun
, as opposed to an instance variable called gun
.
Returns true if data
is a gun node, otherwise false.
Deprecated! It was used to return data
's gun
ID. Use data._["#"]
instead. NOTE! It works only if received data is an object, not a primitive value.
gun.get('test').get('node').put({text:'hello'})
gun.get('test').get('node').once(data=> console.log(data._['#'])) // test/node
Returns a "gun-ified" variant of the json
input by injecting a new gun ID into the metadata field.