chub-dev 0.1.0 → 0.1.2-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/bin/chub-mcp +2 -0
- package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
- package/dist/airtable/docs/database/python/DOC.md +1735 -0
- package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
- package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
- package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
- package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
- package/dist/asana/docs/tasks/DOC.md +1396 -0
- package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
- package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
- package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
- package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
- package/dist/auth0/docs/identity/python/DOC.md +1199 -0
- package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
- package/dist/aws/docs/s3/python/DOC.md +1807 -0
- package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
- package/dist/binance/docs/trading/python/DOC.md +1454 -0
- package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
- package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
- package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
- package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
- package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
- package/dist/clerk/docs/auth/python/DOC.md +274 -0
- package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
- package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
- package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
- package/dist/cohere/docs/llm/DOC.md +1335 -0
- package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
- package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
- package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
- package/dist/deepgram/docs/speech/python/DOC.md +685 -0
- package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
- package/dist/deepl/docs/translation/python/DOC.md +944 -0
- package/dist/deepseek/docs/llm/DOC.md +1220 -0
- package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
- package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
- package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
- package/dist/discord/docs/bot/python/DOC.md +1130 -0
- package/dist/elasticsearch/docs/search/DOC.md +1634 -0
- package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
- package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
- package/dist/firebase/docs/auth/DOC.md +1015 -0
- package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
- package/dist/gemini/docs/genai/python/DOC.md +555 -0
- package/dist/github/docs/octokit/DOC.md +1560 -0
- package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
- package/dist/google/docs/bigquery/python/DOC.md +1503 -0
- package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
- package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
- package/dist/huggingface/docs/transformers/DOC.md +948 -0
- package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
- package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
- package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
- package/dist/jira/docs/issues/python/DOC.md +1492 -0
- package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
- package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
- package/dist/landingai-ade/docs/api/DOC.md +620 -0
- package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
- package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
- package/dist/landingai-ade/skills/SKILL.md +489 -0
- package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
- package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
- package/dist/linear/docs/tracker/DOC.md +1554 -0
- package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
- package/dist/livekit/docs/realtime/python/DOC.md +163 -0
- package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
- package/dist/meilisearch/docs/search/DOC.md +1241 -0
- package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
- package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
- package/dist/mongodb/docs/atlas/DOC.md +2041 -0
- package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
- package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
- package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
- package/dist/okta/docs/identity/python/DOC.md +1401 -0
- package/dist/openai/docs/chat/javascript/DOC.md +407 -0
- package/dist/openai/docs/chat/python/DOC.md +568 -0
- package/dist/paypal/docs/checkout/DOC.md +278 -0
- package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
- package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
- package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
- package/dist/plaid/docs/banking/python/DOC.md +1203 -0
- package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
- package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
- package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
- package/dist/prisma/docs/orm/python/DOC.md +1317 -0
- package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
- package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
- package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
- package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
- package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
- package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
- package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
- package/dist/redis/docs/key-value/python/DOC.md +2054 -0
- package/dist/registry.json +2817 -0
- package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
- package/dist/resend/docs/email/DOC.md +1271 -0
- package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
- package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
- package/dist/search-index.json +1 -0
- package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
- package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
- package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
- package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
- package/dist/shopify/docs/storefront/DOC.md +457 -0
- package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
- package/dist/slack/docs/workspace/python/DOC.md +271 -0
- package/dist/square/docs/payments/javascript/DOC.md +1855 -0
- package/dist/square/docs/payments/python/DOC.md +1728 -0
- package/dist/stripe/docs/api/DOC.md +1727 -0
- package/dist/stripe/docs/payments/DOC.md +1726 -0
- package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
- package/dist/stytch/docs/auth/python/DOC.md +1962 -0
- package/dist/supabase/docs/client/DOC.md +1606 -0
- package/dist/twilio/docs/messaging/python/DOC.md +469 -0
- package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
- package/dist/vercel/docs/platform/DOC.md +1940 -0
- package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
- package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
- package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
- package/dist/zendesk/docs/support/python/DOC.md +2297 -0
- package/package.json +22 -6
- package/skills/get-api-docs/SKILL.md +84 -0
- package/src/commands/annotate.js +83 -0
- package/src/commands/build.js +12 -1
- package/src/commands/feedback.js +150 -0
- package/src/commands/get.js +83 -42
- package/src/commands/search.js +7 -0
- package/src/index.js +43 -17
- package/src/lib/analytics.js +90 -0
- package/src/lib/annotations.js +57 -0
- package/src/lib/bm25.js +170 -0
- package/src/lib/cache.js +69 -6
- package/src/lib/config.js +8 -3
- package/src/lib/identity.js +99 -0
- package/src/lib/registry.js +103 -20
- package/src/lib/telemetry.js +86 -0
- package/src/mcp/server.js +177 -0
- package/src/mcp/tools.js +251 -0
|
@@ -0,0 +1,1773 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: s3
|
|
3
|
+
description: "AWS S3 SDK for JavaScript (v3) - Complete guide for S3 operations in JavaScript/Node.js projects"
|
|
4
|
+
metadata:
|
|
5
|
+
languages: "javascript"
|
|
6
|
+
versions: "3.917.0"
|
|
7
|
+
updated-on: "2026-03-02"
|
|
8
|
+
source: maintainer
|
|
9
|
+
tags: "aws,s3,storage,cloud,bucket"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# AWS S3 SDK for JavaScript (v3) - Complete Guide
|
|
13
|
+
|
|
14
|
+
## Golden Rule
|
|
15
|
+
|
|
16
|
+
**ALWAYS use `@aws-sdk/client-s3` for AWS S3 operations in JavaScript/Node.js projects.**
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @aws-sdk/client-s3
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**DO NOT use:**
|
|
23
|
+
- `aws-sdk` (v2) - End-of-support on September 8, 2025
|
|
24
|
+
- Any unofficial S3 libraries
|
|
25
|
+
|
|
26
|
+
The AWS SDK for JavaScript v3 (`@aws-sdk/client-s3`) is the official, maintained SDK. It uses a modular architecture that reduces bundle size and improves performance.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
### Basic Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install @aws-sdk/client-s3
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Additional Packages for Advanced Features
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# For presigned URLs
|
|
42
|
+
npm install @aws-sdk/s3-request-presigner
|
|
43
|
+
|
|
44
|
+
# For multipart uploads (large files)
|
|
45
|
+
npm install @aws-sdk/lib-storage
|
|
46
|
+
|
|
47
|
+
# For credential providers
|
|
48
|
+
npm install @aws-sdk/credential-providers
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Environment Variables
|
|
52
|
+
|
|
53
|
+
Create a `.env` file:
|
|
54
|
+
|
|
55
|
+
```env
|
|
56
|
+
AWS_ACCESS_KEY_ID=your_access_key_id
|
|
57
|
+
AWS_SECRET_ACCESS_KEY=your_secret_access_key
|
|
58
|
+
AWS_REGION=us-east-1
|
|
59
|
+
AWS_S3_BUCKET=your-bucket-name
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Load environment variables in your code:
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
import dotenv from 'dotenv';
|
|
66
|
+
dotenv.config();
|
|
67
|
+
|
|
68
|
+
const REGION = process.env.AWS_REGION;
|
|
69
|
+
const BUCKET = process.env.AWS_S3_BUCKET;
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Initialization
|
|
75
|
+
|
|
76
|
+
### Basic Client Setup
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
80
|
+
|
|
81
|
+
// Default credentials from environment variables or AWS config files
|
|
82
|
+
const client = new S3Client({});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Client with Region
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
89
|
+
|
|
90
|
+
const client = new S3Client({
|
|
91
|
+
region: "us-east-1"
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Client with Explicit Credentials
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
99
|
+
|
|
100
|
+
const client = new S3Client({
|
|
101
|
+
region: "us-east-1",
|
|
102
|
+
credentials: {
|
|
103
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
104
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Client with Cognito (Browser/Frontend)
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
113
|
+
import { fromCognitoIdentityPool } from "@aws-sdk/credential-providers";
|
|
114
|
+
|
|
115
|
+
const client = new S3Client({
|
|
116
|
+
region: "us-east-1",
|
|
117
|
+
credentials: fromCognitoIdentityPool({
|
|
118
|
+
clientConfig: { region: "us-east-1" },
|
|
119
|
+
identityPoolId: "us-east-1:your-identity-pool-id",
|
|
120
|
+
}),
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Client with Custom Endpoint (LocalStack, MinIO)
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
128
|
+
|
|
129
|
+
const client = new S3Client({
|
|
130
|
+
region: "us-east-1",
|
|
131
|
+
endpoint: "http://localhost:4566",
|
|
132
|
+
forcePathStyle: true,
|
|
133
|
+
credentials: {
|
|
134
|
+
accessKeyId: "test",
|
|
135
|
+
secretAccessKey: "test",
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Bucket Operations
|
|
143
|
+
|
|
144
|
+
### List All Buckets
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
import { S3Client, ListBucketsCommand } from "@aws-sdk/client-s3";
|
|
148
|
+
|
|
149
|
+
const client = new S3Client({});
|
|
150
|
+
|
|
151
|
+
async function listBuckets() {
|
|
152
|
+
try {
|
|
153
|
+
const response = await client.send(new ListBucketsCommand({}));
|
|
154
|
+
console.log("Buckets:");
|
|
155
|
+
response.Buckets.forEach((bucket) => {
|
|
156
|
+
console.log(` • ${bucket.Name} (Created: ${bucket.CreationDate})`);
|
|
157
|
+
});
|
|
158
|
+
} catch (error) {
|
|
159
|
+
console.error("Error listing buckets:", error);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Create Bucket
|
|
165
|
+
|
|
166
|
+
```javascript
|
|
167
|
+
import {
|
|
168
|
+
S3Client,
|
|
169
|
+
CreateBucketCommand,
|
|
170
|
+
waitUntilBucketExists
|
|
171
|
+
} from "@aws-sdk/client-s3";
|
|
172
|
+
|
|
173
|
+
const client = new S3Client({ region: "us-east-1" });
|
|
174
|
+
|
|
175
|
+
async function createBucket(bucketName) {
|
|
176
|
+
try {
|
|
177
|
+
const response = await client.send(
|
|
178
|
+
new CreateBucketCommand({
|
|
179
|
+
Bucket: bucketName,
|
|
180
|
+
})
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
// Wait until bucket exists
|
|
184
|
+
await waitUntilBucketExists(
|
|
185
|
+
{ client, maxWaitTime: 60 },
|
|
186
|
+
{ Bucket: bucketName }
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
console.log(`Bucket created: ${response.Location}`);
|
|
190
|
+
} catch (error) {
|
|
191
|
+
console.error("Error creating bucket:", error);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Create Bucket in Specific Region
|
|
197
|
+
|
|
198
|
+
```javascript
|
|
199
|
+
import { S3Client, CreateBucketCommand } from "@aws-sdk/client-s3";
|
|
200
|
+
|
|
201
|
+
const client = new S3Client({ region: "us-west-2" });
|
|
202
|
+
|
|
203
|
+
async function createBucketInRegion(bucketName, region) {
|
|
204
|
+
try {
|
|
205
|
+
const params = {
|
|
206
|
+
Bucket: bucketName,
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// us-east-1 doesn't require LocationConstraint
|
|
210
|
+
if (region !== "us-east-1") {
|
|
211
|
+
params.CreateBucketConfiguration = {
|
|
212
|
+
LocationConstraint: region,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
await client.send(new CreateBucketCommand(params));
|
|
217
|
+
console.log(`Bucket created in ${region}`);
|
|
218
|
+
} catch (error) {
|
|
219
|
+
console.error("Error creating bucket:", error);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Delete Bucket
|
|
225
|
+
|
|
226
|
+
```javascript
|
|
227
|
+
import {
|
|
228
|
+
S3Client,
|
|
229
|
+
DeleteBucketCommand,
|
|
230
|
+
waitUntilBucketNotExists
|
|
231
|
+
} from "@aws-sdk/client-s3";
|
|
232
|
+
|
|
233
|
+
const client = new S3Client({});
|
|
234
|
+
|
|
235
|
+
async function deleteBucket(bucketName) {
|
|
236
|
+
try {
|
|
237
|
+
await client.send(new DeleteBucketCommand({ Bucket: bucketName }));
|
|
238
|
+
|
|
239
|
+
await waitUntilBucketNotExists(
|
|
240
|
+
{ client, maxWaitTime: 60 },
|
|
241
|
+
{ Bucket: bucketName }
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
console.log(`Bucket deleted: ${bucketName}`);
|
|
245
|
+
} catch (error) {
|
|
246
|
+
console.error("Error deleting bucket:", error);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Check if Bucket Exists
|
|
252
|
+
|
|
253
|
+
```javascript
|
|
254
|
+
import { S3Client, HeadBucketCommand } from "@aws-sdk/client-s3";
|
|
255
|
+
|
|
256
|
+
const client = new S3Client({});
|
|
257
|
+
|
|
258
|
+
async function bucketExists(bucketName) {
|
|
259
|
+
try {
|
|
260
|
+
await client.send(new HeadBucketCommand({ Bucket: bucketName }));
|
|
261
|
+
return true;
|
|
262
|
+
} catch (error) {
|
|
263
|
+
if (error.name === "NotFound") {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
throw error;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Object Upload Operations
|
|
274
|
+
|
|
275
|
+
### Upload File from Disk
|
|
276
|
+
|
|
277
|
+
```javascript
|
|
278
|
+
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
|
|
279
|
+
import { readFile } from "node:fs/promises";
|
|
280
|
+
|
|
281
|
+
const client = new S3Client({});
|
|
282
|
+
|
|
283
|
+
async function uploadFile(bucketName, key, filePath) {
|
|
284
|
+
try {
|
|
285
|
+
const fileContent = await readFile(filePath);
|
|
286
|
+
|
|
287
|
+
const response = await client.send(
|
|
288
|
+
new PutObjectCommand({
|
|
289
|
+
Bucket: bucketName,
|
|
290
|
+
Key: key,
|
|
291
|
+
Body: fileContent,
|
|
292
|
+
})
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
console.log("Upload successful:", response.ETag);
|
|
296
|
+
} catch (error) {
|
|
297
|
+
console.error("Upload error:", error);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Upload with Content Type
|
|
303
|
+
|
|
304
|
+
```javascript
|
|
305
|
+
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
|
|
306
|
+
import { readFile } from "node:fs/promises";
|
|
307
|
+
|
|
308
|
+
const client = new S3Client({});
|
|
309
|
+
|
|
310
|
+
async function uploadWithContentType(bucketName, key, filePath, contentType) {
|
|
311
|
+
try {
|
|
312
|
+
const fileContent = await readFile(filePath);
|
|
313
|
+
|
|
314
|
+
await client.send(
|
|
315
|
+
new PutObjectCommand({
|
|
316
|
+
Bucket: bucketName,
|
|
317
|
+
Key: key,
|
|
318
|
+
Body: fileContent,
|
|
319
|
+
ContentType: contentType,
|
|
320
|
+
})
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
console.log(`Uploaded ${key} as ${contentType}`);
|
|
324
|
+
} catch (error) {
|
|
325
|
+
console.error("Upload error:", error);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Usage
|
|
330
|
+
await uploadWithContentType(
|
|
331
|
+
"my-bucket",
|
|
332
|
+
"images/photo.jpg",
|
|
333
|
+
"./photo.jpg",
|
|
334
|
+
"image/jpeg"
|
|
335
|
+
);
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Upload String/Buffer
|
|
339
|
+
|
|
340
|
+
```javascript
|
|
341
|
+
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
|
|
342
|
+
|
|
343
|
+
const client = new S3Client({});
|
|
344
|
+
|
|
345
|
+
async function uploadString(bucketName, key, content) {
|
|
346
|
+
try {
|
|
347
|
+
await client.send(
|
|
348
|
+
new PutObjectCommand({
|
|
349
|
+
Bucket: bucketName,
|
|
350
|
+
Key: key,
|
|
351
|
+
Body: content,
|
|
352
|
+
ContentType: "text/plain",
|
|
353
|
+
})
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
console.log(`Uploaded text to ${key}`);
|
|
357
|
+
} catch (error) {
|
|
358
|
+
console.error("Upload error:", error);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Upload JSON
|
|
363
|
+
async function uploadJSON(bucketName, key, data) {
|
|
364
|
+
try {
|
|
365
|
+
await client.send(
|
|
366
|
+
new PutObjectCommand({
|
|
367
|
+
Bucket: bucketName,
|
|
368
|
+
Key: key,
|
|
369
|
+
Body: JSON.stringify(data),
|
|
370
|
+
ContentType: "application/json",
|
|
371
|
+
})
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
console.log(`Uploaded JSON to ${key}`);
|
|
375
|
+
} catch (error) {
|
|
376
|
+
console.error("Upload error:", error);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### Upload with Metadata
|
|
382
|
+
|
|
383
|
+
```javascript
|
|
384
|
+
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
|
|
385
|
+
|
|
386
|
+
const client = new S3Client({});
|
|
387
|
+
|
|
388
|
+
async function uploadWithMetadata(bucketName, key, body) {
|
|
389
|
+
try {
|
|
390
|
+
await client.send(
|
|
391
|
+
new PutObjectCommand({
|
|
392
|
+
Bucket: bucketName,
|
|
393
|
+
Key: key,
|
|
394
|
+
Body: body,
|
|
395
|
+
Metadata: {
|
|
396
|
+
"uploaded-by": "user123",
|
|
397
|
+
"original-name": "document.pdf",
|
|
398
|
+
"category": "reports",
|
|
399
|
+
},
|
|
400
|
+
})
|
|
401
|
+
);
|
|
402
|
+
|
|
403
|
+
console.log("Uploaded with metadata");
|
|
404
|
+
} catch (error) {
|
|
405
|
+
console.error("Upload error:", error);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Upload with Server-Side Encryption
|
|
411
|
+
|
|
412
|
+
```javascript
|
|
413
|
+
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
|
|
414
|
+
|
|
415
|
+
const client = new S3Client({});
|
|
416
|
+
|
|
417
|
+
async function uploadEncrypted(bucketName, key, body) {
|
|
418
|
+
try {
|
|
419
|
+
await client.send(
|
|
420
|
+
new PutObjectCommand({
|
|
421
|
+
Bucket: bucketName,
|
|
422
|
+
Key: key,
|
|
423
|
+
Body: body,
|
|
424
|
+
ServerSideEncryption: "AES256",
|
|
425
|
+
})
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
console.log("Uploaded with encryption");
|
|
429
|
+
} catch (error) {
|
|
430
|
+
console.error("Upload error:", error);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Batch Upload Multiple Files
|
|
436
|
+
|
|
437
|
+
```javascript
|
|
438
|
+
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
|
|
439
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
440
|
+
import { join } from "node:path";
|
|
441
|
+
|
|
442
|
+
const client = new S3Client({});
|
|
443
|
+
|
|
444
|
+
async function uploadDirectory(bucketName, folderPath, s3Prefix = "") {
|
|
445
|
+
try {
|
|
446
|
+
const files = readdirSync(folderPath);
|
|
447
|
+
|
|
448
|
+
for (const file of files) {
|
|
449
|
+
const filePath = join(folderPath, file);
|
|
450
|
+
const fileContent = readFileSync(filePath);
|
|
451
|
+
const s3Key = s3Prefix ? `${s3Prefix}/${file}` : file;
|
|
452
|
+
|
|
453
|
+
await client.send(
|
|
454
|
+
new PutObjectCommand({
|
|
455
|
+
Bucket: bucketName,
|
|
456
|
+
Key: s3Key,
|
|
457
|
+
Body: fileContent,
|
|
458
|
+
})
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
console.log(`Uploaded: ${s3Key}`);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
console.log(`Uploaded ${files.length} files`);
|
|
465
|
+
} catch (error) {
|
|
466
|
+
console.error("Batch upload error:", error);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
---
|
|
472
|
+
|
|
473
|
+
## Object Download Operations
|
|
474
|
+
|
|
475
|
+
### Download File to Disk
|
|
476
|
+
|
|
477
|
+
```javascript
|
|
478
|
+
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
|
|
479
|
+
import { writeFile } from "node:fs/promises";
|
|
480
|
+
|
|
481
|
+
const client = new S3Client({});
|
|
482
|
+
|
|
483
|
+
async function downloadFile(bucketName, key, destinationPath) {
|
|
484
|
+
try {
|
|
485
|
+
const response = await client.send(
|
|
486
|
+
new GetObjectCommand({
|
|
487
|
+
Bucket: bucketName,
|
|
488
|
+
Key: key,
|
|
489
|
+
})
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
const fileContent = await response.Body.transformToByteArray();
|
|
493
|
+
await writeFile(destinationPath, fileContent);
|
|
494
|
+
|
|
495
|
+
console.log(`Downloaded to ${destinationPath}`);
|
|
496
|
+
} catch (error) {
|
|
497
|
+
console.error("Download error:", error);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
### Download as String
|
|
503
|
+
|
|
504
|
+
```javascript
|
|
505
|
+
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
|
|
506
|
+
|
|
507
|
+
const client = new S3Client({});
|
|
508
|
+
|
|
509
|
+
async function downloadAsString(bucketName, key) {
|
|
510
|
+
try {
|
|
511
|
+
const response = await client.send(
|
|
512
|
+
new GetObjectCommand({
|
|
513
|
+
Bucket: bucketName,
|
|
514
|
+
Key: key,
|
|
515
|
+
})
|
|
516
|
+
);
|
|
517
|
+
|
|
518
|
+
const content = await response.Body.transformToString();
|
|
519
|
+
return content;
|
|
520
|
+
} catch (error) {
|
|
521
|
+
console.error("Download error:", error);
|
|
522
|
+
throw error;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// Download JSON
|
|
527
|
+
async function downloadJSON(bucketName, key) {
|
|
528
|
+
const content = await downloadAsString(bucketName, key);
|
|
529
|
+
return JSON.parse(content);
|
|
530
|
+
}
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
### Download with Error Handling
|
|
534
|
+
|
|
535
|
+
```javascript
|
|
536
|
+
import {
|
|
537
|
+
S3Client,
|
|
538
|
+
GetObjectCommand,
|
|
539
|
+
NoSuchKey
|
|
540
|
+
} from "@aws-sdk/client-s3";
|
|
541
|
+
|
|
542
|
+
const client = new S3Client({});
|
|
543
|
+
|
|
544
|
+
async function downloadSafe(bucketName, key) {
|
|
545
|
+
try {
|
|
546
|
+
const response = await client.send(
|
|
547
|
+
new GetObjectCommand({
|
|
548
|
+
Bucket: bucketName,
|
|
549
|
+
Key: key,
|
|
550
|
+
})
|
|
551
|
+
);
|
|
552
|
+
|
|
553
|
+
return await response.Body.transformToString();
|
|
554
|
+
} catch (error) {
|
|
555
|
+
if (error instanceof NoSuchKey) {
|
|
556
|
+
console.error(`Key does not exist: ${key}`);
|
|
557
|
+
return null;
|
|
558
|
+
}
|
|
559
|
+
throw error;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
### Download Byte Range
|
|
565
|
+
|
|
566
|
+
```javascript
|
|
567
|
+
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
|
|
568
|
+
|
|
569
|
+
const client = new S3Client({});
|
|
570
|
+
|
|
571
|
+
async function downloadRange(bucketName, key, start, end) {
|
|
572
|
+
try {
|
|
573
|
+
const response = await client.send(
|
|
574
|
+
new GetObjectCommand({
|
|
575
|
+
Bucket: bucketName,
|
|
576
|
+
Key: key,
|
|
577
|
+
Range: `bytes=${start}-${end}`,
|
|
578
|
+
})
|
|
579
|
+
);
|
|
580
|
+
|
|
581
|
+
return await response.Body.transformToByteArray();
|
|
582
|
+
} catch (error) {
|
|
583
|
+
console.error("Download error:", error);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
### Get Object Metadata Only
|
|
589
|
+
|
|
590
|
+
```javascript
|
|
591
|
+
import { S3Client, HeadObjectCommand } from "@aws-sdk/client-s3";
|
|
592
|
+
|
|
593
|
+
const client = new S3Client({});
|
|
594
|
+
|
|
595
|
+
async function getObjectMetadata(bucketName, key) {
|
|
596
|
+
try {
|
|
597
|
+
const response = await client.send(
|
|
598
|
+
new HeadObjectCommand({
|
|
599
|
+
Bucket: bucketName,
|
|
600
|
+
Key: key,
|
|
601
|
+
})
|
|
602
|
+
);
|
|
603
|
+
|
|
604
|
+
console.log("Metadata:", {
|
|
605
|
+
ContentType: response.ContentType,
|
|
606
|
+
ContentLength: response.ContentLength,
|
|
607
|
+
LastModified: response.LastModified,
|
|
608
|
+
ETag: response.ETag,
|
|
609
|
+
Metadata: response.Metadata,
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
return response;
|
|
613
|
+
} catch (error) {
|
|
614
|
+
console.error("Metadata error:", error);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
## List Objects
|
|
622
|
+
|
|
623
|
+
### List All Objects (Paginated)
|
|
624
|
+
|
|
625
|
+
```javascript
|
|
626
|
+
import { S3Client, paginateListObjectsV2 } from "@aws-sdk/client-s3";
|
|
627
|
+
|
|
628
|
+
const client = new S3Client({});
|
|
629
|
+
|
|
630
|
+
async function listAllObjects(bucketName) {
|
|
631
|
+
try {
|
|
632
|
+
const paginator = paginateListObjectsV2(
|
|
633
|
+
{ client },
|
|
634
|
+
{ Bucket: bucketName }
|
|
635
|
+
);
|
|
636
|
+
|
|
637
|
+
let totalObjects = 0;
|
|
638
|
+
|
|
639
|
+
for await (const page of paginator) {
|
|
640
|
+
if (page.Contents) {
|
|
641
|
+
page.Contents.forEach((obj) => {
|
|
642
|
+
console.log(` • ${obj.Key} (${obj.Size} bytes)`);
|
|
643
|
+
totalObjects++;
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
console.log(`\nTotal objects: ${totalObjects}`);
|
|
649
|
+
} catch (error) {
|
|
650
|
+
console.error("List error:", error);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
### List Objects with Prefix
|
|
656
|
+
|
|
657
|
+
```javascript
|
|
658
|
+
import { S3Client, paginateListObjectsV2 } from "@aws-sdk/client-s3";
|
|
659
|
+
|
|
660
|
+
const client = new S3Client({});
|
|
661
|
+
|
|
662
|
+
async function listObjectsWithPrefix(bucketName, prefix) {
|
|
663
|
+
try {
|
|
664
|
+
const paginator = paginateListObjectsV2(
|
|
665
|
+
{ client },
|
|
666
|
+
{
|
|
667
|
+
Bucket: bucketName,
|
|
668
|
+
Prefix: prefix,
|
|
669
|
+
}
|
|
670
|
+
);
|
|
671
|
+
|
|
672
|
+
for await (const page of paginator) {
|
|
673
|
+
if (page.Contents) {
|
|
674
|
+
page.Contents.forEach((obj) => {
|
|
675
|
+
console.log(` • ${obj.Key}`);
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
} catch (error) {
|
|
680
|
+
console.error("List error:", error);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
### List Objects with Custom Page Size
|
|
686
|
+
|
|
687
|
+
```javascript
|
|
688
|
+
import { S3Client, paginateListObjectsV2 } from "@aws-sdk/client-s3";
|
|
689
|
+
|
|
690
|
+
const client = new S3Client({});
|
|
691
|
+
|
|
692
|
+
async function listObjectsPaged(bucketName, pageSize = 10) {
|
|
693
|
+
try {
|
|
694
|
+
const paginator = paginateListObjectsV2(
|
|
695
|
+
{ client, pageSize },
|
|
696
|
+
{ Bucket: bucketName }
|
|
697
|
+
);
|
|
698
|
+
|
|
699
|
+
let pageNumber = 1;
|
|
700
|
+
|
|
701
|
+
for await (const page of paginator) {
|
|
702
|
+
console.log(`\nPage ${pageNumber}:`);
|
|
703
|
+
|
|
704
|
+
if (page.Contents) {
|
|
705
|
+
page.Contents.forEach((obj) => {
|
|
706
|
+
console.log(` • ${obj.Key}`);
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
pageNumber++;
|
|
711
|
+
}
|
|
712
|
+
} catch (error) {
|
|
713
|
+
console.error("List error:", error);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
### List Objects (Non-Paginated)
|
|
719
|
+
|
|
720
|
+
```javascript
|
|
721
|
+
import { S3Client, ListObjectsV2Command } from "@aws-sdk/client-s3";
|
|
722
|
+
|
|
723
|
+
const client = new S3Client({});
|
|
724
|
+
|
|
725
|
+
async function listObjectsSimple(bucketName, maxKeys = 1000) {
|
|
726
|
+
try {
|
|
727
|
+
const response = await client.send(
|
|
728
|
+
new ListObjectsV2Command({
|
|
729
|
+
Bucket: bucketName,
|
|
730
|
+
MaxKeys: maxKeys,
|
|
731
|
+
})
|
|
732
|
+
);
|
|
733
|
+
|
|
734
|
+
if (response.Contents) {
|
|
735
|
+
response.Contents.forEach((obj) => {
|
|
736
|
+
console.log(` • ${obj.Key}`);
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
console.log(`Listed ${response.KeyCount} objects`);
|
|
741
|
+
console.log(`Truncated: ${response.IsTruncated}`);
|
|
742
|
+
} catch (error) {
|
|
743
|
+
console.error("List error:", error);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
### List Objects in Folder Structure
|
|
749
|
+
|
|
750
|
+
```javascript
|
|
751
|
+
import { S3Client, ListObjectsV2Command } from "@aws-sdk/client-s3";
|
|
752
|
+
|
|
753
|
+
const client = new S3Client({});
|
|
754
|
+
|
|
755
|
+
async function listFolder(bucketName, prefix) {
|
|
756
|
+
try {
|
|
757
|
+
const response = await client.send(
|
|
758
|
+
new ListObjectsV2Command({
|
|
759
|
+
Bucket: bucketName,
|
|
760
|
+
Prefix: prefix,
|
|
761
|
+
Delimiter: "/",
|
|
762
|
+
})
|
|
763
|
+
);
|
|
764
|
+
|
|
765
|
+
console.log("Folders:");
|
|
766
|
+
if (response.CommonPrefixes) {
|
|
767
|
+
response.CommonPrefixes.forEach((cp) => {
|
|
768
|
+
console.log(` 📁 ${cp.Prefix}`);
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
console.log("\nFiles:");
|
|
773
|
+
if (response.Contents) {
|
|
774
|
+
response.Contents.forEach((obj) => {
|
|
775
|
+
console.log(` 📄 ${obj.Key}`);
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
} catch (error) {
|
|
779
|
+
console.error("List error:", error);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
---
|
|
785
|
+
|
|
786
|
+
## Delete Operations
|
|
787
|
+
|
|
788
|
+
### Delete Single Object
|
|
789
|
+
|
|
790
|
+
```javascript
|
|
791
|
+
import {
|
|
792
|
+
S3Client,
|
|
793
|
+
DeleteObjectCommand,
|
|
794
|
+
waitUntilObjectNotExists
|
|
795
|
+
} from "@aws-sdk/client-s3";
|
|
796
|
+
|
|
797
|
+
const client = new S3Client({});
|
|
798
|
+
|
|
799
|
+
async function deleteObject(bucketName, key) {
|
|
800
|
+
try {
|
|
801
|
+
await client.send(
|
|
802
|
+
new DeleteObjectCommand({
|
|
803
|
+
Bucket: bucketName,
|
|
804
|
+
Key: key,
|
|
805
|
+
})
|
|
806
|
+
);
|
|
807
|
+
|
|
808
|
+
await waitUntilObjectNotExists(
|
|
809
|
+
{ client, maxWaitTime: 60 },
|
|
810
|
+
{ Bucket: bucketName, Key: key }
|
|
811
|
+
);
|
|
812
|
+
|
|
813
|
+
console.log(`Deleted: ${key}`);
|
|
814
|
+
} catch (error) {
|
|
815
|
+
console.error("Delete error:", error);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
### Delete Multiple Objects (Batch)
|
|
821
|
+
|
|
822
|
+
```javascript
|
|
823
|
+
import { S3Client, DeleteObjectsCommand } from "@aws-sdk/client-s3";
|
|
824
|
+
|
|
825
|
+
const client = new S3Client({});
|
|
826
|
+
|
|
827
|
+
async function deleteMultipleObjects(bucketName, keys) {
|
|
828
|
+
try {
|
|
829
|
+
const response = await client.send(
|
|
830
|
+
new DeleteObjectsCommand({
|
|
831
|
+
Bucket: bucketName,
|
|
832
|
+
Delete: {
|
|
833
|
+
Objects: keys.map((key) => ({ Key: key })),
|
|
834
|
+
},
|
|
835
|
+
})
|
|
836
|
+
);
|
|
837
|
+
|
|
838
|
+
if (response.Deleted) {
|
|
839
|
+
console.log(`Deleted ${response.Deleted.length} objects:`);
|
|
840
|
+
response.Deleted.forEach((obj) => {
|
|
841
|
+
console.log(` • ${obj.Key}`);
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
if (response.Errors) {
|
|
846
|
+
console.error("Errors:", response.Errors);
|
|
847
|
+
}
|
|
848
|
+
} catch (error) {
|
|
849
|
+
console.error("Batch delete error:", error);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// Usage
|
|
854
|
+
await deleteMultipleObjects("my-bucket", [
|
|
855
|
+
"file1.txt",
|
|
856
|
+
"file2.txt",
|
|
857
|
+
"folder/file3.txt",
|
|
858
|
+
]);
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
### Delete All Objects with Prefix
|
|
862
|
+
|
|
863
|
+
```javascript
|
|
864
|
+
import {
|
|
865
|
+
S3Client,
|
|
866
|
+
ListObjectsV2Command,
|
|
867
|
+
DeleteObjectsCommand
|
|
868
|
+
} from "@aws-sdk/client-s3";
|
|
869
|
+
|
|
870
|
+
const client = new S3Client({});
|
|
871
|
+
|
|
872
|
+
async function deleteObjectsWithPrefix(bucketName, prefix) {
|
|
873
|
+
try {
|
|
874
|
+
const listResponse = await client.send(
|
|
875
|
+
new ListObjectsV2Command({
|
|
876
|
+
Bucket: bucketName,
|
|
877
|
+
Prefix: prefix,
|
|
878
|
+
})
|
|
879
|
+
);
|
|
880
|
+
|
|
881
|
+
if (!listResponse.Contents || listResponse.Contents.length === 0) {
|
|
882
|
+
console.log("No objects to delete");
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
const deleteResponse = await client.send(
|
|
887
|
+
new DeleteObjectsCommand({
|
|
888
|
+
Bucket: bucketName,
|
|
889
|
+
Delete: {
|
|
890
|
+
Objects: listResponse.Contents.map((obj) => ({ Key: obj.Key })),
|
|
891
|
+
},
|
|
892
|
+
})
|
|
893
|
+
);
|
|
894
|
+
|
|
895
|
+
console.log(`Deleted ${deleteResponse.Deleted.length} objects`);
|
|
896
|
+
} catch (error) {
|
|
897
|
+
console.error("Delete error:", error);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
### Empty and Delete Bucket
|
|
903
|
+
|
|
904
|
+
```javascript
|
|
905
|
+
import {
|
|
906
|
+
S3Client,
|
|
907
|
+
ListObjectsV2Command,
|
|
908
|
+
DeleteObjectsCommand,
|
|
909
|
+
DeleteBucketCommand
|
|
910
|
+
} from "@aws-sdk/client-s3";
|
|
911
|
+
|
|
912
|
+
const client = new S3Client({});
|
|
913
|
+
|
|
914
|
+
async function emptyAndDeleteBucket(bucketName) {
|
|
915
|
+
try {
|
|
916
|
+
// List all objects
|
|
917
|
+
const listResponse = await client.send(
|
|
918
|
+
new ListObjectsV2Command({ Bucket: bucketName })
|
|
919
|
+
);
|
|
920
|
+
|
|
921
|
+
// Delete all objects if any exist
|
|
922
|
+
if (listResponse.Contents && listResponse.Contents.length > 0) {
|
|
923
|
+
await client.send(
|
|
924
|
+
new DeleteObjectsCommand({
|
|
925
|
+
Bucket: bucketName,
|
|
926
|
+
Delete: {
|
|
927
|
+
Objects: listResponse.Contents.map((obj) => ({ Key: obj.Key })),
|
|
928
|
+
},
|
|
929
|
+
})
|
|
930
|
+
);
|
|
931
|
+
|
|
932
|
+
console.log(`Deleted ${listResponse.Contents.length} objects`);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// Delete the bucket
|
|
936
|
+
await client.send(new DeleteBucketCommand({ Bucket: bucketName }));
|
|
937
|
+
console.log(`Bucket deleted: ${bucketName}`);
|
|
938
|
+
} catch (error) {
|
|
939
|
+
console.error("Error:", error);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
---
|
|
945
|
+
|
|
946
|
+
## Copy and Move Operations
|
|
947
|
+
|
|
948
|
+
### Copy Object
|
|
949
|
+
|
|
950
|
+
```javascript
|
|
951
|
+
import { S3Client, CopyObjectCommand } from "@aws-sdk/client-s3";
|
|
952
|
+
|
|
953
|
+
const client = new S3Client({});
|
|
954
|
+
|
|
955
|
+
async function copyObject(sourceBucket, sourceKey, destBucket, destKey) {
|
|
956
|
+
try {
|
|
957
|
+
await client.send(
|
|
958
|
+
new CopyObjectCommand({
|
|
959
|
+
CopySource: `${sourceBucket}/${sourceKey}`,
|
|
960
|
+
Bucket: destBucket,
|
|
961
|
+
Key: destKey,
|
|
962
|
+
})
|
|
963
|
+
);
|
|
964
|
+
|
|
965
|
+
console.log(`Copied ${sourceKey} to ${destKey}`);
|
|
966
|
+
} catch (error) {
|
|
967
|
+
console.error("Copy error:", error);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
### Move Object (Copy + Delete)
|
|
973
|
+
|
|
974
|
+
```javascript
|
|
975
|
+
import {
|
|
976
|
+
S3Client,
|
|
977
|
+
CopyObjectCommand,
|
|
978
|
+
DeleteObjectCommand
|
|
979
|
+
} from "@aws-sdk/client-s3";
|
|
980
|
+
|
|
981
|
+
const client = new S3Client({});
|
|
982
|
+
|
|
983
|
+
async function moveObject(sourceBucket, sourceKey, destBucket, destKey) {
|
|
984
|
+
try {
|
|
985
|
+
// Copy
|
|
986
|
+
await client.send(
|
|
987
|
+
new CopyObjectCommand({
|
|
988
|
+
CopySource: `${sourceBucket}/${sourceKey}`,
|
|
989
|
+
Bucket: destBucket,
|
|
990
|
+
Key: destKey,
|
|
991
|
+
})
|
|
992
|
+
);
|
|
993
|
+
|
|
994
|
+
// Delete source
|
|
995
|
+
await client.send(
|
|
996
|
+
new DeleteObjectCommand({
|
|
997
|
+
Bucket: sourceBucket,
|
|
998
|
+
Key: sourceKey,
|
|
999
|
+
})
|
|
1000
|
+
);
|
|
1001
|
+
|
|
1002
|
+
console.log(`Moved ${sourceKey} to ${destKey}`);
|
|
1003
|
+
} catch (error) {
|
|
1004
|
+
console.error("Move error:", error);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
```
|
|
1008
|
+
|
|
1009
|
+
---
|
|
1010
|
+
|
|
1011
|
+
## Presigned URLs
|
|
1012
|
+
|
|
1013
|
+
### Install Required Package
|
|
1014
|
+
|
|
1015
|
+
```bash
|
|
1016
|
+
npm install @aws-sdk/s3-request-presigner
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
### Presigned URL for Download (GET)
|
|
1020
|
+
|
|
1021
|
+
```javascript
|
|
1022
|
+
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
|
|
1023
|
+
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
1024
|
+
|
|
1025
|
+
const client = new S3Client({ region: "us-east-1" });
|
|
1026
|
+
|
|
1027
|
+
async function createPresignedDownloadUrl(bucketName, key, expiresIn = 3600) {
|
|
1028
|
+
try {
|
|
1029
|
+
const command = new GetObjectCommand({
|
|
1030
|
+
Bucket: bucketName,
|
|
1031
|
+
Key: key,
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
const url = await getSignedUrl(client, command, { expiresIn });
|
|
1035
|
+
return url;
|
|
1036
|
+
} catch (error) {
|
|
1037
|
+
console.error("Presigned URL error:", error);
|
|
1038
|
+
throw error;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
// Usage
|
|
1043
|
+
const url = await createPresignedDownloadUrl("my-bucket", "file.pdf", 3600);
|
|
1044
|
+
console.log("Download URL:", url);
|
|
1045
|
+
```
|
|
1046
|
+
|
|
1047
|
+
### Presigned URL for Upload (PUT)
|
|
1048
|
+
|
|
1049
|
+
```javascript
|
|
1050
|
+
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
|
|
1051
|
+
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
1052
|
+
|
|
1053
|
+
const client = new S3Client({ region: "us-east-1" });
|
|
1054
|
+
|
|
1055
|
+
async function createPresignedUploadUrl(bucketName, key, expiresIn = 3600) {
|
|
1056
|
+
try {
|
|
1057
|
+
const command = new PutObjectCommand({
|
|
1058
|
+
Bucket: bucketName,
|
|
1059
|
+
Key: key,
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1062
|
+
const url = await getSignedUrl(client, command, { expiresIn });
|
|
1063
|
+
return url;
|
|
1064
|
+
} catch (error) {
|
|
1065
|
+
console.error("Presigned URL error:", error);
|
|
1066
|
+
throw error;
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// Usage with fetch
|
|
1071
|
+
const uploadUrl = await createPresignedUploadUrl("my-bucket", "upload.txt");
|
|
1072
|
+
|
|
1073
|
+
// Client can now upload using PUT request
|
|
1074
|
+
await fetch(uploadUrl, {
|
|
1075
|
+
method: "PUT",
|
|
1076
|
+
body: fileContent,
|
|
1077
|
+
headers: {
|
|
1078
|
+
"Content-Type": "text/plain",
|
|
1079
|
+
},
|
|
1080
|
+
});
|
|
1081
|
+
```
|
|
1082
|
+
|
|
1083
|
+
### Presigned URL with Content Type
|
|
1084
|
+
|
|
1085
|
+
```javascript
|
|
1086
|
+
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
|
|
1087
|
+
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
1088
|
+
|
|
1089
|
+
const client = new S3Client({ region: "us-east-1" });
|
|
1090
|
+
|
|
1091
|
+
async function createPresignedUploadUrlWithType(
|
|
1092
|
+
bucketName,
|
|
1093
|
+
key,
|
|
1094
|
+
contentType,
|
|
1095
|
+
expiresIn = 3600
|
|
1096
|
+
) {
|
|
1097
|
+
try {
|
|
1098
|
+
const command = new PutObjectCommand({
|
|
1099
|
+
Bucket: bucketName,
|
|
1100
|
+
Key: key,
|
|
1101
|
+
ContentType: contentType,
|
|
1102
|
+
});
|
|
1103
|
+
|
|
1104
|
+
const url = await getSignedUrl(client, command, { expiresIn });
|
|
1105
|
+
return url;
|
|
1106
|
+
} catch (error) {
|
|
1107
|
+
console.error("Presigned URL error:", error);
|
|
1108
|
+
throw error;
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
```
|
|
1112
|
+
|
|
1113
|
+
### Presigned URL with Metadata
|
|
1114
|
+
|
|
1115
|
+
```javascript
|
|
1116
|
+
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
|
|
1117
|
+
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
1118
|
+
|
|
1119
|
+
const client = new S3Client({ region: "us-east-1" });
|
|
1120
|
+
|
|
1121
|
+
async function createPresignedUrlWithMetadata(bucketName, key) {
|
|
1122
|
+
try {
|
|
1123
|
+
const command = new PutObjectCommand({
|
|
1124
|
+
Bucket: bucketName,
|
|
1125
|
+
Key: key,
|
|
1126
|
+
Metadata: {
|
|
1127
|
+
"uploaded-by": "user123",
|
|
1128
|
+
"original-name": "document.pdf",
|
|
1129
|
+
},
|
|
1130
|
+
});
|
|
1131
|
+
|
|
1132
|
+
const url = await getSignedUrl(client, command, { expiresIn: 3600 });
|
|
1133
|
+
return url;
|
|
1134
|
+
} catch (error) {
|
|
1135
|
+
console.error("Presigned URL error:", error);
|
|
1136
|
+
throw error;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
### Complete Presigned Upload Example
|
|
1142
|
+
|
|
1143
|
+
```javascript
|
|
1144
|
+
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
|
|
1145
|
+
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
1146
|
+
|
|
1147
|
+
const client = new S3Client({ region: "us-east-1" });
|
|
1148
|
+
|
|
1149
|
+
// Server-side: Generate presigned URL
|
|
1150
|
+
async function generateUploadUrl(fileName, fileType) {
|
|
1151
|
+
const command = new PutObjectCommand({
|
|
1152
|
+
Bucket: "my-bucket",
|
|
1153
|
+
Key: `uploads/${fileName}`,
|
|
1154
|
+
ContentType: fileType,
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1157
|
+
return await getSignedUrl(client, command, { expiresIn: 300 }); // 5 minutes
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
// Client-side: Upload using presigned URL
|
|
1161
|
+
async function uploadUsingPresignedUrl(presignedUrl, file) {
|
|
1162
|
+
const response = await fetch(presignedUrl, {
|
|
1163
|
+
method: "PUT",
|
|
1164
|
+
body: file,
|
|
1165
|
+
headers: {
|
|
1166
|
+
"Content-Type": file.type,
|
|
1167
|
+
},
|
|
1168
|
+
});
|
|
1169
|
+
|
|
1170
|
+
if (response.ok) {
|
|
1171
|
+
console.log("Upload successful");
|
|
1172
|
+
} else {
|
|
1173
|
+
console.error("Upload failed:", response.statusText);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
```
|
|
1177
|
+
|
|
1178
|
+
---
|
|
1179
|
+
|
|
1180
|
+
## Multipart Upload
|
|
1181
|
+
|
|
1182
|
+
### Install Required Package
|
|
1183
|
+
|
|
1184
|
+
```bash
|
|
1185
|
+
npm install @aws-sdk/lib-storage
|
|
1186
|
+
```
|
|
1187
|
+
|
|
1188
|
+
### Basic Multipart Upload
|
|
1189
|
+
|
|
1190
|
+
```javascript
|
|
1191
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
1192
|
+
import { Upload } from "@aws-sdk/lib-storage";
|
|
1193
|
+
import { createReadStream } from "node:fs";
|
|
1194
|
+
|
|
1195
|
+
const client = new S3Client({});
|
|
1196
|
+
|
|
1197
|
+
async function multipartUpload(bucketName, key, filePath) {
|
|
1198
|
+
try {
|
|
1199
|
+
const fileStream = createReadStream(filePath);
|
|
1200
|
+
|
|
1201
|
+
const upload = new Upload({
|
|
1202
|
+
client,
|
|
1203
|
+
params: {
|
|
1204
|
+
Bucket: bucketName,
|
|
1205
|
+
Key: key,
|
|
1206
|
+
Body: fileStream,
|
|
1207
|
+
},
|
|
1208
|
+
});
|
|
1209
|
+
|
|
1210
|
+
const result = await upload.done();
|
|
1211
|
+
console.log("Upload complete:", result.Location);
|
|
1212
|
+
} catch (error) {
|
|
1213
|
+
console.error("Multipart upload error:", error);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
```
|
|
1217
|
+
|
|
1218
|
+
### Multipart Upload with Progress Tracking
|
|
1219
|
+
|
|
1220
|
+
```javascript
|
|
1221
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
1222
|
+
import { Upload } from "@aws-sdk/lib-storage";
|
|
1223
|
+
import { createReadStream, statSync } from "node:fs";
|
|
1224
|
+
|
|
1225
|
+
const client = new S3Client({});
|
|
1226
|
+
|
|
1227
|
+
async function multipartUploadWithProgress(bucketName, key, filePath) {
|
|
1228
|
+
try {
|
|
1229
|
+
const fileStream = createReadStream(filePath);
|
|
1230
|
+
const fileSize = statSync(filePath).size;
|
|
1231
|
+
|
|
1232
|
+
const upload = new Upload({
|
|
1233
|
+
client,
|
|
1234
|
+
params: {
|
|
1235
|
+
Bucket: bucketName,
|
|
1236
|
+
Key: key,
|
|
1237
|
+
Body: fileStream,
|
|
1238
|
+
},
|
|
1239
|
+
});
|
|
1240
|
+
|
|
1241
|
+
upload.on("httpUploadProgress", (progress) => {
|
|
1242
|
+
const percentage = Math.round((progress.loaded / fileSize) * 100);
|
|
1243
|
+
console.log(`Upload progress: ${percentage}%`);
|
|
1244
|
+
});
|
|
1245
|
+
|
|
1246
|
+
const result = await upload.done();
|
|
1247
|
+
console.log("Upload complete:", result.Location);
|
|
1248
|
+
} catch (error) {
|
|
1249
|
+
console.error("Multipart upload error:", error);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
```
|
|
1253
|
+
|
|
1254
|
+
### Multipart Upload with Custom Configuration
|
|
1255
|
+
|
|
1256
|
+
```javascript
|
|
1257
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
1258
|
+
import { Upload } from "@aws-sdk/lib-storage";
|
|
1259
|
+
import { createReadStream } from "node:fs";
|
|
1260
|
+
|
|
1261
|
+
const client = new S3Client({});
|
|
1262
|
+
|
|
1263
|
+
async function multipartUploadConfigured(bucketName, key, filePath) {
|
|
1264
|
+
try {
|
|
1265
|
+
const fileStream = createReadStream(filePath);
|
|
1266
|
+
|
|
1267
|
+
const upload = new Upload({
|
|
1268
|
+
client,
|
|
1269
|
+
params: {
|
|
1270
|
+
Bucket: bucketName,
|
|
1271
|
+
Key: key,
|
|
1272
|
+
Body: fileStream,
|
|
1273
|
+
},
|
|
1274
|
+
queueSize: 4, // Number of concurrent uploads
|
|
1275
|
+
partSize: 1024 * 1024 * 5, // 5 MB parts (minimum is 5 MB)
|
|
1276
|
+
leavePartsOnError: false, // Clean up on error
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
const result = await upload.done();
|
|
1280
|
+
console.log("Upload complete:", result.Location);
|
|
1281
|
+
} catch (error) {
|
|
1282
|
+
console.error("Multipart upload error:", error);
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
```
|
|
1286
|
+
|
|
1287
|
+
### Multipart Upload with Tags and Metadata
|
|
1288
|
+
|
|
1289
|
+
```javascript
|
|
1290
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
1291
|
+
import { Upload } from "@aws-sdk/lib-storage";
|
|
1292
|
+
import { readFileSync } from "node:fs";
|
|
1293
|
+
|
|
1294
|
+
const client = new S3Client({});
|
|
1295
|
+
|
|
1296
|
+
async function multipartUploadWithTags(bucketName, key, filePath) {
|
|
1297
|
+
try {
|
|
1298
|
+
const fileContent = readFileSync(filePath);
|
|
1299
|
+
|
|
1300
|
+
const upload = new Upload({
|
|
1301
|
+
client,
|
|
1302
|
+
params: {
|
|
1303
|
+
Bucket: bucketName,
|
|
1304
|
+
Key: key,
|
|
1305
|
+
Body: fileContent,
|
|
1306
|
+
Metadata: {
|
|
1307
|
+
"uploaded-by": "system",
|
|
1308
|
+
"file-category": "large-files",
|
|
1309
|
+
},
|
|
1310
|
+
},
|
|
1311
|
+
tags: [
|
|
1312
|
+
{ Key: "Environment", Value: "Production" },
|
|
1313
|
+
{ Key: "Department", Value: "Engineering" },
|
|
1314
|
+
],
|
|
1315
|
+
});
|
|
1316
|
+
|
|
1317
|
+
const result = await upload.done();
|
|
1318
|
+
console.log("Upload complete:", result.Location);
|
|
1319
|
+
} catch (error) {
|
|
1320
|
+
console.error("Multipart upload error:", error);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
```
|
|
1324
|
+
|
|
1325
|
+
### Abort Multipart Upload
|
|
1326
|
+
|
|
1327
|
+
```javascript
|
|
1328
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
1329
|
+
import { Upload } from "@aws-sdk/lib-storage";
|
|
1330
|
+
import { createReadStream } from "node:fs";
|
|
1331
|
+
|
|
1332
|
+
const client = new S3Client({});
|
|
1333
|
+
|
|
1334
|
+
async function abortableMultipartUpload(bucketName, key, filePath) {
|
|
1335
|
+
const fileStream = createReadStream(filePath);
|
|
1336
|
+
|
|
1337
|
+
const upload = new Upload({
|
|
1338
|
+
client,
|
|
1339
|
+
params: {
|
|
1340
|
+
Bucket: bucketName,
|
|
1341
|
+
Key: key,
|
|
1342
|
+
Body: fileStream,
|
|
1343
|
+
},
|
|
1344
|
+
});
|
|
1345
|
+
|
|
1346
|
+
// Abort after 5 seconds (example)
|
|
1347
|
+
setTimeout(() => {
|
|
1348
|
+
upload.abort();
|
|
1349
|
+
console.log("Upload aborted");
|
|
1350
|
+
}, 5000);
|
|
1351
|
+
|
|
1352
|
+
try {
|
|
1353
|
+
await upload.done();
|
|
1354
|
+
} catch (error) {
|
|
1355
|
+
if (error.name === "AbortError") {
|
|
1356
|
+
console.log("Upload was aborted");
|
|
1357
|
+
} else {
|
|
1358
|
+
console.error("Upload error:", error);
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
```
|
|
1363
|
+
|
|
1364
|
+
---
|
|
1365
|
+
|
|
1366
|
+
## Streaming Operations
|
|
1367
|
+
|
|
1368
|
+
### Stream Download
|
|
1369
|
+
|
|
1370
|
+
```javascript
|
|
1371
|
+
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
|
|
1372
|
+
import { pipeline } from "node:stream/promises";
|
|
1373
|
+
import { createWriteStream } from "node:fs";
|
|
1374
|
+
|
|
1375
|
+
const client = new S3Client({});
|
|
1376
|
+
|
|
1377
|
+
async function streamDownload(bucketName, key, destinationPath) {
|
|
1378
|
+
try {
|
|
1379
|
+
const response = await client.send(
|
|
1380
|
+
new GetObjectCommand({
|
|
1381
|
+
Bucket: bucketName,
|
|
1382
|
+
Key: key,
|
|
1383
|
+
})
|
|
1384
|
+
);
|
|
1385
|
+
|
|
1386
|
+
await pipeline(
|
|
1387
|
+
response.Body,
|
|
1388
|
+
createWriteStream(destinationPath)
|
|
1389
|
+
);
|
|
1390
|
+
|
|
1391
|
+
console.log(`Streamed download to ${destinationPath}`);
|
|
1392
|
+
} catch (error) {
|
|
1393
|
+
console.error("Stream download error:", error);
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
```
|
|
1397
|
+
|
|
1398
|
+
### Stream Upload
|
|
1399
|
+
|
|
1400
|
+
```javascript
|
|
1401
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
1402
|
+
import { Upload } from "@aws-sdk/lib-storage";
|
|
1403
|
+
import { createReadStream } from "node:fs";
|
|
1404
|
+
|
|
1405
|
+
const client = new S3Client({});
|
|
1406
|
+
|
|
1407
|
+
async function streamUpload(bucketName, key, filePath) {
|
|
1408
|
+
try {
|
|
1409
|
+
const fileStream = createReadStream(filePath);
|
|
1410
|
+
|
|
1411
|
+
const upload = new Upload({
|
|
1412
|
+
client,
|
|
1413
|
+
params: {
|
|
1414
|
+
Bucket: bucketName,
|
|
1415
|
+
Key: key,
|
|
1416
|
+
Body: fileStream,
|
|
1417
|
+
},
|
|
1418
|
+
});
|
|
1419
|
+
|
|
1420
|
+
await upload.done();
|
|
1421
|
+
console.log("Stream upload complete");
|
|
1422
|
+
} catch (error) {
|
|
1423
|
+
console.error("Stream upload error:", error);
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
```
|
|
1427
|
+
|
|
1428
|
+
---
|
|
1429
|
+
|
|
1430
|
+
## Object Tagging
|
|
1431
|
+
|
|
1432
|
+
### Put Object Tags
|
|
1433
|
+
|
|
1434
|
+
```javascript
|
|
1435
|
+
import { S3Client, PutObjectTaggingCommand } from "@aws-sdk/client-s3";
|
|
1436
|
+
|
|
1437
|
+
const client = new S3Client({});
|
|
1438
|
+
|
|
1439
|
+
async function tagObject(bucketName, key, tags) {
|
|
1440
|
+
try {
|
|
1441
|
+
await client.send(
|
|
1442
|
+
new PutObjectTaggingCommand({
|
|
1443
|
+
Bucket: bucketName,
|
|
1444
|
+
Key: key,
|
|
1445
|
+
Tagging: {
|
|
1446
|
+
TagSet: tags.map(({ Key, Value }) => ({ Key, Value })),
|
|
1447
|
+
},
|
|
1448
|
+
})
|
|
1449
|
+
);
|
|
1450
|
+
|
|
1451
|
+
console.log(`Tagged ${key}`);
|
|
1452
|
+
} catch (error) {
|
|
1453
|
+
console.error("Tagging error:", error);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
// Usage
|
|
1458
|
+
await tagObject("my-bucket", "file.txt", [
|
|
1459
|
+
{ Key: "Environment", Value: "Production" },
|
|
1460
|
+
{ Key: "Department", Value: "Engineering" },
|
|
1461
|
+
]);
|
|
1462
|
+
```
|
|
1463
|
+
|
|
1464
|
+
### Get Object Tags
|
|
1465
|
+
|
|
1466
|
+
```javascript
|
|
1467
|
+
import { S3Client, GetObjectTaggingCommand } from "@aws-sdk/client-s3";
|
|
1468
|
+
|
|
1469
|
+
const client = new S3Client({});
|
|
1470
|
+
|
|
1471
|
+
async function getObjectTags(bucketName, key) {
|
|
1472
|
+
try {
|
|
1473
|
+
const response = await client.send(
|
|
1474
|
+
new GetObjectTaggingCommand({
|
|
1475
|
+
Bucket: bucketName,
|
|
1476
|
+
Key: key,
|
|
1477
|
+
})
|
|
1478
|
+
);
|
|
1479
|
+
|
|
1480
|
+
console.log("Tags:");
|
|
1481
|
+
response.TagSet.forEach((tag) => {
|
|
1482
|
+
console.log(` ${tag.Key}: ${tag.Value}`);
|
|
1483
|
+
});
|
|
1484
|
+
|
|
1485
|
+
return response.TagSet;
|
|
1486
|
+
} catch (error) {
|
|
1487
|
+
console.error("Get tags error:", error);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
```
|
|
1491
|
+
|
|
1492
|
+
---
|
|
1493
|
+
|
|
1494
|
+
## Bucket Configuration
|
|
1495
|
+
|
|
1496
|
+
### Enable Versioning
|
|
1497
|
+
|
|
1498
|
+
```javascript
|
|
1499
|
+
import { S3Client, PutBucketVersioningCommand } from "@aws-sdk/client-s3";
|
|
1500
|
+
|
|
1501
|
+
const client = new S3Client({});
|
|
1502
|
+
|
|
1503
|
+
async function enableVersioning(bucketName) {
|
|
1504
|
+
try {
|
|
1505
|
+
await client.send(
|
|
1506
|
+
new PutBucketVersioningCommand({
|
|
1507
|
+
Bucket: bucketName,
|
|
1508
|
+
VersioningConfiguration: {
|
|
1509
|
+
Status: "Enabled",
|
|
1510
|
+
},
|
|
1511
|
+
})
|
|
1512
|
+
);
|
|
1513
|
+
|
|
1514
|
+
console.log(`Versioning enabled for ${bucketName}`);
|
|
1515
|
+
} catch (error) {
|
|
1516
|
+
console.error("Versioning error:", error);
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
```
|
|
1520
|
+
|
|
1521
|
+
### Set Bucket CORS
|
|
1522
|
+
|
|
1523
|
+
```javascript
|
|
1524
|
+
import { S3Client, PutBucketCorsCommand } from "@aws-sdk/client-s3";
|
|
1525
|
+
|
|
1526
|
+
const client = new S3Client({});
|
|
1527
|
+
|
|
1528
|
+
async function setBucketCORS(bucketName) {
|
|
1529
|
+
try {
|
|
1530
|
+
await client.send(
|
|
1531
|
+
new PutBucketCorsCommand({
|
|
1532
|
+
Bucket: bucketName,
|
|
1533
|
+
CORSConfiguration: {
|
|
1534
|
+
CORSRules: [
|
|
1535
|
+
{
|
|
1536
|
+
AllowedHeaders: ["*"],
|
|
1537
|
+
AllowedMethods: ["GET", "PUT", "POST", "DELETE"],
|
|
1538
|
+
AllowedOrigins: ["*"],
|
|
1539
|
+
ExposeHeaders: ["ETag"],
|
|
1540
|
+
MaxAgeSeconds: 3000,
|
|
1541
|
+
},
|
|
1542
|
+
],
|
|
1543
|
+
},
|
|
1544
|
+
})
|
|
1545
|
+
);
|
|
1546
|
+
|
|
1547
|
+
console.log("CORS configured");
|
|
1548
|
+
} catch (error) {
|
|
1549
|
+
console.error("CORS error:", error);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
```
|
|
1553
|
+
|
|
1554
|
+
### Get Bucket CORS
|
|
1555
|
+
|
|
1556
|
+
```javascript
|
|
1557
|
+
import { S3Client, GetBucketCorsCommand } from "@aws-sdk/client-s3";
|
|
1558
|
+
|
|
1559
|
+
const client = new S3Client({});
|
|
1560
|
+
|
|
1561
|
+
async function getBucketCORS(bucketName) {
|
|
1562
|
+
try {
|
|
1563
|
+
const response = await client.send(
|
|
1564
|
+
new GetBucketCorsCommand({
|
|
1565
|
+
Bucket: bucketName,
|
|
1566
|
+
})
|
|
1567
|
+
);
|
|
1568
|
+
|
|
1569
|
+
console.log("CORS Rules:", JSON.stringify(response.CORSRules, null, 2));
|
|
1570
|
+
return response.CORSRules;
|
|
1571
|
+
} catch (error) {
|
|
1572
|
+
console.error("Get CORS error:", error);
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
```
|
|
1576
|
+
|
|
1577
|
+
### Set Bucket Encryption
|
|
1578
|
+
|
|
1579
|
+
```javascript
|
|
1580
|
+
import { S3Client, PutBucketEncryptionCommand } from "@aws-sdk/client-s3";
|
|
1581
|
+
|
|
1582
|
+
const client = new S3Client({});
|
|
1583
|
+
|
|
1584
|
+
async function setBucketEncryption(bucketName) {
|
|
1585
|
+
try {
|
|
1586
|
+
await client.send(
|
|
1587
|
+
new PutBucketEncryptionCommand({
|
|
1588
|
+
Bucket: bucketName,
|
|
1589
|
+
ServerSideEncryptionConfiguration: {
|
|
1590
|
+
Rules: [
|
|
1591
|
+
{
|
|
1592
|
+
ApplyServerSideEncryptionByDefault: {
|
|
1593
|
+
SSEAlgorithm: "AES256",
|
|
1594
|
+
},
|
|
1595
|
+
},
|
|
1596
|
+
],
|
|
1597
|
+
},
|
|
1598
|
+
})
|
|
1599
|
+
);
|
|
1600
|
+
|
|
1601
|
+
console.log("Encryption enabled");
|
|
1602
|
+
} catch (error) {
|
|
1603
|
+
console.error("Encryption error:", error);
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
```
|
|
1607
|
+
|
|
1608
|
+
---
|
|
1609
|
+
|
|
1610
|
+
## Error Handling
|
|
1611
|
+
|
|
1612
|
+
### Common Error Types
|
|
1613
|
+
|
|
1614
|
+
```javascript
|
|
1615
|
+
import {
|
|
1616
|
+
S3Client,
|
|
1617
|
+
GetObjectCommand,
|
|
1618
|
+
NoSuchKey,
|
|
1619
|
+
NoSuchBucket,
|
|
1620
|
+
} from "@aws-sdk/client-s3";
|
|
1621
|
+
|
|
1622
|
+
const client = new S3Client({});
|
|
1623
|
+
|
|
1624
|
+
async function handleErrors(bucketName, key) {
|
|
1625
|
+
try {
|
|
1626
|
+
const response = await client.send(
|
|
1627
|
+
new GetObjectCommand({
|
|
1628
|
+
Bucket: bucketName,
|
|
1629
|
+
Key: key,
|
|
1630
|
+
})
|
|
1631
|
+
);
|
|
1632
|
+
|
|
1633
|
+
return await response.Body.transformToString();
|
|
1634
|
+
} catch (error) {
|
|
1635
|
+
if (error instanceof NoSuchKey) {
|
|
1636
|
+
console.error("Object not found");
|
|
1637
|
+
} else if (error instanceof NoSuchBucket) {
|
|
1638
|
+
console.error("Bucket not found");
|
|
1639
|
+
} else if (error.name === "AccessDenied") {
|
|
1640
|
+
console.error("Access denied");
|
|
1641
|
+
} else if (error.name === "InvalidAccessKeyId") {
|
|
1642
|
+
console.error("Invalid credentials");
|
|
1643
|
+
} else {
|
|
1644
|
+
console.error("Unknown error:", error);
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
throw error;
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
```
|
|
1651
|
+
|
|
1652
|
+
### Retry Logic
|
|
1653
|
+
|
|
1654
|
+
```javascript
|
|
1655
|
+
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
|
|
1656
|
+
|
|
1657
|
+
const client = new S3Client({
|
|
1658
|
+
maxAttempts: 3, // Built-in retry configuration
|
|
1659
|
+
});
|
|
1660
|
+
|
|
1661
|
+
async function downloadWithRetry(bucketName, key, maxRetries = 3) {
|
|
1662
|
+
let lastError;
|
|
1663
|
+
|
|
1664
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
1665
|
+
try {
|
|
1666
|
+
const response = await client.send(
|
|
1667
|
+
new GetObjectCommand({
|
|
1668
|
+
Bucket: bucketName,
|
|
1669
|
+
Key: key,
|
|
1670
|
+
})
|
|
1671
|
+
);
|
|
1672
|
+
|
|
1673
|
+
return await response.Body.transformToString();
|
|
1674
|
+
} catch (error) {
|
|
1675
|
+
lastError = error;
|
|
1676
|
+
console.log(`Attempt ${i + 1} failed, retrying...`);
|
|
1677
|
+
await new Promise((resolve) => setTimeout(resolve, 1000 * (i + 1)));
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
throw lastError;
|
|
1682
|
+
}
|
|
1683
|
+
```
|
|
1684
|
+
|
|
1685
|
+
---
|
|
1686
|
+
|
|
1687
|
+
## Complete Example: Full S3 Operations
|
|
1688
|
+
|
|
1689
|
+
```javascript
|
|
1690
|
+
import {
|
|
1691
|
+
S3Client,
|
|
1692
|
+
CreateBucketCommand,
|
|
1693
|
+
PutObjectCommand,
|
|
1694
|
+
GetObjectCommand,
|
|
1695
|
+
ListObjectsV2Command,
|
|
1696
|
+
DeleteObjectCommand,
|
|
1697
|
+
DeleteBucketCommand,
|
|
1698
|
+
} from "@aws-sdk/client-s3";
|
|
1699
|
+
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
1700
|
+
|
|
1701
|
+
const client = new S3Client({ region: "us-east-1" });
|
|
1702
|
+
const bucketName = `my-test-bucket-${Date.now()}`;
|
|
1703
|
+
|
|
1704
|
+
async function completeS3Example() {
|
|
1705
|
+
try {
|
|
1706
|
+
// 1. Create bucket
|
|
1707
|
+
console.log("Creating bucket...");
|
|
1708
|
+
await client.send(new CreateBucketCommand({ Bucket: bucketName }));
|
|
1709
|
+
|
|
1710
|
+
// 2. Upload object
|
|
1711
|
+
console.log("Uploading object...");
|
|
1712
|
+
await client.send(
|
|
1713
|
+
new PutObjectCommand({
|
|
1714
|
+
Bucket: bucketName,
|
|
1715
|
+
Key: "test-file.txt",
|
|
1716
|
+
Body: "Hello, S3!",
|
|
1717
|
+
ContentType: "text/plain",
|
|
1718
|
+
})
|
|
1719
|
+
);
|
|
1720
|
+
|
|
1721
|
+
// 3. Generate presigned URL
|
|
1722
|
+
console.log("Generating presigned URL...");
|
|
1723
|
+
const url = await getSignedUrl(
|
|
1724
|
+
client,
|
|
1725
|
+
new GetObjectCommand({
|
|
1726
|
+
Bucket: bucketName,
|
|
1727
|
+
Key: "test-file.txt",
|
|
1728
|
+
}),
|
|
1729
|
+
{ expiresIn: 3600 }
|
|
1730
|
+
);
|
|
1731
|
+
console.log("Presigned URL:", url);
|
|
1732
|
+
|
|
1733
|
+
// 4. Download object
|
|
1734
|
+
console.log("Downloading object...");
|
|
1735
|
+
const downloadResponse = await client.send(
|
|
1736
|
+
new GetObjectCommand({
|
|
1737
|
+
Bucket: bucketName,
|
|
1738
|
+
Key: "test-file.txt",
|
|
1739
|
+
})
|
|
1740
|
+
);
|
|
1741
|
+
const content = await downloadResponse.Body.transformToString();
|
|
1742
|
+
console.log("Content:", content);
|
|
1743
|
+
|
|
1744
|
+
// 5. List objects
|
|
1745
|
+
console.log("Listing objects...");
|
|
1746
|
+
const listResponse = await client.send(
|
|
1747
|
+
new ListObjectsV2Command({ Bucket: bucketName })
|
|
1748
|
+
);
|
|
1749
|
+
listResponse.Contents.forEach((obj) => {
|
|
1750
|
+
console.log(` • ${obj.Key}`);
|
|
1751
|
+
});
|
|
1752
|
+
|
|
1753
|
+
// 6. Delete object
|
|
1754
|
+
console.log("Deleting object...");
|
|
1755
|
+
await client.send(
|
|
1756
|
+
new DeleteObjectCommand({
|
|
1757
|
+
Bucket: bucketName,
|
|
1758
|
+
Key: "test-file.txt",
|
|
1759
|
+
})
|
|
1760
|
+
);
|
|
1761
|
+
|
|
1762
|
+
// 7. Delete bucket
|
|
1763
|
+
console.log("Deleting bucket...");
|
|
1764
|
+
await client.send(new DeleteBucketCommand({ Bucket: bucketName }));
|
|
1765
|
+
|
|
1766
|
+
console.log("Complete!");
|
|
1767
|
+
} catch (error) {
|
|
1768
|
+
console.error("Error:", error);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
completeS3Example();
|
|
1773
|
+
```
|