@prisma/engine-core
Advanced tools
Comparing version 0.0.28 to 0.0.29
@@ -1,66 +0,23 @@ | ||
/// <reference types="node" /> | ||
import { ChildProcess } from 'child_process'; | ||
interface EngineConfig { | ||
prismaYmlPath?: string; | ||
prismaConfig?: string; | ||
datamodel: string; | ||
datamodelJson?: string; | ||
debug?: boolean; | ||
schemaInferrerPath?: string; | ||
prismaPath?: string; | ||
export declare class PhotonError extends Error { | ||
readonly message: string; | ||
readonly query?: string; | ||
readonly error?: any; | ||
readonly logs?: string; | ||
readonly isPanicked?: boolean; | ||
constructor(message: string, query?: string, error?: any, logs?: string, isPanicked?: boolean); | ||
} | ||
/** | ||
* Node.js based wrapper to run the Prisma binary | ||
* Engine Base Class used by Browser and Node.js | ||
*/ | ||
export declare class Engine { | ||
prismaYmlPath?: string; | ||
prismaConfig?: string; | ||
port?: number; | ||
debug: boolean; | ||
child?: ChildProcess; | ||
export declare abstract class Engine { | ||
/** | ||
* 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 | ||
* Starts the engine | ||
*/ | ||
exiting: boolean; | ||
managementApiEnabled: boolean; | ||
datamodelJson?: string; | ||
cwd: string; | ||
datamodel: string; | ||
schemaInferrerPath: string; | ||
prismaPath: string; | ||
url: string; | ||
startPromise: Promise<string>; | ||
errorLogs: string; | ||
static defaultSchemaInferrerPath: string; | ||
static defaultPrismaPath: string; | ||
constructor({ prismaConfig, datamodelJson, prismaYmlPath, datamodel, schemaInferrerPath, prismaPath, ...args }: EngineConfig); | ||
abstract start(): Promise<void>; | ||
/** | ||
* Resolve the prisma.yml | ||
*/ | ||
getPrismaYml(ymlPath: string): Promise<string>; | ||
/** | ||
* Starts the engine, returns the url that it runs on | ||
*/ | ||
start(): Promise<string>; | ||
/** | ||
* If Prisma runs, stop it | ||
*/ | ||
stop: () => void; | ||
/** | ||
* Use the port 0 trick to get a new port | ||
*/ | ||
protected getFreePort(): Promise<number>; | ||
/** | ||
* Replace the port in the Prisma Config | ||
*/ | ||
protected generatePrismaConfig(): string; | ||
/** | ||
* Make sure that our internal port is not conflicting with the prisma.yml's port | ||
* @param str config | ||
*/ | ||
protected trimPort(str: string): string; | ||
protected engineReady(): Promise<void>; | ||
request<T>(query: string): Promise<T>; | ||
handleErrors({ errors, query }: { | ||
abstract stop(): void; | ||
abstract request<T>(query: string): Promise<T>; | ||
abstract handleErrors({ errors, query }: { | ||
errors?: any; | ||
@@ -70,2 +27,1 @@ query: string; | ||
} | ||
export {}; |
"use strict"; | ||
var __rest = (this && this.__rest) || function (s, e) { | ||
var t = {}; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) | ||
t[p] = s[p]; | ||
if (s != null && typeof Object.getOwnPropertySymbols === "function") | ||
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { | ||
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) | ||
t[p[i]] = s[p[i]]; | ||
} | ||
return t; | ||
}; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const util_1 = require("util"); | ||
const child_process_1 = require("child_process"); | ||
const fs = __importStar(require("fs")); | ||
const path = __importStar(require("path")); | ||
const net = __importStar(require("net")); | ||
const debug_1 = __importDefault(require("debug")); | ||
const cross_fetch_1 = __importDefault(require("cross-fetch")); | ||
const getInternalDatamodelJson_1 = require("./getInternalDatamodelJson"); | ||
const debug = debug_1.default('engine'); | ||
const readFile = util_1.promisify(fs.readFile); | ||
class PhotonError extends Error { | ||
@@ -44,218 +13,9 @@ constructor(message, query, error, logs, isPanicked) { | ||
} | ||
exports.PhotonError = PhotonError; | ||
/** | ||
* Node.js based wrapper to run the Prisma binary | ||
* Engine Base Class used by Browser and Node.js | ||
*/ | ||
class Engine { | ||
constructor(_a) { | ||
var { prismaConfig, datamodelJson, prismaYmlPath, datamodel, schemaInferrerPath, prismaPath } = _a, args = __rest(_a, ["prismaConfig", "datamodelJson", "prismaYmlPath", "datamodel", "schemaInferrerPath", "prismaPath"]); | ||
/** | ||
* 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 | ||
*/ | ||
this.exiting = false; | ||
this.managementApiEnabled = false; | ||
this.errorLogs = ''; | ||
/** | ||
* If Prisma runs, stop it | ||
*/ | ||
this.stop = () => { | ||
if (this.child) { | ||
debug(`Stopping Prisma engine`); | ||
this.exiting = true; | ||
this.child.kill(); | ||
delete this.child; | ||
} | ||
}; | ||
this.prismaYmlPath = prismaYmlPath; | ||
this.prismaConfig = prismaConfig; | ||
this.cwd = prismaYmlPath ? path.dirname(this.prismaYmlPath) : process.cwd(); | ||
this.debug = args.debug || false; | ||
this.datamodelJson = datamodelJson; | ||
this.datamodel = datamodel; | ||
this.schemaInferrerPath = schemaInferrerPath || Engine.defaultSchemaInferrerPath; | ||
this.prismaPath = prismaPath || Engine.defaultPrismaPath; | ||
if (this.debug) { | ||
debug_1.default.enable('engine'); | ||
} | ||
this.startPromise = this.start(); | ||
} | ||
/** | ||
* Resolve the prisma.yml | ||
*/ | ||
async getPrismaYml(ymlPath) { | ||
return await readFile(ymlPath, 'utf-8'); | ||
} | ||
/** | ||
* Starts the engine, returns the url that it runs on | ||
*/ | ||
start() { | ||
if (this.startPromise) { | ||
return this.startPromise; | ||
} | ||
return new Promise(async (resolve, reject) => { | ||
this.port = await this.getFreePort(); | ||
this.prismaConfig = this.prismaConfig || (await this.getPrismaYml(this.prismaYmlPath)); | ||
const PRISMA_CONFIG = this.generatePrismaConfig(); | ||
const schemaEnv = {}; | ||
if (!this.datamodelJson) { | ||
this.datamodelJson = await getInternalDatamodelJson_1.getInternalDatamodelJson(this.datamodel, this.schemaInferrerPath); | ||
} | ||
debug(`Starting binary at ${this.prismaPath}`); | ||
const env = Object.assign({ PRISMA_CONFIG, PRISMA_SDL: this.datamodel, SERVER_ROOT: process.cwd(), PRISMA_INTERNAL_DATA_MODEL_JSON: this.datamodelJson }, schemaEnv); | ||
debug(env); | ||
this.child = child_process_1.spawn(this.prismaPath, [], { | ||
env, | ||
detached: false, | ||
cwd: this.cwd, | ||
}); | ||
this.child.stderr.on('data', d => { | ||
const str = d.toString(); | ||
this.errorLogs += str; | ||
debug(str); | ||
}); | ||
this.child.stdout.on('data', d => { | ||
debug(d.toString()); | ||
}); | ||
this.child.on('error', e => { | ||
this.errorLogs += e.toString(); | ||
debug(e); | ||
reject(e); | ||
}); | ||
this.child.on('exit', (code, e) => { | ||
if (code !== 0 && !this.exiting) { | ||
const debugString = this.debug | ||
? '' | ||
: 'Please enable "debug": true in the Engine constructor to get more insights.'; | ||
throw new Error(`Child exited with code ${code}${debugString}${e}`); | ||
} | ||
}); | ||
// Make sure we kill Rust when this process is being killed | ||
process.once('SIGTERM', this.stop); | ||
process.once('SIGINT', this.stop); | ||
process.once('uncaughtException', this.stop); | ||
process.once('unhandledRejection', this.stop); | ||
await this.engineReady(); | ||
const url = `http://localhost:${this.port}`; | ||
this.url = url; | ||
resolve(url); | ||
}); | ||
} | ||
/** | ||
* Use the port 0 trick to get a new port | ||
*/ | ||
getFreePort() { | ||
return new Promise((resolve, reject) => { | ||
const server = net.createServer(s => s.end('')); | ||
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); | ||
}); | ||
}); | ||
}); | ||
} | ||
/** | ||
* Replace the port in the Prisma Config | ||
*/ | ||
generatePrismaConfig() { | ||
return `port: ${this.port}\n${this.trimPort(this.prismaConfig)}`; | ||
} | ||
/** | ||
* Make sure that our internal port is not conflicting with the prisma.yml's port | ||
* @param str config | ||
*/ | ||
trimPort(str) { | ||
return str | ||
.split('\n') | ||
.filter(l => !l.startsWith('port:')) | ||
.join('\n'); | ||
} | ||
// TODO: Replace it with a simple tcp connection | ||
async engineReady() { | ||
let tries = 0; | ||
while (true) { | ||
try { | ||
const response = await cross_fetch_1.default(`http://localhost:${this.port}/datamodel`); | ||
await new Promise(r => setTimeout(r, 50)); // TODO: Try out lower intervals here, but we also don't want to spam it too much. | ||
if (response.ok) { | ||
debug(`Ready after try number ${tries}`); | ||
return; | ||
} | ||
} | ||
catch (e) { | ||
debug(e.message); | ||
if (tries >= 100) { | ||
throw e; | ||
} | ||
} | ||
finally { | ||
tries++; | ||
} | ||
} | ||
} | ||
async request(query) { | ||
if (!this.url) { | ||
await this.startPromise; // allows lazily connecting the client to Rust and Rust to the Datasource | ||
} | ||
return cross_fetch_1.default(this.url, { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
body: JSON.stringify({ query, variables: {}, operationName: '' }), | ||
}) | ||
.then(response => { | ||
if (!response.ok) { | ||
return response.text().then(body => { | ||
const { status, statusText } = response; | ||
this.handleErrors({ | ||
errors: { | ||
status, | ||
statusText, | ||
body, | ||
}, | ||
query, | ||
}); | ||
}); | ||
} | ||
else { | ||
return response.json().then(result => { | ||
const { data } = result; | ||
const errors = result.error || result.errors; | ||
if (errors) { | ||
return this.handleErrors({ | ||
errors, | ||
query, | ||
}); | ||
} | ||
return data; | ||
}); | ||
} | ||
}) | ||
.catch(errors => { | ||
if (!(errors instanceof PhotonError)) { | ||
return this.handleErrors({ errors, query }); | ||
} | ||
else { | ||
throw errors; | ||
} | ||
}); | ||
} | ||
handleErrors({ errors, query }) { | ||
const stringified = errors ? JSON.stringify(errors, null, 2) : null; | ||
const message = stringified.length > 0 ? stringified : `Error in prisma.\$\{rootField || 'query'}`; | ||
const isPanicked = this.errorLogs.includes('panicked'); | ||
if (isPanicked) { | ||
this.stop(); | ||
} | ||
throw new PhotonError(message, query, errors, this.errorLogs, isPanicked); | ||
} | ||
} | ||
Engine.defaultSchemaInferrerPath = path.join(__dirname, '../schema-inferrer-bin'); | ||
Engine.defaultPrismaPath = path.join(__dirname, '../prisma'); | ||
exports.Engine = Engine; | ||
//# sourceMappingURL=Engine.js.map |
@@ -1,2 +0,2 @@ | ||
export { Engine } from './Engine'; | ||
export { NodeEngine as Engine } from './NodeEngine'; | ||
export { getInternalDatamodelJson } from './getInternalDatamodelJson'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var Engine_1 = require("./Engine"); | ||
exports.Engine = Engine_1.Engine; | ||
var NodeEngine_1 = require("./NodeEngine"); | ||
exports.Engine = NodeEngine_1.NodeEngine; | ||
var getInternalDatamodelJson_1 = require("./getInternalDatamodelJson"); | ||
exports.getInternalDatamodelJson = getInternalDatamodelJson_1.getInternalDatamodelJson; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@prisma/engine-core", | ||
"version": "0.0.28", | ||
"version": "0.0.29", | ||
"license": "Apache-2.0", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
38528
20
636
5