@prisma/dev
Version:
A local Prisma Postgres server for development and testing
4 lines (3 loc) • 7.67 kB
JavaScript
import{a as P,c as v,d as b}from"./chunk-EPFUMVT3.js";import{minLength as D,object as j,optional as B,parseJson as K,pipe as y,regex as R,safeParse as L,string as w,url as S}from"valibot";var A=/^(postgres|postgresql):\/\//,_=y(w(),K(),j({databaseUrl:y(w(),S(),R(A)),name:B(y(w(),D(1))),shadowDatabaseUrl:y(w(),S(),R(A))}));function W(r){return Buffer.from(JSON.stringify(Object.fromEntries(Object.entries(r).sort(([[e],[n]])=>e.localeCompare(n)))),"utf8").toString("base64url")}function N(r){let e=Buffer.from(r,"base64url").toString("utf8"),{issues:n,output:s,success:t}=L(_,e,{abortEarly:!0});return t?[null,s]:[n]}var Y=async(r,e)=>{let{authorization:n}=r,{HTTPException:s}=await import("hono/http-exception");if(!n)throw new s(401,{message:"Missing API Key"});let[t,o="",i]=n.split(" ");if(t!=="Bearer"||i)throw new s(401,{message:"Invalid API Key"});let[a,p]=N(o);if(a)throw new s(401,{message:"Invalid API Key",cause:a.join(", ")});let{databaseUrl:m,name:c,shadowDatabaseUrl:l}=p,{name:d}=e.get("serverState");if(!c)throw new s(401,{message:`Wrong API Key; The Prisma Dev server running at port ${e.get("port")} requires an API Key from a newer version of \`prisma dev\`. Check the "${d}" server's output for the updated \`DATABASE_URL\` value.`});if(c!==d)throw new s(401,{message:`Wrong API Key; The Prisma Dev server running at port ${e.get("port")} is named "${d}", but the API Key is for "${c}"`});let{hostname:h,port:f}=new URL(m),{port:E}=e.get("db"),{hostname:$,port:C}=new URL(l),H=e.get("shadowDBPort");if(h!=="localhost"||Number(f)!==E||$!=="localhost"||Number(C)!==H)throw new s(401,{message:"Wrong API Key; Check your Prisma schema's `provider.url` value (probably defined in `.env`'s `DATABASE_URL` environment variable) is aligned with `prisma dev`'s output"});return{decodedAPIKey:p}};import{spawn as Q}from"child_process";import{once as F}from"events";import{mkdir as U}from"fs/promises";import{join as V}from"path";import{setTimeout as z}from"timers/promises";function O(r){let e,n,s=new Promise((i,a)=>{e=i,n=a}),t=i=>{t=o=null,n(i),r?.onRejected?.(i),r?.onFulfilled?.()},o=i=>{o=t=null,e(i),r?.onResolved?.(i),r?.onFulfilled?.()};return{isFulfilled:()=>o===t,promise:s,reject:i=>t?.(i),resolve:i=>o?.(i)}}import{process as M}from"std-env";var{PRISMA_DEV_FORCE_ENGINE_BINARY_DOWNLOAD:q,PRISMA_DEV_FORCE_ENGINE_BINARY_PATH:J,PRISMA_DEV_FORCE_NETWORK_DELAY_MS:I}=M.env,x=class r{static#t=new Map;#e;#n;constructor(e){this.#e=e,this.#n=null}static async get(e){let{debug:n}=e,s=`${e.schemaHash}:${e.clientVersion}`;try{let t=r.#t.get(s);if(t)return t;let o=new r(e);return r.#t.set(s,o),n&&console.debug("[Query Engine] starting...",e),await o.start(),n&&console.debug("[Query Engine] started!"),o}finally{r.stopAll(s)}}static async stopAll(e){let s=(await Promise.allSettled(Array.from(r.#t.entries()).filter(([t])=>t!==e).map(async([t,o])=>{try{await o.stop()}finally{r.#t.delete(t)}}))).filter(t=>t.status==="rejected").map(t=>t.reason);if(s.length>0)throw new AggregateError(s,"Failed to stop engines")}async commitTransaction(e,n){return await this.#i(e,n,"commit")}async request(e,n){let{url:s}=await this.start(),t=this.#s(n),o=await fetch(s,{body:typeof e=="string"?e:JSON.stringify(e),headers:{...t,"Content-Type":"application/json"},method:"POST"});if(!o.ok)throw await u.fromResponse(o);return await o.text()}async rollbackTransaction(e,n){return await this.#i(e,n,"rollback")}async startTransaction(e,n){let{url:s}=await this.start(),t=this.#s(n),o=await fetch(`${s}/transaction/start`,{body:JSON.stringify(e),headers:{...t,"Content-Type":"application/json"},method:"POST"});if(!o.ok)throw await u.fromResponse(o);return await o.json()}async start(){if(this.#n!=null)return await this.#n;let{promise:e,reject:n,resolve:s}=O();this.#n=e;let t=J||await this.#o();this.#e.debug&&console.debug("[Query Engine] spinning up at path...",t);let{proxySignals:o}=await import("foreground-child/proxy-signals"),i=Q(t,["--enable-raw-queries","--enable-telemetry-in-response","--port","0"],{env:{LOG_QUERIES:"y",PRISMA_DML:this.#e.base64Schema,QE_LOG_LEVEL:"TRACE",RUST_BACKTRACE:"1",RUST_LOG:"info"},stdio:["ignore","pipe","pipe"],windowsHide:!0});o(i),i.stderr.setEncoding("utf8"),i.stdout.setEncoding("utf8");let a=c=>{let l=c.split(`
`).find(E=>E.includes("Started query engine http server"));if(!l)return;i.stdout.removeListener("data",a);let{fields:d}=JSON.parse(l);if(d==null)return n(new Error(`Unexpected data during initialization, "fields" are missing: ${c}`));let{ip:h,port:f}=d;if(h==null||f==null)return n(new Error(`This version of query-engine is not compatible with minippg, "ip" and "port" are missing in the startup log entry.
Received data: ${c}`));s({childProcess:i,url:`http://${h}:${f}`})},p=c=>{this.#n=null,n(new g(String(c))),i.removeListener("exit",m),i.kill()};i.once("error",p);let m=(c,l)=>{this.#n=null,n(new g(`Query Engine exited with code ${c} and signal ${l}`))};return i.once("exit",m),i.stdout.on("data",a),this.#e.debug&&(i.stderr.on("data",console.error.bind(console,"[Query Engine]")),i.stdout.on("data",console.debug.bind(console,"[Query Engine]"))),await this.#n}async stop(){if(this.#n==null)return;let{childProcess:e}=await this.#n;e.exitCode==null&&e.signalCode==null&&(this.#n=null,e.kill(),await F(e,"exit"))}async#o(){this.#e.debug&&console.debug("[Query Engine] getting engine commit hash...");let e=await this.#r();this.#e.debug&&console.debug("[Query Engine] got engine commit hash",e);let n=P(this.#e.clientVersion,e);this.#e.debug&&console.debug("[Query Engine] cache directory path",n),await U(n,{recursive:!0});let{platform:s}=this.#e.platform,t=s==="windows"?".exe":"",o=V(n,`query-engine-${s}${t}`);return this.#e.debug&&console.debug("[Query Engine] binary path",o),(q==="1"||await v(o)===!1)&&await this.#a({commitHash:e,extension:t,engineBinaryPath:o}),o}async#r(){let e=await fetch(`https://registry.npmjs.org/@prisma/client/${this.#e.clientVersion}`);if(!e.ok)throw new Error(`Couldn't fetch package.json from npm registry, status code: ${e.status}`);let s=(await e.json()).devDependencies?.["@prisma/engines-version"];if(!s)throw new Error("Couldn't find engines version in package.json");let t=s.split(".").at(-1);if(!t)throw new Error("Couldn't find commit hash in engines version");return t}async#a(e){let{commitHash:n,extension:s,engineBinaryPath:t}=e,{binaryTarget:o}=this.#e.platform,i=`https://binaries.prisma.sh/all_commits/${n}/${o}/query-engine${s}.gz`;this.#e.debug&&console.debug("[Query Engine] downloading engine from url",i);let a=await fetch(i);if(!a.ok)throw new Error(`Couldn't download engine. URL: ${i}, status code: ${a.status}`);I&&await z(Number(I)),await b(await a.arrayBuffer(),t),this.#e.debug&&console.debug("[Query Engine] downloaded and saved at",t)}#s(e){let n={};for(let[s,t]of Object.entries(e))t!=null&&(n[s]=t);return n}async#i(e,n,s){let{url:t}=await this.#n,o=this.#s(n),i=await fetch(`${t}/transaction/${e}/${s}`,{headers:{...o,"Content-Type":"application/json"},method:"POST"});if(!i.ok)throw await u.fromResponse(i);try{return await i.json()}catch{return{}}}};function de(r,e){return console.error(r),r instanceof g?e.json({EngineNotStarted:{reason:{EngineStartupError:{logs:[],msg:r.message}}}},500):r instanceof u?e.text(r.responseBody,r.statusCode):e.body(null,500)}var g=class extends Error{name="EngineStartError"},u=class r extends Error{constructor(n,s,t){super(`${n}: Query Engine response status ${s}, body: ${t}`);this.action=n;this.statusCode=s;this.responseBody=t}name="EngineHttpError";static async fromResponse(n){let s=new URL(n.url),t=await n.text();return new r(s.pathname,n.status,t)}};export{W as a,Y as b,O as c,x as d,de as e};