import Debug from '@prisma/debug' ; import { getEnginesPath } from '@prisma/engines' ; import type { ConnectorType , GeneratorConfig } from '@prisma/generator-helper' ; import type { Platform } from '@prisma/get-platform' ; import { getPlatform , platforms } from '@prisma/get-platform' ; import chalk from 'chalk' ; import type { ChildProcessByStdio } from 'child_process' ; import { spawn } from 'child_process' ; import EventEmitter from 'events' ; import execa from 'execa' ; import fs from 'fs' ; import net from 'net' ; import pRetry from 'p-retry' ; import path from 'path' ; import type { Readable } from 'stream' ; import { URL } from 'url' ; import { promisify } from 'util' ; import byline from '../tools/byline' ; import type { DatasourceOverwrite , EngineConfig , EngineEventType , GetConfigResult } from '../common/Engine' ; import { Engine } from '../common/Engine' ; import type { RequestError } from '../common/errors/types/RequestError' ; import { PrismaClientKnownRequestError } from '../common/errors/PrismaClientKnownRequestError' ; import { PrismaClientInitializationError } from '../common/errors/PrismaClientInitializationError' ; import { PrismaClientRustError } from '../common/errors/PrismaClientRustError' ; import { PrismaClientRustPanicError } from '../common/errors/PrismaClientRustPanicError' ; import { PrismaClientUnknownRequestError } from '../common/errors/PrismaClientUnknownRequestError' ; import { getErrorMessageWithLink } from '../common/errors/utils/getErrorMessageWithLink' ; import type { RustError , RustLog } from '../common/errors/utils/log' ; import { convertLog , getMessage , isRustError , isRustErrorLog } from '../common/errors/utils/log' ; import { omit } from '../tools/omit' ; import { printGeneratorConfig } from '../common/utils/printGeneratorConfig' ; import type { Result } from './Connection' ; import { Connection } from './Connection' ; import { fixBinaryTargets , getRandomString , plusX } from '../common/utils/util' ; import type * as Tx from '../common/types/Transaction' ; import type { QueryEngineRequestHeaders , QueryEngineResult } from '../common/types/QueryEngine' ; import type { IncomingHttpHeaders } from 'http' ; import { prismaGraphQLToJSError } from '../common/errors/utils/prismaGraphQLToJSError' ; const debug = Debug ( 'prisma:engine' ) ; const exists = promisify ( fs . exists ) ; const logger = ( ... args ) => { } ; /**
 * Node.js based wrapper to run the Prisma binary
 */ const knownPlatforms = [ ... platforms , 'native' ] ; export type Deferred = { resolve : ( ) => void ; reject : ( err : Error ) => void ; } ; export type StopDeferred = { resolve : ( code : number | null ) => void ; reject : ( err : Error ) => void ; } ; const engines = [ ] ; const socketPaths = [ ] ; const MAX_STARTS = process . env . PRISMA_CLIENT_NO_RETRY ? 1 : 2 ; const MAX_REQUEST_RETRIES = process . env . PRISMA_CLIENT_NO_RETRY ? 1 : 2 ; export class BinaryEngine extends Engine { private logEmitter : EventEmitter ; private showColors : boolean ; private logQueries : boolean ; private logLevel ? : 'info' | 'warn' ; private env ? : Record < string , string > ; private flags : string [ ] ; private port ? : number ; private enableDebugLogs : boolean ; private allowTriggerPanic : boolean ; private child ? : ChildProcessByStdio < null , Readable , Readable > ; private clientVersion ? : string ; private lastPanic ? : Error ; private globalKillSignalReceived ? : string ; private startCount = 0 ; private previewFeatures : string [ ] = [ ] ; private engineEndpoint ? : string ; private lastErrorLog ? : RustLog ; private lastRustError ? : RustError ; private useUds = false ; private socketPath ? : string ; private getConfigPromise ? : Promise < GetConfigResult > ; private stopPromise ? : Promise < void > ; private beforeExitListener ? : ( ) => Promise < void > ; private dirname ? : string ; private cwd : string ; private datamodelPath : string ; private prismaPath ? : string ; private stderrLogs = '' ; private currentRequestPromise ? : any ; private platformPromise ? : Promise < Platform > ; private platform ? : Platform | string ; private generator ? : GeneratorConfig ; private incorrectlyPinnedBinaryTarget ? : string ; private datasources ? : DatasourceOverwrite [ ] ; private startPromise ? : Promise < void > ; private versionPromise ? : Promise < string > ; private engineStartDeferred ? : Deferred ; private engineStopDeferred ? : StopDeferred ; private connection : Connection ; private lastQuery ? : string ; private lastVersion ? : string ; private lastActiveProvider ? : ConnectorType ; private activeProvider ? : string ; /**
     * exiting is used to tell the .on('exit') hook, if the exit came from our script.
     * As soon as the Prisma binary returns a correct return code (like 1 or 0), we don't need this anymore
     */ constructor ( { cwd , datamodelPath , prismaPath , generator , datasources , showColors , logLevel , logQueries , env , flags , clientVersion , previewFeatures , engineEndpoint , enableDebugLogs , allowTriggerPanic , dirname , useUds , activeProvider , } ) { super ( ) ; this . dirname = dirname ; this . useUds = useUds ?? false ; this . env = env ; this . cwd = this . resolveCwd ( cwd ) ; this . enableDebugLogs = enableDebugLogs ?? false ; this . allowTriggerPanic = allowTriggerPanic ?? false ; this . datamodelPath = datamodelPath ; this . prismaPath = process . env . PRISMA_QUERY_ENGINE_BINARY ?? prismaPath ; this . generator = generator ; this . datasources = datasources ; this . logEmitter = new EventEmitter ( ) ; this . logEmitter . on ( 'error' , ( ) => { } ) ; this . showColors = showColors ?? false ; this . logLevel = logLevel ; this . logQueries = logQueries ?? false ; this . clientVersion = clientVersion ; this . flags = flags ?? [ ] ; this . previewFeatures = previewFeatures ?? [ ] ; this . activeProvider = activeProvider ; this . connection = new Connection ( ) ; initHooks ( ) ; const removedFlags = [ 'middlewares' , 'aggregateApi' , 'distinct' , 'aggregations' , 'insensitiveFilters' , 'atomicNumberOperations' , 'transactionApi' , 'transaction' , 'connectOrCreate' , 'uncheckedScalarInputs' , 'nativeTypes' , 'createMany' , 'groupBy' , 'referentialActions' , 'microsoftSqlServer' , ] ; const removedFlagsUsed = this . previewFeatures . filter ( ( e ) => removedFlags . includes ( e ) ) ; if ( removedFlagsUsed . length > 0 && ! process . env . PRISMA_HIDE_PREVIEW_FLAG_WARNINGS ) { console . log ( `${ chalk . blueBright ( 'info' ) } The preview flags \`${ removedFlagsUsed . join ( '`, `' ) }\` were removed, you can now safely remove them from your schema.prisma.` ) ; } this . previewFeatures = this . previewFeatures . filter ( ( e ) => ! removedFlags . includes ( e ) ) ; this . engineEndpoint = engineEndpoint ; if ( engineEndpoint ) { const url = new URL ( engineEndpoint ) ; this . port = Number ( url . port ) ; } if ( this . platform ) { if ( ! knownPlatforms . includes ( this . platform as Platform ) && ! fs . existsSync ( this . platform ) ) { throw new PrismaClientInitializationError ( `Unknown ${ chalk . red ( 'PRISMA_QUERY_ENGINE_BINARY' ) } ${ chalk . redBright . bold ( this . platform ) }. Possible binaryTargets: ${ chalk . greenBright ( knownPlatforms . join ( ', ' ) ) } or a path to the query engine binary.
You may have to run ${ chalk . greenBright ( 'prisma generate' ) } for your changes to take effect.` , this . clientVersion ! ) ; } } else { void this . getPlatform ( ) ; } if ( this . enableDebugLogs ) { Debug . enable ( '*' ) ; } engines . push ( this ) ; this . checkForTooManyEngines ( ) ; } private setError ( err ) { if ( isRustError ( err ) ) { this . lastRustError = err ; this . logEmitter . emit ( 'error' , new PrismaClientRustError ( { clientVersion : this . clientVersion ! , error : err , } ) ) ; if ( err . is_panic ) { this . handlePanic ( ) ; } } else if ( isRustErrorLog ( err ) ) { this . lastErrorLog = err ; this . logEmitter . emit ( 'error' , new PrismaClientRustError ( { clientVersion : this . clientVersion ! , log : err , } ) ) ; if ( err . fields ?. message === 'PANIC' ) { this . handlePanic ( ) ; } } else { this . logEmitter . emit ( 'error' , err ) ; } } private checkForTooManyEngines ( ) { if ( engines . length >= 10 ) { const runningEngines = engines . filter ( ( e ) => e . child ) ; if ( runningEngines . length === 10 ) { console . warn ( `${ chalk . yellow ( 'warn(prisma-client)' ) } There are already 10 instances of Prisma Client actively running.` ) ; } } } private resolveCwd ( cwd ? ) { if ( cwd && fs . existsSync ( cwd ) && fs . lstatSync ( cwd ) . isDirectory ( ) ) { return cwd ; } return process . cwd ( ) ; } on ( event , listener ) { if ( event === 'beforeExit' ) { this . beforeExitListener = listener ; } else { this . logEmitter . on ( event , listener ) ; } } async emitExit ( ) { if ( this . beforeExitListener ) { try { await this . beforeExitListener ( ) ; } catch ( e ) { console . error ( e ) ; } } } private async getPlatform ( ) { if ( this . platformPromise ) { return this . platformPromise ; } this . platformPromise = getPlatform ( ) ; return this . platformPromise ; } private getQueryEnginePath ( platform , prefix = __dirname ) { let queryEnginePath = path . join ( prefix , `query-engine-${ platform }` ) ; if ( platform === 'windows' ) { queryEnginePath = `${ queryEnginePath }.exe` ; } return queryEnginePath ; } private handlePanic ( ) { this . child ?. kill ( ) ; if ( this . currentRequestPromise ?. cancel ) { this . currentRequestPromise . cancel ( ) ; } } private async resolvePrismaPath ( ) { const searchedLocations = [ ] ; let enginePath ; if ( this . prismaPath ) { return { prismaPath : this . prismaPath , searchedLocations } ; } const platform = await this . getPlatform ( ) ; if ( this . platform && this . platform !== platform ) { this . incorrectlyPinnedBinaryTarget = this . platform ; } this . platform = this . platform || platform ; if ( __filename . includes ( 'BinaryEngine' ) ) { enginePath = this . getQueryEnginePath ( this . platform , getEnginesPath ( ) ) ; return { prismaPath : enginePath , searchedLocations } ; } const searchLocations = [ eval ( `require('path').join(__dirname, '../../../.prisma/client')` ) , this . generator ?. output ?. value ?? eval ( '__dirname' ) , path . join ( eval ( '__dirname' ) , '..' ) , path . dirname ( this . datamodelPath ) , this . cwd , '/tmp/prisma-engines' , ] ; if ( this . dirname ) { searchLocations . push ( this . dirname ) ; } for ( const location of searchLocations ) { searchedLocations . push ( location ) ; debug ( `Search for Query Engine in ${ location }` ) ; enginePath = this . getQueryEnginePath ( this . platform , location ) ; if ( fs . existsSync ( enginePath ) ) { return { prismaPath : enginePath , searchedLocations } ; } } enginePath = this . getQueryEnginePath ( this . platform ) ; return { prismaPath : enginePath ?? '' , searchedLocations } ; } private async getPrismaPath ( ) { const { prismaPath , searchedLocations } = await this . resolvePrismaPath ( ) ; const platform = await this . getPlatform ( ) ; if ( ! ( await exists ( prismaPath ) ) ) { const pinnedStr = this . incorrectlyPinnedBinaryTarget ? `\nYou incorrectly pinned it to ${ chalk . redBright . bold ( `${ this . incorrectlyPinnedBinaryTarget }` ) }\n` : '' ; let errorText = `Query engine binary for current platform "${ chalk . bold ( platform ) }" could not be found.${ pinnedStr }
This probably happens, because you built Prisma Client on a different platform.
(Prisma Client looked in "${ chalk . underline ( prismaPath ) }")

Searched Locations:

${ searchedLocations . map ( ( f ) => { let msg = `  ${ f }` ; if ( process . env . DEBUG === 'node-engine-search-locations' && fs . existsSync ( f ) ) { const dir = fs . readdirSync ( f ) ; msg += dir . map ( ( d ) => `    ${ d }` ) . join ( '\n' ) ; } return msg ; } ) . join ( '\n' + ( process . env . DEBUG === 'node-engine-search-locations' ? '\n' : '' ) ) }\n` ; if ( this . generator ) { if ( this . generator . binaryTargets . find ( ( object ) => object . value === this . platform ! ) || this . generator . binaryTargets . find ( ( object ) => object . value === 'native' ) ) { errorText += `
You already added the platform${ this . generator . binaryTargets . length > 1 ? 's' : '' } ${ this . generator . binaryTargets . map ( ( t ) => `"${ chalk . bold ( t . value ) }"` ) . join ( ', ' ) } to the "${ chalk . underline ( 'generator' ) }" block
in the "schema.prisma" file as described in https://pris.ly/d/client-generator,
but something went wrong. That's suboptimal.

Please create an issue at https://github.com/prisma/prisma/issues/new` ; errorText += `` ; } else { errorText += `\n\nTo solve this problem, add the platform "${ this . platform }" to the "${ chalk . underline ( 'binaryTargets' ) }" attribute in the "${ chalk . underline ( 'generator' ) }" block in the "schema.prisma" file:
${ chalk . greenBright ( this . getFixedGenerator ( ) ) }

Then run "${ chalk . greenBright ( 'prisma generate' ) }" for your changes to take effect.
Read more about deploying Prisma Client: https://pris.ly/d/client-generator` ; } } else { errorText += `\n\nRead more about deploying Prisma Client: https://pris.ly/d/client-generator\n` ; } throw new PrismaClientInitializationError ( errorText , this . clientVersion ! ) ; } if ( this . incorrectlyPinnedBinaryTarget ) { console . error ( `${ chalk . yellow ( 'Warning:' ) } You pinned the platform ${ chalk . bold ( this . incorrectlyPinnedBinaryTarget ) }, but Prisma Client detects ${ chalk . bold ( await this . getPlatform ( ) ) }.
This means you should very likely pin the platform ${ chalk . greenBright ( await this . getPlatform ( ) ) } instead.
${ chalk . dim ( "In case we're mistaken, please report this to us 🙏." ) }` ) ; } if ( process . platform !== 'win32' ) { plusX ( prismaPath ) ; } return prismaPath ; } private getFixedGenerator ( ) { const fixedGenerator = { ... this . generator ! , binaryTargets : fixBinaryTargets ( this . generator ! . binaryTargets , this . platform ! ) , } ; return printGeneratorConfig ( fixedGenerator ) ; } private printDatasources ( ) { if ( this . datasources ) { return JSON . stringify ( this . datasources ) ; } return '[]' ; } /**
     * Starts the engine, returns the url that it runs on
     */ async start ( ) { if ( this . stopPromise ) { await this . stopPromise ; } if ( ! this . startPromise ) { this . startCount ++ ; this . startPromise = this . internalStart ( ) ; } await this . startPromise ; if ( ! this . child && ! this . engineEndpoint ) { throw new PrismaClientUnknownRequestError ( `Can't perform request, as the Engine has already been stopped` , this . clientVersion ! ) ; } return this . startPromise ; } private getEngineEnvVars ( ) { const env = { PRISMA_DML_PATH : this . datamodelPath , RUST_BACKTRACE : '1' , RUST_LOG : 'info' , } ; if ( this . logQueries || this . logLevel === 'info' ) { env . RUST_LOG = 'info' ; if ( this . logQueries ) { env . LOG_QUERIES = 'true' ; } } if ( this . datasources ) { env . OVERWRITE_DATASOURCES = this . printDatasources ( ) ; } if ( ! process . env . NO_COLOR && this . showColors ) { env . CLICOLOR_FORCE = '1' ; } return { ... this . env , ... process . env , ... env , } ; } private internalStart ( ) { return new Promise ( async ( resolve , reject ) => { await new Promise ( ( r ) => process . nextTick ( r ) ) ; if ( this . stopPromise ) { await this . stopPromise ; } if ( this . engineEndpoint ) { try { await pRetry ( ( ) => this . connection . get ( '/' ) , { retries : 10 , } ) ; } catch ( e ) { return reject ( e ) ; } return resolve ( ) ; } try { if ( this . child ?. connected || ( this . child && ! this . child ?. killed ) ) { debug ( `There is a child that still runs and we want to start again` ) ; } this . lastRustError = undefined ; this . lastErrorLog = undefined ; this . lastPanic = undefined ; logger ( 'startin & resettin' ) ; this . globalKillSignalReceived = undefined ; if ( this . useUds ) { this . socketPath = `/tmp/prisma-${ getRandomString ( ) }.sock` ; socketPaths . push ( this . socketPath ) ; } debug ( { cwd : this . cwd } ) ; const prismaPath = await this . getPrismaPath ( ) ; const additionalFlag = this . allowTriggerPanic ? [ '--debug' ] : [ ] ; const flags = [ '--enable-raw-queries' , ... this . flags , ... additionalFlag ] ; if ( this . useUds ) { flags . push ( '--unix-path' , this . socketPath ! ) ; } else { this . port = await this . getFreePort ( ) ; flags . push ( '--port' , String ( this . port ) ) ; } debug ( { flags } ) ; const env = this . getEngineEnvVars ( ) ; this . child = spawn ( prismaPath , flags , { env , cwd : this . cwd , windowsHide : true , stdio : [ 'ignore' , 'pipe' , 'pipe' ] , } ) ; byline ( this . child . stderr ) . on ( 'data' , ( msg ) => { const data = String ( msg ) ; debug ( 'stderr' , data ) ; try { const json = JSON . parse ( data ) ; if ( typeof json . is_panic !== 'undefined' ) { debug ( json ) ; this . setError ( json ) ; if ( this . engineStartDeferred ) { const err = new PrismaClientInitializationError ( json . message , this . clientVersion ! ) ; this . engineStartDeferred . reject ( err ) ; } } } catch ( e ) { if ( ! data . includes ( 'Printing to stderr' ) && ! data . includes ( 'Listening on ' ) ) { this . stderrLogs += '\n' + data ; } } } ) ; byline ( this . child . stdout ) . on ( 'data' , ( msg ) => { const data = String ( msg ) ; try { const json = JSON . parse ( data ) ; debug ( 'stdout' , getMessage ( json ) ) ; if ( this . engineStartDeferred && json . level === 'INFO' && json . target === 'query_engine::server' && json . fields ?. message ?. startsWith ( 'Started http server' ) ) { if ( this . useUds ) { this . connection . open ( 'http://127.0.0.1' , { socketPath : this . socketPath , } ) ; } else { this . connection . open ( `http://127.0.0.1:${ this . port }` ) ; } this . engineStartDeferred . resolve ( ) ; this . engineStartDeferred = undefined ; } if ( typeof json . is_panic === 'undefined' ) { const log = convertLog ( json ) ; const logIsRustErrorLog = isRustErrorLog ( log ) ; if ( logIsRustErrorLog ) { this . setError ( log ) ; } else { this . logEmitter . emit ( log . level , log ) ; } } else { this . setError ( json ) ; } } catch ( e ) { debug ( e , data ) ; } } ) ; this . child . on ( 'exit' , ( code ) : void => { logger ( 'removing startPromise' ) ; this . startPromise = undefined ; if ( this . engineStopDeferred ) { this . engineStopDeferred . resolve ( code ) ; return ; } this . connection . close ( ) ; if ( code !== 0 && this . engineStartDeferred && this . startCount === 1 ) { let err ; let msg = this . stderrLogs ; if ( this . lastRustError ) { msg = getMessage ( this . lastRustError ) ; } else if ( this . lastErrorLog ) { msg = getMessage ( this . lastErrorLog ) ; } if ( code !== null ) { err = new PrismaClientInitializationError ( `Query engine exited with code ${ code }\n` + msg , this . clientVersion ! ) ; } else if ( this . child ?. signalCode ) { err = new PrismaClientInitializationError ( `Query engine process killed with signal ${ this . child . signalCode } for unknown reason.
Make sure that the engine binary at ${ prismaPath } is not corrupt.\n` + msg , this . clientVersion ! ) ; } else { err = new PrismaClientInitializationError ( msg , this . clientVersion ! ) ; } this . engineStartDeferred . reject ( err ) ; } if ( ! this . child ) { return ; } if ( this . lastRustError ) { return ; } if ( code === 126 ) { this . setError ( { timestamp : new Date ( ) , target : 'exit' , level : 'error' , fields : { message : `Couldn't start query engine as it's not executable on this operating system.
You very likely have the wrong "binaryTarget" defined in the schema.prisma file.` , } , } ) ; } } ) ; this . child . on ( 'error' , ( err ) : void => { this . setError ( { message : err . message , backtrace : 'Could not start query engine' , is_panic : false , } ) ; reject ( err ) ; } ) ; this . child . on ( 'close' , ( code , signal ) : void => { this . connection . close ( ) ; if ( code === null && signal === 'SIGABRT' && this . child ) { const error = new PrismaClientRustPanicError ( this . getErrorMessageWithLink ( 'Panic in Query Engine with SIGABRT signal' ) , this . clientVersion ! ) ; this . logEmitter . emit ( 'error' , error ) ; } else if ( code === 255 && signal === null && this . lastErrorLog ?. fields . message === 'PANIC' && ! this . lastPanic ) { const error = new PrismaClientRustPanicError ( this . getErrorMessageWithLink ( `${ this . lastErrorLog . fields . message }: ${ this . lastErrorLog . fields . reason } in ${ this . lastErrorLog . fields . file }:${ this . lastErrorLog . fields . line }:${ this . lastErrorLog . fields . column }` ) , this . clientVersion ! ) ; this . setError ( error ) ; } } ) ; if ( this . lastRustError ) { return reject ( new PrismaClientInitializationError ( getMessage ( this . lastRustError ) , this . clientVersion ! ) ) ; } if ( this . lastErrorLog ) { return reject ( new PrismaClientInitializationError ( getMessage ( this . lastErrorLog ) , this . clientVersion ! ) ) ; } try { await new Promise < void > ( ( resolve , reject ) => { this . engineStartDeferred = { resolve , reject } ; } ) ; } catch ( err ) { this . child ?. kill ( ) ; throw err ; } void ( async ( ) => { try { const engineVersion = await this . version ( true ) ; debug ( `Client Version: ${ this . clientVersion }` ) ; debug ( `Engine Version: ${ engineVersion }` ) ; debug ( `Active provider: ${ this . activeProvider }` ) ; } catch ( e ) { debug ( e ) ; } } ) ( ) ; this . stopPromise = undefined ; resolve ( ) ; } catch ( e ) { reject ( e ) ; } } ) ; } async stop ( ) { if ( ! this . stopPromise ) { this . stopPromise = this . _stop ( ) ; } return this . stopPromise ; } /**
     * If Prisma runs, stop it
     */ async _stop ( ) { if ( this . startPromise ) { await this . startPromise ; } await new Promise ( ( resolve ) => process . nextTick ( resolve ) ) ; if ( this . currentRequestPromise ) { try { await this . currentRequestPromise ; } catch ( e ) { } } this . getConfigPromise = undefined ; let stopChildPromise ; if ( this . child ) { debug ( `Stopping Prisma engine4` ) ; if ( this . startPromise ) { debug ( `Waiting for start promise` ) ; await this . startPromise ; } debug ( `Done waiting for start promise` ) ; stopChildPromise = new Promise ( ( resolve , reject ) => { this . engineStopDeferred = { resolve , reject } ; } ) ; this . connection . close ( ) ; this . child ?. kill ( ) ; this . child = undefined ; } if ( stopChildPromise ) { await stopChildPromise ; } await new Promise ( ( r ) => process . nextTick ( r ) ) ; this . startPromise = undefined ; this . engineStopDeferred = undefined ; } kill ( signal ) { this . getConfigPromise = undefined ; this . globalKillSignalReceived = signal ; this . child ?. kill ( ) ; this . connection . close ( ) ; } /**
     * Use the port 0 trick to get a new port
     */ private getFreePort ( ) { return new Promise ( ( resolve , reject ) => { const server = net . createServer ( ( s ) => s . end ( '' ) ) ; server . unref ( ) ; server . on ( 'error' , reject ) ; server . listen ( 0 , ( ) => { const address = server . address ( ) ; const port = typeof address === 'string' ? parseInt ( address . split ( ':' ) . slice ( - 1 ) [ 0 ] , 10 ) : address ! . port ; server . close ( ( e ) => { if ( e ) { reject ( e ) ; } resolve ( port ) ; } ) ; } ) ; } ) ; } async getConfig ( ) { if ( ! this . getConfigPromise ) { this . getConfigPromise = this . _getConfig ( ) ; } return this . getConfigPromise ; } private async _getConfig ( ) { const prismaPath = await this . getPrismaPath ( ) ; const env = await this . getEngineEnvVars ( ) ; const result = await execa ( prismaPath , [ 'cli' , 'get-config' ] , { env : omit ( env , [ 'PORT' ] ) , cwd : this . cwd , } ) ; return JSON . parse ( result . stdout ) ; } async version ( forceRun = false ) { if ( this . versionPromise && ! forceRun ) { return this . versionPromise ; } this . versionPromise = this . internalVersion ( ) ; return this . versionPromise ; } async internalVersion ( ) { const prismaPath = await this . getPrismaPath ( ) ; const result = await execa ( prismaPath , [ '--version' ] ) ; this . lastVersion = result . stdout ; return this . lastVersion ; } async request < T > ( query , headers = { } , numTry = 1 ) { await this . start ( ) ; this . currentRequestPromise = this . connection . post ( '/' , stringifyQuery ( query ) , runtimeHeadersToHttpHeaders ( headers ) ) ; this . lastQuery = query ; try { const { data , headers } = await this . currentRequestPromise ; if ( data . errors ) { if ( data . errors . length === 1 ) { throw prismaGraphQLToJSError ( data . errors [ 0 ] , this . clientVersion ! ) ; } throw new PrismaClientUnknownRequestError ( JSON . stringify ( data . errors ) , this . clientVersion ! ) ; } const elapsed = parseInt ( headers [ 'x-elapsed' ] ) / 1000 ; if ( this . startCount > 0 ) { this . startCount = 0 ; } this . currentRequestPromise = undefined ; return { data , elapsed } as any ; } catch ( e ) { logger ( 'req - e' , e ) ; if ( e instanceof PrismaClientKnownRequestError ) { throw e ; } await this . handleRequestError ( e , numTry <= MAX_REQUEST_RETRIES ) ; if ( numTry <= MAX_REQUEST_RETRIES ) { logger ( 'trying a retry now' ) ; return this . request ( query , headers , numTry + 1 ) ; } } return null as any ; } async requestBatch < T > ( queries , headers = { } , transaction = false , numTry = 1 ) { await this . start ( ) ; const request = { batch : queries . map ( ( query ) => ( { query , variables : { } } ) ) , transaction , } ; this . lastQuery = JSON . stringify ( request ) ; this . currentRequestPromise = this . connection . post ( '/' , this . lastQuery , runtimeHeadersToHttpHeaders ( headers ) ) ; return this . currentRequestPromise . then ( ( { data , headers } ) => { const elapsed = parseInt ( headers [ 'x-elapsed' ] ) / 1000 ; const { batchResult , errors } = data ; if ( Array . isArray ( batchResult ) ) { return batchResult . map ( ( result ) => { if ( result . errors ) { throw prismaGraphQLToJSError ( data . errors [ 0 ] , this . clientVersion ! ) ; } return { data : result , elapsed , } ; } ) ; } else { throw prismaGraphQLToJSError ( data . errors [ 0 ] , this . clientVersion ! ) ; } } ) . catch ( async ( e ) => { const isError = await this . handleRequestError ( e , numTry < 3 ) ; if ( ! isError ) { if ( numTry <= MAX_REQUEST_RETRIES ) { return this . requestBatch ( queries , headers , transaction , numTry + 1 ) ; } } throw isError ; } ) ; } param action param options param info async transaction ( action , options ? ) ; async transaction ( action , info ) ; async transaction ( action , info ) ; async transaction ( action , arg ? ) { await this . start ( ) ; try { if ( action === 'start' ) { const jsonOptions = JSON . stringify ( { max_wait : arg ?. maxWait ?? 2000 , timeout : arg ?. timeout ?? 5000 , } ) ; const result = await Connection . onHttpError ( this . connection . post < Tx . Info > ( '/transaction/start' , jsonOptions ) , transactionHttpErrorHandler ) ; return result . data ; } else if ( action === 'commit' ) { await Connection . onHttpError ( this . connection . post ( `/transaction/${ arg . id }/commit` ) , transactionHttpErrorHandler ) ; } else if ( action === 'rollback' ) { await Connection . onHttpError ( this . connection . post ( `/transaction/${ arg . id }/rollback` ) , transactionHttpErrorHandler ) ; } } catch ( e ) { this . setError ( e ) ; } return undefined ; } private get hasMaxRestarts ( ) { return this . startCount >= MAX_STARTS ; } /**
     * If we have request errors like "ECONNRESET", we need to get the error from a
     * different place, not the request itself. This different place can either be
     * this.lastRustError or this.lastErrorLog
     */ private throwAsyncErrorIfExists ( forceThrow = false ) { logger ( 'throwAsyncErrorIfExists' , this . startCount , this . hasMaxRestarts ) ; if ( this . lastRustError ) { const err = new PrismaClientRustPanicError ( this . getErrorMessageWithLink ( getMessage ( this . lastRustError ) ) , this . clientVersion ! ) ; if ( this . lastRustError . is_panic ) { this . lastPanic = err ; } if ( this . hasMaxRestarts || forceThrow ) { throw err ; } } if ( this . lastErrorLog && isRustErrorLog ( this . lastErrorLog ) ) { const err = new PrismaClientUnknownRequestError ( this . getErrorMessageWithLink ( getMessage ( this . lastErrorLog ) ) , this . clientVersion ! ) ; if ( this . lastErrorLog ?. fields ?. message === 'PANIC' ) { this . lastPanic = err ; } if ( this . hasMaxRestarts || forceThrow ) { throw err ; } } } private getErrorMessageWithLink ( title ) { return getErrorMessageWithLink ( { platform : this . platform , title , version : this . clientVersion ! , engineVersion : this . lastVersion , database : this . lastActiveProvider , query : this . lastQuery ! , } ) ; } private handleRequestError = async ( error , graceful = false ) => { debug ( { error } ) ; if ( this . startPromise ) { await this . startPromise ; } this . throwAsyncErrorIfExists ( ) ; if ( this . currentRequestPromise ?. isCanceled ) { this . throwAsyncErrorIfExists ( ) ; } else if ( error . code === 'ECONNRESET' || error . code === 'ECONNREFUSED' || error . code === 'UND_ERR_CLOSED' || error . code === 'UND_ERR_SOCKET' || error . code === 'UND_ERR_DESTROYED' || error . code === 'UND_ERR_ABORTED' || error . message . toLowerCase ( ) . includes ( 'client is destroyed' ) || error . message . toLowerCase ( ) . includes ( 'other side closed' ) || error . message . toLowerCase ( ) . includes ( 'the client is closed' ) ) { if ( this . globalKillSignalReceived && ! this . child ?. connected ) { throw new PrismaClientUnknownRequestError ( `The Node.js process already received a ${ this . globalKillSignalReceived } signal, therefore the Prisma query engine exited
and your request can't be processed.
You probably have some open handle that prevents your process from exiting.
It could be an open http server or stream that didn't close yet.
We recommend using the \`wtfnode\` package to debug open handles.` , this . clientVersion ! ) ; } this . throwAsyncErrorIfExists ( ) ; if ( this . startCount > MAX_STARTS ) { for ( let i = 0 ; i < 5 ; i ++ ) { await new Promise ( ( r ) => setTimeout ( r , 50 ) ) ; this . throwAsyncErrorIfExists ( true ) ; } throw new Error ( `Query engine is trying to restart, but can't.
Please look into the logs or turn on the env var DEBUG=* to debug the constantly restarting query engine.` ) ; } } if ( ! graceful ) { this . throwAsyncErrorIfExists ( true ) ; throw error ; } return false ; } ; } function stringifyQuery ( q ) { return `{"variables":{},"query":${ JSON . stringify ( q ) }}` ; } function hookProcess ( handler , exit = false ) { process . once ( handler as any , async ( ) => { for ( const engine of engines ) { await engine . emitExit ( ) ; engine . kill ( handler ) ; } engines . splice ( 0 , engines . length ) ; if ( socketPaths . length > 0 ) { for ( const socketPath of socketPaths ) { try { fs . unlinkSync ( socketPath ) ; } catch ( e ) { } } } if ( exit && process . listenerCount ( handler ) === 0 ) { process . exit ( ) ; } } ) ; } let hooksInitialized = false ; function initHooks ( ) { if ( ! hooksInitialized ) { hookProcess ( 'beforeExit' ) ; hookProcess ( 'exit' ) ; hookProcess ( 'SIGINT' , true ) ; hookProcess ( 'SIGUSR2' , true ) ; hookProcess ( 'SIGTERM' , true ) ; hooksInitialized = true ; } } param result function transactionHttpErrorHandler < R > ( result ) { throw result . data ; } param headers returns function runtimeHeadersToHttpHeaders ( headers ) { return Object . keys ( headers ) . reduce ( ( acc , runtimeHeaderKey ) => { let httpHeaderKey = runtimeHeaderKey ; if ( runtimeHeaderKey === 'transactionId' ) { httpHeaderKey = 'X-transaction-id' ; } acc [ httpHeaderKey ] = headers [ runtimeHeaderKey ] ; return acc ; } , { } as IncomingHttpHeaders ) ; }