@mateosuarezdev/brpc 1.0.73 → 1.0.74
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/dist/client/index.js +2 -2
- package/dist/client/storage.d.ts +4 -10
- package/dist/storage/images/constants.d.ts +1 -0
- package/dist/storage/images/types.d.ts +0 -1
- package/dist/storage/index.js +2 -2
- package/dist/storage/s3/types.d.ts +9 -3
- package/dist/storage/s3/upload.d.ts +3 -3
- package/dist/storage/types.d.ts +22 -16
- package/dist/storage/utils/files.d.ts +2 -8
- package/package.json +1 -1
package/dist/client/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
function b(q,G={placeholder:void 0,throwOnInvalid:!0},N){if(!q)return G?.placeholder??"PLACEHOLDER";if(q.url)return q.url;if(q.key)if(q.isPrivate||q.provider==="local")return`/storage/${q.key}`;else return`${N}/${q.key}`;if(G.throwOnInvalid)throw Error("Invalid storage object");else return G?.placeholder??"PLACEHOLDER"}class T extends Error{status;code;clientCode;data;constructor(q,G,N,Q,R){super(q);this.name="BrpcClientError",this.status=G,this.code=N,this.clientCode=Q,this.data=R}isClientError(q){return this.clientCode===q}isUnauthorized(){return this.status===401}isForbidden(){return this.status===403}isNotFound(){return this.status===404}isValidationError(){return this.status===400||this.code==="BAD_REQUEST"}}var U=(q)=>{return q instanceof File||q instanceof Blob||typeof q==="object"&&q!==null&&"uri"in q&&"name"in q&&"type"in q};function x(q){if(!q)return null;return q.replace(/\//g,"")}function v(q){let G=q&&q.length>0?q:typeof window<"u"?window.location.origin:"";return G=G.endsWith("/")?G.slice(0,-1):G,G}function m(q,G){let N=G?`/${G}/ws`:"/ws";return`${q.replace(/^http/,"ws")}${N}`}function k(q,G){if(q&&G)return`/${q}/${G}`;else if(q&&!G)return`/${q}`;else if(!q&&G)return`/${G}`;else return""}class h{baseUrl;ws=null;subscriptions=new Map;messageQueue=[];isConnected=!1;reconnectTimeout=null;WebSocketImpl;getHeaders;authToken=null;debug;pendingAuth=!1;authActions=[];constructor(q,G,N,Q=!1,R){this.baseUrl=q;this.WebSocketImpl=G,this.debug=Q&&R==="development",this.getHeaders=async()=>{if(typeof N==="function")return await N();return N??{}},this.connect()}async connect(){try{let q=await this.getHeaders();this.authToken=q.Authorization||null;let G=this.baseUrl;if(this.debug)console.log(`Connecting to WebSocket: ${G}`);this.ws=new this.WebSocketImpl(G),this.ws.onopen=async()=>{if(this.debug)console.log("WebSocket connection established");if(this.isConnected=!0,this.authActions=[],this.authToken){if(this.pendingAuth=!0,this.send({type:"authenticate",token:this.authToken}),this.debug)console.log("Sent authentication token, waiting for response");this.authActions.push(()=>{for(let N of this.subscriptions.keys())if(this.send({type:"subscribe",topic:N}),this.debug)console.log(`Resubscribed to topic: ${N}`);if(this.messageQueue.length>0&&this.debug)console.log(`Sending ${this.messageQueue.length} queued messages`);this.messageQueue.forEach((N)=>this.send(N)),this.messageQueue=[]})}else{for(let N of this.subscriptions.keys())if(this.send({type:"subscribe",topic:N}),this.debug)console.log(`Resubscribed to topic: ${N}`);if(this.messageQueue.length>0&&this.debug)console.log(`Sending ${this.messageQueue.length} queued messages`);this.messageQueue.forEach((N)=>this.send(N)),this.messageQueue=[]}},this.ws.onmessage=(N)=>{try{if(this.debug)console.log("WebSocket message received:",N.data);let Q=JSON.parse(N.data);if(Q.type==="auth_success"){let R=Q.authenticated!==!1;if(this.debug)console.log(`WebSocket ${R?"authentication":"deauthentication"} successful`);if(this.pendingAuth=!1,R)this.authActions.forEach((S)=>S());this.authActions=[];return}if(Q.type==="auth_error"){console.error("WebSocket authentication failed:",Q.error),this.pendingAuth=!1,this.authActions=[];return}if(this.debug)console.log("Got new message",Q);if(Q.topic&&this.subscriptions.has(Q.topic)){let R=this.subscriptions.get(Q.topic);if(this.debug)console.log("Calling subscription callbacks");R?.forEach((S)=>S(Q.data))}else if(Q.error)console.error("WebSocket error:",Q.error);else console.warn("Unhandled WebSocket message format:",Q)}catch(Q){if(this.debug)console.error("Error processing WebSocket message:",Q),console.error("Raw message:",N.data)}},this.ws.onclose=(N)=>{if(this.isConnected=!1,this.pendingAuth=!1,this.debug)console.log(`WebSocket connection closed. Code: ${N.code}, Reason: ${N.reason}`);this.reconnectTimeout=setTimeout(()=>this.connect(),2000)},this.ws.onerror=(N)=>{if(this.debug)console.log("WebSocket error:",N)}}catch(q){if(this.debug)console.log("Failed to create WebSocket connection:",q);this.pendingAuth=!1,this.reconnectTimeout=setTimeout(()=>this.connect(),2000)}}disconnect(){if(this.reconnectTimeout)clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null;if(this.ws)this.ws.close(),this.ws=null;this.isConnected=!1,this.pendingAuth=!1,this.authActions=[],this.subscriptions.clear()}send(q){if(this.isConnected&&this.ws?.readyState===this.WebSocketImpl.OPEN){if(this.pendingAuth&&q.type!=="authenticate"){if(this.messageQueue.push(q),this.debug)console.log("Message queued until authentication completes:",q);return}let G=JSON.stringify(q);if(this.ws.send(G),this.debug)console.log("WebSocket message sent:",G)}else if(this.messageQueue.push(q),this.debug)console.log("WebSocket message queued (not connected):",q)}subscribe(q,G){if(!this.subscriptions.has(q)){if(this.subscriptions.set(q,new Set),this.isConnected){if(this.pendingAuth)this.authActions.push(()=>{if(this.send({type:"subscribe",topic:q}),this.debug)console.log(`Subscribed to topic after auth: ${q}`)});else if(this.send({type:"subscribe",topic:q}),this.debug)console.log(`Subscribed to topic: ${q}`)}}return this.subscriptions.get(q).add(G),{unsubscribe:()=>this.unsubscribe(q,G),publish:(N)=>this.publish(q,N)}}unsubscribe(q,G){let N=this.subscriptions.get(q);if(N){if(N.delete(G),N.size===0){if(this.subscriptions.delete(q),this.send({type:"unsubscribe",topic:q}),this.debug)console.log(`Unsubscribed from topic: ${q}`)}}}publish(q,G){if(this.send({type:"publish",topic:q,data:G}),this.debug)console.log(`Published to topic: ${q}`,G)}async updateAuth(){let G=(await this.getHeaders()).Authorization||"",N=G.startsWith("Bearer ")?G.substring(7).trim():G.trim(),Q=N.length>0,R=this.authToken!==null&&this.authToken.trim().length>0;if((Q!==R||N!==this.authToken)&&this.isConnected){if(this.authToken=N,this.pendingAuth=Q,this.send({type:"authenticate",token:G}),this.debug)if(Q)console.log("Updated authentication token, waiting for confirmation");else console.log("Sent empty token for deauthentication"),this.pendingAuth=!1,this.authActions=[]}}}function Qq(q,G={}){let N=G.fetch||fetch,Q=G.WebSocket??(typeof WebSocket<"u"?WebSocket:null),R=G.prefix??"",S=G.apiPrefix??"",M=G.debug??!1,g=G.s3Endpoint,c=G.nodeEnv;if(!G.s3Endpoint)throw Error("BRPC Client: Pass s3Endpoint option to createBrpcClient");if(!G.nodeEnv)throw Error("BRPC Client: Pass nodeEnv option to createBrpcClient");if(!Q)throw Error("WebSocket is not available in this environment");let w=G.headers??{},d=async()=>{if(typeof w==="function")return await w();return w},j=v(q),f=x(G.prefix),u=x(G.apiPrefix),D=k(f,u),P=m(j,f),B=new h(P,Q,w,M,c),O=async(X=!0)=>{let I={};if(X)I["Content-Type"]="application/json";let J=await d();return{...I,...J}},n=async(X)=>{if(!X.ok){let J;try{J=await X.json()}catch{try{J={error:await X.text()}}catch{J={error:"Failed to parse error response"}}}if(J?.error&&typeof J.error==="object"){let A=J.error;throw new T(A.message||X.statusText,X.status,A.code,A.clientCode,A.data)}let $=J?.error||J?.message||X.statusText;throw new T($,X.status,void 0,void 0,J)}let I=X.headers.get("Content-Type")||"";try{if(I.includes("application/json"))return(await X.json()).data;else if(I.includes("text/"))return X.text();else return X.blob()}catch(J){throw new T(`Failed to parse response: ${J instanceof Error?J.message:"Unknown error"}`,X.status,"PARSE_ERROR")}},H=async(X,I)=>{try{let J=await N(X,I);return await n(J)}catch(J){if(J instanceof T)throw J;throw new T(J instanceof Error?J.message:"Network request failed",0,"NETWORK_ERROR")}},y=(X=[])=>{return new Proxy({},{get(I,J){if(typeof J==="symbol")return;if(J==="query"||J==="mutation"||J==="formMutation"||J==="subscription"||J==="getStringKey"||J==="getArrayKey"||J==="getNoInputsArrayKey"){let $=X.join("/"),A=`${j}${D}/${$}`;if(M)console.log(`BRPC ${J} procedure path: ${$}`),console.log(`BRPC ${J} full URL: ${A}`);if(J==="query")return async(Z)=>{let L=await O(!0);if(M)console.log(`BRPC query request to ${$}`,{input:Z,headers:L});let _=new URL(A);if(Z&&typeof Z==="object")Object.entries(Z).forEach(([W,F])=>{if(F!==void 0)_.searchParams.append(W,String(F))});let z=await H(_.toString(),{method:"GET",headers:L,credentials:"include"});if(M)console.log(`BRPC query response from ${$}:`,z);return z};else if(J==="mutation")return async(Z)=>{let L=await O(!0);if(M)console.log(`BRPC mutation request to ${$}`,{input:Z,headers:L});let _=JSON.stringify(Z),z=await H(A,{method:"POST",headers:L,body:_,credentials:"include"});if(M)console.log(`BRPC mutation response from ${$}:`,z);return z};else if(J==="formMutation")return async(Z)=>{let L=await O(!1);if(M)console.log(`BRPC formMutation request to ${$}`,{input:Z,headers:L});let _=new FormData,z=(F,Y,C)=>{let V=C?`${C}[${F}]`:F;if(Y===null||Y===void 0)return;else if(U(Y))_.append(V,Y);else if(Array.isArray(Y))Y.forEach((E,K)=>{if(U(E))_.append(V,E);else if(typeof E==="object"&&E!==null)Object.entries(E).forEach(([i,p])=>{z(i,p,`${V}[${K}]`)});else _.append(`${V}[${K}]`,String(E))});else if(typeof Y==="object"&&Y!==null)Object.entries(Y).forEach(([E,K])=>{z(E,K,V)});else _.append(V,String(Y))};Object.entries(Z).forEach(([F,Y])=>{z(F,Y)});let W=await H(A,{method:"POST",headers:L,body:_,credentials:"include"});if(M)console.log(`BRPC formMutation response from ${$}:`,W);return W};else if(J==="subscription")return(Z)=>{if(M)console.log(`BRPC subscription to ${$}`);let L=D?`${D.slice(1)}/${$}`:$;return B.updateAuth(),B.subscribe(L,Z)};else if(J==="getStringKey")return(Z)=>{let L=$;if(!Z||Object.keys(Z).length===0)return L;let _=Object.keys(Z).sort().reduce((W,F)=>{let Y=Z[F];if(Y!==void 0&&Y!==null)W[F]=Y;return W},{});if(Object.keys(_).length===0)return L;let z=JSON.stringify(_);return`${L}?${z}`};else if(J==="getArrayKey")return(Z,L)=>{let _=$,z={...Z??{},...L??{}};if(Object.keys(z).length===0)return[_];let W=[];if(Object.keys(z).sort().forEach((Y)=>{let C=z[Y];if(C!==void 0&&C!==null){let V=C;if(typeof C==="boolean"||typeof C==="number")V=String(C);else if(typeof C==="object")V=JSON.stringify(C);W.push([Y,V])}}),W.length===0)return[_];let F=W.flatMap(([Y,C])=>[Y,C]);return[_,...F]};else if(J==="getNoInputsArrayKey")return()=>{return[$]}}return y([...X,J])}})},l=y();if(M)console.log("BRPC client created",{baseUrl:j,prefix:D,wsUrl:P});return{routes:l,storage:{getObjectUrl:(X,I)=>b(X,I,g)},utils:{updateWsAuth:async()=>await B.updateAuth(),setHeader:async(X,I)=>{if(typeof w==="function"){console.warn("Cannot use setHeader with function-based headers resolver");return}w={...w,[X]:I},await B.updateAuth()},setHeaders:async(X)=>{if(typeof w==="function"){console.warn("Cannot use setHeaders with function-based headers resolver");return}w={...w,...X},await B.updateAuth()}}}}export{b as getObjectUrl,Qq as createBrpcClient,T as BrpcClientError};
|
|
2
|
+
function g(q){return(J)=>{if(!J)return null;return`${q}/${J}`}}class A extends Error{status;code;clientCode;data;constructor(q,J,O,Q,C){super(q);this.name="BrpcClientError",this.status=J,this.code=O,this.clientCode=Q,this.data=C}isClientError(q){return this.clientCode===q}isUnauthorized(){return this.status===401}isForbidden(){return this.status===403}isNotFound(){return this.status===404}isValidationError(){return this.status===400||this.code==="BAD_REQUEST"}}var U=(q)=>{return q instanceof File||q instanceof Blob||typeof q==="object"&&q!==null&&"uri"in q&&"name"in q&&"type"in q};function x(q){if(!q)return null;return q.replace(/\//g,"")}function v(q){let J=q&&q.length>0?q:typeof window<"u"?window.location.origin:"";return J=J.endsWith("/")?J.slice(0,-1):J,J}function m(q,J){let O=J?`/${J}/ws`:"/ws";return`${q.replace(/^http/,"ws")}${O}`}function y(q,J){if(q&&J)return`/${q}/${J}`;else if(q&&!J)return`/${q}`;else if(!q&&J)return`/${J}`;else return""}class b{baseUrl;ws=null;subscriptions=new Map;messageQueue=[];isConnected=!1;reconnectTimeout=null;WebSocketImpl;getHeaders;authToken=null;debug;pendingAuth=!1;authActions=[];constructor(q,J,O,Q=!1,C){this.baseUrl=q;this.WebSocketImpl=J,this.debug=Q&&C==="development",this.getHeaders=async()=>{if(typeof O==="function")return await O();return O??{}},this.connect()}async connect(){try{let q=await this.getHeaders();this.authToken=q.Authorization||null;let J=this.baseUrl;if(this.debug)console.log(`Connecting to WebSocket: ${J}`);this.ws=new this.WebSocketImpl(J),this.ws.onopen=async()=>{if(this.debug)console.log("WebSocket connection established");if(this.isConnected=!0,this.authActions=[],this.authToken){if(this.pendingAuth=!0,this.send({type:"authenticate",token:this.authToken}),this.debug)console.log("Sent authentication token, waiting for response");this.authActions.push(()=>{for(let O of this.subscriptions.keys())if(this.send({type:"subscribe",topic:O}),this.debug)console.log(`Resubscribed to topic: ${O}`);if(this.messageQueue.length>0&&this.debug)console.log(`Sending ${this.messageQueue.length} queued messages`);this.messageQueue.forEach((O)=>this.send(O)),this.messageQueue=[]})}else{for(let O of this.subscriptions.keys())if(this.send({type:"subscribe",topic:O}),this.debug)console.log(`Resubscribed to topic: ${O}`);if(this.messageQueue.length>0&&this.debug)console.log(`Sending ${this.messageQueue.length} queued messages`);this.messageQueue.forEach((O)=>this.send(O)),this.messageQueue=[]}},this.ws.onmessage=(O)=>{try{if(this.debug)console.log("WebSocket message received:",O.data);let Q=JSON.parse(O.data);if(Q.type==="auth_success"){let C=Q.authenticated!==!1;if(this.debug)console.log(`WebSocket ${C?"authentication":"deauthentication"} successful`);if(this.pendingAuth=!1,C)this.authActions.forEach((B)=>B());this.authActions=[];return}if(Q.type==="auth_error"){console.error("WebSocket authentication failed:",Q.error),this.pendingAuth=!1,this.authActions=[];return}if(this.debug)console.log("Got new message",Q);if(Q.topic&&this.subscriptions.has(Q.topic)){let C=this.subscriptions.get(Q.topic);if(this.debug)console.log("Calling subscription callbacks");C?.forEach((B)=>B(Q.data))}else if(Q.error)console.error("WebSocket error:",Q.error);else console.warn("Unhandled WebSocket message format:",Q)}catch(Q){if(this.debug)console.error("Error processing WebSocket message:",Q),console.error("Raw message:",O.data)}},this.ws.onclose=(O)=>{if(this.isConnected=!1,this.pendingAuth=!1,this.debug)console.log(`WebSocket connection closed. Code: ${O.code}, Reason: ${O.reason}`);this.reconnectTimeout=setTimeout(()=>this.connect(),2000)},this.ws.onerror=(O)=>{if(this.debug)console.log("WebSocket error:",O)}}catch(q){if(this.debug)console.log("Failed to create WebSocket connection:",q);this.pendingAuth=!1,this.reconnectTimeout=setTimeout(()=>this.connect(),2000)}}disconnect(){if(this.reconnectTimeout)clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null;if(this.ws)this.ws.close(),this.ws=null;this.isConnected=!1,this.pendingAuth=!1,this.authActions=[],this.subscriptions.clear()}send(q){if(this.isConnected&&this.ws?.readyState===this.WebSocketImpl.OPEN){if(this.pendingAuth&&q.type!=="authenticate"){if(this.messageQueue.push(q),this.debug)console.log("Message queued until authentication completes:",q);return}let J=JSON.stringify(q);if(this.ws.send(J),this.debug)console.log("WebSocket message sent:",J)}else if(this.messageQueue.push(q),this.debug)console.log("WebSocket message queued (not connected):",q)}subscribe(q,J){if(!this.subscriptions.has(q)){if(this.subscriptions.set(q,new Set),this.isConnected){if(this.pendingAuth)this.authActions.push(()=>{if(this.send({type:"subscribe",topic:q}),this.debug)console.log(`Subscribed to topic after auth: ${q}`)});else if(this.send({type:"subscribe",topic:q}),this.debug)console.log(`Subscribed to topic: ${q}`)}}return this.subscriptions.get(q).add(J),{unsubscribe:()=>this.unsubscribe(q,J),publish:(O)=>this.publish(q,O)}}unsubscribe(q,J){let O=this.subscriptions.get(q);if(O){if(O.delete(J),O.size===0){if(this.subscriptions.delete(q),this.send({type:"unsubscribe",topic:q}),this.debug)console.log(`Unsubscribed from topic: ${q}`)}}}publish(q,J){if(this.send({type:"publish",topic:q,data:J}),this.debug)console.log(`Published to topic: ${q}`,J)}async updateAuth(){let J=(await this.getHeaders()).Authorization||"",O=J.startsWith("Bearer ")?J.substring(7).trim():J.trim(),Q=O.length>0,C=this.authToken!==null&&this.authToken.trim().length>0;if((Q!==C||O!==this.authToken)&&this.isConnected){if(this.authToken=O,this.pendingAuth=Q,this.send({type:"authenticate",token:J}),this.debug)if(Q)console.log("Updated authentication token, waiting for confirmation");else console.log("Sent empty token for deauthentication"),this.pendingAuth=!1,this.authActions=[]}}}function Qq(q,J={}){let O=J.fetch||fetch,Q=J.WebSocket??(typeof WebSocket<"u"?WebSocket:null),C=J.prefix??"",B=J.apiPrefix??"",F=J.debug??!1,k=J.s3Endpoint,c=J.nodeEnv;if(!J.s3Endpoint)throw Error("BRPC Client: Pass s3Endpoint option to createBrpcClient");if(!J.nodeEnv)throw Error("BRPC Client: Pass nodeEnv option to createBrpcClient");if(!Q)throw Error("WebSocket is not available in this environment");let W=J.headers??{},d=async()=>{if(typeof W==="function")return await W();return W},D=v(q),f=x(J.prefix),u=x(J.apiPrefix),E=y(f,u),h=m(D,f),T=new b(h,Q,W,F,c),K=async(X=!0)=>{let M={};if(X)M["Content-Type"]="application/json";let N=await d();return{...M,...N}},l=async(X)=>{if(!X.ok){let N;try{N=await X.json()}catch{try{N={error:await X.text()}}catch{N={error:"Failed to parse error response"}}}if(N?.error&&typeof N.error==="object"){let V=N.error;throw new A(V.message||X.statusText,X.status,V.code,V.clientCode,V.data)}let $=N?.error||N?.message||X.statusText;throw new A($,X.status,void 0,void 0,N)}let M=X.headers.get("Content-Type")||"";try{if(M.includes("application/json"))return(await X.json()).data;else if(M.includes("text/"))return X.text();else return X.blob()}catch(N){throw new A(`Failed to parse response: ${N instanceof Error?N.message:"Unknown error"}`,X.status,"PARSE_ERROR")}},H=async(X,M)=>{try{let N=await O(X,M);return await l(N)}catch(N){if(N instanceof A)throw N;throw new A(N instanceof Error?N.message:"Network request failed",0,"NETWORK_ERROR")}},P=(X=[])=>{return new Proxy({},{get(M,N){if(typeof N==="symbol")return;if(N==="query"||N==="mutation"||N==="formMutation"||N==="subscription"||N==="getStringKey"||N==="getArrayKey"||N==="getNoInputsArrayKey"){let $=X.join("/"),V=`${D}${E}/${$}`;if(F)console.log(`BRPC ${N} procedure path: ${$}`),console.log(`BRPC ${N} full URL: ${V}`);if(N==="query")return async(Z)=>{let j=await K(!0);if(F)console.log(`BRPC query request to ${$}`,{input:Z,headers:j});let _=new URL(V);if(Z&&typeof Z==="object")Object.entries(Z).forEach(([I,z])=>{if(z!==void 0)_.searchParams.append(I,String(z))});let G=await H(_.toString(),{method:"GET",headers:j,credentials:"include"});if(F)console.log(`BRPC query response from ${$}:`,G);return G};else if(N==="mutation")return async(Z)=>{let j=await K(!0);if(F)console.log(`BRPC mutation request to ${$}`,{input:Z,headers:j});let _=JSON.stringify(Z),G=await H(V,{method:"POST",headers:j,body:_,credentials:"include"});if(F)console.log(`BRPC mutation response from ${$}:`,G);return G};else if(N==="formMutation")return async(Z)=>{let j=await K(!1);if(F)console.log(`BRPC formMutation request to ${$}`,{input:Z,headers:j});let _=new FormData,G=(z,Y,L)=>{let R=L?`${L}[${z}]`:z;if(Y===null||Y===void 0)return;else if(U(Y))_.append(R,Y);else if(Array.isArray(Y))Y.forEach((w,S)=>{if(U(w))_.append(R,w);else if(typeof w==="object"&&w!==null)Object.entries(w).forEach(([i,p])=>{G(i,p,`${R}[${S}]`)});else _.append(`${R}[${S}]`,String(w))});else if(typeof Y==="object"&&Y!==null)Object.entries(Y).forEach(([w,S])=>{G(w,S,R)});else _.append(R,String(Y))};Object.entries(Z).forEach(([z,Y])=>{G(z,Y)});let I=await H(V,{method:"POST",headers:j,body:_,credentials:"include"});if(F)console.log(`BRPC formMutation response from ${$}:`,I);return I};else if(N==="subscription")return(Z)=>{if(F)console.log(`BRPC subscription to ${$}`);let j=E?`${E.slice(1)}/${$}`:$;return T.updateAuth(),T.subscribe(j,Z)};else if(N==="getStringKey")return(Z)=>{let j=$;if(!Z||Object.keys(Z).length===0)return j;let _=Object.keys(Z).sort().reduce((I,z)=>{let Y=Z[z];if(Y!==void 0&&Y!==null)I[z]=Y;return I},{});if(Object.keys(_).length===0)return j;let G=JSON.stringify(_);return`${j}?${G}`};else if(N==="getArrayKey")return(Z,j)=>{let _=$,G={...Z??{},...j??{}};if(Object.keys(G).length===0)return[_];let I=[];if(Object.keys(G).sort().forEach((Y)=>{let L=G[Y];if(L!==void 0&&L!==null){let R=L;if(typeof L==="boolean"||typeof L==="number")R=String(L);else if(typeof L==="object")R=JSON.stringify(L);I.push([Y,R])}}),I.length===0)return[_];let z=I.flatMap(([Y,L])=>[Y,L]);return[_,...z]};else if(N==="getNoInputsArrayKey")return()=>{return[$]}}return P([...X,N])}})},n=P();if(F)console.log("BRPC client created",{baseUrl:D,prefix:E,wsUrl:h});return{routes:n,storage:{getObjectUrl:g(k)},utils:{updateWsAuth:async()=>await T.updateAuth(),setHeader:async(X,M)=>{if(typeof W==="function"){console.warn("Cannot use setHeader with function-based headers resolver");return}W={...W,[X]:M},await T.updateAuth()},setHeaders:async(X)=>{if(typeof W==="function"){console.warn("Cannot use setHeaders with function-based headers resolver");return}W={...W,...X},await T.updateAuth()}}}}export{g as createGetObjectUrl,Qq as createBrpcClient,A as BrpcClientError};
|
|
3
3
|
|
|
4
|
-
//# debugId=
|
|
4
|
+
//# debugId=706C45AEC3B9A12C64756E2164756E21
|
package/dist/client/storage.d.ts
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
export type GetObjectUrl = (storageObject: StorageObject | null | undefined, options: {
|
|
3
|
-
placeholder?: string;
|
|
4
|
-
throwOnInvalid?: boolean;
|
|
5
|
-
}) => string;
|
|
1
|
+
export type GetObjectUrl = (key: string | null | undefined) => string | null;
|
|
6
2
|
/**
|
|
7
|
-
*
|
|
3
|
+
* Returns a factory bound to the s3Endpoint configured at client construction.
|
|
4
|
+
* Pass the key from whichever variant you need — e.g. object.variants.xl?.key
|
|
8
5
|
*/
|
|
9
|
-
export declare function
|
|
10
|
-
placeholder?: string;
|
|
11
|
-
throwOnInvalid?: boolean;
|
|
12
|
-
} | undefined, s3Endpoint: string): string;
|
|
6
|
+
export declare function createGetObjectUrl(s3Endpoint: string): GetObjectUrl;
|
package/dist/storage/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var S=($)=>$.startsWith("image/"),j=($)=>$.startsWith("video/"),q=($)=>$.startsWith("audio/"),F=($)=>$.startsWith("text/")||$.includes("pdf")||$.includes("word")||$.includes("sheet")||$.includes("presentation")||$.includes("opendocument")||$==="application/rtf",N=($)=>$.includes("zip")||$.includes("rar")||$.includes("tar")||$.includes("7z")||$.includes("gzip"),T=($)=>$==="application/javascript"||$==="application/json"||$==="text/html"||$==="text/css"||$==="application/xml"||$.includes("javascript"),z=($)=>$.startsWith("font/")||$.includes("font"),O=($)=>{if(!$)return"other";let W=$.toLowerCase();if(S(W))return"image";if(j(W))return"video";if(q(W))return"audio";if(F(W))return"document";if(N(W))return"archive";if(T(W))return"code";if(z(W))return"font";return"other"},x={isImage:S,isVideo:j,isAudio:q,isDocument:F,isArchive:N,isCode:T,isFont:z};function o(){let W=Buffer.from("Hello, this is a test file for S3 upload!","utf-8");return new File([W],"test.txt",{type:"text/plain"})}function r($,W){if($.url)return $.url;if($.key)if($.isPrivate)return`/storage/${$.key}`;else return`https://${W?.bucket??process.env.AWS_BUCKET}.s3.amazonaws.com/${$.key}`;throw Error("Invalid storage object")}function G($,W){if(!$||$<1||!W||W<1)return"1:1";let H=(L,Q)=>Q===0?L:H(Q,L%Q),J=H($,W);return`${$/J}:${W/J}`}function a($,W){if(!$||!W||$<1||W<1)return"1:1";let H=$/W,J=[{ratio:1,label:"1:1"},{ratio:0.8,label:"4:5"},{ratio:0.75,label:"3:4"},{ratio:0.6666666666666666,label:"2:3"},{ratio:0.5625,label:"9:16"},{ratio:1.5,label:"3:2"},{ratio:1.3333333333333333,label:"4:3"},{ratio:1.7777777777777777,label:"16:9"},{ratio:2.3333333333333335,label:"21:9"}],L=0.03;for(let{ratio:X,label:Z}of J)if(Math.abs(H-X)/X<L)return Z;let Q=(X,Z)=>Z===0?X:Q(Z,X%Z),Y=Q($,W);return`${$/Y}:${W/Y}`}class M extends Error{code;clientCode;httpStatus;data;cause;static STATUS_MAP={BAD_REQUEST:400,UNAUTHORIZED:401,FORBIDDEN:403,NOT_FOUND:404,METHOD_NOT_SUPPORTED:405,TIMEOUT:408,CONFLICT:409,PRECONDITION_FAILED:412,PAYLOAD_TOO_LARGE:413,UNPROCESSABLE_CONTENT:422,TOO_MANY_REQUESTS:429,CLIENT_CLOSED_REQUEST:499,INTERNAL_SERVER_ERROR:500,NOT_IMPLEMENTED:501,BAD_GATEWAY:502,SERVICE_UNAVAILABLE:503,GATEWAY_TIMEOUT:504};constructor($){super($.message);if(this.name="BRPCError",this.code=$.code,this.clientCode=$.clientCode,this.httpStatus=M.STATUS_MAP[$.code],this.data=$.data,this.cause=$.cause,Error.captureStackTrace)Error.captureStackTrace(this,M)}toJSON(){return{name:this.name,code:this.code,clientCode:this.clientCode,message:this.message,data:this.data,httpStatus:this.httpStatus}}static badRequest($,W,H){return new M({code:"BAD_REQUEST",message:$,clientCode:W,data:H})}static unauthorized($="Unauthorized",W,H){return new M({code:"UNAUTHORIZED",message:$,clientCode:W,data:H})}static forbidden($="Forbidden",W,H){return new M({code:"FORBIDDEN",message:$,clientCode:W,data:H})}static notFound($="Not Found",W,H){return new M({code:"NOT_FOUND",message:$,clientCode:W,data:H})}static preconditionFailed($="Precondition failed",W,H){return new M({code:"NOT_FOUND",message:$,clientCode:W,data:H})}static conflict($,W,H){return new M({code:"CONFLICT",message:$,clientCode:W,data:H})}static unprocessableContent($,W,H){return new M({code:"UNPROCESSABLE_CONTENT",message:$,clientCode:W,data:H})}static tooManyRequests($="Too many requests",W,H){return new M({code:"TOO_MANY_REQUESTS",message:$,clientCode:W,data:H})}static internalServerError($="Internal Server Error",W,H){return new M({code:"INTERNAL_SERVER_ERROR",message:$,clientCode:W,data:H})}static timeout($="Request timeout",W,H){return new M({code:"TIMEOUT",message:$,clientCode:W,data:H})}}import P from"sharp";var w={xs:200,sm:400,md:800,lg:1200},V=1920;async function D($,W,H,J,L){try{let{data:Q,info:Y}=await P($,{limitInputPixels:1e8}).rotate().resize({width:W,height:W,fit:"inside",withoutEnlargement:!0}).webp({quality:H}).toBuffer({resolveWithObject:!0});return{buffer:Q,object:{name:J.replace(/\.[^/.]+$/,".webp"),resolvedType:"image",metadata:{type:"image/webp",size:Q.length,extension:".webp",width:Y.width,height:Y.height,aspectRatio:Y.width&&Y.height?Y.width/Y.height:1,aspectRatioStr:Y.width&&Y.height?G(Y.width,Y.height):"1:1",acl:L}}}}catch(Q){throw M.conflict(`Failed to optimize image: ${Q instanceof Error?Q.message:"Unknown error"}`)}}async function I($){if(!$)throw M.conflict("A file must be provided");let W,H="unknown.webp";if(typeof $==="string"){if(console.log("I'm going to fail here for file",$),!$.startsWith("data:"))throw console.log("I never got here"),M.conflict("Invalid base64 format");let[,J]=$.split(",");if(!J)throw M.conflict("Invalid base64 data");W=Buffer.from(J,"base64")}else{if(!x.isImage($.type))throw M.conflict("File must be an image");let J=await $.arrayBuffer();W=Buffer.from(J),H=$.name??H}return{buffer:W,name:H}}async function L0($,{size:W,quality:H,acl:J}={}){let L=await I($);return D(L.buffer,W??V,H??80,L.name,J??"public-read")}async function M0($,{name:W="unknown.webp",size:H,quality:J,acl:L}={}){if(!$?.length)throw M.conflict("A buffer must be provided");return D($,H??V,J??80,W,L??"public-read")}async function k($,{quality:W=80,acl:H="public-read"}={}){console.log("Going to normalizeImageInput");let J=await I($);console.log("Going to processSharpImage for original");let L=await D(J.buffer,V,W,J.name,H);console.log("Going to processSharpImage for variantsEntries");let Q=await Promise.all(Object.entries(w).map(async([Y,X])=>{let Z=await D(J.buffer,X,W,J.name,H);return[Y,Z]}));return{original:L,variants:Object.fromEntries(Q)}}import c from"sharp";import{randomUUID as b}from"crypto";import{extname as C}from"path";async function v($,W,H){if(!W)return{data:null,error:Error("File not found")};let J=$.replace(/^\/+|\/+$/g,""),L=C(W.name),Q=`${b()}${L}`,Y=`${J}/${Q}`,X=`./buckets/${J}/${Q}`;try{let Z=await Bun.write(X,W);return{data:{key:Y,file:W,bytesWritten:Z},error:null}}catch(Z){return{data:null,error:Error(`Failed to upload ${W.name} to local filesystem`)}}}async function g($,W,H){if(!W||W.length===0)return[];let J=W.map((Q)=>{let Y=H?.(Q)??Q.name;return v($,Q,Y)});return await Promise.all(J)}async function m($){let W=Bun.file(`./buckets/${$}`);if(!await W.exists())return null;return W}async function h($){let W=Bun.file(`./buckets/${$}`);if(!await W.exists())return!1;return await W.delete(),!0}var U={uploadOne:v,uploadMany:g,getOne:m,deleteOne:h};async function D0($){let W=`./cache/images/${$.key}_${$.width}_${$.quality}.webp`,H=await U.getOne(W);if(H){if(!x.isImage(H.type))return null;return H}let J=$.key,L=await U.getOne(J);if(!L)return null;if(!x.isImage(L.type))return null;let Q=await L.arrayBuffer(),Y=await c(Q).resize($.width,null,{withoutEnlargement:!0}).webp({quality:$.quality??75}).toBuffer();await Bun.write(W,Y);let X=Bun.file(W);if(!await X.exists())return null;return X}import u from"sharp";async function j0($){if(!$?.length)return null;try{let W=await u($).metadata(),H=W.width??0,J=W.height??0,L=W.height>0?H/J:1;return{type:`image/${W.format}`,size:W.size??0,extension:`.${W.format}`,width:H,height:J,aspectRatio:L,aspectRatioStr:G(H,J)}}catch(W){return console.warn("Failed to read image metadata:",W),null}}var R=process.env.AWS_FOLDER,B=R?`${R}/`:"";var{s3:y}=globalThis.Bun;import{extname as d}from"path";async function A($,W,H){let J="buffer"in W?W:{buffer:W,object:{name:W.name,resolvedType:O(W.type),metadata:{type:W.type,extension:d(W.name),size:W.size,acl:H?.acl??"public-read"}}};if("buffer"in W){if(!W.object?.name||!W.object?.metadata)throw M.badRequest("Complete metadata required when uploading buffer")}let L=$.length>1?`${$.replace(/^\/+|\/+$/g,"")}/`:"",Q=J.object.metadata.extension.startsWith(".")?J.object.metadata.extension:`.${J.object.metadata.extension}`,Y=J.object.name?J.object.name:`${crypto.randomUUID()}${Q}`,X=`${B}${L}${Y}`,Z=y.file(X),_=J?.object?.metadata?.acl??"public-read",K=_!=="public-read"&&_!=="public-read-write",E=await Z.write(J.buffer,{acl:_,type:J.object.metadata.type});return{uploadedBy:H?.uploadedBy??null,key:X,url:null,name:J.object.name,thumbnail:null,resolvedType:J.object.resolvedType,provider:"s3",isPrivate:K,metadata:{...J.object.metadata,size:E,acl:_},isActive:!0}}async function k0($,W,H={throwIf:"any"}){let J=await Promise.allSettled(W.map((Y)=>A($,Y,{acl:H?.acl,uploadedBy:H?.uploadedBy}))),L=[],Q=[];if(J.forEach((Y)=>{if(Y.status==="fulfilled"){if(L.push(Y.value),H?.externalKeys)H.externalKeys.push(Y.value.key)}else Q.push(Y.reason)}),H?.throwIf==="any"&&Q.length>0||H?.throwIf==="all"&&Q.length===W.length)throw M.internalServerError(`Upload failed: ${Q.length} of ${W.length}`);return{data:L,errors:Q.length?Q:void 0}}async function f($,W,H){let J=H?.baseId??crypto.randomUUID(),L=W.original.object.metadata.extension,Q=await A($,{...W.original,object:{...W.original.object,name:`${J}${L}`}},H),Y=await Promise.all(Object.entries(W.variants).map(async([X,Z])=>{if(!Z)return[X,null];let _=Z.object.metadata.extension,K=await A($,{...Z,object:{...Z.object,name:`${J}_${X}${_}`}},H);return[X,{key:K.key,url:K.url,name:K.name,metadata:{type:K.metadata?.type,size:K.metadata?.size,extension:K.metadata?.extension,width:K.metadata?.width,height:K.metadata?.height,aspectRatio:K.metadata?.aspectRatio,aspectRatioStr:K.metadata?.aspectRatioStr,resolution:K.metadata?.resolution,bitrate:K.metadata?.bitrate,codec:K.metadata?.codec,fps:K.metadata?.fps}}]}));return{original:Q,variants:Object.fromEntries(Y.filter(([,X])=>X!==null))}}async function v0($,W,H){if(Array.isArray(W))throw Error("File can't be an array, pass a single file");let J=await k(W,{quality:H?.quality,acl:H?.acl});return f($,J,{acl:H?.acl,uploadedBy:H?.uploadedBy})}var{s3:n}=globalThis.Bun;async function p($,W){if(!$||typeof $!=="string")throw M.badRequest("Key is required");let H=$.trim();if(!H||H.length===0)throw M.badRequest("Key must be a non-empty string");try{return await n.delete($),{key:$,deleted:!0,error:null}}catch(J){return{key:$,deleted:!1,error:J}}}async function P0($,W){return(await Promise.allSettled($.map((J)=>p(J,W)))).map((J,L)=>{if(J.status==="fulfilled")return J.value;return{key:$[L],deleted:!1,error:J.reason}})}var{s3:s}=globalThis.Bun;async function g0($,W={debug:!0}){try{return{exists:await s.exists($),error:null}}catch(H){if(W?.debug)console.error("There was an error checking for file existance",H);return{exists:null,error:H}}}export{A as uploadOne,k0 as uploadMany,f as uploadGeneratedVariants,M0 as optimizeImageBuffer,L0 as optimizeImage,O as mimeTypeToResolvedType,D0 as getOptimizedImage,r as getObjectUrl,j0 as getImageMetadata,a as getAspectRatioStringRound,G as getAspectRatioString,k as generateVariants,o as generateTestFile,v0 as generateAndUploadImage,x as fileTypePredicates,p as deleteOne,P0 as deleteMany,g0 as checkFileExistance};
|
|
2
|
+
var U=($)=>$.startsWith("image/"),V=($)=>$.startsWith("video/"),q=($)=>$.startsWith("audio/"),A=($)=>$.startsWith("text/")||$.includes("pdf")||$.includes("word")||$.includes("sheet")||$.includes("presentation")||$.includes("opendocument")||$==="application/rtf",F=($)=>$.includes("zip")||$.includes("rar")||$.includes("tar")||$.includes("7z")||$.includes("gzip"),S=($)=>$==="application/javascript"||$==="application/json"||$==="text/html"||$==="text/css"||$==="application/xml"||$.includes("javascript"),N=($)=>$.startsWith("font/")||$.includes("font"),z=($)=>{if(!$)return"other";let W=$.toLowerCase();if(U(W))return"image";if(V(W))return"video";if(q(W))return"audio";if(A(W))return"document";if(F(W))return"archive";if(S(W))return"code";if(N(W))return"font";return"other"},D={isImage:U,isVideo:V,isAudio:q,isDocument:A,isArchive:F,isCode:S,isFont:N};function o(){let W=Buffer.from("Hello, this is a test file for S3 upload!","utf-8");return new File([W],"test.txt",{type:"text/plain"})}function x($,W){if(!$||$<1||!W||W<1)return"1:1";let j=(Q,J)=>J===0?Q:j(J,Q%J),H=j($,W);return`${$/H}:${W/H}`}function t($,W){if(!$||!W||$<1||W<1)return"1:1";let j=$/W,H=[{ratio:1,label:"1:1"},{ratio:0.8,label:"4:5"},{ratio:0.75,label:"3:4"},{ratio:0.6666666666666666,label:"2:3"},{ratio:0.5625,label:"9:16"},{ratio:1.5,label:"3:2"},{ratio:1.3333333333333333,label:"4:3"},{ratio:1.7777777777777777,label:"16:9"},{ratio:2.3333333333333335,label:"21:9"}],Q=0.03;for(let{ratio:X,label:K}of H)if(Math.abs(j-X)/X<Q)return K;let J=(X,K)=>K===0?X:J(K,X%K),Y=J($,W);return`${$/Y}:${W/Y}`}class L extends Error{code;clientCode;httpStatus;data;cause;static STATUS_MAP={BAD_REQUEST:400,UNAUTHORIZED:401,FORBIDDEN:403,NOT_FOUND:404,METHOD_NOT_SUPPORTED:405,TIMEOUT:408,CONFLICT:409,PRECONDITION_FAILED:412,PAYLOAD_TOO_LARGE:413,UNPROCESSABLE_CONTENT:422,TOO_MANY_REQUESTS:429,CLIENT_CLOSED_REQUEST:499,INTERNAL_SERVER_ERROR:500,NOT_IMPLEMENTED:501,BAD_GATEWAY:502,SERVICE_UNAVAILABLE:503,GATEWAY_TIMEOUT:504};constructor($){super($.message);if(this.name="BRPCError",this.code=$.code,this.clientCode=$.clientCode,this.httpStatus=L.STATUS_MAP[$.code],this.data=$.data,this.cause=$.cause,Error.captureStackTrace)Error.captureStackTrace(this,L)}toJSON(){return{name:this.name,code:this.code,clientCode:this.clientCode,message:this.message,data:this.data,httpStatus:this.httpStatus}}static badRequest($,W,j){return new L({code:"BAD_REQUEST",message:$,clientCode:W,data:j})}static unauthorized($="Unauthorized",W,j){return new L({code:"UNAUTHORIZED",message:$,clientCode:W,data:j})}static forbidden($="Forbidden",W,j){return new L({code:"FORBIDDEN",message:$,clientCode:W,data:j})}static notFound($="Not Found",W,j){return new L({code:"NOT_FOUND",message:$,clientCode:W,data:j})}static preconditionFailed($="Precondition failed",W,j){return new L({code:"NOT_FOUND",message:$,clientCode:W,data:j})}static conflict($,W,j){return new L({code:"CONFLICT",message:$,clientCode:W,data:j})}static unprocessableContent($,W,j){return new L({code:"UNPROCESSABLE_CONTENT",message:$,clientCode:W,data:j})}static tooManyRequests($="Too many requests",W,j){return new L({code:"TOO_MANY_REQUESTS",message:$,clientCode:W,data:j})}static internalServerError($="Internal Server Error",W,j){return new L({code:"INTERNAL_SERVER_ERROR",message:$,clientCode:W,data:j})}static timeout($="Request timeout",W,j){return new L({code:"TIMEOUT",message:$,clientCode:W,data:j})}}import B from"sharp";var T={xs:200,sm:400,md:800,lg:1200,xl:1920},_=1920;async function G($,W,j,H,Q){try{let{data:J,info:Y}=await B($,{limitInputPixels:1e8}).rotate().resize({width:W,height:W,fit:"inside",withoutEnlargement:!0}).webp({quality:j}).toBuffer({resolveWithObject:!0});return{buffer:J,object:{name:H.replace(/\.[^/.]+$/,".webp"),resolvedType:"image",metadata:{type:"image/webp",size:J.length,extension:".webp",width:Y.width,height:Y.height,aspectRatio:Y.width&&Y.height?Y.width/Y.height:1,aspectRatioStr:Y.width&&Y.height?x(Y.width,Y.height):"1:1",acl:Q}}}}catch(J){throw L.conflict(`Failed to optimize image: ${J instanceof Error?J.message:"Unknown error"}`)}}async function w($){if(!$)throw L.conflict("A file must be provided");let W,j="unknown.webp";if(typeof $==="string"){if(console.log("I'm going to fail here for file",$),!$.startsWith("data:"))throw console.log("I never got here"),L.conflict("Invalid base64 format");let[,H]=$.split(",");if(!H)throw L.conflict("Invalid base64 data");W=Buffer.from(H,"base64")}else{if(!D.isImage($.type))throw L.conflict("File must be an image");let H=await $.arrayBuffer();W=Buffer.from(H),j=$.name??j}return{buffer:W,name:j}}async function Q0($,{size:W,quality:j,acl:H}={}){let Q=await w($);return G(Q.buffer,W??_,j??80,Q.name,H??"public-read")}async function Y0($,{name:W="unknown.webp",size:j,quality:H,acl:Q}={}){if(!$?.length)throw L.conflict("A buffer must be provided");return G($,j??_,H??80,W,Q??"public-read")}async function I($,{quality:W=80,acl:j="public-read"}={}){let H=await w($),Q=await Promise.all(Object.entries(T).map(async([J,Y])=>{let X=await G(H.buffer,Y,W,H.name,j);return[J,X]}));return{variants:Object.fromEntries(Q)}}import m from"sharp";import{randomUUID as P}from"crypto";import{extname as C}from"path";async function k($,W,j){if(!W)return{data:null,error:Error("File not found")};let H=$.replace(/^\/+|\/+$/g,""),Q=C(W.name),J=`${P()}${Q}`,Y=`${H}/${J}`,X=`./buckets/${H}/${J}`;try{let K=await Bun.write(X,W);return{data:{key:Y,file:W,bytesWritten:K},error:null}}catch(K){return{data:null,error:Error(`Failed to upload ${W.name} to local filesystem`)}}}async function g($,W,j){if(!W||W.length===0)return[];let H=W.map((J)=>{let Y=j?.(J)??J.name;return k($,J,Y)});return await Promise.all(H)}async function c($){let W=Bun.file(`./buckets/${$}`);if(!await W.exists())return null;return W}async function h($){let W=Bun.file(`./buckets/${$}`);if(!await W.exists())return!1;return await W.delete(),!0}var O={uploadOne:k,uploadMany:g,getOne:c,deleteOne:h};async function _0($){let W=`./cache/images/${$.key}_${$.width}_${$.quality}.webp`,j=await O.getOne(W);if(j){if(!D.isImage(j.type))return null;return j}let H=$.key,Q=await O.getOne(H);if(!Q)return null;if(!D.isImage(Q.type))return null;let J=await Q.arrayBuffer(),Y=await m(J).resize($.width,null,{withoutEnlargement:!0}).webp({quality:$.quality??75}).toBuffer();await Bun.write(W,Y);let X=Bun.file(W);if(!await X.exists())return null;return X}import u from"sharp";async function V0($){if(!$?.length)return null;try{let W=await u($).metadata(),j=W.width??0,H=W.height??0,Q=W.height>0?j/H:1;return{type:`image/${W.format}`,size:W.size??0,extension:`.${W.format}`,width:j,height:H,aspectRatio:Q,aspectRatioStr:x(j,H)}}catch(W){return console.warn("Failed to read image metadata:",W),null}}var v=process.env.AWS_FOLDER,b=v?`${v}/`:"";var{s3:y}=globalThis.Bun;import{extname as d}from"path";async function R($,W,j){let H="buffer"in W?W:{buffer:W,object:{name:W.name,resolvedType:z(W.type),metadata:{type:W.type,extension:d(W.name),size:W.size,acl:j?.acl??"public-read"}}};if("buffer"in W){if(!W.object?.name||!W.object?.metadata)throw L.badRequest("Complete metadata required when uploading buffer")}let Q=$.length>1?`${$.replace(/^\/+|\/+$/g,"")}/`:"",J=H.object.metadata.extension.startsWith(".")?H.object.metadata.extension:`.${H.object.metadata.extension}`,Y=H.object.name?H.object.name:`${crypto.randomUUID()}${J}`,X=`${b}${Q}${Y}`,K=y.file(X),M=H?.object?.metadata?.acl??"public-read",Z=M!=="public-read"&&M!=="public-read-write",E=await K.write(H.buffer,{acl:M,type:H.object.metadata.type});return{uploadedBy:j?.uploadedBy??null,key:X,url:null,name:H.object.name,resolvedType:H.object.resolvedType,provider:"s3",isPrivate:Z,metadata:{...H.object.metadata,size:E,acl:M},isActive:!0}}async function I0($,W,j={throwIf:"any"}){let H=await Promise.allSettled(W.map((Y)=>R($,Y,{acl:j?.acl,uploadedBy:j?.uploadedBy}))),Q=[],J=[];if(H.forEach((Y)=>{if(Y.status==="fulfilled"){if(Q.push(Y.value),j?.externalKeys)j.externalKeys.push(Y.value.key)}else J.push(Y.reason)}),j?.throwIf==="any"&&J.length>0||j?.throwIf==="all"&&J.length===W.length)throw L.internalServerError(`Upload failed: ${J.length} of ${W.length}`);return{data:Q,errors:J.length?J:void 0}}async function f($,W,j){let H=j?.baseId??crypto.randomUUID(),Q=Object.values(W.variants).find(Boolean),J=await Promise.all(Object.entries(W.variants).map(async([X,K])=>{if(!K)return[X,null];let M=K.object.metadata.extension,Z=await R($,{...K,object:{...K.object,name:`${H}_${X}${M}`}},j);return[X,{key:Z.key,url:Z.url,name:Z.name,metadata:{type:Z.metadata?.type,extension:Z.metadata?.extension,size:Z.metadata?.size,hash:null,width:Z.metadata?.width,height:Z.metadata?.height,aspectRatio:Z.metadata?.aspectRatio,aspectRatioStr:Z.metadata?.aspectRatioStr,resolution:Z.metadata?.resolution,bitrate:Z.metadata?.bitrate,codec:Z.metadata?.codec,fps:Z.metadata?.fps}}]})),Y=(j?.acl??"public-read")!=="public-read"&&(j?.acl??"public-read")!=="public-read-write";return{shared:{name:Q.object.name,resolvedType:Q.object.resolvedType,provider:"s3",isPrivate:Y,uploadedBy:j?.uploadedBy??null},variants:Object.fromEntries(J.filter(([,X])=>X!==null))}}async function k0($,W,j){if(Array.isArray(W))throw Error("File can't be an array, pass a single file");let H=await I(W,{quality:j?.quality,acl:j?.acl});return f($,H,{acl:j?.acl,uploadedBy:j?.uploadedBy})}var{s3:n}=globalThis.Bun;async function p($,W){if(!$||typeof $!=="string")throw L.badRequest("Key is required");let j=$.trim();if(!j||j.length===0)throw L.badRequest("Key must be a non-empty string");try{return await n.delete($),{key:$,deleted:!0,error:null}}catch(H){return{key:$,deleted:!1,error:H}}}async function E0($,W){return(await Promise.allSettled($.map((H)=>p(H,W)))).map((H,Q)=>{if(H.status==="fulfilled")return H.value;return{key:$[Q],deleted:!1,error:H.reason}})}var{s3:s}=globalThis.Bun;async function C0($,W={debug:!0}){try{return{exists:await s.exists($),error:null}}catch(j){if(W?.debug)console.error("There was an error checking for file existance",j);return{exists:null,error:j}}}export{R as uploadOne,I0 as uploadMany,f as uploadGeneratedVariants,Y0 as optimizeImageBuffer,Q0 as optimizeImage,z as mimeTypeToResolvedType,_0 as getOptimizedImage,V0 as getImageMetadata,t as getAspectRatioStringRound,x as getAspectRatioString,I as generateVariants,o as generateTestFile,k0 as generateAndUploadImage,D as fileTypePredicates,p as deleteOne,E0 as deleteMany,C0 as checkFileExistance};
|
|
3
3
|
|
|
4
|
-
//# debugId=
|
|
4
|
+
//# debugId=0E189ECC2AA2E54464756E2164756E21
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ImageVariantName } from "../images";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ResolvedFileType, StorageObjectVariant, StorageProvider } from "../types";
|
|
3
3
|
type DeleteOneNiceResult = {
|
|
4
4
|
key: string;
|
|
5
5
|
deleted: true;
|
|
@@ -12,7 +12,13 @@ type DeleteOneBadResult = {
|
|
|
12
12
|
};
|
|
13
13
|
type DeleteOneResult = DeleteOneNiceResult | DeleteOneBadResult;
|
|
14
14
|
export type UploadedImageVariants = {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
shared: {
|
|
16
|
+
name: string;
|
|
17
|
+
resolvedType: ResolvedFileType;
|
|
18
|
+
provider: StorageProvider;
|
|
19
|
+
isPrivate: boolean;
|
|
20
|
+
uploadedBy: string | null;
|
|
21
|
+
};
|
|
22
|
+
variants: Partial<Record<ImageVariantName, StorageObjectVariant>>;
|
|
17
23
|
};
|
|
18
24
|
export type { DeleteOneResult };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Acl,
|
|
1
|
+
import type { Acl, RawUploadResult, UploadableObjectBuffer } from "../types";
|
|
2
2
|
import { type BunFile } from "bun";
|
|
3
3
|
import { type GeneratedImageVariants } from "../images";
|
|
4
4
|
import type { UploadedImageVariants } from "./types";
|
|
@@ -32,7 +32,7 @@ declare function uploadOne(path: string, file: File | UploadableObjectBuffer, op
|
|
|
32
32
|
acl?: Acl;
|
|
33
33
|
externalReference?: string;
|
|
34
34
|
uploadedBy?: string;
|
|
35
|
-
}): Promise<
|
|
35
|
+
}): Promise<RawUploadResult>;
|
|
36
36
|
export { uploadOne };
|
|
37
37
|
type UploadManyOptions = {
|
|
38
38
|
acl?: Acl;
|
|
@@ -41,7 +41,7 @@ type UploadManyOptions = {
|
|
|
41
41
|
externalKeys?: string[];
|
|
42
42
|
};
|
|
43
43
|
type UploadManyResult = {
|
|
44
|
-
data:
|
|
44
|
+
data: RawUploadResult[];
|
|
45
45
|
errors?: any[];
|
|
46
46
|
};
|
|
47
47
|
export declare function uploadMany(path: string, files: UploadableObjectBuffer[], opts?: UploadManyOptions): Promise<UploadManyResult>;
|
package/dist/storage/types.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ type StorageObjectMetadata = {
|
|
|
37
37
|
};
|
|
38
38
|
type StorageObjectVariantMetadata = {
|
|
39
39
|
/**
|
|
40
|
-
* Mime type
|
|
40
|
+
* Mime type — e.g. "image/webp", "video/mp4". Per-variant because formats can differ.
|
|
41
41
|
*/
|
|
42
42
|
type: string;
|
|
43
43
|
/**
|
|
@@ -45,9 +45,13 @@ type StorageObjectVariantMetadata = {
|
|
|
45
45
|
*/
|
|
46
46
|
size: number;
|
|
47
47
|
/**
|
|
48
|
-
* File extension
|
|
48
|
+
* File extension — e.g. ".webp", ".mp4". Per-variant for the same reason as type.
|
|
49
49
|
*/
|
|
50
50
|
extension: string;
|
|
51
|
+
/**
|
|
52
|
+
* Integrity checksum — reserved for future use, not yet populated
|
|
53
|
+
*/
|
|
54
|
+
hash?: string | null;
|
|
51
55
|
width?: number;
|
|
52
56
|
height?: number;
|
|
53
57
|
aspectRatio?: number;
|
|
@@ -68,23 +72,16 @@ type StorageObject = {
|
|
|
68
72
|
createdAt: string;
|
|
69
73
|
updatedAt: string;
|
|
70
74
|
uploadedBy: string | null;
|
|
71
|
-
/**
|
|
72
|
-
* Key for S3 or Local storage files: "uploads/user123/file.jpg"
|
|
73
|
-
* Will be null for external files
|
|
74
|
-
*/
|
|
75
|
-
key: string | null;
|
|
76
|
-
/**
|
|
77
|
-
* Full URL for external files: "https://unsplash.com/photo.jpg"
|
|
78
|
-
*/
|
|
79
|
-
url: string | null;
|
|
80
75
|
name: string | null;
|
|
81
|
-
|
|
82
|
-
resolvedType: ResolvedFileType;
|
|
76
|
+
type: ResolvedFileType;
|
|
83
77
|
provider: StorageProvider;
|
|
84
78
|
isPrivate: boolean | null;
|
|
85
|
-
metadata: StorageObjectMetadata | null;
|
|
86
79
|
isActive: boolean;
|
|
80
|
+
thumbnail: string | null;
|
|
81
|
+
alt: string | null;
|
|
82
|
+
colorPalette: string[] | null;
|
|
87
83
|
referenceCount: number;
|
|
84
|
+
variants: Partial<Record<string, StorageObjectVariant>>;
|
|
88
85
|
};
|
|
89
86
|
type StorageObjectVariant = {
|
|
90
87
|
key: string | null;
|
|
@@ -92,8 +89,17 @@ type StorageObjectVariant = {
|
|
|
92
89
|
name: string | null;
|
|
93
90
|
metadata: StorageObjectVariantMetadata;
|
|
94
91
|
};
|
|
95
|
-
type
|
|
92
|
+
type InsertStorageObject = Omit<StorageObject, "id" | "createdAt" | "updatedAt" | "referenceCount">;
|
|
93
|
+
type RawUploadResult = {
|
|
94
|
+
uploadedBy: string | null;
|
|
96
95
|
key: string;
|
|
96
|
+
url: string | null;
|
|
97
|
+
name: string | null;
|
|
98
|
+
resolvedType: ResolvedFileType;
|
|
99
|
+
provider: StorageProvider;
|
|
100
|
+
isPrivate: boolean | null;
|
|
101
|
+
metadata: StorageObjectMetadata | null;
|
|
102
|
+
isActive: boolean;
|
|
97
103
|
};
|
|
98
104
|
export type UploadableObjectBuffer = {
|
|
99
105
|
buffer: Buffer | File;
|
|
@@ -103,4 +109,4 @@ export type UploadableObjectBuffer = {
|
|
|
103
109
|
metadata: StorageObjectMetadata;
|
|
104
110
|
};
|
|
105
111
|
};
|
|
106
|
-
export type { ResolvedFileType, StorageObject, StorageObjectMetadata, StorageObjectVariant, StorageObjectVariantMetadata, Acl, StorageProvider,
|
|
112
|
+
export type { ResolvedFileType, StorageObject, StorageObjectMetadata, StorageObjectVariant, StorageObjectVariantMetadata, Acl, StorageProvider, InsertStorageObject, RawUploadResult, };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ResolvedFileType
|
|
1
|
+
import type { ResolvedFileType } from "../types";
|
|
2
2
|
/**
|
|
3
3
|
* Maps MIME types to file categories
|
|
4
4
|
* @param mimeType - The MIME type string
|
|
@@ -18,10 +18,4 @@ declare const fileTypePredicates: {
|
|
|
18
18
|
* Generates a text.txt file so you can test file uploading is working
|
|
19
19
|
*/
|
|
20
20
|
declare function generateTestFile(): File;
|
|
21
|
-
|
|
22
|
-
* @returns url of the file
|
|
23
|
-
*/
|
|
24
|
-
declare function getObjectUrl(storageObject: StorageObject, options?: {
|
|
25
|
-
bucket?: string;
|
|
26
|
-
}): string;
|
|
27
|
-
export { mimeTypeToResolvedType, fileTypePredicates, getObjectUrl, generateTestFile, };
|
|
21
|
+
export { mimeTypeToResolvedType, fileTypePredicates, generateTestFile, };
|