@electric-sql/pglite
Version:
PGlite is a WASM Postgres build packaged into a TypeScript client library that enables you to run Postgres in the browser, Node.js and Bun, with no need to install any other dependencies. It is only 3.7mb gzipped.
10 lines (9 loc) • 15.3 kB
HTML
<html lang=en-us><head><meta charset=utf-8><meta content="text/html; charset=utf-8"http-equiv=Content-Type><title>PG SHELL TEST</title><style>.emscripten{padding-right:0;margin-left:auto;margin-right:auto;display:block}textarea.emscripten{font-family:monospace;width:80%}div.emscripten{text-align:center}div.emscripten_border{border:1px solid #000}canvas.emscripten{border:0 none;background-color:#000}.spinner{height:50px;width:50px;margin:0 auto;-webkit-animation:rotation .8s linear infinite;-moz-animation:rotation .8s linear infinite;-o-animation:rotation .8s linear infinite;animation:rotation .8s linear infinite;border-left:10px solid #0096f0;border-right:10px solid #0096f0;border-bottom:10px solid #0096f0;border-top:10px solid #6400c8;border-radius:100%;background-color:#c864fa}@-webkit-keyframes rotation{from{-webkit-transform:rotate(0)}to{-webkit-transform:rotate(360deg)}}@-moz-keyframes rotation{from{-moz-transform:rotate(0)}to{-moz-transform:rotate(360deg)}}@-o-keyframes rotation{from{-o-transform:rotate(0)}to{-o-transform:rotate(360deg)}}@keyframes rotation{from{transform:rotate(0)}to{transform:rotate(360deg)}}</style><link href=https://pmp-p.ddns.net/pglite-web/vt/xterm.js rel=prefetch><link href=https://pmp-p.ddns.net/pglite-web/vt/xterm-addon-image.js rel=prefetch><link href=https://pmp-p.ddns.net/pglite-web/vtx.js rel=prefetch><link href=https://pmp-p.ddns.net/pglite-web/tinytar.min.js rel=prefetch><link href=https://pmp-p.ddns.net/wasi/dinovm/defs.js rel=prefetch><link href=https://pmp-p.ddns.net/wasi/dinovm/easywasi.js rel=prefetch><script src=https://pmp-p.ddns.net/pglite-web/tinytar.min.js></script><script type=importmap>{
"imports": {
"pglite" : "./pglite.js",
"easywasi": "https://pmp-p.ddns.net/wasi/dinovm/easywasi.js"
}
}</script><script type=module>console.log(" ============= ES6 MODULE ============= ");import initModule from"pglite";async function pgl_conf(o,n){var t=[];for(const n of o.os.codec.decode(o.FS.readFile(o.PGDATA+"/postgresql.conf")).split("\n")){(e=n.trimStart().split("#")[0].trimEnd()).length<4||(e.startsWith("#")||t.push(e))}var r=[];for(var l in n){for(var s="",i=0;i<t.length;i++){var e;if((e=t[i]).startsWith(l)){s=e,t[i]="# "+e;break}}var c=[];n[l]instanceof Array?(s.length&&console.warn("// TODO extract array from old"),c=n[l]):c.push(n[l].toString());const o=`${l} = ${c.join(",")}`;r.push(o)}if(r.length){t.push(...r);for(const o of t)console.log(o);o.FS.unlink(o.PGDATA+"/postgresql.conf"),o.FS.writeFile(o.PGDATA+"/postgresql.conf",t.join("\n")),o.FS.syncfs(!1,(o=>{o&&console.error("pgl_conf:",o)})),console.log("Config file written at :",o.PGDATA+"/postgresql.conf")}}window.initModule=initModule,globalThis.pgl_conf=pgl_conf</script></head><body><hr><figure id=spinner style=overflow:visible><div class=spinner></div><center style=margin-top:.5em><strong>emscripten</strong></center></figure><div class=emscripten id=status>Downloading...</div><div class=emscripten><progress hidden id=progress max=100 value=0></progress></div><div class=emscripten_border hidden><canvas class=emscripten id=canvas oncontextmenu=event.preventDefault() tabindex=-1></canvas></div><hr><div class=emscripten hidden><input type=checkbox id=resize>Resize canvas <input type=checkbox id=pointerLock checked>Lock/hide mouse pointer <input type=button onclick='Module.requestFullscreen(document.getElementById("pointerLock").checked,document.getElementById("resize").checked)'value=Fullscreen></div><hr><pre>
pglite.wasi: <a download href=pglite.wasi>Download file</a>
pglite.wasi + filesystem: <a download href=pglite-wasi.tar.xz>Download file</a>
</pre><hr><div id=repl></div><hr><textarea class=emscripten id=output rows=20></textarea><hr><script defer>var statusElement=document.getElementById("status"),progressElement=document.getElementById("progress"),spinnerElement=document.getElementById("spinner");window.buffer_stdout="",window.flushed_stdout=!1;const PGUSER="postgres";try{globalThis.window.is_es6=!0}catch(e){globalThis.window.is_es6=!1}function jsimport(e,t){const n=document.createElement("script");n.setAttribute("type","text/javascript"),n.setAttribute("src",e),t||n.setAttribute("async",!0),document.head.appendChild(n)}async function boot(){function e(e){stderr_on&&(stderr_on=!1,buffer_stdout+="[0m");var t=4==e;if(t)flushed_stdout=!0;else{if(10==e){if(flushed_stdout)return void(flushed_stdout=!1);buffer_stdout+="\r\n",t=!0}flushed_stdout=!1}if(""!=buffer_stdout&&t){if(buffer_stdout.startsWith(s))console.info("[sixel image]"),vm.vt.sixel(buffer_stdout);else{if(buffer_stdout.startsWith("Looks like you are rendering"))return;vm.vt.xterm.write(o(buffer_stdout))}buffer_stdout=""}else t||(buffer_stdout+=String.fromCharCode(e))}function t(e){stderr_on||(stderr_on=!0,vm.vt.xterm.write("[1;3;31m")),10==e?(stderr_on&&(stderr_on=!1,vm.vt.xterm.write("[0m")),vm.vt.xterm.write("\r\n")):vm.vt.xterm.write(String.fromCharCode(e))}window.stderr_on=!1,window.fnc_stdout=e,window.fnc_stderr=t,window.fnc_stdin=function(){if(test_data.length>0){return test_data.shift()}return console.error("pump","EOF"),null},window.test_step=0,window.test_data=[];const n=new TextDecoder,s=String.fromCharCode(27)+"Pq";function o(e){for(var t=[],s=0;s<e.length;s+=1)t.push(e.substr(s,1).charCodeAt(0));return n.decode(new Uint8Array(t))}function a(e){var t=null;switch(test_step){case 0:t="SHOW client_encoding;SHOW shared_preload_libraries;";break;case 1:t="SELECT now(), current_database(), session_user, current_user;";break;case 2:t="\nCREATE TABLE IF NOT EXISTS test (\n id SERIAL PRIMARY KEY,\n number INT\n );\n INSERT INTO test (number) VALUES (42);\n";break;case 3:t="\nCREATE EXTENSION IF NOT EXISTS pg_ivm;\n";break;case 4:t="\nSELECT pgivm.create_immv('myview', 'SELECT * FROM test');\n";break;case 5:t="\nINSERT INTO test VALUES (43);\nSELECT * FROM myview;\nINSERT INTO test VALUES (44);\n";break;case 6:t="\nSELECT * FROM myview;\n"}null!=t?(test_step++,console.log("SQL:",t),vm.readline(t+"\n\n"),setTimeout(a,800)):console.log("SQL:End")}window.b_utf8=o;const r="/tmp/pglite/base";function i(e){e?console.error("fs callback : FS error",e):setTimeout(l,0)}async function l(){await u.load_package("vector","vector.tar.gz"),await u.load_package("uuid-ossp","uuid-ossp.tar.gz"),await u.load_package("pg_ivm","pg_ivm.tar.gz"),await u.load_package("pg_stat_statements","pg_stat_statements.tar.gz"),console.warn("calling initdb");const e=vm._pgl_initdb();console.warn("initdb ==",e);var t=!0;e?1&e?console.error("INITDB failed"):(2&e&&(console.log(" #1 initdb was called"),4&e?(console.log(" #2 found db"),12&e&&console.log(" #3 found db+user : switch user"),console.error("Invalid user ?"),t=!1):console.warn(" TODO: create db+user here / callback / throw "),vm.PGDATA=r,t&&await pgl_conf(vm,{shared_preload_libraries:["'pg_stat_statements'"],max_connections:"5",compute_query_id:"on",shared_buffers:"128kB","pg_stat_statements.max":"10000","pg_stat_statements.track":"all"})),vm._pgl_backend(),setTimeout(a,1500)):console.error("FATAL: INITDB failed to return value")}var c,d,u={WASM_PREFIX:"/tmp/pglite",PGDATA:"/tmp/pglite/base",copyFrom:function(e,t){console.warn("copyFrom:",e,t)},copyTo:function(e,t){console.warn("copyTo:",e,t)},load_pg_extension:function(e,t){tinyTar.untar(t).forEach((function(e){if(!e.name.startsWith(".")){const t=u.WASM_PREFIX+"/"+e.name;if(console.log(" + ",t),e.name.endsWith(".so")){console.warn(t,"scheduled for wasm streaming compilation");const n=(...e)=>{console.log("pgfs:ext OK",t,e)},s=(...e)=>{console.log("pgfs:ext FAIL",t,e)};u.FS.createPreloadedFile(function(e){const t=e.lastIndexOf("/");return t>0?e.substr(0,t):e}(t),e.name.split("/").pop(),e.data,!0,!0,n,s,!1),console.log("createPreloadedFile called for :",t)}else u.FS.writeFile(t,e.data)}})),console.warn("pgfs ext:end",e)},load_package:async function(e,t){var n,s;if(u.FS.analyzePath(t).exists?console.error("PGFS TODO: handle local archives",t):(console.warn("PGFS Fetching:",t),s=await fetch(t)),t.endsWith(".tar")){const e=await s.arrayBuffer();n=new Uint8Array(e)}else{const e=new DecompressionStream("gzip"),t=await s.blob();console.log("gzdata",t.size);const o=t.stream().pipeThrough(e);n=new Uint8Array(await new Response(o).arrayBuffer())}u.load_pg_extension(e,n)},arguments:["--single","postgres","--","PGDATA=/tmp/pglite/base","PREFIX=/tmp/pglite",`PGUSER=${PGUSER}`,"REPL=N"],config:{cdn:"https://pygame-web.github.io/archives/0.9/"},print:(d=document.getElementById("output"),d&&(d.value=""),(...e)=>{var t=e.join(" ");console.log(t),d&&(d.value+=t+"\n",d.scrollTop=d.scrollHeight)}),canvas:(c=document.getElementById("canvas"),c.addEventListener("webglcontextlost",(e=>{alert("WebGL context lost. You will need to reload the page."),e.preventDefault()}),!1),c),stdout:e,stderr:t,preRun:[function(e){console.log("prerun(js)",r),e.FS.mkdir(r),e.FS.mount(e.IDBFS,{autoPersist:!0},r)}],postRun:[function(e){console.log("postrun(js)"),e.FS.syncfs(!0,i)}],locateFile:function(e,t){return console.log("locateFile: "+e+" "+t),t+e},setStatus:e=>{if(u.setStatus.last||(u.setStatus.last={time:Date.now(),text:""}),e!==u.setStatus.last.text){var t=e.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/),n=Date.now();t&&n-u.setStatus.last.time<30||(u.setStatus.last.time=n,u.setStatus.last.text=e,t?(e=t[1],progressElement.value=100*parseInt(t[2]),progressElement.max=100*parseInt(t[4]),progressElement.hidden=!1,spinnerElement.hidden=!1):(progressElement.value=null,progressElement.max=null,progressElement.hidden=!0,e||(spinnerElement.hidden=!0)),statusElement.innerHTML=e)}},totalDependencies:0,monitorRunDependencies:e=>{this.totalDependencies=Math.max(this.totalDependencies,e),u.setStatus(e?"Preparing... ("+(this.totalDependencies-e)+"/"+this.totalDependencies+")":"All downloads complete.")},readline:function(e){const t=vm.os;if(e.startsWith("?"))return void setTimeout((async()=>{await t.exec("pg_dump","--help")}),0);if(e.startsWith("v"))return void setTimeout((async()=>{await t.exec("pg_dump","--version")}),0);if(e.startsWith("!"))return void setTimeout((async()=>{await t.exec("pg_dump","-U","postgres","--inserts","-j","1","-v","-c","-C","-f","/tmp/out.sql","--disable-dollar-quoting","postgres")}),0);const n=e.trimStart().trimEnd().split(" ");switch(cmd=n[0],arg=n.at(-1),console.log("CMD:",cmd,"ARG:",arg),cmd){case"rx":var s=arg;console.log("getting file:",s),filename=s.split("/").at(-1);const e=new Blob([vm.FS.readFile(s)]),n=window.document.createElement("a");return n.href=window.URL.createObjectURL(e,{oneTimeOnly:!0}),n.download=filename,document.body.appendChild(n),n.click(),void document.body.removeChild(n);case"cat":for(const e of t.codec.decode(vm.FS.readFile(arg)).split("\n"))vm.vt.xterm.write(e+"\r\n");return}if(e.startsWith("pg_dump "))console.log("RL:",e);else{console.warn("READLINE->postMessage:",e);var o={target:"custom",userData:{type:"stdin",data:e}};globalThis.worker?worker.postMessage(o):u.bc.onmessage(o)}}};u.setStatus("Downloading..."),window.onerror=()=>{u.setStatus("Exception thrown, see JavaScript console"),spinnerElement.style.display="none",u.setStatus=e=>{e&&console.error("[post-exception status] "+e)}},window.vm=u;const{WasmTerminal:p}=await import("https://pmp-p.ddns.net/pglite-web/vtx.js");u.vt=new p("repl",200,60,10),u.bc=new BroadcastChannel("pglite");const m="/tmp/pglite/base/.s.PGSQL.5432.lck.in",g="/tmp/pglite/base/.s.PGSQL.5432.out";u.bc.onmessage=e=>{const t=u.FS;if(e.userData){var n,s=e.userData.data;if(s.byteLength)console.log("binary data, using wire"),u._use_wire(1),n.set(s);else{u._use_wire(0);n=(new TextEncoder).encode(s)}!function(e,t,n){const s=e.byteLength;var o;if(n<0){u._interactive_write(0),t.writeFile(m,e),t.rename(m,"/tmp/pglite/base/.s.PGSQL.5432.in"),console.log("send_to_pglite(sf):",s),u._interactive_one();try{const e=t.stat(g);console.log("pgreply",e.size);var a=t.open(g,"r");o=new Uint8Array(e.size),t.read(a,o,0,e.size,0),t.close(a),t.unlink(g)}catch(e){console.log("REPL: no reply, see stdout",e)}}else{u._interactive_write(s),u.HEAPU8.set(e,n),console.log("send_to_pglite(cma):",s,"sent to",n),u._interactive_one();const t=s+2,a=t+u._interactive_read();o=u.HEAPU8.subarray(t,a)}}(n,t,u.cma_port||1)}else console.warn("BC(srv):",e)},is_es6?(window.Module=await initModule(u),u.os=await async_wasi_init(u.FS,null,null)):(window.Module=u,jsimport("pglite.js"),console.log("main:",u))}console.warn("ES6 ?",globalThis.window.is_es6),window.addEventListener("load",boot)</script><script type=module>async function fget(e){return await fetch(e).then((e=>e.arrayBuffer()))}const isObject=e=>!("object"!=typeof e||null===e||Array.isArray(e)||e instanceof RegExp||e instanceof Date||e instanceof Set||e instanceof Map),isMapping=e=>"object"==typeof e&&null!==e&&!Array.isArray(e)&&!(e instanceof RegExp)&&!(e instanceof Date)&&e instanceof Set&&e instanceof Map;function update(e,n){let s=new Map([...e]);return n.forEach(((e,n)=>{s.has(n)?s.set(n,combinedMap.get(n)+e):s.set(n,e)})),s}function os_system(e){}function os_sched_yield(){const e="/tmp/pglite/base/.s.PGSQL.5432.in";if(os.FS.analyzePath(e).exists){const n=os.FS.readFileSync(e);vm._interactive_one();const s=vm.FS.stat("/tmp/pglite/base/.s.PGSQL.5432.out");console.log("socket file",n.length,"pgreply",s.size)}else console.log("sched_yield - no aio")}function os_mkdir(e){os.FS.mkdir(e,{recursive:!0,mode:os.umask})}function os_listdir(e){var n=os.FS.readdir(e);console.log(`--------- ${e} -------------`);for(var s=0;s<n.length;s++)console.log(n[s]);console.log("------------------------------")}async function async_wasi_init(e,n,s){if(e||(await configure({mounts:{"/tmp":InMemory}}),e=fs),!e.statSync)for(let n of"\nappendFileSync\nfsyncSync\nlinkSync\nsetFlagsSync\nmkdirSync\nreaddirSync\nreadFileSync\nreadlinkSync\nrenameSync\nrmdirSync\nstatSync\nsymlinkSync\ntruncateSync\nunlinkSync\nutimesSync\nwriteFileSync\n".split("\n")){if(!n.length)continue;const s=n.slice(0,n.length-4);try{e[n]=e[s].bind(e)}catch(o){console.warn("EMSDK FS MISSING :",n,s),e[n]=((...e)=>(console.log("FS missing",n),!0)).bind(e)}}n&&await n(e);const o=new TextDecoder,t=new TextEncoder("utf-8");var i={umask:18,PATH:{},FS:e,system:os_system,codec:{decode:e=>o.decode(e),encode:e=>t.encode(e)},sched_yield:os_sched_yield,exec:os_exec,mkdir:os_mkdir,listdir:os_listdir};return s&&await s(i),globalThis.os=i,i}globalThis.async_wasi_init=async_wasi_init,console.log("Using wasi : easywasi"),console.log("---------------------");import{WasiPreview1}from"easywasi";async function os_exec(e,...n){var s={PWD:"/"};n.length&&isMapping(n[n.length-1])&&update(s,n.pop());var o=[e];o.push(...n);var t=new WasiPreview1({fs:os.FS,args:o,env:s});t.stdout=s.stdout||(e=>vm.vt.xterm.write(os.codec.decode(e)+"\r")),t.stderr=s.stderr||(e=>vm.vt.xterm.write("[1;3;31m"+os.codec.decode(e)+"[0m\r"));const i=`bin/${e}.wasm`;console.log("Loading wasi bin : ",e,"from",i,"in",vm),os.PATH[e]=await WebAssembly.instantiateStreaming(fetch(i),{wasi_snapshot_preview1:t});var c=os.PATH[e];c.wasi=t,c.cmdline=i+" "+n.join(" "),c.codec=s.encoding||os.codec,console.log(c);var a=0;try{a=t.start(c.instance.exports)}catch(e){console.trace(),console.warn("abnormal program termination",e)}return console.log(`${e} ${t.args} exit code = ${a}`),a}</script></body></html>