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 and Backblaze B2. It
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 B2 — only the endpoint differs
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 B2 are `auto` |
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-De0Cb_cq.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-De0Cb_cq.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};
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};