Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

async-neocities

Package Overview
Dependencies
Maintainers
1
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

async-neocities - npm Package Compare versions

Comparing version 2.1.6 to 3.0.3

bin.js

34

CHANGELOG.md

@@ -10,6 +10,38 @@ # Changelog

## [v2.1.6](https://github.com/bcomnes/async-neocities/compare/v2.1.5...v2.1.6)
## [v3.0.3](https://github.com/bcomnes/async-neocities/compare/v3.0.2...v3.0.3)
### Commits
- Typo [`ad10451`](https://github.com/bcomnes/async-neocities/commit/ad104512222e442a99a86b42adc2a82f2ec27acd)
- More non-critical docs tweaks [`b350ef5`](https://github.com/bcomnes/async-neocities/commit/b350ef53dc8b7c5dfb46dbc754832416907c3a61)
## [v3.0.2](https://github.com/bcomnes/async-neocities/compare/v3.0.1...v3.0.2) - 2024-01-15
### Commits
- Improve docs [`527990d`](https://github.com/bcomnes/async-neocities/commit/527990d25e25a2570fa9663e4c19fa24843932dc)
## [v3.0.1](https://github.com/bcomnes/async-neocities/compare/v3.0.0...v3.0.1) - 2024-01-15
### Commits
- Fix engines range [`ce08ada`](https://github.com/bcomnes/async-neocities/commit/ce08ada4c78f975954c587af1cc5442cef37ca3f)
## [v3.0.0](https://github.com/bcomnes/async-neocities/compare/v2.1.6...v3.0.0) - 2024-01-15
### Merged
- Add command line interface and convert to ESM [`#81`](https://github.com/bcomnes/async-neocities/pull/81)
- build(deps): bump actions/setup-node from 3 to 4 [`#79`](https://github.com/bcomnes/async-neocities/pull/79)
### Commits
- Convert to esm [`032eb2c`](https://github.com/bcomnes/async-neocities/commit/032eb2cf9f345c48667657cc8444c07ba381e16f)
- Add a bin for local deployments [`7f2d322`](https://github.com/bcomnes/async-neocities/commit/7f2d32229ca5b115c9e000363c1e7503334a6a16)
- Switch to node test runner [`a9bd295`](https://github.com/bcomnes/async-neocities/commit/a9bd295049914a7acb55dd92e2fdd49202928cd7)
## [v2.1.6](https://github.com/bcomnes/async-neocities/compare/v2.1.5...v2.1.6) - 2023-10-22
### Merged
- build(deps): bump async-folder-walker from 2.2.1 to 3.0.1 [`#78`](https://github.com/bcomnes/async-neocities/pull/78)

@@ -16,0 +48,0 @@ - build(deps-dev): bump tap from 16.3.8 to 18.1.5 [`#77`](https://github.com/bcomnes/async-neocities/pull/77)

89

index.js

@@ -1,17 +0,20 @@

const { handleResponse } = require('fetch-errors')
const { createReadStream } = require('fs')
const afw = require('async-folder-walker')
const assert = require('nanoassert')
const fetch = require('node-fetch')
const { URL } = require('url')
const qs = require('querystring')
const os = require('os')
const { ErrorWithCause } = require('pony-cause')
// Replace require with import statements
import { request, fetch } from 'undici'
// @ts-ignore
import { handleResponse } from 'fetch-errors'
import { createReadStream } from 'fs'
import afw from 'async-folder-walker'
// @ts-ignore
import assert from 'webassert'
import { URL } from 'url'
import qs from 'querystring'
import os from 'os'
const { neocitiesLocalDiff } = require('./lib/folder-diff')
const pkg = require('./package.json')
const SimpleTimer = require('./lib/timer')
const { getStreamsLength, getStreamLength, meterStream, captureStreamLength } = require('./lib/stream-meter')
const statsHandler = require('./lib/stats-handler')
const { createForm, createForms } = require('./lib/create-form')
// Use import for local files as well
import { neocitiesLocalDiff } from './lib/folder-diff.js'
import { SimpleTimer } from './lib/timer.js'
import { getStreamsLength, getStreamLength, meterStream, captureStreamLength } from './lib/stream-meter.js'
import { statsHandler } from './lib/stats-handler.js'
import { createForm, createForms } from './lib/create-form.js'
import { pkg } from './pkg.cjs'

@@ -34,3 +37,3 @@ const defaultURL = 'https://neocities.org'

*/
class NeocitiesAPIClient {
export class NeocitiesAPIClient {
/**

@@ -41,6 +44,6 @@ * getKey returns an apiKey from a sitename and password.

* @param {Object} [opts] Options object.
* @param {Object} [opts.url=https://neocities.org] Base URL to request to.
* @param {string} [opts.url='https://neocities.org'] Base URL to request to.
* @return {Promise<String>} An api key for the sitename..
*/
static getKey (sitename, password, opts) {
static async getKey (sitename, password, opts) {
assert(sitename, 'must pass sitename as first arg')

@@ -58,6 +61,24 @@ assert(typeof sitename === 'string', 'user arg must be a string')

if (!baseURL) throw new Error('A url base is required')
const url = new URL('/api/key', baseURL)
url.username = sitename
url.password = password
return fetch(url, opts)
const response = await fetch(url, {
headers: {
Authorization: `Basic ${btoa(sitename + ':' + password)}`
}
})
if (!response.ok) {
let cause
try {
cause = await response.text()
} catch (err) {
cause = err
}
throw new Error('Response was not okay', { cause })
}
/** @type {*} */
const json = await response.json()
const token = json.api_key
return token
}

@@ -156,3 +177,3 @@

const url = new URL(`/api/${endpoint}`, this.url)
return fetch(url, opts)
return request(url, opts)
}

@@ -212,6 +233,6 @@

try {
const result = await fetch(url, reqOpts).then(handleResponse)
const result = await request(url, reqOpts)
results.push(result)
} catch (err) {
const wrappedError = new ErrorWithCause('Neocities API error', {
const wrappedError = new Error('Neocities API error', {
cause: err

@@ -265,3 +286,3 @@ })

return this.post('delete', formEntries, { statsCb: opts.statsCb }).then(handleResponse)
return this.post('delete', formEntries, { statsCb: opts.statsCb })
}

@@ -286,9 +307,9 @@

* 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.
* @param {Integer} opts.batchSize The number of files to upload per request. Default to 50.
* @param {Function} opts.protected FileFilter A filter function that will prevent files from being cleaned up.
* @return {Promise} Promise containing stats about the deploy
* @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.
* @param {number} opts.batchSize The number of files to upload per request. Default to 50.
* @param {function} opts.protected FileFilter A filter function that will prevent files from being cleaned up.
* @return {Promise<object>} Promise containing stats about the deploy
*/

@@ -363,3 +384,3 @@ async deploy (directory, opts) {

// Wrap error with stats so that we don't lose all that context
const wrappedError = new ErrorWithCause('Error uploading files', {
const wrappedError = new Error('Error uploading files', {
cause: err

@@ -387,3 +408,1 @@ })

}
module.exports = NeocitiesAPIClient

@@ -1,5 +0,4 @@

const FormData = require('form-data')
const batch = require('lodash.chunk')
import FormData from 'form-data'
function createForm (formEntries) {
export function createForm (formEntries) {
const form = new FormData()

@@ -13,8 +12,6 @@ for (const { name, value } of formEntries) {

exports.createForm = createForm
function createForms (formEntries, opts = {}) {
export function createForms (formEntries, opts = {}) {
const { batchSize = 50 } = opts
const forms = []
const batchedFormEntries = batch(formEntries, batchSize)
const batchedFormEntries = chunk(formEntries, batchSize)

@@ -29,2 +26,17 @@ for (const formEntryBatch of batchedFormEntries) {

exports.createForms = createForms
function chunk (array, size) {
if (!Array.isArray(array)) {
throw new TypeError('First argument must be an array.')
}
if (!Number.isInteger(size) || size <= 0) {
throw new TypeError('Size must be a positive integer.')
}
const chunked = []
for (let i = 0; i < array.length; i += size) {
chunked.push(array.slice(i, i + size))
}
return chunked
}

@@ -1,6 +0,7 @@

const crypto = require('crypto')
const util = require('util')
const fs = require('fs')
import crypto from 'node:crypto'
import util from 'node:util'
import fs from 'node:fs'
import pump from 'pump'
const ppump = util.promisify(require('pump'))
const ppump = util.promisify(pump)

@@ -13,3 +14,3 @@ /**

*/
async function neocitiesLocalDiff (neocitiesFiles, localListing, opts = {}) {
export async function neocitiesLocalDiff (neocitiesFiles, localListing, opts = {}) {
opts = {

@@ -64,6 +65,2 @@ protectedFileFilter: (path) => false,

module.exports = {
neocitiesLocalDiff
}
/**

@@ -70,0 +67,0 @@ * sha1FromPath returns a sha1 hex from a path

@@ -1,7 +0,10 @@

const afw = require('async-folder-walker')
const path = require('path')
const tap = require('tap')
const { minimatch } = require('minimatch')
import afw from 'async-folder-walker'
import path from 'node:path'
import test from 'node:test'
import assert from 'node:assert'
import { minimatch } from 'minimatch'
import desm from 'desm'
import { neocitiesLocalDiff } from './folder-diff.js'
const { neocitiesLocalDiff } = require('./folder-diff')
const __dirname = desm(import.meta.url)

@@ -58,3 +61,3 @@ const remoteFiles = [

tap.test('test differ', async t => {
test('test differ', async t => {
const localFiles = await afw.allFiles(path.join(__dirname, '../fixtures'), {

@@ -66,9 +69,9 @@ shaper: f => f

t.ok(['tootzzz.png', 'toot.gif', 'cat.png'].every(path => {
assert.ok(['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')
assert.ok(found.path && found.name, 'each file to upload has a name and path')
return found
}), 'every file to upload is included')
t.same(filesToDelete, [
assert.deepEqual(filesToDelete, [
'not_found.html',

@@ -80,3 +83,3 @@ 'style.css',

t.ok(['neocities.png'].every(path => {
assert.ok(['neocities.png'].every(path => {
const found = filesSkipped.find(fs => fs.relname === path)

@@ -86,6 +89,6 @@ return found

t.equal(protectedFiles.length, 0, 'no files are protected by default')
assert.equal(protectedFiles.length, 0, 'no files are protected by default')
})
tap.test('proteceted files', async t => {
test('proteceted files', async t => {
const localFiles = await afw.allFiles(path.join(__dirname, '../fixtures'), {

@@ -99,3 +102,3 @@ shaper: f => f

t.same(filesToDelete, [
assert.deepEqual(filesToDelete, [
'not_found.html',

@@ -105,3 +108,3 @@ 'style.css'

t.same(protectedFiles, ['a-folder/foo', 'a-folder/bar'], 'protected files are protected')
assert.deepEqual(protectedFiles, ['a-folder/foo', 'a-folder/bar'], 'protected files are protected')
})

@@ -1,2 +0,2 @@

const prettyBytes = require('pretty-bytes')
import prettyBytes from 'pretty-bytes'

@@ -9,3 +9,7 @@ // Progress API constants

function statsHandler (opts = {}) {
/**
* Handler for statistics updates.
* @returns {Function} - A function to handle stats updates.
*/
export function statsHandler () {
let progressInterval

@@ -64,3 +68,1 @@ const lastStats = {}

}
module.exports = statsHandler

@@ -1,4 +0,4 @@

const { Writable, Transform } = require('streamx')
const pump = require('pump')
const pumpify = require('pumpify')
import { Writable, Transform } from 'streamx'
import pump from 'pump'
import pumpify from 'pumpify'

@@ -56,3 +56,3 @@ async function getStreamsLength (readables) {

module.exports = {
export {
getStreamsLength,

@@ -59,0 +59,0 @@ getStreamLength,

/**
* Simple timer lets you record start and stop times, with an elapsed time getter.
*/
class SimpleTimer {
export class SimpleTimer {
constructor (startTime) {

@@ -33,3 +33,1 @@ this.start = startTime || Date.now()

}
module.exports = SimpleTimer
{
"name": "async-neocities",
"description": "WIP - nothing to see here",
"version": "2.1.6",
"description": "A library and bin to deploy to neocities",
"version": "3.0.3",
"author": "Bret Comnes <bcomnes@gmail.com> (https://bret.io)",
"type": "module",
"bin": {
"async-neocities": "./bin.js",
"an": "./bin.js"
},
"bugs": {
"url": "https://github.com/bcomnes/async-neocities/issues"
},
"engines": {
"node": ">=20",
"npm": ">=10"
},
"dependencies": {
"@lukeed/ms": "^2.0.2",
"application-config": "^3.0.0",
"argsclopts": "^1.0.4",
"async-folder-walker": "^3.0.1",
"desm": "^1.3.0",
"fetch-errors": "^2.0.1",
"form-data": "^4.0.0",
"lodash.chunk": "^4.2.0",
"nanoassert": "^2.0.0",
"node-fetch": "^2.6.0",
"password-prompt": "1.1.3",
"pony-cause": "^2.1.4",
"pretty-bytes": "^5.3.0",
"pretty-bytes": "^6.0.0",
"pump": "^3.0.0",
"pumpify": "^2.0.1",
"streamx": "^2.6.0"
"streamx": "^2.6.0",
"undici": "^6.0.0",
"webassert": "^3.0.2"
},
"devDependencies": {
"@voxpelli/tsconfig": "^10.0.0",
"auto-changelog": "^2.2.0",
"dependency-check": "^4.1.0",
"c8": "^9.0.0",
"gh-release": "^7.0.0",
"minimatch": "^9.0.0",
"minimatch": "^9.0.3",
"npm-run-all": "^4.1.5",
"standard": "^17.0.0",
"tap": "^18.1.5"
"standard": "^17.0.0"
},

@@ -47,5 +60,4 @@ "homepage": "https://github.com/bcomnes/async-neocities",

"test": "run-s test:*",
"test:deps": "dependency-check . --no-dev --no-peer",
"test:standard": "standard",
"test:tape": "tap",
"test:node-test": "c8 node --test --test-reporter spec",
"version": "auto-changelog -p --template keepachangelog auto-changelog --breaking-pattern 'BREAKING CHANGE:' && git add CHANGELOG.md"

@@ -57,15 +69,3 @@ },

]
},
"tap": {
"serial": [
"lib",
"test.js"
],
"typecheck": false,
"allow-incomplete-coverage": true,
"coverage-report": [
"text",
"lcovonly"
]
}
}

@@ -17,9 +17,9 @@ # async-neocities

``` js
const path = require('path')
const Neocities = require('async-neocities')
import path from 'node:path'
import { NeocitiesAPIClient } from 'async-neocities'
async function deploySite () {
const token = await Neocities.getKey('sitename', 'password')
const token = await NeocitiesAPIClient.getKey('sitename', 'password')
const client = new Neocities(token)
const client = new NeocitiesAPIClient(token)

@@ -36,9 +36,43 @@ console.log(await client.list()) // site files

## Bin
`async-neocities` ships a bin that lets you deploy to neocities locally or in CI.
It's interactive and will help you set up your config and keys.
The site name is configured to a file in cwd called `deploy-to-neocities.json` that looks like:
```json
{"siteName":"the-name-of-the-site"}
```
```console
Usage: async-neocities [options]
Example: async-neocities --src public
--help, -h print help text
--src, -s The directory to deploy to neocities (default: "public")
--cleanup, -c Destructively clean up orphaned files on neocities
--protect, -p String to minimatch files which will never be cleaned up
--status Print auth status of current working directory
--print-key Print api-key status of current working directory
--clear-key Remove the currently assoicated API key
--force-auth Force re-authorization of current working directory
async-neocities (v3.0.0)
```
You can set the flags with ENV vars
- `ASYNC_NEOCITIES_API_KEY` or `NEOCITIES_API_TOKEN`: the API token matching the site name, but you should set and commit the `deploy-to-neocities.json` file.
- `ASYNC_NEOCITIES_SITE_NAME`: the name of the site to deploy to.
## API
### `Neocities = require('async-neocities')`
### `import { NeocitiesAPIClient } from 'async-neocities'`
Import the Neocities API client.
### `apiKey = await Neocities.getKey(sitename, password, [opts])`
### `apiKey = await NeocitiesAPIClient.getKey(sitename, password, [opts])`

@@ -55,3 +89,3 @@ Static class method that will get an API Key from a sitename and password.

### `client = new Neocities(apiKey, [opts])`
### `client = new NeocitiesAPIClient(apiKey, [opts])`

@@ -58,0 +92,0 @@ Create a new API client for a given API key.

@@ -1,7 +0,10 @@

const tap = require('tap')
import test from 'node:test'
import assert from 'node:assert'
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { NeocitiesAPIClient } from './index.js'
import { statsHandler } from './lib/stats-handler.js'
import desm from 'desm'
const { readFileSync } = require('fs')
const { resolve } = require('path')
const NeocitiesAPIClient = require('.')
const statsHanlder = require('./lib/stats-handler')
const __dirname = desm(import.meta.url)

@@ -15,4 +18,4 @@ let token = process.env.NEOCITIES_API_TOKEN

token = config.token
tap.test('token loaded', async t => {
t.ok(token)
test('token loaded', async t => {
assert.ok(token)
})

@@ -27,13 +30,13 @@ } catch (e) {

tap.test('basic client api', async t => {
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')
assert.ok(client.info, 'info method available')
assert.ok(client.list, 'list method available')
assert.ok(client.get, 'get method available')
assert.ok(client.post, 'post method available')
})
if (!fakeToken) {
tap.test('can get info about site', async t => {
test('can get info about site', async t => {
const client = new NeocitiesAPIClient(token)

@@ -43,6 +46,6 @@

// console.log(info)
t.equal(info.result, 'success', 'info requesst successfull')
assert.equal(info.result, 'success', 'info requesst successfull')
const list = await client.list()
// console.log(list)
t.equal(list.result, 'success', 'list result successfull')
assert.equal(list.result, 'success', 'list result successfull')
})

@@ -66,3 +69,3 @@

tap.test('can upload and delete files', async t => {
test('can upload and delete files', async t => {
const client = new NeocitiesAPIClient(token)

@@ -81,4 +84,4 @@

// console.log(uploadResults)
t.equal(uploadResults[0].result, 'success', 'list result successfull')
// console.log(uploadResults[0])
assert.equal(uploadResults[0].statusCode, 200, 'list result successfull')

@@ -90,6 +93,6 @@ const deleteResults = await client.delete([

// console.log(deleteResults)
t.equal(deleteResults.result, 'success', 'list result successfull')
assert.equal(deleteResults.statusCode, 200, 'list result successfull')
})
tap.test('can deploy folders', async t => {
test('can deploy folders', async t => {
const client = new NeocitiesAPIClient(token)

@@ -100,3 +103,3 @@

{
statsCb: statsHanlder(),
statsCb: statsHandler(),
cleanup: false

@@ -106,3 +109,3 @@ }

t.ok(deployStats)
assert.ok(deployStats)

@@ -114,3 +117,3 @@ // console.dir(deployStats, { depth: 99, colors: true })

{
statsCb: statsHanlder(),
statsCb: statsHandler(),
cleanup: false

@@ -120,3 +123,3 @@ }

t.ok(redeployStats)
assert.ok(redeployStats)

@@ -128,3 +131,3 @@ // console.dir(redeployStats, { depth: 99, colors: true })

{
statsCb: statsHanlder(),
statsCb: statsHandler(),
cleanup: true

@@ -134,3 +137,3 @@ }

t.ok(cleanupStats)
assert.ok(cleanupStats)

@@ -137,0 +140,0 @@ // console.dir(cleanupStats, { depth: 99, colors: true })

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc