bknd
Version:
Lightweight Firebase/Supabase alternative built to run anywhere — incl. Next.js, React Router, Astro, Cloudflare, Bun, Node, AWS Lambda & more.
2 lines (1 loc) • 3.35 kB
JavaScript
import u from"node:path";import{serve as P}from"@hono/node-server";import{serveStatic as x}from"@hono/node-server/serve-static";import{registries as C}from"bknd";import{readFile as v,readdir as w,stat as p,unlink as E,writeFile as S}from"node:fs/promises";import{StorageAdapter as A,guessMimeType as c}from"bknd";import{parse as b,s as l,isFile as m}from"bknd/utils";var d=l.object({path:l.string({default:"./"})},{title:"Local",description:"Local file system storage",additionalProperties:!1}),s=class extends A{config;constructor(t={}){super(),this.config=b(d,t)}getSchema(){return d}getName(){return"local"}async listObjects(t){let e=await w(this.config.path);return await Promise.all(e.filter(r=>!t||r.startsWith(t)).map(async r=>{let o=await p(`${this.config.path}/${r}`);return{key:r,last_modified:o.mtime,size:o.size}}))}async computeEtag(t){let e=m(t)?t:new Response(t),n=await crypto.subtle.digest("SHA-256",await e.arrayBuffer());return`"${Array.from(new Uint8Array(n)).map(i=>i.toString(16).padStart(2,"0")).join("")}"`}async putObject(t,e){if(e===null)throw new Error("Body is empty");let n=`${this.config.path}/${t}`;return await S(n,m(e)?e.stream():e),await this.computeEtag(e)}async deleteObject(t){try{await E(`${this.config.path}/${t}`)}catch{}}async objectExists(t){try{return(await p(`${this.config.path}/${t}`)).isFile()}catch{return!1}}async getObject(t,e){try{let n=await v(`${this.config.path}/${t}`),r=c(t);return new Response(n,{status:200,headers:{"Content-Type":r||"application/octet-stream","Content-Length":n.length.toString()}})}catch{return new Response("",{status:404})}}getObjectUrl(t){throw new Error("Method not implemented.")}async getObjectMeta(t){let e=await p(`${this.config.path}/${t}`);return{type:c(t)||"application/octet-stream",size:e.size}}toJSON(t){return{type:this.getName(),config:this.config}}};var f=!1;function g(){return f||(C.media.register("local",s),f=!0),(a={})=>new s(a).toJSON(!0)}import{createRuntimeApp as N}from"bknd/adapter";import{config as $}from"bknd";import{$console as O}from"bknd/utils";async function B({distPath:a,relativeDistPath:t,...e}={},n={},r){let o=u.relative(process.cwd(),u.resolve(a??t??"./node_modules/bknd/dist","static"));return t&&console.warn("relativeDistPath is deprecated, please use distPath instead"),g(),await N({serveStatic:x({root:o}),...e},n??{env:process.env},r)}function F(a={},t={},e){let n;return async r=>(n||(n=await B(a,t??process.env,e)),n.fetch(r))}function G({port:a=$.server.default_port,hostname:t,listener:e,...n}={},r={},o){P({port:a,hostname:t,fetch:F(n,r,o)},i=>{O.log(`Server is running on http://localhost:${i.port}`),e?.(i)})}import{genericSqlite as R}from"bknd";import{DatabaseSync as h}from"node:sqlite";function Y(a){let t;return a?"database"in a?t=a.database:t=new h(a.url):t=new h(":memory:"),R("node-sqlite",t,e=>{let n=r=>t.prepare(r);return{db:t,query:e.buildQueryFn({all:(r,o=[])=>n(r).all(...o),run:(r,o=[])=>{let{changes:i,lastInsertRowid:y}=n(r).run(...o);return{insertId:e.parseBigInt(y),numAffectedRows:e.parseBigInt(i)}}}),close:()=>t.close(),iterator:(r,o,i=[])=>{if(!r)throw new Error("Only support select in stream()");return n(o).iterate(...i)}}},{supports:{batching:!1}})}export{s as StorageLocalAdapter,B as createApp,F as createHandler,d as localAdapterConfig,Y as nodeSqlite,g as registerLocalMediaAdapter,G as serve};