{"id":41136376,"url":"https://github.com/kaiwood/pnut-butter","last_synced_at":"2026-01-22T18:38:52.540Z","repository":{"id":17020559,"uuid":"80996016","full_name":"kaiwood/pnut-butter","owner":"kaiwood","description":"pnut-butter.js – A modern, promise based wrapper library for the pnut.io API","archived":false,"fork":false,"pushed_at":"2022-07-06T18:47:54.000Z","size":1325,"stargazers_count":5,"open_issues_count":6,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-09-25T17:54:00.794Z","etag":null,"topics":["api-wrapper","es6","hacktoberfest","javascript-library","library","pnut"],"latest_commit_sha":null,"homepage":"https://kaiwood.github.io/pnut-butter/","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/kaiwood.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-02-05T13:51:43.000Z","updated_at":"2020-11-05T06:06:44.000Z","dependencies_parsed_at":"2022-09-21T02:01:23.433Z","dependency_job_id":null,"html_url":"https://github.com/kaiwood/pnut-butter","commit_stats":null,"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"purl":"pkg:github/kaiwood/pnut-butter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaiwood%2Fpnut-butter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaiwood%2Fpnut-butter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaiwood%2Fpnut-butter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaiwood%2Fpnut-butter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kaiwood","download_url":"https://codeload.github.com/kaiwood/pnut-butter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kaiwood%2Fpnut-butter/sbom","scorecard":{"id":547852,"data":{"date":"2025-08-11","repo":{"name":"github.com/kaiwood/pnut-butter","commit":"9ef32ca976b9b2076c1e05e8891738953cc2ffc5"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 2/28 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 6 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"30 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-cwfw-4gq5-mrqx","Warn: Project is vulnerable to: GHSA-g95f-p29q-9xw4","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-4q6p-r6v2-jvc5","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-6vfc-qv3f-vr6c","Warn: Project is vulnerable to: GHSA-5v2h-r2cx-5xgj","Warn: Project is vulnerable to: GHSA-rrrm-qjm4-v8hf","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-8hfj-j24r-96c4","Warn: Project is vulnerable to: GHSA-wc69-rhjr-hc9g","Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g","Warn: Project is vulnerable to: GHSA-g6ww-v8xp-vmwg","Warn: Project is vulnerable to: GHSA-566m-qj78-rww5","Warn: Project is vulnerable to: GHSA-7fh5-64p2-3v2j","Warn: Project is vulnerable to: GHSA-rjqq-98f6-6j3r","Warn: Project is vulnerable to: GHSA-mjxr-4v3x-q3m4","Warn: Project is vulnerable to: GHSA-cgfm-xwp7-2cvr","Warn: Project is vulnerable to: GHSA-rm97-x556-q36h","Warn: Project is vulnerable to: GHSA-mxhp-79qh-mcx6","Warn: Project is vulnerable to: GHSA-cf4h-3jhx-xvhq"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-20T09:59:27.656Z","repository_id":17020559,"created_at":"2025-08-20T09:59:27.657Z","updated_at":"2025-08-20T09:59:27.657Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28668197,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-22T17:07:18.858Z","status":"ssl_error","status_checked_at":"2026-01-22T17:05:02.040Z","response_time":144,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["api-wrapper","es6","hacktoberfest","javascript-library","library","pnut"],"created_at":"2026-01-22T18:38:52.467Z","updated_at":"2026-01-22T18:38:52.532Z","avatar_url":"https://github.com/kaiwood.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pnut-butter.js\n\nA modern, promise based wrapper library for the [pnut.io](https://pnut.io) API.\n\nIt is currently developed and tested on Node 8 LTS, but should work with basically any current browser supporting ES6 as well (feel free to open an issue if not), especially if you throw it in your typical Webpack/Babel/whatever toolchain.\n\nHowever, we are currently in the process of moving the whole library to TypeScript and try to modernize its core. Stay tuned for a bigger revamp in the short future.\n\n## Installation\n\n```bash\nnpm install pnut-butter\n```\n\n## Usage\n\nEverything related to data fetching returns a Promise, which you can either use directly, with a supporting library like [co](https://www.npmjs.com/package/co) or the upcoming async/await standard.\n\nFor example, to fetch the global timeline:\n\n```javascript\nconst pnut = require(\"pnut-butter\");\n\n(async () =\u003e {\n  const { meta, data } = await pnut.global();\n})();\n```\n\nFetch a post by its ID:\n\n```javascript\nconst pnut = require(\"pnut-butter\");\n\n(async () =\u003e {\n  const { meta, data } = await pnut.post(1234);\n})();\n```\n\nMost methods allow any arbiritary, additional URL parameters that can be found in the [official documentation](https://pnut.io/docs/api). For example, you can use something like this:\n\n```javascript\nconst { meta, data } = await pnut.mentions({ beforeId: 1235 });\n```\n\n…to get posts in the mentions category before the specified id. We generate them dynamically and convert the parameters to snake_case automatically for you, so it doesn't matter if you write:\n\n```javascript\nconst { meta, data } = await pnut.global({ sinceId: 4567 });\n```\n\nor\n\n```javascript\nconst { meta, data } = await pnut.global({ since_id: 4567 });\n```\n\nBoth versions work, it's just syntactic sugar and a matter of personal preference.\n\n## Documentation\n\nYou can find the full documentation of all methods [here](https://kaiwood.github.io/pnut-butter/).\n\n## Custom requests\n\nPnut is a moving target, so there are still some methods missing and/or parameters that are not yet implemented. Therefor you can always fall back to a custom request with support for all HTTP verbs.\n\n```javascript\nconst pnut = require(\"pnut-butter\");\n\n(async () =\u003e {\n  const { meta, data } = await pnut.custom(\"/posts/streams/explore/trending\");\n\n  await pnut.custom(\"/posts\", \"POST\", { text: \"Posting with pnut-butter!\" });\n  await pnut.custom(\"/posts/1234\", \"DELETE\");\n})();\n```\n\n## Authentication\n\nFor everything that requires an authenticated user, you will need an access token. You can create one in the setting of your account on pnut.io under the \"Develop\" menu.\n\nYou can set it like this:\n\n```javascript\nconst pnut = require(\"pnut-butter\");\npnut.token = ACCESS_TOKEN;\n\n(async () =\u003e {\n  const { meta, data } = await pnut.mentions(\"me\");\n})();\n```\n\nPlease consult the [pnut docs](https://pnut.io/docs) for further information about how authentication is handled in the network, how to aquire a \"real\" token able to authenticate multiple users and so on.\n\n## Changing profile / cover images\n\nUploading images is currently only supported on the client side. You can give the DOM node for an upload form containing file fields for \"avatar\" or \"cover\" as argument to the corresponding methods `uploadAvatar` / `uploadCover`.\n\nA basic HTML form would look something like this:\n\n```html\n\u003cform id=\"avatar-form\"\u003e\n  \u003cinput type=\"file\" name=\"avatar\"\u003e\n\u003c/form\u003e\n```\n\nDepending on how your application is set up, an upload function looks somewhat like this:\n\n```javascript\nasync function upload(ev) {\n  event.preventDefault();\n\n  const form = document.querySelector(\"#avatar-form\");\n  await pnut.uploadAvatar(form);\n}\n```\n\nBoth, `uploadAvatar` and `uploadCover` will handle server side uploads in a future release.\n\n## App Streams\n\npnut-butter has support for creating, managing and reading app streams (you need a properly \"signed\" pair of Client ID and Client Secret to use this).\n\nFirst, you need to request an app stream access token:\n\n```js\nconst pnut = require(\"pnut-butter\");\n(async () =\u003e {\n  const { meta, data } = await pnut.requestAppAccessToken(\n    YOUR_CLIENT_ID,\n    YOUR_CLIENT_SECRET\n  );\n})();\n```\n\nIf successful, you will get back a proper token in the response. Set it via:\n\n```js\npnut.token = YOUR_ACCESS_TOKEN;\n```\n\nNext step is to setup your app stream with up to 5 (!) options (post, bookmark, follow, mute, block, message, channel, channel_subscription, token, user) and a key name:\n\n```js\n(async () =\u003e {\n  const { meta, data } = await pnut.createStream({\n    objectTypes: [\"post\", \"bookmark\", \"follow\"],\n    key: \"myfancykeyname\"\n  });\n})();\n```\n\nFor reading the stream, we provide a separate module you have to require, that preconfigures a web socket connection for you, where you can simply listen on the \"message\" event to read the stream:\n\n```js\nconst pnut = require(\"pnut-butter\");\nconst AppStreamSocket = require(\"pnut-butter/dist/app_stream_socket\");\n\npnut.token = \"MY_VALID_ACCESS_TOKEN\";\nconst ws = AppStreamSocket(\"myfancykeyname\");\n\nws.on(\"open\", event =\u003e {\n  console.log(\"Opening app stream\");\n});\n\nws.on(\"message\", event =\u003e {\n  console.log(event.data);\n});\n\nws.on(\"close\", event =\u003e {\n  console.log(\"Closing app stream\", event.code, event.reason);\n});\n```\n\nYou can now work on the streaming data from the \"message\" event. Keep in mind that you might want to reconnect to the socket in case it closes on the server side.\n\n## Collaboration / Project status\n\nIssues / Pull Requests are always welcome. If you have any questions, feel free to drop me an email or write a message on pnut.io. There are still a couple of things not implemented yet (creating and updating channels comes to mind), but should be stable and usable already.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaiwood%2Fpnut-butter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkaiwood%2Fpnut-butter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkaiwood%2Fpnut-butter/lists"}