Browse Source

add url option for development

master
nkzawa 9 years ago
parent
commit
7903aa69a6
  1. 33
      bin/now-deploy
  2. 43
      bin/now-list
  3. 6
      lib/agent.js
  4. 25
      lib/error.js
  5. 32
      lib/index.js
  6. 20
      lib/login.js

33
bin/now-deploy

@ -11,6 +11,7 @@ import chalk from 'chalk';
import minimist from 'minimist';
import Now from '../lib';
import ms from 'ms';
import { handleError, error } from '../lib/error';
const argv = minimist(process.argv.slice(2));
const help = () => {
@ -49,6 +50,7 @@ const clipboard = !(argv.noClipboard || argv.C);
const force = argv.f || argv.force;
const forceSync = argv.F || argv.forceSync;
const shouldLogin = argv.L || argv.login;
const apiUrl = argv.url || 'https://api.now.sh';
const config = cfg.read();
@ -59,7 +61,7 @@ if (argv.h || argv.help) {
console.log(chalk.bold('𝚫 now'), version);
process.exit(0);
} else if (!config.token || shouldLogin) {
login()
login(apiUrl)
.then((token) => {
if (shouldLogin) {
console.log('> Logged in successfully. Token saved in ~/.now.json');
@ -87,13 +89,13 @@ async function sync (token) {
console.log(`> Deploying "${path}"`);
const now = new Now(token, { debug });
const now = new Now(apiUrl, token, { debug });
try {
await now.create(path, { forceNew: force, forceSync: forceSync });
} catch (err) {
handleError(err);
return;
process.exit(1);
}
const { url } = now;
@ -170,28 +172,3 @@ function printLogs (host) {
process.exit(0);
});
}
function handleError (err) {
if (403 === err.status) {
error('Authentication error. Run `now -L` or `now --login` to log-in again.');
} else if (429 === err.status) {
if (null != err.retryAfter) {
error('Rate limit exceeded error. Try again in ' +
ms(err.retryAfter * 1000, { long: true }) +
', or upgrade your account: https://zeit.co/now#pricing');
} else {
error('Rate limit exceeded error. Please try later.');
}
} else if (err.userError) {
error(err.message);
} else if (500 === err.status) {
error('Unexpected server error. Please retry.');
} else {
error(`Unexpected error. Please try later. (${err.message})`);
}
process.exit(1);
}
function error (err) {
console.error(`> \u001b[31mError!\u001b[39m ${err}`);
}

43
bin/now-list

@ -1,3 +1,44 @@
#!/usr/bin/env node
console.log('!list', process.argv);
import minimist from 'minimist';
import Now from '../lib';
import login from '../lib/login';
import * as cfg from '../lib/cfg';
import { handleError, error } from '../lib/error';
const argv = minimist(process.argv.slice(2));
const app = argv._[0];
// options
const debug = argv.debug || argv.d;
const apiUrl = argv.url || 'https://api.now.sh';
const config = cfg.read();
Promise.resolve(config.token || login(apiUrl))
.then(async (token) => {
try {
await list(token);
} catch (err) {
error(`Unknown error: ${err.stack}`);
process.exit(1);
}
})
.catch((e) => {
error(`Authentication error – ${e.message}`);
process.exit(1);
});
async function list (token) {
const now = new Now(apiUrl, token, { debug });
let deployments;
try {
deployments = await now.list(app);
} catch (err) {
handleError(err);
process.exit(1);
}
console.log(deployments);
}

6
lib/agent.js

@ -12,8 +12,8 @@ import fetch from 'node-fetch';
*/
export default class Agent {
constructor (host, { debug } = {}) {
this._host = host;
constructor (url, { debug } = {}) {
this._url = url;
this._debug = debug;
this._initAgent();
}
@ -54,7 +54,7 @@ export default class Agent {
opts.headers['Content-Length'] = Buffer.byteLength(opts.body);
}
return fetch(`https://${this._host}${path}`, opts);
return fetch(this._url + path, opts);
}
close () {

25
lib/error.js

@ -0,0 +1,25 @@
import ms from 'ms';
export function handleError (err) {
if (403 === err.status) {
error('Authentication error. Run `now -L` or `now --login` to log-in again.');
} else if (429 === err.status) {
if (null != err.retryAfter) {
error('Rate limit exceeded error. Try again in ' +
ms(err.retryAfter * 1000, { long: true }) +
', or upgrade your account: https://zeit.co/now#pricing');
} else {
error('Rate limit exceeded error. Please try later.');
}
} else if (err.userError) {
error(err.message);
} else if (500 === err.status) {
error('Unexpected server error. Please retry.');
} else {
error(`Unexpected error. Please try later. (${err.message})`);
}
}
export function error (err) {
console.error(`> \u001b[31mError!\u001b[39m ${err}`);
}

32
lib/index.js

@ -20,12 +20,12 @@ const IS_WIN = /^win/.test(process.platform);
const SEP = IS_WIN ? '\\' : '/';
export default class Now extends EventEmitter {
constructor (token, { forceNew = false, debug = false }) {
constructor (url, token, { forceNew = false, debug = false }) {
super();
this._token = token;
this._debug = debug;
this._forceNew = forceNew;
this._agent = new Agent('api.now.sh', { debug });
this._agent = new Agent(url, { debug });
this._onRetry = this._onRetry.bind(this);
}
@ -159,6 +159,32 @@ export default class Now extends EventEmitter {
uploadChunk();
}
async list (app) {
const query = app ? `?app=${encodeURIComponent(app)}` : '';
const { deployments } = await retry(async (bail) => {
if (this._debug) console.time('> [debug] /list');
const res = await this._fetch('/list' + query);
if (this._debug) console.timeEnd('> [debug] /list');
// no retry on 4xx
if (400 <= res.status && 500 > res.status) {
if (this._debug) {
console.log('> [debug] bailing on listing due to %s', res.status);
}
return bail(responseError(res));
}
if (200 !== res.status) {
throw new Error('Fetching deployment list failed');
}
return res.json();
}, { retries: 3, minTimeout: 2500, onRetry: this._onRetry });
return deployments;
}
_onRetry (err) {
if (this._debug) {
console.log(`> [debug] Retrying: ${err.stack}`);
@ -190,7 +216,7 @@ export default class Now extends EventEmitter {
return this._syncAmount;
}
async _fetch (_url, opts) {
async _fetch (_url, opts = {}) {
opts.headers = opts.headers || {};
opts.headers.authorization = `Bearer ${this._token}`;
return await this._agent.fetch(_url, opts);

20
lib/login.js

@ -3,8 +3,6 @@ import fetch from 'node-fetch';
import * as cfg from './cfg';
import { stringify as stringifyQuery } from 'querystring';
const URL = 'https://api.now.sh/registration';
const stdin = process.openStdin();
function readEmail () {
@ -17,9 +15,9 @@ function readEmail () {
});
}
async function getVerificationToken (email) {
async function getVerificationToken (url, email) {
const data = JSON.stringify({ email });
const res = await fetch(URL, {
const res = await fetch(url + '/registration', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@ -36,13 +34,13 @@ async function getVerificationToken (email) {
return body.token;
}
async function verify (email, verificationToken) {
async function verify (url, email, verificationToken) {
const query = {
email,
token: verificationToken
};
const res = await fetch(`${URL}/verify?${stringifyQuery(query)}`);
const res = await fetch(`${url}/registration/verify?${stringifyQuery(query)}`);
const body = await res.json();
return body.token;
}
@ -53,9 +51,9 @@ function sleep (ms) {
});
}
async function register () {
async function register (url) {
const email = await readEmail();
const verificationToken = await getVerificationToken(email);
const verificationToken = await getVerificationToken(url, email);
console.log(`> Please follow the link sent to ${chalk.bold(email)} to log in.`);
process.stdout.write('> Waiting for confirmation..');
@ -64,7 +62,7 @@ async function register () {
do {
await sleep(2500);
try {
final = await verify(email, verificationToken);
final = await verify(url, email, verificationToken);
} catch (e) {}
process.stdout.write('.');
} while (!final);
@ -74,8 +72,8 @@ async function register () {
return { email, token: final };
}
export default async function () {
const loginData = await register();
export default async function (url) {
const loginData = await register(url);
cfg.merge(loginData);
return loginData.token;
}

Loading…
Cancel
Save