@edgeone/pages-blob 0.0.1 → 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/README.md CHANGED
@@ -57,7 +57,6 @@ const store = getStore({ name: "my-store", consistency: "strong" });
57
57
 
58
58
  // Per-call override
59
59
  await store.get("key", { consistency: "strong" });
60
- await store.getMetadata("key", { consistency: "strong" });
61
60
  await store.list({ consistency: "strong" });
62
61
  ```
63
62
 
@@ -111,14 +110,6 @@ Read a Blob. Returns `null` if it does not exist.
111
110
  - `options.type`: `"text"` (default) | `"json"` | `"arrayBuffer"` | `"blob"` | `"stream"`
112
111
  - `options.consistency`: `"eventual"` | `"strong"` (overrides Store-level default)
113
112
 
114
- ### `store.getMetadata(key, options?)`
115
-
116
- Read blob metadata without downloading the body. Returns `null` if the key does not exist.
117
-
118
- Returns: `{ cacheControl?, contentType?, etag?, headers? }`
119
-
120
- - `options.consistency`: `"eventual"` | `"strong"`
121
-
122
113
  ### `store.getWithHeaders(key, options?)`
123
114
 
124
115
  Read a blob along with all response headers. Returns `null` if the key does not exist.
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- "use strict";var D=Object.defineProperty;var te=Object.getOwnPropertyDescriptor;var ne=Object.getOwnPropertyNames;var re=Object.prototype.hasOwnProperty;var se=(t,e)=>{for(var r in e)D(t,r,{get:e[r],enumerable:!0})},oe=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of ne(e))!re.call(t,o)&&o!==r&&D(t,o,{get:()=>e[o],enumerable:!(n=te(e,o))||n.enumerable});return t};var ie=t=>oe(D({},"__esModule",{value:!0}),t);var ke={};se(ke,{InvalidKeyError:()=>y,InvalidStoreNameError:()=>m,MissingProjectIdError:()=>C,PagesBlobError:()=>f,PreconditionFailedError:()=>p,QuotaExceededError:()=>P,RateLimitedError:()=>R,Store:()=>x,getStore:()=>Te,listStores:()=>Ie});module.exports=ie(ke);var f=class extends Error{code;constructor(e,r){super(`PagesBlob: ${r}`),this.name="PagesBlobError",this.code=e}},y=class extends f{constructor(e){super("INVALID_KEY",e)}},m=class extends f{constructor(e){super("INVALID_STORE_NAME",e)}},S=class extends f{constructor(e){super("MISSING_ENVIRONMENT",`Environment not configured for Pages Blob. Missing: ${e.join(", ")}. Supply these properties when creating a store, or ensure the function is running in a Pages environment.`)}},P=class extends f{constructor(){super("QUOTA_EXCEEDED","storage quota exceeded")}},R=class extends f{constructor(){super("RATE_LIMITED","request rate limited, please retry later")}},C=class extends f{constructor(){super("MISSING_PROJECT_ID","projectId is required when using API token mode. Please supply { name, projectId, token } to getStore() / listStores().")}},h=class extends f{constructor(e){super("CREDENTIAL_ERROR",e)}},l=class extends f{constructor(e,r){super("COS_ERROR",`COS returned ${e}: ${r}`)}},p=class extends f{constructor(){super("PRECONDITION_FAILED","conditional write failed (key already exists)")}};function w(t){if(t==="")throw new y("Blob key must not be empty.");if(t.startsWith("/")||t.startsWith("%2F"))throw new y("Blob key must not start with forward slash (/).");if(new TextEncoder().encode(t).length>600)throw new y("Blob key must be a sequence of Unicode characters whose UTF-8 encoding is at most 600 bytes long.")}function $(t){if(t==="")throw new m("Store name must not be empty.");if(t.includes("/")||t.includes(":"))throw new m("Store name must not contain forward slashes (/) or colons (:).");if(!/^[a-zA-Z0-9_-]+$/.test(t))throw new m("Store name must only contain letters, digits, underscores, and hyphens.");if(new TextEncoder().encode(t).length>64)throw new m("Store name must be a sequence of Unicode characters whose UTF-8 encoding is at most 64 bytes long.")}var x=class{cosClient;storeName;defaultConsistency;constructor(e,r,n="eventual"){this.cosClient=e,this.storeName=r,this.defaultConsistency=n}resolveConsistency(e){return e??this.defaultConsistency}async set(e,r,n){w(e);let o=await this.cosClient.putObject(this.storeName,e,r,{onlyIfNew:n?.onlyIfNew,cacheControl:n?.cacheControl});if(n?.onlyIfNew&&o.statusCode===412)throw new p}async setJSON(e,r,n){w(e);let o=JSON.stringify(r),s=await this.cosClient.putObject(this.storeName,e,o,{onlyIfNew:n?.onlyIfNew,contentType:"application/json",cacheControl:n?.cacheControl});if(n?.onlyIfNew&&s.statusCode===412)throw new p}async get(e,r){w(e);let n=this.resolveConsistency(r?.consistency),o=await this.cosClient.getObject(this.storeName,e,n);if(o===null)return null;let{body:s}=o,i=r?.type??"text",a=new TextDecoder("utf-8");switch(i){case"text":return a.decode(s);case"json":return JSON.parse(a.decode(s));case"arrayBuffer":return s.buffer.slice(s.byteOffset,s.byteOffset+s.byteLength);case"blob":return new Blob([s]);case"stream":return new ReadableStream({start(c){c.enqueue(s),c.close()}});default:return a.decode(s)}}async getMetadata(e,r){w(e);let n=this.resolveConsistency(r?.consistency);return this.cosClient.headObject(this.storeName,e,n)}async getWithHeaders(e,r){w(e);let n=this.resolveConsistency(r?.consistency),o=await this.cosClient.getObject(this.storeName,e,n);return o?{body:new TextDecoder("utf-8").decode(o.body),headers:o.headers||{}}:null}async delete(e){w(e),await this.cosClient.deleteObject(this.storeName,e)}async list(e){let r=e?.paginate!==!1,n=[],o=[],s=this.resolveConsistency(e?.consistency),i=e?.cursor||"",a=!0;for(;a;){let c=await this.cosClient.listObjects(this.storeName,{prefix:e?.prefix,delimiter:e?.directories?"/":void 0,marker:i||void 0,maxKeys:1e3,consistency:s});for(let d of c.contents)n.push({key:d.key,etag:d.etag});o.push(...c.commonPrefixes),!r||!c.isTruncated?a=!1:i=c.nextMarker}return{blobs:n,directories:o}}};var ae=new TextEncoder;function N(t){let e=ae.encode(t),r=new ArrayBuffer(e.byteLength),n=new Uint8Array(r);return n.set(e),n}function H(t){let e=t instanceof Uint8Array?t:new Uint8Array(t),r="";for(let n=0;n<e.length;n++)r+=e[n].toString(16).padStart(2,"0");return r}async function L(t,e){let r=await crypto.subtle.importKey("raw",N(t),{name:"HMAC",hash:"SHA-1"},!1,["sign"]),n=await crypto.subtle.sign("HMAC",r,N(e));return H(n)}async function ce(t){let e=await crypto.subtle.digest("SHA-1",N(t));return H(e)}function v(t){return encodeURIComponent(t).replace(/[!'()*]/g,e=>"%"+e.charCodeAt(0).toString(16).toUpperCase())}function de(t){return t.split("/").map(e=>v(e)).join("/")}var le=new Set(["cache-control","content-disposition","content-encoding","content-length","content-md5","content-type","expect","expires","if-match","if-modified-since","if-none-match","if-unmodified-since","origin","range","transfer-encoding"]);function ue(t){return t==="host"||t==="x-cos-security-token"?!1:!!(le.has(t)||t.startsWith("x-cos-"))}function K(t){if(!t)return[];let e=[];for(let[r,n]of Object.entries(t))n!=null&&e.push([r.toLowerCase(),String(n)]);return e.sort(([r],[n])=>r<n?-1:r>n?1:0),e}function q(t){return t.map(([e,r])=>`${v(e)}=${v(r)}`).join("&")}function U(t){return t.map(([e])=>v(e)).join(";")}async function ge(t){let e=t.method.toLowerCase(),r=t.pathname.startsWith("/")?t.pathname:`/${t.pathname}`,n=Math.floor(Date.now()/1e3),o=n+(t.expireSeconds??3600),s=`${n};${o}`,a=K(t.headers).filter(([j])=>ue(j)),c=U(a),d=q(a),u=K(t.query),g=U(u),M=q(u),O=`${e}
1
+ "use strict";var B=Object.defineProperty;var te=Object.getOwnPropertyDescriptor;var ne=Object.getOwnPropertyNames;var re=Object.prototype.hasOwnProperty;var se=(t,e)=>{for(var r in e)B(t,r,{get:e[r],enumerable:!0})},oe=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of ne(e))!re.call(t,o)&&o!==r&&B(t,o,{get:()=>e[o],enumerable:!(n=te(e,o))||n.enumerable});return t};var ie=t=>oe(B({},"__esModule",{value:!0}),t);var ke={};se(ke,{InvalidKeyError:()=>y,InvalidStoreNameError:()=>m,MissingProjectIdError:()=>C,PagesBlobError:()=>f,PreconditionFailedError:()=>p,QuotaExceededError:()=>P,RateLimitedError:()=>v,Store:()=>x,getStore:()=>Ee,listStores:()=>Te});module.exports=ie(ke);var f=class extends Error{code;constructor(e,r){super(`PagesBlob: ${r}`),this.name="PagesBlobError",this.code=e}},y=class extends f{constructor(e){super("INVALID_KEY",e)}},m=class extends f{constructor(e){super("INVALID_STORE_NAME",e)}},S=class extends f{constructor(e){super("MISSING_ENVIRONMENT",`Environment not configured for Pages Blob. Missing: ${e.join(", ")}. Supply these properties when creating a store, or ensure the function is running in a Pages environment.`)}},P=class extends f{constructor(){super("QUOTA_EXCEEDED","storage quota exceeded")}},v=class extends f{constructor(){super("RATE_LIMITED","request rate limited, please retry later")}},C=class extends f{constructor(){super("MISSING_PROJECT_ID","projectId is required when using API token mode. Please supply { name, projectId, token } to getStore() / listStores().")}},h=class extends f{constructor(e){super("CREDENTIAL_ERROR",e)}},l=class extends f{constructor(e,r){super("COS_ERROR",`COS returned ${e}: ${r}`)}},p=class extends f{constructor(){super("PRECONDITION_FAILED","conditional write failed (key already exists)")}};function w(t){if(t==="")throw new y("Blob key must not be empty.");if(t.startsWith("/")||t.startsWith("%2F"))throw new y("Blob key must not start with forward slash (/).");if(new TextEncoder().encode(t).length>600)throw new y("Blob key must be a sequence of Unicode characters whose UTF-8 encoding is at most 600 bytes long.")}function $(t){if(t==="")throw new m("Store name must not be empty.");if(t.includes("/")||t.includes(":"))throw new m("Store name must not contain forward slashes (/) or colons (:).");if(!/^[a-zA-Z0-9_-]+$/.test(t))throw new m("Store name must only contain letters, digits, underscores, and hyphens.");if(new TextEncoder().encode(t).length>64)throw new m("Store name must be a sequence of Unicode characters whose UTF-8 encoding is at most 64 bytes long.")}var x=class{cosClient;storeName;defaultConsistency;constructor(e,r,n="eventual"){this.cosClient=e,this.storeName=r,this.defaultConsistency=n}resolveConsistency(e){return e??this.defaultConsistency}async set(e,r,n){w(e);let o=await this.cosClient.putObject(this.storeName,e,r,{onlyIfNew:n?.onlyIfNew,cacheControl:n?.cacheControl});if(n?.onlyIfNew&&o.statusCode===412)throw new p}async setJSON(e,r,n){w(e);let o=JSON.stringify(r),s=await this.cosClient.putObject(this.storeName,e,o,{onlyIfNew:n?.onlyIfNew,contentType:"application/json",cacheControl:n?.cacheControl});if(n?.onlyIfNew&&s.statusCode===412)throw new p}async get(e,r){w(e);let n=this.resolveConsistency(r?.consistency),o=await this.cosClient.getObject(this.storeName,e,n);if(o===null)return null;let{body:s}=o,i=r?.type??"text",a=new TextDecoder("utf-8");switch(i){case"text":return a.decode(s);case"json":return JSON.parse(a.decode(s));case"arrayBuffer":return s.buffer.slice(s.byteOffset,s.byteOffset+s.byteLength);case"blob":return new Blob([s]);case"stream":return new ReadableStream({start(c){c.enqueue(s),c.close()}});default:return a.decode(s)}}async getMetadata(e,r){w(e);let n=this.resolveConsistency(r?.consistency);return this.cosClient.headObject(this.storeName,e,n)}async getWithHeaders(e,r){w(e);let n=this.resolveConsistency(r?.consistency),o=await this.cosClient.getObject(this.storeName,e,n);return o?{body:new TextDecoder("utf-8").decode(o.body),headers:o.headers||{}}:null}async delete(e){w(e),await this.cosClient.deleteObject(this.storeName,e)}async list(e){let r=e?.paginate!==!1,n=[],o=[],s=this.resolveConsistency(e?.consistency),i=e?.cursor||"",a=!0;for(;a;){let c=await this.cosClient.listObjects(this.storeName,{prefix:e?.prefix,delimiter:e?.directories?"/":void 0,marker:i||void 0,maxKeys:1e3,consistency:s});for(let d of c.contents)n.push({key:d.key,etag:d.etag});o.push(...c.commonPrefixes),!r||!c.isTruncated?a=!1:i=c.nextMarker}return{blobs:n,directories:o}}};var ae=new TextEncoder;function D(t){let e=ae.encode(t),r=new ArrayBuffer(e.byteLength),n=new Uint8Array(r);return n.set(e),n}function H(t){let e=t instanceof Uint8Array?t:new Uint8Array(t),r="";for(let n=0;n<e.length;n++)r+=e[n].toString(16).padStart(2,"0");return r}async function L(t,e){let r=await crypto.subtle.importKey("raw",D(t),{name:"HMAC",hash:"SHA-1"},!1,["sign"]),n=await crypto.subtle.sign("HMAC",r,D(e));return H(n)}async function ce(t){let e=await crypto.subtle.digest("SHA-1",D(t));return H(e)}function R(t){return encodeURIComponent(t).replace(/[!'()*]/g,e=>"%"+e.charCodeAt(0).toString(16).toUpperCase())}function de(t){return t.split("/").map(e=>R(e)).join("/")}var le=new Set(["cache-control","content-disposition","content-encoding","content-length","content-md5","content-type","expect","expires","if-match","if-modified-since","if-none-match","if-unmodified-since","origin","range","transfer-encoding"]);function ue(t){return t==="host"||t==="x-cos-security-token"?!1:!!(le.has(t)||t.startsWith("x-cos-"))}function K(t){if(!t)return[];let e=[];for(let[r,n]of Object.entries(t))n!=null&&e.push([r.toLowerCase(),String(n)]);return e.sort(([r],[n])=>r<n?-1:r>n?1:0),e}function q(t){return t.map(([e,r])=>`${R(e)}=${R(r)}`).join("&")}function U(t){return t.map(([e])=>R(e)).join(";")}async function ge(t){let e=t.method.toLowerCase(),r=t.pathname.startsWith("/")?t.pathname:`/${t.pathname}`,n=Math.floor(Date.now()/1e3),o=n+(t.expireSeconds??3600),s=`${n};${o}`,a=K(t.headers).filter(([j])=>ue(j)),c=U(a),d=q(a),u=K(t.query),g=U(u),M=q(u),O=`${e}
2
2
  ${r}
3
3
  ${M}
4
4
  ${d}
5
5
  `,V=`sha1
6
6
  ${s}
7
7
  ${await ce(O)}
8
- `,J=await L(t.secretKey,s),Q=await L(J,V),Z=["q-sign-algorithm=sha1",`q-ak=${t.secretId}`,`q-sign-time=${s}`,`q-key-time=${s}`,`q-header-list=${c}`,`q-url-param-list=${g}`,`q-signature=${Q}`].join("&"),_={};for(let[j,ee]of a)_[j]=ee;return{authorization:Z,signedHeaders:_}}async function b(t){let e=new URL(t.domain),r=t.key?`/${de(t.key)}`:"/";if(e.pathname=r,t.query)for(let[s,i]of Object.entries(t.query))i!=null&&e.searchParams.set(s,String(i));let{authorization:n}=await ge({method:t.method,pathname:r,query:t.query,headers:t.headers,secretId:t.credential.secretId,secretKey:t.credential.secretKey}),o=new Headers;if(t.headers)for(let[s,i]of Object.entries(t.headers))i!=null&&o.set(s,String(i));return o.set("Authorization",n),t.credential.sessionToken&&o.set("x-cos-security-token",t.credential.sessionToken),fetch(e.toString(),{method:t.method,headers:o,body:t.body??void 0,signal:t.signal})}var fe="blob.edgeone.site",he="blob-nocache.edgeone.site",k=class{credentialManager;bucket="";region="";keyPrefix="";cachedDomain="";uncachedDomain="";initialized=!1;constructor(e){this.credentialManager=e}computeSubdomain(e){let r=[];if(e.appId&&r.push(e.appId),e.zoneId&&r.push(e.zoneId),e.projectId&&r.push(e.projectId),r.length===3)return r.join("-");if(e.resourcePrefix){let o=e.resourcePrefix.replace(/\/?\*$/,"").split("/").filter(Boolean);if(o.length>=3)return o.slice(0,3).join("-")}return""}async ensureInitialized(){if(this.initialized)return;let e=await this.credentialManager.getCredential();!this.keyPrefix&&e.resourcePrefix&&(this.keyPrefix=e.resourcePrefix.replace(/\/?\*$/,""));let r=e.edgeRegion==="CN",n=e.cosMainland,o=e.cosOverseas,s=r?n||o:o||n;!this.bucket&&s&&(this.bucket=s.bucket,this.region=s.region);let i=this.computeSubdomain(e);if(!i)throw new l(0,"unable to derive tenant subdomain from credential; missing appId/zoneId/projectId or resourcePrefix");this.cachedDomain=`https://${i}.${fe}`,this.uncachedDomain=`https://${i}.${he}`,this.initialized=!0}async resolveDomain(e){return await this.ensureInitialized(),e==="strong"?this.uncachedDomain:this.cachedDomain}async resolveCredential(){let e=await this.credentialManager.getCredential();return{secretId:e.tmpSecretId,secretKey:e.tmpSecretKey,sessionToken:e.sessionToken}}buildCosKey(e,r){return`${this.keyPrefix}/${e}/${r}`}async getDomains(){return await this.ensureInitialized(),{cached:this.cachedDomain,uncached:this.uncachedDomain}}async putObject(e,r,n,o){let s=await this.resolveDomain("eventual"),i=await this.resolveCredential(),a=this.buildCosKey(e,r),d=o?.cacheControl===null?void 0:o?.cacheControl??"max-age=0, stale-while-revalidate=60",u={};o?.onlyIfNew&&(u["If-None-Match"]="*"),d&&(u["Cache-Control"]=d),o?.contentType&&(u["Content-Type"]=o.contentType);try{let g=await b({domain:s,method:"PUT",key:a,headers:u,body:n,credential:i});if(g.status===412)return await g.arrayBuffer().catch(()=>{}),{etag:"",statusCode:412};if(!g.ok){let O=await T(g);throw new l(g.status,O||`putObject failed: ${g.status}`)}let M=g.headers.get("etag")||"";return await g.arrayBuffer().catch(()=>{}),{etag:M,statusCode:g.status}}catch(g){throw g instanceof l?g:new l(0,g.message||String(g))}}async getObject(e,r,n){let o=await this.resolveDomain(n),s=await this.resolveCredential(),i=this.buildCosKey(e,r);try{let a=await b({domain:o,method:"GET",key:i,credential:s});if(a.status===404)return await a.arrayBuffer().catch(()=>{}),null;if(!a.ok){let u=await T(a);throw new l(a.status,u||`getObject failed: ${a.status}`)}let c=new Uint8Array(await a.arrayBuffer()),d=z(a.headers);return{body:c,contentType:d["content-type"],headers:d}}catch(a){throw a instanceof l?a:new l(0,a.message||String(a))}}async headObject(e,r,n){let o=await this.resolveDomain(n),s=await this.resolveCredential(),i=this.buildCosKey(e,r);try{let a=await b({domain:o,method:"HEAD",key:i,credential:s});if(a.status===404)return null;if(!a.ok){let d=await T(a);throw new l(a.status,d||`headObject failed: ${a.status}`)}let c=z(a.headers);return{cacheControl:c["cache-control"],contentType:c["content-type"],etag:c.etag,headers:c}}catch(a){throw a instanceof l?a:new l(0,a.message||String(a))}}async deleteObject(e,r){let n=await this.resolveDomain("eventual"),o=await this.resolveCredential(),s=this.buildCosKey(e,r);try{let i=await b({domain:n,method:"DELETE",key:s,credential:o});if(i.status===204||i.status===404||i.ok){await i.arrayBuffer().catch(()=>{});return}let a=await T(i);throw new l(i.status,a||`deleteObject failed: ${i.status}`)}catch(i){throw i instanceof l?i:new l(0,i.message||String(i))}}async listObjects(e,r){let n=`${this.keyPrefix}/${e}/`,o=r?.prefix?n+r.prefix:n,s=await this.getBucketRaw({prefix:o,delimiter:r?.delimiter,marker:r?.marker,maxKeys:r?.maxKeys,consistency:r?.consistency}),i=s.contents.map(c=>{let d=c.key,u=d.startsWith(n)?d.slice(n.length):d;return u?{key:u,etag:c.etag}:null}).filter(c=>c!==null),a=s.commonPrefixes.map(c=>c.startsWith(n)?c.slice(n.length):c).filter(c=>!!c);return{contents:i,commonPrefixes:a,isTruncated:s.isTruncated,nextMarker:s.nextMarker}}async listStores(e){let r=[],n="",o=!0;for(;o;){await this.ensureInitialized();let s=`${this.keyPrefix}/`,i=await this.getBucketRaw({prefix:s,delimiter:"/",maxKeys:1e3,marker:n||void 0,consistency:e});for(let a of i.commonPrefixes){let c=a.startsWith(s)?a.slice(s.length,-1):a.slice(0,-1);c&&r.push(c)}if(o=i.isTruncated,n=i.nextMarker,!o||!n)break}return r}async getBucketRaw(e){let r=await this.resolveDomain(e.consistency),n=await this.resolveCredential(),o={prefix:e.prefix};e.delimiter&&(o.delimiter=e.delimiter),e.marker&&(o.marker=e.marker),e.maxKeys&&(o["max-keys"]=e.maxKeys);try{let s=await b({domain:r,method:"GET",query:o,credential:n});if(!s.ok){let a=await T(s);throw new l(s.status,a||`getBucket failed: ${s.status}`)}let i=await s.text();return me(i)}catch(s){throw s instanceof l?s:new l(0,s.message||String(s))}}};async function T(t){try{return await t.text()}catch{return""}}function z(t){let e={};return t.forEach((r,n)=>{e[n.toLowerCase()]=r}),e}function me(t){let e=[],r=/<Contents>([\s\S]*?)<\/Contents>/g,n;for(;(n=r.exec(t))!==null;){let d=n[1],u=I(d,"Key"),g=I(d,"ETag");u!==null&&e.push({key:B(u),etag:g||""})}let o=[],s=/<CommonPrefixes>([\s\S]*?)<\/CommonPrefixes>/g;for(;(n=s.exec(t))!==null;){let d=n[1],u=I(d,"Prefix");u!==null&&o.push(B(u))}let a=I(t,"IsTruncated")==="true",c=I(t,"NextMarker")||"";return{contents:e,commonPrefixes:o,isTruncated:a,nextMarker:B(c)}}function I(t,e){let n=new RegExp(`<${e}>([\\s\\S]*?)<\\/${e}>`).exec(t);return n?n[1]:null}function B(t){return t.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&apos;/g,"'").replace(/&amp;/g,"&")}var ye="X-RateLimit-Reset";async function A(t,e,r=5){e.signal?.throwIfAborted?.();try{let n=await fetch(t,e);if(r>0&&(n.status===429||n.status>=500)){let o=Y(n.headers.get(ye));return await X(o,e.signal),A(t,e,r-1)}return n}catch(n){if(r===0||n instanceof DOMException&&n.name==="AbortError")throw n;let o=Y();return await X(o,e.signal),A(t,e,r-1)}}function Y(t){return t?Math.max(Number(t)*1e3-Date.now(),1e3):5e3}function X(t,e){return new Promise((r,n)=>{if(e?.aborted)return n(e.reason);let o=setTimeout(()=>{e?.removeEventListener("abort",s),r()},t),s=()=>{clearTimeout(o),n(e.reason)};e?.addEventListener("abort",s,{once:!0})})}var F="prod";var pe=300,we="https://blob-sts.edgeone.site/",E=class{authToken;projectId;cached=null;constructor(e,r){this.authToken=e,this.projectId=r}async getCredential(){if(this.cached&&!this.isExpired(this.cached))return this.cached;let e=await this.fetchCredential();return this.cached=e,e}clearCache(){this.cached=null}isExpired(e){let r=Math.floor(Date.now()/1e3);return e.expiredTime-r<pe}async fetchCredential(){for(let r=1;r<=3;r++){let n=await A(we,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.authToken}`,"X-Env":F},body:JSON.stringify(this.projectId?{ProjectId:this.projectId}:{})});if(n.status===413)throw new h("storage quota exceeded");if(n.status===429)throw new h("rate limited, please retry later");if(!n.ok){let i=await n.text().catch(()=>"unknown error");throw new h(`failed to obtain STS credential: ${n.status} ${i}`)}let o=await n.json(),s=o.data&&typeof o.data=="object"?o.data:o;if(s.tmpSecretId&&s.tmpSecretKey&&s.sessionToken&&s.expiredTime){let i=s.cosMainland,a=s.cosOverseas,c=n.headers.get("X-Edge-Region")||void 0;return{tmpSecretId:s.tmpSecretId,tmpSecretKey:s.tmpSecretKey,sessionToken:s.sessionToken,expiredTime:s.expiredTime,appId:s.appId||void 0,zoneId:s.zoneId||void 0,projectId:s.projectId||void 0,resourcePrefix:s.resourcePrefix||void 0,cosMainland:i||void 0,cosOverseas:a||void 0,edgeRegion:c}}if(s.code!==void 0&&s.code!==0){let i=s.msg||s.message||"unknown error";throw new h(`credential exchange failed (code=${s.code}): ${i}`)}if(o.code!==void 0&&o.code!==0){let i=o.msg||o.message||"unknown error";throw new h(`credential exchange failed (code=${o.code}): ${i}`)}if(r<3){await Ce(1e3*r);continue}throw new h("invalid STS credential response")}throw new h("invalid STS credential response")}};function Ce(t){return new Promise(e=>setTimeout(e,t))}var xe="{{PAGES_BLOB_DEPLOY_CREDENTIAL}}";function W(){let t=be();if(t)return{deployCredential:t};let e=Se("PAGES_BLOB_DEPLOY_CREDENTIAL");return e?{deployCredential:e}:{}}function be(){let t=xe;if(!(t.startsWith("{{")&&t.endsWith("}}")))return t||void 0}function Se(t){if(typeof process<"u"&&process.env)return process.env[t]}function Te(t){let e=typeof t=="string"?t:t.name;$(e);let r=G(typeof t=="string"?void 0:t),n=new E(r.authToken,r.projectId),o=new k(n);return new x(o,e,r.consistency??"eventual")}async function Ie(t){let e=G(t?{name:"__list__",projectId:t.projectId,token:t.token,consistency:t.consistency}:void 0),r=new E(e.authToken,e.projectId);return{stores:(await new k(r).listStores(e.consistency)).map(s=>({name:s}))}}function G(t){if(t?.token){if(!t.projectId)throw new C;return{authToken:t.token,projectId:t.projectId,consistency:t.consistency}}if(t?.projectId&&!t.token)throw new S(["token"]);let e=W();if(!e.deployCredential)throw new S(["deployCredential"]);return{authToken:e.deployCredential,consistency:t?.consistency}}0&&(module.exports={InvalidKeyError,InvalidStoreNameError,MissingProjectIdError,PagesBlobError,PreconditionFailedError,QuotaExceededError,RateLimitedError,Store,getStore,listStores});
8
+ `,J=await L(t.secretKey,s),Q=await L(J,V),Z=["q-sign-algorithm=sha1",`q-ak=${t.secretId}`,`q-sign-time=${s}`,`q-key-time=${s}`,`q-header-list=${c}`,`q-url-param-list=${g}`,`q-signature=${Q}`].join("&"),_={};for(let[j,ee]of a)_[j]=ee;return{authorization:Z,signedHeaders:_}}async function b(t){let e=new URL(t.domain),r=t.key?`/${de(t.key)}`:"/";if(e.pathname=r,t.query)for(let[s,i]of Object.entries(t.query))i!=null&&e.searchParams.set(s,String(i));let{authorization:n}=await ge({method:t.method,pathname:r,query:t.query,headers:t.headers,secretId:t.credential.secretId,secretKey:t.credential.secretKey}),o=new Headers;if(t.headers)for(let[s,i]of Object.entries(t.headers))i!=null&&o.set(s,String(i));return o.set("Authorization",n),t.credential.sessionToken&&o.set("x-cos-security-token",t.credential.sessionToken),fetch(e.toString(),{method:t.method,headers:o,body:t.body??void 0,signal:t.signal})}var fe="blob.edgeone.site",he="blob-nocache.edgeone.site",T=class{credentialManager;bucket="";region="";keyPrefix="";cachedDomain="";uncachedDomain="";initialized=!1;constructor(e){this.credentialManager=e}computeSubdomain(e){let r=[];if(e.appId&&r.push(e.appId),e.zoneId&&r.push(e.zoneId),e.projectId&&r.push(e.projectId),r.length===3)return r.join("-");if(e.resourcePrefix){let o=e.resourcePrefix.replace(/\/?\*$/,"").split("/").filter(Boolean);if(o.length>=3)return o.slice(0,3).join("-")}return""}async ensureInitialized(){if(this.initialized)return;let e=await this.credentialManager.getCredential();!this.keyPrefix&&e.resourcePrefix&&(this.keyPrefix=e.resourcePrefix.replace(/\/?\*$/,""));let r=e.edgeRegion==="CN",n=e.cosMainland,o=e.cosOverseas,s=r?n||o:o||n;!this.bucket&&s&&(this.bucket=s.bucket,this.region=s.region);let i=this.computeSubdomain(e);if(!i)throw new l(0,"unable to derive tenant subdomain from credential; missing appId/zoneId/projectId or resourcePrefix");this.cachedDomain=`https://${i}.${fe}`,this.uncachedDomain=`https://${i}.${he}`,this.initialized=!0}async resolveDomain(e){return await this.ensureInitialized(),e==="strong"?this.uncachedDomain:this.cachedDomain}async resolveCredential(){let e=await this.credentialManager.getCredential();return{secretId:e.tmpSecretId,secretKey:e.tmpSecretKey,sessionToken:e.sessionToken}}buildCosKey(e,r){return`${this.keyPrefix}/${e}/${r}`}async getDomains(){return await this.ensureInitialized(),{cached:this.cachedDomain,uncached:this.uncachedDomain}}async putObject(e,r,n,o){let s=await this.resolveDomain("eventual"),i=await this.resolveCredential(),a=this.buildCosKey(e,r),d=o?.cacheControl===null?void 0:o?.cacheControl??"max-age=0, stale-while-revalidate=60",u={};o?.onlyIfNew&&(u["If-None-Match"]="*"),d&&(u["Cache-Control"]=d),o?.contentType&&(u["Content-Type"]=o.contentType);try{let g=await b({domain:s,method:"PUT",key:a,headers:u,body:n,credential:i});if(g.status===412)return await g.arrayBuffer().catch(()=>{}),{etag:"",statusCode:412};if(!g.ok){let O=await I(g);throw new l(g.status,O||`putObject failed: ${g.status}`)}let M=g.headers.get("etag")||"";return await g.arrayBuffer().catch(()=>{}),{etag:M,statusCode:g.status}}catch(g){throw g instanceof l?g:new l(0,g.message||String(g))}}async getObject(e,r,n){let o=await this.resolveDomain(n),s=await this.resolveCredential(),i=this.buildCosKey(e,r);try{let a=await b({domain:o,method:"GET",key:i,credential:s});if(a.status===404)return await a.arrayBuffer().catch(()=>{}),null;if(!a.ok){let u=await I(a);throw new l(a.status,u||`getObject failed: ${a.status}`)}let c=new Uint8Array(await a.arrayBuffer()),d=z(a.headers);return{body:c,contentType:d["content-type"],headers:d}}catch(a){throw a instanceof l?a:new l(0,a.message||String(a))}}async headObject(e,r,n){let o=await this.resolveDomain(n),s=await this.resolveCredential(),i=this.buildCosKey(e,r);try{let a=await b({domain:o,method:"HEAD",key:i,credential:s});if(a.status===404)return null;if(!a.ok){let d=await I(a);throw new l(a.status,d||`headObject failed: ${a.status}`)}let c=z(a.headers);return{cacheControl:c["cache-control"],contentType:c["content-type"],etag:c.etag,headers:c}}catch(a){throw a instanceof l?a:new l(0,a.message||String(a))}}async deleteObject(e,r){let n=await this.resolveDomain("eventual"),o=await this.resolveCredential(),s=this.buildCosKey(e,r);try{let i=await b({domain:n,method:"DELETE",key:s,credential:o});if(i.status===204||i.status===404||i.ok){await i.arrayBuffer().catch(()=>{});return}let a=await I(i);throw new l(i.status,a||`deleteObject failed: ${i.status}`)}catch(i){throw i instanceof l?i:new l(0,i.message||String(i))}}async listObjects(e,r){let n=`${this.keyPrefix}/${e}/`,o=r?.prefix?n+r.prefix:n,s=await this.getBucketRaw({prefix:o,delimiter:r?.delimiter,marker:r?.marker,maxKeys:r?.maxKeys,consistency:r?.consistency}),i=s.contents.map(c=>{let d=c.key,u=d.startsWith(n)?d.slice(n.length):d;return u?{key:u,etag:c.etag}:null}).filter(c=>c!==null),a=s.commonPrefixes.map(c=>c.startsWith(n)?c.slice(n.length):c).filter(c=>!!c);return{contents:i,commonPrefixes:a,isTruncated:s.isTruncated,nextMarker:s.nextMarker}}async listStores(e){let r=[],n="",o=!0;for(;o;){await this.ensureInitialized();let s=`${this.keyPrefix}/`,i=await this.getBucketRaw({prefix:s,delimiter:"/",maxKeys:1e3,marker:n||void 0,consistency:e});for(let a of i.commonPrefixes){let c=a.startsWith(s)?a.slice(s.length,-1):a.slice(0,-1);c&&r.push(c)}if(o=i.isTruncated,n=i.nextMarker,!o||!n)break}return r}async getBucketRaw(e){let r=await this.resolveDomain(e.consistency),n=await this.resolveCredential(),o={prefix:e.prefix};e.delimiter&&(o.delimiter=e.delimiter),e.marker&&(o.marker=e.marker),e.maxKeys&&(o["max-keys"]=e.maxKeys);try{let s=await b({domain:r,method:"GET",query:o,credential:n});if(!s.ok){let a=await I(s);throw new l(s.status,a||`getBucket failed: ${s.status}`)}let i=await s.text();return me(i)}catch(s){throw s instanceof l?s:new l(0,s.message||String(s))}}};async function I(t){try{return await t.text()}catch{return""}}function z(t){let e={};return t.forEach((r,n)=>{e[n.toLowerCase()]=r}),e}function me(t){let e=[],r=/<Contents>([\s\S]*?)<\/Contents>/g,n;for(;(n=r.exec(t))!==null;){let d=n[1],u=E(d,"Key"),g=E(d,"ETag");u!==null&&e.push({key:N(u),etag:g||""})}let o=[],s=/<CommonPrefixes>([\s\S]*?)<\/CommonPrefixes>/g;for(;(n=s.exec(t))!==null;){let d=n[1],u=E(d,"Prefix");u!==null&&o.push(N(u))}let a=E(t,"IsTruncated")==="true",c=E(t,"NextMarker")||"";return{contents:e,commonPrefixes:o,isTruncated:a,nextMarker:N(c)}}function E(t,e){let n=new RegExp(`<${e}>([\\s\\S]*?)<\\/${e}>`).exec(t);return n?n[1]:null}function N(t){return t.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&apos;/g,"'").replace(/&amp;/g,"&")}var ye="X-RateLimit-Reset";async function A(t,e,r=5){e.signal?.throwIfAborted?.();try{let n=await fetch(t,e);if(r>0&&(n.status===429||n.status>=500)){let o=Y(n.headers.get(ye));return await X(o,e.signal),A(t,e,r-1)}return n}catch(n){if(r===0||n instanceof DOMException&&n.name==="AbortError")throw n;let o=Y();return await X(o,e.signal),A(t,e,r-1)}}function Y(t){return t?Math.max(Number(t)*1e3-Date.now(),1e3):5e3}function X(t,e){return new Promise((r,n)=>{if(e?.aborted)return n(e.reason);let o=setTimeout(()=>{e?.removeEventListener("abort",s),r()},t),s=()=>{clearTimeout(o),n(e.reason)};e?.addEventListener("abort",s,{once:!0})})}var pe="prod";function F(){let t=typeof process<"u"?process.env.PAGES_BLOB_STS_ENV:void 0;return t==="test"||t==="prod"?t:pe}var we=300,Ce="https://blob-sts.edgeone.site/",k=class{authToken;projectId;cached=null;constructor(e,r){this.authToken=e,this.projectId=r}async getCredential(){if(this.cached&&!this.isExpired(this.cached))return this.cached;let e=await this.fetchCredential();return this.cached=e,e}clearCache(){this.cached=null}isExpired(e){let r=Math.floor(Date.now()/1e3);return e.expiredTime-r<we}async fetchCredential(){for(let r=1;r<=3;r++){let n=await A(Ce,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.authToken}`,"X-Env":F()},body:JSON.stringify(this.projectId?{ProjectId:this.projectId}:{})});if(n.status===413)throw new h("storage quota exceeded");if(n.status===429)throw new h("rate limited, please retry later");if(!n.ok){let i=await n.text().catch(()=>"unknown error");throw new h(`failed to obtain STS credential: ${n.status} ${i}`)}let o=await n.json(),s=o.data&&typeof o.data=="object"?o.data:o;if(s.tmpSecretId&&s.tmpSecretKey&&s.sessionToken&&s.expiredTime){let i=s.cosMainland,a=s.cosOverseas,c=n.headers.get("X-Edge-Region")||void 0;return{tmpSecretId:s.tmpSecretId,tmpSecretKey:s.tmpSecretKey,sessionToken:s.sessionToken,expiredTime:s.expiredTime,appId:s.appId||void 0,zoneId:s.zoneId||void 0,projectId:s.projectId||void 0,resourcePrefix:s.resourcePrefix||void 0,cosMainland:i||void 0,cosOverseas:a||void 0,edgeRegion:c}}if(s.code!==void 0&&s.code!==0){let i=s.msg||s.message||"unknown error";throw new h(`credential exchange failed (code=${s.code}): ${i}`)}if(o.code!==void 0&&o.code!==0){let i=o.msg||o.message||"unknown error";throw new h(`credential exchange failed (code=${o.code}): ${i}`)}if(r<3){await xe(1e3*r);continue}throw new h("invalid STS credential response")}throw new h("invalid STS credential response")}};function xe(t){return new Promise(e=>setTimeout(e,t))}var be="{{PAGES_BLOB_DEPLOY_CREDENTIAL}}";function W(){let t=Se();if(t)return{deployCredential:t};let e=Ie("PAGES_BLOB_DEPLOY_CREDENTIAL");return e?{deployCredential:e}:{}}function Se(){let t=be;if(!(t.startsWith("{{")&&t.endsWith("}}")))return t||void 0}function Ie(t){if(typeof process<"u"&&process.env)return process.env[t]}function Ee(t){let e=typeof t=="string"?t:t.name;$(e);let r=G(typeof t=="string"?void 0:t),n=new k(r.authToken,r.projectId),o=new T(n);return new x(o,e,r.consistency??"eventual")}async function Te(t){let e=G(t?{name:"__list__",projectId:t.projectId,token:t.token,consistency:t.consistency}:void 0),r=new k(e.authToken,e.projectId);return{stores:(await new T(r).listStores(e.consistency)).map(s=>({name:s}))}}function G(t){if(t?.token){if(!t.projectId)throw new C;return{authToken:t.token,projectId:t.projectId,consistency:t.consistency}}if(t?.projectId&&!t.token)throw new S(["token"]);let e=W();if(!e.deployCredential)throw new S(["deployCredential"]);return{authToken:e.deployCredential,consistency:t?.consistency}}0&&(module.exports={InvalidKeyError,InvalidStoreNameError,MissingProjectIdError,PagesBlobError,PreconditionFailedError,QuotaExceededError,RateLimitedError,Store,getStore,listStores});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edgeone/pages-blob",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Blob storage SDK for EdgeOne Pages functions",
5
5
  "publishConfig": {
6
6
  "access": "public"