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 minimist from 'minimist';
import Now from '../lib'; import Now from '../lib';
import ms from 'ms'; import ms from 'ms';
import { handleError, error } from '../lib/error';
const argv = minimist(process.argv.slice(2)); const argv = minimist(process.argv.slice(2));
const help = () => { const help = () => {
@ -49,6 +50,7 @@ const clipboard = !(argv.noClipboard || argv.C);
const force = argv.f || argv.force; const force = argv.f || argv.force;
const forceSync = argv.F || argv.forceSync; const forceSync = argv.F || argv.forceSync;
const shouldLogin = argv.L || argv.login; const shouldLogin = argv.L || argv.login;
const apiUrl = argv.url || 'https://api.now.sh';
const config = cfg.read(); const config = cfg.read();
@ -59,7 +61,7 @@ if (argv.h || argv.help) {
console.log(chalk.bold('𝚫 now'), version); console.log(chalk.bold('𝚫 now'), version);
process.exit(0); process.exit(0);
} else if (!config.token || shouldLogin) { } else if (!config.token || shouldLogin) {
login() login(apiUrl)
.then((token) => { .then((token) => {
if (shouldLogin) { if (shouldLogin) {
console.log('> Logged in successfully. Token saved in ~/.now.json'); console.log('> Logged in successfully. Token saved in ~/.now.json');
@ -87,13 +89,13 @@ async function sync (token) {
console.log(`> Deploying "${path}"`); console.log(`> Deploying "${path}"`);
const now = new Now(token, { debug }); const now = new Now(apiUrl, token, { debug });
try { try {
await now.create(path, { forceNew: force, forceSync: forceSync }); await now.create(path, { forceNew: force, forceSync: forceSync });
} catch (err) { } catch (err) {
handleError(err); handleError(err);
return; process.exit(1);
} }
const { url } = now; const { url } = now;
@ -170,28 +172,3 @@ function printLogs (host) {
process.exit(0); 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 #!/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 { export default class Agent {
constructor (host, { debug } = {}) { constructor (url, { debug } = {}) {
this._host = host; this._url = url;
this._debug = debug; this._debug = debug;
this._initAgent(); this._initAgent();
} }
@ -54,7 +54,7 @@ export default class Agent {
opts.headers['Content-Length'] = Buffer.byteLength(opts.body); opts.headers['Content-Length'] = Buffer.byteLength(opts.body);
} }
return fetch(`https://${this._host}${path}`, opts); return fetch(this._url + path, opts);
} }
close () { 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 ? '\\' : '/'; const SEP = IS_WIN ? '\\' : '/';
export default class Now extends EventEmitter { export default class Now extends EventEmitter {
constructor (token, { forceNew = false, debug = false }) { constructor (url, token, { forceNew = false, debug = false }) {
super(); super();
this._token = token; this._token = token;
this._debug = debug; this._debug = debug;
this._forceNew = forceNew; this._forceNew = forceNew;
this._agent = new Agent('api.now.sh', { debug }); this._agent = new Agent(url, { debug });
this._onRetry = this._onRetry.bind(this); this._onRetry = this._onRetry.bind(this);
} }
@ -159,6 +159,32 @@ export default class Now extends EventEmitter {
uploadChunk(); 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) { _onRetry (err) {
if (this._debug) { if (this._debug) {
console.log(`> [debug] Retrying: ${err.stack}`); console.log(`> [debug] Retrying: ${err.stack}`);
@ -190,7 +216,7 @@ export default class Now extends EventEmitter {
return this._syncAmount; return this._syncAmount;
} }
async _fetch (_url, opts) { async _fetch (_url, opts = {}) {
opts.headers = opts.headers || {}; opts.headers = opts.headers || {};
opts.headers.authorization = `Bearer ${this._token}`; opts.headers.authorization = `Bearer ${this._token}`;
return await this._agent.fetch(_url, opts); 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 * as cfg from './cfg';
import { stringify as stringifyQuery } from 'querystring'; import { stringify as stringifyQuery } from 'querystring';
const URL = 'https://api.now.sh/registration';
const stdin = process.openStdin(); const stdin = process.openStdin();
function readEmail () { function readEmail () {
@ -17,9 +15,9 @@ function readEmail () {
}); });
} }
async function getVerificationToken (email) { async function getVerificationToken (url, email) {
const data = JSON.stringify({ email }); const data = JSON.stringify({ email });
const res = await fetch(URL, { const res = await fetch(url + '/registration', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -36,13 +34,13 @@ async function getVerificationToken (email) {
return body.token; return body.token;
} }
async function verify (email, verificationToken) { async function verify (url, email, verificationToken) {
const query = { const query = {
email, email,
token: verificationToken token: verificationToken
}; };
const res = await fetch(`${URL}/verify?${stringifyQuery(query)}`); const res = await fetch(`${url}/registration/verify?${stringifyQuery(query)}`);
const body = await res.json(); const body = await res.json();
return body.token; return body.token;
} }
@ -53,9 +51,9 @@ function sleep (ms) {
}); });
} }
async function register () { async function register (url) {
const email = await readEmail(); 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.`); console.log(`> Please follow the link sent to ${chalk.bold(email)} to log in.`);
process.stdout.write('> Waiting for confirmation..'); process.stdout.write('> Waiting for confirmation..');
@ -64,7 +62,7 @@ async function register () {
do { do {
await sleep(2500); await sleep(2500);
try { try {
final = await verify(email, verificationToken); final = await verify(url, email, verificationToken);
} catch (e) {} } catch (e) {}
process.stdout.write('.'); process.stdout.write('.');
} while (!final); } while (!final);
@ -74,8 +72,8 @@ async function register () {
return { email, token: final }; return { email, token: final };
} }
export default async function () { export default async function (url) {
const loginData = await register(); const loginData = await register(url);
cfg.merge(loginData); cfg.merge(loginData);
return loginData.token; return loginData.token;
} }

Loading…
Cancel
Save