pixel-serve-server
Version:
A robust Node.js utility for handling and processing images. This package provides features like resizing, format conversion and etc.
4 lines • 18.9 kB
JavaScript
import v from'path';import*as E from'fs/promises';import {readFile}from'fs/promises';import {createHash}from'crypto';import K from'sharp';import {fileURLToPath}from'url';import*as O from'dns/promises';import*as re from'http';import*as ne from'https';import {isIP}from'net';import Re from'axios';import {z as z$1}from'zod';var Ae=v.dirname(fileURLToPath(import.meta.url)),ee=e=>v.join(Ae,"assets",e),Ie=ee("noimage.jpg"),Ee=ee("noavatar.png"),R={normal:async()=>readFile(Ie),avatar:async()=>readFile(Ee)},W=/^\/api\/v1\//,D=["jpeg","jpg","png","webp","gif","tiff","avif"],B={jpeg:"image/jpeg",jpg:"image/jpeg",png:"image/png",webp:"image/webp",gif:"image/gif",tiff:"image/tiff",avif:"image/avif"};var w=(e,t,n,r)=>{if(e)try{e(t,{phase:n,src:r});}catch{}},Fe=4096,N=async(e,t)=>{try{if(!e||!t||typeof t!="string"||t.length>Fe||t.includes("\0")||t.includes("\\")||v.isAbsolute(t)||!/^[^\x00-\x1F\x7F]+$/.test(t))return !1;let n=v.resolve(e),r=v.resolve(n,t),[i,l]=await Promise.all([E.realpath(n),E.realpath(r)]);if(!(await E.stat(i)).isDirectory()||!(await E.stat(l)).isFile())return !1;let d=i+v.sep,g=(l+v.sep).startsWith(d)||l===i,s=v.relative(i,l);return !s.startsWith("..")&&!v.isAbsolute(s)&&g}catch{return false}},Se=e=>{let t=e,n=t.lastIndexOf(":"),r=n>=0?t.slice(n+1):t;if(isIP(r)===4){let m=r.split(".").map(Number),d=(m[0]<<8|m[1]).toString(16),o=(m[2]<<8|m[3]).toString(16);t=t.slice(0,n+1)+d+":"+o;}let i=t.split("::");if(i.length>2)return null;let l=m=>{if(m==="")return [];let d=[];for(let o of m.split(":")){if(!/^[0-9a-f]{1,4}$/i.test(o))return null;d.push(parseInt(o,16));}return d},a;if(i.length===1){let m=l(i[0]);if(m===null)return null;a=m;}else {let m=l(i[0]),d=l(i[1]);if(m===null||d===null)return null;let o=8-m.length-d.length;if(o<0)return null;a=[...m,...Array(o).fill(0),...d];}return a.length===8?a:null},I=e=>{let t=isIP(e);if(t===0)return true;if(t===4){let c=e.split(".").map(x=>Number(x));if(c.length!==4||c.some(x=>Number.isNaN(x)))return true;let[f,p]=c;return f===0||f===10||f===100&&p>=64&&p<=127||f===127||f===169&&p===254||f===172&&p>=16&&p<=31||f===192&&p===168||f===192&&p===0||f===192&&p===88&&c[2]===99||f===198&&(p===18||p===19)||f===198&&p===51&&c[2]===100||f===203&&p===0&&c[2]===113||f>=224&&f<=239||f>=240}let n=Se(e.toLowerCase());if(!n)return true;let[r,i,l,a,m,d,o,g]=n,s=(c,f)=>`${c>>8}.${c&255}.${f>>8}.${f&255}`,y=r===0&&i===0&&l===0&&a===0&&m===0;if(y&&d===0||y&&d===65535)return I(s(o,g));if(r===100&&i===65435){if(l===0&&a===0&&m===0&&d===0)return I(s(o,g));if(l===1)return true}return r===8194?I(s(i,l)):r>=65152&&r<=65215||r>=65216&&r<=65279||r>=64512&&r<=65023||r>=65280&&r<=65535},Ce=async e=>{if(!e)return false;let t=e.replace(/^\[|\]$/g,"");if(isIP(t)!==0)return !I(t);try{let n=await O.lookup(t,{all:!0,verbatim:!0});return n.length?n.every(r=>!I(r.address)):!1}catch{return false}},V=async e=>{if(!e)return null;let t=e.replace(/^\[|\]$/g,"");if(isIP(t)!==0){if(I(t))return null;let n=isIP(t)===6?6:4;return [{address:t,family:n}]}try{let n=await O.lookup(t,{all:!0,verbatim:!0});return !n.length||n.some(r=>I(r.address))?null:n.map(r=>({address:r.address,family:r.family===6?6:4}))}catch{return null}},Le=async e=>{let t=await V(e);return t?t[0]:null},He=e=>(t,n,r)=>{if(n?.all)r(null,e);else {let i=e[0];r(null,i.address,i.family);}};function ie(e,t){let n=Array.isArray(e)?e:[{address:e,family:t}],r=He(n);return {httpAgent:new re.Agent({lookup:r}),httpsAgent:new ne.Agent({lookup:r})}}var te=(e,t)=>{if(t.startsWith("*.")){let n=t.slice(1);return e===t.slice(2)||e.endsWith(n)}return e===t},se=(e,t,n)=>n.some(r=>te(e,r)||te(t,r)),Te=async(e,t,n,r)=>{try{return await Re.get(e,{responseType:"arraybuffer",timeout:t,maxContentLength:n,maxBodyLength:n,maxRedirects:0,httpAgent:r.httpAgent,httpsAgent:r.httpsAgent,proxy:!1,validateStatus:i=>i>=200&&i<300||i>=300&&i<400})}catch(i){let l=i;return l?.response?l.response:null}},ke=async(e,t="normal",{timeoutMs:n,maxBytes:r,allowedNetworkList:i,maxRedirects:l,onError:a,onFallback:m})=>{let d=async()=>(m?.(),R[t]());try{let o=e;for(let g=0;g<=l;g++){let s;try{s=new URL(o);}catch(b){return w(a,b,"fetch",o),await d()}if(!["http:","https:"].includes(s.protocol))return w(a,new Error(`disallowed protocol ${s.protocol}`),"fetch",o),await d();if(!se(s.hostname,s.host,i))return w(a,new Error(`host ${s.hostname} not in allowedNetworkList`),"fetch",o),await d();let y=await V(s.hostname);if(!y)return w(a,new Error(`host ${s.hostname} resolves to a private IP or DNS lookup failed`),"fetch",o),await d();let c=ie(y),f=await Te(o,n,r,c);if(!f)return w(a,new Error("network request returned no response"),"fetch",o),await d();if(f.status>=300&&f.status<400){let b=f.headers?.location;if(!b)return w(a,new Error("redirect response missing Location header"),"fetch",o),await d();try{o=new URL(b,o).toString();}catch(L){return w(a,L,"fetch",b),await d()}continue}if(f.status<200||f.status>=300)return w(a,new Error(`non-2xx status ${f.status}`),"fetch",o),await d();let p=f.headers?.["content-type"]?.toLowerCase()?.split(";")[0]?.trim(),x=Object.values(B);return p&&x.includes(p)?Buffer.from(f.data):(w(a,new Error(`disallowed content-type ${p??"missing"} for ${o}`),"fetch",o),await d())}return w(a,new Error(`exceeded maxRedirects=${l}`),"fetch",e),await d()}catch(o){return w(a,o,"fetch",e),await d()}},_=async(e,t,n="normal",r,i,l)=>{let a=async()=>(l?.(),R[n]());if(!await N(t,e))return w(i,new Error(`invalid local path: ${e}`),"fs",e),await a();try{let d=v.resolve(t,e);if(r){let o=await E.stat(d);if(o.size>r)return w(i,new Error(`local file ${e} exceeds maxDownloadBytes (${o.size} > ${r})`),"fs",e),await a()}return await E.readFile(d)}catch(d){return w(i,d,"fs",e),await a()}},oe=(e,t,n)=>n!==void 0?e.startsWith(n)?e.slice(n.length):e:e.replace(t,""),Be=e=>{if(e===void 0)return null;try{let t=new URL(e.includes("://")?e:`http://${e}`);return {hostname:t.hostname,host:t.host}}catch{return {hostname:e,host:e}}},M=(e,t,n,r)=>{let i;try{i=new URL(e);}catch{return null}let l=Be(t);return l!==null&&([l.hostname,`www.${l.hostname}`].includes(i.hostname)||[l.host,`www.${l.host}`].includes(i.host))?oe(i.pathname,n,r):null},ae=(e,t,n,r="normal",i,l=[],{timeoutMs:a,maxBytes:m,maxRedirects:d=3,onError:o,apiPrefix:g,onFallback:s})=>{try{let y=M(e,n,i,g);if(y!==null)return _(y,t,r,m,o,s);let c=new URL(e);return se(c.hostname,c.host,l)?["http:","https:"].includes(c.protocol)?ke(e,r,{timeoutMs:a,maxBytes:m,allowedNetworkList:l,maxRedirects:d,onError:o,onFallback:s}):(w(o,new Error(`disallowed protocol ${c.protocol}`),"fetch",e),s?.(),R[r]()):(w(o,new Error(`host ${c.hostname} not in allowedNetworkList`),"fetch",e),s?.(),R[r]())}catch(y){return w(o,y,"fetch",e),_(e,t,r,m,o,s)}};var $e=z$1.enum(D),Ue=z$1.enum(["avatar","normal"]),G=z$1.object({src:z$1.preprocess((e,t)=>{if(e==null||typeof e=="string")return e;let n=Array.isArray(e)?"array":typeof e;return t.addIssue({code:z$1.ZodIssueCode.custom,message:`src must be a string (received ${n})`}),z$1.NEVER},z$1.string().optional()).optional(),format:z$1.string().optional().transform(e=>{let t=e?.toLowerCase();return t&&$e.options.includes(t)?t:void 0}).optional(),width:z$1.union([z$1.number(),z$1.string()]).optional().transform(e=>e==null?void 0:Number(e)).pipe(z$1.number().int().min(1,"width too small").max(4e3,"width too large").optional()),height:z$1.union([z$1.number(),z$1.string()]).optional().transform(e=>e==null?void 0:Number(e)).pipe(z$1.number().int().min(1,"height too small").max(4e3,"height too large").optional()),quality:z$1.union([z$1.number(),z$1.string()]).optional().transform(e=>e==null?void 0:Number(e)).pipe(z$1.number().int().min(1).max(100).optional()),folder:z$1.enum(["public","private"]).default("public"),type:Ue.default("normal"),userId:z$1.union([z$1.string(),z$1.number()]).optional().transform(e=>e==null?void 0:String(e).trim()).pipe(z$1.string().min(1,"userId cannot be empty").max(128,"userId too long").optional())}).strict(),X=z$1.object({baseDir:z$1.string().min(1,"baseDir is required"),idHandler:z$1.custom(e=>typeof e=="function",{message:"idHandler must be a function"}).optional(),getUserFolder:z$1.custom(e=>typeof e=="function",{message:"getUserFolder must be a function"}).optional(),getUserFolderRootDir:z$1.string().min(1).optional(),websiteURL:z$1.union([z$1.url(),z$1.string().regex(/^(?!-)[A-Za-z0-9-]{1,63}(\.(?!-)[A-Za-z0-9-]{1,63})*$/)]).optional(),apiRegex:z$1.instanceof(RegExp).default(W),apiPrefix:z$1.string().min(1,"apiPrefix cannot be empty").optional(),allowedNetworkList:z$1.array(z$1.string().transform(e=>e.trim()).pipe(z$1.string().min(1,"allowedNetworkList entries cannot be empty").regex(/^(\*\.)?[a-z0-9.-]+$/i,"allowedNetworkList entry is not a valid hostname").refine(e=>!e.startsWith("*.")||e.slice(2).split(".").filter(Boolean).length>=2,{message:"wildcard allowedNetworkList entry must have at least two labels after '*.' (e.g. *.example.com)"}))).transform(e=>e.map(t=>t.toLowerCase())).default([]),cacheControl:z$1.string().optional(),etag:z$1.boolean().default(true),minWidth:z$1.number().int().positive().default(50),maxWidth:z$1.number().int().positive().default(4e3),minHeight:z$1.number().int().positive().default(50),maxHeight:z$1.number().int().positive().default(4e3),defaultQuality:z$1.number().int().min(1).max(100).default(80),requestTimeoutMs:z$1.number().int().positive().default(5e3),idHandlerTimeoutMs:z$1.number().int().positive().optional(),maxDownloadBytes:z$1.number().int().positive().default(5e6),maxRedirects:z$1.number().int().min(0).max(10).default(3),maxInputPixels:z$1.number().int().positive().default(16e3*16e3),allowSvgInput:z$1.boolean().default(false),onError:z$1.custom(e=>typeof e=="function",{message:"onError must be a function"}).optional(),onComplete:z$1.custom(e=>typeof e=="function",{message:"onComplete must be a function"}).optional()}).strict().refine(e=>e.minWidth<=e.maxWidth,{message:"minWidth must be less than or equal to maxWidth",path:["minWidth"]}).refine(e=>e.minHeight<=e.maxHeight,{message:"minHeight must be less than or equal to maxHeight",path:["minHeight"]}).refine(e=>e.maxWidth<=4e3,{message:"maxWidth must lie within the framework's hard [1, 4000] dimension window",path:["maxWidth"]}).refine(e=>e.maxHeight<=4e3,{message:"maxHeight must lie within the framework's hard [1, 4000] dimension window",path:["maxHeight"]});var le=e=>X.parse(e),ue=(e,t)=>{let n=G.parse(e),r=(i,l,a)=>{if(i!==void 0)return Math.min(Math.max(i,l),a)};return {...n,width:r(n.width,t.minWidth,t.maxWidth),height:r(n.height,t.minHeight,t.maxHeight),quality:n.quality??t.defaultQuality,format:n.format??"jpeg"}};var A=(e,t,n)=>{if(e)try{e(t,n);}catch{}},q=(e,t)=>{if(e)try{e(t);}catch{}},z=e=>{let t=process.hrtime.bigint()-e,n=Number(t/1000000n),r=Number(t%1000000n)/1e6;return n+r},We=100,me="image",Q="public, max-age=86400, stale-while-revalidate=604800",Z="public, max-age=60",ge=(e,t)=>{let n=t,r=(e??"").split("#")[0].split("?")[0],i=v.basename(r),l=i&&i!=="/"&&i!=="\\"?v.basename(i,v.extname(i)):"",a=l.replace(/[^\x20-\x7E]/g,"_").replace(/["\\\x00-\x1F\x7F]/g,"_").replace(/_+/g,"_");a.startsWith("_")&&(a=a.slice(1)),a.endsWith("_")&&(a=a.slice(0,-1));let m=a.length>0?a:me,d=Math.max(1,We-n.length-1),g=`${m.slice(0,d)}.${n}`,s=l.length>0?l:me,c=encodeURIComponent(s).replace(/['()*]/g,x=>`%${x.charCodeAt(0).toString(16).toUpperCase()}`).slice(0,d),f=c.lastIndexOf("%");for(f>=0&&c.length-f<3&&(c=c.slice(0,f));c.length>=3;){let x=c.slice(-3);if(x[0]!=="%")break;let b=parseInt(x.slice(1),16);if(b>=192&&b<=253){c=c.slice(0,-3);break}if(b>=128&&b<=191){c=c.slice(0,-3);continue}break}let p=`${c}.${n}`;return {asciiFilename:g,encodedFilename:p}},he=async(e,t,n)=>{if(!e)return null;let r=async i=>{if(!await N(t,i))return null;try{let l=v.resolve(t,i),a=await E.stat(l);return n?.maxBytes!==void 0&&a.size>n.maxBytes?null:`file:${a.mtimeMs}:${a.size}`}catch{return null}};if(e.startsWith("http://")||e.startsWith("https://")){let i=M(e,n?.websiteURL,n?.apiRegex??W,n?.apiPrefix);return i!==null?r(i):`url:${e}`}return r(e)},pe=(e,t)=>{let n=JSON.stringify({src:e.src??"",w:e.width??"",h:e.height??"",f:e.format,q:e.quality,t:e.type,fo:e.folder,u:e.parsedUserId??"",sid:t});return `"${createHash("sha256").update(n).digest("hex")}"`},de=async(e,t,n)=>{let r;try{return await Promise.race([e,new Promise((i,l)=>{r=setTimeout(()=>l(new Error(`${n} timed out after ${t}ms`)),t);})])}finally{r!==void 0&&clearTimeout(r);}},xe=async(e,t,n)=>{if(!e||!t)return false;let r;if(n!==void 0)r=n;else try{r=await E.realpath(v.resolve(e));}catch{r=v.resolve(e);}let i=v.resolve(t),l;try{l=await E.realpath(i);}catch{l=i;}if(r===l)return true;let a=v.relative(r,l);return a===""||a==="."?true:!a.startsWith("..")&&!v.isAbsolute(a)},ye=async e=>{try{return await E.realpath(v.resolve(e))}catch{return v.resolve(e)}},De=/^<!doctype\s+svg(?:[\s[>]|$)/,_e=e=>{let t=0,n=()=>{for(;t<e.length&&(e[t]===" "||e[t]===" "||e[t]===`
`||e[t]==="\r");)t++;};for(;;){if(n(),e.startsWith("<?xml",t)){let r=e.indexOf("?>",t);if(r===-1)return e.slice(t);t=r+2;continue}if(e.startsWith("<!--",t)){let r=e.indexOf("-->",t);if(r===-1)return e.slice(t);t=r+3;continue}return e.slice(t)}},fe=e=>e.startsWith("<svg")?true:e.startsWith("<?xml")||e.startsWith("<!--")||e.startsWith("<!doctype")?/<svg[\s>]/.test(e)?true:De.test(_e(e)):false,we=e=>{if(!e||e.length===0)return false;let t=0;for(;t<e.length&&(e[t]===9||e[t]===10||e[t]===13||e[t]===32);)t++;if(e.length>=t+2&&(e[t]===254&&e[t+1]===255||e[t]===255&&e[t+1]===254)){let r=e[t]===255,i=Math.min(e.length,t+2+4096),l;if(r)l=e.subarray(t+2,i).toString("utf16le");else {let m=e.subarray(t+2,i),d=Buffer.alloc(m.length-m.length%2);for(let o=0;o+1<m.length;o+=2)d[o]=m[o+1],d[o+1]=m[o];l=d.toString("utf16le");}let a=l.trimStart().toLowerCase();return fe(a)}e.length>=t+3&&e[t]===239&&e[t+1]===187&&e[t+2]===191&&(t+=3);let n=e.subarray(t,Math.min(e.length,t+4096)).toString("latin1").trimStart().toLowerCase();return fe(n)},Ne=async(e,t,n,r,i)=>{let l=process.hrtime.bigint(),a="normal",m=r.onError,d=r.onComplete,o,g;try{let s;try{s=ue(e.query,{minWidth:r.minWidth,maxWidth:r.maxWidth,minHeight:r.minHeight,maxHeight:r.maxHeight,defaultQuality:r.defaultQuality});}catch(h){throw A(m,h,{phase:"validation"}),h}o=s.src,g=s.userId,a=s.type??"normal";let y=r.baseDir,c;if(s.userId&&(c=s.userId,r.idHandler)){let h=s.userId,P=r.idHandlerTimeoutMs??r.requestTimeoutMs;try{let S=Promise.resolve().then(()=>r.idHandler(h)),U=await de(S,P,"idHandler");c=typeof U=="string"?U:h,typeof U!="string"&&A(m,new Error(`idHandler returned a non-string value (${typeof U})`),{phase:"idHandler",src:o,userId:h});}catch(S){c=h,A(m,S,{phase:"idHandler",src:o,userId:h});}g=c;}if(s.folder==="private"&&r.getUserFolder)try{let h=Promise.resolve().then(()=>r.getUserFolder(e,c)),P=await de(h,r.requestTimeoutMs,"getUserFolder");P&&(r.getUserFolderRootDir?await xe(r.getUserFolderRootDir,P,i)?y=P:A(m,new Error(`getUserFolder returned path "${P}" outside getUserFolderRootDir "${r.getUserFolderRootDir}"`),{phase:"getUserFolder",src:o,userId:g}):y=P);}catch(h){A(m,h,{phase:"getUserFolder",src:o,userId:g});}let f=D.includes(s.format)?s.format:"jpeg",p=await he(s.src,y,{websiteURL:r.websiteURL,apiRegex:r.apiRegex,apiPrefix:r.apiPrefix,maxBytes:r.maxDownloadBytes}),x;if(r.etag&&p&&(x=pe({src:s.src,width:s.width,height:s.height,format:f,quality:s.quality,type:s.type,folder:s.folder,parsedUserId:c},p),e.headers["if-none-match"]===x)){t.setHeader("Vary","Accept-Encoding"),t.setHeader("Cache-Control",r.cacheControl??Q),t.setHeader("ETag",x),t.status(304).end(),q(d,{src:o,userId:g,format:f,outputBytes:0,cached:!0,durationMs:z(l),fallback:!1});return}let b=!1,L=()=>{b=!0;},j=await(async()=>s.src?s.src.startsWith("http://")||s.src.startsWith("https://")?ae(s.src,y,r.websiteURL,s.type,r.apiRegex,r.allowedNetworkList,{timeoutMs:r.requestTimeoutMs,maxBytes:r.maxDownloadBytes,maxRedirects:r.maxRedirects,onError:m,apiPrefix:r.apiPrefix,onFallback:L}):_(s.src,y,s.type,r.maxDownloadBytes,m,L):(L(),R[s.type]()))();if(b&&(x=void 0),!r.allowSvgInput&&we(j)){let h=new Error("svg input rejected");throw A(m,h,{phase:"sharp",src:o,userId:g}),h}let H;try{let h=K(j,{failOn:"warning",limitInputPixels:r.maxInputPixels,sequentialRead:!0,unlimited:!1}),P=await h.metadata();if(P.width&&P.height&&P.width*P.height>r.maxInputPixels)throw new Error("input exceeds maxInputPixels");if(!r.allowSvgInput&&P.format==="svg")throw new Error("svg input rejected");if(h=K(j,{failOn:"warning",limitInputPixels:r.maxInputPixels,sequentialRead:!0,unlimited:!1}).rotate(),s.width||s.height){let S={width:s.width??void 0,height:s.height??void 0,fit:K.fit.cover,withoutEnlargement:!0};h=h.resize(S);}H=await h.toFormat(f,{quality:s.quality}).toBuffer();}catch(h){throw A(m,h,{phase:"sharp",src:o,userId:g}),h}if(r.etag&&!x&&(x=`"${createHash("sha256").update(H).digest("hex")}"`,e.headers["if-none-match"]===x)){t.setHeader("Vary","Accept-Encoding"),t.setHeader("Cache-Control",b?Z:r.cacheControl??Q),t.setHeader("ETag",x),t.status(304).end(),q(d,{src:o,userId:g,format:f,outputBytes:0,cached:!0,durationMs:z(l),fallback:!1});return}let{asciiFilename:be,encodedFilename:Pe}=ge(s.src,f);t.type(B[f]),t.setHeader("Content-Disposition",`inline; filename="${be}"; filename*=UTF-8''${Pe}`),t.setHeader("Vary","Accept-Encoding"),t.setHeader("X-Content-Type-Options","nosniff"),t.setHeader("Cache-Control",b?Z:r.cacheControl??Q),x&&t.setHeader("ETag",x),t.setHeader("Content-Length",H.length.toString()),t.send(H),q(d,{src:o,userId:g,format:f,outputBytes:H.length,cached:!1,durationMs:z(l),fallback:b});}catch{if(t.headersSent){let s=new Error("response already flushed");A(m,s,{phase:"fs",src:o,userId:g}),n(s);return}try{let s=a==="avatar"?"avatar":"normal",y=await R[s](),c=s==="avatar"?"png":"jpeg";t.type(B[c]),t.setHeader("Content-Disposition",`inline; filename="fallback.${c}"`),t.setHeader("Vary","Accept-Encoding"),t.setHeader("X-Content-Type-Options","nosniff"),t.setHeader("Cache-Control",Z),t.send(y),q(d,{src:o,userId:g,format:c,outputBytes:y.length,cached:!1,durationMs:z(l),fallback:!0});}catch(s){A(m,s,{phase:"fs",src:o,userId:g}),n(s);}}},Me=e=>{let t;try{t=le(e);}catch(a){throw A(e.onError,a,{phase:"schema"}),a}let n,r=false,i,l=async a=>r&&n!==void 0?n:(i||(i=ye(a).then(m=>(n=m,r=true,m))),i);return async(a,m,d)=>{let o;return t.getUserFolderRootDir&&(o=await l(t.getUserFolderRootDir)),Ne(a,m,d,t,o)}},qe=Me;
export{pe as buildDeterministicEtag,ge as buildFilename,ie as buildPinnedAgents,he as buildSourceIdentifier,xe as isInsideRoot,I as isPrivateIp,Ce as isPublicHost,N as isValidPath,we as looksLikeSvg,X as optionsSchema,qe as registerServe,M as resolveInternalLocalPath,Le as resolvePinnedAddress,V as resolvePinnedAddresses,ye as resolveRootDir,oe as stripApiPrefix,G as userDataSchema};//# sourceMappingURL=index.mjs.map
//# sourceMappingURL=index.mjs.map