duckdb-terminal 0.1.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/README.md +505 -0
- package/dist/duckdb-terminal.js +3407 -0
- package/dist/duckdb-terminal.umd.cjs +29 -0
- package/dist/lib.d.ts +2194 -0
- package/package.json +58 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
(function(l,g){typeof exports=="object"&&typeof module<"u"?g(exports,require("ghostty-web"),require("@duckdb/duckdb-wasm")):typeof define=="function"&&define.amd?define(["exports","ghostty-web","@duckdb/duckdb-wasm"],g):(l=typeof globalThis<"u"?globalThis:l||self,g(l.DuckDBTerminal={},l.GhosttyWeb,l.duckdb))})(this,(function(l,g,A){"use strict";var Ce=Object.defineProperty;var Ie=(l,g,A)=>g in l?Ce(l,g,{enumerable:!0,configurable:!0,writable:!0,value:A}):l[g]=A;var a=(l,g,A)=>Ie(l,typeof g!="symbol"?g+"":g,A);function Tt(i){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(i){for(const e in i)if(e!=="default"){const s=Object.getOwnPropertyDescriptor(i,e);Object.defineProperty(t,e,s.get?s:{enumerable:!0,get:()=>i[e]})}}return t.default=i,Object.freeze(t)}const I=Tt(A),Et="https://cdn.jsdelivr.net/npm/ghostty-web",yt=()=>`${Et}@0.3.0/dist/ghostty-vt.wasm`;class j{constructor(){a(this,"terminal");a(this,"fitAddon");a(this,"ghostty");a(this,"dataHandler");a(this,"resizeHandler");a(this,"currentTheme",null);a(this,"initialized",!1);a(this,"container",null);a(this,"options",{});a(this,"resizeObserver",null);a(this,"mobileInput",null);a(this,"handleResize",()=>{this.fit()})}async init(t,e={}){this.initialized||(this.container=t,this.options=e,this.currentTheme=e.theme??null,this.ghostty=await g.Ghostty.load(yt()),this.createTerminal(),this.initialized=!0,this.focus())}createTerminal(){this.container&&(this.terminal=new g.Terminal({ghostty:this.ghostty,cursorBlink:!0,fontSize:this.options.fontSize??14,fontFamily:this.options.fontFamily??'"Fira Code", "Cascadia Code", "JetBrains Mono", Consolas, monospace',theme:this.currentTheme?this.themeToGhostty(this.currentTheme):void 0,scrollback:this.options.scrollback??10*1024*1024}),this.fitAddon=new g.FitAddon,this.terminal.loadAddon(this.fitAddon),this.container.innerHTML="",this.terminal.open(this.container),this.fit(),window.addEventListener("resize",this.handleResize),typeof ResizeObserver<"u"&&(this.resizeObserver?.disconnect(),this.resizeObserver=new ResizeObserver(()=>{this.fit()}),this.resizeObserver.observe(this.container)),this.terminal.onData(t=>{this.dataHandler?.(t)}),this.terminal.onResize(({cols:t,rows:e})=>{this.resizeHandler?.(t,e)}),this.setupMobileInput())}setupMobileInput(){this.container&&this.isTouchDevice()&&(this.setupTouchScrolling(),this.setupMobileKeyboard())}setupMobileKeyboard(){this.mobileInput?.remove();const t=document.createElement("textarea");t.className="mobile-keyboard-input",t.setAttribute("autocapitalize","off"),t.setAttribute("autocomplete","off"),t.setAttribute("autocorrect","off"),t.setAttribute("spellcheck","false"),t.setAttribute("enterkeyhint","send"),t.setAttribute("aria-label","Terminal input"),t.style.cssText=`
|
|
2
|
+
position: fixed;
|
|
3
|
+
bottom: 0;
|
|
4
|
+
left: 50%;
|
|
5
|
+
transform: translateX(-50%);
|
|
6
|
+
width: 1px;
|
|
7
|
+
height: 1px;
|
|
8
|
+
opacity: 0;
|
|
9
|
+
font-size: 16px;
|
|
10
|
+
border: none;
|
|
11
|
+
outline: none;
|
|
12
|
+
resize: none;
|
|
13
|
+
background: transparent;
|
|
14
|
+
color: transparent;
|
|
15
|
+
z-index: -1;
|
|
16
|
+
`,t.addEventListener("input",()=>{const e=t.value;e&&this.dataHandler&&this.dataHandler(e),t.value=""}),t.addEventListener("keydown",e=>{e.key.length===1&&!e.ctrlKey&&!e.altKey&&!e.metaKey||(e.key==="Enter"?(e.preventDefault(),this.dataHandler?.("\r"),t.value="",t.blur()):e.key==="Backspace"?(e.preventDefault(),this.dataHandler?.("")):e.key==="Tab"?(e.preventDefault(),this.dataHandler?.(" ")):e.key==="ArrowUp"?(e.preventDefault(),this.dataHandler?.("\x1B[A")):e.key==="ArrowDown"?(e.preventDefault(),this.dataHandler?.("\x1B[B")):e.key==="ArrowLeft"?(e.preventDefault(),this.dataHandler?.("\x1B[D")):e.key==="ArrowRight"&&(e.preventDefault(),this.dataHandler?.("\x1B[C")))}),document.body.appendChild(t),this.mobileInput=t}setupTouchScrolling(){if(!this.container)return;let t=0,e=0,s=!1;const r=h=>{h.touches.length===1&&(t=h.touches[0].clientY,e=t,s=!1)},n=h=>{if(h.touches.length!==1)return;const c=h.touches[0].clientY,f=e-c;if(!s&&Math.abs(c-t)>10&&(s=!0),s){h.preventDefault();const m=Math.round(f/20);m!==0&&this.terminal&&this.terminal.scrollLines?.(m),e=c}},o=()=>{s=!1};this.container.addEventListener("touchstart",r,{passive:!0}),this.container.addEventListener("touchmove",n,{passive:!1}),this.container.addEventListener("touchend",o,{passive:!0})}themeToGhostty(t){return{background:t.colors.background,foreground:t.colors.foreground,cursor:t.colors.cursor,black:t.colors.black,red:t.colors.red,green:t.colors.green,yellow:t.colors.yellow,blue:t.colors.blue,magenta:t.colors.magenta,cyan:t.colors.cyan,white:t.colors.white,brightBlack:t.colors.brightBlack,brightRed:t.colors.brightRed,brightGreen:t.colors.brightGreen,brightYellow:t.colors.brightYellow,brightBlue:t.colors.brightBlue,brightMagenta:t.colors.brightMagenta,brightCyan:t.colors.brightCyan,brightWhite:t.colors.brightWhite}}fit(){this.fitAddon&&this.fitAddon.fit()}write(t){this.terminal?.write(t)}writeln(t){this.terminal?.writeln(t)}clear(){this.terminal?.write("\x1B[2J\x1B[H")}focus(){this.mobileInput&&this.isTouchDevice()?this.mobileInput.focus():this.terminal?.focus()}isTouchDevice(){return"ontouchstart"in window||navigator.maxTouchPoints>0}onData(t){this.dataHandler=t}onResize(t){this.resizeHandler=t}get cols(){return this.terminal?.cols??80}get rows(){return this.terminal?.rows??24}setTheme(t){this.currentTheme=t,!(!this.initialized||!this.container)&&(window.removeEventListener("resize",this.handleResize),this.terminal?.dispose(),this.createTerminal(),this.focus())}getTheme(){return this.currentTheme}dispose(){window.removeEventListener("resize",this.handleResize),this.resizeObserver?.disconnect(),this.resizeObserver=null,this.mobileInput?.remove(),this.mobileInput=null,this.terminal?.dispose(),this.initialized=!1,this.container=null}}class Y{constructor(t={}){a(this,"db",null);a(this,"conn",null);a(this,"worker",null);a(this,"initialized",!1);a(this,"options");this.options={storage:"memory",databasePath:":memory:",...t}}async init(){if(this.initialized)return;const t=I.getJsDelivrBundles(),e=await I.selectBundle(t),s=URL.createObjectURL(new Blob([`importScripts("${e.mainWorker}");`],{type:"text/javascript"}));this.worker=new Worker(s);const r=new I.ConsoleLogger;this.db=new I.AsyncDuckDB(r,this.worker),await this.db.instantiate(e.mainModule,e.pthreadWorker),URL.revokeObjectURL(s);const n={castDecimalToDouble:!0};this.options.storage==="opfs"&&this.options.databasePath?await this.db.open({path:this.options.databasePath,accessMode:I.DuckDBAccessMode.READ_WRITE,query:n}):await this.db.open({path:":memory:",query:n}),this.conn=await this.db.connect(),this.initialized=!0}async executeQuery(t){if(!this.conn)throw new Error("Database not initialized");const e=performance.now(),s=await this.conn.query(t),r=performance.now()-e,n=s.schema.fields.map(c=>c.name),o=[];for(let c=0;c<s.numRows;c++){const f=[];for(let m=0;m<n.length;m++){const p=s.getChildAt(m);f.push(p?.get(c))}o.push(f)}const h=typeof s.numRows=="bigint"?Number(s.numRows):s.numRows;return{columns:n,rows:o,rowCount:h,duration:r}}async getCompletions(t,e){if(!this.db)return[];try{const r=t.substring(0,e).match(/[\w.]*$/),n=r?r[0].toLowerCase():"";if(!n)return[];const o=[],h=["SELECT","FROM","WHERE","AND","OR","NOT","INSERT","INTO","VALUES","UPDATE","SET","DELETE","CREATE","TABLE","DROP","ALTER","INDEX","VIEW","JOIN","LEFT","RIGHT","INNER","OUTER","ON","GROUP","BY","ORDER","HAVING","LIMIT","OFFSET","UNION","EXCEPT","INTERSECT","AS","DISTINCT","ALL","NULL","TRUE","FALSE","CASE","WHEN","THEN","ELSE","END","IS","IN","BETWEEN","LIKE","EXISTS","COUNT","SUM","AVG","MIN","MAX","CAST","COALESCE","NULLIF"];for(const f of h)f.toLowerCase().startsWith(n)&&o.push({value:f,type:"keyword"});try{const f=await this.executeQuery("SELECT table_name FROM information_schema.tables WHERE table_schema = 'main'");for(const m of f.rows){const p=String(m[0]);p.toLowerCase().startsWith(n)&&o.push({value:p,type:"table"})}}catch{}const c=["abs","ceil","floor","round","sqrt","log","exp","power","length","lower","upper","trim","ltrim","rtrim","replace","substring","concat","now","current_date","current_time","current_timestamp","date_part","date_trunc","extract","array_agg","string_agg","list_agg","first","last","any_value"];for(const f of c)f.toLowerCase().startsWith(n)&&o.push({value:f,type:"function"});return o.sort((f,m)=>{const p=f.value.toLowerCase()===n,z=m.value.toLowerCase()===n;return p&&!z?-1:!p&&z?1:f.value.localeCompare(m.value)}),o.slice(0,20)}catch{return[]}}async getTables(){if(!this.conn)return[];try{return(await this.executeQuery("SELECT table_name FROM information_schema.tables WHERE table_schema = 'main' ORDER BY table_name")).rows.map(e=>String(e[0]))}catch{return[]}}async getTableSchema(t){if(!this.conn)return[];try{const e=t.replace(/'/g,"''");return(await this.executeQuery(`SELECT column_name, data_type FROM information_schema.columns WHERE table_name = '${e}' ORDER BY ordinal_position`)).rows.map(r=>({name:String(r[0]),type:String(r[1])}))}catch{return[]}}async registerFile(t,e){if(!this.db)throw new Error("Database not initialized");await this.db.registerFileBuffer(t,e)}async dropFile(t){if(!this.db)throw new Error("Database not initialized");await this.db.dropFile(t)}isReady(){return this.initialized&&this.conn!==null}async close(){this.conn&&(await this.conn.close(),this.conn=null),this.db&&(await this.db.terminate(),this.db=null),this.worker&&(this.worker.terminate(),this.worker=null),this.initialized=!1}}const P="\x1B[0m",V="\x1B[1m",K="\x1B[2m",St="\x1B[30m",w="\x1B[31m",b="\x1B[32m",N="\x1B[33m",O="\x1B[34m",X="\x1B[35m",R="\x1B[36m",$="\x1B[37m",T="\x1B[90m",Lt="\x1B[91m",Rt="\x1B[92m",At="\x1B[93m",Ct="\x1B[94m",It="\x1B[95m",Pt="\x1B[96m",Nt="\x1B[97m",vt="\x1B[C",J="\x1B[D",v="\x1B[K";function Bt(i){return`\x1B[${i}C`}function y(i){return`\x1B[${i}D`}const kt={black:St,red:w,green:b,yellow:N,blue:O,magenta:X,cyan:R,white:$,brightBlack:T,brightRed:Lt,brightGreen:Rt,brightYellow:At,brightBlue:Ct,brightMagenta:It,brightCyan:Pt,brightWhite:Nt};function u(i,t){return`${kt[t]||t}${i}${P}`}function S(i){return`${V}${i}${P}`}function d(i){return`${K}${i}${P}`}const Ot=64*1024;class Z{constructor(){a(this,"buffer","");a(this,"cursorPos",0);a(this,"maxSize",Ot)}setPromptLength(t){}setMaxSize(t){this.maxSize=t}getMaxSize(){return this.maxSize}getContent(){return this.buffer}getCursorPos(){return this.cursorPos}clear(){this.buffer="",this.cursorPos=0}setContent(t){t.length>this.maxSize&&(t=t.substring(0,this.maxSize)),this.buffer=t,this.cursorPos=t.length}insert(t){if(this.buffer.length+t.length>this.maxSize){const r=this.maxSize-this.buffer.length;if(r<=0)return"";t=t.substring(0,r)}const e=this.buffer.substring(0,this.cursorPos),s=this.buffer.substring(this.cursorPos);return this.buffer=e+t+s,this.cursorPos+=t.length,s.length===0?t:t+s+y(s.length)}backspace(){if(this.cursorPos===0)return"";const t=this.buffer.substring(0,this.cursorPos-1),e=this.buffer.substring(this.cursorPos);return this.buffer=t+e,this.cursorPos--,e.length===0?"\b \b":J+e+" "+y(e.length+1)}delete(){if(this.cursorPos>=this.buffer.length)return"";const t=this.buffer.substring(0,this.cursorPos),e=this.buffer.substring(this.cursorPos+1);return this.buffer=t+e,e+" "+y(e.length+1)}moveLeft(){return this.cursorPos>0?(this.cursorPos--,J):""}moveRight(){return this.cursorPos<this.buffer.length?(this.cursorPos++,vt):""}moveToStart(){if(this.cursorPos===0)return"";const t=this.cursorPos;return this.cursorPos=0,y(t)}moveToEnd(){if(this.cursorPos===this.buffer.length)return"";const t=this.buffer.length-this.cursorPos;return this.cursorPos=this.buffer.length,Bt(t)}clearToEnd(){return this.buffer=this.buffer.substring(0,this.cursorPos),v}clearLine(){const t=this.moveToStart()+v;return this.buffer="",this.cursorPos=0,t}getWordBeforeCursor(){const e=this.buffer.substring(0,this.cursorPos).match(/[\w.]*$/);return e?e[0]:""}replaceWordBeforeCursor(t){const e=this.getWordBeforeCursor(),s=this.cursorPos-e.length,r=this.buffer.substring(0,s),n=this.buffer.substring(this.cursorPos);this.buffer=r+t+n,this.cursorPos=s+t.length;let o="";return e.length>0&&(o+=y(e.length)),o+=v,o+=t+n,n.length>0&&(o+=y(n.length)),o}isEmpty(){return this.buffer.length===0}isBlank(){return this.buffer.trim().length===0}}const $t="duckdb-terminal",E="history",B=1e3;class q{constructor(){a(this,"db",null);a(this,"history",[]);a(this,"cursor",-1);a(this,"currentInput","");a(this,"initialized",!1)}async init(){if(!this.initialized)try{this.db=await this.openDatabase(),this.history=await this.loadHistory(),this.history.length>B&&(this.history=this.history.slice(-B),this.db&&await this.trimHistory()),this.cursor=this.history.length,this.initialized=!0}catch(t){console.warn("IndexedDB not available, using in-memory history:",t),this.initialized=!0}}openDatabase(){return new Promise((t,e)=>{const s=indexedDB.open($t,1);s.onerror=()=>e(s.error),s.onsuccess=()=>t(s.result),s.onupgradeneeded=r=>{const n=r.target.result;n.objectStoreNames.contains(E)||n.createObjectStore(E,{keyPath:"id",autoIncrement:!0})}})}loadHistory(){return new Promise((t,e)=>{if(!this.db){t([]);return}const n=this.db.transaction(E,"readonly").objectStore(E).getAll();n.onerror=()=>e(n.error),n.onsuccess=()=>{const o=n.result;o.sort((h,c)=>h.id-c.id),t(o.map(h=>h.command))}})}async add(t){const e=t.trim();if(e){if(this.history.length>0&&this.history[this.history.length-1]===e){this.reset();return}for(this.history.push(e);this.history.length>B;)this.history.shift();if(this.db)try{await this.saveCommand(e),await this.trimHistory()}catch(s){console.warn("Failed to save history:",s)}this.reset()}}saveCommand(t){return new Promise((e,s)=>{if(!this.db){e();return}const o=this.db.transaction(E,"readwrite").objectStore(E).add({command:t});o.onerror=()=>s(o.error),o.onsuccess=()=>e()})}trimHistory(){return new Promise((t,e)=>{if(!this.db){t();return}const s=this.db.transaction(E,"readwrite"),r=s.objectStore(E),n=r.count();n.onsuccess=()=>{const o=n.result;if(o<=B){t();return}const h=o-B,c=r.getAllKeys();c.onsuccess=()=>{const m=c.result.slice(0,h);if(m.length===0){t();return}s.oncomplete=()=>t(),s.onerror=()=>e(s.error);for(const p of m)r.delete(p)},c.onerror=()=>e(c.error)},n.onerror=()=>e(n.error)})}previous(t){return this.history.length===0?null:(this.cursor===this.history.length&&(this.currentInput=t),this.cursor>0?(this.cursor--,this.history[this.cursor]):null)}next(){return this.cursor<this.history.length-1?(this.cursor++,this.history[this.cursor]):this.cursor===this.history.length-1?(this.cursor++,this.currentInput):null}reset(){this.cursor=this.history.length,this.currentInput=""}getAll(){return[...this.history]}async clear(){if(this.history=[],this.cursor=0,this.currentInput="",this.db)return new Promise((t,e)=>{const n=this.db.transaction(E,"readwrite").objectStore(E).clear();n.onerror=()=>e(n.error),n.onsuccess=()=>t()})}}const Dt=50;function D(i){let t=0;for(const e of i){const s=e.charCodeAt(0);s>=4352&&s<=4447||s>=11904&&s<=42191||s>=44032&&s<=55203||s>=63744&&s<=64255||s>=65040&&s<=65055||s>=65072&&s<=65135||s>=65280&&s<=65376||s>=65504&&s<=65510?t+=2:t+=1}return t}function tt(i,t){const e=D(i),s=t-e;return s<=0?i:i+" ".repeat(s)}function et(i,t){if(D(i)<=t)return i;let e="",s=0;for(const r of i){const n=r.charCodeAt(0)>=4352&&r.charCodeAt(0)<=65535?2:1;if(s+n+1>t)break;e+=r,s+=n}return e+"…"}function it(i){return i>=Number.MIN_SAFE_INTEGER&&i<=Number.MAX_SAFE_INTEGER?Number(i):i.toString()}function Ft(i){const t=[];if(i.months){const e=Math.floor(i.months/12),s=i.months%12;e&&t.push(`${e} year${e!==1?"s":""}`),s&&t.push(`${s} month${s!==1?"s":""}`)}if(i.days&&t.push(`${i.days} day${i.days!==1?"s":""}`),i.micros){const e=typeof i.micros=="bigint"?Number(i.micros):i.micros,s=Math.floor(e/36e8),r=Math.floor(e%36e8/6e7),n=e%6e7/1e6;(s||r||n)&&t.push(`${String(s).padStart(2,"0")}:${String(r).padStart(2,"0")}:${n.toFixed(6).padStart(9,"0")}`)}return t.length?t.join(" "):"00:00:00"}function Ut(i){if(typeof i!="object"||i===null)return!1;const t=i;return"months"in t||"days"in t||"micros"in t}function st(i,t){return typeof t=="bigint"?it(t):t instanceof Date?t.toISOString():t instanceof Map?Object.fromEntries(t):t instanceof Uint8Array?"\\x"+Array.from(t).map(e=>e.toString(16).padStart(2,"0")).join(""):t}function C(i,t){return i==null?t:typeof i=="string"?i:typeof i=="boolean"?i?"true":"false":typeof i=="bigint"?String(it(i)):i instanceof Date?i.toISOString():i instanceof Map?"{"+Array.from(i.entries()).map(([s,r])=>`${C(s,t)}: ${C(r,t)}`).join(", ")+"}":i instanceof Uint8Array?"\\x"+Array.from(i).map(e=>e.toString(16).padStart(2,"0")).join(""):Array.isArray(i)?"["+i.map(e=>C(e,t)).join(", ")+"]":Ut(i)?Ft(i):typeof i=="object"?JSON.stringify(i,st):String(i)}function F(i,t,e={}){const{maxColumnWidth:s=Dt,nullValue:r="NULL"}=e;if(i.length===0)return"";const n=t.map(c=>c.map(f=>{const m=C(f,r);return s?et(m,s):m})),o=i.map((c,f)=>{const m=D(c),p=n.reduce((z,Re)=>{const Ae=D(Re[f]??"");return Math.max(z,Ae)},0);return Math.min(Math.max(m,p),s)}),h=[];h.push("┌"+o.map(c=>"─".repeat(c+2)).join("┬")+"┐"),h.push("│"+i.map((c,f)=>" "+tt(et(c,o[f]),o[f])+" ").join("│")+"│"),h.push("├"+o.map(c=>"─".repeat(c+2)).join("┼")+"┤");for(const c of n)h.push("│"+c.map((f,m)=>" "+tt(f,o[m])+" ").join("│")+"│");return h.push("└"+o.map(c=>"─".repeat(c+2)).join("┴")+"┘"),h.join(`
|
|
17
|
+
`)}function U(i,t){const e=r=>{const n=C(r,"");return n.includes(",")||n.includes('"')||n.includes(`
|
|
18
|
+
`)?'"'+n.replace(/"/g,'""')+'"':n},s=[];s.push(i.map(e).join(","));for(const r of t)s.push(r.map(e).join(","));return s.join(`
|
|
19
|
+
`)}function M(i,t){const e=r=>C(r,"").replace(/\t/g," ").replace(/\n/g," "),s=[];s.push(i.map(e).join(" "));for(const r of t)s.push(r.map(e).join(" "));return s.join(`
|
|
20
|
+
`)}function _(i,t){const e=t.map(s=>{const r={};return i.forEach((n,o)=>{r[n]=s[o]??null}),r});return JSON.stringify(e,st,2)}const H=100*1024*1024;class Mt extends Error{constructor(t,e,s=H){super(`File "${t}" (${k(e)}) exceeds maximum size of ${k(s)}`),this.filename=t,this.size=e,this.maxSize=s,this.name="FileSizeError"}}function _t(i,t=H){if(i.size>t)throw new Mt(i.name,i.size,t)}async function nt(i){return new Promise(t=>{const e=document.createElement("input");e.type="file",e.multiple=i?.multiple??!0,e.accept=i?.accept??".csv,.parquet,.json,.db,.duckdb",e.onchange=()=>{const s=Array.from(e.files??[]);t(s)},e.oncancel=()=>{t([])},e.click()})}async function zt(i,t=H){return _t(i,t),new Promise((e,s)=>{const r=new FileReader;r.onload=()=>{e(new Uint8Array(r.result))},r.onerror=()=>s(r.error),r.readAsArrayBuffer(i)})}function k(i){if(i===0)return"0 B";const t=1024,e=["B","KB","MB","GB"],s=Math.floor(Math.log(i)/Math.log(t));return parseFloat((i/Math.pow(t,s)).toFixed(2))+" "+e[s]}function rt(i){const t=i.lastIndexOf(".");return t===-1?"":i.substring(t+1).toLowerCase()}function Ht(i){return{name:i.name,size:i.size,type:i.type||rt(i.name),lastModified:new Date(i.lastModified)}}function Gt(i,t){const e=n=>{n.preventDefault(),n.stopPropagation(),i.classList.add("drag-over")},s=n=>{n.preventDefault(),n.stopPropagation(),i.classList.remove("drag-over")},r=n=>{n.preventDefault(),n.stopPropagation(),i.classList.remove("drag-over");const o=Array.from(n.dataTransfer?.files??[]);o.length>0&&t(o)};return i.addEventListener("dragover",e),i.addEventListener("dragleave",s),i.addEventListener("drop",r),()=>{i.removeEventListener("dragover",e),i.removeEventListener("dragleave",s),i.removeEventListener("drop",r)}}async function G(i){try{if(navigator.clipboard&&navigator.clipboard.writeText)return await navigator.clipboard.writeText(i),!0;const t=document.createElement("textarea");t.value=i,t.style.position="fixed",t.style.left="-9999px",t.style.top="-9999px",document.body.appendChild(t),t.select();try{return document.execCommand("copy"),!0}finally{document.body.removeChild(t)}}catch{return!1}}async function ot(){try{return navigator.clipboard&&navigator.clipboard.readText?await navigator.clipboard.readText():null}catch{return null}}function Qt(){return!!(navigator.clipboard&&navigator.clipboard.writeText)}const xt=new Set(["SELECT","FROM","WHERE","AND","OR","NOT","IN","IS","NULL","INSERT","INTO","VALUES","UPDATE","SET","DELETE","CREATE","TABLE","DROP","ALTER","INDEX","VIEW","DATABASE","SCHEMA","JOIN","LEFT","RIGHT","INNER","OUTER","FULL","CROSS","ON","USING","GROUP","BY","ORDER","HAVING","LIMIT","OFFSET","UNION","EXCEPT","INTERSECT","ALL","DISTINCT","AS","CASE","WHEN","THEN","ELSE","END","BETWEEN","LIKE","ILIKE","EXISTS","ANY","SOME","TRUE","FALSE","ASC","DESC","NULLS","FIRST","LAST","WITH","RECURSIVE","OVER","PARTITION","WINDOW","CAST","COALESCE","NULLIF","EXTRACT","INTERVAL","PRIMARY","KEY","FOREIGN","REFERENCES","UNIQUE","CHECK","DEFAULT","CONSTRAINT","CASCADE","RESTRICT","NO","ACTION","BEGIN","COMMIT","ROLLBACK","TRANSACTION","SAVEPOINT","GRANT","REVOKE","PRIVILEGES","TO","PUBLIC","IF","REPLACE","TEMPORARY","TEMP","VIRTUAL","MATERIALIZED"]),Wt=new Set(["INTEGER","INT","BIGINT","SMALLINT","TINYINT","HUGEINT","FLOAT","DOUBLE","REAL","DECIMAL","NUMERIC","VARCHAR","CHAR","TEXT","STRING","BLOB","BYTEA","BOOLEAN","BOOL","BIT","DATE","TIME","TIMESTAMP","DATETIME","TIMESTAMPTZ","UUID","JSON","ARRAY","LIST","MAP","STRUCT"]),jt=new Set(["COUNT","SUM","AVG","MIN","MAX","TOTAL","ABS","CEIL","CEILING","FLOOR","ROUND","TRUNC","TRUNCATE","SQRT","POWER","POW","EXP","LOG","LOG10","LOG2","LN","SIN","COS","TAN","ASIN","ACOS","ATAN","ATAN2","LENGTH","CHAR_LENGTH","OCTET_LENGTH","BIT_LENGTH","UPPER","LOWER","INITCAP","TRIM","LTRIM","RTRIM","SUBSTR","SUBSTRING","LEFT","RIGHT","LPAD","RPAD","CONCAT","CONCAT_WS","REPLACE","REVERSE","REPEAT","POSITION","STRPOS","INSTR","LOCATE","SPLIT_PART","STRING_SPLIT","STRING_AGG","LISTAGG","ARRAY_AGG","NOW","CURRENT_DATE","CURRENT_TIME","CURRENT_TIMESTAMP","DATE_PART","DATE_TRUNC","DATE_DIFF","DATE_ADD","DATE_SUB","YEAR","MONTH","DAY","HOUR","MINUTE","SECOND","COALESCE","NULLIF","IFNULL","NVL","IIF","GREATEST","LEAST","RANDOM","SETSEED","ROW_NUMBER","RANK","DENSE_RANK","NTILE","LAG","LEAD","FIRST_VALUE","LAST_VALUE","NTH_VALUE","TYPEOF","TRY_CAST","UNNEST","GENERATE_SERIES","RANGE","READ_CSV","READ_PARQUET","READ_JSON"]);function Q(i){const t=[];let e=0;for(;e<i.length;){const s=i[e];if(/\s/.test(s)){const n=e;for(;e<i.length&&/\s/.test(i[e]);)e++;t.push({type:"whitespace",value:i.slice(n,e),start:n,end:e});continue}if(i.slice(e,e+2)==="--"){const n=e;for(;e<i.length&&i[e]!==`
|
|
21
|
+
`;)e++;t.push({type:"comment",value:i.slice(n,e),start:n,end:e});continue}if(i.slice(e,e+2)==="/*"){const n=e;for(e+=2;e<i.length-1&&i.slice(e,e+2)!=="*/";)e++;e+=2,t.push({type:"comment",value:i.slice(n,e),start:n,end:e});continue}if(s==="'"){const n=e;for(e++;e<i.length;)if(i[e]==="'"&&i[e+1]==="'")e+=2;else if(i[e]==="'"){e++;break}else e++;t.push({type:"string",value:i.slice(n,e),start:n,end:e});continue}if(s==='"'){const n=e;for(e++;e<i.length&&i[e]!=='"';)e++;e++,t.push({type:"identifier",value:i.slice(n,e),start:n,end:e});continue}if(/[0-9]/.test(s)||s==="."&&/[0-9]/.test(i[e+1]||"")){const n=e;for(;e<i.length&&/[0-9]/.test(i[e]);)e++;if(i[e]==="."&&/[0-9]/.test(i[e+1]||""))for(e++;e<i.length&&/[0-9]/.test(i[e]);)e++;if(i[e]==="e"||i[e]==="E")for(e++,(i[e]==="+"||i[e]==="-")&&e++;e<i.length&&/[0-9]/.test(i[e]);)e++;t.push({type:"number",value:i.slice(n,e),start:n,end:e});continue}if(/[a-zA-Z_]/.test(s)){const n=e;for(;e<i.length&&/[a-zA-Z0-9_]/.test(i[e]);)e++;const o=i.slice(n,e),h=o.toUpperCase();let c="identifier";xt.has(h)?c="keyword":Wt.has(h)?c="type":jt.has(h)&&(c="function"),t.push({type:c,value:o,start:n,end:e});continue}const r=e;e++,t.push({type:"operator",value:i.slice(r,e),start:r,end:e})}return t}function Yt(i){switch(i){case"keyword":return O;case"type":return R;case"function":return N;case"string":return b;case"number":return X;case"comment":return T;case"operator":return $;case"identifier":case"whitespace":default:return""}}function x(i){const t=Q(i);let e="";for(const s of t){const r=Yt(s.type);r?e+=r+s.value+P:e+=s.value}return e}function Vt(i){const t=i.trim();return t?[...Q(t)].reverse().find(r=>r.type!=="whitespace")?.value===";":!1}function Kt(i,t){let e=null;const s=function(...r){e!==null&&clearTimeout(e),e=setTimeout(()=>{i.apply(this,r),e=null},t)};return s.cancel=()=>{e!==null&&(clearTimeout(e),e=null)},s}function Xt(i){const t=[];let e="",s=null,r=!1,n=!1;for(let o=0;o<i.length;o++){const h=i[o];if(r){switch(h){case"n":e+=`
|
|
22
|
+
`;break;case"t":e+=" ";break;case"r":e+="\r";break;case"\\":e+="\\";break;case'"':e+='"';break;case"'":e+="'";break;case" ":e+=" ";break;default:e+="\\"+h}r=!1;continue}if(h==="\\"&&s!=="'"){r=!0;continue}if((h==='"'||h==="'")&&!s){s=h,n=!0;continue}if(h===s){s=null;continue}if(h===" "&&!s){(e||n)&&(t.push(e),e="",n=!1);continue}e+=h}return(e||n)&&t.push(e),t}function Jt(i){const t=Xt(i),e=t[0]?.toLowerCase()??"",s=t.slice(1);return{command:e,args:s,allArgs:t}}const L=/https?:\/\/[^\s<>"\])\[}{'|^`\\]+/gi,Zt="\x1B]8;;",qt="\x07",te="\x1B]8;;\x07";function ee(i){return L.lastIndex=0,L.test(i)}function ie(i){return L.lastIndex=0,i.match(L)||[]}function at(i,t){return`${Zt}${i}${qt}${t??i}${te}`}function lt(i){return L.lastIndex=0,i.replace(L,t=>at(t))}function se(i){try{return new URL(i),!0}catch{return!1}}function ne(i,t=60){if(i.length<=t)return i;try{const e=new URL(i),s=e.host,r=e.pathname+e.search+e.hash,n=s.length,o=t-n-8;if(o<10)return i.substring(0,t-3)+"...";const h=r.substring(0,Math.floor(o/2)),c=r.substring(r.length-Math.floor(o/2));return`${e.protocol}//${s}${h}...${c}`}catch{return i.substring(0,t-3)+"..."}}class ht{constructor(){a(this,"enabled",!0);a(this,"maxURLLength",80)}setEnabled(t){this.enabled=t}isEnabled(){return this.enabled}setMaxURLLength(t){this.maxURLLength=t}process(t){return this.enabled?lt(t):t}processWithTruncation(t){return this.enabled?(L.lastIndex=0,t.replace(L,e=>{const s=ne(e,this.maxURLLength);return at(e,s)})):t}}const re={background:"#1e1e1e",foreground:"#d4d4d4",cursor:"#d4d4d4",selection:"#264f78",black:"#000000",red:"#cd3131",green:"#0dbc79",yellow:"#e5e510",blue:"#2472c8",magenta:"#bc3fbc",cyan:"#11a8cd",white:"#e5e5e5",brightBlack:"#666666",brightRed:"#f14c4c",brightGreen:"#23d18b",brightYellow:"#f5f543",brightBlue:"#3b8eea",brightMagenta:"#d670d6",brightCyan:"#29b8db",brightWhite:"#ffffff"},oe={background:"#ffffff",foreground:"#1e1e1e",cursor:"#1e1e1e",selection:"#add6ff",black:"#000000",red:"#cd3131",green:"#008000",yellow:"#795e00",blue:"#0451a5",magenta:"#bc05bc",cyan:"#0598bc",white:"#e5e5e5",brightBlack:"#666666",brightRed:"#cd3131",brightGreen:"#14ce14",brightYellow:"#b5ba00",brightBlue:"#0451a5",brightMagenta:"#bc05bc",brightCyan:"#0598bc",brightWhite:"#a5a5a5"},ct={name:"dark",colors:re},ut={name:"light",colors:oe};function W(i){return i==="light"?ut:ct}function dt(){try{const i=localStorage.getItem("duckdb-terminal-theme");if(i==="light"||i==="dark")return i}catch{}return"dark"}function ft(i){try{localStorage.setItem("duckdb-terminal-theme",i)}catch{}}const mt="🦆 ",gt=" > ";class pt{constructor(t){a(this,"terminalAdapter");a(this,"database");a(this,"inputBuffer");a(this,"history");a(this,"state","idle");a(this,"collectedSQL",[]);a(this,"commands",new Map);a(this,"showTimer",!1);a(this,"outputMode","table");a(this,"currentThemeName");a(this,"customTheme",null);a(this,"config");a(this,"loadedFiles",new Map);a(this,"syntaxHighlighting",!0);a(this,"lastQueryResult",null);a(this,"linkProvider");a(this,"eventListeners",new Map);a(this,"pageSize",0);a(this,"paginationQuery",null);a(this,"currentPage",0);a(this,"totalRows",0);a(this,"prompt");a(this,"continuationPrompt");a(this,"debouncedHighlight",Kt(()=>this.redrawLineHighlighted(),150));a(this,"queryQueue",Promise.resolve(null));a(this,"dragDropCleanup",null);this.config=t,this.terminalAdapter=new j,this.database=new Y({storage:t.storage??"memory",databasePath:t.databasePath}),this.inputBuffer=new Z,this.history=new q,this.linkProvider=new ht,t.linkDetection===!1&&this.linkProvider.setEnabled(!1),this.prompt=t.prompt??mt,this.continuationPrompt=t.continuationPrompt??gt,typeof t.theme=="object"?(this.customTheme=t.theme,this.currentThemeName="custom"):this.currentThemeName=t.theme??dt(),this.registerCommands()}on(t,e){return this.eventListeners.has(t)||this.eventListeners.set(t,new Set),this.eventListeners.get(t).add(e),()=>this.off(t,e)}off(t,e){this.eventListeners.get(t)?.delete(e)}emit(t,e){this.eventListeners.get(t)?.forEach(s=>{try{s(e)}catch(r){console.error(`Error in ${t} event listener:`,r)}})}setState(t){const e=this.state;e!==t&&(this.state=t,this.emit("stateChange",{state:t,previous:e}))}getHighlightedSQL(t){return this.syntaxHighlighting?x(t):t}redrawLineHighlighted(){if(!this.syntaxHighlighting)return;const t=this.inputBuffer.getContent();if(t.length===0)return;const e=this.inputBuffer.getCursorPos(),s=x(t);e>0&&this.write(y(e)),this.write(v),this.write(s);const r=t.length-e;r>0&&this.write(y(r))}getCurrentThemeObject(){return this.customTheme?this.customTheme:W(this.currentThemeName)}async start(){const t=this.resolveContainer();await this.terminalAdapter.init(t,{fontFamily:this.config.fontFamily,fontSize:this.config.fontSize,theme:this.getCurrentThemeObject(),scrollback:this.config.scrollback}),this.config.welcomeMessage!==!1&&(this.writeln(S("DuckDB Terminal")+" v0.1.0"),this.write(d("Loading DuckDB WASM..."))),await Promise.all([this.database.init(),this.history.init()]),this.config.welcomeMessage!==!1&&(this.write("\r"+v),this.writeln(d("Powered by DuckDB WASM and Ghostty")),this.writeln(""),this.writeln("Type "+u(".help",R)+" for available commands"),this.writeln("Enter SQL statements ending with "+u(";",N)),this.writeln("")),this.terminalAdapter.onData(this.handleInput.bind(this)),this.dragDropCleanup=Gt(t,e=>{this.handleDroppedFiles(e)}),this.showPrompt(),this.emit("ready",{})}destroy(){this.dragDropCleanup&&(this.dragDropCleanup(),this.dragDropCleanup=null),this.eventListeners.clear(),this.debouncedHighlight.cancel()}async handleDroppedFiles(t){const e=await Promise.allSettled(t.map(n=>this.loadFile(n))),s=e.filter(n=>n.status==="fulfilled"&&n.value).length,r=e.length-s;r>0&&s>0&&this.writeln(d(`Loaded ${s} of ${e.length} files (${r} failed)`)),this.showPrompt()}async loadFile(t){const e=rt(t.name),s=Ht(t);try{const r=await zt(t);await this.database.registerFile(t.name,r),this.loadedFiles.set(t.name,s),this.emit("fileLoaded",{filename:t.name,size:t.size,type:e}),this.writeln(""),this.writeln(u(`Loaded: ${t.name}`,b)+` (${k(t.size)})`);const n=t.name.replace(/'/g,"''");if(e==="csv"){const o=t.name.replace(/\.[^.]+$/,"").replace(/[^a-zA-Z0-9_]/g,"_");this.writeln(d(`Hint: SELECT * FROM read_csv('${n}');`)),this.writeln(d(` or: CREATE TABLE ${o} AS SELECT * FROM read_csv('${n}');`))}else e==="parquet"?this.writeln(d(`Hint: SELECT * FROM read_parquet('${n}');`)):e==="json"&&this.writeln(d(`Hint: SELECT * FROM read_json('${n}');`));return!0}catch(r){const n=r instanceof Error?r.message:String(r);return this.writeln(u(`Error loading ${t.name}: ${n}`,w)),!1}}resolveContainer(){if(typeof this.config.container=="string"){const t=document.querySelector(this.config.container);if(!t)throw new Error(`Container not found: ${this.config.container}`);return t}return this.config.container}registerCommands(){this.commands.set(".help",{name:".help",description:"Show available commands",handler:()=>this.cmdHelp()}),this.commands.set(".clear",{name:".clear",description:"Clear the terminal",handler:()=>this.clear()}),this.commands.set(".tables",{name:".tables",description:"List all tables",handler:()=>this.cmdTables()}),this.commands.set(".schema",{name:".schema",description:"Show table schema",usage:".schema <table_name>",handler:t=>this.cmdSchema(t)}),this.commands.set(".timer",{name:".timer",description:"Toggle query timing",usage:".timer on|off",handler:t=>this.cmdTimer(t)}),this.commands.set(".mode",{name:".mode",description:"Set output mode",usage:".mode table|csv|tsv|json",handler:t=>this.cmdMode(t)}),this.commands.set(".theme",{name:".theme",description:"Set color theme (clears screen)",usage:".theme dark|light",handler:t=>this.cmdTheme(t)}),this.commands.set(".examples",{name:".examples",description:"Show example queries",handler:()=>this.cmdExamples()}),this.commands.set(".files",{name:".files",description:"Manage loaded files",usage:".files [list|add|remove <name|index>]",handler:t=>this.cmdFiles(t)}),this.commands.set(".open",{name:".open",description:"Open a file picker to load files",handler:()=>this.cmdOpen()}),this.commands.set(".copy",{name:".copy",description:"Copy last result to clipboard",handler:async()=>{await this.copyLastResult()}}),this.commands.set(".highlight",{name:".highlight",description:"Toggle syntax highlighting",usage:".highlight on|off",handler:t=>this.cmdHighlight(t)}),this.commands.set(".links",{name:".links",description:"Toggle clickable URL detection",usage:".links on|off",handler:t=>this.cmdLinks(t)}),this.commands.set(".pagesize",{name:".pagesize",description:"Enable pagination for large results (default: off)",usage:".pagesize <number> (0 = disabled)",handler:t=>this.cmdPageSize(t)}),this.commands.set(".reset",{name:".reset",description:"Reset database and all settings to defaults",handler:()=>this.cmdReset()}),this.commands.set(".prompt",{name:".prompt",description:"Get or set the command prompt",usage:".prompt [primary [continuation]]",handler:t=>this.cmdPrompt(t)})}showPrompt(){const t=this.state==="collecting"?this.continuationPrompt:this.prompt;this.inputBuffer.setPromptLength(t.length),this.write(u(t,b)),this.state!=="collecting"&&this.setState("idle")}handleInput(t){if(this.state!=="executing"){if(this.state==="paginating"){this.handlePaginationInput(t);return}if(t.startsWith("\x1B[")){this.handleEscapeSequence(t);return}for(const e of t)this.handleChar(e)}}async handlePaginationInput(t){const e=Math.ceil(this.totalRows/this.pageSize),s=t.toLowerCase();if(s==="n"||t==="\x1B[B"){this.currentPage<e-1?(this.currentPage++,await this.executePaginatedQuery()):this.writeln(d("Already on last page"));return}if(s==="p"||t==="\x1B[A"){this.currentPage>0?(this.currentPage--,await this.executePaginatedQuery()):this.writeln(d("Already on first page"));return}if(s==="q"||s==="\x1B"||s===""){this.writeln(""),this.exitPagination(),this.writeln(""),this.showPrompt();return}if(s==="\r"||s===`
|
|
23
|
+
`){const r=this.inputBuffer.getContent().trim();if(r){const n=parseInt(r,10);!isNaN(n)&&n>=1&&n<=e?(this.currentPage=n-1,this.inputBuffer.clear(),await this.executePaginatedQuery()):(this.writeln(u(`Invalid page number. Enter 1-${e}`,w)),this.inputBuffer.clear())}return}if(/^\d$/.test(s)){this.write(this.inputBuffer.insert(s));return}if(s===""||s==="\b"){this.write(this.inputBuffer.backspace());return}}handleChar(t){const e=t.charCodeAt(0);switch(t){case"\r":case`
|
|
24
|
+
`:this.handleEnter();return;case"":case"\b":this.write(this.inputBuffer.backspace());return;case"\x1B":return;case" ":this.handleTab();return;case"":this.handleCtrlC();return;case"":this.handlePaste();return;case"":this.write(this.inputBuffer.moveToStart());return;case"":this.write(this.inputBuffer.moveToEnd());return;case"\v":this.write(this.inputBuffer.clearToEnd());return;case"":this.write(this.inputBuffer.clearLine());return}t!=="\x1B"&&(e>=32&&e<127?(this.write(this.inputBuffer.insert(t)),this.isHighlightTrigger(t)&&this.debouncedHighlight()):e>=128&&this.write(this.inputBuffer.insert(t)))}isHighlightTrigger(t){return t===" "||t===";"||t==="("||t===")"||t===","}handleEscapeSequence(t){switch(t){case"\x1B[A":this.handleArrowUp();break;case"\x1B[B":this.handleArrowDown();break;case"\x1B[C":this.write(this.inputBuffer.moveRight());break;case"\x1B[D":this.write(this.inputBuffer.moveLeft());break;case"\x1B[H":this.write(this.inputBuffer.moveToStart());break;case"\x1B[F":this.write(this.inputBuffer.moveToEnd());break;case"\x1B[3~":this.write(this.inputBuffer.delete());break}}async handleEnter(){const t=this.inputBuffer.getContent();if(this.writeln(""),t.trim()===""&&this.state!=="collecting"){this.showPrompt();return}if(t.trim().startsWith(".")&&this.state!=="collecting"){this.writeln(""),await this.history.add(t.trim()),await this.executeCommand(t.trim()),this.inputBuffer.clear(),this.writeln(""),this.showPrompt();return}this.collectedSQL.push(t);const e=this.collectedSQL.join(`
|
|
25
|
+
`).trim();e.endsWith(";")?(this.writeln(""),await this.executeSQL(e),this.collectedSQL=[],this.state!=="paginating"&&this.setState("idle")):this.setState("collecting"),this.inputBuffer.clear(),this.state!=="paginating"&&(e.endsWith(";")&&this.writeln(""),this.showPrompt())}handleArrowUp(){const t=this.history.previous(this.inputBuffer.getContent());t!==null&&(this.write(this.inputBuffer.clearLine()),this.inputBuffer.setContent(t),this.write(this.getHighlightedSQL(t)))}handleArrowDown(){const t=this.history.next();t!==null&&(this.write(this.inputBuffer.clearLine()),this.inputBuffer.setContent(t),this.write(this.getHighlightedSQL(t)))}async handleTab(){const t=this.inputBuffer.getContent(),e=this.inputBuffer.getCursorPos(),s=await this.database.getCompletions(t,e);if(s.length!==0)if(s.length===1)this.write(this.inputBuffer.replaceWordBeforeCursor(s[0].value)),this.redrawLineHighlighted();else{this.writeln("");const r=s.map(c=>{const f=c.type==="keyword"?O:c.type==="table"?b:c.type==="function"?N:$;return u(c.value,f)}).join(" ");this.writeln(r);const n=this.findCommonPrefix(s.map(c=>c.value)),o=this.inputBuffer.getWordBeforeCursor();n.length>o.length&&this.write(this.inputBuffer.replaceWordBeforeCursor(n));const h=this.state==="collecting"?this.continuationPrompt:this.prompt;this.write(u(h,b)),this.write(this.getHighlightedSQL(this.inputBuffer.getContent()))}}findCommonPrefix(t){if(t.length===0)return"";if(t.length===1)return t[0];let e=t[0];for(let s=1;s<t.length;s++)for(;!t[s].toLowerCase().startsWith(e.toLowerCase());)if(e=e.slice(0,-1),e==="")return"";return e}handleCtrlC(){this.writeln("^C"),this.inputBuffer.clear(),this.collectedSQL=[],this.setState("idle"),this.showPrompt()}async handlePaste(){const t=await ot();if(t)for(const e of t)e===`
|
|
26
|
+
`||e==="\r"||this.write(this.inputBuffer.insert(e))}async copyLastResult(){if(!this.lastQueryResult)return this.writeln(d("No query result to copy")),!1;let t;switch(this.outputMode){case"csv":t=U(this.lastQueryResult.columns,this.lastQueryResult.rows);break;case"tsv":t=M(this.lastQueryResult.columns,this.lastQueryResult.rows);break;case"json":t=_(this.lastQueryResult.columns,this.lastQueryResult.rows);break;default:t=F(this.lastQueryResult.columns,this.lastQueryResult.rows)}const e=await G(t);return e?this.writeln(u("Result copied to clipboard",b)):this.writeln(u("Failed to copy to clipboard",w)),e}async executeCommand(t){const{command:e,args:s}=Jt(t),r=this.commands.get(e);if(!r){this.writeln(u(`Unknown command: ${e}`,w)),this.writeln("Type .help for available commands"),this.emit("error",{message:`Unknown command: ${e}`,source:"command"});return}this.emit("commandExecute",{command:e,args:s});try{await r.handler(s,this)}catch(n){const o=n instanceof Error?n.message:String(n);this.writeln(u(`Error: ${o}`,w)),this.emit("error",{message:o,source:"command"})}}async executeSQL(t){const e=this.queryQueue.then(()=>this.executeSQLInternal(t));return this.queryQueue=e.catch(()=>null),e}async executeSQLInternal(t){this.setState("executing");const e=performance.now();this.emit("queryStart",{sql:t});try{await this.history.add(t);const s=t.trim().replace(/;+$/,""),r=/^\s*SELECT\s/i.test(s),n=/\b(LIMIT|OFFSET)\b/i.test(s);if(this.pageSize>0&&r&&!n){const c=`SELECT COUNT(*) as cnt FROM (${s}) AS _count_subquery`,m=(await this.database.executeQuery(c)).rows[0]?.[0],p=typeof m=="bigint"?Number(m):m??0;if(p>this.pageSize)return this.paginationQuery=s,this.totalRows=p,this.currentPage=0,await this.executePaginatedQuery()}const o=await this.database.executeQuery(t),h=performance.now()-e;return this.lastQueryResult=o,o.columns.length>0&&this.displayResult(o),this.showTimer&&this.writeln(d(`Time: ${o.duration.toFixed(2)}ms`)),this.emit("queryEnd",{sql:t,result:o,duration:h}),o}catch(s){const r=s instanceof Error?s.message:String(s),n=performance.now()-e;if(this.writeln(u(`Error: ${r}`,w)),t.includes(`
|
|
27
|
+
`)||t.length>80){const o=t.length>200?t.substring(0,200)+"...":t;this.writeln(d(` Query: ${o.replace(/\n/g," ")}`))}return this.emit("queryEnd",{sql:t,result:null,error:r,duration:n}),this.emit("error",{message:r,source:"query"}),null}finally{this.state!=="paginating"&&this.setState("idle")}}async executePaginatedQuery(){if(!this.paginationQuery)return null;const t=this.currentPage*this.pageSize,e=`${this.paginationQuery} LIMIT ${this.pageSize} OFFSET ${t}`;try{const s=await this.database.executeQuery(e);this.lastQueryResult=s,s.columns.length>0&&this.displayResult(s);const r=Math.ceil(this.totalRows/this.pageSize),n=t+1,o=Math.min(t+this.pageSize,this.totalRows);return this.writeln(""),this.writeln(d(`Showing rows ${n}-${o} of ${this.totalRows} (page ${this.currentPage+1}/${r})`)),this.writeln(u(" [n]ext [p]rev [q]uit or enter page number",R)),this.setState("paginating"),s}catch(s){const r=s instanceof Error?s.message:String(s);if(this.writeln(u(`Error: ${r}`,w)),e.length>80){const n=e.length>200?e.substring(0,200)+"...":e;this.writeln(d(` Query: ${n.replace(/\n/g," ")}`))}return this.exitPagination(),null}}exitPagination(){this.paginationQuery=null,this.currentPage=0,this.totalRows=0,this.setState("idle")}displayResult(t){switch(this.outputMode){case"csv":this.writeln(U(t.columns,t.rows));break;case"tsv":this.writeln(M(t.columns,t.rows));break;case"json":this.writeln(_(t.columns,t.rows));break;case"table":default:this.writeln(F(t.columns,t.rows));break}this.writeln(d(`${t.rowCount} row${t.rowCount!==1?"s":""}`))}cmdHelp(){this.writeln(S("Available commands:")),this.writeln("");for(const t of this.commands.values()){const e=t.usage?` ${d(t.usage)}`:"";this.writeln(` ${u(t.name,R)} ${t.description}${e}`)}this.writeln(""),this.writeln("SQL statements must end with a semicolon (;)")}async cmdTables(){const t=await this.database.getTables();if(t.length===0){this.writeln(d("No tables found"));return}for(const e of t)this.writeln(e)}async cmdSchema(t){if(t.length===0){this.writeln("Usage: .schema <table_name>");return}const e=await this.database.getTableSchema(t[0]);if(e.length===0){this.writeln(d(`Table not found: ${t[0]}`));return}for(const s of e)this.writeln(` ${s.name} ${d(s.type)}`)}cmdTimer(t){if(t.length===0){this.writeln(`Timer is ${this.showTimer?"on":"off"}`);return}const e=t[0].toLowerCase();e==="on"?(this.showTimer=!0,this.writeln("Timer is now on")):e==="off"?(this.showTimer=!1,this.writeln("Timer is now off")):this.writeln("Usage: .timer on|off")}cmdMode(t){if(t.length===0){this.writeln(`Output mode: ${this.outputMode}`);return}const e=t[0].toLowerCase();e==="table"||e==="csv"||e==="tsv"||e==="json"?(this.outputMode=e,this.writeln(`Output mode set to ${e}`)):this.writeln("Usage: .mode table|csv|tsv|json")}cmdTheme(t){if(t.length===0){const s=this.customTheme?this.customTheme.name:this.currentThemeName;this.writeln(`Theme: ${s}`);return}const e=t[0].toLowerCase();e==="dark"||e==="light"?this.setTheme(e):this.writeln("Usage: .theme dark|light")}cmdExamples(){this.writeln(S("Example queries:")),this.writeln(""),this.writeln(u(" -- Create a table",T)),this.writeln(" "+this.getHighlightedSQL("CREATE TABLE users (id INTEGER, name VARCHAR);")),this.writeln(""),this.writeln(u(" -- Insert data",T)),this.writeln(" "+this.getHighlightedSQL("INSERT INTO users VALUES (1, 'Alice'), (2, 'Bob');")),this.writeln(""),this.writeln(u(" -- Query data",T)),this.writeln(" "+this.getHighlightedSQL("SELECT * FROM users WHERE name LIKE 'A%';")),this.writeln(""),this.writeln(u(" -- Use built-in functions",T)),this.writeln(" "+this.getHighlightedSQL("SELECT range(10), current_timestamp;"))}async cmdFiles(t){const e=t[0]?.toLowerCase()??"list";if(e==="list"){if(this.loadedFiles.size===0){this.writeln(d("No files loaded")),this.writeln(d("Use .open or drag-and-drop to add files"));return}this.writeln(S("Loaded files:"));let s=1;for(const[r,n]of this.loadedFiles)this.writeln(` ${d(`${s}.`)} ${r} ${d(`(${k(n.size)})`)}`),s++}else if(e==="add")await this.cmdOpen();else if(e==="remove"||e==="rm"){const s=t.slice(1).join(" ");if(!s){this.writeln("Usage: .files remove <filename|index>");return}const r=parseInt(s,10);let n=null;if(!isNaN(r)&&r>=1){const o=Array.from(this.loadedFiles.keys());if(r<=o.length)n=o[r-1];else{this.writeln(u(`Invalid index: ${r}. Use .files list to see available files.`,"red"));return}}else if(this.loadedFiles.has(s))n=s;else{this.writeln(u(`File not found: ${s}`,"red"));return}if(n)try{await this.database.dropFile(n),this.loadedFiles.delete(n),this.writeln(u(`Removed: ${n}`,"green"))}catch(o){this.writeln(u(`Error removing file: ${o}`,"red"))}}else this.writeln("Usage: .files [list|add|remove <name|index>]")}async cmdOpen(){this.writeln(d("Opening file picker..."));const t=await nt({multiple:!0,accept:".csv,.parquet,.json,.db,.duckdb"});if(t.length===0){this.writeln(d("No files selected"));return}for(const e of t)await this.loadFile(e)}cmdHighlight(t){if(t.length===0){this.writeln(`Syntax highlighting is ${this.syntaxHighlighting?"on":"off"}`);return}const e=t[0].toLowerCase();e==="on"?(this.syntaxHighlighting=!0,this.writeln("Syntax highlighting is now on")):e==="off"?(this.syntaxHighlighting=!1,this.writeln("Syntax highlighting is now off")):this.writeln("Usage: .highlight on|off")}cmdLinks(t){if(t.length===0){this.writeln(`URL link detection is ${this.linkProvider.isEnabled()?"on":"off"}`);return}const e=t[0].toLowerCase();e==="on"?(this.linkProvider.setEnabled(!0),this.writeln("URL link detection is now on")):e==="off"?(this.linkProvider.setEnabled(!1),this.writeln("URL link detection is now off")):this.writeln("Usage: .links on|off")}cmdPageSize(t){if(t.length===0){this.pageSize===0?this.writeln("Pagination is disabled (showing all rows)"):this.writeln(`Page size: ${this.pageSize} rows`);return}const e=parseInt(t[0],10);if(isNaN(e)||e<0){this.writeln("Usage: .pagesize <number> (0 = no pagination)");return}this.pageSize=e,e===0?this.writeln("Pagination disabled (will show all rows)"):this.writeln(`Page size set to ${e} rows`)}async cmdReset(){try{const t=await this.database.getTables(),e=t.length;for(const r of t)await this.database.executeQuery(`DROP TABLE IF EXISTS "${r}";`);const s=this.loadedFiles.size;for(const r of this.loadedFiles.keys())try{await this.database.dropFile(r)}catch{}this.loadedFiles.clear(),this.lastQueryResult=null,this.history.reset(),this.showTimer=!1,this.outputMode="table",this.syntaxHighlighting=!0,this.pageSize=0,this.linkProvider.setEnabled(!0),this.prompt=mt,this.continuationPrompt=gt,this.paginationQuery=null,this.currentPage=0,this.totalRows=0,this.writeln(u(`Reset complete: dropped ${e} table${e!==1?"s":""}, cleared ${s} file${s!==1?"s":""}, settings restored to defaults`,b))}catch(t){const e=t instanceof Error?t.message:String(t);this.writeln(u(`Error during reset: ${e}`,w))}}cmdPrompt(t){if(t.length===0){this.writeln(`Primary prompt: "${this.prompt}"`),this.writeln(`Continuation prompt: "${this.continuationPrompt}"`);return}const e=t[0];this.prompt=e,t.length>=2?(this.continuationPrompt=t[1],this.writeln(`Prompts set to "${this.prompt}" and "${this.continuationPrompt}"`)):this.writeln(`Primary prompt set to "${this.prompt}"`)}write(t){this.terminalAdapter.write(t)}writeln(t){const s=this.linkProvider.process(t).replace(/\r?\n/g,`\r
|
|
28
|
+
`);this.terminalAdapter.writeln(s)}clear(){this.terminalAdapter.clear()}setTheme(t){const e=this.getCurrentThemeObject();typeof t=="object"?(this.customTheme=t,this.currentThemeName="custom",this.terminalAdapter.setTheme(t),this.writeln(`Theme set to ${t.name}`)):(this.customTheme=null,this.currentThemeName=t,this.terminalAdapter.setTheme(W(t)),ft(t),this.writeln(`Theme set to ${t}`));const s=this.getCurrentThemeObject();this.emit("themeChange",{theme:s,previous:e});const r=this.currentThemeName==="light"||this.customTheme?.name==="light";document.body.classList.toggle("light",r),document.body.classList.toggle("dark",!r)}getTheme(){return this.currentThemeName==="custom"&&this.customTheme?this.customTheme.name==="light"?"light":"dark":this.currentThemeName}}function ae(i){const t=new Map;return t.set(".help",{name:".help",description:"Show available commands",handler:()=>le(t,i)}),t.set(".clear",{name:".clear",description:"Clear the terminal",handler:()=>i.clear()}),t.set(".tables",{name:".tables",description:"List all tables",handler:()=>he(i)}),t.set(".schema",{name:".schema",description:"Show table schema",usage:".schema <table_name>",handler:e=>ce(e,i)}),t.set(".timer",{name:".timer",description:"Toggle query timing",usage:".timer on|off",handler:e=>ue(e,i)}),t.set(".mode",{name:".mode",description:"Set output mode",usage:".mode table|csv|tsv|json",handler:e=>de(e,i)}),t.set(".theme",{name:".theme",description:"Set color theme (clears screen)",usage:".theme dark|light",handler:e=>fe(e,i)}),t.set(".examples",{name:".examples",description:"Show example queries",handler:()=>me(i)}),t.set(".files",{name:".files",description:"Manage loaded files",usage:".files [list|add|remove <name|index>]",handler:e=>ge(e,i)}),t.set(".open",{name:".open",description:"Open a file picker to load files",handler:()=>wt(i)}),t.set(".copy",{name:".copy",description:"Copy last result to clipboard",handler:()=>ye(i)}),t.set(".highlight",{name:".highlight",description:"Toggle syntax highlighting",usage:".highlight on|off",handler:e=>pe(e,i)}),t.set(".links",{name:".links",description:"Toggle clickable URL detection",usage:".links on|off",handler:e=>we(e,i)}),t.set(".pagesize",{name:".pagesize",description:"Enable pagination for large results (default: off)",usage:".pagesize <number> (0 = disabled)",handler:e=>be(e,i)}),t.set(".reset",{name:".reset",description:"Reset database and all settings to defaults",handler:()=>Te(i)}),t.set(".prompt",{name:".prompt",description:"Get or set the command prompt",usage:".prompt [primary [continuation]]",handler:e=>Ee(e,i)}),t}function le(i,t){t.writeln(S("Available commands:")),t.writeln("");for(const e of i.values()){const s=e.usage?` ${d(e.usage)}`:"";t.writeln(` ${u(e.name,R)} ${e.description}${s}`)}t.writeln(""),t.writeln("SQL statements must end with a semicolon (;)")}async function he(i){const t=await i.getDatabase().getTables();if(t.length===0){i.writeln(d("No tables found"));return}for(const e of t)i.writeln(e)}async function ce(i,t){if(i.length===0){t.writeln("Usage: .schema <table_name>");return}const e=await t.getDatabase().getTableSchema(i[0]);if(e.length===0){t.writeln(d(`Table not found: ${i[0]}`));return}for(const s of e)t.writeln(` ${s.name} ${d(s.type)}`)}function ue(i,t){if(i.length===0){t.writeln(`Timer is ${t.getShowTimer()?"on":"off"}`);return}const e=i[0].toLowerCase();e==="on"?(t.setShowTimer(!0),t.writeln("Timer is now on")):e==="off"?(t.setShowTimer(!1),t.writeln("Timer is now off")):t.writeln("Usage: .timer on|off")}function de(i,t){if(i.length===0){t.writeln(`Output mode: ${t.getOutputMode()}`);return}const e=i[0].toLowerCase();e==="table"||e==="csv"||e==="tsv"||e==="json"?(t.setOutputMode(e),t.writeln(`Output mode set to ${e}`)):t.writeln("Usage: .mode table|csv|tsv|json")}function fe(i,t){if(i.length===0){t.writeln(`Theme: ${t.getThemeName()}`);return}const e=i[0].toLowerCase();e==="dark"||e==="light"?t.setTheme(e):t.writeln("Usage: .theme dark|light")}function me(i){i.writeln(S("Example queries:")),i.writeln(""),i.writeln(u(" -- Create a table",T)),i.writeln(" "+i.getHighlightedSQL("CREATE TABLE users (id INTEGER, name VARCHAR);")),i.writeln(""),i.writeln(u(" -- Insert data",T)),i.writeln(" "+i.getHighlightedSQL("INSERT INTO users VALUES (1, 'Alice'), (2, 'Bob');")),i.writeln(""),i.writeln(u(" -- Query data",T)),i.writeln(" "+i.getHighlightedSQL("SELECT * FROM users WHERE name LIKE 'A%';")),i.writeln(""),i.writeln(u(" -- Use built-in functions",T)),i.writeln(" "+i.getHighlightedSQL("SELECT range(10), current_timestamp;"))}async function ge(i,t){const e=i[0]?.toLowerCase()??"list",s=t.getLoadedFiles();if(e==="list"){if(s.size===0){t.writeln(d("No files loaded")),t.writeln(d("Use .open or drag-and-drop to add files"));return}t.writeln(S("Loaded files:"));let r=1;for(const[n,o]of s)t.writeln(` ${d(`${r}.`)} ${n} ${d(`(${k(o.size)})`)}`),r++}else if(e==="add")await wt(t);else if(e==="remove"||e==="rm"){const r=i.slice(1).join(" ");if(!r){t.writeln("Usage: .files remove <filename|index>");return}const n=parseInt(r,10);let o=null;if(!isNaN(n)&&n>=1){const h=Array.from(s.keys());if(n<=h.length)o=h[n-1];else{t.writeln(u(`Invalid index: ${n}. Use .files list to see available files.`,"red"));return}}else if(s.has(r))o=r;else{t.writeln(u(`File not found: ${r}`,"red"));return}if(o)try{await t.removeFile(o),t.writeln(u(`Removed: ${o}`,"green"))}catch(h){t.writeln(u(`Error removing file: ${h}`,"red"))}}else t.writeln("Usage: .files [list|add|remove <name|index>]")}async function wt(i){i.writeln(d("Opening file picker..."));const t=await nt({multiple:!0,accept:".csv,.parquet,.json,.db,.duckdb"});if(t.length===0){i.writeln(d("No files selected"));return}for(const e of t)await i.loadFile(e)}function pe(i,t){if(i.length===0){t.writeln(`Syntax highlighting is ${t.getSyntaxHighlighting()?"on":"off"}`);return}const e=i[0].toLowerCase();e==="on"?(t.setSyntaxHighlighting(!0),t.writeln("Syntax highlighting is now on")):e==="off"?(t.setSyntaxHighlighting(!1),t.writeln("Syntax highlighting is now off")):t.writeln("Usage: .highlight on|off")}function we(i,t){const e=t.getLinkProvider();if(i.length===0){t.writeln(`URL link detection is ${e.isEnabled()?"on":"off"}`);return}const s=i[0].toLowerCase();s==="on"?(e.setEnabled(!0),t.writeln("URL link detection is now on")):s==="off"?(e.setEnabled(!1),t.writeln("URL link detection is now off")):t.writeln("Usage: .links on|off")}function be(i,t){if(i.length===0){const s=t.getPageSize();s===0?t.writeln("Pagination is disabled (showing all rows)"):t.writeln(`Page size: ${s} rows`);return}const e=parseInt(i[0],10);if(isNaN(e)||e<0){t.writeln("Usage: .pagesize <number> (0 = no pagination)");return}t.setPageSize(e),e===0?t.writeln("Pagination disabled (will show all rows)"):t.writeln(`Page size set to ${e} rows`)}async function Te(i){await i.resetState()}function Ee(i,t){if(i.length===0){t.writeln(`Primary prompt: "${t.getPrompt()}"`),t.writeln(`Continuation prompt: "${t.getContinuationPrompt()}"`);return}const e=i[0];i.length>=2?(t.setPrompts(e,i[1]),t.writeln(`Prompts set to "${e}" and "${i[1]}"`)):(t.setPrompts(e),t.writeln(`Primary prompt set to "${e}"`))}async function ye(i){const t=i.getLastQueryResult();if(!t){i.writeln(d("No query result to copy"));return}const e=i.getOutputMode();let s;switch(e){case"csv":s=U(t.columns,t.rows);break;case"tsv":s=M(t.columns,t.rows);break;case"json":s=_(t.columns,t.rows);break;default:s=F(t.columns,t.rows)}await G(s)?i.writeln(u(`Copied ${t.rowCount} rows to clipboard (${e} format)`,b)):i.writeln(u("Failed to copy to clipboard",w))}class Se{constructor(t){a(this,"state",{query:null,currentPage:0,totalRows:0,pageSize:0,isActive:!1});a(this,"ctx");this.ctx=t}start(t,e,s){this.state={query:t,currentPage:0,totalRows:e,pageSize:s,isActive:!0}}exit(){this.state={query:null,currentPage:0,totalRows:0,pageSize:0,isActive:!1}}isActive(){return this.state.isActive}getState(){return this.state}getTotalPages(){return this.state.pageSize===0?0:Math.ceil(this.state.totalRows/this.state.pageSize)}getCurrentPageDisplay(){return this.state.currentPage+1}async executeCurrentPage(){if(!this.state.query)return;const t=this.state.currentPage*this.state.pageSize,e=`${this.state.query} LIMIT ${this.state.pageSize} OFFSET ${t}`;try{const s=await this.ctx.getDatabase().executeQuery(e);this.ctx.displayResult(s,!1),this.showNavigationHint()}catch(s){const r=s instanceof Error?s.message:String(s);this.ctx.writeln(u(`Error: ${r}`,w))}}showNavigationHint(){const t=this.getTotalPages();this.ctx.writeln(""),this.ctx.writeln(d(`Page ${this.getCurrentPageDisplay()}/${t} (${this.state.totalRows} rows) - n:next p:prev 1-${t}:goto q:quit`))}async handleInput(t){if(!this.state.isActive)return!1;const e=this.getTotalPages(),s=t.toLowerCase();if(s==="n"||t==="\x1B[B")return this.state.currentPage<e-1?(this.state.currentPage++,await this.executeCurrentPage()):this.ctx.writeln(d("Already on last page")),!0;if(s==="p"||t==="\x1B[A")return this.state.currentPage>0?(this.state.currentPage--,await this.executeCurrentPage()):this.ctx.writeln(d("Already on first page")),!0;if(s==="q"||s==="\x1B"||s==="")return this.ctx.writeln(""),this.exit(),!0;if(s==="\r"||s===`
|
|
29
|
+
`){const r=this.ctx.getInputContent().trim();if(r){const n=parseInt(r,10);!isNaN(n)&&n>=1&&n<=e?(this.state.currentPage=n-1,this.ctx.clearInput(),await this.executeCurrentPage()):(this.ctx.writeln(u(`Invalid page number. Enter 1-${e}`,w)),this.ctx.clearInput())}return!0}return/^\d$/.test(s)?(this.ctx.write(this.ctx.insertChar(s)),!0):s===""||s==="\b"?(this.ctx.write(this.ctx.backspace()),!0):!1}static shouldPaginate(t,e,s){return!(s===0||e<=s||!t.trim().toUpperCase().startsWith("SELECT")||/\b(LIMIT|OFFSET)\b/i.test(t))}static prepareQuery(t){return t.replace(/;\s*$/,"")}}async function bt(i){const t=new pt(i);return await t.start(),t}async function Le(i){return bt(i)}l.BOLD=V,l.DIM=K,l.Database=Y,l.DuckDBTerminal=pt,l.FG_BLUE=O,l.FG_CYAN=R,l.FG_GREEN=b,l.FG_RED=w,l.FG_WHITE=$,l.FG_YELLOW=N,l.HistoryStore=q,l.InputBuffer=Z,l.LinkProvider=ht,l.PaginationHandler=Se,l.RESET=P,l.TerminalAdapter=j,l.bold=S,l.colorize=u,l.containsURL=ee,l.copyToClipboard=G,l.createCommands=ae,l.createTerminal=bt,l.darkTheme=ct,l.dim=d,l.embed=Le,l.extractURLs=ie,l.formatCSV=U,l.formatJSON=_,l.formatTSV=M,l.formatTable=F,l.getSavedTheme=dt,l.getTheme=W,l.highlightSQL=x,l.isClipboardAvailable=Qt,l.isSQLComplete=Vt,l.isValidURL=se,l.lightTheme=ut,l.linkifyText=lt,l.readFromClipboard=ot,l.saveTheme=ft,l.tokenize=Q,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})}));
|