{"id":22539447,"url":"https://github.com/benaubin/b2-js","last_synced_at":"2026-03-14T13:21:35.293Z","repository":{"id":39985699,"uuid":"263734309","full_name":"benaubin/b2-js","owner":"benaubin","description":"Use Backblaze B2's native API from Javascript","archived":false,"fork":false,"pushed_at":"2022-06-25T12:45:13.000Z","size":210,"stargazers_count":21,"open_issues_count":8,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-05T15:15:27.377Z","etag":null,"topics":["backblaze-b2","javascript","nodejs","object-storage","typescript"],"latest_commit_sha":null,"homepage":"https://b2-js.netlify.app/","language":"TypeScript","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/benaubin.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2020-05-13T20:18:50.000Z","updated_at":"2025-01-03T01:20:55.000Z","dependencies_parsed_at":"2022-06-26T02:26:45.585Z","dependency_job_id":null,"html_url":"https://github.com/benaubin/b2-js","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benaubin%2Fb2-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benaubin%2Fb2-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benaubin%2Fb2-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benaubin%2Fb2-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/benaubin","download_url":"https://codeload.github.com/benaubin/b2-js/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248119333,"owners_count":21050753,"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":["backblaze-b2","javascript","nodejs","object-storage","typescript"],"created_at":"2024-12-07T12:07:01.373Z","updated_at":"2026-03-14T13:21:35.226Z","avatar_url":"https://github.com/benaubin.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1\u003e \u003cimg src=\"https://www.backblaze.com/blog/wp-content/uploads/2017/12/backblaze_icon_transparent.png\" alt=\"Backblaze logo\" width=\"32\"\u003e Backblaze B2 JavaScript Client \u003c/h1\u003e\n\n\u003cp\u003e\n  \u003ca href=\"https://www.npmjs.com/package/b2-js\" target=\"_blank\"\u003e\n    \u003cimg alt=\"Version\" src=\"https://img.shields.io/npm/v/b2-js.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/benaubin/b2-js/graphs/commit-activity\" target=\"_blank\"\u003e\n    \u003cimg alt=\"Maintenance\" src=\"https://img.shields.io/badge/Maintained%3F-yes-green.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/benaubin/b2-js/blob/master/LICENSE\" target=\"_blank\"\u003e\n    \u003cimg alt=\"License: MIT\" src=\"https://img.shields.io/github/license/benaubin/b2-js\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://codeclimate.com/github/benaubin/b2-js/maintainability\"\u003e\n    \u003cimg alt=\"Code Climate Maintainability\" src=\"https://api.codeclimate.com/v1/badges/1124a063a4644aae3d3e/maintainability\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://twitter.com/BenAubin_\" target=\"_blank\"\u003e\n    \u003cimg alt=\"Twitter: BenAubin_\" src=\"https://img.shields.io/twitter/follow/BenAubin_.svg?style=social\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\nA powerful library for using Backblaze B2.\n\n✅ Streaming uploads (automatic switching between single and multi-part)\u003cbr/\u003e\n✅ Single-part uploads\u003cbr/\u003e\n✅ Streaming downloads\u003cbr/\u003e\n✅ Graceful error handling (exponential back-off)\u003cbr/\u003e\n✅ Requires ES2018\u003cbr/\u003e\n✅ Used in production at [Mintere](https://mintere.com)\u003cbr/\u003e\n🚫 Browser Not Supported (uses `node-fetch` and `streams`)\n\n### 📜 [Documentation](https://b2-js.netlify.app/)\n\n\n\u003ca href=\"https://mintere.com\"\u003e\n  \u003cimg src=\"https://app.mintere.com/assets/logo-no-space-cae371bbf448f4dcc2596ff65617601dea1da09e35fd5a217039642a93752517.png\" width=\"100\"/\u003e\n\u003c/a\u003e\n\nDeveloped for \u003ca href=\"https://mintere.site\"\u003eMintere Sites\u003c/a\u003e, a platform enabling \nwebsites to be global, easy-to-develop, performant and dynamic.\n\n## Install\n\n```sh\nnpm install b2-js\n```\n\n```\nyarn install b2-js\n```\n\n## Principles\n\n- Backblaze allows uploading files as a single-part or as multiple parts.\n  However, you must know the length of each file in advance, and you cannot\n  use chunked-encoding.\n- Single-part uploads are generally faster for smaller files. Backblaze recommends\n  a part-size.\n- The library should handle the complexity of working with the B2 API, including\n  handling splitting streams into multi-part uploads.\n\n## Key Considerations\n\n- For streams of unknown length, each part must be read into memory (up-to 100MB). \n  You can configure this down to `b2.auth.absoluteMinimumPartSize` using `b2.partSize = BYTES`.\n- It's generally faster to use single part upload for smaller files. The library will make\n  the decision for you based on `b2.partSize`.\n\n## Usage\n\n```js\nimport B2 from \"./src/b2\";\n\nconst b2 = await B2.authorize({ applicationKeyId: \"KEY_ID\", applicationKey: \"SECRET_KEY\"});\nconst bucket = b2.bucket(\"bucket-name\");\n```\n\n### Uploading\n\n#### Buffers\n\nWhen uploading Buffers, the library automatically decides whether to conduct a single or multi-part\nupload based on the Buffer's `byteLength`.\n\n```js\n// a single-part upload will be attempted.\nbucket.upload(\"test.txt\", Buffer.from(\"foobar\"));\n\n// a multi-part upload will automatically be attempted for larger files\nbucket.upload(\"test.txt\", Buffer.from(\"*\".repeat(101*1000*1000 /* 101MB */)));\n```\n\n#### Streams\n\nWhen the `contentLength` is known, you may conduct a single part upload without\nloading the stream into memory.\n\n```js\nconst fileStream = require(\"fs\").createReadStream(\"./README.md\")\n// In order to conduct a single-part upload without loading a stream\n// into memory, the content length of the stream in bytes must be known.\nbucket.uploadSinglePart(\"readme\", fileStream, {contentLength: 2174}) \n```\n\nWhen the `contentLength` is unknown, or a stream is too large for a single-part upload,\neach part of the stream must be loaded into memory in order to size the stream,\ncompute a digest of the content and properly split the stream into parts. \n\nIf the stream less than or equal to `b2.partSize` bytes, a single-part upload will\nbe attempted. Otherwise, a multi-part upload will be attempted by loading up-to \n`b2.partSize` bytes of the stream into memory at a time.\n\n```js\nconst file = bucket.file(\"example\");\nconst stream = file.createWriteStream();\n\nstream.on(\"error\", (err) =\u003e {\n  // handle the error \n  // note that retries are automatically attempted before errors are \n  // thrown for most potentially recoverable errors, as per the B2 docs.\n})\n\nstream.on(\"finish\", (err) =\u003e {\n  // upload done, the file instance has been updated to reflect this\n})\n\nres.body.pipe(stream);\n```\n\n\n### Downloading\n```js\nconst file = bucket.file(\"text.txt\");\nfile.createReadStream();\n```\n\n### Stat\n\n#### By id\n\n```js\nconst file = bucket.file({fileId: \"....\"});\nconst fileData = await file.stat(); //=\u003e see https://www.backblaze.com/b2/docs/b2_get_file_info.html\n```\n\n#### By name\n\nNote that statting a file by name involves a Class C transaction\nas it involves listing files with a call to `b2_list_file_names`.\n\n```js\nconst file = bucket.file(\"text.txt\");\ntry {\n  const fileData = await file.stat(); //=\u003e see https://www.backblaze.com/b2/docs/b2_get_file_info.html\n} catch (e) {\n  if (e instanceof BackblazeLibraryError.FileNotFound) {\n    // handle file not found.\n  } else {\n    throw e;  // re-throw the error unchanged\n  }\n}\n```\n\n## Author\n\n👤 **Ben Aubin (benaubin.com)**\n\n* Website: benaubin.com\n* Twitter: [@BenAubin\\_](https://twitter.com/BenAubin\\_)\n* Github: [@benaubin](https://github.com/benaubin)\n* LinkedIn: [@benaubin](https://linkedin.com/in/benaubin)\n\n## 🤝 Contributing\n\nContributions, issues and feature requests are welcome!\u003cbr /\u003eFeel free to check [issues page](https://github.com/benaubin/b2-js/issues). You can also take a look at the [contributing guide](https://github.com/benaubin/b2-js/blob/master/CONTRIBUTING.md).\n\n## Users\n\n- [Mintere](https://mintere.com) uses `b2-js` to serve static assets for its CDN and to deploy files on servers around the world.\n\nUsing `b2-js` in production? Submit a PR to add yourself to this list!\n\n## Show your support\n\nGive a ⭐️ if this project helped you!\n\n## 📝 License\n\nCopyright © 2020 [Ben Aubin (benaubin.com)](https://github.com/benaubin).\u003cbr /\u003e\nThis project is [MIT](https://github.com/benaubin/b2-js/blob/master/LICENSE) licensed.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbenaubin%2Fb2-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbenaubin%2Fb2-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbenaubin%2Fb2-js/lists"}