manage-storage 0.0.2
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/.env +7 -0
- package/README.md +427 -0
- package/bun.lock +230 -0
- package/manage-storage.js +265 -0
- package/package.json +42 -0
package/.env
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img width="350px" src="https://i.imgur.com/qEdTwly.png" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# Cloud Storage Manager
|
|
6
|
+
|
|
7
|
+
Universal cloud storage manager supporting AWS S3, Cloudflare R2, and Backblaze B2 with automatic provider detection. Built on the lightweight [@aws-lite](https://aws-lite.org/) SDK for optimal performance in serverless environments.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Multi-Cloud Support**: Works seamlessly with AWS S3, Cloudflare R2, and Backblaze B2
|
|
12
|
+
- **Auto-Detection**: Automatically detects the configured provider from environment variables
|
|
13
|
+
- **Lightweight**: Built on aws-lite (not the bloated AWS SDK) for faster cold starts
|
|
14
|
+
- **Simple API**: Single function interface for all storage operations
|
|
15
|
+
- **No File System**: Returns data directly - perfect for serverless/edge environments
|
|
16
|
+
- **TypeScript Ready**: Full type support (coming soon)
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install manage-storage
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
bun i manage-storage
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
import { manageStorage } from "manage-storage";
|
|
32
|
+
|
|
33
|
+
// Upload a file
|
|
34
|
+
await manageStorage("upload", {
|
|
35
|
+
key: "documents/report.pdf",
|
|
36
|
+
body: fileContent,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Download a file
|
|
40
|
+
const data = await manageStorage("download", {
|
|
41
|
+
key: "documents/report.pdf",
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// List all files
|
|
45
|
+
const files = await manageStorage("list");
|
|
46
|
+
|
|
47
|
+
// Delete a file
|
|
48
|
+
await manageStorage("delete", {
|
|
49
|
+
key: "documents/report.pdf",
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Configuration
|
|
54
|
+
|
|
55
|
+
Set environment variables for your preferred provider. The library will automatically detect which provider to use.
|
|
56
|
+
|
|
57
|
+
### Cloudflare R2
|
|
58
|
+
|
|
59
|
+
```env
|
|
60
|
+
R2_BUCKET_NAME=my-bucket
|
|
61
|
+
R2_ACCESS_KEY_ID=your-access-key-id
|
|
62
|
+
R2_SECRET_ACCESS_KEY=your-secret-access-key
|
|
63
|
+
R2_BUCKET_URL=https://your-account-id.r2.cloudflarestorage.com
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Backblaze B2
|
|
67
|
+
|
|
68
|
+
```env
|
|
69
|
+
B2_BUCKET_NAME=my-bucket
|
|
70
|
+
B2_ACCESS_KEY_ID=your-key-id
|
|
71
|
+
B2_SECRET_ACCESS_KEY=your-application-key
|
|
72
|
+
B2_BUCKET_URL=https://s3.us-west-004.backblazeb2.com
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### AWS S3
|
|
76
|
+
|
|
77
|
+
```env
|
|
78
|
+
S3_BUCKET_NAME=my-bucket
|
|
79
|
+
S3_ACCESS_KEY_ID=your-access-key-id
|
|
80
|
+
S3_SECRET_ACCESS_KEY=your-secret-access-key
|
|
81
|
+
S3_BUCKET_URL=https://s3.amazonaws.com
|
|
82
|
+
S3_REGION=us-east-1
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## API Reference
|
|
86
|
+
|
|
87
|
+
### `manageStorage(action, options)`
|
|
88
|
+
|
|
89
|
+
Performs storage operations on your configured cloud provider.
|
|
90
|
+
|
|
91
|
+
#### Parameters
|
|
92
|
+
|
|
93
|
+
- **action** `string` - The operation to perform: `'upload'`, `'download'`, `'delete'`, `'list'`, or `'deleteAll'`
|
|
94
|
+
- **options** `object` - Operation-specific options
|
|
95
|
+
|
|
96
|
+
#### Options
|
|
97
|
+
|
|
98
|
+
| Option | Type | Required | Description |
|
|
99
|
+
| ---------- | ------------------------ | ----------------------------------- | ---------------------------------------------------- |
|
|
100
|
+
| `key` | `string` | Yes (except for `list`/`deleteAll`) | The object key/path |
|
|
101
|
+
| `body` | `string\|Buffer\|Stream` | Yes (for `upload`) | The file content to upload |
|
|
102
|
+
| `provider` | `'s3'\|'r2'\|'b2'` | No | Force a specific provider (auto-detected if omitted) |
|
|
103
|
+
|
|
104
|
+
## Usage Examples
|
|
105
|
+
|
|
106
|
+
### 1. Upload Files
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
// Upload text content
|
|
110
|
+
await manageStorage("upload", {
|
|
111
|
+
key: "notes/memo.txt",
|
|
112
|
+
body: "Hello, World!",
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Upload Buffer
|
|
116
|
+
const buffer = Buffer.from("File contents");
|
|
117
|
+
await manageStorage("upload", {
|
|
118
|
+
key: "data/file.bin",
|
|
119
|
+
body: buffer,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Upload JSON
|
|
123
|
+
await manageStorage("upload", {
|
|
124
|
+
key: "config/settings.json",
|
|
125
|
+
body: JSON.stringify({ theme: "dark", lang: "en" }),
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 2. Download Files
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
// Download and get the raw data
|
|
133
|
+
const data = await manageStorage("download", {
|
|
134
|
+
key: "notes/memo.txt",
|
|
135
|
+
});
|
|
136
|
+
console.log(data); // "Hello, World!"
|
|
137
|
+
|
|
138
|
+
// Download JSON and parse
|
|
139
|
+
const configData = await manageStorage("download", {
|
|
140
|
+
key: "config/settings.json",
|
|
141
|
+
});
|
|
142
|
+
const config = JSON.parse(configData);
|
|
143
|
+
console.log(config.theme); // "dark"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### 3. List Files
|
|
147
|
+
|
|
148
|
+
```javascript
|
|
149
|
+
// List all files in the bucket
|
|
150
|
+
const files = await manageStorage("list");
|
|
151
|
+
console.log(files);
|
|
152
|
+
// Output: ['notes/memo.txt', 'data/file.bin', 'config/settings.json']
|
|
153
|
+
|
|
154
|
+
// Filter by prefix (folder)
|
|
155
|
+
const notes = files.filter((key) => key.startsWith("notes/"));
|
|
156
|
+
console.log(notes); // ['notes/memo.txt']
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### 4. Delete Files
|
|
160
|
+
|
|
161
|
+
```javascript
|
|
162
|
+
// Delete a single file
|
|
163
|
+
await manageStorage("delete", {
|
|
164
|
+
key: "notes/memo.txt",
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Delete all files in the bucket (use with caution!)
|
|
168
|
+
const result = await manageStorage("deleteAll");
|
|
169
|
+
console.log(`Deleted ${result.count} files`);
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 5. Force a Specific Provider
|
|
173
|
+
|
|
174
|
+
```javascript
|
|
175
|
+
// Use R2 even if other providers are configured
|
|
176
|
+
await manageStorage("upload", {
|
|
177
|
+
key: "test.txt",
|
|
178
|
+
body: "Hello R2!",
|
|
179
|
+
provider: "r2",
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Use B2 specifically
|
|
183
|
+
await manageStorage("upload", {
|
|
184
|
+
key: "test.txt",
|
|
185
|
+
body: "Hello B2!",
|
|
186
|
+
provider: "b2",
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 6. Runtime Configuration (Override Environment Variables)
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
// Pass credentials at runtime instead of using env vars
|
|
194
|
+
await manageStorage("upload", {
|
|
195
|
+
key: "secure/data.json",
|
|
196
|
+
body: JSON.stringify({ secret: "value" }),
|
|
197
|
+
provider: "r2",
|
|
198
|
+
BUCKET_NAME: "my-custom-bucket",
|
|
199
|
+
ACCESS_KEY_ID: "runtime-key-id",
|
|
200
|
+
SECRET_ACCESS_KEY: "runtime-secret",
|
|
201
|
+
BUCKET_URL: "https://custom-account.r2.cloudflarestorage.com",
|
|
202
|
+
});
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Advanced Examples
|
|
206
|
+
|
|
207
|
+
### Next.js API Route
|
|
208
|
+
|
|
209
|
+
```javascript
|
|
210
|
+
// app/api/upload/route.js
|
|
211
|
+
import { manageStorage } from "manage-storage";
|
|
212
|
+
|
|
213
|
+
export async function POST(req) {
|
|
214
|
+
const { fileName, fileContent } = await req.json();
|
|
215
|
+
|
|
216
|
+
const result = await manageStorage("upload", {
|
|
217
|
+
key: `uploads/${fileName}`,
|
|
218
|
+
body: fileContent,
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
return Response.json(result);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export async function GET(req) {
|
|
225
|
+
const { searchParams } = new URL(req.url);
|
|
226
|
+
const fileName = searchParams.get("file");
|
|
227
|
+
|
|
228
|
+
const data = await manageStorage("download", {
|
|
229
|
+
key: `uploads/${fileName}`,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
return new Response(data, {
|
|
233
|
+
headers: {
|
|
234
|
+
"Content-Type": "application/octet-stream",
|
|
235
|
+
"Content-Disposition": `attachment; filename="${fileName}"`,
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Express.js Endpoint
|
|
242
|
+
|
|
243
|
+
```javascript
|
|
244
|
+
import express from "express";
|
|
245
|
+
import { manageStorage } from "@opensourceagi/cloud-storage";
|
|
246
|
+
|
|
247
|
+
const app = express();
|
|
248
|
+
app.use(express.json());
|
|
249
|
+
|
|
250
|
+
app.post("/api/files", async (req, res) => {
|
|
251
|
+
try {
|
|
252
|
+
const { key, content } = req.body;
|
|
253
|
+
const result = await manageStorage("upload", { key, body: content });
|
|
254
|
+
res.json(result);
|
|
255
|
+
} catch (error) {
|
|
256
|
+
res.status(500).json({ error: error.message });
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
app.get("/api/files", async (req, res) => {
|
|
261
|
+
try {
|
|
262
|
+
const files = await manageStorage("list");
|
|
263
|
+
res.json({ files });
|
|
264
|
+
} catch (error) {
|
|
265
|
+
res.status(500).json({ error: error.message });
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
app.get("/api/files/:key", async (req, res) => {
|
|
270
|
+
try {
|
|
271
|
+
const data = await manageStorage("download", { key: req.params.key });
|
|
272
|
+
res.send(data);
|
|
273
|
+
} catch (error) {
|
|
274
|
+
res.status(500).json({ error: error.message });
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
app.delete("/api/files/:key", async (req, res) => {
|
|
279
|
+
try {
|
|
280
|
+
const result = await manageStorage("delete", { key: req.params.key });
|
|
281
|
+
res.json(result);
|
|
282
|
+
} catch (error) {
|
|
283
|
+
res.status(500).json({ error: error.message });
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
app.listen(3000, () => console.log("Server running on port 3000"));
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Cloudflare Workers
|
|
291
|
+
|
|
292
|
+
```javascript
|
|
293
|
+
import { manageStorage } from "@opensourceagi/cloud-storage";
|
|
294
|
+
|
|
295
|
+
export default {
|
|
296
|
+
async fetch(request, env) {
|
|
297
|
+
const url = new URL(request.url);
|
|
298
|
+
|
|
299
|
+
if (request.method === "POST" && url.pathname === "/upload") {
|
|
300
|
+
const { key, content } = await request.json();
|
|
301
|
+
|
|
302
|
+
const result = await manageStorage("upload", {
|
|
303
|
+
key,
|
|
304
|
+
body: content,
|
|
305
|
+
provider: "r2",
|
|
306
|
+
BUCKET_NAME: env.R2_BUCKET_NAME,
|
|
307
|
+
ACCESS_KEY_ID: env.R2_ACCESS_KEY_ID,
|
|
308
|
+
SECRET_ACCESS_KEY: env.R2_SECRET_ACCESS_KEY,
|
|
309
|
+
BUCKET_URL: env.R2_BUCKET_URL,
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
return Response.json(result);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return new Response("Not found", { status: 404 });
|
|
316
|
+
},
|
|
317
|
+
};
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Batch Operations
|
|
321
|
+
|
|
322
|
+
```javascript
|
|
323
|
+
// Upload multiple files
|
|
324
|
+
const files = [
|
|
325
|
+
{ key: "docs/file1.txt", content: "Content 1" },
|
|
326
|
+
{ key: "docs/file2.txt", content: "Content 2" },
|
|
327
|
+
{ key: "docs/file3.txt", content: "Content 3" },
|
|
328
|
+
];
|
|
329
|
+
|
|
330
|
+
await Promise.all(
|
|
331
|
+
files.map((file) =>
|
|
332
|
+
manageStorage("upload", { key: file.key, body: file.content })
|
|
333
|
+
)
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
// Download multiple files
|
|
337
|
+
const keys = ["docs/file1.txt", "docs/file2.txt", "docs/file3.txt"];
|
|
338
|
+
const contents = await Promise.all(
|
|
339
|
+
keys.map((key) => manageStorage("download", { key }))
|
|
340
|
+
);
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
## Return Values
|
|
344
|
+
|
|
345
|
+
### Upload
|
|
346
|
+
|
|
347
|
+
```javascript
|
|
348
|
+
{
|
|
349
|
+
success: true,
|
|
350
|
+
key: 'path/to/file.txt',
|
|
351
|
+
// ... additional provider-specific metadata
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Download
|
|
356
|
+
|
|
357
|
+
```javascript
|
|
358
|
+
// Returns the file content as a string
|
|
359
|
+
"File contents here...";
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Delete
|
|
363
|
+
|
|
364
|
+
```javascript
|
|
365
|
+
{
|
|
366
|
+
success: true,
|
|
367
|
+
key: 'path/to/file.txt'
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### List
|
|
372
|
+
|
|
373
|
+
```javascript
|
|
374
|
+
["folder/file1.txt", "folder/file2.txt", "another/file3.json"];
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### DeleteAll
|
|
378
|
+
|
|
379
|
+
```javascript
|
|
380
|
+
{
|
|
381
|
+
success: true,
|
|
382
|
+
count: 42
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## Why aws-lite?
|
|
387
|
+
|
|
388
|
+
This library uses [@aws-lite](https://aws-lite.org/) instead of the official AWS SDK because:
|
|
389
|
+
|
|
390
|
+
- **10-100x smaller**: Significantly reduced bundle size
|
|
391
|
+
- **Faster cold starts**: Critical for serverless/edge functions
|
|
392
|
+
- **S3-compatible**: Works with S3, R2, B2, and any S3-compatible service
|
|
393
|
+
- **Modern API**: Clean, promise-based interface
|
|
394
|
+
- **No dependencies overhead**: Minimal dependency tree
|
|
395
|
+
|
|
396
|
+
# Cloud Object Storage Comparison: GCS, Backblaze B2, Cloudflare R2, and AWS S3
|
|
397
|
+
|
|
398
|
+
Google Cloud Storage (GCS) joins Backblaze B2, Cloudflare R2, and AWS S3 as a hyperscaler option with [strong multi-region support](https://cloud.google.com/storage/pricing), multiple storage classes, and [deep integration with Google Cloud services](https://cloud.google.com/storage/pricing). These providers all [offer S3-compatible object storage](https://www.backblaze.com/cloud-storage/pricing) but differ significantly in [pricing models](https://www.backblaze.com/cloud-storage/pricing), especially storage costs, egress fees, and ecosystem fit.
|
|
399
|
+
|
|
400
|
+
## Updated pricing snapshot ("hot"/Standard storage)
|
|
401
|
+
|
|
402
|
+
| Service | Storage price (/TB-month) | Egress to internet | API ops (Class A/B per 1K, approx) | Minimum duration | Notes |
|
|
403
|
+
| --------------------------------------------------------------- | ------------------------------ | ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
404
|
+
| [Backblaze B2](https://www.backblaze.com/cloud-storage/pricing) | **$6** | [Free up to 3x stored/mo](https://www.backblaze.com/cloud-storage/pricing), then $0.01/GB | [Free quotas](https://www.backblaze.com/cloud-storage/pricing); then ~$0.004/10K B | [None](https://www.backblaze.com/cloud-storage/pricing) | Lowest storage; generous egress. |
|
|
405
|
+
| [Cloudflare R2](https://developers.cloudflare.com/r2/pricing/) | **$15** | [**Zero**](https://www.cloudflare.com/pg-cloudflare-r2-vs-aws-s3/) | [~$4.50/M A; $0.36/M B](https://developers.cloudflare.com/r2/pricing/) | None | No bandwidth bills. |
|
|
406
|
+
| [AWS S3 Standard](https://aws.amazon.com/s3/pricing/) | **$23** | [Tiered ~$0.09/GB first 10TB](https://www.nops.io/blog/aws-s3-pricing/) | [~$5/M A; $0.4/M B](https://aws.amazon.com/s3/pricing/) | None | Ecosystem premium. |
|
|
407
|
+
| [Google GCS Standard](https://cloud.google.com/storage/pricing) | **$20-26** (region/dual/multi) | [Tiered ~$0.08-0.12/GB worldwide](https://cloud.google.com/storage/pricing) | [$5/1K A; $0.4/1K B (Standard)](https://cloud.google.com/storage/pricing) | [None (Standard)](https://cloud.google.com/storage/pricing) | Multi-region ~$26; cheaper classes available (Nearline $10, etc.). |
|
|
408
|
+
|
|
409
|
+
## Feature comparison
|
|
410
|
+
|
|
411
|
+
| Aspect | Backblaze B2 | Cloudflare R2 | AWS S3 | Google GCS |
|
|
412
|
+
| -------------------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
413
|
+
| **Ecosystem** | [Standalone; partners (Fastly, Vultr)](https://www.backblaze.com/cloud-storage/pricing) | [Cloudflare Workers/CDN/Zero Trust](https://www.cloudflare.com/developer-platform/products/r2/) | [Full AWS (Lambda, EC2, Athena)](https://aws.amazon.com/s3/pricing/) | [Full GCP (GKE, BigQuery, AI/ML)](https://cloud.google.com/storage/pricing) |
|
|
414
|
+
| **Storage classes** | [Single hot](https://www.backblaze.com/cloud-storage/pricing) | [Single](https://developers.cloudflare.com/r2/pricing/) | [Many (IA, Glacier, Intelligent)](https://aws.amazon.com/s3/pricing/) | [Standard, Nearline, Coldline, Archive](https://cloud.google.com/storage/pricing) |
|
|
415
|
+
| **S3 compatibility** | [Strong](https://onidel.com/blog/cloudflare-r2-vs-backblaze-b2) | [Excellent (99% ops)](https://onidel.com/blog/cloudflare-r2-vs-backblaze-b2) | [Native](https://aws.amazon.com/s3/pricing/) | [Strong](https://cloud.google.com/storage/pricing) |
|
|
416
|
+
| **Lifecycle mgmt** | [Basic rules](https://onidel.com/blog/cloudflare-r2-vs-backblaze-b2) | [Basic expiration](https://onidel.com/blog/cloudflare-r2-vs-backblaze-b2) | [Advanced](https://aws.amazon.com/s3/pricing/) | [Advanced, Autoclass](https://cloud.google.com/storage/pricing) |
|
|
417
|
+
| **Object Lock** | [Yes (compliance/gov)](https://onidel.com/blog/cloudflare-r2-vs-backblaze-b2) | [Limited](https://onidel.com/blog/cloudflare-r2-vs-backblaze-b2) | [Yes](https://onidel.com/blog/cloudflare-r2-vs-backblaze-b2) | [Yes (via retention)](https://cloud.google.com/storage/pricing) |
|
|
418
|
+
| **Free tier** | [First 10GB](https://www.backblaze.com/cloud-storage/pricing) | [10GB storage, 1M Class A/mo](https://developers.cloudflare.com/r2/pricing/) | [Limited](https://aws.amazon.com/s3/pricing/) | 5GB-months Standard |
|
|
419
|
+
|
|
420
|
+
## Core use-case fit
|
|
421
|
+
|
|
422
|
+
- **[Backblaze B2](https://www.backblaze.com/cloud-storage)**: [Cheapest for bulk/hot storage](https://onidel.com/blog/cloudflare-r2-vs-backblaze-b2) with moderate egress (backups, media archives); simple, [no vendor lock-in](https://www.backblaze.com/cloud-storage).
|
|
423
|
+
- **[Cloudflare R2](https://developers.cloudflare.com/r2/pricing/)**: [Public-facing assets/images/APIs](https://www.cloudflare.com/pg-cloudflare-r2-vs-aws-s3/) with high traffic; [zero egress](https://www.cloudflare.com/developer-platform/products/r2/) saves big on [web delivery](https://onidel.com/blog/cloudflare-r2-vs-backblaze-b2).
|
|
424
|
+
- **[AWS S3](https://aws.amazon.com/s3/pricing/)**: [AWS-centric apps](https://www.nops.io/blog/aws-s3-pricing/) needing [advanced analytics, replication, compliance](https://cloudian.com/blog/5-components-of-aws-s3-storage-pricing/); [pay for features/ecosystem](https://onidel.com/blog/cloudflare-r2-vs-backblaze-b2).
|
|
425
|
+
- **[Google GCS](https://cloud.google.com/storage/pricing)**: [GCP workloads](https://cloud.google.com/storage/pricing) (BigQuery, AI, Kubernetes); [multi-region needs](https://onidel.com/blog/cloudflare-r2-vs-backblaze-b2) or tiered classes for cost optimization.
|
|
426
|
+
|
|
427
|
+
Backblaze wins on raw storage cost, R2 on bandwidth-heavy apps, while AWS/GCS suit enterprise ecosystems with richer tools. For exact costs, use [calculators](https://r2-calculator.cloudflare.com) with your workload (e.g., [TB stored](https://www.backblaze.com/cloud-storage/pricing), [TB egress](https://onidel.com/blog/cloudflare-r2-vs-backblaze-b2), [ops volume](https://aws.amazon.com/s3/pricing/)).
|
package/bun.lock
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"configVersion": 1,
|
|
4
|
+
"workspaces": {
|
|
5
|
+
"": {
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@aws-lite/client": "^0.23.2",
|
|
8
|
+
"@aws-sdk/client-s3": "^3.965.0",
|
|
9
|
+
"dotenv": "^17.2.3",
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
"packages": {
|
|
14
|
+
"@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="],
|
|
15
|
+
|
|
16
|
+
"@aws-crypto/crc32c": ["@aws-crypto/crc32c@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag=="],
|
|
17
|
+
|
|
18
|
+
"@aws-crypto/sha1-browser": ["@aws-crypto/sha1-browser@5.2.0", "", { "dependencies": { "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg=="],
|
|
19
|
+
|
|
20
|
+
"@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="],
|
|
21
|
+
|
|
22
|
+
"@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="],
|
|
23
|
+
|
|
24
|
+
"@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg=="],
|
|
25
|
+
|
|
26
|
+
"@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="],
|
|
27
|
+
|
|
28
|
+
"@aws-lite/client": ["@aws-lite/client@0.23.2", "", { "dependencies": { "aws4": "^1.13.2" } }, "sha512-K7QgDnYZfe5dTLzZPq9ZSVtpQjT3gPvowJrtzXLZxpKPPWUsyeMbUvtOgfCNemSCH2xK1YCVh7YsLNtYb6ZYtw=="],
|
|
29
|
+
|
|
30
|
+
"@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.965.0", "", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.965.0", "@aws-sdk/credential-provider-node": "3.965.0", "@aws-sdk/middleware-bucket-endpoint": "3.965.0", "@aws-sdk/middleware-expect-continue": "3.965.0", "@aws-sdk/middleware-flexible-checksums": "3.965.0", "@aws-sdk/middleware-host-header": "3.965.0", "@aws-sdk/middleware-location-constraint": "3.965.0", "@aws-sdk/middleware-logger": "3.965.0", "@aws-sdk/middleware-recursion-detection": "3.965.0", "@aws-sdk/middleware-sdk-s3": "3.965.0", "@aws-sdk/middleware-ssec": "3.965.0", "@aws-sdk/middleware-user-agent": "3.965.0", "@aws-sdk/region-config-resolver": "3.965.0", "@aws-sdk/signature-v4-multi-region": "3.965.0", "@aws-sdk/types": "3.965.0", "@aws-sdk/util-endpoints": "3.965.0", "@aws-sdk/util-user-agent-browser": "3.965.0", "@aws-sdk/util-user-agent-node": "3.965.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/eventstream-serde-browser": "^4.2.7", "@smithy/eventstream-serde-config-resolver": "^4.3.7", "@smithy/eventstream-serde-node": "^4.2.7", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-blob-browser": "^4.2.8", "@smithy/hash-node": "^4.2.7", "@smithy/hash-stream-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/md5-js": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-retry": "^4.4.17", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.16", "@smithy/util-defaults-mode-node": "^4.2.19", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-BTeaaU1iK0BfatTCrtYjNkIHCoZH256qOI18l9bK4z6mVOgpHkYN4RvOu+NnKgyX58n+HWfOuhtKUD4OE33Vdw=="],
|
|
31
|
+
|
|
32
|
+
"@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.965.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.965.0", "@aws-sdk/middleware-host-header": "3.965.0", "@aws-sdk/middleware-logger": "3.965.0", "@aws-sdk/middleware-recursion-detection": "3.965.0", "@aws-sdk/middleware-user-agent": "3.965.0", "@aws-sdk/region-config-resolver": "3.965.0", "@aws-sdk/types": "3.965.0", "@aws-sdk/util-endpoints": "3.965.0", "@aws-sdk/util-user-agent-browser": "3.965.0", "@aws-sdk/util-user-agent-node": "3.965.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-retry": "^4.4.17", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.16", "@smithy/util-defaults-mode-node": "^4.2.19", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-iv2tr+n4aZ+nPUFFvG00hISPuEd4DU+1/Q8rPAYKXsM+vEPJ2nAnP5duUOa2fbOLIUCRxX3dcQaQaghVHDHzQw=="],
|
|
33
|
+
|
|
34
|
+
"@aws-sdk/core": ["@aws-sdk/core@3.965.0", "", { "dependencies": { "@aws-sdk/types": "3.965.0", "@aws-sdk/xml-builder": "3.965.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-aq9BhQxdHit8UUJ9C0im9TtuKeK0pT6NXmNJxMTCFeStI7GG7ImIsSislg3BZTIifVg1P6VLdzMyz9de85iutQ=="],
|
|
35
|
+
|
|
36
|
+
"@aws-sdk/crc64-nvme": ["@aws-sdk/crc64-nvme@3.965.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-9FbIyJ/Zz1AdEIrb0+Pn7wRi+F/0Y566ooepg0hDyHUzRV3ZXKjOlu3wJH3YwTz2UkdwQmldfUos2yDJps7RyA=="],
|
|
37
|
+
|
|
38
|
+
"@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.965.0", "", { "dependencies": { "@aws-sdk/core": "3.965.0", "@aws-sdk/types": "3.965.0", "@smithy/property-provider": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-mdGnaIjMxTIjsb70dEj3VsWPWpoq1V5MWzBSfJq2H8zgMBXjn6d5/qHP8HMf53l9PrsgqzMpXGv3Av549A2x1g=="],
|
|
39
|
+
|
|
40
|
+
"@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.965.0", "", { "dependencies": { "@aws-sdk/core": "3.965.0", "@aws-sdk/types": "3.965.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-YuGQel9EgA/z25oeLM+GYYQS750+8AESvr7ZEmVnRPL0sg+K3DmGqdv+9gFjFd0UkLjTlC/jtbP2cuY6UcPiHQ=="],
|
|
41
|
+
|
|
42
|
+
"@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.965.0", "", { "dependencies": { "@aws-sdk/core": "3.965.0", "@aws-sdk/credential-provider-env": "3.965.0", "@aws-sdk/credential-provider-http": "3.965.0", "@aws-sdk/credential-provider-login": "3.965.0", "@aws-sdk/credential-provider-process": "3.965.0", "@aws-sdk/credential-provider-sso": "3.965.0", "@aws-sdk/credential-provider-web-identity": "3.965.0", "@aws-sdk/nested-clients": "3.965.0", "@aws-sdk/types": "3.965.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-xRo72Prer5s0xYVSCxCymVIRSqrVlevK5cmU0GWq9yJtaBNpnx02jwdJg80t/Ni7pgbkQyFWRMcq38c1tc6M/w=="],
|
|
43
|
+
|
|
44
|
+
"@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.965.0", "", { "dependencies": { "@aws-sdk/core": "3.965.0", "@aws-sdk/nested-clients": "3.965.0", "@aws-sdk/types": "3.965.0", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-43/H8Qku8LHyugbhLo8kjD+eauhybCeVkmrnvWl8bXNHJP7xi1jCdtBQJKKJqiIHZws4MOEwkji8kFdAVRCe6g=="],
|
|
45
|
+
|
|
46
|
+
"@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.965.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.965.0", "@aws-sdk/credential-provider-http": "3.965.0", "@aws-sdk/credential-provider-ini": "3.965.0", "@aws-sdk/credential-provider-process": "3.965.0", "@aws-sdk/credential-provider-sso": "3.965.0", "@aws-sdk/credential-provider-web-identity": "3.965.0", "@aws-sdk/types": "3.965.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-cRxmMHF+Zh2lkkkEVduKl+8OQdtg/DhYA69+/7SPSQURlgyjFQGlRQ58B7q8abuNlrGT3sV+UzeOylZpJbV61Q=="],
|
|
47
|
+
|
|
48
|
+
"@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.965.0", "", { "dependencies": { "@aws-sdk/core": "3.965.0", "@aws-sdk/types": "3.965.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-gmkPmdiR0yxnTzLPDb7rwrDhGuCUjtgnj8qWP+m0gSz/W43rR4jRPVEf6DUX2iC+ImQhxo3NFhuB3V42Kzo3TQ=="],
|
|
49
|
+
|
|
50
|
+
"@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.965.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.965.0", "@aws-sdk/core": "3.965.0", "@aws-sdk/token-providers": "3.965.0", "@aws-sdk/types": "3.965.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-N01AYvtCqG3Wo/s/LvYt19ity18/FqggiXT+elAs3X9Om/Wfx+hw9G+i7jaDmy+/xewmv8AdQ2SK5Q30dXw/Fw=="],
|
|
51
|
+
|
|
52
|
+
"@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.965.0", "", { "dependencies": { "@aws-sdk/core": "3.965.0", "@aws-sdk/nested-clients": "3.965.0", "@aws-sdk/types": "3.965.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-T4gMZ2JzXnfxe1oTD+EDGLSxFfk1+WkLZdiHXEMZp8bFI1swP/3YyDFXI+Ib9Uq1JhnAmrCXtOnkicKEhDkdhQ=="],
|
|
53
|
+
|
|
54
|
+
"@aws-sdk/middleware-bucket-endpoint": ["@aws-sdk/middleware-bucket-endpoint@3.965.0", "", { "dependencies": { "@aws-sdk/types": "3.965.0", "@aws-sdk/util-arn-parser": "3.965.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-gbdv3Dl8l8xmg4oH60fXvfDyTxfx28w5/Hxdymx3vurM07tAyd4qld8zEXejnSpraTo45QcHRtk5auELIMfeag=="],
|
|
55
|
+
|
|
56
|
+
"@aws-sdk/middleware-expect-continue": ["@aws-sdk/middleware-expect-continue@3.965.0", "", { "dependencies": { "@aws-sdk/types": "3.965.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-UBxVytsmhEmFwkBnt+aV0eAJ7uc+ouNokCqMBrQ7Oc5A77qhlcHfOgXIKz2SxqsiYTsDq+a0lWFM/XpyRWraqA=="],
|
|
57
|
+
|
|
58
|
+
"@aws-sdk/middleware-flexible-checksums": ["@aws-sdk/middleware-flexible-checksums@3.965.0", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", "@aws-sdk/core": "3.965.0", "@aws-sdk/crc64-nvme": "3.965.0", "@aws-sdk/types": "3.965.0", "@smithy/is-array-buffer": "^4.2.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-5rzEW08trcpHMe6jkQyYc4PL1KG/H7BbnySFSzhih+r/gktQEiE36sb1BNf7av9I0Vk2Ccmt7wocB5PIT7GDkQ=="],
|
|
59
|
+
|
|
60
|
+
"@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.965.0", "", { "dependencies": { "@aws-sdk/types": "3.965.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-SfpSYqoPOAmdb3DBsnNsZ0vix+1VAtkUkzXM79JL3R5IfacpyKE2zytOgVAQx/FjhhlpSTwuXd+LRhUEVb3MaA=="],
|
|
61
|
+
|
|
62
|
+
"@aws-sdk/middleware-location-constraint": ["@aws-sdk/middleware-location-constraint@3.965.0", "", { "dependencies": { "@aws-sdk/types": "3.965.0", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-07T1rwAarQs33mVg5U28AsSdLB5JUXu9yBTBmspFGajKVsEahIyntf53j9mAXF1N2KR0bNdP0J4A0kst4t43UQ=="],
|
|
63
|
+
|
|
64
|
+
"@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.965.0", "", { "dependencies": { "@aws-sdk/types": "3.965.0", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-gjUvJRZT1bUABKewnvkj51LAynFrfz2h5DYAg5/2F4Utx6UOGByTSr9Rq8JCLbURvvzAbCtcMkkIJRxw+8Zuzw=="],
|
|
65
|
+
|
|
66
|
+
"@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.965.0", "", { "dependencies": { "@aws-sdk/types": "3.965.0", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-6dvD+18Ni14KCRu+tfEoNxq1sIGVp9tvoZDZ7aMvpnA7mDXuRLrOjRQ/TAZqXwr9ENKVGyxcPl0cRK8jk1YWjA=="],
|
|
67
|
+
|
|
68
|
+
"@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.965.0", "", { "dependencies": { "@aws-sdk/core": "3.965.0", "@aws-sdk/types": "3.965.0", "@aws-sdk/util-arn-parser": "3.965.0", "@smithy/core": "^3.20.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-dXEgnojaaVRl+OlOx35mg3rYEbfffIN4X6tLmIfDnaKz0hMaDMvsE9jJXb/vBvokbdO1sVB27/2FEM4ttLSLnw=="],
|
|
69
|
+
|
|
70
|
+
"@aws-sdk/middleware-ssec": ["@aws-sdk/middleware-ssec@3.965.0", "", { "dependencies": { "@aws-sdk/types": "3.965.0", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-dke++CTw26y+a2D1DdVuZ4+2TkgItdx6TeuE0zOl4lsqXGvTBUG4eaIZalt7ZOAW5ys2pbDOk1bPuh4opoD3pQ=="],
|
|
71
|
+
|
|
72
|
+
"@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.965.0", "", { "dependencies": { "@aws-sdk/core": "3.965.0", "@aws-sdk/types": "3.965.0", "@aws-sdk/util-endpoints": "3.965.0", "@smithy/core": "^3.20.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-RBEYVGgu/WeAt+H/qLrGc+t8LqAUkbyvh3wBfTiuAD+uBcWsKnvnB1iSBX75FearC0fmoxzXRUc0PMxMdqpjJQ=="],
|
|
73
|
+
|
|
74
|
+
"@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.965.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.965.0", "@aws-sdk/middleware-host-header": "3.965.0", "@aws-sdk/middleware-logger": "3.965.0", "@aws-sdk/middleware-recursion-detection": "3.965.0", "@aws-sdk/middleware-user-agent": "3.965.0", "@aws-sdk/region-config-resolver": "3.965.0", "@aws-sdk/types": "3.965.0", "@aws-sdk/util-endpoints": "3.965.0", "@aws-sdk/util-user-agent-browser": "3.965.0", "@aws-sdk/util-user-agent-node": "3.965.0", "@smithy/config-resolver": "^4.4.5", "@smithy/core": "^3.20.0", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", "@smithy/middleware-endpoint": "^4.4.1", "@smithy/middleware-retry": "^4.4.17", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", "@smithy/smithy-client": "^4.10.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.16", "@smithy/util-defaults-mode-node": "^4.2.19", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-muNVUjUEU+/KLFrLzQ8PMXyw4+a/MP6t4GIvwLtyx/kH0rpSy5s0YmqacMXheuIe6F/5QT8uksXGNAQenitkGQ=="],
|
|
75
|
+
|
|
76
|
+
"@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.965.0", "", { "dependencies": { "@aws-sdk/types": "3.965.0", "@smithy/config-resolver": "^4.4.5", "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-RoMhu9ly2B0coxn8ctXosPP2WmDD0MkQlZGLjoYHQUOCBmty5qmCxOqBmBDa6wbWbB8xKtMQ/4VXloQOgzjHXg=="],
|
|
77
|
+
|
|
78
|
+
"@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.965.0", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "3.965.0", "@aws-sdk/types": "3.965.0", "@smithy/protocol-http": "^5.3.7", "@smithy/signature-v4": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-hgbAThbsUrWtNpFBQxzXevIfd5Qgr4TLbXY1AIbmpSX9fPVC114pdieRMpopJ0fYaJ7v5/blTiS6wzVdXleZ/w=="],
|
|
79
|
+
|
|
80
|
+
"@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.965.0", "", { "dependencies": { "@aws-sdk/core": "3.965.0", "@aws-sdk/nested-clients": "3.965.0", "@aws-sdk/types": "3.965.0", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-aR0qxg0b8flkXJVE+CM1gzo7uJ57md50z2eyCwofC0QIz5Y0P7/7vvb9/dmUQt6eT9XRN5iRcUqq2IVxVDvJOw=="],
|
|
81
|
+
|
|
82
|
+
"@aws-sdk/types": ["@aws-sdk/types@3.965.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-jvodoJdMavvg8faN7co58vVJRO5MVep4JFPRzUNCzpJ98BDqWDk/ad045aMJcmxkLzYLS2UAnUmqjJ/tUPNlzQ=="],
|
|
83
|
+
|
|
84
|
+
"@aws-sdk/util-arn-parser": ["@aws-sdk/util-arn-parser@3.965.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-bNGKr5Tct28jGLkL8xIkGu7swpDgBpkTVbGaofhzr/X80iclbOv656RGxhMpDvmc4S9UuQnqLRXyceNFNF2V7Q=="],
|
|
85
|
+
|
|
86
|
+
"@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.965.0", "", { "dependencies": { "@aws-sdk/types": "3.965.0", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-endpoints": "^3.2.7", "tslib": "^2.6.2" } }, "sha512-WqSCB0XIsGUwZWvrYkuoofi2vzoVHqyeJ2kN+WyoOsxPLTiQSBIoqm/01R/qJvoxwK/gOOF7su9i84Vw2NQQpQ=="],
|
|
87
|
+
|
|
88
|
+
"@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.965.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-9LJFand4bIoOjOF4x3wx0UZYiFZRo4oUauxQSiEX2dVg+5qeBOJSjp2SeWykIE6+6frCZ5wvWm2fGLK8D32aJw=="],
|
|
89
|
+
|
|
90
|
+
"@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.965.0", "", { "dependencies": { "@aws-sdk/types": "3.965.0", "@smithy/types": "^4.11.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-Xiza/zMntQGpkd2dETQeAK8So1pg5+STTzpcdGWxj5q0jGO5ayjqT/q1Q7BrsX5KIr6PvRkl9/V7lLCv04wGjQ=="],
|
|
91
|
+
|
|
92
|
+
"@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.965.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.965.0", "@aws-sdk/types": "3.965.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-kokIHUfNT3/P55E4fUJJrFHuuA9BbjFKUIxoLrd3UaRfdafT0ScRfg2eaZie6arf60EuhlUIZH0yALxttMEjxQ=="],
|
|
93
|
+
|
|
94
|
+
"@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.965.0", "", { "dependencies": { "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-Tcod25/BTupraQwtb+Q+GX8bmEZfxIFjjJ/AvkhUZsZlkPeVluzq1uu3Oeqf145DCdMjzLIN6vab5MrykbDP+g=="],
|
|
95
|
+
|
|
96
|
+
"@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.2", "", {}, "sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg=="],
|
|
97
|
+
|
|
98
|
+
"@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="],
|
|
99
|
+
|
|
100
|
+
"@smithy/chunked-blob-reader": ["@smithy/chunked-blob-reader@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA=="],
|
|
101
|
+
|
|
102
|
+
"@smithy/chunked-blob-reader-native": ["@smithy/chunked-blob-reader-native@4.2.1", "", { "dependencies": { "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ=="],
|
|
103
|
+
|
|
104
|
+
"@smithy/config-resolver": ["@smithy/config-resolver@4.4.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-HAGoUAFYsUkoSckuKbCPayECeMim8pOu+yLy1zOxt1sifzEbrsRpYa+mKcMdiHKMeiqOibyPG0sFJnmaV/OGEg=="],
|
|
105
|
+
|
|
106
|
+
"@smithy/core": ["@smithy/core@3.20.1", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.8", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-wOboSEdQ85dbKAJ0zL+wQ6b0HTSBRhtGa0PYKysQXkRg+vK0tdCRRVruiFM2QMprkOQwSYOnwF4og96PAaEGag=="],
|
|
107
|
+
|
|
108
|
+
"@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-CmduWdCiILCRNbQWFR0OcZlUPVtyE49Sr8yYL0rZQ4D/wKxiNzBNS/YHemvnbkIWj623fplgkexUd/c9CAKdoA=="],
|
|
109
|
+
|
|
110
|
+
"@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.7", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DrpkEoM3j9cBBWhufqBwnbbn+3nf1N9FP6xuVJ+e220jbactKuQgaZwjwP5CP1t+O94brm2JgVMD2atMGX3xIQ=="],
|
|
111
|
+
|
|
112
|
+
"@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.7", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-ujzPk8seYoDBmABDE5YqlhQZAXLOrtxtJLrbhHMKjBoG5b4dK4i6/mEU+6/7yXIAkqOO8sJ6YxZl+h0QQ1IJ7g=="],
|
|
113
|
+
|
|
114
|
+
"@smithy/eventstream-serde-config-resolver": ["@smithy/eventstream-serde-config-resolver@4.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-x7BtAiIPSaNaWuzm24Q/mtSkv+BrISO/fmheiJ39PKRNH3RmH2Hph/bUKSOBOBC9unqfIYDhKTHwpyZycLGPVQ=="],
|
|
115
|
+
|
|
116
|
+
"@smithy/eventstream-serde-node": ["@smithy/eventstream-serde-node@4.2.7", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-roySCtHC5+pQq5lK4be1fZ/WR6s/AxnPaLfCODIPArtN2du8s5Ot4mKVK3pPtijL/L654ws592JHJ1PbZFF6+A=="],
|
|
117
|
+
|
|
118
|
+
"@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.7", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-QVD+g3+icFkThoy4r8wVFZMsIP08taHVKjE6Jpmz8h5CgX/kk6pTODq5cht0OMtcapUx+xrPzUTQdA+TmO0m1g=="],
|
|
119
|
+
|
|
120
|
+
"@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg=="],
|
|
121
|
+
|
|
122
|
+
"@smithy/hash-blob-browser": ["@smithy/hash-blob-browser@4.2.8", "", { "dependencies": { "@smithy/chunked-blob-reader": "^5.2.0", "@smithy/chunked-blob-reader-native": "^4.2.1", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-07InZontqsM1ggTCPSRgI7d8DirqRrnpL7nIACT4PW0AWrgDiHhjGZzbAE5UtRSiU0NISGUYe7/rri9ZeWyDpw=="],
|
|
123
|
+
|
|
124
|
+
"@smithy/hash-node": ["@smithy/hash-node@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-PU/JWLTBCV1c8FtB8tEFnY4eV1tSfBc7bDBADHfn1K+uRbPgSJ9jnJp0hyjiFN2PMdPzxsf1Fdu0eo9fJ760Xw=="],
|
|
125
|
+
|
|
126
|
+
"@smithy/hash-stream-node": ["@smithy/hash-stream-node@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ZQVoAwNYnFMIbd4DUc517HuwNelJUY6YOzwqrbcAgCnVn+79/OK7UjwA93SPpdTOpKDVkLIzavWm/Ck7SmnDPQ=="],
|
|
127
|
+
|
|
128
|
+
"@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-ncvgCr9a15nPlkhIUx3CU4d7E7WEuVJOV7fS7nnK2hLtPK9tYRBkMHQbhXU1VvvKeBm/O0x26OEoBq+ngFpOEQ=="],
|
|
129
|
+
|
|
130
|
+
"@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="],
|
|
131
|
+
|
|
132
|
+
"@smithy/md5-js": ["@smithy/md5-js@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Wv6JcUxtOLTnxvNjDnAiATUsk8gvA6EeS8zzHig07dotpByYsLot+m0AaQEniUBjx97AC41MQR4hW0baraD1Xw=="],
|
|
133
|
+
|
|
134
|
+
"@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.7", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-GszfBfCcvt7kIbJ41LuNa5f0wvQCHhnGx/aDaZJCCT05Ld6x6U2s0xsc/0mBFONBZjQJp2U/0uSJ178OXOwbhg=="],
|
|
135
|
+
|
|
136
|
+
"@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.2", "", { "dependencies": { "@smithy/core": "^3.20.1", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" } }, "sha512-mqpAdux0BNmZu/SqkFhQEnod4fX23xxTvU2LUpmKp0JpSI+kPYCiHJMmzREr8yxbNxKL2/DU1UZm9i++ayU+2g=="],
|
|
137
|
+
|
|
138
|
+
"@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.18", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/service-error-classification": "^4.2.7", "@smithy/smithy-client": "^4.10.3", "@smithy/types": "^4.11.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-E5hulijA59nBk/zvcwVMaS7FG7Y4l6hWA9vrW018r+8kiZef4/ETQaPI4oY+3zsy9f6KqDv3c4VKtO4DwwgpCg=="],
|
|
139
|
+
|
|
140
|
+
"@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.8", "", { "dependencies": { "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w=="],
|
|
141
|
+
|
|
142
|
+
"@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw=="],
|
|
143
|
+
|
|
144
|
+
"@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.7", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw=="],
|
|
145
|
+
|
|
146
|
+
"@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/querystring-builder": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ=="],
|
|
147
|
+
|
|
148
|
+
"@smithy/property-provider": ["@smithy/property-provider@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-jmNYKe9MGGPoSl/D7JDDs1C8b3dC8f/w78LbaVfoTtWy4xAd5dfjaFG9c9PWPihY4ggMQNQSMtzU77CNgAJwmA=="],
|
|
149
|
+
|
|
150
|
+
"@smithy/protocol-http": ["@smithy/protocol-http@5.3.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA=="],
|
|
151
|
+
|
|
152
|
+
"@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg=="],
|
|
153
|
+
|
|
154
|
+
"@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w=="],
|
|
155
|
+
|
|
156
|
+
"@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0" } }, "sha512-YB7oCbukqEb2Dlh3340/8g8vNGbs/QsNNRms+gv3N2AtZz9/1vSBx6/6tpwQpZMEJFs7Uq8h4mmOn48ZZ72MkA=="],
|
|
157
|
+
|
|
158
|
+
"@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.2", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg=="],
|
|
159
|
+
|
|
160
|
+
"@smithy/signature-v4": ["@smithy/signature-v4@5.3.7", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg=="],
|
|
161
|
+
|
|
162
|
+
"@smithy/smithy-client": ["@smithy/smithy-client@4.10.3", "", { "dependencies": { "@smithy/core": "^3.20.1", "@smithy/middleware-endpoint": "^4.4.2", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" } }, "sha512-EfECiO/0fAfb590LBnUe7rI5ux7XfquQ8LBzTe7gxw0j9QW/q8UT/EHWHlxV/+jhQ3+Ssga9uUYXCQgImGMbNg=="],
|
|
163
|
+
|
|
164
|
+
"@smithy/types": ["@smithy/types@4.11.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA=="],
|
|
165
|
+
|
|
166
|
+
"@smithy/url-parser": ["@smithy/url-parser@4.2.7", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg=="],
|
|
167
|
+
|
|
168
|
+
"@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="],
|
|
169
|
+
|
|
170
|
+
"@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="],
|
|
171
|
+
|
|
172
|
+
"@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="],
|
|
173
|
+
|
|
174
|
+
"@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="],
|
|
175
|
+
|
|
176
|
+
"@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="],
|
|
177
|
+
|
|
178
|
+
"@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.17", "", { "dependencies": { "@smithy/property-provider": "^4.2.7", "@smithy/smithy-client": "^4.10.3", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-dwN4GmivYF1QphnP3xJESXKtHvkkvKHSZI8GrSKMVoENVSKW2cFPRYC4ZgstYjUHdR3zwaDkIaTDIp26JuY7Cw=="],
|
|
179
|
+
|
|
180
|
+
"@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.20", "", { "dependencies": { "@smithy/config-resolver": "^4.4.5", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", "@smithy/smithy-client": "^4.10.3", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-VD/I4AEhF1lpB3B//pmOIMBNLMrtdMXwy9yCOfa2QkJGDr63vH3RqPbSAKzoGMov3iryCxTXCxSsyGmEB8PDpg=="],
|
|
181
|
+
|
|
182
|
+
"@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.7", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-s4ILhyAvVqhMDYREeTS68R43B1V5aenV5q/V1QpRQJkCXib5BPRo4s7uNdzGtIKxaPHCfU/8YkvPAEvTpxgspg=="],
|
|
183
|
+
|
|
184
|
+
"@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="],
|
|
185
|
+
|
|
186
|
+
"@smithy/util-middleware": ["@smithy/util-middleware@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w=="],
|
|
187
|
+
|
|
188
|
+
"@smithy/util-retry": ["@smithy/util-retry@4.2.7", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-SvDdsQyF5CIASa4EYVT02LukPHVzAgUA4kMAuZ97QJc2BpAqZfA4PINB8/KOoCXEw9tsuv/jQjMeaHFvxdLNGg=="],
|
|
189
|
+
|
|
190
|
+
"@smithy/util-stream": ["@smithy/util-stream@4.5.8", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.8", "@smithy/node-http-handler": "^4.4.7", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w=="],
|
|
191
|
+
|
|
192
|
+
"@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="],
|
|
193
|
+
|
|
194
|
+
"@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="],
|
|
195
|
+
|
|
196
|
+
"@smithy/util-waiter": ["@smithy/util-waiter@4.2.7", "", { "dependencies": { "@smithy/abort-controller": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-vHJFXi9b7kUEpHWUCY3Twl+9NPOZvQ0SAi+Ewtn48mbiJk4JY9MZmKQjGB4SCvVb9WPiSphZJYY6RIbs+grrzw=="],
|
|
197
|
+
|
|
198
|
+
"@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
|
|
199
|
+
|
|
200
|
+
"aws4": ["aws4@1.13.2", "", {}, "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw=="],
|
|
201
|
+
|
|
202
|
+
"bowser": ["bowser@2.13.1", "", {}, "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw=="],
|
|
203
|
+
|
|
204
|
+
"dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="],
|
|
205
|
+
|
|
206
|
+
"fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
|
|
207
|
+
|
|
208
|
+
"strnum": ["strnum@2.1.2", "", {}, "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ=="],
|
|
209
|
+
|
|
210
|
+
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
|
211
|
+
|
|
212
|
+
"@aws-crypto/sha1-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
|
213
|
+
|
|
214
|
+
"@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
|
215
|
+
|
|
216
|
+
"@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
|
217
|
+
|
|
218
|
+
"@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
|
|
219
|
+
|
|
220
|
+
"@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
|
|
221
|
+
|
|
222
|
+
"@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
|
|
223
|
+
|
|
224
|
+
"@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
|
|
225
|
+
|
|
226
|
+
"@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
|
|
227
|
+
|
|
228
|
+
"@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
|
|
229
|
+
}
|
|
230
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { AwsLiteClient } from "@aws-lite/client";
|
|
2
|
+
import s3 from "@aws-lite/s3";
|
|
3
|
+
import { config } from "dotenv";
|
|
4
|
+
config();
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {'s3' | 'r2' | 'b2'} Provider
|
|
8
|
+
* Cloud storage provider type
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {'upload' | 'download' | 'delete' | 'list' | 'deleteAll'} Action
|
|
13
|
+
* Storage operation action type
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {Object} StorageOptions
|
|
18
|
+
* @property {string} [key] - The object key/path (required for upload, download, delete)
|
|
19
|
+
* @property {string | Buffer | ReadableStream} [body] - The file content to upload (required for upload)
|
|
20
|
+
* @property {Provider} [provider] - Force a specific cloud provider (auto-detected if omitted)
|
|
21
|
+
* @property {string} [BUCKET_NAME] - Override bucket name at runtime
|
|
22
|
+
* @property {string} [ACCESS_KEY_ID] - Override access key ID at runtime
|
|
23
|
+
* @property {string} [SECRET_ACCESS_KEY] - Override secret access key at runtime
|
|
24
|
+
* @property {string} [BUCKET_URL] - Override bucket URL at runtime
|
|
25
|
+
* @property {string} [awsRegion] - AWS region (only for S3 provider)
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @typedef {Object} UploadResult
|
|
30
|
+
* @property {boolean} success - Whether the upload was successful
|
|
31
|
+
* @property {string} key - The object key that was uploaded
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @typedef {Object} DeleteResult
|
|
36
|
+
* @property {boolean} success - Whether the deletion was successful
|
|
37
|
+
* @property {string} key - The object key that was deleted
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @typedef {Object} DeleteAllResult
|
|
42
|
+
* @property {boolean} success - Whether the operation was successful
|
|
43
|
+
* @property {number} count - Number of objects deleted
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Universal cloud storage manager supporting AWS S3, Cloudflare R2, and Backblaze B2.
|
|
48
|
+
* Automatically detects the configured provider from environment variables.
|
|
49
|
+
*
|
|
50
|
+
* @param {Action} action - The storage operation to perform
|
|
51
|
+
* @param {StorageOptions} [options={}] - Operation-specific options
|
|
52
|
+
* @returns {Promise<UploadResult | string | DeleteResult | string[] | DeleteAllResult>}
|
|
53
|
+
* - upload: Returns {success: true, key: string}
|
|
54
|
+
* - download: Returns the file content as a string
|
|
55
|
+
* - delete: Returns {success: true, key: string}
|
|
56
|
+
* - list: Returns array of object keys
|
|
57
|
+
* - deleteAll: Returns {success: true, count: number}
|
|
58
|
+
* @throws {Error} When credentials are missing or operation fails
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* // Upload a file
|
|
62
|
+
* await manageStorage('upload', {
|
|
63
|
+
* key: 'documents/report.pdf',
|
|
64
|
+
* body: fileContent
|
|
65
|
+
* });
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* // Download a file
|
|
69
|
+
* const data = await manageStorage('download', {
|
|
70
|
+
* key: 'documents/report.pdf'
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* // List all files
|
|
75
|
+
* const files = await manageStorage('list');
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* // Delete a file
|
|
79
|
+
* await manageStorage('delete', {
|
|
80
|
+
* key: 'documents/report.pdf'
|
|
81
|
+
* });
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* // Force a specific provider with runtime credentials
|
|
85
|
+
* await manageStorage('upload', {
|
|
86
|
+
* key: 'test.txt',
|
|
87
|
+
* body: 'Hello!',
|
|
88
|
+
* provider: 'r2',
|
|
89
|
+
* BUCKET_NAME: 'my-bucket',
|
|
90
|
+
* ACCESS_KEY_ID: 'key-id',
|
|
91
|
+
* SECRET_ACCESS_KEY: 'secret',
|
|
92
|
+
* BUCKET_URL: 'https://account.r2.cloudflarestorage.com'
|
|
93
|
+
* });
|
|
94
|
+
*/
|
|
95
|
+
export async function manageStorage(action, options = {}) {
|
|
96
|
+
const { key, body, provider: optProvider, ...rest } = options;
|
|
97
|
+
const provider = optProvider || detectDefaultProvider();
|
|
98
|
+
const providerOptions = Object.fromEntries(
|
|
99
|
+
Object.entries(rest).map(([k, v]) => [`${provider.toUpperCase()}_${k}`, v])
|
|
100
|
+
);
|
|
101
|
+
const config = getConfig(provider, providerOptions);
|
|
102
|
+
if (!config.bucket || !config.accessKeyId || !config.secretAccessKey) {
|
|
103
|
+
throw new Error(`Missing credentials for ${provider}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const client = new AwsLiteClient({
|
|
107
|
+
region: config.region,
|
|
108
|
+
endpoint: config.endpoint,
|
|
109
|
+
credentials: {
|
|
110
|
+
accessKeyId: config.accessKeyId,
|
|
111
|
+
secretAccessKey: config.secretAccessKey,
|
|
112
|
+
},
|
|
113
|
+
plugins: [s3],
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
switch (action) {
|
|
118
|
+
case "upload":
|
|
119
|
+
const uploadResult = await client.s3.PutObject({
|
|
120
|
+
Bucket: config.bucket,
|
|
121
|
+
Key: key,
|
|
122
|
+
Body: body,
|
|
123
|
+
});
|
|
124
|
+
console.log(`Uploaded ${key} to ${provider}`);
|
|
125
|
+
return { success: true, key, ...uploadResult };
|
|
126
|
+
case "download":
|
|
127
|
+
const downloadResult = await client.s3.GetObject({
|
|
128
|
+
Bucket: config.bucket,
|
|
129
|
+
Key: key,
|
|
130
|
+
});
|
|
131
|
+
console.log(`Downloaded ${key} from ${provider}`);
|
|
132
|
+
return downloadResult.Body;
|
|
133
|
+
case "delete":
|
|
134
|
+
const deleteResult = await client.s3.DeleteObject({
|
|
135
|
+
Bucket: config.bucket,
|
|
136
|
+
Key: key,
|
|
137
|
+
});
|
|
138
|
+
console.log(`Deleted ${key} from ${provider}`);
|
|
139
|
+
return { success: true, key, ...deleteResult };
|
|
140
|
+
case "list":
|
|
141
|
+
const listResult = await client.s3.ListObjectsV2({
|
|
142
|
+
Bucket: config.bucket,
|
|
143
|
+
});
|
|
144
|
+
const keys = listResult.Contents?.map((obj) => obj.Key) || [];
|
|
145
|
+
console.log(keys.join("\n"));
|
|
146
|
+
return keys;
|
|
147
|
+
case "deleteAll":
|
|
148
|
+
const allObjects = await client.s3.ListObjectsV2({
|
|
149
|
+
Bucket: config.bucket,
|
|
150
|
+
});
|
|
151
|
+
if (allObjects.Contents?.length) {
|
|
152
|
+
const deleteAllResult = await client.s3.DeleteObjects({
|
|
153
|
+
Bucket: config.bucket,
|
|
154
|
+
Delete: {
|
|
155
|
+
Objects: allObjects.Contents.map((obj) => ({ Key: obj.Key })),
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
console.log(
|
|
159
|
+
`Deleted all ${allObjects.Contents.length} files from ${provider}`
|
|
160
|
+
);
|
|
161
|
+
return {
|
|
162
|
+
success: true,
|
|
163
|
+
count: allObjects.Contents.length,
|
|
164
|
+
...deleteAllResult,
|
|
165
|
+
};
|
|
166
|
+
} else {
|
|
167
|
+
console.log(`${provider} bucket empty`);
|
|
168
|
+
return { success: true, count: 0 };
|
|
169
|
+
}
|
|
170
|
+
default:
|
|
171
|
+
throw new Error(
|
|
172
|
+
"Invalid action: upload, download, delete, list, deleteAll"
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error(`Error in ${provider}:`, error.message);
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Detects which cloud storage provider is configured based on environment variables.
|
|
183
|
+
* Checks for complete sets of credentials for each provider in priority order: R2, B2, S3.
|
|
184
|
+
*
|
|
185
|
+
* @private
|
|
186
|
+
* @returns {Provider} The detected provider ('r2', 'b2', or 's3'). Defaults to 'r2' if none configured.
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* // With R2 env vars set
|
|
190
|
+
* const provider = detectDefaultProvider(); // Returns 'r2'
|
|
191
|
+
*/
|
|
192
|
+
function detectDefaultProvider() {
|
|
193
|
+
const checks = {
|
|
194
|
+
r2: [
|
|
195
|
+
"R2_BUCKET_NAME",
|
|
196
|
+
"R2_ACCESS_KEY_ID",
|
|
197
|
+
"R2_SECRET_ACCESS_KEY",
|
|
198
|
+
"R2_BUCKET_URL",
|
|
199
|
+
],
|
|
200
|
+
b2: [
|
|
201
|
+
"B2_BUCKET_NAME",
|
|
202
|
+
"B2_ACCESS_KEY_ID",
|
|
203
|
+
"B2_SECRET_ACCESS_KEY",
|
|
204
|
+
"B2_BUCKET_URL",
|
|
205
|
+
],
|
|
206
|
+
s3: [
|
|
207
|
+
"S3_BUCKET_NAME",
|
|
208
|
+
"S3_ACCESS_KEY_ID",
|
|
209
|
+
"S3_SECRET_ACCESS_KEY",
|
|
210
|
+
"S3_BUCKET_URL",
|
|
211
|
+
],
|
|
212
|
+
};
|
|
213
|
+
for (const [provider, keys] of Object.entries(checks)) {
|
|
214
|
+
if (keys.every((key) => process.env[key])) {
|
|
215
|
+
return provider;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return "r2"; // Default
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Builds the configuration object for the cloud storage client by merging
|
|
223
|
+
* environment variables with runtime options.
|
|
224
|
+
*
|
|
225
|
+
* @private
|
|
226
|
+
* @param {Provider} provider - The cloud storage provider to configure
|
|
227
|
+
* @param {Object} [options={}] - Runtime configuration options (with provider prefix)
|
|
228
|
+
* @returns {Object} Configuration object with bucket, credentials, and endpoint
|
|
229
|
+
* @property {string} region - AWS region (or 'auto' for R2/B2)
|
|
230
|
+
* @property {string} endpoint - Storage service endpoint URL
|
|
231
|
+
* @property {string} bucket - Bucket name
|
|
232
|
+
* @property {string} accessKeyId - Access key ID
|
|
233
|
+
* @property {string} secretAccessKey - Secret access key
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* const config = getConfig('r2', {
|
|
237
|
+
* R2_BUCKET_NAME: 'my-bucket',
|
|
238
|
+
* R2_ACCESS_KEY_ID: 'key123'
|
|
239
|
+
* });
|
|
240
|
+
*/
|
|
241
|
+
function getConfig(provider, options = {}) {
|
|
242
|
+
const varPrefix = provider.toUpperCase() + "_";
|
|
243
|
+
return {
|
|
244
|
+
region:
|
|
245
|
+
provider === "s3"
|
|
246
|
+
? options.awsRegion || process.env.S3_REGION || "us-east-1"
|
|
247
|
+
: "auto",
|
|
248
|
+
endpoint:
|
|
249
|
+
options[`${varPrefix}BUCKET_URL`] ||
|
|
250
|
+
process.env[`${varPrefix}BUCKET_URL`],
|
|
251
|
+
bucket:
|
|
252
|
+
options[`${varPrefix}BUCKET_NAME`] ||
|
|
253
|
+
process.env[`${varPrefix}BUCKET_NAME`],
|
|
254
|
+
accessKeyId:
|
|
255
|
+
options[`${varPrefix}ACCESS_KEY_ID`] ||
|
|
256
|
+
options[`${varPrefix}APPLICATION_KEY_ID`] ||
|
|
257
|
+
process.env[`${varPrefix}ACCESS_KEY_ID`] ||
|
|
258
|
+
process.env[`${varPrefix}APPLICATION_KEY_ID`],
|
|
259
|
+
secretAccessKey:
|
|
260
|
+
options[`${varPrefix}SECRET_ACCESS_KEY`] ||
|
|
261
|
+
options[`${varPrefix}APPLICATION_KEY`] ||
|
|
262
|
+
process.env[`${varPrefix}SECRET_ACCESS_KEY`] ||
|
|
263
|
+
process.env[`${varPrefix}APPLICATION_KEY`],
|
|
264
|
+
};
|
|
265
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "manage-storage",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Storage manager supporting AWS S3, Cloudflare R2, and Backblaze B2 with automatic provider detection",
|
|
5
|
+
"main": "manage-storage.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"s3",
|
|
9
|
+
"r2",
|
|
10
|
+
"cloudflare",
|
|
11
|
+
"backblaze",
|
|
12
|
+
"b2",
|
|
13
|
+
"storage",
|
|
14
|
+
"cloud",
|
|
15
|
+
"aws",
|
|
16
|
+
"object-storage",
|
|
17
|
+
"multi-cloud"
|
|
18
|
+
],
|
|
19
|
+
"author": "vtempest",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/vtempest/Starter-DOCS.git",
|
|
24
|
+
"directory": "storage"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/vtempest/Starter-DOCS/issues"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://github.com/vtempest/Starter-DOCS#readme",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@aws-lite/client": "^0.23.2",
|
|
32
|
+
"@aws-lite/s3": "^0.4.5",
|
|
33
|
+
"dotenv": "^17.2.3"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"ship": "npx standard-version --release-as patch; rm CHANGELOG.md; npm publish"
|
|
38
|
+
},
|
|
39
|
+
"exports": {
|
|
40
|
+
".": "./storage-manager.js"
|
|
41
|
+
}
|
|
42
|
+
}
|