{"id":17981131,"url":"https://github.com/bradenmacdonald/s3-lite-client","last_synced_at":"2025-12-11T21:13:56.724Z","repository":{"id":62422338,"uuid":"421913518","full_name":"bradenmacdonald/s3-lite-client","owner":"bradenmacdonald","description":"A lightweight but powerful JavaScript S3 client","archived":false,"fork":false,"pushed_at":"2025-03-13T14:59:23.000Z","size":80,"stargazers_count":76,"open_issues_count":1,"forks_count":14,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-30T19:09:23.260Z","etag":null,"topics":["bun","deno","nodejs","s3"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bradenmacdonald.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-27T17:31:08.000Z","updated_at":"2025-03-13T14:59:28.000Z","dependencies_parsed_at":"2024-02-08T23:40:14.017Z","dependency_job_id":"4a9a836d-9cb4-4b22-a073-83828e360447","html_url":"https://github.com/bradenmacdonald/s3-lite-client","commit_stats":null,"previous_names":["bradenmacdonald/s3-lite-client","bradenmacdonald/deno-s3-lite-client"],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bradenmacdonald%2Fs3-lite-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bradenmacdonald%2Fs3-lite-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bradenmacdonald%2Fs3-lite-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bradenmacdonald%2Fs3-lite-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bradenmacdonald","download_url":"https://codeload.github.com/bradenmacdonald/s3-lite-client/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247550690,"owners_count":20956987,"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":["bun","deno","nodejs","s3"],"created_at":"2024-10-29T18:07:48.255Z","updated_at":"2025-12-11T21:13:56.697Z","avatar_url":"https://github.com/bradenmacdonald.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# s3-lite-client\n\nThis is a lightweight S3 (object storage) client for JavaScript runtimes (Deno, Node 19+, Bun, browsers, etc.). It is\ndesigned to offer all the key features you may need, without bloat. It should work with any runtime that supports the\n`fetch` API, web streams API, and ES modules (ESM).\n\nKey features:\n\n- Has no dependencies and minifies to about 21kB (\u003c 8 kB gzipped).\n  - For comparison, the official `@aws-sdk/client-s3` has\n    [56 dependencies and weighs 399 kB (94 kB gzipped)](https://bundlephobia.com/package/@aws-sdk/client-s3@3.758.0) at\n    the time of writing.\n- Implemented in TypeScript and fully typed.\n- 100% MIT licensed, derived from the excellent [MinIO JavaScript Client](https://github.com/minio/minio-js).\n\nSupported functionality:\n\n- Authenticated or unauthenticated requests\n- List objects: `for await (const object of client.listObjects(options)) { ... }`\n  - Handles pagination transparently\n  - Supports filtering using a prefix\n  - Supports [grouping using a delimiter](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-prefixes.html)\n    (use `client.listObjectsGrouped(...)`)\n- Check if an object exists: `client.exists(\"key\")`\n- Get metadata about an object: `client.statObject(\"key\")`\n  - Can include custom headers in the request:\n    `client.statObject(\"key\", { headers: { 'x-amz-checksum-mode': 'ENABLED' } })`\n- Download an object: `client.getObject(\"key\", options)`\n  - This just returns a standard HTTP `Response` object, so for large files, you can opt to consume the data as a stream\n    (use the `.body` property).\n- Download a partial object: `client.getPartialObject(\"key\", options)`\n  - Like `getObject`, this also supports streaming the response if you want to.\n- Upload an object: `client.putObject(\"key\", streamOrData, options)`\n  - Can upload from a `string`, `Uint8Array`, or `ReadableStream`\n  - Can split large uploads into multiple parts and uploads parts in parallel.\n  - Can set custom headers, ACLs, and other metadata on the new object (example below).\n- Copy an object: `client.copyObject({ sourceKey: \"source\", options }, \"dest\", options)`\n  - Can copy between different buckets.\n- Delete an object: `client.deleteObject(\"key\")`\n- Create pre-signed URLs: `client.presignedGetObject(\"key\", options)` or\n  `client.getPresignedUrl(method, \"key\", options)`\n- Create pre-signed POST policy: `client.presignedPostObject(\"key\", options)` for direct browser uploads\n- Check if a bucket exists: `client.bucketExists(\"bucketName\")`\n- Create a new bucket: `client.makeBucket(\"bucketName\")`\n- Remove a bucket: `client.removeBucket(\"bucketName\")`\n\n## Installation\n\n[![JSR Version](https://jsr.io/badges/@bradenmacdonald/s3-lite-client)](https://jsr.io/@bradenmacdonald/s3-lite-client)\n[![JSR Score](https://jsr.io/badges/@bradenmacdonald/s3-lite-client/score)](https://jsr.io/@bradenmacdonald/s3-lite-client/score)\n\n- Deno: `deno add @bradenmacdonald/s3-lite-client`\n- Deno (no install): `import { S3Client } from \"jsr:@bradenmacdonald/s3-lite-client@0.9.4\";`\n- NPM: `npx jsr add @bradenmacdonald/s3-lite-client`\n- Yarn: `yarn add jsr:@bradenmacdonald/s3-lite-client`\n- pnpm: `pnpm add jsr:@bradenmacdonald/s3-lite-client`\n- Bun: `bunx jsr add @bradenmacdonald/s3-lite-client`\n- Browser:\n  ```html\n  \u003cscript type=\"module\"\u003e\n    import { S3Client } from \"https://esm.sh/jsr/@bradenmacdonald/s3-lite-client@0.9.4\";\n    // Or:\n    const { S3Client } = await import(\"https://esm.sh/jsr/@bradenmacdonald/s3-lite-client@0.9.4\");\n  \u003c/script\u003e\n  ```\n\n## Usage Examples (Quickstart)\n\nList data files from a public data set on Amazon S3:\n\n```typescript\nimport { S3Client } from \"@bradenmacdonald/s3-lite-client\";\n\nconst s3client = new S3Client({\n  endPoint: \"https://s3.us-east-1.amazonaws.com\",\n  region: \"us-east-1\",\n  bucket: \"openalex\",\n});\n\n// Log data about each object found under the 'data/concepts/' prefix:\nfor await (const obj of s3client.listObjects({ prefix: \"data/concepts/\" })) {\n  console.log(obj);\n}\n// {\n//   type: \"Object\",\n//   key: \"data/concepts/updated_date=2024-01-25/part_000.gz\",\n//   etag: \"2c9b2843c8d2e9057656e1af1c2a92ad\",\n//   size: 44105,\n//   lastModified: 2024-01-25T22:57:43.000Z\n// },\n// ...\n\n// Or, to get all the keys (paths) as an array:\nconst keys = await Array.fromAsync(s3client.listObjects(), (entry) =\u003e entry.key);\n// keys = [\n//  \"data/authors/manifest\",\n//  \"data/authors/updated_date=2023-06-08/part_000.gz\",\n//  ...\n// ]\n```\n\nUploading and downloading a file using a local MinIO server:\n\n```typescript\nimport { S3Client } from \"@bradenmacdonald/s3-lite-client\";\n\n// Connecting to a local MinIO server:\nconst s3client = new S3Client({\n  endPoint: \"http://localhost:9000\",\n  region: \"dev-region\",\n  bucket: \"dev-bucket\",\n  accessKey: \"AKIA_DEV\",\n  secretKey: \"secretkey\",\n});\n\n// Upload a file:\nawait s3client.putObject(\"test.txt\", \"This is the contents of the file.\");\n\n// Now download it\nconst result = await s3client.getObject(\"test.txt\");\n// and stream the results to a local file:\nconst localOutFile = await Deno.open(\"test-out.txt\", { write: true, createNew: true });\nawait result.body!.pipeTo(localOutFile.writable);\n// or instead of streaming, you can consume the whole file into memory by awaiting\n// result.text(), result.blob(), result.arrayBuffer(), or result.json()\n```\n\nCreating a bucket on the S3 service of a local supabase development server:\n\n```ts\nconst client = new S3Client({\n  endPoint: \"http://127.0.0.1:54321/storage/v1/s3\",\n  region: \"local\",\n  accessKey: \"paste from output of supabase start\",\n  secretKey: \"paste from output of supabase start\",\n});\nawait client.makeBucket(\"my-bucket\");\n```\n\nSet ACLs, Content-Type, custom metadata, etc. during upload:\n\n```ts\nawait s3client.putObject(\"key\", streamOrData, {\n  metadata: {\n    \"x-amz-acl\": \"public-read\",\n    \"x-amz-meta-custom\": \"value\",\n  },\n});\n```\n\nCreate a presigned POST policy for direct uploads from a browser:\n\n```ts\n// Create a presigned POST policy\nconst { url, fields } = await s3client.presignedPostObject(\"my-file.txt\", {\n  expirySeconds: 3600, // URL expires in 1 hour\n  fields: {\n    \"Content-Type\": \"text/plain\",\n  },\n});\n\n// In the browser, use the policy for direct uploads:\nconst formData = new FormData();\n// Add all required fields from the presigned POST\nObject.entries(fields).forEach(([key, value]) =\u003e {\n  formData.append(key, value);\n});\n// Add the file content\nformData.append(\"file\", fileInput.files[0]);\n\n// Upload the object using the presigned POST\nconst response = await fetch(url, {\n  method: \"POST\",\n  body: formData,\n});\n\nif (response.ok) {\n  console.log(\"File uploaded successfully!\");\n}\n```\n\nFor more examples, check out the tests in [`integration.ts`](./integration.ts)\n\n## Developer notes\n\nTo run the tests, please use:\n\n```sh\ndeno lint \u0026\u0026 deno test\n```\n\nTo format the code, use:\n\n```sh\ndeno fmt\n```\n\nTo run the integration tests, first start MinIO with this command:\n\n```sh\ndocker run --rm -e MINIO_ROOT_USER=AKIA_DEV -e MINIO_ROOT_PASSWORD=secretkey -e MINIO_REGION_NAME=dev-region -p 9000:9000 -p 9001:9001 --entrypoint /bin/sh minio/minio:RELEASE.2025-02-28T09-55-16Z -c 'mkdir -p /data/dev-bucket \u0026\u0026 minio server --console-address \":9001\" /data'\n```\n\nThen while MinIO is running, run\n\n```sh\ndeno test --allow-net integration.ts\n```\n\n(If you encounter issues and need to debug what MinIO is seeing, run these two commands:)\n\n```sh\nmc alias set localdebug http://localhost:9000 AKIA_DEV secretkey\nmc admin trace --verbose --all localdebug\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbradenmacdonald%2Fs3-lite-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbradenmacdonald%2Fs3-lite-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbradenmacdonald%2Fs3-lite-client/lists"}