@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.
13 lines (10 loc) • 16.5 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>globalThis.is_es6=!0,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"));try{o.FS.syncfs(!1,(o=>{}))}catch(o){console.error("pgl_conf: exception",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>
pg_dump.wasm: <a download href=bin/pg_dump.wasm>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";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))}console.warn("ES6 ?",is_es6),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 r(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="SELECT now(),* FROM pg_timezone_names WHERE name = current_setting('TIMEZONE');";break;case 3:case 4: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 5:t="\nCREATE EXTENSION IF NOT EXISTS plpgsql;\nCREATE OR REPLACE PROCEDURE raise_exception() LANGUAGE plpgsql AS $$\nBEGIN\n RAISE 'exception';\nEND;\n$$;\nCREATE OR REPLACE FUNCTION safe_cast(text, anyelement) RETURNS anyelement AS $$\nBEGIN\n $0 := $1;\n RETURN $0;\n EXCEPTION WHEN OTHERS THEN\n RETURN $2;\nEND;\n$$ LANGUAGE plpgsql;\n";break;case 6:t="\nCALL raise_exception();\n";break;case 7:t="\nSELECT safe_cast('abc'::text, 42::numeric);\n"}null!=t?(test_step++,console.log("SQL:",t),vm.readline(t+"\n\n"),setTimeout(r,800)):console.log("SQL:End")}window.b_utf8=o;const a="/tmp/pglite/base";Error;function i(e){e?console.error("fs callback : FS error",e):(console.error("fs callback : populate FS async"),setTimeout(l,0))}async function l(){await m.load_package("pgcrypto","pgcrypto.tar.gz");const e=new URLSearchParams(window.location.search).get("dataDir");if(e){console.log("unpack",e,"to",a);const t=await c(e);tinyTar.untar(t).forEach((function(e){var t=e.name;if(t.startsWith("./")&&(t=t.substr(2)),t.length){const n=a+"/"+t;t.endsWith("/")?m.FS.analyzePath(n).exists||(console.log("FS mkdir: ",n,"from",e.name),vm.FS.mkdir(n)):(console.log(" + ",n,"from",e.name),m.FS.writeFile(n,e.data))}}))}console.warn("calling initdb");const t=vm._pgl_initdb();console.warn("initdb ==",t);var n=!1;t?1&t?console.error("INITDB failed"):(2&t&&(console.log(" #1 initdb was called"),4&t?(console.log(" #2 found db"),12&t&&console.log(" #3 found db+user : switch user"),console.error("Invalid user ?"),n=!1):console.warn(" TODO: create db+user here / callback / throw "),vm.PGDATA=a,n&&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(r,1500)):console.error("FATAL: INITDB failed to return value")}async function c(e){var t,n;if(m.FS.analyzePath(e).exists?console.error("PGFS TODO: handle local archives",e):(console.warn("PGFS Fetching:",e),n=await fetch(e)),e.endsWith(".tar")){const e=await n.arrayBuffer();t=new Uint8Array(e)}else{const e=new DecompressionStream("gzip"),s=await n.blob();console.log("gzdata",s.size);const o=s.stream().pipeThrough(e);t=new Uint8Array(await new Response(o).arrayBuffer())}return t}var d,u,m={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_package:async function(e,t){const n=c(t);tinyTar.untar(n).forEach((function(e){if(!e.name.startsWith(".")){const t=m.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)};m.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 m.FS.writeFile(t,e.data)}})),console.warn("load_package:done:",e)},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:(u=document.getElementById("output"),u&&(u.value=""),(...e)=>{var t=e.join(" ");console.log(t),u&&(u.value+=t+"\n",u.scrollTop=u.scrollHeight)}),canvas:(d=document.getElementById("canvas"),d.addEventListener("webglcontextlost",(e=>{alert("WebGL context lost. You will need to reload the page."),e.preventDefault()}),!1),d),stdout:e,stderr:t,preRun:[function(e){console.log("prerun(js), fs mount ",a),e.FS.mkdir(a),e.FS.mount(e.IDBFS,{autoPersist:!0},a)}],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(m.setStatus.last||(m.setStatus.last={time:Date.now(),text:""}),e!==m.setStatus.last.text){var t=e.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/),n=Date.now();t&&n-m.setStatus.last.time<30||(m.setStatus.last.time=n,m.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),m.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","-Z0","-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":console.warn(`cat "${arg}"`);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):m.bc.onmessage(o)}}};m.setStatus("Downloading..."),window.onerror=()=>{m.setStatus("Exception thrown, see JavaScript console"),spinnerElement.style.display="none",m.setStatus=e=>{e&&console.error("[post-exception status] "+e)}},window.vm=m;const{WasmTerminal:p}=await import("https://pmp-p.ddns.net/pglite-web/vtx.js");m.vt=new p("repl",200,55,16),m.bc=new BroadcastChannel("pglite");const g="/tmp/pglite/base/.s.PGSQL.5432.lock.in",f="/tmp/pglite/base/.s.PGSQL.5432.out";m.bc.onmessage=e=>{const t=m.FS;if(e.userData){var n,s=e.userData.data;if(s.byteLength)console.log("binary data, using wire"),m._use_wire(1),n.set(s);else{m._use_wire(0);n=(new TextEncoder).encode(s)}!function(e,t,n){const s=e.byteLength;var o;if(n<0)if(m._interactive_write(0),t.writeFile(g,e),t.rename(g,"/tmp/pglite/base/.s.PGSQL.5432.in"),console.log("send_to_pglite(sf):",s),m._interactive_one(),os.FS.analyzePath(f).exists){const e=t.stat(f);console.log("pgreply",e.size);var r=t.open(f,"r");o=new Uint8Array(e.size),t.read(r,o,0,e.size,0),t.close(r),t.unlink(f)}else console.log("REPL: no reply, see stdout",x);else{m._interactive_write(s),m.HEAPU8.set(e,n),console.log("send_to_pglite(cma):",s,"sent to",n),m._interactive_one();const t=s+2,r=t+m._interactive_read();o=m.HEAPU8.subarray(t,r)}}(n,t,m.cma_port||1)}else console.warn("BC(srv):",e)},is_es6?(window.Module=await initModule(m),m.os=await async_wasi_init(m.FS,null,null)):(globalThis.is_es6=!1,window.Module=m,jsimport("pglite.js"),console.log("main:",m))}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(){console.warn("--os_sched_yield--");const e="/tmp/pglite/base/.s.PGSQL.5432.lock.in",n="/tmp/pglite/base/.s.PGSQL.5432.in",s="/tmp/pglite/base/.s.PGSQL.5432.out";if(os.FS.analyzePath(e).exists&&(os.FS.rename(e,n),console.log("rename lock for send:",e,"->",n)),os.FS.analyzePath(n).exists){vm._use_wire(1),vm._interactive_write(0);var o=os.FS.readFileSync(n);if(console.log("os_sched_yield/send_to_pglite(sf):",n,o.byteLength),vm._interactive_one(),os.FS.analyzePath(s).exists){const e=os.FS.stat(s);console.log("socket file",o.length,"pgreply",e.size)}else console.warn("no reply from server")}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 : dinovm wasm32-wasi-preview1 (easywasi)"),console.log("---------------------");import{wasm32_wasi_preview1}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 wasm32_wasi_preview1({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 a=os.PATH[e];a.wasi=t,a.cmdline=i+" "+n.join(" "),a.codec=s.encoding||os.codec,console.log(a);var c=0;try{c=t.start(a.instance.exports)}catch(e){console.trace(),console.warn("abnormal program termination",e);c=new DataView(a.instance.exports.memory.buffer).getUint8(0)}return console.log(`${e} ${t.args} exit code = ${c}`),c}</script></body></html>