npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

bitballoon

v0.2.2

Published

BitBalloon API client

Readme

BitBalloon Node Client

BitBalloon is a hosting service for the programmable web. It understands your documents, processes forms and lets you do deploys, manage forms submissions, inject javascript snippets into sites and do intelligent updates of HTML documents through it's API.

Installation

Install by running

npm install bitballoon

Authenticating

Register a new application at https://www.bitballoon.com/applications to get your Oauth2 secret and key.

Once you have your credentials you can instantiate a BitBalloon client.

var bitballoon = require("bitballoon"),
    client     = bitballoon.createClient(options);

Typically you'll have an access_token stored that you want to instantiate the client with:

var client = bitballoon.createClient({access_token: "my-access-token"});

A client need an access token before it can make requests to the BitBalloon API. Oauth2 gives you two ways to get an access token:

  1. Authorize from credentials: Authenticate directly with your API credentials.
  2. Authorize from a URL: send a user to a URL, where she can grant your access API access on her behalf.

The first method is the simplest, and works when you don't need to authenticate on behalf of some other user:

var client = bitballoon.createClient({client_id: CLIENT_ID, client_secret: CLIENT_SECRET});

client.authorizeFromCredentials(function(err, access_token) {
  if (err) return console.log(err);
  // Client is now ready to do requests
  // You can store the access_token to avoid authorizing in the future
});

To authorize on behalf of a user, you first need to send the user to a BitBalloon url where she'll be asked to grant your application permission. Once the user has visited that URL, she'll be redirected back to a redirect URI you specify (this must match the redirect URI on file for your Application). When the user returns to your app, you'll be able to access a code query parameter, that you can use to obtain the final access_token

var client = bitballoon.createClient({
  client_id: CLIENT_ID,
  client_secret: CLIENT_SECRET,
  redirect_uri: "http://www.example.com/callback"
});

var url = client.authorizeUrl();

// Send the client to the url, they will be redirected back to the redirect_uri
// Once they are back at your url, grab the code query param and use it to authorize

client.authorizeFromCode(params.code, function(err, access_token) {
  if (err) return console.log(err);
  // Client is now ready to do requests
  // You can store the access_token to avoid authorizing in the future  
});

Deploy a new version of a site

If you're just going to deploy a new version of a site from a script, the module exports a simple deploy method that will handle this:

var bitballoon = require("bitballoon");

bitballoon.deploy({access_token: "some-token", site_id: "some-site", dir: "/path/to/site"}, function(err, deploy) {
  if (err) { return console.log(err); }
  console.log("New deploy is live");
});

Sites

Getting a list of all sites you have access to:

client.sites(function(err, sites) {
  // do work
});

Getting a specific site by id:

client.site(id, function(err, site) {
  // do work
})

Creating a new empty site:

client.createSite({name: "my-unique-site-name", domain: "example.com", password: "secret"}, function(err, site) {
  console.log(site);
})

To deploy a site from a dir and wait for the processing of the site to finish:

```js
client.createSite({}, function(err, site) {
  site.createDeploy({dir: "/tmp/my-site"}, function(err, deploy) {
    deploy.waitForReady(function(deploy) {
      console.log("Deploy is done: ", deploy);
    });
  });
});

Creating a new deploy for a site from a zip file:

client.site(id, function(err, site) {
  if (err) return console.log("Error finding site %o", err);
  site.createDeploy({zip: "/tmp/my-site.zip"}, function(err, deploy) {
    if (err) return console.log("Error updating site %o", err);
    deploy.waitForReady(function(err, deploy) {
      if (err) return console.log("Error updating site %o", err);
      console.log("Site redeployed");
    });
  });
})

Update the name of the site (its subdomain), the custom domain and the notification email for form submissions:

site.update({name: "my-site", customDomain: "www.example.com", notificationEmail: "[email protected]", password: "secret"}, function(err, site) {
  if (err) return console.log("Error updating site %o", err);
  console.log("Updated site");
});

Deleting a site:

site.destroy(function(err) {
  if (err) return console.log("Error deleting site");
  console.log("Site deleted");
});

Forms

Access all forms you have access to:

client.forms(function(err, forms) {
  // do work
})

Access forms for a specific site:

client.site(id, function(err, site) {
  if (err) return console.log("Error getting site %o", err);
  site.forms(function(err, forms) {
    // do work
  });
});

Access a specific form:

client.form(id, function(err, form) {
  if (err) return console.log("Error getting form %o", err);
  // do work
});

Access a list of all form submissions you have access to:

client.submissions(function(err, submissions) {
  if (err) return console.log("Error getting submissions %o", err);
  // do work
});

Access submissions from a specific site

client.site(id, function(err, site) {
  if (err) return console.log("Error getting site %o", err);
  site.submissions(function(err, submissions) {
    if (err) return console.log("Error getting submissions %o", err);
    // do work
  })
});

Access submissions from a specific form

client.form(id, function(err, form) {
  if (err) return console.log("Error getting form %o", err);
  form.submissions(function(err, submissions) {
    if (err) return console.log("Error getting submissions %o", err);
    // do work
  });
});

Get a specific submission

client.submission(id, function(err, submission) {
  if (err) return console.log("Error getting submission %o", err);
  // do work
})

Files

Access all files in a site:

client.site(id, function(err, site) {
  if (err) return console.log("Error getting site %o", err);
  site.files(function(err, files) {
    if (err) return console.log("Error getting files %o", err);
    // do work
  });
});

Get a specific file:

client.site(id, function(err, site) {
  if (err) return console.log("Error getting site %o", err);
  site.file(path, function(err, file) {
    if (err) return console.log("Error getting file %o", err);

    file.readFile(function(err, data) {
      if (err) return console.log("Error reading file %o", err);
      console.log("Got data %o", data);
    });

    file.writeFile("Hello, World!", function(err, file) {
      if (err) return console.log("Error writing to file %o", err);
      console.log("Wrote to file - site will now be processing");
    });
  });
});

Deploys

Access all deploys for a site

site.deploys(function(err, deploys) {
  // do work
});

Access a specific deploy

site.deploy(id, function(err, deploy) {
  // do work
});

Create a new deploy:

site.createDeploy({dir: "/path/to/folder"}, function(err, deploy) {
  console.log(deploy)
})

Create a draft deploy (wont get published after processing):

site.createDeploy({dir: "/path/to/folder", draft: true}, function(err, deploy) {
  console.log(deploy);
})

Publish a deploy (makes it the current live version of the site)

site.deploy(id, function(err, deploy) {
  if (err) return console.log(err);
  deploy.publish(function(err, deploy) {
    // restored
  });
});

Snippets

Snippets are small code snippets injected into all HTML pages of a site right before the closing head or body tag. To get all snippets for a site:

client.site(id, function(err, site) {
  if (err) return console.log("Error getting site %o", err);
  site.snippets(function(err, snippets) {
    if (err) return console.log("Error getting snippets %o", err);
    // do work
  });
});

Get a specific snippet

client.site(id, function(err, site) {
  if (err) return console.log("Error getting site %o", err);
  site.snippet(snippetId, function(err, snippet) {
    if (err) return console.log("Error getting snippet %o", err);
    // do work
  });
});

Add a snippet to a site

You can specify a general snippet that will be inserted into all pages, and a goal snippet that will be injected into a page following a successful form submission. Each snippet must have a title. You can optionally set the position of both the general and the goal snippet to head or footer to determine if it gets injected into the head tag or at the end of the page.

client.site(id, function(err, site) {
  if (err) return console.log("Error getting site %o", err);
  site.createSnippet({
    general: "<script>alert('Hello')</script>",
    general_position: "head",
    goal: "<script>alert('Success')</script>",
    goal_position: "footer",
    title: "Alerts"
  }, function(err, snippet) {
    if (err) return console.log("Error creating snippet %o", err);
    console.log(snippet);
  });
});

Update a snippet

snippet.update({
  general: "<script>alert('Hello')</script>",
  general_position: "head",
  goal: "<script>alert('Success')</script>",
  goal_position: "footer",
  title: "Alerts"
}, function(err, snippet) {
  if (err) return console.log("Error creating snippet %o", err);
  console.log(snippet);
});

Delete a snippet

snippet.destroy(function(err) {
  if (err) return console.log("Error deleting snippet");
  console.log("Snippet deleted");
});

Users

The user methods are mainly useful for resellers. Creating, deleting and updating users are limited to resellers.

Getting a list of users

client.users(function(err, users) {
  // do work
});

Getting a specific user

client.user(id, function(err, user) {
  // do work
});

Creating a new user (email is required, uid is optional. Both must be unique)

client.createUser({email: "[email protected]", uid: "12345"}, function(err, user) {
  if (err) return console("Error creating user");
  console.log(user);
});

Updating a user

client.user(id, function(err, user) {
  if (err) return console.log("Error getting user");
  user.update({email: "[email protected]", uid: "12345"}, function(err, user) {
    if (err) return console("Error updating user");
    console.log(user);
  });
});

Deleting a user

client.user(id, function(err, user) {
  if (err) return console.log("Error getting user");
  user.destroy(function(err) {
    if (err) return console("Error deleting");
  });
});

Getting sites belonging to a user

client.user(id, function(err, user) {
  if (err) return console.log("Error getting user");
  user.sites(function(err, sites) {
    if (err) return console("Error getting sites");
    console.log(sites);
  });
});

DNS

Resellers can create and manage DNS Zones through the BitBalloon API.

Getting a list of DNS Zones:

client.dnsZones(function(err, zones) {
  console.log(zones);
});

Getting a specific DNS zone:

client.dnsZone(id, function(err, zone) {
  console.log(zone);
});

Creating a new zone

client.createDnsZone({name: "example.com"}, function(err, zone) {
  console.log(zone);
});

Deleting a zone

client.dnsZone(id, function(err, zone) {
  if (err) return console.log(err);
  zone.destroy(function(err) {
    // Deleted
  });
});

Getting records for a zone

zone.records(function(err, records) {
  console.log(records);
});

Getting a specific record

zone.record(id, function(err, record) {
  console.log(record);
});

Adding a new record (supported types: A, CNAME, TXT, MX)

zone.createRecord({
  hostname: "www",
  type: "CNAME",
  value: "bitballoon.com",
  ttl: 3600
}, function(err, record) {
  console.log(record);
});

Deleting a record

record.destroy(function(err) {
  // deleted
});

Access Tokens

Resellers can use the node client to create and revoke access tokens on behalf of their users. To use any of these methods your OAuth access token must belong to a reseller admin user.

Creating an access token:

client.createAccessToken({user: {email: "[email protected]", uid: "1234"}}, function(err, accessToken) {
  // accessToken.access_token
});

The user must have either an email or a uid (or both) as a unique identifier. If the user doesn't exist, a new user will be created on the fly.

Deleting an access token:

client.accessToken("token-string", function(err, accessToken) {
  accessToken.destroy(function(err) {
    console.log("Access token revoked");
  });
});