@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 b,d as v}from"./chunk-ITQ6ILGR.js";import{minLength as B,object as j,optional as K,parseJson as L,pipe as y,regex as R,safeParse as _,string as w,url as A}from"valibot";var S=/^(postgres|postgresql):\/\//,N=y(w(),L(),j({databaseUrl:y(w(),A(),R(S)),name:K(y(w(),B(1))),shadowDatabaseUrl:y(w(),A(),R(S))}));function Y(r){return Buffer.from(JSON.stringify(Object.fromEntries(Object.entries(r).sort(([[e],[n]])=>e.localeCompare(n)))),"utf8").toString("base64url")}function Q(r){let e=Buffer.from(r,"base64url").toString("utf8"),{issues:n,output:s,success:t}=_(N,e,{abortEarly:!0});return t?[null,s]:[n]}var X=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,m]=Q(o);if(a)throw new s(401,{message:"Invalid API Key",cause:a.join(", ")});let{databaseUrl:h,name:c,shadowDatabaseUrl:d}=m,l=e.get("name"),g=new URL(e.req.url).port;if(!c)throw new s(401,{message:`Wrong API Key; The Prisma Dev server running at port ${g} requires an API Key from a newer version of \`prisma dev\`. Check the "${l}" server's output for the updated \`DATABASE_URL\` value.`});if(c!==l)throw new s(401,{message:`Wrong API Key; The Prisma Dev server running at port ${g} is named "${l}", but the API Key is for "${c}"`});let{hostname:f,port:E}=new URL(h),{port:$}=e.get("db"),{hostname:C,port:D}=new URL(d),H=e.get("shadowDBPort");if(f!=="localhost"||Number(E)!==$||C!=="localhost"||Number(D)!==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:m}};import{spawn as U}from"child_process";import{once as F}from"events";import{mkdir as V}from"fs/promises";import{join as q}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:J,PRISMA_DEV_FORCE_ENGINE_BINARY_PATH:G,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=G||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=U(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 d=c.split(`
`).find(E=>E.includes("Started query engine http server"));if(!d)return;i.stdout.removeListener("data",a);let{fields:l}=JSON.parse(d);if(l==null)return n(new Error(`Unexpected data during initialization, "fields" are missing: ${c}`));let{ip:g,port:f}=l;if(g==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://${g}:${f}`})},m=c=>{this.#n=null,n(new p(String(c))),i.removeListener("exit",h),i.kill()};i.once("error",m);let h=(c,d)=>{this.#n=null,n(new p(`Query Engine exited with code ${c} and signal ${d}`))};return i.once("exit",h),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 V(n,{recursive:!0});let{binaryTarget:s}=this.#e.platform,t=s==="windows"?".exe":"",o=q(n,`query-engine-${s}${t}`);return this.#e.debug&&console.debug("[Query Engine] binary path",o),(J==="1"||await b(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 v(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 ue(r,e){return console.error(r),r instanceof p?e.json({EngineNotStarted:{reason:{EngineStartupError:{logs:[],msg:r.message}}}},500):r instanceof u?e.text(r.responseBody,r.statusCode):e.body(null,500)}var p=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{Y as a,X as b,O as c,x as d,ue as e};