Nuts is a simple (and smart) application to serve desktop-application releases.
It uses GitHub as a backend to store assets, and it can easily be deployed to Heroku as a stateless service. It supports GitHub private repositories (useful to store releases of a closed-source application available on GitHub).
- ✨ Store assets on GitHub releases
- ✨ Proxy releases from private repositories to your users
- ✨ Simple but powerful download urls
/download/latest
/download/latest/:os
/download/:version
/download/:version/:os
/download/channel/:channel
/download/channel/:channel/:os
- ✨ Support pre-release channels (
beta
,alpha
, ...) - ✨ Auto-updates with Squirrel
- For Mac using
/update?version=<x.x.x>&platform=osx
- For Windows using Squirrel.Windows and Nugets packages
- For Mac using
- ✨ Private API
- ✨ Use it as a middleware: add custom analytics, authentication
- ✨ Serve the perfect type of assets:
.zip
for Squirrel.Mac,.nupkg
for Squirrel.Windows,.dmg
for Mac users, ... - ✨ Release notes endpoint
/notes/:version
- ✨ Up-to-date releases (GitHub webhooks)
Install dependencies using:
$ npm install
This service requires to be configured using environment variables:
# Set the port for the service (default is 5000)
$ export PORT=6000
# Set the host for the service (default is 0.0.0.0)
$ export HOST=127.0.0.1
# Set a base URL for the service (default is '/')
$ export BASE_URL=/release
# Access token for the GitHub API (requires permissions to access the repository)
# If the repository is public you do not need to provide an access token
# you can also use GITHUB_USERNAME and GITHUB_PASSWORD
$ export GITHUB_TOKEN=...
# ID for the GitHub repository
$ export GITHUB_REPO=Username/MyApp
# Secret for GitHub webhook (default is 'secret')
$ export GITHUB_WEBHOOK_SECRET=somethingsupersecret
# Authentication for the private API
$ export API_USERNAME=hello
$ export API_PASSWORD=world
Then start the application using:
$ npm start
Nuts uses some filename/extension conventions to serve the correct asset to a specific request:
Platform will be detected from the filename:
- Windows: filename should contain
win
- Mac/OS X: filename should contain
mac
orosx
- Linux: filename should contain
linux
By default releases are tagged as 32-bits (except for OSX), but 64-bits will also be detected from filenames.
Filetype and usage will be detected from the extension:
.dmg
will be served in priority to Mac users.nupkg
will only be served to Squirrel.Windows requests- Otherwise,
.zip
are advised (Linux, Mac, Windows and Squirrel.Mac)
Nuts provides urls to access releases assets. These assets are cached on the disk.
- Latest version for detected platform:
http://download.myapp.com/download/latest
orhttp://download.myapp.com/download
- Latest version for specific platform:
http://download.myapp.com/download/latest/osx
or ``http://download.myapp.com/download/osx` - Specific version for detected platform:
http://download.myapp.com/download/1.1.0
- Specific version for specific platform:
http://download.myapp.com/download/1.2.0/osx
- Specific channel:
http://download.myapp.com/download/channel/beta
- Specific channel for specific platform:
http://download.myapp.com/download/channel/beta/osx
Platforms can be detected from user-agent and are normalized to values: osx
, osx_32
, osx_64
, linux
, linux_32
, linux_64
, windows
, windows_32
, windows_64
.
Non-prefixed platform will be resolve to 32 bits (except for OSX).
This server provides an endpoint for Squirrel auto-updater: http://download.myapp.com/update/osx/:currentVersion
.
This url requires different parameters to return a correct version: version
and platform
.
For example with Electron's auto-updater
module:
var app = require('app');
var os = require('os');
var autoUpdater = require('auto-updater');
var platform = os.platform() + '_' + os.arch();
var version = app.getVersion();
autoUpdater.setFeedUrl('http://download.myapp.com/update/'+platform+'/'+version);
Nuts will serve NuGet packages on http://download.myapp.com/update/win32/:version/RELEASES
.
Your application just need to configurer Update.exe
or Squirrel.Windows
to use http://download.myapp.com/update/win32/:version
as a feed url (:warning: without query parameters).
You'll just need to upload as release assets: RELEASES
, *-delta.nupkg
and -full.nupkg
(files generated by Squirrel.Windows
releaser).
Nuts lets you manage updates for non-stable release channels.
By default Nuts will only look for newer versions related to the same primary version as the current version which on the same or higher precedence channel. (Nuts uses the node-semver module to compare version tags.)
// Given versions 1.2.3-alpha.1, 1.2.3-beta.1
GET http://download.myapp.com/update/osx/1.2.3-alpha.1
// Returns download info for 1.2.3-beta.1
// Given versions 1.2.3-alpha.1, 1.2.3-beta.1, 1.2.3, 1.2.4-alpha.1
GET http://download.mayapp.com/update/osx/1.2.3-alpha.1
// Returns download info for 1.2.3
You can override this behavior and tell Nuts to check updates only on a given channel regardless of which primary version they are related to by appending a channel query parameter after the update URL.
// Given versions 1.2.3-alpha.1, 1.2.3-beta.1, 1.2.3, 1.2.4-alpha.1
GET http://download.mayapp.com/update/osx/1.2.3-alpha.1?channel=alpha
// Returns download info for 1.2.4-alpha.1
Nuts provides a /notes
endpoint that output release notes as text or json.
A private API is available to access more infos about releases and stats. This API can be protected by HTTP basic auth (username/password) using configuration API_USERNAME
and API_PASSWORD
.
List versions:
GET http://download.myapp.com/api/versions
Get details about specific version:
GET http://download.myapp.com/api/version/1.1.0
Resolve a version:
GET http://download.myapp.com/api/resolve?platform=osx&channel=alpha
List channels:
GET http://download.myapp.com/api/channels
Get stats about downloads:
GET http://download.myapp.com/api/stats
Add http://download.myapp.com/refresh
as a GitHub webhook to refresh versions cache everytime you update a release on GitHub.
The secret can be configured using GITHUB_SECRET
(default value is secret
).
Nuts can be integrated into a Node.JS application as a middleware. Using the middleware, you can add custom authentication on downloads or analytics for downloads counts.
var express = require('express');
var Nuts = require('nuts-serve');
var app = express();
var nuts = Nuts(
// GitHub configuration
repository: "Me/MyRepo",
token: "my_api_token",
// Timeout for releases cache (seconds)
timeout: 60*60,
// Folder to cache assets (by default: a temporary folder)
cache: './assets',
// Pre-fetch list of releases at startup
preFetch: true,
// Secret for refresh webhook
refreshSecret: 'my-secret',
// Middlewares
onDownload: function(version, req, res, next) {
console.log('download', download.version.tag, "on channel", download.version.channel, "for", download.platform.type);
next();
},
onAPIAccess: function(req, res, next) {
next();
}
);
app.use('/myapp', nuts);
app.listen(4000);