UNPKG

@prisma/dev

Version:

A local Prisma Postgres server for development and testing

4 lines (3 loc) 8.54 kB
import{d as h,e as f,f as y}from"./chunk-OTI5SWIV.js";import{b as l,f as O,g as V,h as N,i as C}from"./chunk-ITQ6ILGR.js";import{writeFile as Q}from"fs/promises";import{join as c}from"pathe";import{check as W,lock as X,unlock as ee}from"proper-lockfile";import{process as j}from"std-env";import{integer as F,literal as te,minLength as re,minValue as q,number as H,object as v,optional as g,parseJson as se,pipe as m,safeParse as ae,string as w,url as oe}from"valibot";import{setTimeout as z}from"timers/promises";import{process as P}from"std-env";function x(r,e){if(r==null)return!1;try{return P.kill?.(r,0)??!0}catch(t){return e&&console.error(`Error checking if process with PID ${r} exists:`,t),!1}}async function A(r,e){if(!P.kill)return!1;try{P.kill(r,"SIGTERM")}catch(s){return e&&console.error(`Error killing process with PID ${r}:`,s),!1}let t=0;do{if(!x(r,e))return!0;await z(100)}while(++t<50);try{return P.kill(r,"SIGKILL")}catch(s){return e&&console.error(`Error forcefully killing process with PID ${r}:`,s),!1}}var _=m(w(),oe()),L=v({connectionString:_,prismaORMConnectionString:g(_),terminalCommand:g(w())}),J=v({url:_}),M=m(H(),F(),q(1)),ie=v({database:L,http:J,ppg:J,shadowDatabase:L}),ne=v({databasePort:M,exports:g(ie),name:m(w(),re(1)),pid:g(m(H(),F(),q(0))),port:M,shadowDatabasePort:M,version:te("1")}),E=Symbol("initialize"),k="default",u=class{_databasePort;databaseConnectTimeoutMillis;databaseIdleTimeoutMillis;debug;dryRun;name;persistenceMode;pid;shadowDatabaseConnectTimeoutMillis;shadowDatabaseIdleTimeoutMillis;_port;_shadowDatabasePort;constructor(e){this._databasePort=e.databasePort??f,this.databaseConnectTimeoutMillis=e.databaseConnectTimeoutMillis??6e4,this.databaseIdleTimeoutMillis=e.databaseIdleTimeoutMillis??1/0,this.debug=e.debug??!1,this.dryRun=e.dryRun??!1,this.name=e.name??k,this.persistenceMode=e.persistenceMode,this.pid=e.pid??j.pid,this.shadowDatabaseConnectTimeoutMillis=e.shadowDatabaseConnectTimeoutMillis??this.databaseConnectTimeoutMillis,this.shadowDatabaseIdleTimeoutMillis=e.shadowDatabaseIdleTimeoutMillis??this.databaseIdleTimeoutMillis,this._port=e.port??f,this._shadowDatabasePort=e.shadowDatabasePort??f}static async createExclusively(e){let t=e?.dryRun!==!0&&e?.persistenceMode==="stateful"?new p(e):new I(e);return await t[E](),t}static async fromServerDump(e){let{debug:t,name:s=k}=e??{},o=l(s),i=p.getServerDumpPath(o),a=await O(i);if(a==null)return t&&console.debug(`[State] No server dump file found at: ${i}`),null;t&&(console.debug(`[State] server dump file found at "${i}":`),console.debug(a));let{issues:n,output:d,success:b}=ae(m(w(),se(),ne),a);if(!b)throw t&&console.debug(`[State] Invalid server dump file at "${i}": ${JSON.stringify(n,null,2)}`),new Error(`Invalid Prisma Dev state for "${s}".`);return new p({databasePort:d.databasePort,debug:t,dryRun:!1,name:s,pid:d.pid,port:d.port,serverDump:d,shadowDatabasePort:d.shadowDatabasePort})}static async scan(e){let{debug:t,globs:s}=e??{},o=c(l(k),"..");t&&console.debug(`[State] scanning for server states in: ${o}`);let i=await N(o,s);return t&&console.debug(`[State] found server names: ${JSON.stringify(i)}`),await Promise.all(i.map(a=>K(a,e)))}get databasePort(){return this._databasePort}set databasePort(e){this.#t("databasePort",e)}get port(){return this._port}set port(e){this.#t("port",e)}get shadowDatabasePort(){return this._shadowDatabasePort}set shadowDatabasePort(e){this.#t("shadowDatabasePort",e)}#t(e,t){if(t<0||!Number.isInteger(t))throw new Error(`Invalid port number: ${t}`);let s=`_${e}`;if(this[s]!==h&&this[s]!==t)throw new Error(`\`${e}\` is already set to ${this[s]}, cannot change it to ${t}`);this[s]=t}},I=class extends u{constructor(e){super({...e,databasePort:e?.databasePort||h,persistenceMode:"stateless",port:e?.port||h,shadowDatabasePort:e?.shadowDatabasePort||h})}get databaseDumpPath(){return"<DUMP_PATH>"}get pgliteDataDirPath(){return"memory://"}async[E](){let e;try{e=await u.scan({debug:this.debug,onlyMetadata:!0})}catch(s){this.debug&&console.warn("[State] failed to scan for existing servers, assuming filesystem does not exist or other reasons.",s),e=[]}let t=await y({debug:this.debug,name:this.dryRun?this.name:"",requestedPorts:{databasePort:this.databasePort,port:this.port,shadowDatabasePort:this.shadowDatabasePort},servers:e});this._databasePort=t.databasePort,this._port=t.port,this._shadowDatabasePort=t.shadowDatabasePort}async close(){}async writeServerDump(){}},p=class r extends u{#t;#e;#s;#o;#i;#a;#r;constructor(e){super({...e,persistenceMode:"stateful"}),this.#a=!1,this.#e=l(this.name),this.#t=c(this.#e,"db_dump.bak"),this.#s=c(this.#e,".lock"),this.#o=c(this.#e,".pglite"),this.#r=e?.serverDump??null,this.#i=r.getServerDumpPath(this.#e)}static getServerDumpPath(e){return c(e,"server.json")}get databaseDumpPath(){return this.#t}get exports(){return this.#r?.exports}get pgliteDataDirPath(){return this.#o}async[E](){await V(this.#e),this.debug&&console.debug(`[State] using data directory: ${this.#e}`);try{await X(this.#e,{lockfilePath:this.#s}),this.debug&&console.debug(`[State] obtained lock on: ${this.#e}`);let e=await u.scan({debug:this.debug,onlyMetadata:!0}),t=await y({debug:this.debug,name:this.name,requestedPorts:{databasePort:this.databasePort,port:this.port,shadowDatabasePort:this.shadowDatabasePort},servers:e});this._databasePort=t.databasePort,this._port=t.port,this._shadowDatabasePort=t.shadowDatabasePort,await this.writeServerDump()}catch(e){throw e instanceof Error&&"code"in e&&e.code==="ELOCKED"?new T(this):e}}async close(){if(!this.#a)try{await ee(this.#e,{lockfilePath:this.#s}),this.#a=!0,this.debug&&console.debug(`[State] released lock on: ${this.#e}`)}catch(e){throw this.debug&&console.error(`[State] failed to release lock on: ${this.#e}`,e),e}}async writeServerDump(e){this.#r={name:this.name,version:"1",pid:j.pid,port:this.port,databasePort:this.databasePort,shadowDatabasePort:this.shadowDatabasePort,exports:e},await Q(this.#i,`${JSON.stringify(this.#r,null,2)} `,{encoding:"utf-8"})}};async function Se(r,e){await de(r,e);let t=l(typeof r=="string"?r:r.name);await C(t)}async function K(r,e){let{debug:t,onlyMetadata:s}=e||{},o=typeof r=="string"?r:r.name,i=typeof r!="string"?r:void 0,a={databasePort:i?.databasePort??-1,exports:i?.exports,name:o,pid:i?.pid,port:i?.port??-1,shadowDatabasePort:i?.shadowDatabasePort??-1,version:"1"};try{let n=i||await u.fromServerDump({debug:t,name:o});if(!n)return t&&console.debug(`[State] no server state found for name: ${o}`),{...a,status:"no_such_server"};a.databasePort=n.databasePort,a.exports=n.exports,a.pid=n.pid,a.port=n.port,a.shadowDatabasePort=n.shadowDatabasePort;let{exports:d,pid:b}=n;if(s)return{...a,status:"unknown"};if(!x(b,t))return t&&console.debug(`[State] server state for "${o}" has no running process with PID: ${b}`),{...a,status:"not_running"};let R=l(o);try{if(!await W(R,{lockfilePath:c(R,".lock")}))return t&&console.debug(`[State] server state for "${o}" is not locked, indicating it is not running.`),{...a,status:"starting_up"}}catch(G){t&&console.error(`[State] server state for "${o}" failed to check lock:`,G)}if(!d)return{...a,status:"starting_up"};let{http:Y}=d,{hc:B}=await import("hono/client"),D=await B(Y.url).health.$get();if(!D.ok)return t&&console.debug(`[State] server state for "${o}" is not live: ${JSON.stringify(D)}`),{...a,status:"not_running"};let S=await D.json();return S.name!==r?(t&&console.debug(`[State] server state for "${o}" has mismatched health response: ${JSON.stringify(S)}`),{...a,status:"unknown"}):(t&&console.debug(`[State] server state for "${r}" is live: ${JSON.stringify(S)}`),{...a,status:"running"})}catch(n){return t&&console.error(`[State] failed to get server status for "${o}":`,n),{...a,status:"error"}}}function ue(r){let{status:e}=r;return e==="running"||e==="starting_up"}async function de(r,e){let{pid:t,...s}=typeof r=="string"?await K(r,{debug:e}):r;if(!ue(s))return!1;let o=await u.fromServerDump({debug:e,name:s.name});if(t==null){e&&console.debug(`[State] No PID found for server "${s.name}" to kill.`);try{await o?.close()}catch{}return!1}let i=await A(t,e);try{await o?.close()}catch{}return i}var $=class extends Error{name="ServerStateAlreadyExistsError";constructor(e){super(`A Prisma Dev server with the name "${e}" is already running.`)}},T=class extends ${#t;name="ServerAlreadyRunningError";constructor(e){super(e.name),this.#t=e}get server(){return u.fromServerDump({debug:this.#t.debug,name:this.#t.name})}};export{u as a,Se as b,K as c,ue as d,de as e,$ as f,T as g};