The subspace client is a javascript library that works in a node.js or browser runtime. It allows you to build client-side applications for web, mobile, or desktop apps to store and retreive data through the subspace protocol and peer-to-peer device network.
Subspace is a decentralized NoSQL database, or key-value store, written entirely in javascript with a developer friendly API. Data hosted on subspace is sharded across a network of end user devices including mobile phones, tablets, desktops, servers, and custom farming hardware. Subspace hosts pledge free disk space to the network in order to earn subspace credits, which they receive for hosting and serving data for subspace apps. Developers may reserve space on the network by creating a client data contract through the subspace developer console.
To learn more about how the subspace protocol works browse the FAQ or read the technical white paper.
Example workflow
const Subspace = require('subspace-client')
// create the client instance
// a contract is only required to put new records
const client = new Subspace({
contract: '5cd2ac01f8f5bd5f149455925b3023e1c1c54133042477b59059e388df1366a4'
})
// connect to the network
client.join((error => {
if (error) throw(error)
// put a record to your database contract
client.put('hello subspace', (error, record) => {
if (error) throw(error)
console.log(record)
// {
// key: '678e749011f8a911f011e105c618db898a71f8759929cc9a9ebcfe7b125870ee',
// value: 'hello subspace'
// }
// get a record from your database contract
client.get(record.key, (error, value) => {
if (error) throw(error)
console.log(value) // -> 'hello subspace'
})
})
})
Creates a new client
instance that is used to interface with the subspace network.
options
: optional arguments to set identity and configure connection parameters
If no options are passed to the constructor a new subspace identity will be generated allowing the client to connect
and get
records from the subspace network. If a valid contract_id
is provided the client will be able to put
new record and rev
and del
records they own. Remaining options are purely optional, with suitable defaulst provided.
let options = {
contract: '5cd2ac...', // optional id for storage contract, obtained through the subspace console
name: 'Gavin Belson', // optional name to associate with profile
email: 'gavin@hooli.com', // optional email to associate with profile
passphrase: 'box_three', // optional passhprase to associate with profile
gateway_nodes: [], // optional, overirdes the default gateways for bootstrapping onto subspace
gateway_count: 1, // optional, default is 1
delegated: true, // optional, will delegate put/get of replicas to a first host for improved performance
}
Joins the subspace network by connecting to one or more gateway nodes, authenticating your public key, and fetching the latest tracker.
Returns a callback or promise on authentication with the first gateway.
Emit a connected
event when fully authenticated with all gateway nodes and tracker sync is complete.
Returns an error if failed
client.connect(error => {
if (error) throw(error)
console.log('Authenticated with a gateway node')
})
client.on('connected', () => {
console.log('Authenticated with all gateway nodes and fetched the tracker')
})
Writes some data to the subspace network. Data is encoded and encrypted based on the clients public key. Requires a signature from a valid data contract private key. Record type (mutable or immutable) is based on the underlying contract. Resolves once the record is written to the first host. Emits an event when the record is fully replicated on SSDB or if error during replication.
value
- the data to be stored. Valid types include boolean, number, string, array, json, binary, and buffer.
Returns the record object, a key-value pair with the derived key and value in the same format it was provided. Returns an error if failed. Emits an event when fully resolved.
Example
client.put('hello subspace', (error, record) => {
if (error) throw(error)
console.log('Record successfully put to subspace')
console.log(record)
// {
// key: '678e749011f8a911f011e105c618db898a71f8759929cc9a9ebcfe7b125870ee',
// value: 'hello subspace'
// }
})
client.on('put', (record, hosts) => {
console.log(`New record with id: ${record.key} has been fully replicated to all hosts, including: `)
hosts.forEach(hostId => console.log(`\n ${hostId}`))
})
Retrieves some data from the subspace network with a given record key (id). Data is decoded and decrypted using the clients private key. No data contract is required to get
records. Resolves once the record is retrieved from the first host. Emits an event when the record is fully retrieved and validated or if error during replication.
key
- 32 byte record key as a hex encoded string
Returns the record value in the same format it was provided. Returns an error if failed. Emits an event when fully resolved.
Example
client.get('678e749011f8a911f011e105c618db898a71f8759929cc9a9ebcfe7b125870ee', (error, value) => {
if (error) throw(error)
console.log('Succesfully got value from subspace')
console.log(value)
// 'hello subspace'
})
client.on('get', (record, hosts) => {
console.log(`Existing record with id: ${record.key} has been fully retrieved to all hosts, including: `)
hosts.forEach(hostId => console.log(`\n ${hostId}`))
})
Updates a mutable record. Resolves once the record is validated and replicated to the first valid host. Emits an event when the update is fully replicated on SSDB or if error during replication.
key
- 32 byte record key as a hex encoded stringvalue
- the new value to be assigned to this key. Does not have be the same type as previous value. Valid types include boolean, number, string, array, json, binary, and buffer.
Returns the new record object, a key-value pair with the same key and updated value in the same format it was provided. Returns an error if failed. Emits an event when fully resolved.
Example
client.rev('goodbye subspace', (error, record) => {
if (error) throw(error)
console.log('Record successfully updated on subspace')
console.log(record)
// {
// key: '678e749011f8a911f011e105c618db898a71f8759929cc9a9ebcfe7b125870ee',
// value: 'goodbye subspace'
// }
})
client.on('rev', (record, hosts) => {
console.log(`Update to existing record with id: ${record.key} has been fully replicated to all hosts, including: `)
hosts.forEach(hostId => console.log(`\n ${hostId}`))
})
Deletes a mutable record from a mutable contract. Resolves once the record is deleted from the first host. Emits an event when the delete is fully replicated on SSDB or if error replication.
key
- 32 byte record key as a hex encoded string
Returns an error if failed. Emits an event when fully resolved.
Example
client.del('678e749011f8a911f011e105c618db898a71f8759929cc9a9ebcfe7b125870ee', (error) => {
if (error) throw(error)
console.log('Succesfully started record deletion from subspace')
})
client.on('del', (record, hosts) => {
console.log(`Existing record with id: ${record.key} has been fully deleted from all hosts, including: `)
hosts.forEach(hostId => console.log(`\n ${hostId}`))
})
Leaves the subspace network by gracefully disconnecting from all nodes you are directly connected to.
Returns a callback or promise on send of all disconnect notifications.
Emits a disconnected
event when all connections are fully closed.
client.disconnect(error => {
if (error) throw(error)
console.log('Notified all peers I am leaving')
})
client.on('disconnected', () => {
console.log('All peers connections have been closed')
})
subspace-client ships with native Promise support out of the box.
Each function taking a callback also can be used as a promise, if the callback is omitted. This applies for:
client.join()
client.get(key)
client.put(key, value)
client.rev(key, value)
client.del(key)
client.leave()
client.join(error => {
if (error) throw(error)
console.log('connected to subspace network')
client.put('hello subspace', (error, record) => {
if (error) throw(error)
console.log('put a new record to remote host')
client.get(record.key, (error, value) => {
if (error) throw(error)
assert(record.value === value)
console.log('got same record back from remote host ')
return record
})
})
})
client.join()
.then(() => {
console.log('connected to subspace network')
client.put('hello subspace')
})
.then(record => {
console.log('put a new record to remote host')
client.get(record.key)
})
.then(value => {
assert(record.value === value)
console.log('got same record back from remote host ')
return(record)
})
.catch(error => {
throw(error)
})
const testSubspace = async () => {
try {
await client.join()
console.log('connected to subspace network')
const record = await client.put('hello subspace')
console.log('put a new record to remote host')
const value = await client.get(record.key)
assert(record.value === value)
console.log('got same record back from remote host ')
return record
}
catch (error) {
throw(error)
}
}
client
is an EventEmitter
and emits the following events.
Event | Description | Arguments |
---|---|---|
connected |
Client has fully joined network | - |
put |
Record replicated to all hosts | record: object, hosts: array |
get |
Record retrieved from all hosts | record: object, hosts: array |
rev |
Updated record replicated on all hosts | record: object, hosts: array |
del |
Record deleted from all hosts | record: object, hosts: array |
disconnected |
Client has fully left the network | - |
For example you can do:
client.on('put', (record, hosts) => {
console.log(`New record with id: ${record.key} has been fully replicated to all hosts, including: `)
hosts.forEach(hostId => console.log(`\n ${hostId}`))
})