mirror of
https://github.com/bcomnes/deploy-to-neocities.git
synced 2026-01-16 22:56:28 +00:00
Update logging
This commit is contained in:
parent
e49d0b8d3a
commit
383cb4ca53
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@ sandbox.js
|
||||
.nyc_output
|
||||
config.json
|
||||
public
|
||||
node_modules
|
||||
|
||||
91
index.js
91
index.js
@ -2,25 +2,100 @@ const core = require('@actions/core')
|
||||
// const github = require('@actions/github')
|
||||
const Neocities = require('async-neocities')
|
||||
const path = require('path')
|
||||
const exec = require('child_process').exec
|
||||
const prettyTime = require('pretty-time')
|
||||
const prettyBytes = require('pretty-bytes')
|
||||
|
||||
async function doDeploy () {
|
||||
const token = core.getInput('api-token')
|
||||
const distDir = path.join(process.cwd(), core.getInput('dist-dir'))
|
||||
const cleanup = core.getInput('cleanup')
|
||||
|
||||
const time = (new Date()).toTimeString()
|
||||
core.setOutput('time', time)
|
||||
|
||||
const client = new Neocities(token)
|
||||
|
||||
return client.deploy(distDir, {
|
||||
const finalStats = await client.deploy(distDir, {
|
||||
cleanup,
|
||||
statusCb: console.log
|
||||
statsCb: statsHandler({ cleanup, distDir })
|
||||
})
|
||||
|
||||
return finalStats
|
||||
}
|
||||
|
||||
doDeploy().then(() => {}).catch(err => {
|
||||
console.error(err)
|
||||
doDeploy().then((finalStats) => {}).catch(err => {
|
||||
core.setFailed(err.message)
|
||||
})
|
||||
|
||||
function statsHandler (opts = {}) {
|
||||
return (stats) => {
|
||||
switch (stats.stage) {
|
||||
case 'inspecting': {
|
||||
switch (stats.status) {
|
||||
case 'start': {
|
||||
core.startGroup('Inspecting')
|
||||
console.log(`Inspecting local (${opts.distDir}) and remote files...`)
|
||||
break
|
||||
}
|
||||
case 'progress': {
|
||||
break
|
||||
}
|
||||
case 'stop': {
|
||||
console.log(`Done inspecting local and remote files in ${prettyTime([0, stats.timer.elapsed])}`)
|
||||
const { tasks: { localScan, remoteScan } } = stats
|
||||
console.log(`Scanned ${localScan.numberOfFiles} local files (${prettyBytes(localScan.totalSize)}) in ${prettyTime([0, localScan.timer.elapsed])}`)
|
||||
console.log(`Scanned ${remoteScan.numberOfFiles} remote files (${prettyBytes(remoteScan.totalSize)}) in ${prettyTime([0, remoteScan.timer.elapsed])}`)
|
||||
core.endGroup()
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'diffing': {
|
||||
switch (stats.status) {
|
||||
case 'start': {
|
||||
core.startGroup('Diffing files')
|
||||
console.log('Diffing local and remote files...')
|
||||
break
|
||||
}
|
||||
case 'progress': {
|
||||
// No progress on diffing
|
||||
break
|
||||
}
|
||||
case 'stop': {
|
||||
const { tasks: { diffing } } = stats
|
||||
console.log(`Done diffing local and remote files in ${prettyTime([0, stats.timer.elapsed])}`)
|
||||
console.log(`${diffing.uploadCount} files to upload`)
|
||||
console.log(`${diffing.deleteCount} ` + opts.cleanup ? 'files to delete' : 'orphaned files')
|
||||
console.log(`${diffing.skipCoount} files to skip`)
|
||||
core.endGroup()
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'applying': {
|
||||
switch (stats.status) {
|
||||
case 'start': {
|
||||
core.startGroup('Applying diff')
|
||||
console.log('Uploading changes' + opts.cleanup ? ' and deleting orphaned files...' : '...')
|
||||
break
|
||||
}
|
||||
case 'progress': {
|
||||
break
|
||||
}
|
||||
case 'stop': {
|
||||
const { tasks: { uploadFiles, deleteFiles, skippedFiles } } = stats
|
||||
console.log('Done uploading changes' + opts.cleanup ? ' and deleting orphaned files' : '' + ` in ${prettyTime([0, stats.timer.elapsed])}`)
|
||||
console.log(`Average upload speed: ${prettyBytes(uploadFiles.speed)}/s`)
|
||||
if (opts.cleanup) console.log(`Average delete speed: ${prettyBytes(deleteFiles.speed)}/s`)
|
||||
console.log(`Skipped ${skippedFiles.count} files (${prettyBytes(skippedFiles.size)})`)
|
||||
core.endGroup()
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
default: {
|
||||
console.log(stats)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
172
lib/client.js
172
lib/client.js
@ -1,172 +0,0 @@
|
||||
const assert = require('nanoassert')
|
||||
const fetch = require('node-fetch')
|
||||
const { URL } = require('url')
|
||||
const qs = require('qs')
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
const { createReadStream } = require('fs')
|
||||
const FormData = require('form-data')
|
||||
const { handleResponse } = require('fetch-errors')
|
||||
const afw = require('async-folder-walker')
|
||||
const pkg = require('../package.json')
|
||||
const { neocitiesLocalDiff } = require('./folder-diff')
|
||||
|
||||
const defaultURL = 'https://neocities.org'
|
||||
|
||||
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({
|
||||
baseURL: defaultURL
|
||||
}, opts)
|
||||
|
||||
const baseURL = opts.baseURL
|
||||
delete opts.baseURL
|
||||
|
||||
const url = new URL('/api/key', baseURL)
|
||||
url.username = sitename
|
||||
url.password = password
|
||||
return fetch(url, opts)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
get defaultHeaders () {
|
||||
return {
|
||||
Authorization: `Bearer ${this.apiKey}`,
|
||||
Accept: 'application/json',
|
||||
'User-Agent': `deploy-to-neocities/${pkg.version} (${os.type()})`
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic get request to neocities
|
||||
*/
|
||||
get (endpoint, quieries, opts) {
|
||||
assert(endpoint, 'must pass endpoint as first argument')
|
||||
opts = Object.assign({
|
||||
method: 'GET'
|
||||
}, opts)
|
||||
opts.headers = Object.assign({}, this.defaultHeaders, opts.headers)
|
||||
|
||||
let path = `/api/${endpoint}`
|
||||
if (quieries) path += `?${qs.stringify(quieries)}`
|
||||
|
||||
const url = new URL(path, this.url)
|
||||
return fetch(url, opts)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic post request to neocities
|
||||
*/
|
||||
post (endpoint, formEntries, opts) {
|
||||
assert(endpoint, 'must pass endpoint as first argument')
|
||||
const form = new FormData()
|
||||
opts = Object.assign({
|
||||
method: 'POST',
|
||||
body: form
|
||||
}, opts)
|
||||
|
||||
for (const { name, value } of formEntries) {
|
||||
form.append(name, value)
|
||||
}
|
||||
|
||||
opts.headers = Object.assign(
|
||||
{},
|
||||
this.defaultHeaders,
|
||||
form.getHeaders(),
|
||||
opts.headers)
|
||||
|
||||
const url = new URL(`/api/${endpoint}`, this.url)
|
||||
return fetch(url, opts)
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload files to neocities
|
||||
*/
|
||||
upload (files) {
|
||||
const formEntries = files.map(({ name, path }) => {
|
||||
return {
|
||||
name,
|
||||
value: createReadStream(path)
|
||||
}
|
||||
})
|
||||
|
||||
return this.post('upload', formEntries).then(handleResponse)
|
||||
}
|
||||
|
||||
/**
|
||||
* delete files from your website
|
||||
*/
|
||||
delete (filenames) {
|
||||
assert(filenames, 'filenames is a required first argument')
|
||||
assert(Array.isArray(filenames), 'filenames argument must be an array of file paths in your website')
|
||||
|
||||
const formEntries = filenames.map(file => ({
|
||||
name: 'filenames[]',
|
||||
value: file
|
||||
}))
|
||||
|
||||
return this.post('delete', formEntries).then(handleResponse)
|
||||
}
|
||||
|
||||
list (queries) {
|
||||
// args.path: Path to list
|
||||
return this.get('list', queries).then(handleResponse)
|
||||
}
|
||||
|
||||
/**
|
||||
* info returns info on your site, or optionally on a sitename querystrign
|
||||
* @param {Object} args Querystring arguments to include (e.g. sitename)
|
||||
* @return {Promise} Fetch request promise
|
||||
*/
|
||||
info (queries) {
|
||||
// args.sitename: sitename to get info on
|
||||
return this.get('info', queries).then(handleResponse)
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploy a folder to neocities, skipping already uploaded files and optionally cleaning orphaned files.
|
||||
* @param {String} folder The path of the folder to deploy.
|
||||
* @param {Object} opts Options object.
|
||||
* @param {Boolean} opts.cleanup Boolean to delete orphaned files nor not. Defaults to false.
|
||||
* @param {Boolean} opts.statsCb Get access to stat info before uploading is complete.
|
||||
* @return {Promise} Promise containing stats about the deploy
|
||||
*/
|
||||
async deploy (folder, opts) {
|
||||
opts = {
|
||||
cleanup: false, // delete remote orphaned files
|
||||
statsCb: () => {},
|
||||
...opts
|
||||
}
|
||||
|
||||
const [localFiles, remoteFiles] = Promise.all([
|
||||
afw.allFiles(path.join(folder), { shaper: f => f }),
|
||||
this.list()
|
||||
])
|
||||
|
||||
const { filesToUpload, filesToDelete, filesSkipped } = await neocitiesLocalDiff(remoteFiles, localFiles)
|
||||
opts.statsCb({ filesToUpload, filesToDelete, filesSkipped })
|
||||
const work = [this.upload(filesToUpload)]
|
||||
if (opts.cleanup) work.push(this.delete(filesToDelete))
|
||||
|
||||
await work
|
||||
|
||||
return { filesToUpload, filesToDelete, filesSkipped }
|
||||
}
|
||||
}
|
||||
module.exports = { NeocitiesAPIClient }
|
||||
@ -1,159 +0,0 @@
|
||||
const crypto = require('crypto')
|
||||
const util = require('util')
|
||||
const fs = require('fs')
|
||||
const ppump = util.promisify(require('pump'))
|
||||
|
||||
/**
|
||||
* neocitiesLocalDiff returns an array of files to delete and update and some useful stats.
|
||||
*/
|
||||
async function neocitiesLocalDiff (neocitiesFiles, localListing, opts = {}) {
|
||||
opts = {
|
||||
...opts
|
||||
}
|
||||
|
||||
const localIndex = {}
|
||||
const ncIndex = {}
|
||||
|
||||
const neoCitiesFiltered = neocitiesFiles.filter(f => !f.is_directory)
|
||||
neoCitiesFiltered.forEach(f => { ncIndex[f.path] = f }) // index
|
||||
const ncFiles = new Set(neoCitiesFiltered.map(f => f.path)) // shape
|
||||
|
||||
const localListingFiltered = localListing.filter(f => !f.stat.isDirectory()) // files only
|
||||
localListingFiltered.forEach(f => { localIndex[f.relname] = f }) // index
|
||||
// TODO: convert windows to unix paths
|
||||
const localFiles = new Set(localListingFiltered.map(f => f.relname)) // shape
|
||||
|
||||
const filesToAdd = difference(localFiles, ncFiles)
|
||||
const filesToDelete = difference(ncFiles, localFiles)
|
||||
|
||||
const maybeUpdate = intersection(localFiles, ncFiles)
|
||||
const skipped = new Set()
|
||||
|
||||
for (const p of maybeUpdate) {
|
||||
const local = localIndex[p]
|
||||
const remote = ncIndex[p]
|
||||
|
||||
if (local.stat.size !== remote.size) { filesToAdd.add(p); continue }
|
||||
|
||||
const localSha1 = await sha1FromPath(local.filepath)
|
||||
if (localSha1 !== remote.sha1_hash) { filesToAdd.add(p); continue }
|
||||
|
||||
skipped.add(p)
|
||||
}
|
||||
|
||||
return {
|
||||
filesToUpload: Array.from(filesToAdd).map(p => ({
|
||||
name: localIndex[p].relname,
|
||||
path: localIndex[p].filepath
|
||||
})),
|
||||
filesToDelete: Array.from(filesToDelete).map(p => ncIndex[p].path),
|
||||
filesSkipped: Array.from(skipped).map(p => localIndex[p])
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
neocitiesLocalDiff
|
||||
}
|
||||
|
||||
/**
|
||||
* sha1FromPath returns a sha1 hex from a path
|
||||
* @param {String} p string of the path of the file to hash
|
||||
* @return {Promise<String>} the hex representation of the sha1
|
||||
*/
|
||||
async function sha1FromPath (p) {
|
||||
const rs = fs.createReadStream(p)
|
||||
const hash = crypto.createHash('sha1')
|
||||
|
||||
await ppump(rs, hash)
|
||||
|
||||
return hash.digest('hex')
|
||||
}
|
||||
|
||||
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#Implementing_basic_set_operations
|
||||
|
||||
/**
|
||||
* difference betwen setA and setB
|
||||
* @param {Set} setA LHS set
|
||||
* @param {Set} setB RHS set
|
||||
* @return {Set} The difference Set
|
||||
*/
|
||||
function difference (setA, setB) {
|
||||
const _difference = new Set(setA)
|
||||
for (const elem of setB) {
|
||||
_difference.delete(elem)
|
||||
}
|
||||
return _difference
|
||||
}
|
||||
|
||||
function intersection (setA, setB) {
|
||||
const _intersection = new Set()
|
||||
for (const elem of setB) {
|
||||
if (setA.has(elem)) {
|
||||
_intersection.add(elem)
|
||||
}
|
||||
}
|
||||
return _intersection
|
||||
}
|
||||
|
||||
// [
|
||||
// {
|
||||
// path: 'img',
|
||||
// is_directory: true,
|
||||
// updated_at: 'Thu, 21 Nov 2019 04:06:17 -0000'
|
||||
// },
|
||||
// {
|
||||
// path: 'index.html',
|
||||
// is_directory: false,
|
||||
// size: 1094,
|
||||
// updated_at: 'Mon, 11 Nov 2019 22:23:16 -0000',
|
||||
// sha1_hash: '7f15617e87d83218223662340f4052d9bb9d096d'
|
||||
// },
|
||||
// {
|
||||
// path: 'neocities.png',
|
||||
// is_directory: false,
|
||||
// size: 13232,
|
||||
// updated_at: 'Mon, 11 Nov 2019 22:23:16 -0000',
|
||||
// sha1_hash: 'fd2ee41b1922a39a716cacb88c323d613b0955e4'
|
||||
// },
|
||||
// {
|
||||
// path: 'not_found.html',
|
||||
// is_directory: false,
|
||||
// size: 347,
|
||||
// updated_at: 'Mon, 11 Nov 2019 22:23:16 -0000',
|
||||
// sha1_hash: 'd7f004e9d3b2eaaa8827f741356f1122dc9eb030'
|
||||
// },
|
||||
// {
|
||||
// path: 'style.css',
|
||||
// is_directory: false,
|
||||
// size: 298,
|
||||
// updated_at: 'Mon, 11 Nov 2019 22:23:16 -0000',
|
||||
// sha1_hash: 'e516457acdb0d00710ab62cc257109ef67209ce8'
|
||||
// }
|
||||
// ]
|
||||
|
||||
// [{
|
||||
// root: '/Users/bret/repos/async-folder-walker/fixtures',
|
||||
// filepath: '/Users/bret/repos/async-folder-walker/fixtures/sub-folder/sub-sub-folder',
|
||||
// stat: Stats {
|
||||
// dev: 16777220,
|
||||
// mode: 16877,
|
||||
// nlink: 3,
|
||||
// uid: 501,
|
||||
// gid: 20,
|
||||
// rdev: 0,
|
||||
// blksize: 4096,
|
||||
// ino: 30244023,
|
||||
// size: 96,
|
||||
// blocks: 0,
|
||||
// atimeMs: 1574381262779.8396,
|
||||
// mtimeMs: 1574380914743.5474,
|
||||
// ctimeMs: 1574380914743.5474,
|
||||
// birthtimeMs: 1574380905232.5996,
|
||||
// atime: 2019-11-22T00:07:42.780Z,
|
||||
// mtime: 2019-11-22T00:01:54.744Z,
|
||||
// ctime: 2019-11-22T00:01:54.744Z,
|
||||
// birthtime: 2019-11-22T00:01:45.233Z
|
||||
// },
|
||||
// relname: 'sub-folder/sub-sub-folder',
|
||||
// basename: 'sub-sub-folder'
|
||||
// }]
|
||||
@ -1,65 +0,0 @@
|
||||
const tap = require('tap')
|
||||
const afw = require('async-folder-walker')
|
||||
const path = require('path')
|
||||
const { neocitiesLocalDiff } = require('./folder-diff')
|
||||
|
||||
const remoteFiles = [
|
||||
{
|
||||
path: 'img',
|
||||
is_directory: true,
|
||||
updated_at: 'Thu, 21 Nov 2019 04:06:17 -0000'
|
||||
},
|
||||
{
|
||||
path: 'index.html',
|
||||
is_directory: false,
|
||||
size: 1094,
|
||||
updated_at: 'Mon, 11 Nov 2019 22:23:16 -0000',
|
||||
sha1_hash: '7f15617e87d83218223662340f4052d9bb9d096d'
|
||||
},
|
||||
{
|
||||
path: 'neocities.png',
|
||||
is_directory: false,
|
||||
size: 13232,
|
||||
updated_at: 'Mon, 11 Nov 2019 22:23:16 -0000',
|
||||
sha1_hash: 'fd2ee41b1922a39a716cacb88c323d613b0955e4'
|
||||
},
|
||||
{
|
||||
path: 'not_found.html',
|
||||
is_directory: false,
|
||||
size: 347,
|
||||
updated_at: 'Mon, 11 Nov 2019 22:23:16 -0000',
|
||||
sha1_hash: 'd7f004e9d3b2eaaa8827f741356f1122dc9eb030'
|
||||
},
|
||||
{
|
||||
path: 'style.css',
|
||||
is_directory: false,
|
||||
size: 298,
|
||||
updated_at: 'Mon, 11 Nov 2019 22:23:16 -0000',
|
||||
sha1_hash: 'e516457acdb0d00710ab62cc257109ef67209ce8'
|
||||
}
|
||||
]
|
||||
|
||||
tap.test('test differ', async t => {
|
||||
const localFiles = await afw.allFiles(path.join(__dirname, '../fixtures'), {
|
||||
shaper: f => f
|
||||
})
|
||||
|
||||
const { filesToUpload, filesToDelete, filesSkipped } = await neocitiesLocalDiff(remoteFiles, localFiles)
|
||||
|
||||
t.true(['tootzzz.png', 'toot.gif', 'cat.png'].every(path => {
|
||||
const found = filesToUpload.find(ftu => ftu.name === path)
|
||||
t.ok(found.path && found.name, 'each file to upload has a name and path')
|
||||
return found
|
||||
}), 'every file to upload is included')
|
||||
|
||||
t.deepEqual(filesToDelete, [
|
||||
'index.html',
|
||||
'not_found.html',
|
||||
'style.css'
|
||||
], 'filesToDelete returned correctly')
|
||||
|
||||
t.true(['neocities.png'].every(path => {
|
||||
const found = filesSkipped.find(fs => fs.relname === path)
|
||||
return found
|
||||
}), 'every file skipped is included')
|
||||
})
|
||||
2
node_modules/@types/node/README.md
generated
vendored
2
node_modules/@types/node/README.md
generated
vendored
@ -8,7 +8,7 @@ This package contains type definitions for Node.js (http://nodejs.org/).
|
||||
Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node.
|
||||
|
||||
### Additional Details
|
||||
* Last updated: Fri, 31 Jan 2020 21:34:20 GMT
|
||||
* Last updated: Tue, 11 Feb 2020 17:16:28 GMT
|
||||
* Dependencies: none
|
||||
* Global values: `Buffer`, `Symbol`, `__dirname`, `__filename`, `clearImmediate`, `clearInterval`, `clearTimeout`, `console`, `exports`, `global`, `module`, `process`, `queueMicrotask`, `require`, `setImmediate`, `setInterval`, `setTimeout`
|
||||
|
||||
|
||||
6
node_modules/@types/node/globals.d.ts
generated
vendored
6
node_modules/@types/node/globals.d.ts
generated
vendored
@ -239,6 +239,12 @@ declare class Buffer extends Uint8Array {
|
||||
*/
|
||||
static from(data: number[]): Buffer;
|
||||
static from(data: Uint8Array): Buffer;
|
||||
/**
|
||||
* Creates a new buffer containing the coerced value of an object
|
||||
* A `TypeError` will be thrown if {obj} has not mentioned methods or is not of other type appropriate for `Buffer.from()` variants.
|
||||
* @param obj An object supporting `Symbol.toPrimitive` or `valueOf()`.
|
||||
*/
|
||||
static from(obj: { valueOf(): string | object } | { [Symbol.toPrimitive](hint: 'string'): string }, byteOffset?: number, length?: number): Buffer;
|
||||
/**
|
||||
* Creates a new Buffer containing the given JavaScript string {str}.
|
||||
* If provided, the {encoding} parameter identifies the character encoding.
|
||||
|
||||
12
node_modules/@types/node/package.json
generated
vendored
12
node_modules/@types/node/package.json
generated
vendored
@ -1,8 +1,8 @@
|
||||
{
|
||||
"_from": "@types/node@>= 8",
|
||||
"_id": "@types/node@13.7.0",
|
||||
"_id": "@types/node@13.7.1",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ==",
|
||||
"_integrity": "sha512-Zq8gcQGmn4txQEJeiXo/KiLpon8TzAl0kmKH4zdWctPj05nWwp1ClMdAVEloqrQKfaC48PNLdgN/aVaLqUrluA==",
|
||||
"_location": "/@types/node",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
@ -20,8 +20,8 @@
|
||||
"/@octokit/types",
|
||||
"/@types/glob"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.0.tgz",
|
||||
"_shasum": "b417deda18cf8400f278733499ad5547ed1abec4",
|
||||
"_resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.1.tgz",
|
||||
"_shasum": "238eb34a66431b71d2aaddeaa7db166f25971a0d",
|
||||
"_spec": "@types/node@>= 8",
|
||||
"_where": "/Users/bret/repos/deploy-to-neocities/node_modules/@octokit/types",
|
||||
"bugs": {
|
||||
@ -209,7 +209,7 @@
|
||||
"scripts": {},
|
||||
"typeScriptVersion": "2.8",
|
||||
"types": "index.d.ts",
|
||||
"typesPublisherContentHash": "b0cd8dccd6d2eca8bb1de5a05bebf13796984567eb809f63164972122c4ddbaf",
|
||||
"typesPublisherContentHash": "8b99aa0031fac941d520282519c47b0255109858a20251313b1210c28769f463",
|
||||
"typesVersions": {
|
||||
">=3.5.0-0": {
|
||||
"*": [
|
||||
@ -217,5 +217,5 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": "13.7.0"
|
||||
"version": "13.7.1"
|
||||
}
|
||||
|
||||
25
node_modules/async-neocities/.github/workflows/tests.yml
generated
vendored
25
node_modules/async-neocities/.github/workflows/tests.yml
generated
vendored
@ -1,25 +0,0 @@
|
||||
name: tests
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
node: [12]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Use Node.js ${{ matrix.node }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
- name: npm install && npm test
|
||||
run: |
|
||||
npm i
|
||||
npm test
|
||||
env:
|
||||
CI: true
|
||||
76
node_modules/async-neocities/CHANGELOG.md
generated
vendored
76
node_modules/async-neocities/CHANGELOG.md
generated
vendored
@ -1,8 +1,74 @@
|
||||
# async-neocities Change Log
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Unreleased
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.0.1 - 2020-02-10
|
||||
* wip release
|
||||
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
||||
|
||||
## [v1.0.0](https://github.com/bcomnes/async-neocities/compare/v0.0.10...v1.0.0) - 2020-02-12
|
||||
|
||||
### Commits
|
||||
|
||||
- feat: progress API sketch [`be8b9ec`](https://github.com/bcomnes/async-neocities/commit/be8b9ec062b5ea23157a6a841c9d66d03a85a8ca)
|
||||
- docs: update README [`ec4f5f1`](https://github.com/bcomnes/async-neocities/commit/ec4f5f154b690dba0814ec0955fee674e8e94692)
|
||||
- CHANGELOG [`c9b64ed`](https://github.com/bcomnes/async-neocities/commit/c9b64edd4d3db025adc737982477ce0d760f3254)
|
||||
|
||||
## [v0.0.10](https://github.com/bcomnes/async-neocities/compare/v0.0.9...v0.0.10) - 2020-02-10
|
||||
|
||||
### Commits
|
||||
|
||||
- dont do work unless there is work [`616a306`](https://github.com/bcomnes/async-neocities/commit/616a306ba3ca091da11c9c85bae2b07cb0b2768e)
|
||||
|
||||
## [v0.0.9](https://github.com/bcomnes/async-neocities/compare/v0.0.8...v0.0.9) - 2020-02-10
|
||||
|
||||
### Commits
|
||||
|
||||
- Use stream ctor [`e8201a0`](https://github.com/bcomnes/async-neocities/commit/e8201a053950848962a220b83ffa1a97ebab6e70)
|
||||
|
||||
## [v0.0.8](https://github.com/bcomnes/async-neocities/compare/v0.0.7...v0.0.8) - 2020-02-10
|
||||
|
||||
### Commits
|
||||
|
||||
- Fix more bugs [`95da7b7`](https://github.com/bcomnes/async-neocities/commit/95da7b7218082ab51c1463851f87428dc0c501ac)
|
||||
|
||||
## [v0.0.7](https://github.com/bcomnes/async-neocities/compare/v0.0.6...v0.0.7) - 2020-02-10
|
||||
|
||||
### Commits
|
||||
|
||||
- bugs [`71ead78`](https://github.com/bcomnes/async-neocities/commit/71ead78e0f48f619816b3ae3ea8154e8301c77ac)
|
||||
|
||||
## [v0.0.6](https://github.com/bcomnes/async-neocities/compare/v0.0.5...v0.0.6) - 2020-02-10
|
||||
|
||||
### Commits
|
||||
|
||||
- bugs [`c1d9973`](https://github.com/bcomnes/async-neocities/commit/c1d9973afef3abd7d6edfc5a6ae1c9d37f6cb34d)
|
||||
|
||||
## [v0.0.5](https://github.com/bcomnes/async-neocities/compare/v0.0.4...v0.0.5) - 2020-02-10
|
||||
|
||||
### Commits
|
||||
|
||||
- bugs [`e542111`](https://github.com/bcomnes/async-neocities/commit/e542111f3404ab923be3490e62ba16b4f6b66a70)
|
||||
|
||||
## [v0.0.4](https://github.com/bcomnes/async-neocities/compare/v0.0.3...v0.0.4) - 2020-02-10
|
||||
|
||||
### Commits
|
||||
|
||||
- bump version [`a3da5f7`](https://github.com/bcomnes/async-neocities/commit/a3da5f77cda15fb3e9ec5861b588f616d8b0055c)
|
||||
|
||||
## [v0.0.3](https://github.com/bcomnes/async-neocities/compare/v0.0.2...v0.0.3) - 2020-02-10
|
||||
|
||||
### Commits
|
||||
|
||||
- tmp releases [`16a6db4`](https://github.com/bcomnes/async-neocities/commit/16a6db49a06bebef89007b94e03dd34e6d17b298)
|
||||
|
||||
## [v0.0.2](https://github.com/bcomnes/async-neocities/compare/v0.0.1...v0.0.2) - 2020-02-10
|
||||
|
||||
## v0.0.1 - 2020-02-10
|
||||
|
||||
### Commits
|
||||
|
||||
- Init [`bb055ae`](https://github.com/bcomnes/async-neocities/commit/bb055ae8e76b0344acc929e8ffd3974d19144001)
|
||||
- fix tests [`c294b52`](https://github.com/bcomnes/async-neocities/commit/c294b528a64a50638c4374a8782b177fe3634eb2)
|
||||
- Init [`9ec8fb5`](https://github.com/bcomnes/async-neocities/commit/9ec8fb557ebf8578c9eb07dedffcb1b7eedbd3e6)
|
||||
|
||||
2
node_modules/async-neocities/CODE_OF_CONDUCT.md
generated
vendored
2
node_modules/async-neocities/CODE_OF_CONDUCT.md
generated
vendored
@ -1,4 +1,4 @@
|
||||
# Code of conduct
|
||||
|
||||
- This repo is governed as a dictatorship starting with the originator of the project.
|
||||
- No malevolence tolerated whatsoever.
|
||||
- This is a malevolence free zone.
|
||||
|
||||
12
node_modules/async-neocities/CONTRIBUTING.md
generated
vendored
12
node_modules/async-neocities/CONTRIBUTING.md
generated
vendored
@ -1,5 +1,17 @@
|
||||
# Contributing
|
||||
|
||||
## Releasing
|
||||
|
||||
Changelog, and releasing is autmated with npm scripts. To create a release:
|
||||
|
||||
- Ensure a clean working git workspace.
|
||||
- Run `npm version {patch,minor,major}`.
|
||||
- This wills update the version number and generate the changelog.
|
||||
- Run `npm publish`.
|
||||
- This will push your local git branch and tags to the default remote, perform a [gh-release](https://ghub.io/gh-release), and create an npm publication.
|
||||
|
||||
## Guidelines
|
||||
|
||||
- Patches, ideas and changes welcome.
|
||||
- Fixes almost always welcome.
|
||||
- Features sometimes welcome.
|
||||
|
||||
216
node_modules/async-neocities/README.md
generated
vendored
216
node_modules/async-neocities/README.md
generated
vendored
@ -1,9 +1,11 @@
|
||||
# async-neocities
|
||||
[](https://github.com/bcomnes/async-neocities/actions)
|
||||
|
||||
WIP - nothing to see here
|
||||
An api client for [neocities][nc] with an async/promise API and an efficient deploy algorithm.
|
||||
|
||||
```
|
||||
<center><img src="logo.jpg"></center>
|
||||
|
||||
```console
|
||||
npm install async-neocities
|
||||
```
|
||||
|
||||
@ -28,6 +30,216 @@ deploySite.then(info => { console.log('done deploying site!') })
|
||||
.catch(e => { throw e })
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### `Neocities = require('async-neocities')`
|
||||
|
||||
Import the Neocities API client.
|
||||
|
||||
### `apiKey = await Neocities.getKey(sitename, password, [opts])`
|
||||
|
||||
Static class method that will get an API Key from a sitename and password.
|
||||
|
||||
`opts` include:
|
||||
|
||||
```js
|
||||
{
|
||||
url: 'https://neocities.org' // Base URL to use for requests
|
||||
}
|
||||
```
|
||||
|
||||
### `client = new Neocities(apiKey, [opts])`
|
||||
|
||||
Create a new API client for a given API key.
|
||||
|
||||
`opts` include:
|
||||
|
||||
```js
|
||||
{
|
||||
url: 'https://neocities.org' // Base URL to use for requests
|
||||
}
|
||||
```
|
||||
|
||||
### `response = await client.upload(files)`
|
||||
|
||||
Pass an array of objects with the `{ name, path }` pair to upload these files to neocities, where `name` is desired remote unix path on neocities and `path` is the local path on disk in whichever format the local operating system desires.
|
||||
|
||||
A successful `response`:
|
||||
|
||||
```js
|
||||
{
|
||||
result: 'success',
|
||||
message: 'your file(s) have been successfully uploaded'
|
||||
}
|
||||
```
|
||||
|
||||
### `response = await client.delete(filenames)`
|
||||
|
||||
Pass an array of path strings to delete on neocities. The path strings should be the unix style path of the file you want to delete.
|
||||
|
||||
A successful `response`:
|
||||
|
||||
```js
|
||||
{ result: 'success', message: 'file(s) have been deleted' }
|
||||
```
|
||||
|
||||
### `response = await client.list([queries])`
|
||||
|
||||
Get a list of files for your site. The optional `queries` object is passed through [qs][qs] and added to the request.
|
||||
|
||||
Available queries:
|
||||
|
||||
```js
|
||||
{
|
||||
path // list the contents of a subdirectory on neocities
|
||||
}
|
||||
```
|
||||
|
||||
Example `responses`:
|
||||
|
||||
```json
|
||||
{
|
||||
"result": "success",
|
||||
"files": [
|
||||
{
|
||||
"path": "index.html",
|
||||
"is_directory": false,
|
||||
"size": 1023,
|
||||
"updated_at": "Sat, 13 Feb 2016 03:04:00 -0000",
|
||||
"sha1_hash": "c8aac06f343c962a24a7eb111aad739ff48b7fb1"
|
||||
},
|
||||
{
|
||||
"path": "not_found.html",
|
||||
"is_directory": false,
|
||||
"size": 271,
|
||||
"updated_at": "Sat, 13 Feb 2016 03:04:00 -0000",
|
||||
"sha1_hash": "cfdf0bda2557c322be78302da23c32fec72ffc0b"
|
||||
},
|
||||
{
|
||||
"path": "images",
|
||||
"is_directory": true,
|
||||
"updated_at": "Sat, 13 Feb 2016 03:04:00 -0000"
|
||||
},
|
||||
{
|
||||
"path": "images/cat.png",
|
||||
"is_directory": false,
|
||||
"size": 16793,
|
||||
"updated_at": "Sat, 13 Feb 2016 03:04:00 -0000",
|
||||
"sha1_hash": "41fe08fc0dd44e79f799d03ece903e62be25dc7d"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
With the `path` query:
|
||||
|
||||
```json
|
||||
{
|
||||
"result": "success",
|
||||
"files": [
|
||||
{
|
||||
"path": "images/cat.png",
|
||||
"is_directory": false,
|
||||
"size": 16793,
|
||||
"updated_at": "Sat, 13 Feb 2016 03:04:00 -0000",
|
||||
"sha1_hash": "41fe08fc0dd44e79f799d03ece903e62be25dc7d"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `response = await client.info([queries])`
|
||||
|
||||
Get info about your or other sites. The optional `queries` object is passed through [qs][qs] and added to the request.
|
||||
|
||||
Available queries:
|
||||
|
||||
```js
|
||||
{
|
||||
sitename // get info on a given sitename
|
||||
}
|
||||
```
|
||||
|
||||
Example `responses`:
|
||||
|
||||
```json
|
||||
{
|
||||
"result": "success",
|
||||
"info": {
|
||||
"sitename": "youpi",
|
||||
"hits": 5072,
|
||||
"created_at": "Sat, 29 Jun 2013 10:11:38 +0000",
|
||||
"last_updated": "Tue, 23 Jul 2013 20:04:03 +0000",
|
||||
"domain": null,
|
||||
"tags": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `stats = await client.deploy(directory, [opts])`
|
||||
|
||||
Deploy a path to a `directory`, efficiently only uploading missing and changed files. Files are determined to be different by size, and sha1 hash, if the size is the same.
|
||||
|
||||
`opts` include:
|
||||
|
||||
```js
|
||||
{
|
||||
cleanup: false // delete orphaned files on neocities that are not in the `directory`
|
||||
statsCb: () => {} // WIP progress API
|
||||
}
|
||||
```
|
||||
|
||||
The return value of this method is subject to change.
|
||||
|
||||
### `client.get(endpoint, [quieries], [opts])`
|
||||
|
||||
Low level GET request to a given `endpoint`.
|
||||
|
||||
**NOTE**: The `/api/` prefix is automatically added: `/api/${endpoint}` so that must be omitted from `endpoint.
|
||||
|
||||
The optional `queries` object is stringified to a querystring using [`qs`][qs]a and added to the request.
|
||||
|
||||
`opts` includes:
|
||||
|
||||
```js
|
||||
{
|
||||
method: 'GET',
|
||||
headers: { ...client.defaultHeaders, ...opts.headers },
|
||||
}
|
||||
```
|
||||
|
||||
Note, that `opts` is passed internally to [`node-fetch`][nf] and you can include any options that work for that client here.
|
||||
|
||||
### `client.post(endpoint, formEntries, [opts])`
|
||||
|
||||
Low level POST request to a given `endpoint`.
|
||||
|
||||
**NOTE**: The `/api/` prefix is automatically adeded: `/api/${endpoint}` so that must be omitted from `endpoint.
|
||||
|
||||
Pass a `formEntries` array or iterator containing objects with `{name, value}` pairs to be sent with the POST request as [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData). The [form-datat][fd] module is used internally.
|
||||
|
||||
`opts` include:
|
||||
|
||||
```js
|
||||
{
|
||||
method: 'POST',
|
||||
body: new FormData(), // Don't override this.
|
||||
headers: { ...client.defafultHeaders, ...formHeaders, opts.headers }
|
||||
}
|
||||
```
|
||||
|
||||
Note, that `opts` is passed internally to [`node-fetch`][nf] and you can include any options that work for that client here.
|
||||
|
||||
## See also
|
||||
|
||||
- [Neocities API docs](https://neocities.org/api)
|
||||
- [Official Node.js API client](https://github.com/neocities/neocities-node)
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
[qs]: https://ghub.io/qs
|
||||
[nf]: https://ghub.io/node-fetch
|
||||
[fd]: https://ghub.io/form-data
|
||||
[nc]: https://neocities.org
|
||||
|
||||
BIN
node_modules/async-neocities/fixtures/cat.png
generated
vendored
BIN
node_modules/async-neocities/fixtures/cat.png
generated
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
BIN
node_modules/async-neocities/fixtures/neocities.png
generated
vendored
BIN
node_modules/async-neocities/fixtures/neocities.png
generated
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
BIN
node_modules/async-neocities/fixtures/toot.gif
generated
vendored
BIN
node_modules/async-neocities/fixtures/toot.gif
generated
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 461 B |
BIN
node_modules/async-neocities/fixtures/tootzzz.png
generated
vendored
BIN
node_modules/async-neocities/fixtures/tootzzz.png
generated
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 1.7 KiB |
312
node_modules/async-neocities/index.js
generated
vendored
312
node_modules/async-neocities/index.js
generated
vendored
@ -1,18 +1,41 @@
|
||||
const { handleResponse } = require('fetch-errors')
|
||||
const { createReadStream } = require('fs')
|
||||
const afw = require('async-folder-walker')
|
||||
const FormData = require('form-data')
|
||||
const assert = require('nanoassert')
|
||||
const fetch = require('node-fetch')
|
||||
const { URL } = require('url')
|
||||
const qs = require('qs')
|
||||
const os = require('os')
|
||||
const { createReadStream } = require('fs')
|
||||
const FormData = require('form-data')
|
||||
const { handleResponse } = require('fetch-errors')
|
||||
const afw = require('async-folder-walker')
|
||||
const pkg = require('./package.json')
|
||||
|
||||
const { neocitiesLocalDiff } = require('./lib/folder-diff')
|
||||
const pkg = require('./package.json')
|
||||
const SimpleTimer = require('./lib/timer')
|
||||
const { getStreamLength, meterStream } = require('./lib/stream-meter')
|
||||
|
||||
const defaultURL = 'https://neocities.org'
|
||||
|
||||
// Progress API constants
|
||||
const START = 'start'
|
||||
const PROGRESS = 'progress' // progress updates
|
||||
const STOP = 'stop'
|
||||
// Progress stages
|
||||
const INSPECTING = 'inspecting'
|
||||
const DIFFING = 'diffing'
|
||||
const APPLYING = 'applying'
|
||||
|
||||
/**
|
||||
* NeocitiesAPIClient class representing a neocities api client.
|
||||
*/
|
||||
class NeocitiesAPIClient {
|
||||
/**
|
||||
* getKey returns an apiKey from a sitename and password.
|
||||
* @param {String} sitename username/sitename to log into.
|
||||
* @param {String} password password to log in with.
|
||||
* @param {Object} [opts] Options object.
|
||||
* @param {Object} [opts.url=https://neocities.org] Base URL to request to.
|
||||
* @return {Promise<String>} An api key for the sitename..
|
||||
*/
|
||||
static getKey (sitename, password, opts) {
|
||||
assert(sitename, 'must pass sitename as first arg')
|
||||
assert(typeof sitename === 'string', 'user arg must be a string')
|
||||
@ -20,11 +43,11 @@ class NeocitiesAPIClient {
|
||||
assert(typeof password, 'password arg must be a string')
|
||||
|
||||
opts = Object.assign({
|
||||
baseURL: defaultURL
|
||||
url: defaultURL
|
||||
}, opts)
|
||||
|
||||
const baseURL = opts.baseURL
|
||||
delete opts.baseURL
|
||||
const baseURL = opts.url
|
||||
delete opts.url
|
||||
|
||||
const url = new URL('/api/key', baseURL)
|
||||
url.username = sitename
|
||||
@ -32,6 +55,13 @@ class NeocitiesAPIClient {
|
||||
return fetch(url, opts)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an async-neocities api client.
|
||||
* @param {string} apiKey An apiKey to make requests with.
|
||||
* @param {Object} [opts] Options object.
|
||||
* @param {Object} [opts.url=https://neocities.org] Base URL to make requests to.
|
||||
* @return {Object} An api client instance.
|
||||
*/
|
||||
constructor (apiKey, opts) {
|
||||
assert(apiKey, 'must pass apiKey as first argument')
|
||||
assert(typeof apiKey === 'string', 'apiKey must be a string')
|
||||
@ -39,7 +69,6 @@ class NeocitiesAPIClient {
|
||||
url: defaultURL
|
||||
})
|
||||
|
||||
this.opts = opts
|
||||
this.url = opts.url
|
||||
this.apiKey = apiKey
|
||||
}
|
||||
@ -48,12 +77,18 @@ class NeocitiesAPIClient {
|
||||
return {
|
||||
Authorization: `Bearer ${this.apiKey}`,
|
||||
Accept: 'application/json',
|
||||
'User-Agent': `deploy-to-neocities/${pkg.version} (${os.type()})`
|
||||
'User-Agent': `async-neocities/${pkg.version} (${os.type()})`
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic get request to neocities
|
||||
* Generic GET request to neocities.
|
||||
* @param {String} endpoint An endpoint path to GET request.
|
||||
* @param {Object} [quieries] An object that gets added to the request in the form of a query string.
|
||||
* @param {Object} [opts] Options object.
|
||||
* @param {String} [opts.method=GET] The http method to use.
|
||||
* @param {Object} [opts.headers] Headers to include in the request.
|
||||
* @return {Object} The parsed JSON from the request response.
|
||||
*/
|
||||
get (endpoint, quieries, opts) {
|
||||
assert(endpoint, 'must pass endpoint as first argument')
|
||||
@ -70,19 +105,46 @@ class NeocitiesAPIClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic post request to neocities
|
||||
* Low level POST request to neocities with FormData.
|
||||
* @param {String} endpoint The endpoint to make the request to.
|
||||
* @param {Array.<{name: String, value: String}>} formEntries Array of form entries.
|
||||
* @param {Object} [opts] Options object.
|
||||
* @param {String} [opts.method=POST] HTTP Method.
|
||||
* @param {Object} [opts.headers] Additional headers to send.
|
||||
* @return {Object} The parsed JSON response object.
|
||||
*/
|
||||
post (endpoint, formEntries, opts) {
|
||||
async post (endpoint, formEntries, opts) {
|
||||
assert(endpoint, 'must pass endpoint as first argument')
|
||||
const form = new FormData()
|
||||
assert(formEntries, 'must pass formEntries as second argument')
|
||||
|
||||
function createForm () {
|
||||
const form = new FormData()
|
||||
for (const { name, value } of formEntries) {
|
||||
form.append(name, value)
|
||||
}
|
||||
|
||||
return form
|
||||
}
|
||||
|
||||
opts = Object.assign({
|
||||
method: 'POST',
|
||||
body: form
|
||||
statsCb: () => {}
|
||||
}, opts)
|
||||
const statsCb = opts.statsCb
|
||||
delete opts.statsCb
|
||||
|
||||
for (const { name, value } of formEntries) {
|
||||
form.append(name, value)
|
||||
const stats = {
|
||||
totalBytes: await getStreamLength(createForm()),
|
||||
bytesWritten: 0
|
||||
}
|
||||
statsCb(stats)
|
||||
|
||||
const form = createForm()
|
||||
|
||||
opts.body = meterStream(form, bytesRead => {
|
||||
stats.bytesWritten = bytesRead
|
||||
statsCb(stats)
|
||||
})
|
||||
|
||||
opts.headers = Object.assign(
|
||||
{},
|
||||
@ -97,7 +159,11 @@ class NeocitiesAPIClient {
|
||||
/**
|
||||
* Upload files to neocities
|
||||
*/
|
||||
upload (files) {
|
||||
upload (files, opts = {}) {
|
||||
opts = {
|
||||
statsCb: () => {},
|
||||
...opts
|
||||
}
|
||||
const formEntries = files.map(({ name, path }) => {
|
||||
const streamCtor = (next) => next(createReadStream(path))
|
||||
streamCtor.path = path
|
||||
@ -107,22 +173,26 @@ class NeocitiesAPIClient {
|
||||
}
|
||||
})
|
||||
|
||||
return this.post('upload', formEntries).then(handleResponse)
|
||||
return this.post('upload', formEntries, { statsCb: opts.statsCb }).then(handleResponse)
|
||||
}
|
||||
|
||||
/**
|
||||
* delete files from your website
|
||||
*/
|
||||
delete (filenames) {
|
||||
delete (filenames, opts = {}) {
|
||||
assert(filenames, 'filenames is a required first argument')
|
||||
assert(Array.isArray(filenames), 'filenames argument must be an array of file paths in your website')
|
||||
opts = {
|
||||
statsCb: () => {},
|
||||
...opts
|
||||
}
|
||||
|
||||
const formEntries = filenames.map(file => ({
|
||||
name: 'filenames[]',
|
||||
value: file
|
||||
}))
|
||||
|
||||
return this.post('delete', formEntries).then(handleResponse)
|
||||
return this.post('delete', formEntries, { statsCb: opts.statsCb }).then(handleResponse)
|
||||
}
|
||||
|
||||
list (queries) {
|
||||
@ -141,34 +211,210 @@ class NeocitiesAPIClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploy a folder to neocities, skipping already uploaded files and optionally cleaning orphaned files.
|
||||
* @param {String} folder The path of the folder to deploy.
|
||||
* Deploy a directory to neocities, skipping already uploaded files and optionally cleaning orphaned files.
|
||||
* @param {String} directory The path of the directory to deploy.
|
||||
* @param {Object} opts Options object.
|
||||
* @param {Boolean} opts.cleanup Boolean to delete orphaned files nor not. Defaults to false.
|
||||
* @param {Boolean} opts.statsCb Get access to stat info before uploading is complete.
|
||||
* @return {Promise} Promise containing stats about the deploy
|
||||
*/
|
||||
async deploy (folder, opts) {
|
||||
async deploy (directory, opts) {
|
||||
opts = {
|
||||
cleanup: false, // delete remote orphaned files
|
||||
statsCb: () => {},
|
||||
...opts
|
||||
}
|
||||
|
||||
const [localFiles, remoteFiles] = await Promise.all([
|
||||
afw.allFiles(folder, { shaper: f => f }),
|
||||
this.list()
|
||||
])
|
||||
const statsCb = opts.statsCb
|
||||
const startDeployTime = Date.now()
|
||||
const totalTime = new SimpleTimer(startDeployTime)
|
||||
|
||||
// Inspection stage stats initializer
|
||||
const inspectionStats = {
|
||||
stage: INSPECTING,
|
||||
status: START,
|
||||
timer: new SimpleTimer(startDeployTime),
|
||||
totalTime,
|
||||
tasks: {
|
||||
localScan: {
|
||||
numberOfFiles: 0,
|
||||
totalSize: 0,
|
||||
timer: new SimpleTimer(startDeployTime)
|
||||
},
|
||||
remoteScan: {
|
||||
numberOfFiles: 0,
|
||||
totalSize: 0,
|
||||
timer: new SimpleTimer(startDeployTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
const sendInspectionUpdate = (status) => {
|
||||
if (status) inspectionStats.status = status
|
||||
statsCb(inspectionStats)
|
||||
}
|
||||
sendInspectionUpdate(START)
|
||||
|
||||
// Remote scan timers
|
||||
const remoteScanJob = this.list()
|
||||
remoteScanJob.then(({ files }) => { // Comes in the form of a response object
|
||||
const { tasks: { remoteScan } } = inspectionStats
|
||||
remoteScan.numberOfFiles = files.length
|
||||
remoteScan.totalSize = files.reduce((accum, cur) => {
|
||||
return accum + cur.size || 0
|
||||
}, 0)
|
||||
remoteScan.timer.stop()
|
||||
sendInspectionUpdate(PROGRESS)
|
||||
})
|
||||
|
||||
// Local scan timers and progress accumulator
|
||||
const localScanJob = progressAccum(
|
||||
afw.asyncFolderWalker(directory, { shaper: f => f })
|
||||
)
|
||||
async function progressAccum (iterator) {
|
||||
const localFiles = []
|
||||
const { tasks: { localScan } } = inspectionStats
|
||||
|
||||
for await (const file of iterator) {
|
||||
localFiles.push(file)
|
||||
localScan.numberOfFiles += 1
|
||||
localScan.totalSize += file.stat.blksize
|
||||
sendInspectionUpdate(PROGRESS)
|
||||
}
|
||||
return localFiles
|
||||
}
|
||||
localScanJob.then(files => {
|
||||
const { tasks: { localScan } } = inspectionStats
|
||||
localScan.timer.stop()
|
||||
sendInspectionUpdate(PROGRESS)
|
||||
})
|
||||
|
||||
// Inspection stage finalizer
|
||||
const [localFiles, remoteFiles] = await Promise.all([
|
||||
localScanJob,
|
||||
this.list().then(res => res.files)
|
||||
])
|
||||
inspectionStats.timer.stop()
|
||||
sendInspectionUpdate(STOP)
|
||||
|
||||
// DIFFING STAGE
|
||||
|
||||
const diffingStats = {
|
||||
stage: DIFFING,
|
||||
status: START,
|
||||
timer: new SimpleTimer(Date.now()),
|
||||
totalTime,
|
||||
tasks: {
|
||||
diffing: {
|
||||
uploadCount: 0,
|
||||
deleteCount: 0,
|
||||
skipCount: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
statsCb(diffingStats)
|
||||
|
||||
const { tasks: { diffing } } = diffingStats
|
||||
const { filesToUpload, filesToDelete, filesSkipped } = await neocitiesLocalDiff(remoteFiles, localFiles)
|
||||
diffingStats.timer.stop()
|
||||
diffingStats.status = STOP
|
||||
diffing.uploadCount = filesToUpload.length
|
||||
diffing.deleteCount = filesToDelete.length
|
||||
diffing.skipCount = filesSkipped.length
|
||||
statsCb(diffingStats)
|
||||
|
||||
const applyingStartTime = Date.now()
|
||||
const applyingStats = {
|
||||
stage: APPLYING,
|
||||
status: START,
|
||||
timer: new SimpleTimer(applyingStartTime),
|
||||
totalTime,
|
||||
tasks: {
|
||||
uploadFiles: {
|
||||
timer: new SimpleTimer(applyingStartTime),
|
||||
bytesWritten: 0,
|
||||
totalBytes: 0,
|
||||
get percent () {
|
||||
return this.totalBytes === 0 ? 0 : this.bytesWritten / this.totalBytes
|
||||
},
|
||||
get speed () {
|
||||
return this.bytesWritten / this.timer.elapsed
|
||||
}
|
||||
},
|
||||
deleteFiles: {
|
||||
timer: new SimpleTimer(applyingStartTime),
|
||||
bytesWritten: 0,
|
||||
totalBytes: 0,
|
||||
get percent () {
|
||||
return this.totalBytes === 0 ? 0 : this.bytesWritten / this.totalBytes
|
||||
},
|
||||
get speed () {
|
||||
return this.bytesWritten / this.timer.elapsed
|
||||
}
|
||||
},
|
||||
skippedFiles: {
|
||||
count: filesSkipped.length,
|
||||
size: filesSkipped.reduce((accum, file) => accum + file.stat.blksize, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
const sendApplyingUpdate = (status) => {
|
||||
if (status) applyingStats.status = status
|
||||
statsCb(applyingStats)
|
||||
}
|
||||
sendApplyingUpdate(START)
|
||||
|
||||
const { filesToUpload, filesToDelete, filesSkipped } = await neocitiesLocalDiff(remoteFiles.files, localFiles)
|
||||
opts.statsCb({ filesToUpload, filesToDelete, filesSkipped })
|
||||
const work = []
|
||||
if (filesToUpload.length > 0) work.push(this.upload(filesToUpload))
|
||||
if (opts.cleanup && filesToDelete.length > 0) { work.push(this.delete(filesToDelete)) }
|
||||
const { tasks: { uploadFiles, deleteFiles } } = applyingStats
|
||||
|
||||
if (filesToUpload.length > 0) {
|
||||
const uploadJob = this.upload(filesToUpload, {
|
||||
statsCb: ({ bytesWritten, totalBytes }) => {
|
||||
uploadFiles.bytesWritten = bytesWritten
|
||||
uploadFiles.totalBytes = totalBytes
|
||||
sendApplyingUpdate(PROGRESS)
|
||||
}
|
||||
})
|
||||
work.push(uploadJob)
|
||||
uploadJob.then(res => {
|
||||
uploadFiles.timer.stop()
|
||||
sendApplyingUpdate(PROGRESS)
|
||||
})
|
||||
} else {
|
||||
uploadFiles.timer.stop()
|
||||
}
|
||||
|
||||
if (opts.cleanup && filesToDelete.length > 0) {
|
||||
const deleteJob = this.delete(filesToDelete, {
|
||||
statsCb: ({ bytesWritten, totalBytes }) => {
|
||||
deleteFiles.bytesWritten = bytesWritten
|
||||
deleteFiles.totalBytes = totalBytes
|
||||
sendApplyingUpdate(PROGRESS)
|
||||
}
|
||||
})
|
||||
work.push(deleteJob)
|
||||
deleteJob.then(res => {
|
||||
deleteFiles.timer.stop()
|
||||
sendApplyingUpdate(PROGRESS)
|
||||
})
|
||||
} else {
|
||||
deleteFiles.timer.stop()
|
||||
}
|
||||
|
||||
await Promise.all(work)
|
||||
applyingStats.timer.stop()
|
||||
sendApplyingUpdate(STOP)
|
||||
|
||||
return { filesToUpload, filesToDelete, filesSkipped }
|
||||
totalTime.stop()
|
||||
|
||||
const statsSummary = {
|
||||
time: totalTime,
|
||||
inspectionStats,
|
||||
diffingStats,
|
||||
applyingStats
|
||||
}
|
||||
|
||||
return statsSummary
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = NeocitiesAPIClient
|
||||
|
||||
40
node_modules/async-neocities/lib/folder-diff.js
generated
vendored
40
node_modules/async-neocities/lib/folder-diff.js
generated
vendored
@ -1,16 +1,16 @@
|
||||
const crypto = require('crypto')
|
||||
const util = require('util')
|
||||
const fs = require('fs')
|
||||
|
||||
const ppump = util.promisify(require('pump'))
|
||||
|
||||
/**
|
||||
* neocitiesLocalDiff returns an array of files to delete and update and some useful stats.
|
||||
* @param {Array} neocitiesFiles Array of files returned from the neocities list api.
|
||||
* @param {Array} localListing Array of files returned by a full data async-folder-walker run.
|
||||
* @return {Promise<Object>} Object of filesToUpload, filesToDelete and filesSkipped.
|
||||
*/
|
||||
async function neocitiesLocalDiff (neocitiesFiles, localListing, opts = {}) {
|
||||
opts = {
|
||||
...opts
|
||||
}
|
||||
|
||||
async function neocitiesLocalDiff (neocitiesFiles, localListing) {
|
||||
const localIndex = {}
|
||||
const ncIndex = {}
|
||||
|
||||
@ -19,9 +19,8 @@ async function neocitiesLocalDiff (neocitiesFiles, localListing, opts = {}) {
|
||||
const ncFiles = new Set(neoCitiesFiltered.map(f => f.path)) // shape
|
||||
|
||||
const localListingFiltered = localListing.filter(f => !f.stat.isDirectory()) // files only
|
||||
localListingFiltered.forEach(f => { localIndex[f.relname] = f }) // index
|
||||
// TODO: convert windows to unix paths
|
||||
const localFiles = new Set(localListingFiltered.map(f => f.relname)) // shape
|
||||
localListingFiltered.forEach(f => { localIndex[forceUnixRelname(f.relname)] = f }) // index
|
||||
const localFiles = new Set(localListingFiltered.map(f => forceUnixRelname(f.relname))) // shape
|
||||
|
||||
const filesToAdd = difference(localFiles, ncFiles)
|
||||
const filesToDelete = difference(ncFiles, localFiles)
|
||||
@ -43,7 +42,7 @@ async function neocitiesLocalDiff (neocitiesFiles, localListing, opts = {}) {
|
||||
|
||||
return {
|
||||
filesToUpload: Array.from(filesToAdd).map(p => ({
|
||||
name: localIndex[p].relname,
|
||||
name: forceUnixRelname(localIndex[p].relname),
|
||||
path: localIndex[p].filepath
|
||||
})),
|
||||
filesToDelete: Array.from(filesToDelete).map(p => ncIndex[p].path),
|
||||
@ -72,7 +71,7 @@ async function sha1FromPath (p) {
|
||||
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#Implementing_basic_set_operations
|
||||
|
||||
/**
|
||||
* difference betwen setA and setB
|
||||
* difference returnss the difference betwen setA and setB.
|
||||
* @param {Set} setA LHS set
|
||||
* @param {Set} setB RHS set
|
||||
* @return {Set} The difference Set
|
||||
@ -85,6 +84,12 @@ function difference (setA, setB) {
|
||||
return _difference
|
||||
}
|
||||
|
||||
/**
|
||||
* intersection returns the interesction between setA and setB.
|
||||
* @param {Set} setA setA LHS set
|
||||
* @param {Set} setB setB RHS set
|
||||
* @return {Set} The intersection set between setA and setB.
|
||||
*/
|
||||
function intersection (setA, setB) {
|
||||
const _intersection = new Set()
|
||||
for (const elem of setB) {
|
||||
@ -95,6 +100,18 @@ function intersection (setA, setB) {
|
||||
return _intersection
|
||||
}
|
||||
|
||||
/**
|
||||
* forceUnixRelname forces a OS dependent path to a unix style path.
|
||||
* @param {String} relname String path to convert to unix style.
|
||||
* @return {String} The unix variant of the path
|
||||
*/
|
||||
function forceUnixRelname (relname) {
|
||||
return relname.split(relname.sep).join('/')
|
||||
}
|
||||
|
||||
/**
|
||||
* Example of neocitiesFiles
|
||||
*/
|
||||
// [
|
||||
// {
|
||||
// path: 'img',
|
||||
@ -131,6 +148,9 @@ function intersection (setA, setB) {
|
||||
// }
|
||||
// ]
|
||||
|
||||
/**
|
||||
* Example of localListing
|
||||
*/
|
||||
// [{
|
||||
// root: '/Users/bret/repos/async-folder-walker/fixtures',
|
||||
// filepath: '/Users/bret/repos/async-folder-walker/fixtures/sub-folder/sub-sub-folder',
|
||||
|
||||
4
node_modules/async-neocities/lib/folder-diff.test.js
generated
vendored
4
node_modules/async-neocities/lib/folder-diff.test.js
generated
vendored
@ -1,6 +1,7 @@
|
||||
const tap = require('tap')
|
||||
const afw = require('async-folder-walker')
|
||||
const path = require('path')
|
||||
const tap = require('tap')
|
||||
|
||||
const { neocitiesLocalDiff } = require('./folder-diff')
|
||||
|
||||
const remoteFiles = [
|
||||
@ -53,7 +54,6 @@ tap.test('test differ', async t => {
|
||||
}), 'every file to upload is included')
|
||||
|
||||
t.deepEqual(filesToDelete, [
|
||||
'index.html',
|
||||
'not_found.html',
|
||||
'style.css'
|
||||
], 'filesToDelete returned correctly')
|
||||
|
||||
37
node_modules/async-neocities/package.json
generated
vendored
37
node_modules/async-neocities/package.json
generated
vendored
@ -1,26 +1,26 @@
|
||||
{
|
||||
"_from": "async-neocities@0.0.10",
|
||||
"_id": "async-neocities@0.0.10",
|
||||
"_from": "async-neocities@1.0.0",
|
||||
"_id": "async-neocities@1.0.0",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-K6QNpBPNlZtRX7wGkL3f+i1HNJ5NNnq0dURGbDVYtrwwYN+PUfbqElugIsvyj+OIsO2wp5A7NBo1Wm6T3prSeg==",
|
||||
"_integrity": "sha512-iRdvlFfyyqS390fGzs/FJOFG5izOJFVG/0w/xRoqZ6ochmjkxiByp16zjBb1Ade5lvXuKTuBdM/sdqmIQvWe5w==",
|
||||
"_location": "/async-neocities",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "async-neocities@0.0.10",
|
||||
"raw": "async-neocities@1.0.0",
|
||||
"name": "async-neocities",
|
||||
"escapedName": "async-neocities",
|
||||
"rawSpec": "0.0.10",
|
||||
"rawSpec": "1.0.0",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "0.0.10"
|
||||
"fetchSpec": "1.0.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/async-neocities/-/async-neocities-0.0.10.tgz",
|
||||
"_shasum": "fcb1e7e49c1577a2f2735256e51ca9e51893b792",
|
||||
"_spec": "async-neocities@0.0.10",
|
||||
"_resolved": "https://registry.npmjs.org/async-neocities/-/async-neocities-1.0.0.tgz",
|
||||
"_shasum": "cdb2d2c4f3a431ab2aba7982693f8922f94d4360",
|
||||
"_spec": "async-neocities@1.0.0",
|
||||
"_where": "/Users/bret/repos/deploy-to-neocities",
|
||||
"author": {
|
||||
"name": "Bret Comnes",
|
||||
@ -38,18 +38,27 @@
|
||||
"nanoassert": "^2.0.0",
|
||||
"node-fetch": "^2.6.0",
|
||||
"pump": "^3.0.0",
|
||||
"qs": "^6.9.1"
|
||||
"pumpify": "^2.0.1",
|
||||
"qs": "^6.9.1",
|
||||
"streamx": "^2.6.0"
|
||||
},
|
||||
"deprecated": false,
|
||||
"description": "WIP - nothing to see here",
|
||||
"devDependencies": {
|
||||
"auto-changelog": "^1.16.2",
|
||||
"dependency-check": "^4.1.0",
|
||||
"gh-release": "^3.5.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"standard": "^13.1.0",
|
||||
"tap": "^14.10.2"
|
||||
},
|
||||
"homepage": "https://github.com/bcomnes/async-neocities",
|
||||
"keywords": [],
|
||||
"keywords": [
|
||||
"neocities",
|
||||
"async",
|
||||
"api client",
|
||||
"static hosting"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "index.js",
|
||||
"name": "async-neocities",
|
||||
@ -58,15 +67,17 @@
|
||||
"url": "git+https://github.com/bcomnes/async-neocities.git"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublishOnly": "git push --follow-tags && gh-release",
|
||||
"test": "run-s test:*",
|
||||
"test:deps": "dependency-check . --no-dev --no-peer",
|
||||
"test:standard": "standard",
|
||||
"test:tape": "tap"
|
||||
"test:tape": "tap",
|
||||
"version": "auto-changelog -p --template keepachangelog auto-changelog --breaking-pattern 'BREAKING:' && git add CHANGELOG.md"
|
||||
},
|
||||
"standard": {
|
||||
"ignore": [
|
||||
"dist"
|
||||
]
|
||||
},
|
||||
"version": "0.0.10"
|
||||
"version": "1.0.0"
|
||||
}
|
||||
|
||||
48
node_modules/async-neocities/test.js
generated
vendored
48
node_modules/async-neocities/test.js
generated
vendored
@ -83,4 +83,52 @@ if (!fakeToken) {
|
||||
// console.log(deleteResults)
|
||||
t.equal(deleteResults.result, 'success', 'list result successfull')
|
||||
})
|
||||
|
||||
tap.test('can deploy folders', async t => {
|
||||
const client = new NeocitiesAPIClient(token)
|
||||
|
||||
// const statsCb = (stats) => {
|
||||
// let logLine = `${stats.stage} ${stats.status} ${stats.timer.elapsed}`
|
||||
// Object.entries(stats.tasks).forEach(([key, val]) => {
|
||||
// logLine += ` ${key}: ${JSON.stringify(val)}`
|
||||
// })
|
||||
// console.log(logLine)
|
||||
// }
|
||||
|
||||
const deployStats = await client.deploy(
|
||||
resolve(__dirname, 'fixtures'),
|
||||
{
|
||||
// statsCb,
|
||||
cleanup: false
|
||||
}
|
||||
)
|
||||
|
||||
t.ok(deployStats)
|
||||
|
||||
// console.dir(deployStats, { depth: 99, colors: true })
|
||||
|
||||
const redeployStats = await client.deploy(
|
||||
resolve(__dirname, 'fixtures'),
|
||||
{
|
||||
// statsCb,
|
||||
cleanup: false
|
||||
}
|
||||
)
|
||||
|
||||
t.ok(redeployStats)
|
||||
|
||||
// console.dir(redeployStats, { depth: 99, colors: true })
|
||||
|
||||
const cleanupStats = await client.deploy(
|
||||
resolve(__dirname, 'fixtures/empty'),
|
||||
{
|
||||
// statsCb,
|
||||
cleanup: true
|
||||
}
|
||||
)
|
||||
|
||||
t.ok(cleanupStats)
|
||||
|
||||
// console.dir(cleanupStats, { depth: 99, colors: true })
|
||||
})
|
||||
}
|
||||
|
||||
1
node_modules/end-of-stream/package.json
generated
vendored
1
node_modules/end-of-stream/package.json
generated
vendored
@ -16,6 +16,7 @@
|
||||
"fetchSpec": "^1.1.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/duplexify",
|
||||
"/pump"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
|
||||
4
node_modules/is-stream/package.json
generated
vendored
4
node_modules/is-stream/package.json
generated
vendored
@ -17,7 +17,9 @@
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/execa",
|
||||
"/hasha"
|
||||
"/got",
|
||||
"/hasha",
|
||||
"/term-size/execa"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
|
||||
"_shasum": "12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44",
|
||||
|
||||
3
node_modules/nanoassert/package.json
generated
vendored
3
node_modules/nanoassert/package.json
generated
vendored
@ -16,7 +16,8 @@
|
||||
"fetchSpec": "^2.0.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/async-neocities"
|
||||
"/async-neocities",
|
||||
"/streamx"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz",
|
||||
"_shasum": "a05f86de6c7a51618038a620f88878ed1e490c09",
|
||||
|
||||
3
node_modules/node-fetch/package.json
generated
vendored
3
node_modules/node-fetch/package.json
generated
vendored
@ -17,7 +17,8 @@
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/@octokit/request",
|
||||
"/async-neocities"
|
||||
"/async-neocities",
|
||||
"/auto-changelog"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
|
||||
"_shasum": "e633456386d4aa55863f676a7ab0daa8fdecb0fd",
|
||||
|
||||
3
node_modules/npm-run-path/package.json
generated
vendored
3
node_modules/npm-run-path/package.json
generated
vendored
@ -16,7 +16,8 @@
|
||||
"fetchSpec": "^2.0.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/execa"
|
||||
"/execa",
|
||||
"/term-size/execa"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
|
||||
"_shasum": "35a9232dfa35d7067b4cb2ddf2357b1871536c5f",
|
||||
|
||||
3
node_modules/p-finally/package.json
generated
vendored
3
node_modules/p-finally/package.json
generated
vendored
@ -16,7 +16,8 @@
|
||||
"fetchSpec": "^1.0.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/execa"
|
||||
"/execa",
|
||||
"/term-size/execa"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
|
||||
"_shasum": "3fbcfb15b899a44123b34b6dcc18b724336a2cae",
|
||||
|
||||
3
node_modules/pump/package.json
generated
vendored
3
node_modules/pump/package.json
generated
vendored
@ -17,7 +17,8 @@
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/async-neocities",
|
||||
"/get-stream"
|
||||
"/get-stream",
|
||||
"/pumpify"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
|
||||
"_shasum": "b4a2116815bde2f4e1ea602354e8c75565107a64",
|
||||
|
||||
11
node_modules/semver/package.json
generated
vendored
11
node_modules/semver/package.json
generated
vendored
@ -16,9 +16,16 @@
|
||||
"fetchSpec": "^5.5.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/caching-transform/make-dir",
|
||||
"/cp-file/make-dir",
|
||||
"/cross-spawn",
|
||||
"/make-dir",
|
||||
"/normalize-package-data"
|
||||
"/find-cache-dir/make-dir",
|
||||
"/istanbul-lib-report/make-dir",
|
||||
"/istanbul-lib-source-maps/make-dir",
|
||||
"/normalize-package-data",
|
||||
"/nyc/make-dir",
|
||||
"/package-json",
|
||||
"/semver-diff"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"_shasum": "a954f931aeba508d307bbf069eff0c01c96116f7",
|
||||
|
||||
3
node_modules/shebang-command/package.json
generated
vendored
3
node_modules/shebang-command/package.json
generated
vendored
@ -16,7 +16,8 @@
|
||||
"fetchSpec": "^1.2.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/cross-spawn"
|
||||
"/cross-spawn",
|
||||
"/term-size/cross-spawn"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
|
||||
"_shasum": "44aac65b695b03398968c39f363fee5deafdf1ea",
|
||||
|
||||
3
node_modules/signal-exit/package.json
generated
vendored
3
node_modules/signal-exit/package.json
generated
vendored
@ -16,12 +16,13 @@
|
||||
"fetchSpec": "^3.0.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/caching-transform/write-file-atomic",
|
||||
"/execa",
|
||||
"/foreground-child",
|
||||
"/gauge",
|
||||
"/nyc",
|
||||
"/restore-cursor",
|
||||
"/spawn-wrap",
|
||||
"/term-size/execa",
|
||||
"/write-file-atomic"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
|
||||
|
||||
3
node_modules/strip-eof/package.json
generated
vendored
3
node_modules/strip-eof/package.json
generated
vendored
@ -16,7 +16,8 @@
|
||||
"fetchSpec": "^1.0.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/execa"
|
||||
"/execa",
|
||||
"/term-size/execa"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
|
||||
"_shasum": "bb43ff5598a6eb05d89b59fcd129c983313606bf",
|
||||
|
||||
3
node_modules/which/package.json
generated
vendored
3
node_modules/which/package.json
generated
vendored
@ -18,7 +18,8 @@
|
||||
"_requiredBy": [
|
||||
"/cross-spawn",
|
||||
"/foreground-child/cross-spawn",
|
||||
"/spawn-wrap"
|
||||
"/spawn-wrap",
|
||||
"/term-size/cross-spawn"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
||||
"_shasum": "a45043d54f5805316da8d62f9f50918d3da70b0a",
|
||||
|
||||
13
package.json
13
package.json
@ -9,6 +9,11 @@
|
||||
"test-skip:deps": "dependency-check . --no-dev --no-peer",
|
||||
"test:standard": "standard",
|
||||
"test:tape": "tap",
|
||||
"release": "git push --follow-tags && gh-release",
|
||||
"version": "run-s version:*",
|
||||
"version:1-changelog": "auto-changelog -p --template keepachangelog auto-changelog --breaking-pattern 'BREAKING:' && git add CHANGELOG.md",
|
||||
"version:2-cleandeps": "rm -rf node_modules && npm i --only=prod && git add node_modules --force",
|
||||
"postversion": "npm i",
|
||||
"clean": "rimraf dist && mkdirp dist",
|
||||
"build": "mkdir public && cp package.json public/test.json"
|
||||
},
|
||||
@ -27,12 +32,16 @@
|
||||
"dependency-check": "^4.1.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"standard": "^14.3.1",
|
||||
"tap": "^14.10.5"
|
||||
"gh-release": "^3.5.0",
|
||||
"tap": "^14.10.5",
|
||||
"auto-changelog": "^1.16.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "1.2.2",
|
||||
"@actions/github": "2.1.0",
|
||||
"async-neocities": "0.0.10"
|
||||
"async-neocities": "1.0.0",
|
||||
"pretty-bytes": "^5.3.0",
|
||||
"pretty-time": "^1.1.0"
|
||||
},
|
||||
"standard": {
|
||||
"ignore": [
|
||||
|
||||
81
test.js
81
test.js
@ -1,82 +1,5 @@
|
||||
const tap = require('tap')
|
||||
|
||||
const { readFileSync } = require('fs')
|
||||
const { resolve } = require('path')
|
||||
const { NeocitiesAPIClient } = require('./lib/client')
|
||||
|
||||
let token = process.env.NEOCITIES_API_TOKEN
|
||||
|
||||
if (!token) {
|
||||
try {
|
||||
const config = JSON.parse(readFileSync(resolve(__dirname, 'config.json')))
|
||||
token = config.token
|
||||
} catch (e) {
|
||||
console.warn('error loading config.json')
|
||||
console.warn(e)
|
||||
}
|
||||
}
|
||||
|
||||
tap.test('token loaded', async t => {
|
||||
t.ok(token)
|
||||
})
|
||||
|
||||
tap.test('basic client api', async t => {
|
||||
const client = new NeocitiesAPIClient(token)
|
||||
|
||||
t.ok(client.info, 'info method available')
|
||||
t.ok(client.list, 'list method available')
|
||||
t.ok(client.get, 'get method available')
|
||||
t.ok(client.post, 'post method available')
|
||||
})
|
||||
|
||||
tap.test('can get info about site', async t => {
|
||||
const client = new NeocitiesAPIClient(token)
|
||||
|
||||
const info = await client.info()
|
||||
// console.log(info)
|
||||
t.equal(info.result, 'success', 'info requesst successfull')
|
||||
const list = await client.list()
|
||||
// console.log(list)
|
||||
t.equal(list.result, 'success', 'list result successfull')
|
||||
})
|
||||
|
||||
// test('form data works the way I think', t => {
|
||||
// const form = new FormData();
|
||||
// const p = resolve(__dirname, 'package.json');
|
||||
// form.append('package.json', next => next(createReadStream(p)));
|
||||
//
|
||||
// const concatStream = concat((data) => {
|
||||
// console.log(data);
|
||||
// t.end();
|
||||
// });
|
||||
//
|
||||
// form.on('error', (err) => {
|
||||
// t.error(err);
|
||||
// });
|
||||
// form.pipe(concatStream);
|
||||
// });
|
||||
|
||||
tap.test('can upload and delete files', async t => {
|
||||
const client = new NeocitiesAPIClient(token)
|
||||
|
||||
const uploadResults = await client.upload([
|
||||
{
|
||||
name: 'toot.gif',
|
||||
path: resolve(__dirname, 'fixtures/toot.gif')
|
||||
},
|
||||
{
|
||||
name: 'img/tootzzz.png',
|
||||
path: resolve(__dirname, 'fixtures/tootzzz.png')
|
||||
}
|
||||
])
|
||||
|
||||
// console.log(uploadResults)
|
||||
t.equal(uploadResults.result, 'success', 'list result successfull')
|
||||
|
||||
const deleteResults = await client.delete([
|
||||
'toot.gif',
|
||||
'img/tootzzz.png'
|
||||
])
|
||||
// console.log(deleteResults)
|
||||
t.equal(deleteResults.result, 'success', 'list result successfull')
|
||||
tap.test('test', async t => {
|
||||
t.ok(true)
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user