manage-storage 0.0.138 → 0.0.139
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
CHANGED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
<a href="https://github.com/OpenSourceAGI/dev-tools-starter-agent/commits/master/"><img src="https://img.shields.io/github/last-commit/OpenSourceAGI/dev-tools-starter-agent.svg" alt="GitHub last commit" /></a>
|
|
39
39
|
<br />
|
|
40
40
|
<a href="https://stackblitz.com/github/OpenSourceAGI/dev-tools-starter-agent/tree/master/packages/manage-storage"><img height="20px" src="https://developer.stackblitz.com/img/open_in_stackblitz.svg" alt="Open in StackBlitz" /></a>
|
|
41
|
-
<img src="https://img.shields.io/badge/Bun-14151A?logo=bun&logoColor=white" alt="Bun" /> <img src="https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=white" alt="TypeScript" /> <img src="https://img.shields.io/badge/Vite-646CFF?logo=vite&logoColor=white" alt="Vite" /> <img src="https://img.shields.io/badge/Vitest-6E9F18?logo=vitest&logoColor=white" alt="Vitest" />
|
|
41
|
+
<img src="https://img.shields.io/badge/Bun-14151A?logo=bun&logoColor=white" alt="Bun" /> <img src="https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=white" alt="TypeScript" /> <img src="https://img.shields.io/badge/React-20232A?logo=react&logoColor=white" alt="React" /> <img src="https://img.shields.io/badge/Tailwind%20CSS-06B6D4?logo=tailwindcss&logoColor=white" alt="Tailwind CSS" /> <img src="https://img.shields.io/badge/Vite-646CFF?logo=vite&logoColor=white" alt="Vite" /> <img src="https://img.shields.io/badge/Vitest-6E9F18?logo=vitest&logoColor=white" alt="Vitest" />
|
|
42
42
|
</p>
|
|
43
43
|
<!-- template-git-repo:badges:end -->
|
|
44
44
|
|
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
|
|
51
51
|
# Cloud Storage Manager
|
|
52
52
|
|
|
53
|
-
One class, `StorageManager`, for Amazon S3, Cloudflare R2
|
|
53
|
+
One class, `StorageManager`, for Amazon S3, Cloudflare R2, Backblaze B2 and
|
|
54
|
+
Google Cloud Storage. It
|
|
54
55
|
resolves credentials once, from the environment or from what you pass it, then
|
|
55
56
|
exposes the bucket as methods: `.upload()`, `.download()`, `.list()`, `.copy()`,
|
|
56
57
|
`.rename()`, `.delete()`, `.deleteAll()`, `.exists()`. Built on the official AWS
|
|
@@ -61,9 +62,19 @@ body an operation needs are in its signature rather than in a comment.
|
|
|
61
62
|
— it boots this package with its dependencies installed; add your bucket's four
|
|
62
63
|
env vars in the StackBlitz shell and the snippets below run as written.
|
|
63
64
|
|
|
65
|
+
## Live demo
|
|
66
|
+
|
|
67
|
+
`bun run dev` starts a demo page with a shadcn/ui settings panel: pick a
|
|
68
|
+
provider, enter a bucket and its keys, test the connection, then upload, list,
|
|
69
|
+
read and delete objects. Every action is a `StorageManager` call made by the
|
|
70
|
+
demo's own server route (`api/storage.ts` on Vercel, Vite middleware locally),
|
|
71
|
+
so the bucket needs no CORS setup. Blank fields fall back to the server's
|
|
72
|
+
`<PROVIDER>_*` env vars. `bun run build:demo` builds it into `dist-demo/`, and
|
|
73
|
+
`vercel.json` deploys the page and the route together.
|
|
74
|
+
|
|
64
75
|
## Features
|
|
65
76
|
|
|
66
|
-
- **Multi-cloud**: the same calls against S3, R2 and
|
|
77
|
+
- **Multi-cloud**: the same calls against S3, R2, B2 and GCS — only the endpoint differs
|
|
67
78
|
- **Auto-detection**: the provider is read from whichever credential prefix your environment has
|
|
68
79
|
- **Typed end to end**: `.upload(key, body)` and `.list(prefix)` are checked at the call site, not documented in prose
|
|
69
80
|
- **Paginated**: `list()` follows the continuation token and `deleteAll()` batches, so neither stops silently at 1000 keys
|
|
@@ -100,7 +111,8 @@ await storage.delete("documents/report.pdf");
|
|
|
100
111
|
|
|
101
112
|
Set environment variables for your preferred provider. The library detects which
|
|
102
113
|
provider to use from the first prefix whose four variables are all present:
|
|
103
|
-
Cloudflare, then Backblaze, then Amazon
|
|
114
|
+
Cloudflare, then Backblaze, then Amazon, then Google (which needs only three,
|
|
115
|
+
since its endpoint is fixed).
|
|
104
116
|
|
|
105
117
|
### Cloudflare R2
|
|
106
118
|
|
|
@@ -133,6 +145,21 @@ AMAZON_BUCKET_URL=https://s3.amazonaws.com
|
|
|
133
145
|
AMAZON_REGION=us-east-1
|
|
134
146
|
```
|
|
135
147
|
|
|
148
|
+
### Google Cloud Storage
|
|
149
|
+
|
|
150
|
+
```env
|
|
151
|
+
GOOGLE_BUCKET_NAME=my-bucket
|
|
152
|
+
GOOGLE_ACCESS_KEY_ID=GOOG1E...
|
|
153
|
+
GOOGLE_SECRET_ACCESS_KEY=your-hmac-secret
|
|
154
|
+
# GOOGLE_BUCKET_URL defaults to https://storage.googleapis.com
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
GCS is reached through its S3-compatible XML API with an **HMAC key**: Cloud
|
|
158
|
+
Storage → Settings → Interoperability → *Create a key for a service account*.
|
|
159
|
+
`GOOGLE_HMAC_ACCESS_ID` and `GOOGLE_HMAC_SECRET` are read too. GCS has no
|
|
160
|
+
multi-object delete in that API, so `deleteAll()` deletes keys one at a time
|
|
161
|
+
(ten in parallel) there.
|
|
162
|
+
|
|
136
163
|
Or pass any of it to the constructor, which wins over the environment — the only
|
|
137
164
|
option on an edge runtime, where there is no `process.env` to read:
|
|
138
165
|
|
|
@@ -154,12 +181,12 @@ const storage = new StorageManager({
|
|
|
154
181
|
|
|
155
182
|
| Option | Type | Falls back to |
|
|
156
183
|
| ----------------- | ---------------------------------------- | ---------------------------------------------------------- |
|
|
157
|
-
| `provider` | `"amazon" \| "cloudflare" \| "backblaze"` | Auto-detected from the environment
|
|
184
|
+
| `provider` | `"amazon" \| "cloudflare" \| "backblaze" \| "google"` | Auto-detected from the environment |
|
|
158
185
|
| `bucket` | `string` | `<PROVIDER>_BUCKET_NAME` |
|
|
159
186
|
| `accessKeyId` | `string` | `<PROVIDER>_ACCESS_KEY_ID` |
|
|
160
187
|
| `secretAccessKey` | `string` | `<PROVIDER>_SECRET_ACCESS_KEY` |
|
|
161
|
-
| `endpoint` | `string` | `<PROVIDER>_BUCKET_URL`
|
|
162
|
-
| `region` | `string` | `AMAZON_REGION`, else `us-east-1`; R2 and
|
|
188
|
+
| `endpoint` | `string` | `<PROVIDER>_BUCKET_URL`; GCS defaults to `https://storage.googleapis.com` |
|
|
189
|
+
| `region` | `string` | `AMAZON_REGION`, else `us-east-1`; R2, B2 and GCS are `auto` |
|
|
163
190
|
| `client` | `S3Client` | A client built from the above — pass one to supply your own |
|
|
164
191
|
|
|
165
192
|
Credentials are checked on the first operation, not in the constructor, so a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e,h as t}from"./manage-storage-
|
|
1
|
+
import{t as e,h as t}from"./manage-storage-cSVxpbo9.js";import{E as r,a,H as s,I as n,M as i,c as o,S as l,d as c,b as m,g as d,i as y,j as h,k as u,r as S,n as p}from"./manage-storage-cSVxpbo9.js";class f{marshaller;serializer;deserializer;serdeContext;defaultContentType;constructor({marshaller:e,serializer:t,deserializer:r,serdeContext:a,defaultContentType:s}){this.marshaller=e,this.serializer=t,this.deserializer=r,this.serdeContext=a,this.defaultContentType=s}async serializeEventStream({eventStream:e,requestSchema:t,initialRequest:r}){const a=this.marshaller,s=t.getEventStreamMember(),n=t.getMemberSchema(s),i=this.serializer,o=this.defaultContentType,l=/* @__PURE__ */Symbol("initialRequestMarker"),c={async*[Symbol.asyncIterator](){if(r){const e={":event-type":{type:"string",value:"initial-request"},":message-type":{type:"string",value:"event"},":content-type":{type:"string",value:o}};i.write(t,r);const a=i.flush();yield{[l]:!0,headers:e,body:a}}for await(const t of e)yield t}};return a.serialize(c,e=>{if(e[l])return{headers:e.headers,body:e.body};let t="";for(const n in e)if("__type"!==n){t=n;break}const{additionalHeaders:r,body:a,eventType:s,explicitPayloadContentType:i}=this.writeEventBody(t,n,e);return{headers:{":event-type":{type:"string",value:s},":message-type":{type:"string",value:"event"},":content-type":{type:"string",value:i??o},...r},body:a}})}async deserializeEventStream({response:t,responseSchema:r,initialResponseContainer:a}){const s=this.marshaller,n=r.getEventStreamMember(),i=r.getMemberSchema(n).getMemberSchemas(),o=/* @__PURE__ */Symbol("initialResponseMarker"),l=s.deserialize(t.body,async t=>{let a="";for(const e in t)if("__type"!==e){a=e;break}const s=t[a].body;if("initial-response"===a){const e=await this.deserializer.read(r,s);return delete e[n],{[o]:!0,...e}}if(a in i){const r=i[a];if(r.isStructSchema()){const n={};let i=!1;for(const[o,l]of r.structIterator()){const{eventHeader:r,eventPayload:c}=l.getMergedTraits();if(i=i||Boolean(r||c),c)l.isBlobSchema()?n[o]=s:l.isStringSchema()?n[o]=(this.serdeContext?.utf8Encoder??e)(s):l.isStructSchema()&&(n[o]=await this.deserializer.read(l,s));else if(r){const e=t[a].headers[o]?.value;null!=e&&(l.isNumericSchema()?n[o]=e&&"object"==typeof e&&"bytes"in e?BigInt(e.toString()):Number(e):n[o]=e)}}if(i)return{[a]:n};if(0===s.byteLength)return{[a]:{}}}return{[a]:await this.deserializer.read(r,s)}}return{$unknown:t}}),c=l[Symbol.asyncIterator](),m=await c.next();if(m.done)return l;if(m.value?.[o]){if(!r)throw new Error("@smithy::core/protocols - initial-response event encountered in event stream but no response schema given.");for(const e in m.value)a[e]=m.value[e]}return{async*[Symbol.asyncIterator](){for(m?.value?.[o]||(yield m.value);;){const{done:e,value:t}=await c.next();if(e)break;yield t}}}}writeEventBody(e,r,a){const s=this.serializer;let n,i=e,o=null;const l={};if(r.getSchema()[4].includes(e)){const t=r.getMemberSchema(e);if(t.isStructSchema()){for(const[r,s]of t.structIterator()){const{eventHeader:t,eventPayload:n}=s.getMergedTraits();if(n)o=r;else if(t){const t=a[e][r];let n="binary";s.isNumericSchema()?n=(-2)**31<=t&&t<=2**31-1?"integer":"long":s.isTimestampSchema()?n="timestamp":s.isStringSchema()?n="string":s.isBooleanSchema()&&(n="boolean"),null!=t&&(l[r]={type:n,value:t},delete a[e][r])}}if(null!==o){const r=t.getMemberSchema(o);r.isBlobSchema()?n="application/octet-stream":r.isStringSchema()&&(n="text/plain"),s.write(r,a[e][o])}else s.write(t,a[e])}else{if(!t.isUnitSchema())throw new Error("@smithy/core/event-streams - non-struct member not supported in event stream union.");s.write(t,{})}}else{const[t,r]=a[e];i=t,s.write(15,r)}const c=s.flush()??new Uint8Array;return{body:"string"==typeof c?(this.serdeContext?.utf8Decoder??t)(c):c,eventType:i,explicitPayloadContentType:n,additionalHeaders:l}}}export{r as EventStreamCodec,a as EventStreamMarshaller,f as EventStreamSerde,s as HeaderMarshaller,n as Int64,i as MessageDecoderStream,o as MessageEncoderStream,l as SmithyMessageDecoderStream,c as SmithyMessageEncoderStream,m as UniversalEventStreamMarshaller,d as eventStreamSerdeProvider,y as getChunkedStream,h as getMessageUnmarshaller,u as iterableToReadableStream,S as readableStreamToIterable,p as resolveEventStreamSerdeConfig};
|