UNPKG

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) 5.03 kB
import{StorageAdapter as R,guessMimeType as y}from"bknd";import{parse as S,s as h,isFile as k,isBlob as v}from"bknd/utils";var w=h.object({root:h.string({default:""}).optional()},{title:"OPFS",description:"Origin Private File System storage",additionalProperties:!1}),B=class extends R{config;rootPromise;constructor(e={}){super(),this.config=S(w,e),this.rootPromise=this.initializeRoot()}async initializeRoot(){let e=await navigator.storage.getDirectory();if(!this.config.root)return e;let t=this.config.root.split("/").filter(Boolean),i=e;for(let s of t)i=await i.getDirectoryHandle(s,{create:!0});return i}getSchema(){return w}getName(){return"opfs"}async listObjects(e){let t=await this.rootPromise,i=[];for await(let[s,o]of t.entries())if(o.kind==="file"&&(!e||s.startsWith(e))){let r=await o.getFile();i.push({key:s,last_modified:new Date(r.lastModified),size:r.size})}return i}async computeEtagFromArrayBuffer(e){let t=await crypto.subtle.digest("SHA-256",e);return`"${Array.from(new Uint8Array(t)).map(o=>o.toString(16).padStart(2,"0")).join("")}"`}async putObject(e,t){if(t===null)throw new Error("Body is empty");let o=await(await(await this.rootPromise).getFileHandle(e,{create:!0})).createWritable();try{let r;if(k(t))r=await t.arrayBuffer(),await o.write(r);else if(t instanceof ReadableStream){let n=[],l=t.getReader();try{for(;;){let{done:c,value:m}=await l.read();if(c)break;n.push(m),await o.write(m)}}finally{l.releaseLock()}let d=n.reduce((c,m)=>c+m.length,0),f=new Uint8Array(d),u=0;for(let c of n)f.set(c,u),u+=c.length;r=f.buffer}else if(v(t))r=await t.arrayBuffer(),await o.write(r);else{if(ArrayBuffer.isView(t)){let n=t;r=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength)}else r=t;await o.write(t)}return await o.close(),await this.computeEtagFromArrayBuffer(r)}catch(r){throw await o.abort(),r}}async deleteObject(e){try{await(await this.rootPromise).removeEntry(e)}catch{}}async objectExists(e){try{return await(await this.rootPromise).getFileHandle(e),!0}catch{return!1}}parseRangeHeader(e,t){let i=e.match(/^bytes=(\d*)-(\d*)$/);if(!i)return null;let[,s,o]=i,r=s?Number.parseInt(s,10):0,n=o?Number.parseInt(o,10):t-1;return!s&&o&&(r=Math.max(0,t-Number.parseInt(o,10)),n=t-1),r<0||n>=t||r>n?null:{start:r,end:n}}async getObject(e,t){try{let o=await(await(await this.rootPromise).getFileHandle(e)).getFile(),r=o.size,n=y(e),l=new Headers({"Accept-Ranges":"bytes","Content-Type":n||"application/octet-stream"}),d=t.get("range");if(d){let f=this.parseRangeHeader(d,r);if(!f)return l.set("Content-Range",`bytes */${r}`),new Response("",{status:416,headers:l});let{start:u,end:c}=f,g=(await o.arrayBuffer()).slice(u,c+1);return l.set("Content-Range",`bytes ${u}-${c}/${r}`),l.set("Content-Length",g.byteLength.toString()),new Response(g,{status:206,headers:l})}else{let f=await o.arrayBuffer();return l.set("Content-Length",f.byteLength.toString()),new Response(f,{status:200,headers:l})}}catch{return new Response("",{status:404})}}getObjectUrl(e){throw new Error("Method not implemented.")}async getObjectMeta(e){let s=await(await(await this.rootPromise).getFileHandle(e)).getFile();return{type:y(e)||"application/octet-stream",size:s.size}}toJSON(e){return{type:this.getName(),config:this.config}}};import{createContext as O,lazy as x,Suspense as L,useContext as j,useEffect as N,useState as A}from"react";import{checksum as M}from"bknd/utils";import{App as z,registries as E,sqlocal as D}from"bknd";import{Route as b,Router as T,Switch as U}from"wouter";import{ClientProvider as $}from"bknd/client";import{SQLocalKysely as I}from"sqlocal/kysely";import{OpfsStorageAdapter as V}from"bknd/adapter/browser";import{jsx as p,jsxs as F}from"react/jsx-runtime";var q=x(()=>Promise.all([import("bknd/ui"),import("bknd/dist/styles.css")]).then(([a])=>({default:a.Admin})));function _(a){document.startViewTransition?document.startViewTransition(a):a()}var H=O(void 0);function oe({children:a,adminConfig:e,header:t,loading:i,notFound:s,...o}){let[r,n]=A(void 0),[l,d]=A(""),f=(e?.basepath??"")+"/*?";async function u(c){_(async()=>{n(c),d(await M(c.toJSON()))})}return N(()=>{J({...o,adminConfig:e}).then(c=>u(c)).catch(console.error)},[]),r?p(H.Provider,{value:{app:r,hash:l},children:F($,{storage:window.localStorage,fetcher:r.server.request,children:[t,p(T,{children:F(U,{children:[a,p(b,{path:f,children:p(L,{children:p(q,{config:e})})}),p(b,{path:"*",children:s??p(P,{style:{fontSize:"48px",fontFamily:"monospace"},children:"404"})})]})},l)]})}):i??p(P,{children:p("span",{style:{opacity:.2},children:"Loading..."})})}function ne(){return j(H)}var P=a=>p("div",{...a,style:{width:"100%",minHeight:"100vh",display:"flex",justifyContent:"center",alignItems:"center",...a.style??{}}}),C=!1;async function J(a={}){if(C)return;C=!0,E.media.register("opfs",V);let e=z.create({...a,connection:D(new I(a.connection??":localStorage:"))});return await a.beforeBuild?.(e),await e.build({sync:!0}),await a.onBuilt?.(e),e}export{oe as BkndBrowserApp,B as OpfsStorageAdapter,w as opfsAdapterConfig,ne as useApp};