@skybolt/vite-plugin
Version:
Vite plugin for Skybolt - High-performance asset caching for multi-page applications
3 lines (2 loc) • 7.56 kB
JavaScript
(()=>{function m(r){let t=2166136261n,e=16777619n,s=0xFFFFFFFFn;for(let o=0;o<r.length;o++)t^=BigInt(r.charCodeAt(o)),t=t*e&s;return Number(t)}function d(r){return m(r)&4095||1}function p(r,t){return m(r)%t}function f(r,t,e){let s=m(String(t)),o=e-1,n=(s|1)&o;return(r^n)&o}var k=class r{constructor(t=64){let e=Math.ceil(t/3.8);this.numBuckets=B(Math.max(e,4)),this.bucketMask=this.numBuckets-1,this.buckets=new Uint16Array(this.numBuckets*4),this.count=0}insert(t){let e=d(t),s=p(t,this.numBuckets),o=f(s,e,this.numBuckets);if(this._insertIntoBucket(s,e))return this.count++,!0;if(this._insertIntoBucket(o,e))return this.count++,!0;let n=this.buckets.slice(),a=Math.random()<.5?s:o,c=e;for(let i=0;i<500;i++){let h=Math.floor(Math.random()*4),u=a*4,S=this.buckets[u+h];if(this.buckets[u+h]=c,c=S,a=f(a,c,this.numBuckets),this._insertIntoBucket(a,c))return this.count++,!0}return this.buckets.set(n),!1}lookup(t){let e=d(t),s=p(t,this.numBuckets),o=f(s,e,this.numBuckets);return this._bucketContains(s,e)||this._bucketContains(o,e)}delete(t){let e=d(t),s=p(t,this.numBuckets),o=f(s,e,this.numBuckets);return this._removeFromBucket(s,e)?(this.count--,!0):this._removeFromBucket(o,e)?(this.count--,!0):!1}serialize(){let t=this.numBuckets*4,e=new Uint8Array(5+t*2);e[0]=1,e[1]=this.numBuckets>>8&255,e[2]=this.numBuckets&255,e[3]=this.count>>8&255,e[4]=this.count&255;for(let s=0;s<t;s++){let o=this.buckets[s],n=5+s*2;e[n]=o>>8&255,e[n+1]=o&255}return e}toBase64(){let t=this.serialize();if(typeof Buffer<"u"&&typeof btoa>"u")return Buffer.from(t).toString("base64url");let e=String.fromCharCode(...t);return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}static deserialize(t){if(t.length<5)throw new Error("Invalid cache digest: too short");let e=t[0];if(e!==1)throw new Error(`Invalid cache digest version: ${e}`);let s=t[1]<<8|t[2],o=t[3]<<8|t[4],n=new r(s*4);n.numBuckets=s,n.bucketMask=s-1,n.buckets=new Uint16Array(s*4),n.count=o;let a=s*4;for(let c=0;c<a;c++){let i=5+c*2;i+1<t.length&&(n.buckets[c]=t[i]<<8|t[i+1])}return n}static fromBase64(t){let e=t.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4;)e+="=";let s;if(typeof atob<"u"){let o=atob(e);s=new Uint8Array(o.length);for(let n=0;n<o.length;n++)s[n]=o.charCodeAt(n)}else s=new Uint8Array(Buffer.from(t,"base64url"));return r.deserialize(s)}_insertIntoBucket(t,e){let s=t*4;for(let o=0;o<4;o++)if(this.buckets[s+o]===0)return this.buckets[s+o]=e,!0;return!1}_bucketContains(t,e){let s=t*4;for(let o=0;o<4;o++)if(this.buckets[s+o]===e)return!0;return!1}_removeFromBucket(t,e){let s=t*4;for(let o=0;o<4;o++)if(this.buckets[s+o]===e)return this.buckets[s+o]=0,!0;return!1}get stats(){let t=this.numBuckets*4,e=this.count;return{numBuckets:this.numBuckets,bucketSize:4,totalSlots:t,usedSlots:e,loadFactor:e/t,fingerprintBits:12,estimatedFalsePositiveRate:Math.pow(2,-12)*4*2,serializedSizeBytes:5+t*2}}};function B(r){return r--,r|=r>>1,r|=r>>2,r|=r>>4,r|=r>>8,r|=r>>16,r+1}var l="skybolt-v1",y="sb_digest",C=31536e3,g=class{constructor(){this.versions={},this.registration=null,this.config=null,this.init()}async init(){if(!("serviceWorker"in navigator)){console.warn("[Skybolt] Service Workers not supported"),this.handleNoServiceWorker();return}if(new URLSearchParams(location.search).has("no-sw")){console.warn("[Skybolt] Service Worker disabled via ?no-sw"),this.handleNoServiceWorker();return}try{this.config=this.loadConfig(),this.registration=await navigator.serviceWorker.register(this.config.swPath,{scope:"/"}),await navigator.serviceWorker.ready,console.log("[Skybolt] Service Worker ready")}catch(t){console.error("[Skybolt] Service Worker registration failed:",t),this.handleNoServiceWorker();return}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>this.processAndFinalize()):this.processAndFinalize()}async processAndFinalize(){await this.processInlinedAssets(),await this.finalize()}loadConfig(){let t={swPath:"/skybolt-sw.js"},e=document.querySelector('meta[name="skybolt-config"]');if(e)try{return{...t,...JSON.parse(e.content)}}catch{console.warn("[Skybolt] Invalid config meta tag")}return t}async processInlinedAssets(){let t=document.querySelectorAll("[sb-asset]");console.log(`[Skybolt] Found ${t.length} assets to cache`);let e=[];t.forEach(s=>{let o=s.getAttribute("sb-asset"),n=s.getAttribute("sb-url");if(!o||!n){console.warn("[Skybolt] Invalid cache attributes on element:",s);return}let a=o.lastIndexOf(":");if(a===-1){console.warn("[Skybolt] Invalid cache info format:",o);return}let c=o.substring(0,a),i=o.substring(a+1);if(this.versions[c]=i,s.type==="importmap"){e.push(this.processImportMapAsset(s,n,c,i));return}let h=s.textContent||"",u=s.tagName==="STYLE"?"text/css":"application/javascript";e.push(this.cacheAsset(n,h,u,c,i))}),await Promise.all(e)}async processImportMapAsset(t,e,s,o){try{let n=JSON.parse(t.textContent||"{}"),a=Object.values(n.imports||{})[0];if(!a?.startsWith("data:application/javascript;base64,")){console.warn("[Skybolt] Invalid importmap data URL:",s);return}let c=a.slice(35);await this.cacheAsset(e,atob(c),"application/javascript",s,o)}catch(n){console.error("[Skybolt] Failed to process importmap:",s,n)}}async cacheAsset(t,e,s,o,n){try{let a=await caches.open(l),c=new Response(e,{status:200,statusText:"OK",headers:{"Content-Type":s,"Content-Length":String(new Blob([e]).size),"X-Skybolt-Name":o,"X-Skybolt-Hash":n,"Cache-Control":"public, max-age=31536000, immutable"}});await a.put(t,c),console.log(`[Skybolt] Cached: ${o}`)}catch(a){console.error(`[Skybolt] Failed to cache ${o}:`,a)}}async finalize(){let t=Object.keys(this.versions).length;t>0?(await this.updateCookieFromCache(),console.log(`[Skybolt] Ready (${t} new assets cached)`)):this.validateCache()}async updateCookieFromCache(){try{let t=await caches.open(l),e=await t.keys(),s={};for(let c of e){let i=await t.match(c);if(i){let h=i.headers.get("X-Skybolt-Name"),u=i.headers.get("X-Skybolt-Hash");h&&u&&(s[h]=u)}}let o=Object.entries(s);if(o.length===0)return;let n=new k(o.length);for(let[c,i]of o)n.insert(`${c}:${i}`);let a=n.toBase64();document.cookie=`${y}=${a}; path=/; max-age=${C}; SameSite=Lax`,console.log(`[Skybolt] Cache state stored (${a.length} bytes, ${o.length} assets)`)}catch(t){console.error("[Skybolt] Failed to update cookie from cache:",t)}}async validateCache(){if(document.cookie.includes(y))try{(await(await caches.open(l)).keys()).length===0&&(console.warn("[Skybolt] Cache/cookie mismatch detected, clearing cookies"),this.clearCookies(),location.reload())}catch(e){console.error("[Skybolt] Cache validation failed:",e)}}handleNoServiceWorker(){console.warn("[Skybolt] Service Worker unavailable, clearing cookies"),this.clearCookies()}clearCookies(){document.cookie=`${y}=; path=/; max-age=0`}async clearCache(){try{await caches.delete(l),this.clearCookies(),console.log("[Skybolt] Cache cleared")}catch(t){console.error("[Skybolt] Failed to clear cache:",t)}}async selfDestruct(t=!0){console.warn("[Skybolt] Self-destruct initiated");try{await caches.delete(l)}catch{}this.clearCookies();try{let e=await navigator.serviceWorker.getRegistrations();await Promise.all(e.map(s=>s.unregister()))}catch{}t&&location.reload()}async getCacheInfo(){try{let e=await(await caches.open(l)).keys();return{name:l,count:e.length,urls:e.map(s=>s.url)}}catch(t){return{name:l,count:0,urls:[],error:t.message}}}isCachedUrl(t){for(let e of Object.values(this.versions))if(t.includes(e))return!0;return!1}},b=new g;typeof window<"u"&&(window.skybolt=b);var E=b;})();
/*! Skybolt - @version 3.5.1 */