{"_id":"@airnauts/airside-storage-s3","_rev":"3-ca82c6d04379dded6ee16c8ea4865e88","name":"@airnauts/airside-storage-s3","dist-tags":{"latest":"0.10.1"},"versions":{"0.9.1":{"name":"@airnauts/airside-storage-s3","version":"0.9.1","keywords":["comments","commenting","annotations","feedback","airnauts","storage","s3","aws","cloudflare","r2"],"author":{"name":"Airnauts"},"license":"MIT","_id":"@airnauts/airside-storage-s3@0.9.1","maintainers":[{"name":"jkrzemie","email":"hello@airnauts.com"},{"name":"mateuszpaulski","email":"mateusz@airnauts.com"}],"homepage":"https://github.com/Airnauts/airside#readme","bugs":{"url":"https://github.com/Airnauts/airside/issues"},"dist":{"shasum":"91885b4e028eb448f4086212db92e3970aefb041","tarball":"https://registry.npmjs.org/@airnauts/airside-storage-s3/-/airside-storage-s3-0.9.1.tgz","fileCount":7,"integrity":"sha512-uCDaNftThMomMGsnLnPDcJrGF07DHNZtilwrGJjKudeD44W9ZaRYkuIEjyZmPA4Rje6GBJ1ms5aNVD0Owl10Qg==","signatures":[{"sig":"MEUCIQCOXIyGkR3a0P/BchskMoQO6UpaQdtzrU58yHxUSi0mYwIgNNH3uFb5s1fZrY6AZU9BGgASJcnrXN/aRoVvt2INQng=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":19747},"type":"module","_from":"file:airnauts-airside-storage-s3-0.9.1.tgz","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"test":"vitest run","build":"tsup && tsc --build --force","typecheck":"tsc --build"},"_npmUser":{"name":"mateuszpaulski","email":"mateusz@airnauts.com"},"_resolved":"/tmp/dc5e3daf094242847bf4d4416bcaa28f/airnauts-airside-storage-s3-0.9.1.tgz","_integrity":"sha512-uCDaNftThMomMGsnLnPDcJrGF07DHNZtilwrGJjKudeD44W9ZaRYkuIEjyZmPA4Rje6GBJ1ms5aNVD0Owl10Qg==","repository":{"url":"git+https://github.com/Airnauts/airside.git","type":"git","directory":"packages/storage-s3"},"_npmVersion":"10.9.8","description":"Amazon S3 / Cloudflare R2 attachment-storage adapter for the Airnauts commenting tool server.","directories":{},"_nodeVersion":"22.23.0","dependencies":{"@aws-sdk/client-s3":"^3.700.0","@airnauts/airside-core":"^0.9.1","@airnauts/airside-server":"^0.9.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@airnauts/airside-test-support":"0.0.0"},"_npmOperationalInternal":{"tmp":"tmp/airside-storage-s3_0.9.1_1782730394281_0.363513277089911","host":"s3://npm-registry-packages-npm-production"}},"0.10.0":{"name":"@airnauts/airside-storage-s3","version":"0.10.0","keywords":["comments","commenting","annotations","feedback","airnauts","storage","s3","aws","cloudflare","r2"],"author":{"name":"Airnauts"},"license":"MIT","_id":"@airnauts/airside-storage-s3@0.10.0","maintainers":[{"name":"jkrzemie","email":"hello@airnauts.com"},{"name":"mateuszpaulski","email":"mateusz@airnauts.com"}],"homepage":"https://github.com/Airnauts/airside#readme","bugs":{"url":"https://github.com/Airnauts/airside/issues"},"dist":{"shasum":"e6a2f557b2ccab1ae7b4b45f63cca3b6da0c5184","tarball":"https://registry.npmjs.org/@airnauts/airside-storage-s3/-/airside-storage-s3-0.10.0.tgz","fileCount":7,"integrity":"sha512-SC+R3TVqluQzJTQT1FKbE6kPQ5DzBVApw43kwjkJ58J1AT5h+BmjbTZNHBiSOs9qHbSw9GwPhxx8JFlvxL1blA==","signatures":[{"sig":"MEQCIH+aIw8M3JRLKBy8oeDeA6tA3JJb2TyNFSJxLWsnWfVmAiBQ6FzqTwaK+47YhKQ2tkf+sor6/qDSMSBNjLAHJnaarA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":19750},"type":"module","_from":"file:airnauts-airside-storage-s3-0.10.0.tgz","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"test":"vitest run","build":"tsup && tsc --build --force","typecheck":"tsc --build"},"_npmUser":{"name":"mateuszpaulski","email":"mateusz@airnauts.com"},"_resolved":"/tmp/072a981df54f77962636e240d0d27b1b/airnauts-airside-storage-s3-0.10.0.tgz","_integrity":"sha512-SC+R3TVqluQzJTQT1FKbE6kPQ5DzBVApw43kwjkJ58J1AT5h+BmjbTZNHBiSOs9qHbSw9GwPhxx8JFlvxL1blA==","repository":{"url":"git+https://github.com/Airnauts/airside.git","type":"git","directory":"packages/storage-s3"},"_npmVersion":"10.9.8","description":"Amazon S3 / Cloudflare R2 attachment-storage adapter for the Airnauts commenting tool server.","directories":{},"_nodeVersion":"22.23.0","dependencies":{"@aws-sdk/client-s3":"^3.700.0","@airnauts/airside-core":"^0.10.0","@airnauts/airside-server":"^0.10.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@airnauts/airside-test-support":"0.0.0"},"_npmOperationalInternal":{"tmp":"tmp/airside-storage-s3_0.10.0_1782730558163_0.3951160131812912","host":"s3://npm-registry-packages-npm-production"}},"0.10.1":{"name":"@airnauts/airside-storage-s3","version":"0.10.1","description":"Amazon S3 / Cloudflare R2 attachment-storage adapter for the Airnauts commenting tool server.","keywords":["comments","commenting","annotations","feedback","airnauts","storage","s3","aws","cloudflare","r2"],"license":"MIT","author":{"name":"Airnauts"},"homepage":"https://github.com/Airnauts/airside#readme","repository":{"type":"git","url":"git+https://github.com/Airnauts/airside.git","directory":"packages/storage-s3"},"bugs":{"url":"https://github.com/Airnauts/airside/issues"},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"publishConfig":{"access":"public"},"dependencies":{"@aws-sdk/client-s3":"^3.700.0","@airnauts/airside-core":"^0.10.1","@airnauts/airside-server":"^0.10.1"},"devDependencies":{"@airnauts/airside-test-support":"0.0.0"},"scripts":{"build":"tsup && tsc --build --force","typecheck":"tsc --build","test":"vitest run"},"_id":"@airnauts/airside-storage-s3@0.10.1","_integrity":"sha512-sFFzDrq77W+Dxj/PlBzxM5SENk+WvwjGHy/IQMIcE1B6ykA37kY+/Y6so4X/cKFW3kw3Dw4qQ8hxiysCR0C4lA==","_resolved":"/tmp/c1386eae25ceada8712ac86fc2f633d8/airnauts-airside-storage-s3-0.10.1.tgz","_from":"file:airnauts-airside-storage-s3-0.10.1.tgz","_nodeVersion":"22.23.0","_npmVersion":"10.9.8","dist":{"integrity":"sha512-sFFzDrq77W+Dxj/PlBzxM5SENk+WvwjGHy/IQMIcE1B6ykA37kY+/Y6so4X/cKFW3kw3Dw4qQ8hxiysCR0C4lA==","shasum":"1dacf72041b662ec5c905487d1ede926cef6f915","tarball":"https://registry.npmjs.org/@airnauts/airside-storage-s3/-/airside-storage-s3-0.10.1.tgz","fileCount":7,"unpackedSize":19750,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDt+BtYu14ytJL+qul6/L/k2n3mtuv39iWw/86D50yq7AiEAzk/7jH6lYlBZM59acGzv8iBpDwIQpZwv05IThWhKRGA="}]},"_npmUser":{"name":"mateuszpaulski","email":"mateusz@airnauts.com"},"directories":{},"maintainers":[{"name":"jkrzemie","email":"hello@airnauts.com"},{"name":"mateuszpaulski","email":"mateusz@airnauts.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/airside-storage-s3_0.10.1_1782737644820_0.8259751226979803"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-29T10:53:14.168Z","modified":"2026-06-29T12:54:05.212Z","0.9.1":"2026-06-29T10:53:14.410Z","0.10.0":"2026-06-29T10:55:58.297Z","0.10.1":"2026-06-29T12:54:04.952Z"},"bugs":{"url":"https://github.com/Airnauts/airside/issues"},"author":{"name":"Airnauts"},"license":"MIT","homepage":"https://github.com/Airnauts/airside#readme","keywords":["comments","commenting","annotations","feedback","airnauts","storage","s3","aws","cloudflare","r2"],"repository":{"type":"git","url":"git+https://github.com/Airnauts/airside.git","directory":"packages/storage-s3"},"description":"Amazon S3 / Cloudflare R2 attachment-storage adapter for the Airnauts commenting tool server.","maintainers":[{"name":"jkrzemie","email":"hello@airnauts.com"},{"name":"mateuszpaulski","email":"mateusz@airnauts.com"}],"readme":"<p align=\"center\">\n  <a href=\"https://github.com/Airnauts/airside\">\n    <picture>\n      <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/Airnauts/airside/main/assets/airside-logo-dark.svg\">\n      <img src=\"https://raw.githubusercontent.com/Airnauts/airside/main/assets/airside-logo-light.svg\" alt=\"Airside\" height=\"40\">\n    </picture>\n  </a>\n  <h1 align=\"center\">\nEmbeddable Commenting Tool\n</h1>\n</p>\n\n# @airnauts/airside-storage-s3\n\nAmazon S3 (and any S3-compatible store — **Cloudflare R2**, MinIO, …) attachment-storage adapter for the [Airside](https://github.com/Airnauts/airside) server. Uploads images to a bucket and returns a stable, public URL.\n\n## Installation\n\n```bash\npnpm add @airnauts/airside-storage-s3\n```\n\n## Quick start\n\n### Amazon S3\n\n```ts\nimport { createS3Storage } from '@airnauts/airside-storage-s3'\n\nconst storage = createS3Storage({\n  bucket: 'my-bucket',\n  // Stable, public base for the returned URLs (a CloudFront/custom domain, or the\n  // virtual-hosted S3 URL). The object is uploaded WITHOUT an ACL — serving it\n  // publicly is your bucket-policy / CDN responsibility.\n  publicBaseUrl: 'https://cdn.example.com',\n  region: 'eu-west-1',\n  // Omit `credentials` to use the AWS SDK default provider chain\n  // (IAM instance/task role on Lambda/ECS/EC2).\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID!,\n    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,\n  },\n})\n```\n\n### Cloudflare R2\n\n`createR2Storage` fills `region: 'auto'` and derives the R2 S3-API endpoint from your account ID:\n\n```ts\nimport { createR2Storage } from '@airnauts/airside-storage-s3'\n\nconst storage = createR2Storage({\n  accountId: process.env.R2_ACCOUNT_ID!, // -> https://<accountId>.r2.cloudflarestorage.com\n  bucket: 'my-bucket',\n  // R2 public bucket URL or a custom domain bound to the bucket.\n  publicBaseUrl: 'https://pub-<hash>.r2.dev',\n  credentials: {\n    accessKeyId: process.env.R2_ACCESS_KEY_ID!,\n    secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,\n  },\n})\n```\n\nPass `storage` to `createAirsideServer` from `@airnauts/airside-server` (or to `createAirsideAppRoute` / `createAirsidePagesRoute` from `@airnauts/airside-integration-next`).\n\n## API reference\n\n### `createS3Storage(opts)`\n\n```ts\ncreateS3Storage({\n  bucket: string            // target bucket (required)\n  publicBaseUrl: string     // stable, public base for returned URLs (required; trailing slash trimmed)\n  region?: string           // default \"us-east-1\"\n  endpoint?: string         // S3-compatible endpoint (R2, MinIO)\n  credentials?: { accessKeyId: string; secretAccessKey: string } // omit -> SDK default chain\n  keyPrefix?: string        // optional key prefix, e.g. \"staging/\" (trailing slash added automatically)\n  forcePathStyle?: boolean  // path-style addressing (MinIO / some endpoints)\n  client?: S3ClientLike     // inject a client (testing/advanced); overrides build-from-config options\n}): StorageAdapter\n```\n\nEach upload sends a `PutObjectCommand` (no ACL) and returns `{ key, url, size }` where `url` is `${publicBaseUrl}/${key}`.\n\n### `createR2Storage(opts)`\n\nSame as `createS3Storage`, minus `region`/`endpoint`, plus a required `accountId` (used to derive the R2 endpoint and pin `region: 'auto'`).\n\n### `S3Storage`\n\nThe underlying class, exported for direct construction:\n\n```ts\nimport { S3Storage } from '@airnauts/airside-storage-s3'\n\nconst storage = new S3Storage({ bucket: 'my-bucket', publicBaseUrl: 'https://cdn.example.com' })\n```\n\n## Configuration / env vars\n\nThe adapter reads no environment variables itself — values are passed explicitly. Typical sources:\n\n| Env var | Description |\n|---|---|\n| `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` | Credentials for `createS3Storage({ credentials })` (omit to use the SDK default provider chain — IAM role) |\n| `R2_ACCOUNT_ID` | Cloudflare account ID for `createR2Storage({ accountId })` |\n| `R2_ACCESS_KEY_ID` / `R2_SECRET_ACCESS_KEY` | R2 S3-API token credentials |\n\n## Public access requirement\n\n`put()` uploads **without an ACL** and returns `${publicBaseUrl}/${key}`. Airside persists and serves that exact URL in `<img src>`, so the bucket prefix **must be publicly readable** through `publicBaseUrl`. Configure one of:\n\n- an **S3 bucket policy** (or a CloudFront distribution / custom domain) that serves the objects publicly, or\n- a **Cloudflare R2 public bucket** (`*.r2.dev`) or a custom domain bound to the bucket.\n\nA private bucket with no public route yields broken images. Presigned (expiring) URLs are intentionally **not** used — see ADR-0045.\n\n## Requirements\n\n- Node.js ≥ 18 (or any fetch-capable runtime)\n- A bucket on Amazon S3, Cloudflare R2, or another S3-compatible store\n\n## Related packages\n\n- **`@airnauts/airside-server`** — defines the `StorageAdapter` interface\n- **`@airnauts/airside-storage-vercel-blob`** — Vercel Blob alternative\n- **`@airnauts/airside-storage-fs`** — filesystem alternative for local development\n\n## License\n\nMIT © Airnauts\n","readmeFilename":"README.md"}