mirror of
https://github.com/bcomnes/deploy-to-neocities.git
synced 2026-01-16 22:56:28 +00:00
135 lines
3.3 KiB
JavaScript
135 lines
3.3 KiB
JavaScript
import assert from 'nanoassert';
|
|
import fetch from 'node-fetch';
|
|
import { URL } from 'url';
|
|
import qs from 'qs';
|
|
import pkg from '../package.json';
|
|
import os from 'os';
|
|
|
|
const defaultURL = 'https://neocities.org/api';
|
|
|
|
export class NeocitiesAPIClient {
|
|
static getKey (sitename, password, opts) {
|
|
assert(sitename, 'must pass sitename as first arg');
|
|
assert(typeof sitename === 'string', 'user arg must be a string');
|
|
assert(password, 'must pass a password as the second arg');
|
|
assert(typeof password, 'password arg must be a string');
|
|
|
|
opts = Object.assign({
|
|
url: defaultURL
|
|
}, opts);
|
|
|
|
return fetch();
|
|
}
|
|
|
|
constructor (apiKey, opts) {
|
|
assert(apiKey, 'must pass apiKey as first argument');
|
|
assert(typeof apiKey === 'string', 'apiKey must be a string');
|
|
opts = Object.assign({
|
|
url: defaultURL
|
|
});
|
|
|
|
this.opts = opts;
|
|
this.url = opts.url;
|
|
this.apiKey = apiKey;
|
|
}
|
|
|
|
request (endpoint, args, opts) {
|
|
assert(endpoint, 'must pass endpoint as first argument');
|
|
opts = Object.assign({}, opts);
|
|
opts.headers = Object.assign({
|
|
Authorization: `Bearer ${this.apiKey}`,
|
|
Accept: 'application/json',
|
|
'User-Agent': `deploy-to-neocities/${pkg.version} (${os.type()})`
|
|
}, opts.headers);
|
|
|
|
let path = `/api/${endpoint}`;
|
|
if (args) path += `?${qs.stringify(args)}`;
|
|
|
|
const url = new URL(path, this.url);
|
|
return fetch(url, opts);
|
|
}
|
|
|
|
get (endpoint, args, opts) {
|
|
opts = Object.assign({
|
|
method: 'GET'
|
|
}, opts);
|
|
return this.request(endpoint, args, opts);
|
|
}
|
|
|
|
post (endpoint, args, opts) {
|
|
opts = Object.assign({
|
|
method: 'POST'
|
|
}, opts);
|
|
return this.request(endpoint, args, opts);
|
|
}
|
|
|
|
upload (files) {
|
|
throw new Error('NOT IMPLEMENTED');
|
|
}
|
|
|
|
deploy (folder) {
|
|
throw new Error('NOT IMPLEMENTED');
|
|
}
|
|
|
|
delete (filenames) {
|
|
const args = {
|
|
filenames
|
|
};
|
|
|
|
return this.post('/delete', args);
|
|
}
|
|
|
|
list (args) {
|
|
// args.path: Path to list
|
|
return this.get('/list', args).then(handleResponse);
|
|
}
|
|
|
|
/**
|
|
* @param {Object} args Querystring arguments to include
|
|
* @return {Promise} Fetch request promise
|
|
*/
|
|
info (args) {
|
|
// args.sitename: sitename to get info on
|
|
return this.get('/info', args).then(handleResponse);
|
|
}
|
|
}
|
|
|
|
export async function handleResponse (response) {
|
|
const contentType = response.headers.get('Content-Type');
|
|
const isJSON = contentType && contentType.match(/json/);
|
|
const data = isJSON ? await response.json() : await response.text();
|
|
if (response.ok) return data;
|
|
else {
|
|
return isJSON
|
|
? Promise.reject(new JSONHTTPError(response, data))
|
|
: Promise.reject(new TextHTTPError(response, data));
|
|
}
|
|
}
|
|
|
|
export class HTTPError extends Error {
|
|
constructor (response) {
|
|
super(response.statusText);
|
|
this.name = this.constructor.name;
|
|
if (typeof Error.captureStackTrace === 'function') {
|
|
Error.captureStackTrace(this, this.constructor);
|
|
} else {
|
|
this.stack = new Error(response.statusText).stack;
|
|
}
|
|
this.status = response.status;
|
|
}
|
|
}
|
|
|
|
export class TextHTTPError extends HTTPError {
|
|
constructor (response, data) {
|
|
super(response);
|
|
this.data = data;
|
|
}
|
|
}
|
|
|
|
export class JSONHTTPError extends HTTPError {
|
|
constructor (response, json) {
|
|
super(response);
|
|
this.json = json;
|
|
}
|
|
}
|