Getting Started
Introduction
Axiom is a platform for building decentralized applications. It is also a cryptocurrency. If you've used application platforms like Heroku or App Engine before, you'll find parts of this familiar. If you've developed an application using other cryptocurrencies like Ethereum before, you'll find different parts of this familiar.
Currently, Axiom primarily targets web applications built in JavaScript. If you know how to make a simple website, you'll be able to deploy a simple decentralized site. To build a more complicated application, you'll probably want to be familiar with a JavaScript framework like React or Vue.
The best way to learn about the Axiom system is to build a simple application on it. The Getting Started section of this documentation will explain how to get an account set up and how to deploy a simple static site to Axiom. The Building Applications section will explain how to build a slightly more complicated application. If you're interested in learning more, the later sections will go into more detail.
If you run into any bugs, we would really appreciate it if you report them in the GitHub issues.
Thanks for reading!
Installing the CLI
There are several different ways to interact with Axiom. Servers running the Axiom blockchain and hosting Axiom files interact with each other through the wire protocol. Application code typically interacts with Axiom through the JavaScript Axiom client. During the development process, the most convenient way to interact with Axiom is typically through the CLI.
The CLI is tested on OS X and Linux. It might also work in Windows.
You can install the CLI using npm or yarn:
npm install -g axiom-cli
yarn global add axiom-cli
Signing Up
The Axiom system stores data in two different ways. The blockchain is replicated among every machine running Axiom. Storage space there is limited, but it is very reliable. Account data, like public keys to validate users, and balances indicating how much cryptocurrency is owned by each account, is kept on the blockchain.
File storage, on the other hand, is not replicated among every machine running Axiom. Files stored on Axiom will only be replicated to a few different machines. Only hash values of file content will be stored on the blockchain.
To store any data in Axiom, you'll need to acquire some cryptocurrency, to pay for storage. To make this easier during the beta period, we have a faucet set up to give out a small amount of currency to use for development.
To sign up, first register your email here. Then run this command:
axiom signup youremail@example.com
You will have to enter a token that was emailed to you, so please use a legitimate email address.
The signup command will log in the CLI and generate a secure passphrase for you. Keep this somewhere secure.
Once you complete the signup command, you should have enough money in your account to pay for the storage used in application development. To check your account balance, run:
axiom status
Log in using the passphrase that the signup
command generated.
You should see output that displays a balance greater than
zero. Congratulations, you now own some of the Axiom cryptocurrency!
Creating a Bucket
To understand file storage on Axiom, it is helpful to understand the concepts of buckets and hosting providers. An Axiom bucket is similar to an Amazon S3 bucket. A bucket can hold many files, and a user can own many buckets. Each bucket has a capacity for how many files it can store. One of your buckets could hold the static content for a web application you are deploying, or it could hold the data for an application you are using, or it could hold any sort of files you would like to keep in decentralized storage.
Data on the blockchain is replicated among every machine running the blockchain. Data in a bucket is only replicated among a few different hosting providers. This makes it relatively inexpensive to store data in a bucket. With the developer faucet, you should have enough to pay for about 100 megabytes of bucket storage.
Let's make a bucket. Pick a unique name like "my-cool-example". Names are unique, so if you pick this exact one it probably won't work because someone else will have gone through the example. Bucket names also have to be at least six letters long.
First, we have to create a new bucket. Let's pick a size of 1 megabyte because we're just using this as an example:
axiom create-bucket my-cool-example 1
You should see output that looks like:
created bucket: www:my-cool-example
Bucket: www:my-cool-example
owner: 0x32bbd7e6ffc293bd586953bc2d66aa4f30269e4ab7a084d29f94d2a1fdab9858fe19
size: 1
magnet: magnet:?xt=urn:btih:4185e95e9f147f2f245da786f79a6e7ca3e5455b&dn=.&tr=ws%3A%2F
4 providers
The www
is the application tag for this bucket. It defaults to www
which indicates that these files are intended for web access.
The create-bucket
command will automatically allocate the bucket to a
few hosting providers for you. Either the owner of a bucket or the
hosting provider can deallocate the bucket at any time. As a developer, you
might want to reallocate a bucket elsewhere if a hosting provider is providing
a poor service level. As a hosting provider, you might want to
deallocate a bucket if you discover that it is hosting content that
you don't want to be hosting. Providers are never forced to host
particular files.
Storing Files
Now that you've created a bucket, you can upload files to that
bucket. The simplest way to upload files is to use the axiom upload
command to upload the contents of a local directory to a bucket:
mkdir ~/my-cool-example
cd ~/my-cool-example
echo "hello decentralized world" > index.html
axiom upload . my-cool-example
When you run an upload, the files are transferred to the hosting providers via WebTorrent. The blockchain only contains a single hash value encoded in a magnet URI, so that other users can verify the contents of the bucket.
Using the WebTorrent protocol for uploads and downloads means that the costs of file hosting for providers don't scale linearly according to the number of downloads, and can be amortized into the base cost of the bucket. When you update the blockchain, you do have to pay a fee. The CLI by default attempts to use a 0-fee transaction. Since the blockchain uses the Stellar Consensus Protocol, hopefully these fees can stay very small over time even as blockchain usage increases.
Now that we've uploaded content to a bucket, let's download it to make sure it's working.
mkdir ~/testdir
cd ~/testdir
axiom download my-cool-example
You should be able to inspect the newly-created ~/testdir
directory
to see a copy of your uploaded file.
Decentralized Websites
Any bucket can be used to upload and download files. Since we stored
this data in a bucket with the application tag www
, the convention
is that these files are meant to be used as a website, with the root
page in index.html
.
Normal websites are based on a domain name which is found through a centralized domain name registry. Since an Axiom application is based on files that are available through decentralized buckets, it can be accessed without depending on this centralized registry.
The easiest way to do so is to install the Axiom Authenticator
Chrome extension.
When you install this extension, domains that end with .axiom
will
be loaded from an Axiom bucket, rather than doing a DNS lookup and
loading content over HTTP. .axiom
isn't a real domain, so this
shouldn't cause conflict with any normal websites.
After installing the authenticator, check out your site in your browser, with a URL like:
http://my-cool-example.axiom/
Replace my-cool-example
with your bucket name, and you should see
the contents of your index.html
, loaded as a website.
Congratulations! You have now distributed your "hello world" application on the decentralized web. Read on to learn about building more complicated applications that interact with user data.
Building an Application
A React Example
There are two logical parts to an Axiom application. First, the application code is a bundle of JavaScript, HTML, and other files that works like a website. This code is stored in a bucket owned by the app developer. Second, there is user data, which contains things like blog posts, messages, or profile pictures. This data is stored in separate buckets, each owned by a different user. An application interacts with user data via the JavaScript Axiom API.
When building an Axiom application, you can use any framework that outputs JavaScript and HTML. This includes tools like React, Angular, and Vue. You can't use server-side frameworks like Rails, Django, or PHP.
This section of the documentation will demonstrate the basics of Axiom apps, using an example app written with React. We won't do anything too React-centric, so if you don't know React, hopefully you can follow along and figure out how this would work in your favorite framework.
The easiest way to follow along is to clone this GitHub repository with our example React app:
git clone git@github.com:axiom-org/react-example.git
There isn't much in this repo. To make it, we ran
create-react-app,
ran npm install axiom-api
, and removed some stuff we aren't
going to use. App.js
is the file that contains all the code we're
going to write. To start out, it contains:
import React from "react";
import Axiom from "axiom-api";
export default class App extends React.Component {
constructor(props) {
super(props);
this.axiom = new Axiom();
this.state = {
message: null
};
}
async onClick() {
this.setState({ message: "click!" });
}
render() {
if (this.state.message) {
return <p>{this.state.message}</p>;
}
return <button onClick={() => this.onClick()}>Click Me</button>;
}
}
All this app does so far is display a button that says "Click Me", and when you click it, it displays the message "click!". To serve it on localhost, run:
npm start
It's a useful shell for experimenting with the Axiom API, because we can edit the
onClick
function to do different things.
If you're familiar with React, this app should look pretty straightforward. The only parts that relate to Axiom are constructing the Axiom object:
import Axiom from "axiom-api";
this.axiom = new Axiom();
The Axiom object provides access to the Axiom API. You only need to
create one of them at a time, and it's a good idea to only create one
because it will automatically cache some things for you. We can create it
in the constructor of App
here because the App
component only gets
rendered once.
The following sections will show you different things you can do with
this axiom
object.
Logging In
The first thing we can get from the Axiom API is an identity. This is useful so that we can store information specific to the person who is currently using the application.
We can use the axiom.getPublicKey method to access the current
user. Try replacing the onClick
logic with this:
async onClick() {
let key = await this.axiom.getPublicKey();
this.setState({ message: `your public key is ${key}` });
}
When you run npm start
, the application will reload whenever you
change its code, so if you already have it running, you don't need to
run it again.
Now, clicking the button will attempt to log the user in. Try it out, with the Axiom Authenticator Chrome extension installed. You should see a popup asking for permission. If you haven't configured the extension yet, you will need to enter your private key, which you can get by running axiom get-private-key:
axiom get-private-key
The extension will ask you to set a password, so you don't need to
enter your private key every time you are authenticating a website. Once you
accept the permission, the getPublicKey
method in the application
will return, and the application will display your public key.
It's important that getPublicKey
is an async function. By default,
the extension doesn't share any information about users with
websites. The user has to grant permission each time. This might take
some time, so the method can't return immediately, and has to be
asynchronous. However, if the user has already granted this
permission, getPublicKey
will return immediately.
Permissions are not stored globally. They are only stored in the extension. That means users need to give permission to an application separately for every browser they are using to access it. This is similar to regular password-protected application access - you typically need to log in separately on each device. Because the extension stores the authentication keys, applications no longer have the ability to authenticate as a user once the user closes the web page.
One important thing to note is that since getPublicKey
may open a
popup to ask for information, you should call it as a direct response
to a user action like clicking a button. This will ensure that
browsers show the popup instead of hiding it.
Storing User Data
By default, all data stored on Axiom is unencrypted. Applications can retrieve arbitrary data stored in buckets via the API.
Buckets are specified by two strings, the application tag and the bucket name. Each of these must be at least six letters long, to discourage collisions. One useful pattern is to pick a unique name for your application, and use that as the application tag. Then, you can pick a user-specific name for the bucket name, like the user's public key, or a username they pick themselves.
Let's say we're building an application that keeps track of a
counter for each user. We'll name it counter
, and have each user
store their data in a bucket with the counter
application tag, and a
bucket name of their own public key.
We can use the axiom.getBucket method to check if a bucket exists
already, and we can use the axiom.createBucket method to create a bucket on
behalf of the user. Try replacing the
onClick
logic in our application with this:
async onClick() {
let key = await this.axiom.getPublicKey();
let bucket = await this.axiom.getBucket("counter", key);
if (bucket) {
this.setState({ message: "the bucket already exists" });
} else {
await this.axiom.createBucket("counter", key, 1);
this.setState({ message: "created a bucket" });
}
}
The same pattern for permissions operates here as with login. Since data is public, getting a bucket requires no permissions. Creating a new bucket does require the user to grant permission. If this permission has not already been granted, an extension popup opens so that the user can grant permission.
Try running this application and clicking the button. The first time you run this code, it should discover that the bucket does not exist, prompt you for permission, and create the bucket for you. The next time you run this code, it should tell you that the bucket already exists.
While buckets are often created by individual applications, the user maintains control. For example, you can delete this bucket from the CLI when you are done with this sample application. To list all buckets you are using, run axiom get-buckets:
axiom get-buckets
Then you can delete any you are not using with axiom delete-bucket:
axiom delete-bucket <full-name>
This is similar to how applications are installed on a PC hard drive. A well-behaved application will offer ways to uninstall or clean itself up. But even when an application is not well-behaved, you can delete the folder that its files are installed into. The permission model here also prevents some forms of bad behavior. An application can write to the bucket or buckets that the user gives it permission for, but an application doesn't have the ability to modify all the files you own.
Modifying User Data
The Axiom API provides a number of ways to manipulate files in a bucket. For our example application, let's say we are storing a counter in a file named counter.json
. It's a simple JSON object with a single key named counter
. So if our counter value is 5, our file would have the contents:
{"counter":5}
Once we have a bucket, we can use bucket.getJSON and bucket.setJSON to manipulate the contents of files. Once we're done modifying the bucket, we can use bucket.upload to save the result.
Once you've created a bucket according to the previous
section, try replacing the onClick
logic in our application with this:
async onClick() {
let key = await this.axiom.getPublicKey();
let bucket = await this.axiom.getBucket("counter", key);
let data = await bucket.getJSON("counter.json");
if (!data) {
data = { counter: 1 };
} else {
data = { counter: data.counter + 1 };
}
bucket.setJSON("counter.json", data);
this.setState({ message: "setting data to " + JSON.stringify(data) });
await bucket.upload();
this.setState({ message: "upload complete" });
}
Try running this application and clicking the button. The first time you run this code, it should discover that there is no file storing a counter, set its value to 1, and upload the new data. If you reload the page and click the button again, it should pick up the new value of the counter and increase it again.
Developers aren't required to use JSON to store application data. The plain file data is also available via the bucket.getFile and bucket.setFile methods.
Putting It All Together
So far, we've investigated areas of the API by building an application with a single button. We can put it all together to make an application that will do all of this: get permission from the user to log in, create a bucket to store data, store a counter in that bucket, and increment the counter every time a button is clicked.
Combining this functionality together, we can get something like this:
import React from "react";
import Axiom from "axiom-api";
export default class App extends React.Component {
constructor(props) {
super(props);
this.axiom = new Axiom({ verbose: true });
this.state = {
publicKey: null,
loadingMessage: null,
bucket: null,
counter: null
};
this.login = this.login.bind(this);
this.createBucket = this.createBucket.bind(this);
this.increment = this.increment.bind(this);
}
async login() {
let publicKey = await this.axiom.getPublicKey();
this.setState({
publicKey: publicKey
});
this.setState({
loadingMessage: "loading your data..."
});
let bucket = await this.axiom.getBucket("counter", this.state.publicKey);
if (bucket) {
console.log("got bucket:", bucket);
let data = await bucket.getJSON("counter.json");
console.log("got data:", data);
let counter = data ? data.counter : 0;
this.setState({
bucket: bucket,
counter: counter,
loadingMessage: null
});
} else {
console.log("failed to get bucket");
this.setState({
loadingMessage: null
});
}
}
async createBucket() {
this.setState({
loadingMessage: "creating a bucket..."
});
console.log("creating a bucket");
await this.axiom.createBucket("counter", this.state.publicKey, 1);
await this.login();
}
async increment() {
this.setState({
loadingMessage: `saving counter = ${this.state.counter + 1}...`
});
this.state.bucket.setJSON("counter.json", {
counter: this.state.counter + 1
});
console.log("uploading...");
await this.state.bucket.upload();
console.log("upload complete");
this.setState({
waiting: false,
loadingMessage: null,
counter: this.state.counter + 1
});
}
render() {
if (this.state.loadingMessage) {
return <p>{this.state.loadingMessage}</p>;
}
if (!this.state.publicKey) {
return <button onClick={this.login}>Log In</button>;
}
if (!this.state.bucket) {
return <button onClick={this.createBucket}>Create a Counter</button>;
}
return (
<div>
<p>Counter: {this.state.counter}</p>
<button onClick={this.increment}>count!</button>
</div>
);
}
}
If you'd like to play around with this sample application, check out the code on GitHub, or you can clone it locally with:
git clone git@github.com:axiom-org/counter.git
This example has only touched on a small part of what is possible. To learn more, check out the API reference.
The Axiom system is also fully open source, with new functionality being frequently added. If there is an application you want to build, but it doesn't seem like the API currently supports some functionality you need, it might be a good candidate for future work. You can check out the API source code if you're interested in contributing, or you can submit a GitHub issue if you would like to encourage other people to develop the feature you need.
Thanks for reading this far, and good luck building applications!
API Reference
API Overview
This section provides a reference to all of the JavaScript API methods.
The Axiom API is distributed through the axiom-api
npm package. You can
install it using npm or
yarn:
npm install axiom-api
yarn add axiom-api
We recommend that you use the async/await
pattern when
developing Axiom applications. Most of the sample code will be written
in that style. It isn't mandatory, though. When a
function is documented as being async
, and you call it without
using await
, it will return a Promise
object that you can use from
code that isn't using async/await
.
Currently, axiom-api
only supports a browser environment. It's
designed for running applications where the user is only authorizing
specific operations. However, anything that can be done through the JS
API can also be done through HTTP or through the CLI. If you're
interested in this, you may find it
useful to check out the API source
code
or the CLI source code
new Axiom()
import Axiom from "axiom-api";
let axiom = new Axiom();
All access to the Axiom JavaScript API happens through an Axiom
object. You only need to create this
once for your application. It will internally handle caching and permissions.
The constructor can take an options object, with the fields:
-
network
can be set to"local"
to use a development blockchain you are running locally on your own machine. The default is to use the public network. -
verbose
can be set totrue
to log debugging messages to the console. By default Axiom shouldn't log unless there is an error.
If you have a question about the Axiom
class that isn't answered by
this documentation, you can check out its source code on GitHub.
axiom.createBucket
async axiom.createBucket(app, name, size)
createBucket
creates a new bucket on behalf of the user of the application. A common pattern
is that users can browse content for an application without creating a bucket to store
their application files, but once they want to create an account, or create content of some
kind, they create a bucket to store it.
app
is a string that identifies the application, and name
is a string that
identifies this particular bucket. If your application has usernames, it's reasonable to use
usernames as bucket names, and to create the bucket at the time that the user is creating
an account. Since the data is controlled by the end user who owns the
bucket, different applications can share the same app
string to
interact with the same data.
size
is the size of the bucket in megabytes.
For example, if we wrote an app named blogpost
to let people make
blog posts, we could let a user named BradNelson
create an account
with:
await axiom.createBucket("blogpost", "BradNelson", 0);
The first call to this method will cause a popup in the extension, to ask the user for authorization to create the bucket.
If you want to manipulate this bucket in the CLI later, the full name
of the bucket is the app name and the bucket name joined by a
colon. So in this case, it would be blogpost:BradNelson
.
createBucket
throws an error if bucket creation does not
succeed. This usually means the bucket already exists, your connection
to the internet failed, or the user rejected this request.
If you have a question about the Bucket
class that isn't answered by
this documentation, you can check out its source code on GitHub.
axiom.getAccount
async axiom.getAccount(publicKey)
getAccount
fetches account data for a public key. The account is a plain object with the fields:
-
owner
is the public key who owns the account -
sequence
is the sequence id of the last operation authorized by this account. The blockchain resolution logic uses this to prevent replay attacks. -
balance
is the current balance of this account. -
storage
is how much total bucket size, in megabytes, this account is currently storing.
No permissions are needed to fetch account data for a public key, since the information is public.
axiom.getBucket
async axiom.getBucket(app, name)
getBucket
retrieves a Bucket
object that contains information for
a bucket from the blockchain. It does not download
the actual contents of the bucket. If you want that, you should
subsequently call bucket.download.
app
and name
are the same parameters used when the bucket was
created.
No permissions are needed to get a bucket, since the data is public data.
axiom.getPublicKey
async axiom.getPublicKey()
getPublicKey
gets the current user's public key from the extension.
For privacy, the extension won't just tell every application your public key. The first time
this is called, a popup opens that asks the user if they would like to grant this website
knowledge of their public key. In order to make sure this popup is shown, getPublicKey
should be called directly in response to the user interacting with an input element, like
a login button.
If the user has already granted access, however, getPublicKey
will
return successfully without further authorization.
bucket.download
async bucket.download()
download()
downloads the entire contents of a bucket to the local browser.
You don't necessarily need to call this, because the asynchronous
getter functions like getJSON will download as
they need to anyway. But if you know your application is going to want
this information later, you can call download()
as soon as the
bucket is acquired, to begin the download immediately.
bucket.getFile
async bucket.getFile(path)
getFile
returns a standard File object given a path within a bucket.
If the file isn't available locally, this will download the file and then return it. If the bucket has already been entirely downloaded with bucket.download, the file will be returned from the cache.
In general, a File
object is the most standard form for files in a
browser, but it isn't very convenient for most common operations. If you're
interacting with application data, you may find it more helpful to use
bucket.getJSON or bucket.getText.
bucket.getJSON
async bucket.getJSON(path)
getJSON
returns the result of JSON-parsing the file stored at path
. It will throw an error if that file doesn't contain valid JSON. It will return null if that file does not exist.
This is often more useful for accessing application data than using getFile to access a file directly. But it's just a simple wrapper around getFile
.
bucket.getPaths
async bucket.getPaths()
getPaths
returns a list of paths for every file stored in this bucket.
Directories aren't stored recursively in a bucket. They are just stored as long pathnames that happen to have slashes in them. So if your bucket contains two directories, each with two files, you might get a response to getPaths
that looks like:
[ "foo/1.txt", "foo/2.txt", "bar/1.txt", "bar/2.txt" ]
bucket.getText
async bucket.getText(path, encoding)
getText
returns the text content for a file stored at path
. If you don't provide an encoding, the file is assumed to be utf-8
.
This is often more useful for accessing application data than using getFile to access a file directly. But it's just a simple wrapper around getFile
.
bucket.magnet
bucket.magnet
This field provides access to a magnet URI for the WebTorrent protocol. You can use this to download the current contents of a bucket if you don't want to use this API.
In most cases, you should be able to use getters on the Bucket
object instead of using
the magnet directly.
Don't write to this field.
bucket.name
bucket.name
This field provides the full name of the bucket, which is the app name and the bucket name separated by a colon.
This field is mostly useful for debugging. You usually won't need to
use it in code because all the data access for the bucket can happen
via the Bucket
object. But if you want to inspect a bucket using the
CLI, you'll need its full name.
Don't write to this field.
bucket.owner
bucket.owner
This field provides access to the public key of the user that owns this bucket.
In particular, if axiom.getPublicKey() doesn't match, then this user won't be able to write to this bucket.
bucket.setFile
bucket.setFile(path, file)
setFile
stores a file into a bucket at path
.
This function only changes the content of the bucket locally. You have to call bucket.upload to upload the new contents of the bucket when you are ready to save it.
In general, a File
object is the most standard form for files in a
browser, but it isn't very convenient for most common operations. If you're
storing application data, you may find it more helpful to use
bucket.setJSON or bucket.setText.
bucket.setJSON
bucket.setJSON(path, object)
setJSON
JSON-encodes a provided object, and stores the result in a file at path
.
Like setFile, this function only changes the content of the bucket locally. You have to call bucket.upload to upload the new contents of the bucket when you are ready to save it.
It's a good idea to end files with .json
when they are storing JSON data. It isn't required, though.
bucket.setText
bucket.setText(path, text)
setText
stores the provided text in a file at path
.
It only supports utf-8
encoding. If you want to use a different encoding, or if you want to store nontextual data, try using setFile instead.
You have to call bucket.upload to upload the new contents of the bucket when you are ready to save it.
It's a good idea to end files with .txt
when they are storing plain text data. It isn't required, though.
bucket.size
bucket.size
This field tells you the size of the bucket, in megabytes. It is always an integer; you can't have buckets that are half a megabyte in size.
The size of a bucket is an upper limit. Usually the total size of all files in a bucket is smaller than the bucket size.
Don't write to this field.
bucket.upload
async bucket.upload()
upload
uploads new content to a bucket.
The typical usage pattern is first to fetch information for a bucket using bucket.download(). Then, the user can access data in the bucket with getters like bucket.getJSON and modify it with setters like bucket.setJSON. Once some modifications to the bucket have been made, it can be uploaded with bucket.upload
.
CLI Reference
CLI Overview
This section provides a reference to all of the CLI commands.
The CLI is distributed through the axiom-cli
npm package. You can
install the CLI using npm or
yarn:
npm install -g axiom-cli
yarn global add axiom-cli
The general format of CLI commands is:
axiom command-name argument-1 argument-2 [...]
If you run a command with no arguments, you'll get a brief usage message.
Anything that can be done through the CLI can also be done through HTTP. The CLI source code is on GitHub so if some of its behavior is insufficiently documented, or it's unclear how to achieve it programmatically, you can check there.
Several of the CLI commands use bucket names. A bucket name can
optionally have an application tag on it. If the application tag is
omitted, the application is considered to be www
. For example, in the
bucket name foobar:bazqux
, foobar
is the application tag and
bazqux
is the name of the bucket itself.
axiom alloc
axiom alloc [bucketName] [providerID]
Allocates a bucket to a particular provider.
Usually you don't have to run this command because create-bucket allocates a bucket for you. This is useful if there is a specific set of providers that you would like to use.
This command is a synonym of axiom allocate for those who prefer to avoid typing.
axiom allocate
axiom allocate [bucketName] [providerID]
The long form of axiom alloc for those who prefer spelling out whole words.
axiom config
Used in one of two ways:
axiom config alpha
axiom config local
axiom config
switches the CLI between using different networks. There are two Axiom networks that it can talk to. alpha
is the developer network that you can deploy things to and have them be accessible to the outside world. local
is a network that you are running on your own machine, for testing purposes.
By default, this talks to the alpha network. You don't have to use this command unless you are working on the Axiom software itself.
axiom create-bucket
axiom create-bucket [bucketName] [size]
Creates a new bucket, finds some providers with enough available space to host this bucket, and allocates the bucket to those providers.
If you want to allocate the bucket yourself, use axiom create-unallocated-bucket instead, which won't automatically allocate the bucket.
size
is denominated in megabytes.
axiom create-provider
axiom create-provider [capacity]
This command creates a provider object on the blockchain. The blockchain will assign it a unique numerical id, and users creating a bucket can use it to specify which provider they want to store their files.
You usually wouldn't want to do this yourself. If you want to run a file hosting server, try the instructions for running hserver. When you run an hserver, it automatically creates a provider object if it doesn't have one already. This CLI command is useful if you are writing your own file hosting logic, or if you are debugging a buggy hserver.
axiom create-unallocated-bucket
axiom create-unallocated-bucket [bucketName] [size]
axiom create-unallocated-bucket
creates a new bucket with no providers. This is useful if you wish
to use a specific set of providers, and manually allocate them yourself later. But usually
you just want to use axiom create-bucket.
size
is denominated in megabytes.
axiom dealloc
axiom dealloc [bucketName] [providerID]
Deallocates a bucket from a particular provider.
You might want to run this command if you own a bucket, and a particular provider has been performing poorly. Axiom doesn't enforce an SLA through the blockchain mechanisms itself. So if a provider is not providing good service, you can deallocate your buckets from one provider and reallocate them to another.
You also might want to run this commend if you are running a hosting provider, and you discover a particular bucket contains content that you don't want to be hosting. Perhaps it's illegal in your jurisdiction, or you just don't like it for whatever reason. Deallocating the bucket means you aren't obliged to host it any more.
This command is a synonym of axiom deallocate for those who prefer not to spell out whole words.
axiom deallocate
axiom deallocate [bucketName] [providerID]
The long form of axiom dealloc for those who prefer to type more.
axiom delete-bucket
axiom delete-bucket [name]
If you created a bucket that you don't want any more, you can use this command to delete it.
axiom deploy
axiom deploy [directory] [bucketName]
This command is a synonym of axiom upload.
It's a bit more logical to have the commands named "upload" and "download" so that the names are kind of parallel to each other. But when you're building an application, the typical usage pattern is to write some code, and then when you're ready, you deploy that code to production to have the application go live. So it's kind of common to call this "deploy" in a command-line tool. Anyway, in a fit of indecisiveness we left both commands in the CLI.
axiom download
axiom download [bucketName]
Downloads the contents of a bucket to a newly-created directory with the same name as the bucket, in the current working directory.
axiom generate
axiom generate
This command generates a keypair file containing both private key and public key that correspond to a passphrase. You don't need this just to use the CLI, but you will need this keypair file in order to run your own hosting server. If you're interested in running your own hosting server, check out the instructions here.
axiom get-account
axiom get-account [username]
Shows the account data for a user. This includes information like their account balance and how much total storage they are using.
axiom get-bucket
axiom get-bucket [name]
Shows information about a bucket. In particular this tells you the magnet URI you need to access the bucket's content, the owner of the bucket, and which providers are responsible for the bucket.
axiom get-buckets
axiom get-buckets [owner=<id>] [provider=<id>]
Shows which buckets match a query. You can either find buckets owned by a particular user, or buckets that are being hosted by a particular provider.
If you don't provide any arguments, this command will show you all buckets that you own.
axiom get-private-key
axiom get-private-key
Prints out your private key. The CLI stores login data in
~/.axiom/config.json
, so this could already be accessed there. This
CLI command just makes it a bit more convenient.
axiom get-provider
axiom get-provider [id]
Shows information about a particular provider. In particular this tells you the owner of the provider, and which buckets this provider is hosting.
axiom get-providers
axiom get-providers [owner=<user>] [bucket=<name>] [available=<amount>] [id=<id>]
Shows which providers match a query. You can find buckets owned by a particular user, which providers are hosting a particular bucket, or providers with a certain amount of available space.
axiom login
axiom login
Asks you for a passphrase and tells you your corresponding public key.
Most commands, if you aren't already logged in, will just ask you to log in. So you usually don't need to run this explicitly.
There is no associated "username" with your passphrase. The passphrase is all you need to gain access to the user account. The string username in the Axiom system is just the public key associated with your keypair. So your passphrase by itself should be a very unique phrase.
The CLI stores its configuration information in
~/.axiom/config.json
. The login
command will populate that file,
and subsequent commands will use the information in that file. You
should keep this file secure, just like you would with your SSH keys.
If you regret logging in, you can use axiom logout to log back out.
axiom logout
axiom logout
Logs you out. After you log out, none of your keypair information is left on the local machine.
Once you log out, you might want to use axiom login to log back in.
axiom send
axiom send [recipient] [amount]
Sends currency to another user.
The recipient here is the public key that is provided when you
initially generate an account, or that is included on bucket and
provider information. Public keys start with 0x
.
Be careful when you use this, because when you send currency, there is no way to undo the transaction.
axiom set-magnet
axiom set-magnet [bucketName] [magnet]
Updates the magnet URI stored for a particular bucket.
The file hosting software also runs WebTorrent trackers which will create magnet URIs for bucket contents. So normally you wouldn't want to set a magnet directly; you would just use the axiom upload command which does this for you.
This is useful if you have created a magnet URI in some other way and want your bucket to use it instead. Like if you have a WebTorrent tracker with some extra functionality that you want. But these are somewhat obscure cases, so it's rare you would want to do this.
axiom signup
axiom signup
During the developer beta, we are giving away currency so that people can build applications on the system. This command is how you collect. First, sign up for the newsletter. Then, run this command. You will have to enter a token that gets emailed to you, and then you will have an account set up with enough currency to build an application.
Maybe it's a little tacky to make you sign up for the newsletter to try this out. Sorry! At least it makes it a little harder for spammers to take up all the capacity in the system.
Speaking of spammers... when we launch the main net, we plan to keep running applications operational and transfer them from the testnet to the main net. But we don't plan to keep account balances in place. So there's no point in spamming this system to get hundreds of developer accounts. The only thing this currency is getting you is capacity on the development system.
axiom upload
axiom upload [directory] [bucketName]
Uploads the contents of a local directory to a decentralized bucket. The bucket must already have been created, and you must own it.
axiom version
axiom version
Prints out which version of the Axiom CLI you are using.
If you are debugging an Axiom CLI installation issue, you might also find axiom which to be useful.
axiom which
axiom which
This command just tells you where the file is that is running the CLI itself. It is useful if you are trying to debug a problem about how exactly your CLI is installed.