@dvai-bridge/core 4.0.0 → 4.0.2
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/LICENSE +341 -34
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/README.md +0 -199
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ var er=Object.defineProperty;var u=(t,e)=>()=>(t&&(e=t(t=0)),e);var v=(t,e)=>{fo
|
|
|
16
16
|
`))}catch{s.enqueue(n.encode(`data: ${p}
|
|
17
17
|
|
|
18
18
|
`))}}}}finally{s.close()}}})}async function _(t,e){if(!e.backend)return Response.json({error:"AI engine not initialized"},{status:503});let r=t.prompt,n=Array.isArray(r)?r.join(`
|
|
19
|
-
`):r??"",i={...t,messages:[{role:"user",content:n}]};delete i.prompt;try{if(i.stream){let o=e.backend.createStreamingResponse(i),a=we(o,t.model||e.modelId);return new Response(a,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}})}let s=await e.backend.chatCompletion(i);return Response.json(be(s))}catch(s){return Response.json({error:s.message},{status:500})}}var ke=u(()=>{"use strict"});import{x25519 as rn}from"@noble/curves/ed25519";function G(t){let e="";for(let n of t)e+=String.fromCharCode(n);return(typeof btoa<"u"?btoa(e):Buffer.from(e,"binary").toString("base64")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}var st=u(()=>{"use strict"});function O(){let t=typeof globalThis.crypto<"u"?globalThis.crypto:void 0;if(!t||typeof t.getRandomValues!="function")throw new Error("[DVAI/pairing] no secure random source");let e=new Uint8Array(32);return t.getRandomValues(e),G(e)}function Pe(){let t=typeof globalThis.crypto<"u"?globalThis.crypto:void 0;if(!t||typeof t.getRandomValues!="function")throw new Error("[DVAI/pairing] no secure random source");let e=new Uint8Array(16);return t.getRandomValues(e),G(e)}async function X(t,e){let r=globalThis.crypto;if(!r?.subtle)throw new Error("[DVAI/pairing] WebCrypto subtle not available");let n=dr(t),i=await r.subtle.importKey("raw",n,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await r.subtle.sign("HMAC",i,new TextEncoder().encode(e));return G(new Uint8Array(s))}async function Ce(t,e,r){let n=await X(t,e);return cr(n,r)}function cr(t,e){if(t.length!==e.length)return!1;let r=0;for(let n=0;n<t.length;n++)r|=t.charCodeAt(n)^e.charCodeAt(n);return r===0}function dr(t){let e=t.replace(/-/g,"+").replace(/_/g,"/"),r=e+"=".repeat((4-e.length%4)%4),n=typeof atob<"u"?atob(r):Buffer.from(r,"base64").toString("binary"),i=new Uint8Array(n.length);for(let s=0;s<n.length;s++)i[s]=n.charCodeAt(s);return i}async function Ie(t,e,r,n){let i=n?await lr(n):"0000000000000000000000000000000000000000000000000000000000000000";return`${t}
|
|
19
|
+
`):r??"",i={...t,messages:[{role:"user",content:n}]};delete i.prompt;try{if(i.stream){let o=e.backend.createStreamingResponse(i),a=we(o,t.model||e.modelId);return new Response(a,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}})}let s=await e.backend.chatCompletion(i);return Response.json(be(s))}catch(s){return Response.json({error:s.message},{status:500})}}var ke=u(()=>{"use strict"});import{x25519 as rn}from"@noble/curves/ed25519.js";function G(t){let e="";for(let n of t)e+=String.fromCharCode(n);return(typeof btoa<"u"?btoa(e):Buffer.from(e,"binary").toString("base64")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}var st=u(()=>{"use strict"});function O(){let t=typeof globalThis.crypto<"u"?globalThis.crypto:void 0;if(!t||typeof t.getRandomValues!="function")throw new Error("[DVAI/pairing] no secure random source");let e=new Uint8Array(32);return t.getRandomValues(e),G(e)}function Pe(){let t=typeof globalThis.crypto<"u"?globalThis.crypto:void 0;if(!t||typeof t.getRandomValues!="function")throw new Error("[DVAI/pairing] no secure random source");let e=new Uint8Array(16);return t.getRandomValues(e),G(e)}async function X(t,e){let r=globalThis.crypto;if(!r?.subtle)throw new Error("[DVAI/pairing] WebCrypto subtle not available");let n=dr(t),i=await r.subtle.importKey("raw",n,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await r.subtle.sign("HMAC",i,new TextEncoder().encode(e));return G(new Uint8Array(s))}async function Ce(t,e,r){let n=await X(t,e);return cr(n,r)}function cr(t,e){if(t.length!==e.length)return!1;let r=0;for(let n=0;n<t.length;n++)r|=t.charCodeAt(n)^e.charCodeAt(n);return r===0}function dr(t){let e=t.replace(/-/g,"+").replace(/_/g,"/"),r=e+"=".repeat((4-e.length%4)%4),n=typeof atob<"u"?atob(r):Buffer.from(r,"base64").toString("binary"),i=new Uint8Array(n.length);for(let s=0;s<n.length;s++)i[s]=n.charCodeAt(s);return i}async function Ie(t,e,r,n){let i=n?await lr(n):"0000000000000000000000000000000000000000000000000000000000000000";return`${t}
|
|
20
20
|
${e.toUpperCase()}
|
|
21
21
|
${r}
|
|
22
22
|
${i}`}async function lr(t){let e=globalThis.crypto;if(!e?.subtle)throw new Error("[DVAI/pairing] WebCrypto subtle not available");let r=await e.subtle.digest("SHA-256",new TextEncoder().encode(t));return Array.from(new Uint8Array(r)).map(n=>n.toString(16).padStart(2,"0")).join("")}var Y=u(()=>{"use strict";st()});function L(t){let e={none:3,integrated:8,discrete:35,"apple-silicon":40},r={low:.6,mid:1,high:1.3},n;t.ramGb<4?n=.3:t.ramGb<8?n=.7:n=1;let i=t.hasNpu?1.4:1,s=e[t.gpuClass]*r[t.cpuClass]*n*i;return Math.round(s*10)/10}function De(){if(typeof navigator<"u"){let t=navigator,e=t.deviceMemory??4,r=t.hardwareConcurrency??4,n=typeof t.gpu<"u";return{hasNpu:!1,ramGb:e,gpuClass:n?"discrete":"none",cpuClass:r>=8?"high":r>=4?"mid":"low"}}return typeof globalThis.process<"u"&&globalThis.process.versions?.node,{hasNpu:!1,ramGb:4,gpuClass:"integrated",cpuClass:"mid"}}async function V(){if(typeof globalThis.process<"u"&&globalThis.process.versions?.node)try{let t=await import("os"),e=t.totalmem(),r=Math.round(e/1024**3),n=t.cpus().length;return{hasNpu:!1,ramGb:r,gpuClass:"integrated",cpuClass:n>=12?"high":n>=6?"mid":"low"}}catch{}return De()}var Te=u(()=>{"use strict"});var Ae={};v(Ae,{HardwareTooWeakError:()=>N,assessCapability:()=>xe});async function xe(t={}){let e=t.hardwareMinimum??pr,r=t.minLocalCapability??ur;e>r;let n=t.hints??await V(),i=L(n);return i<e?{mode:"too-weak",tokPerSec:i,hints:n,reason:`estimated ${i} tok/s, below the ${e} tok/s hardware floor \u2014 local inference would be unusable, no peer to offload to either (a peer-only mode still requires the host to bring up discovery + pairing).`}:i<r?{mode:"offload-only",tokPerSec:i,hints:n,reason:`estimated ${i} tok/s, below the ${r} tok/s comfort threshold \u2014 model will not be loaded locally; every request will be forwarded to a paired peer.`}:{mode:"ok",tokPerSec:i,hints:n,reason:`estimated ${i} tok/s, above the ${r} tok/s local-capability threshold \u2014 running normally.`}}var pr,ur,N,Q=u(()=>{"use strict";Te();pr=3,ur=10;N=class extends Error{tokPerSec;hardwareMinimum;hints;constructor(e){super(`DVAI: ${e.reason}`),this.name="HardwareTooWeakError",this.tokPerSec=e.tokPerSec,this.hardwareMinimum=e.hardwareMinimum,this.hints=e.hints}}});async function U(t,e,r){if(e.chatCompletionInterceptor)try{let i=await e.chatCompletionInterceptor(t,e,r);if(i!==null)return i}catch(i){return Response.json({error:i?.message??"interceptor failed"},{status:500})}if(!e.backend)return Response.json({error:"AI engine not initialized"},{status:503});let n=async()=>{let i=e.backend;if(!i)return Response.json({error:"AI engine not initialized"},{status:503});if(t.stream){let o=i.createStreamingResponse(t);return new Response(o,{headers:mr})}let s=await i.chatCompletion(t);return Response.json(s)};try{return e.backend.lastFatalError&&e.onRecovery&&await e.onRecovery(),await n()}catch(i){if(e.backend?.lastFatalError&&e.onRecovery)try{return await e.onRecovery(),await n()}catch{}return Response.json({error:i.message},{status:500})}}var mr,ot=u(()=>{"use strict";mr={"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}});async function j(t,e){if(!e.backend)return Response.json({error:"AI engine not initialized"},{status:503});if(e.resolvedBackend==="webllm")return Response.json({error:"Embeddings are not supported on the WebLLM backend. Use backend: 'transformers' with pipelineTask: 'feature-extraction'."},{status:400});if(typeof e.backend.embedding!="function")return Response.json({error:"The current backend does not support embeddings. For transformers: use pipelineTask: 'feature-extraction'."},{status:400});let r=t?.input;if(r==null)return Response.json({error:"Missing 'input' field."},{status:400});try{let n=await e.backend.embedding(r);return Response.json({object:"list",data:n.map((i,s)=>({object:"embedding",embedding:i,index:s})),model:t.model||e.modelId,usage:{prompt_tokens:0,total_tokens:0}})}catch(n){return Response.json({error:n.message},{status:500})}}var at=u(()=>{"use strict"});async function H(t){return Response.json({object:"list",data:[{id:t.modelId,object:"model",created:Math.floor(Date.now()/1e3),owned_by:"dvai-bridge"}]})}var ct=u(()=>{"use strict"});var Se=u(()=>{"use strict";ot();ke();at();ct()});import{setupWorker as hr}from"msw/browser";import{http as Z}from"msw";function fr(t){let e=t,r=e,n="/chat/completions";if(e.endsWith(n))r=e.slice(0,-n.length);else try{let i=new URL(e),s=i.pathname.split("/").filter(Boolean);s.pop(),i.pathname="/"+s.join("/"),r=i.toString().replace(/\/$/,"")}catch{}return{chat:e,completions:`${r}/completions`,embeddings:`${r}/embeddings`,models:`${r}/models`,base:r}}var ee,dt=u(()=>{"use strict";Se();ee=class{constructor(e){this.opts=e}opts;kind="msw";worker=null;async start(e){let r=fr(this.opts.mockUrl);if(this.opts.serviceWorkerUrl){let n=[Z.post(r.chat,async({request:i})=>U(await i.json(),e)),Z.post(r.completions,async({request:i})=>_(await i.json(),e)),Z.post(r.embeddings,async({request:i})=>j(await i.json(),e)),Z.get(r.models,async()=>H(e))];this.worker=hr(...n),await this.worker.start({onUnhandledRequest:"bypass",serviceWorker:{url:this.opts.serviceWorkerUrl}})}return{baseUrl:r.base}}async stop(){this.worker&&(this.worker.stop(),this.worker=null)}}});async function te(t,e=38883,r=16,n="127.0.0.1"){for(let i=0;i<r;i++){let s=e+i;try{return await new Promise((o,a)=>{let c=d=>{t.off("error",c),a(d)};t.once("error",c),t.listen(s,n,()=>{t.off("error",c),o()})}),s}catch(o){if(o.code!=="EADDRINUSE")throw o}}throw new Error(`[DVAI] Could not bind HTTP transport to any port in range ${e}..${e+r-1} (all in use). Another local AI server may already be running.`)}var lt,pt,Ee=u(()=>{"use strict";lt=38883,pt=16});function yr(t,e){return e==="*"?"*":typeof e=="string"?e:t&&e.includes(t)?t:null}function gr(t,e){let r=yr(t,e),n={"Access-Control-Allow-Methods":"POST, GET, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Authorization","Access-Control-Allow-Private-Network":"true"};return r&&(n["Access-Control-Allow-Origin"]=r),n}async function re(t){let e=[];for await(let n of t)e.push(n);let r=Buffer.concat(e).toString("utf8");if(!r)return{};try{return JSON.parse(r)}catch{throw new Error("Invalid JSON body")}}async function ne(t,e,r){let n={...r};if(e.headers.forEach((s,o)=>{n[o]=s}),e.body){t.writeHead(e.status,n);let s=e.body.getReader();try{for(;;){let{done:o,value:a}=await s.read();if(o)break;t.write(Buffer.from(a))}}finally{t.end()}return}let i=await e.text();t.writeHead(e.status,n),t.end(i)}async function vr(t,e,r,n){let i=t.headers.origin,s=gr(i,n.corsOrigin);if(t.method==="OPTIONS"){e.writeHead(204,s),e.end();return}let a=new URL(t.url||"/","http://127.0.0.1").pathname;try{if(t.method==="POST"&&a==="/v1/chat/completions"){let d=await re(t),l={};for(let[p,h]of Object.entries(t.headers))typeof h=="string"?l[p.toLowerCase()]=h:Array.isArray(h)&&h.length>0&&(l[p.toLowerCase()]=h.join(", "));let m=await U(d,r,l);return ne(e,m,s)}if(t.method==="POST"&&a==="/v1/completions"){let d=await re(t),l=await _(d,r);return ne(e,l,s)}if(t.method==="POST"&&a==="/v1/embeddings"){let d=await re(t),l=await j(d,r);return ne(e,l,s)}if(t.method==="GET"&&a==="/v1/models"){let d=await H(r);return ne(e,d,s)}let c=r.dvaiRoutes;if(c){let d=`${t.method??"GET"} ${a}`,l=c[d];if(l){let m;(t.method==="POST"||t.method==="PUT"||t.method==="PATCH")&&(m=await re(t));let p=await l({body:m}),h={...s,"Content-Type":"application/json"};e.writeHead(p.status,h),e.end(JSON.stringify(p.body));return}}e.writeHead(404,{...s,"Content-Type":"application/json"}),e.end(JSON.stringify({error:"not found"}))}catch(c){e.writeHead(500,{...s,"Content-Type":"application/json"}),e.end(JSON.stringify({error:c?.message??"unknown error"}))}}var ie,ut=u(()=>{"use strict";Se();Ee();ie=class{constructor(e){this.opts=e}opts;kind="http";server=null;boundPort;async start(e){let{createServer:r}=await import("http"),n=r((o,a)=>{vr(o,a,e,this.opts).catch(c=>{try{a.writeHead(500,{"Content-Type":"application/json"}),a.end(JSON.stringify({error:c.message}))}catch{}})}),i=this.opts.bindHost??"127.0.0.1",s=await te(n,this.opts.httpBasePort,this.opts.httpMaxPortAttempts,i);return this.server=n,this.boundPort=s,{baseUrl:`http://${i}:${s}/v1`,port:s}}async stop(){this.server&&(await new Promise(e=>this.server.close(()=>e())),this.server=null,this.boundPort=void 0)}}});var se,mt=u(()=>{"use strict";se=class{constructor(e){this.opts=e}opts;kind="capacitor";async start(e){let{DVAIBridge:r}=await import("@dvai-bridge/capacitor"),n=await r.start({backend:this.opts.capacitorBackend,modelPath:this.opts.nativeModelPath,mmprojPath:this.opts.nativeMmprojPath,gpuLayers:this.opts.nativeGpuLayers,contextSize:this.opts.nativeContextSize,threads:this.opts.nativeThreads,embeddingMode:this.opts.nativeEmbeddingMode,httpBasePort:this.opts.httpBasePort,httpMaxPortAttempts:this.opts.httpMaxPortAttempts,corsOrigin:this.opts.corsOrigin,autoUnloadOnLowMemory:this.opts.autoUnloadOnLowMemory,logLevel:this.opts.logLevel});return{baseUrl:n.baseUrl,port:n.port}}async stop(){let{DVAIBridge:e}=await import("@dvai-bridge/capacitor");await e.stop()}}});var ht={};v(ht,{BASE_PORT:()=>lt,CapacitorTransport:()=>se,HttpTransport:()=>ie,MAX_PORT_ATTEMPTS:()=>pt,MswTransport:()=>ee,selectTransport:()=>br,tryBind:()=>te});function br(t){if(t.serviceWorkerUrl===""&&t.transport==null)return"none";let e=t.transport??"auto";return e!=="auto"?e:wr()?"capacitor":kr()?"msw":Pr()?"http":"none"}function wr(){return typeof window<"u"&&!!window.Capacitor?.isNativePlatform?.()}function kr(){return typeof window<"u"&&typeof document<"u"&&typeof navigator<"u"&&typeof navigator.serviceWorker<"u"}function Pr(){return typeof process<"u"&&process.versions!=null&&process.versions.node!=null}var ft=u(()=>{"use strict";dt();ut();mt();Ee()});function oe(t){if(!t.config.enabled)return{kind:"local"};if(t.header==="never")return{kind:"local"};let e=t.peers.map(s=>({peer:s,score:s.capability[t.modelId]??0,hasModel:s.loadedModels.includes(t.modelId)})).filter(s=>s.score>0).sort((s,o)=>{if(s.hasModel!==o.hasModel)return s.hasModel?-1:1;if(s.score!==o.score)return o.score-s.score;let a={mdns:0,static:1,custom:2,rendezvous:3};return a[s.peer.via]-a[o.peer.via]}),r=e[0]?.peer,n=e[0]?.score??0,i=t.config.minLocalCapability;return t.header==="require"?r&&n>=i?{kind:"offload",peer:r}:{kind:"no_capable_device",checked:yt(t),localCapability:t.localCapability,required:i}:t.localCapability>=i?{kind:"local"}:r&&n>t.localCapability?{kind:"offload",peer:r}:t.localCapability>0?{kind:"local"}:{kind:"no_capable_device",checked:yt(t),localCapability:t.localCapability,required:i}}function yt(t){let e=[{deviceId:"self",capabilityScore:t.localCapability,reason:t.localCapability<t.config.minLocalCapability?"below threshold":"no eligible peer found"}];for(let r of t.peers){let n=r.capability[t.modelId]??0;e.push({deviceId:r.deviceId,deviceName:r.deviceName,capabilityScore:n,reason:n===0?"model not advertised":n<t.config.minLocalCapability?"below threshold":"checked"})}return e}var Me=u(()=>{"use strict"});function ae(t,e){let r=`No device with capability \u2265 ${t.required} tok/s for model ${e.modelId} was reachable. Local: ${t.localCapability} tok/s; ${t.checked.length-1} peer(s) checked.`;return{status:503,headers:{"Content-Type":"application/json","Retry-After":"30"},body:{error:{type:"no_capable_device",code:503,message:r,checked:t.checked,localCapability:t.localCapability,requiredAtLeast:t.required,rendezvousConfigured:e.rendezvousConfigured,pairedRemotePeers:e.pairedRemotePeers,requestId:e.requestId}}}}var Re=u(()=>{"use strict"});function ce(t){let e;if(t instanceof Headers)e=t.get("x-dvai-offload");else for(let[n,i]of Object.entries(t))if(n.toLowerCase()==="x-dvai-offload"){e=i;break}if(!e)return"prefer";let r=e.toLowerCase().trim();return Cr.has(r)?r:"prefer"}var Cr,_e=u(()=>{"use strict";Cr=new Set(["never","prefer","require"])});async function de(t,e){if(t.via==="rendezvous"&&(!t.baseUrl||!t.baseUrl.startsWith("http")))throw new Error("[DVAI/offload] rendezvous-paired peers require WebSocket relay (not yet implemented in v3.0.0-rc1; expected in v3.0.0 final).");let r=`${t.baseUrl.replace(/\/$/,"")}${e.path}`,n={"Content-Type":"application/json","X-DVAI-Forwarded":"1",...e.headers??{}},i=await fetch(r,{method:e.method,headers:n,body:e.body!==void 0?JSON.stringify(e.body):void 0,signal:e.signal}),s={};return i.headers.forEach((o,a)=>{s[a]=o}),e.stream&&i.body?{status:i.status,headers:s,stream:i.body}:{status:i.status,headers:s,body:await i.json().catch(()=>{})}}var Oe=u(()=>{"use strict"});function vt(t){return async function(r,n,i){if(!t.config.enabled)return null;let s=Ir(i),o=t.getPeers(),a=n.modelId,c=t.getLocalCapability(a),d=oe({config:t.config,modelId:a,localCapability:c,peers:o,header:s});if(d.kind==="local")return t.offloadOnlyMode?gt(503,{error:{type:"no_local_backend",code:503,message:"DVAI is running in offload-only mode (device below minLocalCapability) and the request requested local execution (X-DVAI-Offload: never). Either drop the header or route to a peer."}}):null;if(d.kind==="offload"){let m=r&&typeof r=="object"&&r.stream===!0;try{let p=await de(d.peer,{method:"POST",path:"/chat/completions",body:r,stream:m,headers:Dr(i)});try{t.config.onOffload?.(d.peer)}catch{}return p.stream?new Response(p.stream,{status:p.status,headers:p.headers}):new Response(JSON.stringify(p.body),{status:p.status,headers:p.headers})}catch(p){return gt(502,{error:{type:"peer_unreachable",code:502,message:`Offload to peer ${d.peer.deviceId} failed: ${p instanceof Error?p.message:String(p)}`,peerId:d.peer.deviceId}})}}let l=ae(d,{rendezvousConfigured:!!t.config.rendezvousUrl,pairedRemotePeers:o.filter(m=>m.via==="rendezvous").length,modelId:a});return new Response(JSON.stringify(l.body),{status:l.status,headers:l.headers})}}function Ir(t){return t?ce(t):"prefer"}function Dr(t){if(!t)return{};let e={},r=new Set(["host","content-length","connection","keep-alive","transfer-encoding"]);for(let[n,i]of Object.entries(t))r.has(n.toLowerCase())||(e[n]=i);return e}function gt(t,e){return new Response(JSON.stringify(e),{status:t,headers:{"Content-Type":"application/json"}})}var bt=u(()=>{"use strict";Me();Re();Oe();_e()});var wt={};v(wt,{buildNoCapableDeviceResponse:()=>ae,buildOffloadInterceptor:()=>vt,decide:()=>oe,parseOffloadHeader:()=>ce,proxyToPeer:()=>de});var kt=u(()=>{"use strict";Me();Re();_e();Oe();bt()});function xr(){if(typeof globalThis.process<"u"){let t=globalThis.process.env,e=t.HOME??t.USERPROFILE??".";return t.LOCALAPPDATA?`${t.LOCALAPPDATA}/dvai-bridge/capability.json`:t.XDG_CACHE_HOME?`${t.XDG_CACHE_HOME}/dvai-bridge/capability.json`:`${e}/.cache/dvai-bridge/capability.json`}return"./.dvai-bridge-capability.json"}function Pt(){return typeof indexedDB<"u"?new S:typeof globalThis.process<"u"&&globalThis.process.versions?.node?new E:new B}var B,Tr,k,A,S,E,Ct=u(()=>{"use strict";B=class{map=new Map;async get(e){return this.map.get(this.keyOf(e))}async set(e){this.map.set(this.keyOf({modelId:e.modelId,libraryVersion:e.libraryVersion}),e)}async list(){return Array.from(this.map.values())}async clear(){this.map.clear()}keyOf(e){return`${e.libraryVersion}::${e.modelId}`}},Tr="dvai-bridge",k="capability-v1",A="meta-v1",S=class{dbPromise;openDb(){return this.dbPromise||(this.dbPromise=new Promise((e,r)=>{let n=indexedDB.open(Tr,1);n.onupgradeneeded=()=>{let i=n.result;i.objectStoreNames.contains(k)||i.createObjectStore(k),i.objectStoreNames.contains(A)||i.createObjectStore(A)},n.onsuccess=()=>e(n.result),n.onerror=()=>r(n.error)})),this.dbPromise}async get(e){let r=await this.openDb();return await new Promise((n,i)=>{let o=r.transaction(k,"readonly").objectStore(k).get(this.keyOf(e));o.onsuccess=()=>n(o.result),o.onerror=()=>i(o.error)})}async set(e){let r=await this.openDb();await new Promise((n,i)=>{let s=r.transaction(k,"readwrite");s.objectStore(k).put(e,this.keyOf({modelId:e.modelId,libraryVersion:e.libraryVersion})),s.oncomplete=()=>n(),s.onerror=()=>i(s.error)})}async list(){let e=await this.openDb();return await new Promise((r,n)=>{let s=e.transaction(k,"readonly").objectStore(k).getAll();s.onsuccess=()=>r(s.result),s.onerror=()=>n(s.error)})}async clear(){let e=await this.openDb();await new Promise((r,n)=>{let i=e.transaction(k,"readwrite");i.objectStore(k).clear(),i.oncomplete=()=>r(),i.onerror=()=>n(i.error)})}async getMeta(e){let r=await this.openDb();return await new Promise((n,i)=>{let o=r.transaction(A,"readonly").objectStore(A).get(e);o.onsuccess=()=>n(o.result),o.onerror=()=>i(o.error)})}async setMeta(e,r){let n=await this.openDb();await new Promise((i,s)=>{let o=n.transaction(A,"readwrite");o.objectStore(A).put(r,e),o.oncomplete=()=>i(),o.onerror=()=>s(o.error)})}keyOf(e){return`${e.libraryVersion}::${e.modelId}`}},E=class{cachePath;cache;constructor(e){this.cachePath=e??xr()}async load(){if(this.cache)return this.cache;let e=await import("fs/promises"),r=await import("path");try{let n=await e.readFile(this.cachePath,"utf8");this.cache=JSON.parse(n)}catch{this.cache={deviceId:"",scores:{}}}return await e.mkdir(r.dirname(this.cachePath),{recursive:!0}),this.cache}async save(){if(!this.cache)return;await(await import("fs/promises")).writeFile(this.cachePath,JSON.stringify(this.cache,null,2),"utf8")}async get(e){return(await this.load()).scores[this.keyOf(e)]}async set(e){let r=await this.load();r.scores[this.keyOf({modelId:e.modelId,libraryVersion:e.libraryVersion})]=e,await this.save()}async list(){let e=await this.load();return Object.values(e.scores)}async clear(){let e=await this.load();e.scores={},await this.save()}async getDeviceId(){return(await this.load()).deviceId}async setDeviceId(e){let r=await this.load();r.deviceId=e,await this.save()}keyOf(e){return`${e.libraryVersion}::${e.modelId}`}}});function $(){let t=typeof globalThis.crypto<"u"?globalThis.crypto:void 0;if(!t||typeof t.getRandomValues!="function")throw new Error("[DVAI/capability] No secure random source available. globalThis.crypto.getRandomValues required (Node \u226519, modern browsers, Bun, Deno).");let e=new Uint8Array(16);return t.getRandomValues(e),Ar(e)}function Ar(t){let e="";for(let n of t)e+=String.fromCharCode(n);return(typeof btoa<"u"?btoa(e):Buffer.from(e,"binary").toString("base64")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}var It=u(()=>{"use strict"});async function Le(t){let e=performance.now(),r=await t.backend.chatCompletion({messages:[{role:"user",content:Sr}],max_tokens:50,stream:!1}),n=(performance.now()-e)/1e3,i=r.usage?.completion_tokens,s=r.choices[0]?.message?.content??r.choices[0]?.text??"",o=i??Er(s),a=o>0&&n>0?Math.round(o/n*10)/10:0;return{modelId:t.modelId,deviceId:t.deviceId,libraryVersion:t.libraryVersion,tokPerSec:a,source:"probe",measuredAt:Date.now()}}function Er(t){return Math.max(1,Math.round(t.length/4))}var Sr,Dt=u(()=>{"use strict";Sr="Generate a single short sentence about clouds."});var le={};v(le,{HardwareTooWeakError:()=>N,InMemoryCapabilityCache:()=>B,IndexedDBCapabilityCache:()=>S,NodeFsCapabilityCache:()=>E,assessCapability:()=>xe,clearCapabilityCache:()=>Rr,createCapabilityCache:()=>Pt,detectDeviceHints:()=>De,detectDeviceHintsAsync:()=>V,ensureDeviceId:()=>Ve,generateDeviceId:()=>$,getCapability:()=>Mr,heuristicTokPerSec:()=>L,probeAndCache:()=>Ne,probeCapability:()=>Le});async function Ve(t){if(t instanceof S){let r=await t.getMeta(Tt);if(r)return r;let n=$();return await t.setMeta(Tt,n),n}if(t instanceof E){let r=await t.getDeviceId();if(r)return r;let n=$();return await t.setDeviceId(n),n}return $()}async function Mr(t){let e=await t.cache.get({modelId:t.modelId,libraryVersion:t.libraryVersion});if(e)return e;let r=t.hints??await V(),n=await Ve(t.cache);return{modelId:t.modelId,deviceId:n,libraryVersion:t.libraryVersion,tokPerSec:L(r),source:"heuristic",measuredAt:Date.now()}}async function Ne(t){let e=await Ve(t.cache),r=await Le({backend:t.backend,modelId:t.modelId,libraryVersion:t.libraryVersion,deviceId:e});return await t.cache.set(r),r}async function Rr(t){await t.clear()}var Tt,W=u(()=>{"use strict";Ct();Te();It();Dt();Q();Tt="dvai.deviceId"});var I,Ue=u(()=>{"use strict";I="_dvai-bridge._tcp.local"});var pe,xt=u(()=>{"use strict";pe=class{listeners=new Set;peerList;started=!1;constructor(e){let r=Date.now();this.peerList=e.map(n=>({...n,lastSeenAt:n.lastSeenAt&&n.lastSeenAt>0?n.lastSeenAt:r,via:"static"}))}async start(){if(!this.started){this.started=!0;for(let e of this.peerList)this.emit({type:"peer-up",peer:e})}}async stop(){this.started=!1;for(let e of this.peerList)this.emit({type:"peer-down",deviceId:e.deviceId})}peers(){return this.started?[...this.peerList]:[]}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}emit(e){for(let r of this.listeners)try{r(e)}catch(n){console.error("[DVAI/discovery] listener threw:",n)}}}});var At={};v(At,{NodeMdnsDiscovery:()=>je});var je,St=u(()=>{"use strict";Ue();je=class{constructor(e){this.opts=e}opts;mdns;peerMap=new Map;listeners=new Set;queryTimer;gcTimer;started=!1;async start(){if(this.started)return;let e;try{e=await import("multicast-dns")}catch{this.emit({type:"error",message:"[DVAI/discovery] `multicast-dns` not installed; LAN discovery disabled. Install with `npm i multicast-dns` (optional dep) to enable peer discovery."});return}let r=typeof e=="function"?e:e.default;this.mdns=r(),this.started=!0,this.mdns.on("response",s=>this.onResponse(s)),this.broadcastQuery();let n=this.opts.queryIntervalMs??3e4;this.queryTimer=setInterval(()=>this.broadcastQuery(),n);let i=this.opts.gcIntervalMs??6e4;this.gcTimer=setInterval(()=>this.gc(),i)}async stop(){if(this.started){this.started=!1,this.queryTimer&&clearInterval(this.queryTimer),this.gcTimer&&clearInterval(this.gcTimer),this.mdns?.destroy(),this.mdns=void 0;for(let e of this.peerMap.values())this.emit({type:"peer-down",deviceId:e.deviceId});this.peerMap.clear()}}peers(){return Array.from(this.peerMap.values())}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}broadcastQuery(){if(this.mdns){try{this.mdns.query({questions:[{name:I,type:"PTR"}]})}catch(e){this.emit({type:"error",message:`mDNS query failed: ${String(e)}`})}if(this.opts.advertise)try{this.mdns.respond({answers:this.buildAdvertisementAnswers(this.opts.advertise)})}catch(e){this.emit({type:"error",message:`mDNS respond failed: ${String(e)}`})}}}buildAdvertisementAnswers(e){let r=`${e.deviceId}.${I}`;return[{name:I,type:"PTR",data:r,ttl:120},{name:r,type:"SRV",data:{port:e.port,target:`${e.deviceId}.local`},ttl:120},{name:r,type:"TXT",data:this.encodeTxt(e),ttl:120}]}encodeTxt(e){return[`dvaiVersion=${e.dvaiVersion}`,`deviceId=${e.deviceId}`,`deviceName=${e.deviceName}`,`models=${e.models.join(",")}`,`capability=${JSON.stringify(e.capability)}`,`port=${e.port}`,`secure=${e.secure?"1":"0"}`]}onResponse(e){let r=[...e.answers,...e.additionals??[]],n,i;for(let l of r)l.type==="SRV"&&String(l.name).endsWith(I)&&(n=l),l.type==="TXT"&&String(l.name).endsWith(I)&&(i=l);if(!n||!i)return;let s=this.decodeTxt(i.data);if(!s||s.deviceId===this.opts.selfDeviceId)return;let o=n.data,a=`${s.secure?"https":"http"}://${o.target}:${o.port}/v1`,c={deviceId:s.deviceId,deviceName:s.deviceName,dvaiVersion:s.dvaiVersion,baseUrl:a,loadedModels:s.models,capability:s.capability,via:"mdns",secure:s.secure,lastSeenAt:Date.now()},d=this.peerMap.get(c.deviceId);this.peerMap.set(c.deviceId,c),d||this.emit({type:"peer-up",peer:c})}decodeTxt(e){let r;if(Array.isArray(e))r=e.map(s=>Buffer.isBuffer(s)?s.toString("utf8"):String(s));else if(Buffer.isBuffer(e))r=e.toString("utf8").split(`
|