@dvai-bridge/core 4.0.0
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 +51 -0
- package/README.md +199 -0
- package/bin/dvai-bridge.js +72 -0
- package/dist/dvai-transformers.worker.js +48 -0
- package/dist/dvai-webllm.worker.js +89 -0
- package/dist/index.cjs +69 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1030 -0
- package/dist/index.d.ts +1030 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/package.json +75 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
var er=Object.defineProperty;var u=(t,e)=>()=>(t&&(e=t(t=0)),e);var v=(t,e)=>{for(var r in e)er(t,r,{get:e[r],enumerable:!0})};function or(t){let e=t[t.length-1];if(!e||!Array.isArray(e.content))return{audio:null,images:null};let r=null,n=[];for(let i of e.content)i&&(i.type==="audio"&&i.data?r=i.data:i.type==="image"&&(i.image||i.data||i.url)&&n.push(i.image??i.data??i.url));return{audio:r,images:n.length>0?n:null}}function tt(t,e,r={}){let n=r.defaultMaxNewTokens??1024,i=async(s,o)=>{let a=e.apply_chat_template(s,{enable_thinking:!1,add_generation_prompt:!0}),{audio:c,images:d}=or(s),l=await e(a,d,c,{add_special_tokens:!1}),m={...l,max_new_tokens:o?.max_new_tokens??n,temperature:o?.temperature??0,do_sample:o?.do_sample??!1,top_p:o?.top_p??1};o?.streamer&&(m.streamer=o.streamer);let p=await t.generate(m),h=l.input_ids.dims.at(-1),f=p.slice(null,[h,null]);return[{generated_text:e.batch_decode(f,{skip_special_tokens:!0})[0]??""}]};return i.tokenizer=e.tokenizer,i.dispose=async()=>{try{await t.dispose?.()}catch{}},i}function rt(t,e){if(!(!e||e.length===0))for(let r of e)try{t&&t[r]&&(t[r]=null)}catch{}}var nt=u(()=>{"use strict"});var it={};v(it,{TransformersBackend:()=>ye,detectWebGPU:()=>ge});function ar(t){if(!t)return[];if(Array.isArray(t))return t.length>0&&Array.isArray(t[0])?t:[t];if(typeof t.tolist=="function"){let e=t.tolist();return Array.isArray(e)&&e.length>0&&Array.isArray(e[0])?e:[e]}if(t.data&&t.dims){let[e,r]=t.dims.length===2?t.dims:[1,t.dims[t.dims.length-1]],n=Array.from(t.data),i=[];for(let s=0;s<e;s++)i.push(n.slice(s*r,(s+1)*r));return i}return[]}function fe(t){return typeof t=="string"?t:Array.isArray(t)?t.map(e=>fe(e)).join(""):t&&typeof t=="object"?t.text||t.content||JSON.stringify(t):String(t||"")}async function ge(){if(typeof navigator>"u"||!("gpu"in navigator))return!1;try{return await navigator.gpu.requestAdapter()!==null}catch{return!1}}var ye,ve=u(()=>{"use strict";nt();ye=class{pipeline=null;worker=null;modelId;device;resolvedDevice="wasm";generationTimeout;workerUrl;pipelineTask;dtype;createPipelineFn;modelClass;processorClass;disableEncoders;usingWorker=!1;pendingRequests=new Map;pendingStreams=new Map;constructor(e){this.modelId=e.modelId,this.device=e.device,this.generationTimeout=e.generationTimeout,this.workerUrl=e.workerUrl,this.pipelineTask=e.pipelineTask||"text-generation",this.dtype=e.dtype,this.createPipelineFn=e.createPipeline,this.modelClass=e.modelClass,this.processorClass=e.processorClass,this.disableEncoders=e.disableEncoders}async initialize(e){let r=typeof window>"u"&&typeof process<"u"&&process.versions?.node!==void 0;if(this.device==="auto"){let n=await ge();this.resolvedDevice=n?"webgpu":r?"cpu":"wasm",console.log(`[DVAI/Transformers] Auto-detected device: ${this.resolvedDevice}`)}else this.device==="cpu"?this.resolvedDevice=r?"cpu":"wasm":this.resolvedDevice=this.device;if(this.workerUrl&&typeof Worker<"u")try{await this.initializeWithWorker(e);return}catch(n){console.error(`[DVAI/Transformers] Worker initialization FAILED \u2014 falling back to main thread. This WILL block the UI during inference. Check that the worker file is deployed at "${this.workerUrl}" (run \`dvai-bridge init\` to copy it).`,n),this.worker=null}else this.workerUrl||console.warn("[DVAI/Transformers] No workerUrl configured \u2014 running on main thread. This blocks the UI during inference. Set `transformersWorkerUrl` (defaults to '/dvai-transformers.worker.js') to enable the worker path.");await this.initializeMainThread(e)}async initializeWithWorker(e){return new Promise((r,n)=>{let i=new Worker(this.workerUrl,{type:"module"}),s=this.generateRequestId(),o=c=>{let d=c.data;if(d.id===s)switch(d.type){case"progress":if(e){let l=d.data,m=l.progress??0,p=l.status==="progress"?`Downloading ${l.file}: ${Math.round(m)}%`:l.status==="ready"?"Model ready":`${l.status}${l.file?`: ${l.file}`:""}`;e({text:p,progress:m/100,timeElapsed:0})}break;case"init_complete":i.removeEventListener("message",o),this.worker=i,this.usingWorker=!0,i.addEventListener("message",l=>this.handleWorkerMessage(l)),console.log("[DVAI/Transformers] Initialized with Web Worker (main thread unblocked)"),r();break;case"error":i.removeEventListener("message",o),i.terminate(),n(new Error(d.error));break}};i.addEventListener("message",o),i.addEventListener("error",c=>{i.removeEventListener("message",o);let d=c.message||(c.error?c.error.message:"Unknown worker error");n(new Error(`Worker error: ${d}`))});let a={type:"init",id:s,pipelineTask:this.pipelineTask,modelId:this.modelId,device:this.resolvedDevice,dtype:this.dtype,modelClass:this.modelClass,processorClass:this.processorClass,disableEncoders:this.disableEncoders};console.log("[DVAI/Transformers] Sending init to worker:",a),i.postMessage(a)})}handleWorkerMessage(e){let r=e.data;if(!r.id)return;let n=this.pendingStreams.get(r.id);if(n)switch(r.type){case"stream_chunk":n.onChunk(r.text);return;case"stream_complete":this.pendingStreams.delete(r.id),n.onComplete();return;case"error":this.pendingStreams.delete(r.id),n.onError(new Error(r.error||"Unknown worker internal error"));return}let i=this.pendingRequests.get(r.id);if(i)switch(r.type){case"generate_complete":case"embed_complete":this.pendingRequests.delete(r.id),i.resolve(r.data);break;case"unload_complete":this.pendingRequests.delete(r.id),i.resolve(void 0);break;case"error":this.pendingRequests.delete(r.id),i.reject(new Error(r.error||"Unknown worker internal error"));break}}sendWorkerRequest(e,r={}){return new Promise((n,i)=>{let s=this.generateRequestId();this.pendingRequests.set(s,{resolve:n,reject:i}),this.worker.postMessage({type:e,id:s,...r})})}async initializeMainThread(e){let r=await import("@huggingface/transformers"),{pipeline:n,env:i}=r;i.allowLocalModels=!1,i.allowRemoteModels=!0,i.remoteHost="https://huggingface.co",i.remotePathTemplate="{model}/resolve/{revision}/";let s=e?o=>{let a=o.progress??0,c=o.status==="progress"?`Downloading ${o.file}: ${Math.round(a)}%`:o.status==="ready"?`Model ready (${this.pipelineTask})`:`${o.status}${o.file?`: ${o.file}`:""}`;e({text:c,progress:a/100,timeElapsed:0})}:void 0;if(this.createPipelineFn)console.log("[DVAI/Transformers] Using custom createPipeline factory."),this.pipeline=await this.createPipelineFn(r,{modelId:this.modelId,device:this.resolvedDevice,dtype:this.dtype,onProgress:s});else if(this.modelClass){console.log(`[DVAI/Transformers] Using declarative loader: ${this.modelClass} + ${this.processorClass||"AutoProcessor"}`);let o=r[this.modelClass];if(!o)throw new Error(`transformers.js has no export named "${this.modelClass}". Check your modelClass config.`);let a=this.processorClass||"AutoProcessor",c=r[a];if(!c)throw new Error(`transformers.js has no export named "${a}". Check your processorClass config.`);let d=await c.from_pretrained(this.modelId,{progress_callback:s}),l=await o.from_pretrained(this.modelId,{dtype:this.dtype,device:this.resolvedDevice,progress_callback:s});rt(l,this.disableEncoders),this.pipeline=tt(l,d)}else this.pipeline=await n(this.pipelineTask,this.modelId,{device:this.resolvedDevice,progress_callback:s,dtype:this.dtype});this.usingWorker=!1,this.resolvedDevice==="wasm"||this.resolvedDevice==="cpu"?console.warn(`[DVAI/Transformers] Running on main thread with ${this.resolvedDevice.toUpperCase()} (CPU). `+(this.resolvedDevice==="wasm"?"Inference may block the UI. Set `workerUrl` to a deployed transformers worker for better performance.":"(Node host \u2014 no UI thread to block.)")):console.log("[DVAI/Transformers] Initialized on main thread (WebGPU compute is async)")}getPipelineTask(){return this.pipelineTask}getResolvedDevice(){return this.resolvedDevice}isWorkerBased(){return this.usingWorker}getPipeline(){return this.pipeline}isTextTask(){return["text-generation","text2text-generation","summarization","translation","image-text-to-text","any-to-any"].includes(this.pipelineTask)}async runPipeline(e,r){if(this.usingWorker&&this.worker)return this.withTimeout(this.sendWorkerRequest("generate",{requestBody:{raw:!0,inputs:e,options:r}}),this.generationTimeout);if(!this.pipeline)throw new Error("Transformers.js pipeline not initialized");return this.withTimeout(this.pipeline(e,r),this.generationTimeout)}async chatCompletion(e){if(!this.isTextTask())throw new Error(`chatCompletion() is only available for text-generation tasks. Current task: "${this.pipelineTask}". Use runPipeline() instead.`);let r=(e.messages||[]).map(l=>({...l,content:fe(l.content)})),n=e.max_tokens??e.max_completion_tokens??256,i=e.temperature??.7,s=e.top_p??1,o={max_new_tokens:n,temperature:i,top_p:s,do_sample:i>0,return_full_text:!1},a;if(this.usingWorker&&this.worker)a=await this.withTimeout(this.sendWorkerRequest("generate",{requestBody:{...e,messages:r}}),this.generationTimeout);else if(this.pipeline)console.log("[DVAI/Transformers] Running local inference:",r),a=await this.withTimeout(this.pipeline(r,o),this.generationTimeout);else throw new Error("Transformers.js backend not initialized");let c=a?.[0]?.generated_text??"",d=typeof c=="string"?c:Array.isArray(c)?c[c.length-1]?.content??"":String(c);return{id:`chatcmpl-${Date.now()}`,object:"chat.completion",created:Math.floor(Date.now()/1e3),model:this.modelId,choices:[{index:0,message:{role:"assistant",content:d},finish_reason:"stop"}],usage:{prompt_tokens:0,completion_tokens:0,total_tokens:0}}}createStreamingResponse(e){if(!this.isTextTask())throw new Error(`Streaming chat completion is only available for text-generation tasks. Current task: "${this.pipelineTask}".`);let r=this.modelId,n=this,i=this.generationTimeout;return new ReadableStream({async start(s){let o=`chatcmpl-${Date.now()}`,a=Math.floor(Date.now()/1e3),c=new TextEncoder,d=p=>{let h={id:o,object:"chat.completion.chunk",created:a,model:r,choices:[{index:0,delta:{content:p},finish_reason:null}]};s.enqueue(c.encode(`data: ${JSON.stringify(h)}
|
|
2
|
+
|
|
3
|
+
`))},l=(p="stop")=>{let h={id:o,object:"chat.completion.chunk",created:a,model:r,choices:[{index:0,delta:{},finish_reason:p}]};s.enqueue(c.encode(`data: ${JSON.stringify(h)}
|
|
4
|
+
|
|
5
|
+
`))},m=null;try{let p=new Promise((f,y)=>{if(n.usingWorker&&n.worker){let P=n.generateRequestId();n.pendingStreams.set(P,{onChunk:d,onComplete:f,onError:y}),n.worker.postMessage({type:"generate_stream",id:P,requestBody:e})}else n.pipeline?(async()=>{try{let{TextStreamer:P}=await import("@huggingface/transformers"),T=n.pipeline.tokenizer;if(!T)throw new Error("Streaming requires a tokenizer on the pipeline.");let g=(e.messages||[]).map(C=>({...C,content:fe(C.content)})),w={max_new_tokens:e.max_tokens??e.max_completion_tokens??256,temperature:e.temperature??.7,top_p:e.top_p??1,do_sample:(e.temperature??.7)>0,return_full_text:!1,streamer:new P(T,{skip_prompt:!0,skip_special_tokens:!0,callback_function:C=>{C&&d(C)}})};await n.pipeline(g,w),f()}catch(P){y(P)}})():y(new Error("Transformers.js backend not initialized"))}),h=new Promise((f,y)=>{m=setTimeout(()=>y(new Error(`Generation timed out after ${i}ms`)),i)});await Promise.race([p,h]),l("stop")}catch(p){console.error("[DVAI/Transformers] Stream error:",p.message),s.enqueue(c.encode(`data: ${JSON.stringify({error:p.message})}
|
|
6
|
+
|
|
7
|
+
`))}finally{m&&clearTimeout(m),s.enqueue(c.encode(`data: [DONE]
|
|
8
|
+
|
|
9
|
+
`)),s.close()}}})}async embedding(e){if(this.pipelineTask!=="feature-extraction")throw new Error(`embedding() requires pipelineTask="feature-extraction". Current task: "${this.pipelineTask}".`);let r=Array.isArray(e)?e:[e];if(this.usingWorker&&this.worker)return await this.withTimeout(this.sendWorkerRequest("embed",{inputs:r,pooling:"mean",normalize:!0}),this.generationTimeout);if(!this.pipeline)throw new Error("Transformers.js pipeline not initialized");let n=await this.withTimeout(this.pipeline(r,{pooling:"mean",normalize:!0}),this.generationTimeout);return ar(n)}async unload(){if(this.usingWorker&&this.worker){try{await this.sendWorkerRequest("unload")}catch{}this.worker.terminate(),this.worker=null}this.pipeline&&(typeof this.pipeline.dispose=="function"&&await this.pipeline.dispose(),this.pipeline=null),this.pendingRequests.clear(),this.usingWorker=!1}withTimeout(e,r){return new Promise((n,i)=>{let s=setTimeout(()=>i(new Error(`Generation timed out after ${r}ms`)),r);e.then(o=>{clearTimeout(s),n(o)}).catch(o=>{clearTimeout(s),i(o)})})}generateRequestId(){return`${Date.now()}-${Math.random().toString(36).substring(2,9)}`}}});function be(t){return{id:(t.id||"").replace("chatcmpl-","cmpl-")||`cmpl-${Date.now()}`,object:"text_completion",created:t.created??Math.floor(Date.now()/1e3),model:t.model,choices:(t.choices||[]).map(e=>({text:e.message?.content??"",index:e.index??0,finish_reason:e.finish_reason??"stop",logprobs:null})),usage:t.usage??{prompt_tokens:0,completion_tokens:0,total_tokens:0}}}function we(t,e){let r=new TextDecoder,n=new TextEncoder,i="";return new ReadableStream({async start(s){let o=t.getReader();try{for(;;){let{done:a,value:c}=await o.read();if(a)break;i+=r.decode(c,{stream:!0});let d;for(;(d=i.indexOf(`
|
|
10
|
+
|
|
11
|
+
`))!==-1;){let l=i.slice(0,d);i=i.slice(d+2);let m=l.split(`
|
|
12
|
+
`).find(h=>h.startsWith("data:"));if(!m)continue;let p=m.slice(5).trim();if(p==="[DONE]"){s.enqueue(n.encode(`data: [DONE]
|
|
13
|
+
|
|
14
|
+
`));continue}try{let h=JSON.parse(p),f={id:(h.id||"").replace("chatcmpl-","cmpl-"),object:"text_completion.chunk",created:h.created,model:h.model||e,choices:(h.choices||[]).map(y=>({text:y.delta?.content??"",index:y.index??0,finish_reason:y.finish_reason??null,logprobs:null}))};s.enqueue(n.encode(`data: ${JSON.stringify(f)}
|
|
15
|
+
|
|
16
|
+
`))}catch{s.enqueue(n.encode(`data: ${p}
|
|
17
|
+
|
|
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}
|
|
20
|
+
${e.toUpperCase()}
|
|
21
|
+
${r}
|
|
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(`
|
|
23
|
+
`);else if(typeof e=="string")r=e.split(`
|
|
24
|
+
`);else return;let n={};for(let s of r){let o=s.indexOf("=");o<0||(n[s.slice(0,o)]=s.slice(o+1))}if(!n.deviceId||!n.dvaiVersion)return;let i={};try{i=JSON.parse(n.capability??"{}")}catch{}return{dvaiVersion:n.dvaiVersion,deviceId:n.deviceId,deviceName:n.deviceName??n.deviceId,models:n.models?n.models.split(",").filter(Boolean):[],capability:i,port:Number.parseInt(n.port??"0",10),secure:n.secure==="1"}}gc(){let e=this.opts.peerTtlMs??9e4,r=Date.now()-e;for(let[n,i]of this.peerMap)i.lastSeenAt<r&&(this.peerMap.delete(n),this.emit({type:"peer-down",deviceId:n}))}emit(e){for(let r of this.listeners)try{r(e)}catch(n){console.error("[DVAI/discovery] listener threw:",n)}}}});var Et={};v(Et,{BrowserMdnsDiscovery:()=>z});var z,He=u(()=>{"use strict";z=class{constructor(e={}){}async start(){}async stop(){}peers(){return[]}subscribe(e){return()=>{}}}});async function Mt(t){if(typeof globalThis.process<"u"&&globalThis.process.versions?.node){let{NodeMdnsDiscovery:r}=await Promise.resolve().then(()=>(St(),At));return new r(t)}let{BrowserMdnsDiscovery:e}=await Promise.resolve().then(()=>(He(),Et));return new e}var ue,Rt=u(()=>{"use strict";ue=class{constructor(e){this.sources=e}sources;listeners=new Set;subscriptions=[];started=!1;async start(){if(!this.started){this.started=!0;for(let e of this.sources){let r=e.subscribe(n=>this.onEvent(n));this.subscriptions.push(r),await e.start()}}}async stop(){if(this.started){this.started=!1;for(let e of this.subscriptions)e();this.subscriptions.length=0;for(let e of this.sources)await e.stop()}}peers(){let e=new Map;for(let r of this.sources)for(let n of r.peers()){let i=e.get(n.deviceId);(!i||n.lastSeenAt>i.lastSeenAt)&&e.set(n.deviceId,n)}return Array.from(e.values())}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}onEvent(e){for(let r of this.listeners)try{r(e)}catch(n){console.error("[DVAI/discovery] listener threw:",n)}}}});var _t={};v(_t,{BrowserMdnsDiscovery:()=>z,CompositeDiscovery:()=>ue,MDNS_SERVICE_TYPE:()=>I,StaticDiscovery:()=>pe,createMdnsDiscovery:()=>Mt});var Ot=u(()=>{"use strict";Ue();xt();Rt();He()});function Or(){if(typeof globalThis.process<"u"){let t=globalThis.process.env,e=t.HOME??t.USERPROFILE??".";return t.LOCALAPPDATA?`${t.LOCALAPPDATA}/dvai-bridge/pairings.json`:t.XDG_CACHE_HOME?`${t.XDG_CACHE_HOME}/dvai-bridge/pairings.json`:`${e}/.cache/dvai-bridge/pairings.json`}return"./.dvai-bridge-pairings.json"}function Lt(){return typeof indexedDB<"u"?new q:typeof globalThis.process<"u"&&globalThis.process.versions?.node?new K:new F}var F,_r,b,q,K,Vt=u(()=>{"use strict";F=class{map=new Map;async get(e){return this.map.get(e)}async set(e){this.map.set(e.peerDeviceId,e)}async list(){return Array.from(this.map.values())}async remove(e){this.map.delete(e)}async clear(){this.map.clear()}},_r="dvai-bridge",b="pairings-v1",q=class{dbPromise;openDb(){return this.dbPromise||(this.dbPromise=new Promise((e,r)=>{let n=indexedDB.open(_r,1);n.onupgradeneeded=()=>{let i=n.result;i.objectStoreNames.contains(b)||i.createObjectStore(b,{keyPath:"peerDeviceId"})},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 s=r.transaction(b,"readonly").objectStore(b).get(e);s.onsuccess=()=>n(s.result),s.onerror=()=>i(s.error)})}async set(e){let r=await this.openDb();await new Promise((n,i)=>{let s=r.transaction(b,"readwrite");s.objectStore(b).put(e),s.oncomplete=()=>n(),s.onerror=()=>i(s.error)})}async list(){let e=await this.openDb();return await new Promise((r,n)=>{let i=e.transaction(b,"readonly").objectStore(b).getAll();i.onsuccess=()=>r(i.result),i.onerror=()=>n(i.error)})}async remove(e){let r=await this.openDb();await new Promise((n,i)=>{let s=r.transaction(b,"readwrite");s.objectStore(b).delete(e),s.oncomplete=()=>n(),s.onerror=()=>i(s.error)})}async clear(){let e=await this.openDb();await new Promise((r,n)=>{let i=e.transaction(b,"readwrite");i.objectStore(b).clear(),i.oncomplete=()=>r(),i.onerror=()=>n(i.error)})}},K=class{cachePath;cache;constructor(e){this.cachePath=e??Or()}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={}}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())[e]}async set(e){let r=await this.load();r[e.peerDeviceId]=e,await this.save()}async list(){let e=await this.load();return Object.values(e)}async remove(e){let r=await this.load();delete r[e],await this.save()}async clear(){this.cache={},await this.save()}}});var me,Nt=u(()=>{"use strict";Y();me=class{constructor(e){this.opts=e}opts;async getActive(e){let r=await this.opts.store.get(e);if(!r)return;let n=(this.opts.expireAfterDays??30)*24*60*60*1e3;if(Date.now()-r.lastUsedAt>n){await this.opts.store.remove(e);return}return r}async approveOrFetch(e){let r=await this.getActive(e.peerDeviceId);if(r)return r.lastUsedAt=Date.now(),await this.opts.store.set(r),r;let n=this.opts.onPairingRequest,i=n?await n(e.peerDeviceId,e.peerDeviceName,e.appId):!1;if(!(typeof i=="boolean"?i:i.approved))throw new Error(`[DVAI/pairing] denied: peer ${e.peerDeviceId} (${e.peerDeviceName})${n?"":" (no onPairingRequest callback supplied)"}`);let o=typeof i=="object"&&"pairingKey"in i?i.pairingKey:void 0,a={peerDeviceId:e.peerDeviceId,peerDeviceName:e.peerDeviceName,pairingKey:o??O(),pairedAt:Date.now(),lastUsedAt:Date.now(),via:e.via};return await this.opts.store.set(a),a}async touch(e){let r=await this.opts.store.get(e);r&&(r.lastUsedAt=Date.now(),await this.opts.store.set(r))}async revoke(e){await this.opts.store.remove(e)}}});var Ut={};v(Ut,{InMemoryPairingStore:()=>F,IndexedDBPairingStore:()=>q,NodeFsPairingStore:()=>K,PairingPolicy:()=>me,composeSignedMessage:()=>Ie,createPairingStore:()=>Lt,generateNonce:()=>Pe,generatePairingKey:()=>O,signHmac:()=>X,verifyHmac:()=>Ce});var jt=u(()=>{"use strict";Y();Vt();Nt()});var Kt={};v(Kt,{buildDvaiRoutes:()=>Lr,handleCapability:()=>Bt,handleHandshake:()=>zt,handleHealth:()=>Ht,handlePairQr:()=>Ft,handlePairScan:()=>qt,handlePeers:()=>$t,handleProbe:()=>Wt});function Ht(t){return async()=>({status:200,body:{status:"ok",version:t.libraryVersion,uptimeSec:Math.floor((Date.now()-t.startedAt)/1e3),currentModelId:t.currentModelId??null}})}function Bt(t){return async()=>({status:200,body:{scores:await t.capabilityCache.list()}})}function $t(t){return async()=>({status:200,body:{peers:t.discovery?.peers()??[]}})}function Wt(t){return async e=>{if(!t.backend)return{status:503,body:{error:{type:"no_backend",message:"no backend currently loaded"}}};let n=(e.body??{}).modelId??t.currentModelId;return n?{status:200,body:{score:await Ne({cache:t.capabilityCache,backend:t.backend,modelId:n,libraryVersion:t.libraryVersion})}}:{status:400,body:{error:{type:"missing_model_id",message:"supply `modelId` in request body or call after a model is loaded"}}}}}function zt(t){return async e=>{if(!t.pairingPolicy)return{status:503,body:{error:{type:"pairing_disabled",message:"pairing not configured"}}};let r=e.body;if(!r?.peerDeviceId||!r?.peerDeviceName)return{status:400,body:{error:{type:"malformed_handshake",message:"missing peerDeviceId / peerDeviceName"}}};try{let n=await t.pairingPolicy.approveOrFetch({peerDeviceId:r.peerDeviceId,peerDeviceName:r.peerDeviceName,via:r.via??"lan-handshake",...r.appId!==void 0?{appId:r.appId}:{}});return{status:200,body:{paired:!0,pairedAt:n.pairedAt,via:n.via,pairingKey:n.pairingKey,peerDeviceId:n.peerDeviceId}}}catch(n){return{status:403,body:{error:{type:"pairing_denied",message:String(n)}}}}}}function Ft(t){return async()=>({status:501,body:{error:{type:"not_implemented_yet",message:"POST /v1/dvai/pair-qr requires per-SDK integration (Task 8); the rendezvous client surface (rendezvous/client.ts) is callable directly until then."}}})}function qt(t){return async()=>({status:501,body:{error:{type:"not_implemented_yet",message:"POST /v1/dvai/pair-scan requires per-SDK integration (Task 8)."}}})}function Lr(t){return{"GET /v1/dvai/health":Ht(t),"GET /v1/dvai/capability":Bt(t),"GET /v1/dvai/peers":$t(t),"POST /v1/dvai/probe":Wt(t),"POST /v1/dvai/handshake":zt(t),"POST /v1/dvai/pair-qr":Ft(t),"POST /v1/dvai/pair-scan":qt(t)}}var Jt=u(()=>{"use strict";W()});var Gt={};v(Gt,{NodeLlamaCppBackend:()=>Be});var Be,Xt=u(()=>{"use strict";Be=class{modelPath;gpuLayers;threads;contextSize;generationTimeout;modelId;llama=null;model=null;context=null;session=null;lastFatalError=null;constructor(e){if(!e.modelPath)throw new Error("[DVAI/NodeLlamaCpp] modelPath is required (path to a GGUF file).");this.modelPath=e.modelPath,this.gpuLayers=e.gpuLayers??99,this.threads=e.threads,this.contextSize=e.contextSize??2048,this.generationTimeout=e.generationTimeout??6e4,this.modelId=e.modelId||this.modelPath.split(/[\\/]/).pop()?.replace(/\.gguf$/i,"")||"node-llama-cpp"}clearFatalError(){this.lastFatalError=null}async initialize(e){let r;try{r=await import("node-llama-cpp")}catch{throw new Error(`[DVAI/NodeLlamaCpp] backend selected but "node-llama-cpp" is not installed.
|
|
25
|
+
Install it with: npm install node-llama-cpp`)}e?.({text:"Loading llama.cpp runtime...",progress:0}),this.llama=await r.getLlama(),e?.({text:`Loading model: ${this.modelId}`,progress:.1}),this.model=await this.llama.loadModel({modelPath:this.modelPath,gpuLayers:this.gpuLayers}),e?.({text:"Creating context...",progress:.9}),this.context=await this.model.createContext({contextSize:this.contextSize,threads:this.threads}),this.session=new r.LlamaChatSession({contextSequence:this.context.getSequence()}),e?.({text:"Ready",progress:1}),console.log(`[DVAI/NodeLlamaCpp] Loaded "${this.modelId}" (gpuLayers=${this.gpuLayers}, contextSize=${this.contextSize})`)}isWorkerBased(){return!1}getModelId(){return this.modelId}withTimeout(e,r){return new Promise((n,i)=>{let s=setTimeout(()=>i(new Error(`Generation timed out after ${r}ms`)),r);e.then(o=>{clearTimeout(s),n(o)},o=>{clearTimeout(s),i(o)})})}extractUserPrompt(e){let r=e.find(s=>s.role==="system"),n=[...e].reverse().find(s=>s.role==="user"),i=s=>typeof s=="string"?s:Array.isArray(s)?s.map(i).join(""):s&&typeof s=="object"?s.text||s.content||JSON.stringify(s):String(s||"");return{systemPrompt:r?i(r.content):void 0,userPrompt:n?i(n.content):""}}async chatCompletion(e){if(!this.session)throw new Error("[DVAI/NodeLlamaCpp] Backend not initialized.");let r=e.messages||[],{systemPrompt:n,userPrompt:i}=this.extractUserPrompt(r),s=e.max_tokens??e.max_completion_tokens??256,o=e.temperature??.7,a=e.top_p??1,c={maxTokens:s,temperature:o,topP:a};n&&(c.systemPrompt=n);let d=await this.withTimeout(this.session.prompt(i,c),this.generationTimeout);return{id:`chatcmpl-${Date.now()}`,object:"chat.completion",created:Math.floor(Date.now()/1e3),model:this.modelId,choices:[{index:0,message:{role:"assistant",content:d},finish_reason:"stop"}],usage:{prompt_tokens:0,completion_tokens:0,total_tokens:0}}}createStreamingResponse(e){if(!this.session)throw new Error("[DVAI/NodeLlamaCpp] Backend not initialized.");let r=this.session,n=this.modelId,i=this.generationTimeout,s=e.messages||[],{systemPrompt:o,userPrompt:a}=this.extractUserPrompt(s),c=e.max_tokens??e.max_completion_tokens??256,d=e.temperature??.7,l=e.top_p??1;return new ReadableStream({async start(m){let p=`chatcmpl-${Date.now()}`,h=Math.floor(Date.now()/1e3),f=new TextEncoder,y=g=>{let w={id:p,object:"chat.completion.chunk",created:h,model:n,choices:[{index:0,delta:{content:g},finish_reason:null}]};m.enqueue(f.encode(`data: ${JSON.stringify(w)}
|
|
26
|
+
|
|
27
|
+
`))},P=(g="stop")=>{let w={id:p,object:"chat.completion.chunk",created:h,model:n,choices:[{index:0,delta:{},finish_reason:g}]};m.enqueue(f.encode(`data: ${JSON.stringify(w)}
|
|
28
|
+
|
|
29
|
+
`))},T=null;try{let g={maxTokens:c,temperature:d,topP:l,onTextChunk:w=>{w&&y(w)}};o&&(g.systemPrompt=o),await new Promise((w,C)=>{T=setTimeout(()=>C(new Error(`Generation timed out after ${i}ms`)),i),r.prompt(a,g).then(()=>w(),Zt=>C(Zt))}),P("stop")}catch(g){console.error("[DVAI/NodeLlamaCpp] Stream error:",g?.message??g),m.enqueue(f.encode(`data: ${JSON.stringify({error:g?.message??String(g)})}
|
|
30
|
+
|
|
31
|
+
`))}finally{T&&clearTimeout(T),m.enqueue(f.encode(`data: [DONE]
|
|
32
|
+
|
|
33
|
+
`)),m.close()}}})}async unload(){try{this.session&&typeof this.session.dispose=="function"&&await this.session.dispose()}catch{}try{this.context&&typeof this.context.dispose=="function"&&await this.context.dispose()}catch{}try{this.model&&typeof this.model.dispose=="function"&&await this.model.dispose()}catch{}this.session=null,this.context=null,this.model=null,this.llama=null}}});var Yt={};v(Yt,{WebLLMBackend:()=>$e});var $e,Qt=u(()=>{"use strict";$e=class{engine=null;modelId;generationTimeout;maxBlankChunks;workerUrl;usingWorker=!1;lastFatalError=null;constructor(e){this.modelId=e.modelId,this.generationTimeout=e.generationTimeout,this.maxBlankChunks=e.maxBlankChunks,this.workerUrl=e.workerUrl}clearFatalError(){this.lastFatalError=null}async initialize(e){let r=await import("@mlc-ai/web-llm");if(this.workerUrl&&typeof Worker<"u")try{let n=new Worker(this.workerUrl,{type:"module"});this.engine=new r.WebWorkerMLCEngine(n,{initProgressCallback:e}),await this.engine.reload(this.modelId),this.usingWorker=!0,console.log("[DVAI/WebLLM] Initialized with Web Worker (main thread unblocked)");return}catch(n){console.warn("[DVAI/WebLLM] Worker initialization failed, falling back to main thread:",n)}this.engine=await r.CreateMLCEngine(this.modelId,{initProgressCallback:e}),this.usingWorker=!1,console.log("[DVAI/WebLLM] Initialized on main thread (WebGPU compute is async)")}isWorkerBased(){return this.usingWorker}getEngine(){return this.engine}async chatCompletion(e){if(!this.engine)throw new Error("WebLLM engine not initialized");let r=await this.withTimeout(this.engine.chat.completions.create({...e,stream:!1}),this.generationTimeout),n=r?.choices?.[0]?.message?.content;if(n==null||n===""){console.warn("[DVAI/WebLLM] Warning: Engine returned blank content \u2014 flagging for full restart."),this.lastFatalError="blank_output";try{await this.engine.resetChat()}catch{}throw new Error("WebLLM engine returned blank content. A full engine restart is required.")}return r}createStreamingResponse(e){let r=this.engine;if(!r)throw new Error("WebLLM engine not initialized");let n=this.maxBlankChunks,i=this.generationTimeout,s=this;return new ReadableStream({async start(o){let a=0,c=null;try{let d=await r.chat.completions.create({...e,stream:!0}),l=new Promise((p,h)=>{c=setTimeout(()=>{h(new Error(`Generation timed out after ${i}ms`))},i)}),m=(async()=>{for await(let p of d){let h=p?.choices?.[0]?.delta,f=p?.choices?.[0]?.finish_reason;if(!h?.content&&h?.content!==void 0){if(a++,a>=n){console.warn(`[DVAI/WebLLM] ${n} consecutive blank chunks detected \u2014 flagging for full restart.`),s.lastFatalError="blank_stream";try{r.interruptGenerate()}catch{}try{await r.resetChat()}catch{}o.enqueue(new TextEncoder().encode(`data: ${JSON.stringify({error:"Stream aborted: too many blank chunks. Engine restart required."})}
|
|
34
|
+
|
|
35
|
+
`));break}}else a=0;if(o.enqueue(new TextEncoder().encode(`data: ${JSON.stringify(p)}
|
|
36
|
+
|
|
37
|
+
`)),f==="stop"||f==="length")break}})();await Promise.race([m,l])}catch(d){console.error("[DVAI/WebLLM] Stream error:",d.message),d.message?.includes("timed out")&&(s.lastFatalError="timeout");try{r.interruptGenerate()}catch{}try{await r.resetChat()}catch{}o.enqueue(new TextEncoder().encode(`data: ${JSON.stringify({error:d.message})}
|
|
38
|
+
|
|
39
|
+
`))}finally{c&&clearTimeout(c),o.enqueue(new TextEncoder().encode(`data: [DONE]
|
|
40
|
+
|
|
41
|
+
`)),o.close()}}})}async unload(){this.engine&&(await this.engine.unload(),this.engine=null)}withTimeout(e,r){return new Promise((n,i)=>{let s=setTimeout(()=>i(new Error(`Generation timed out after ${r}ms`)),r);e.then(o=>{clearTimeout(s),n(o)}).catch(o=>{clearTimeout(s),i(o)})})}}});import{importJWK as rr,jwtVerify as nr,errors as he}from"jose";var J={"2026-05":{kty:"EC",crv:"P-256",x:"2Y8TuhnlE4tiVDtliozYTgc1TAqi4_TBTI6FHe1p_Vw",y:"pyxMJHj10HPe2hnpJvMpnZ4AzpYZRfqGEMhpBr1-Oto",alg:"ES256",use:"sig",kid:"2026-05"},"placeholder-do-not-ship":{kty:"EC",crv:"P-256",x:"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",y:"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",alg:"ES256",use:"sig",kid:"placeholder-do-not-ship"}},M="placeholder-do-not-ship";function ze(){if(typeof globalThis<"u"){let t=globalThis;if(t.Capacitor?.isNativePlatform?.())return"capacitor";if(t.process?.versions?.node&&typeof t.window>"u")return"node"}return typeof window<"u"&&typeof document<"u"?"web":"node"}function Fe(){if(typeof window<"u"){let e=window.location?.hostname;if(typeof e=="string"&&e.length>0)return e}return typeof process<"u"&&process.env?.DVAI_AUDIENCE?process.env.DVAI_AUDIENCE:null}function qe(){if(typeof process<"u"&&process.env){if(process.env.DVAI_FORCE_PROD==="1"||process.env.DVAI_FORCE_PROD==="true")return{isDev:!1,reason:"DVAI_FORCE_PROD set"};if(process.env.DVAI_FORCE_DEV==="1"||process.env.DVAI_FORCE_DEV==="true")return{isDev:!0,reason:"DVAI_FORCE_DEV set"};if(process.env.NODE_ENV==="test")return{isDev:!0,reason:"NODE_ENV=test"}}if((typeof globalThis<"u"?globalThis:{}).Capacitor?.DEBUG===!0)return{isDev:!0,reason:"Capacitor.DEBUG=true"};if(typeof window<"u"){let n=window.location?.hostname??"";if(n==="localhost"||n==="127.0.0.1"||n==="::1"||n.endsWith(".local")||n.startsWith("192.168.")||n.startsWith("10.")||n.startsWith("172."))return{isDev:!0,reason:`localhost-class hostname: ${n}`};try{let i=window.localStorage;if(i?.getItem("DVAI_FORCE_PROD")==="true")return{isDev:!1,reason:"localStorage DVAI_FORCE_PROD=true"};if(i?.getItem("DVAI_FORCE_DEV")==="true")return{isDev:!0,reason:"localStorage DVAI_FORCE_DEV=true"}}catch{}}return{isDev:!1,reason:"production-class environment"}}function Ke(t,e){if(t===null)return e.includes("*")?"*":null;let r=t.toLowerCase();for(let n of e){let i=n.toLowerCase();if(i==="*"||i===r)return n;if(i.startsWith("*.")){let s=i.slice(2);if(r===s||r.endsWith("."+s))return n}}return null}var R="dvai-license.jwt";async function Ge(t={}){if(typeof t.token=="string"&&t.token.length>0)return{token:t.token.trim(),source:"config.licenseToken"};if(typeof t.path=="string"&&t.path.length>0){let e=await Je(t.path);return e!==null?{token:e,source:t.path}:null}if(typeof process<"u"&&process.env?.DVAI_LICENSE_PATH){let e=process.env.DVAI_LICENSE_PATH,r=await Je(e);if(r!==null)return{token:r,source:`DVAI_LICENSE_PATH=${e}`}}return typeof process<"u"&&process.env?.DVAI_LICENSE_TOKEN?{token:process.env.DVAI_LICENSE_TOKEN.trim(),source:"DVAI_LICENSE_TOKEN env var"}:await tr()}async function Je(t){return/^https?:\/\//i.test(t)?await Xe(t):await Ye(t)}async function Xe(t){try{let e=await fetch(t,{method:"GET"});if(!e.ok)return null;let r=(await e.text()).trim();return r.length>0?r:null}catch{return null}}async function Ye(t){try{let n=(await(await import("fs/promises")).readFile(t,"utf-8")).trim();return n.length>0?n:null}catch{return null}}async function tr(){if(typeof window<"u"){let t=`/${R}`,e=await Xe(t);return e!==null?{token:e,source:t}:null}if(typeof process<"u"&&typeof process.cwd=="function"){let t=await import("path").catch(()=>null);if(t===null)return null;let e=[t.join(process.cwd(),R),t.join(process.cwd(),"..",R)];for(let r of e){let n=await Ye(r);if(n!==null)return{token:n,source:r}}}return null}function Qe(t){return t.kind==="commercial"||t.kind==="trial"}var D=class t extends Error{constructor(r,n){super(r);this.status=n;Object.setPrototypeOf(this,t.prototype)}status;name="LicenseRequiredError"};var x=class{opts;constructor(e={}){this.opts=e}async validate(){let e=qe();if(e.isDev)return{kind:"free-dev",reason:e.reason};let r=await Ge({...this.opts.token!==void 0?{token:this.opts.token}:{},...this.opts.path!==void 0?{path:this.opts.path}:{}});if(r===null)return{kind:"free-prod",reason:"no license token found; checked config.licenseToken, config.licenseKeyPath, DVAI_LICENSE_PATH env, DVAI_LICENSE_TOKEN env, and platform-default paths"};let n=ze(),i=Fe();return await this.verifyToken(r.token,n,i)}async validateAndAssert(){let e=await this.validate();if(e.kind==="free-prod")throw new D(et(e),e);if(e.kind==="free-expired")throw new D(et(e),e);return e}async verifyToken(e,r,n){let i=this.opts.publicKeys??J,s;try{let d=e.split(".");if(d.length!==3||!d[0])return{kind:"free-prod",reason:"license token is not a well-formed JWT (need 3 segments)"};let l=sr(d[0]);s=JSON.parse(l)}catch(d){return{kind:"free-prod",reason:`license token header is not parseable JSON: ${Ze(d)}`}}if(s.alg!=="ES256")return{kind:"free-prod",reason:`license token uses unsupported alg "${s.alg??"(missing)"}", expected ES256`};if(typeof s.kid!="string"||s.kid.length===0)return{kind:"free-prod",reason:"license token header missing kid; cannot select verification key"};let o=i[s.kid];if(o===void 0)return{kind:"free-prod",reason:`license token kid "${s.kid}" is not in the SDK's public-key registry; either the key was rotated and you're on an old SDK, or the token was signed with a key we don't recognise`};if(s.kid===M&&this.opts.allowPlaceholderKey!==!0)return{kind:"free-prod",reason:`license token signed with the placeholder key (kid "${M}"); replace the placeholder in publicKeys.ts with a real key generated via scripts/license/generate-keypair.mjs before issuing real licenses`};let a;try{let d=await rr(o,"ES256");a=(await nr(e,d,{algorithms:["ES256"],issuer:"DVAI-Bridge"})).payload}catch(d){if(d instanceof he.JWTExpired){let l=d.payload?.exp??0;return{kind:"free-expired",licensee:d.payload?.licensee??"(unknown)",expiredAt:l}}return d instanceof he.JWSSignatureVerificationFailed?{kind:"free-prod",reason:`license token signature did not verify against kid "${s.kid}"; the token may have been tampered with or was signed by a different key`}:d instanceof he.JWTClaimValidationFailed?{kind:"free-prod",reason:`license token claim "${d.claim}" failed: ${d.reason}`}:{kind:"free-prod",reason:`license token verification failed: ${Ze(d)}`}}if(!ir(a))return{kind:"free-prod",reason:"license token payload missing required DVAI fields (tier/platforms/aud/licensee)"};if(!a.platforms.includes(r))return{kind:"free-prod",reason:`license token does not authorise platform "${r}"; the token covers [${a.platforms.join(", ")}]`};let c=Ke(n,a.aud);return c===null?{kind:"free-prod",reason:`license token's audience entries [${a.aud.join(", ")}] do not match the current runtime audience "${n??"(none)"}"`+(n===null?' \u2014 set DVAI_AUDIENCE in your environment, or use a "*" aud entry for any-domain licenses':"")}:{kind:a.tier,licensee:a.licensee,expiresAt:a.exp,platform:r,audienceMatched:c}}};function ir(t){return typeof t.iss=="string"&&typeof t.sub=="string"&&Array.isArray(t.aud)&&t.aud.every(e=>typeof e=="string")&&(t.tier==="commercial"||t.tier==="trial")&&Array.isArray(t.platforms)&&t.platforms.every(e=>typeof e=="string")&&typeof t.licensee=="string"&&typeof t.iat=="number"&&typeof t.exp=="number"}function sr(t){let e=t.length%4===0?"":"=".repeat(4-t.length%4),r=t.replace(/-/g,"+").replace(/_/g,"/")+e;if(typeof atob=="function"){let n=atob(r),i=new Uint8Array(n.length);for(let s=0;s<n.length;s++)i[s]=n.charCodeAt(s);return new TextDecoder().decode(i)}return Buffer.from(r,"base64").toString("utf-8")}function Ze(t){return t instanceof Error?t.message:String(t)}function et(t){let e=`
|
|
42
|
+
DVAI-Bridge Commercial License Required
|
|
43
|
+
=======================================
|
|
44
|
+
`,r=t.kind==="free-expired"?`License for "${t.licensee}" expired at ${new Date(t.expiredAt*1e3).toISOString()}.`:t.kind==="free-prod"?t.reason:"(unknown status)";return e+`
|
|
45
|
+
`+r+`
|
|
46
|
+
`+`
|
|
47
|
+
This SDK is licensed under BSL 1.1 and requires a valid commercial
|
|
48
|
+
or trial license to run in production / release builds.
|
|
49
|
+
|
|
50
|
+
To resolve:
|
|
51
|
+
1. Obtain a license at https://deepvoiceai.com/dvai-bridge/license
|
|
52
|
+
2. Place the file at one of these locations (any will work):
|
|
53
|
+
- <project-root>/dvai-license.jwt (auto-discovered)
|
|
54
|
+
- the path you pass as DVAIConfig.licenseKeyPath
|
|
55
|
+
- the path in $DVAI_LICENSE_PATH
|
|
56
|
+
- inline JWT in DVAIConfig.licenseToken or $DVAI_LICENSE_TOKEN
|
|
57
|
+
3. Re-run.
|
|
58
|
+
|
|
59
|
+
Developing locally? The SDK auto-detects dev mode on:
|
|
60
|
+
- localhost / 127.0.0.1 / *.local hostnames in the browser
|
|
61
|
+
- NODE_ENV=test or NODE_ENV=development in Node
|
|
62
|
+
- DVAI_FORCE_DEV=1 environment variable (explicit override)
|
|
63
|
+
- Capacitor.DEBUG=true on hybrid mobile builds
|
|
64
|
+
Any of these silences this error and lets the SDK run without a
|
|
65
|
+
license.
|
|
66
|
+
`}ve();ke();Y();var We=class{modelId;mockUrl;serviceWorkerUrl;licenseKeyPath;licenseToken;licenseStatus=null;backend;transformersModelId;pipelineTask;device;generationTimeout;maxBlankChunks;maxRetries;webllmWorkerUrl;transformersWorkerUrl;dtype;createPipeline;transformersModelClass;transformersProcessorClass;transformersDisableEncoders;nativeModelPath;nativeGpuLayers;nativeThreads;nativeContextSize;nativeEmbeddingMode;capacitorBackend;nativeMmprojPath;transport;httpBasePort;httpMaxPortAttempts;corsOrigin;httpBindHost;chatCompletionInterceptor;resolvedTransport="none";baseUrl;port;activeTransport=null;validator;backendInstance=null;isReady=!1;recoveryAttempts=0;resolvedBackend="webllm";offload;offloadOnlyMode=!1;capabilityCache;dvaiRoutes;startedAt=Date.now();discovery;pairingPolicy;deviceId;constructor(e={}){this.modelId=e.modelId||"gemma-2-2b-it-q4f16_1-MLC",this.backend=e.backend||"webllm",this.transformersModelId=e.transformersModelId||e.modelId||"onnx-community/gemma-3n-E2B-it-ONNX",this.pipelineTask=e.pipelineTask||"text-generation",this.device=e.device||"auto",this.dtype=e.dtype,this.createPipeline=e.createPipeline,this.transformersModelClass=e.transformersModelClass,this.transformersProcessorClass=e.transformersProcessorClass,this.transformersDisableEncoders=e.transformersDisableEncoders,this.generationTimeout=e.generationTimeout??6e4,this.maxBlankChunks=e.maxBlankChunks??20,this.maxRetries=e.maxRetries??2,this.webllmWorkerUrl=e.webllmWorkerUrl??"/dvai-webllm.worker.js",this.transformersWorkerUrl=e.transformersWorkerUrl??"/dvai-transformers.worker.js",this.mockUrl=e.mockUrl??"https://api.openai.local/v1/chat/completions",this.serviceWorkerUrl=e.serviceWorkerUrl??"/mockServiceWorker.js",this.licenseKeyPath=e.licenseKeyPath,this.licenseToken=e.licenseToken,this.validator=new x({...this.licenseKeyPath!==void 0?{path:this.licenseKeyPath}:{},...this.licenseToken!==void 0?{token:this.licenseToken}:{}}),this.nativeModelPath=e.nativeModelPath||"",this.nativeGpuLayers=e.nativeGpuLayers??99,this.nativeThreads=e.nativeThreads??4,this.nativeContextSize=e.nativeContextSize??2048,this.nativeEmbeddingMode=e.nativeEmbeddingMode??!1,this.capacitorBackend=e.capacitorBackend??"llama",this.nativeMmprojPath=e.nativeMmprojPath,this.transport=e.transport??"auto",this.httpBasePort=e.httpBasePort??38883,this.httpMaxPortAttempts=e.httpMaxPortAttempts??16,this.corsOrigin=e.corsOrigin??"*",this.httpBindHost=e.httpBindHost,this.chatCompletionInterceptor=e.chatCompletionInterceptor,this.backend!=="auto"&&(this.resolvedBackend=this.backend),this.offload=e.offload}getActiveBackend(){return this.resolvedBackend}getActiveTransport(){return this.resolvedTransport}getBaseUrl(){return this.baseUrl}getPort(){return this.port}resolveBackend(){return this.backend==="auto"?(console.log("[DVAI] Auto-detected web environment \u2192 using webllm backend"),"webllm"):this.backend}async initialize(e=console.log){if(this.isReady)return!0;if(this.resolvedBackend=this.resolveBackend(),this.licenseStatus=await this.validator.validateAndAssert(),!(typeof window>"u"&&typeof self<"u"&&typeof self.importScripts=="function")&&this.serviceWorkerUrl)try{(await fetch(this.serviceWorkerUrl,{method:"HEAD"})).ok||console.warn(`[DVAI] Warning: Service Worker not found at "${this.serviceWorkerUrl}". Please run "dvai-bridge init" or "npx msw init <public_dir>" to generate it.`)}catch{console.warn(`[DVAI] Could not verify Service Worker existence at "${this.serviceWorkerUrl}".`)}try{if(this.offload?.enabled){let{assessCapability:a}=await Promise.resolve().then(()=>(Q(),Ae)),c=await a({hardwareMinimum:this.offload.hardwareMinimum,minLocalCapability:this.offload.minLocalCapability});this.offloadOnlyMode=c.mode==="offload-only"||c.mode==="too-weak",e({phase:"precheck",mode:c.mode,tokPerSec:c.tokPerSec,reason:c.reason})}this.offloadOnlyMode?e({phase:"backend",skipped:!0,reason:"offload-only mode (device below minLocalCapability or below hardwareMinimum)"}):await this.initializeBackend(e);let{selectTransport:n,MswTransport:i,HttpTransport:s,CapacitorTransport:o}=await Promise.resolve().then(()=>(ft(),ht));if(this.resolvedTransport=n({transport:this.transport==="auto"?void 0:this.transport,serviceWorkerUrl:this.serviceWorkerUrl}),this.resolvedTransport==="http"&&this.mockUrl!=="https://api.openai.local/v1/chat/completions"&&console.warn('[DVAI] mockUrl config is ignored under transport="http". The HTTP server always serves at /v1/*. Use dvai.baseUrl to get the exact endpoint.'),this.resolvedTransport==="msw"&&this.serviceWorkerUrl===""&&this.transport==="msw"&&console.warn("[DVAI] serviceWorkerUrl is empty but transport='msw' was requested; MSW will fail to register."),this.resolvedTransport==="none"&&typeof window>"u"&&typeof self<"u"&&console.log("[DVAI] Running in a Web Worker \u2014 no transport started. Use dvai.chatCompletion() directly, or register MSW on the main thread."),this.resolvedTransport==="msw"?this.activeTransport=new i({mockUrl:this.mockUrl,serviceWorkerUrl:this.serviceWorkerUrl}):this.resolvedTransport==="http"?this.activeTransport=new s({httpBasePort:this.httpBasePort,httpMaxPortAttempts:this.httpMaxPortAttempts,corsOrigin:this.corsOrigin,...this.httpBindHost!==void 0?{bindHost:this.httpBindHost}:{}}):this.resolvedTransport==="capacitor"?this.activeTransport=new o({capacitorBackend:this.capacitorBackend,nativeModelPath:this.nativeModelPath||void 0,nativeMmprojPath:this.nativeMmprojPath,nativeGpuLayers:this.nativeGpuLayers,nativeContextSize:this.nativeContextSize,nativeThreads:this.nativeThreads,nativeEmbeddingMode:this.nativeEmbeddingMode,httpBasePort:this.httpBasePort,httpMaxPortAttempts:this.httpMaxPortAttempts,corsOrigin:this.corsOrigin}):this.activeTransport=null,this.activeTransport){let a=this.getHandlerContext(e),c=await this.activeTransport.start(a);this.baseUrl=c.baseUrl,this.port=c.port}else this.baseUrl=void 0,this.port=void 0;if(this.isReady=!0,this.recoveryAttempts=0,this.offload?.enabled)try{if(await this.initializeOffload(),this.chatCompletionInterceptor===void 0&&this.offloadOnlyMode){let{buildOffloadInterceptor:a}=await Promise.resolve().then(()=>(kt(),wt)),c=this.offload;this.chatCompletionInterceptor=a({config:c,getPeers:()=>this.discovery?.peers()??[],getLocalCapability:()=>0,offloadOnlyMode:!0})}}catch(a){console.warn("[DVAI/offload] failed to initialize offload state; local inference still works. Cause:",a)}return!0}catch(n){throw console.error("[DVAI] Failed to initialize:",n),n}}async initializeOffload(){let{createCapabilityCache:e,ensureDeviceId:r}=await Promise.resolve().then(()=>(W(),le)),{CompositeDiscovery:n,StaticDiscovery:i,createMdnsDiscovery:s}=await Promise.resolve().then(()=>(Ot(),_t)),{PairingPolicy:o,createPairingStore:a}=await Promise.resolve().then(()=>(jt(),Ut));this.capabilityCache=e(),this.deviceId=await r(this.capabilityCache);let c=[];if(this.offload?.discoverLAN!==!1){let m=typeof globalThis.process<"u"&&globalThis.process.platform==="darwin",p=this.offload?.advertiseLAN&&!m?{deviceId:this.deviceId,deviceName:typeof globalThis.process<"u"&&(globalThis.process.env.DVAI_DEVICE_NAME??"")||"DVAI",dvaiVersion:"3.2.1",port:this.offload.advertisePort??this.port??38883,secure:!1,models:[],capability:{}}:void 0;c.push(await s({selfDeviceId:this.deviceId,...p?{advertise:p}:{}}))}this.offload?.knownPeers&&this.offload.knownPeers.length>0&&c.push(new i(this.offload.knownPeers)),c.length>0&&(this.discovery=new n(c),await this.discovery.start()),this.pairingPolicy=new o({store:a(),onPairingRequest:this.offload?.onPairingRequest?async(m,p,h)=>{let f=this.offload?.onPairingRequest;return f?f({deviceId:m,deviceName:p,dvaiVersion:"unknown",baseUrl:"",loadedModels:[],capability:{},via:"static",secure:!1,lastSeenAt:Date.now(),...h!==void 0?{appId:h}:{}}):!1}:void 0});let{buildDvaiRoutes:d}=await Promise.resolve().then(()=>(Jt(),Kt)),l=this;this.dvaiRoutes=d({libraryVersion:"3.0.0",get currentModelId(){return l.resolvedBackend==="transformers"?l.transformersModelId:l.modelId},capabilityCache:this.capabilityCache,get backend(){let m=l.backendInstance;if(m)return m},discovery:this.discovery,pairingPolicy:this.pairingPolicy,startedAt:this.startedAt})}async shutdownOffload(){if(this.discovery){try{await this.discovery.stop()}catch{}this.discovery=void 0}this.capabilityCache=void 0,this.pairingPolicy=void 0,this.dvaiRoutes=void 0,this.deviceId=void 0}getHandlerContext(e){let r=this;return{get backend(){return r.backendInstance},resolvedBackend:this.resolvedBackend,modelId:this.resolvedBackend==="transformers"?this.transformersModelId:this.modelId,onRecovery:this.resolvedBackend==="webllm"?async()=>{if(this.backendInstance?.lastFatalError&&this.recoveryAttempts<this.maxRetries)await this.attemptRecovery(e);else if(this.recoveryAttempts>=this.maxRetries)throw new Error("Recovery exhausted")}:void 0,get dvaiRoutes(){return r.dvaiRoutes},...this.chatCompletionInterceptor!==void 0?{chatCompletionInterceptor:this.chatCompletionInterceptor}:{}}}async attemptRecovery(e){this.recoveryAttempts++;let r=this.backendInstance?.lastFatalError;if(console.log(`[DVAI] Auto-recovery: unloading engine due to "${r}" (attempt ${this.recoveryAttempts}/${this.maxRetries})`),this.backendInstance){try{await this.backendInstance.unload()}catch(n){console.warn("[DVAI] Error during recovery unload:",n)}this.backendInstance=null}await this.initializeBackend(e),this.backendInstance?.clearFatalError&&this.backendInstance.clearFatalError(),console.log("[DVAI] Auto-recovery: engine reloaded successfully")}async initializeBackend(e){if(this.resolvedBackend==="native"){let r;try{r=(await Promise.resolve().then(()=>(Xt(),Gt))).NodeLlamaCppBackend}catch{throw new Error("[DVAI] native backend selected but the NodeLlamaCppBackend module failed to load.")}if(!this.nativeModelPath)throw new Error('[DVAI] backend: "native" requires `nativeModelPath` (path to a GGUF file).');let n=this.modelId!=="gemma-2-2b-it-q4f16_1-MLC"?this.modelId:void 0,i=new r({modelPath:this.nativeModelPath,gpuLayers:this.nativeGpuLayers,threads:this.nativeThreads,contextSize:this.nativeContextSize,generationTimeout:this.generationTimeout,modelId:n});await i.initialize(e),this.backendInstance=i,this.modelId=i.getModelId(),console.log(`[DVAI] node-llama-cpp backend ready (modelId="${this.modelId}", gpuLayers=${this.nativeGpuLayers}, contextSize=${this.nativeContextSize})`);return}if(this.resolvedBackend==="transformers"){let r;try{r=(await Promise.resolve().then(()=>(ve(),it))).TransformersBackend}catch{throw new Error(`[DVAI] Transformers.js backend selected but "@huggingface/transformers" is not installed.
|
|
67
|
+
Install it with: npm install @huggingface/transformers`)}let n=new r({modelId:this.transformersModelId,device:this.device,generationTimeout:this.generationTimeout,workerUrl:this.transformersWorkerUrl,pipelineTask:this.pipelineTask,dtype:this.dtype,createPipeline:this.createPipeline,modelClass:this.transformersModelClass,processorClass:this.transformersProcessorClass,disableEncoders:this.transformersDisableEncoders});await n.initialize(e),this.backendInstance=n,console.log(`[DVAI] Transformers.js backend ready (task: ${this.pipelineTask}, device: ${n.getResolvedDevice()}, worker: ${n.isWorkerBased()})`)}else{let r;try{r=(await Promise.resolve().then(()=>(Qt(),Yt))).WebLLMBackend}catch{throw new Error(`[DVAI] WebLLM backend selected but "@mlc-ai/web-llm" is not installed.
|
|
68
|
+
Install it with: npm install @mlc-ai/web-llm`)}let n=new r({modelId:this.modelId,generationTimeout:this.generationTimeout,maxBlankChunks:this.maxBlankChunks,workerUrl:this.webllmWorkerUrl});await n.initialize(e),this.backendInstance=n,console.log(`[DVAI] WebLLM backend ready (worker: ${n.isWorkerBased()})`)}}getEngine(){return this.backendInstance?this.resolvedBackend==="webllm"?this.backendInstance.getEngine?.()??null:this.resolvedBackend==="native"?this.backendInstance??null:this.backendInstance.getPipeline?.()??null:null}async chatCompletion(e){if(!this.backendInstance)throw new Error("[DVAI] Backend not initialized. Call initialize() first.");return this.backendInstance.chatCompletion(e)}async embedding(e){if(!this.backendInstance)throw new Error("[DVAI] Backend not initialized. Call initialize() first.");if(this.resolvedBackend==="webllm")throw new Error("[DVAI] Embeddings are not supported on the WebLLM backend. Use backend: 'transformers' with pipelineTask: 'feature-extraction'.");if(this.resolvedBackend==="native")throw new Error("[DVAI] Embeddings are not yet supported on the node-llama-cpp backend. Use backend: 'transformers' with pipelineTask: 'feature-extraction'.");if(typeof this.backendInstance.embedding!="function")throw new Error("[DVAI] The current backend does not expose an embedding() method.");return this.backendInstance.embedding(e)}async runPipeline(e,r){if(!this.backendInstance)throw new Error("[DVAI] Backend not initialized. Call initialize() first.");if(this.resolvedBackend!=="transformers"||!this.backendInstance.runPipeline)throw new Error("[DVAI] runPipeline() is only available with the Transformers.js backend.");return this.backendInstance.runPipeline(e,r)}async unload(){await this.shutdownOffload(),this.backendInstance&&(await this.backendInstance.unload(),this.backendInstance=null),this.activeTransport&&(await this.activeTransport.stop(),this.activeTransport=null),this.baseUrl=void 0,this.port=void 0,this.isReady=!1,this.recoveryAttempts=0,console.log("[DVAI] Unloaded model and transport.")}async assessHardware(e={}){let{assessCapability:r}=await Promise.resolve().then(()=>(Q(),Ae)),n=await r({hardwareMinimum:e.hardwareMinimum,minLocalCapability:e.minLocalCapability});return{mode:n.mode,tokPerSec:n.tokPerSec,reason:n.reason,hints:n.hints}}async probeCapability(){if(!this.capabilityCache||!this.backendInstance)return;let{probeAndCache:e}=await Promise.resolve().then(()=>(W(),le)),r=this.resolvedBackend==="transformers"?this.transformersModelId:this.modelId;return e({cache:this.capabilityCache,backend:this.backendInstance,modelId:r,libraryVersion:"3.0.0"})}async getCapability(e){if(!this.capabilityCache)return;let{getCapability:r}=await Promise.resolve().then(()=>(W(),le)),n=e??(this.resolvedBackend==="transformers"?this.transformersModelId:this.modelId);return r({cache:this.capabilityCache,modelId:n,libraryVersion:"3.0.0"})}getPeers(){return this.discovery?.peers()??[]}},yi=new We;export{R as DEFAULT_LICENSE_FILENAME,We as DVAI,J as DVAI_PUBLIC_KEYS,D as LicenseRequiredError,x as LicenseValidator,M as PLACEHOLDER_KID,be as chatToLegacyCompletion,Ie as composeSignedMessage,ge as detectWebGPU,yi as dvai,Pe as generateNonce,O as generatePairingKey,Qe as isPaidTier,we as legacyCompletionStreamAdapter,X as signHmac,Ce as verifyHmac};
|
|
69
|
+
//# sourceMappingURL=index.js.map
|