{"id":15497539,"url":"https://github.com/bcomnes/async-neocities","last_synced_at":"2025-04-22T22:20:12.726Z","repository":{"id":41451595,"uuid":"239421217","full_name":"bcomnes/async-neocities","owner":"bcomnes","description":"An api client for Neocities with an async API and an efficient deploy algorithm and progress.","archived":false,"fork":false,"pushed_at":"2024-04-29T15:02:29.000Z","size":891,"stargazers_count":6,"open_issues_count":5,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-29T16:27:43.253Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://npmjs.com/async-neocities","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bcomnes.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["bcomnes"],"custom":["https://bret.io","https://neocities.org/donate"]}},"created_at":"2020-02-10T03:43:00.000Z","updated_at":"2024-04-29T16:27:45.228Z","dependencies_parsed_at":"2024-01-16T00:12:52.618Z","dependency_job_id":"3a16aed7-2711-4bd6-b970-b4fbf836a335","html_url":"https://github.com/bcomnes/async-neocities","commit_stats":{"total_commits":150,"total_committers":5,"mean_commits":30.0,"dds":"0.42000000000000004","last_synced_commit":"f6d41c0a21b0cfccab5ae3cf6086e01759321b52"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bcomnes%2Fasync-neocities","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bcomnes%2Fasync-neocities/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bcomnes%2Fasync-neocities/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bcomnes%2Fasync-neocities/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bcomnes","download_url":"https://codeload.github.com/bcomnes/async-neocities/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250331995,"owners_count":21413136,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-02T08:39:38.234Z","updated_at":"2025-04-22T22:20:12.702Z","avatar_url":"https://github.com/bcomnes.png","language":"JavaScript","funding_links":["https://github.com/sponsors/bcomnes","https://bret.io","https://neocities.org/donate"],"categories":[],"sub_categories":[],"readme":"# async-neocities\n[![Actions Status](https://github.com/bcomnes/async-neocities/workflows/tests/badge.svg)](https://github.com/bcomnes/async-neocities/actions)\n[![Types in JS](https://img.shields.io/badge/types_in_js-yes-brightgreen)](https://github.com/voxpelli/types-in-js)\n\nAn api client for [neocities][nc] with an async/promise API and an efficient content-aware diff algorithm.\nNow including full type support!\n\n\u003ccenter\u003e\u003cimg src=\"logo.jpg\"\u003e\u003c/center\u003e\n\nAlso available as a Github Action: [deploy-to-neocities](https://github.com/marketplace/actions/deploy-to-neocities)\n\n```console\nnpm install async-neocities\n```\n\n## Usage\n\n``` js\nimport path from 'node:path'\nimport { NeocitiesAPIClient } from 'async-neocities'\n\nconst apiKeyResponse = await NeocitiesAPIClient.getKey({\n  siteName: 'siteName',\n  ownerPassword: 'password'\n})\n\nconst client = new NeocitiesAPIClient(apiKeyResponse.api_key)\n\nconsole.log(await client.list()) // site files\nconsole.log(await client.info()) // site info\n\nawait client.deploy({\n  directory: path.join(import.meta.dirname, './site-contents'),\n  cleanup: true, // Delete orphaned files\n  includeUnsupportedFiles: true // Upload unsupported files. Paid neocities feature\n})\n```\n\n## Bin\n\n`async-neocities` ships a bin that lets you deploy to neocities locally or in CI.\n\nIt's interactive and will help you set up your config and keys.\n\nThe site name is configured to a file in cwd called `deploy-to-neocities.json` that looks like:\n\n```json\n{\"siteName\":\"the-name-of-the-site\"}\n```\n\n```console\nUsage: async-neocities [options]\n\n    Example: async-neocities --src public\n\n    --help, -h            print help text\n    --src, -s             The directory to deploy to neocities (default: \"public\")\n    --cleanup, -c         Destructively clean up orphaned files on neocities\n    --protect, -p         String to minimatch files which will never be cleaned up\n    --supporter, -S       Neocities Supporter mode: bypass file type restrictions\n    --status              Print auth status of current working directory\n    --print-key           Print api-key status of current working directory\n    --clear-key           Remove the currently associated API key\n    --force-auth          Force re-authorization of current working directory\n    --preview, -P         Preview the files that will be uploaded\n\nasync-neocities (v3.0.7)\n```\n\nYou can set the flags with ENV vars\n\n- `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.\n- `ASYNC_NEOCITIES_SITE_NAME`: the name of the site to deploy to.\n\n## API\n\n### `import { NeocitiesAPIClient } from 'async-neocities'`\n\nImport the Neocities API client.\n\n### `{ result, api_key } = await NeocitiesAPIClient.getKey({ siteName, ownerPassword })`\n\nStatic class method that will get an API Key from a `siteName` and `ownerPassword`.\n\n### `client = new NeocitiesAPIClient(apiKey)`\n\nCreate a new API client for a given API key.\n\nAll API methods return data from a successful request.\nAny bad responses will throw an error.\nAnything else that goes wrong will throw an error.\nIf you call any methods from a client instance, be sure to handle the errors!\n\n### `uploadResult = await client.upload(files)`\n\nPass 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.\n\nReturns a `UploadResults` result:\n\n```js\n{\n   errors: [],\n   results: [\n     {\n       type: 'uploadResult',\n       body: {\n          result: 'success',\n          message: 'files have been uploaded'\n        },\n       },\n       files: [\n         name: 'index.html',\n         path: '/path/to/index.html'\n        ]\n     }\n   ]\n}\n```\n\n### `deleteResults = await client.delete(files)`\n\nPass 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.\n\nA successful `deleteResult`:\n\n```js\n{\n   type: \"deleteResult\",\n   body: {\n     result: 'success',\n     message: 'file(s) have been deleted'\n   },\n    files: [\n      '/path/to/index.html'\n    ]\n}\n```\n\n### `siteFileList = await client.list([path])`\n\nGet a list of files for your site.  The optional `path` argument can be used to list files only at a given path of the website.\n\nExample `siteFileList`:\n\n```json\n{\n  \"result\": \"success\",\n  \"files\": [\n    {\n      \"path\": \"index.html\",\n      \"is_directory\": false,\n      \"size\": 1023,\n      \"updated_at\": \"Sat, 13 Feb 2016 03:04:00 -0000\",\n      \"sha1_hash\": \"c8aac06f343c962a24a7eb111aad739ff48b7fb1\"\n    },\n    {\n      \"path\": \"not_found.html\",\n      \"is_directory\": false,\n      \"size\": 271,\n      \"updated_at\": \"Sat, 13 Feb 2016 03:04:00 -0000\",\n      \"sha1_hash\": \"cfdf0bda2557c322be78302da23c32fec72ffc0b\"\n    },\n    {\n      \"path\": \"images\",\n      \"is_directory\": true,\n      \"updated_at\": \"Sat, 13 Feb 2016 03:04:00 -0000\"\n    },\n    {\n      \"path\": \"images/cat.png\",\n      \"is_directory\": false,\n      \"size\": 16793,\n      \"updated_at\": \"Sat, 13 Feb 2016 03:04:00 -0000\",\n      \"sha1_hash\": \"41fe08fc0dd44e79f799d03ece903e62be25dc7d\"\n    }\n  ]\n}\n```\n\nWith the `path` argument:\n\n```json\n{\n  \"result\": \"success\",\n  \"files\": [\n    {\n      \"path\": \"images/cat.png\",\n      \"is_directory\": false,\n      \"size\": 16793,\n      \"updated_at\": \"Sat, 13 Feb 2016 03:04:00 -0000\",\n      \"sha1_hash\": \"41fe08fc0dd44e79f799d03ece903e62be25dc7d\"\n    }\n  ]\n}\n```\n\n### `siteInfo = await client.info([siteName])`\n\nGet info about your or other sites.\nThe optional `siteName` argument can be used to request unauthenticated info about any neocities website.\nWhen `siteName` is omitted, the authenticated site's info is returned.\n\nExample `siteInfo`:\n\n```json\n{\n  \"result\": \"success\",\n  \"info\": {\n    \"sitename\": \"youpi\",\n    \"hits\": 5072,\n    \"created_at\": \"Sat, 29 Jun 2013 10:11:38 +0000\",\n    \"last_updated\": \"Tue, 23 Jul 2013 20:04:03 +0000\",\n    \"domain\": null,\n    \"tags\": []\n  }\n}\n```\n\n### `deployResult = await client.deploy({ directory, [cleanup], [includeUnsupportedFiles], [protectedFileFilter] })`\n\nEfficiently deploy a `directory` path to Neocities, only uploading missing and changed files.  Files are determined to be different by size, and sha1 hash, if the size is the same.\n\nOther options include:\n\n```js\n{\n  cleanup: false, // delete orphaned files on neocities that are not in the `directory`\n  protectedFileFilter: path =\u003e false, // a function that is passed neocities file paths.  When it returns true, that path will never be cleaned up when cleanup is set to true.\n  includeUnsupportedFiles: false // include files that are not supported by neocities in the upload. This is a paid neocities supporter feature.\n  uploadSort: (a: FileUpload, b: FileUpload) =\u003e number // A custom sort function for the files to upload.\n}\n```\n\n`deployResult` is a complex type that includes a results summary, error summary and diff summary. Please check the types on this one.\n\n### `diff = await client.previewDeploy({ directory, [includeUnsupportedFiles], [protectedFileFilter] })`\n\nPreview a deploy from a `directory` path to Neocities. Returns the diff summary without modifying anything.\n\nOther options include:\n\n`diff` is a complex type that includes a diff summary. Please check the types on this one.\n\n## See also\n\n- [Neocities API docs](https://neocities.org/api)\n- [Official Node.js API client](https://github.com/neocities/neocities-node)\n- [bcomnes/deploy-to-neocities](https://github.com/bcomnes/deploy-to-neocities) This module as an action.\n\n## License\n\nMIT\n\n[querystring]: https://nodejs.org/api/querystring.html\n[nf]: https://ghub.io/node-fetch\n[fd]: https://ghub.io/form-data\n[nc]: https://neocities.org\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbcomnes%2Fasync-neocities","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbcomnes%2Fasync-neocities","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbcomnes%2Fasync-neocities/lists"}