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.
|
||||
|
||||
16
node_modules/async-neocities/CONTRIBUTING.md
generated
vendored
16
node_modules/async-neocities/CONTRIBUTING.md
generated
vendored
@ -1,10 +1,22 @@
|
||||
# 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.
|
||||
- Please open an issue to discuss the issue prior to spending lots of time on the problem.
|
||||
- It may be rejected.
|
||||
- Please open an issue to discuss the issue prior to spending lots of time on the problem.
|
||||
- It may be rejected.
|
||||
- If you don't want to wait around for the discussion to commence, and you really want to jump into the implementation work, be prepared for fork if the idea is respectfully declined.
|
||||
- Try to stay within the style of the existing code.
|
||||
- All tests must pass.
|
||||
|
||||
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