UNPKG

@prisma/cli-init

Version:

Init CLI for Prisma

222 lines (215 loc) • 7.34 kB
import { createRequire } from 'node:module'; const require = createRequire(import.meta.url); import { Engine, apiKeyValidator, array, handleEngineError, integer, literal, looseObject, minLength, minValue, number, object, optional, pipe, safeParse, string, union } from "./chunk-ASMCGOOW.js"; import "./chunk-YX4UTTNJ.js"; // ../../dev/server/src/accelerate.ts import { Hono } from "hono/tiny"; import { validator } from "hono/validator"; // ../../dev/server/src/caching.ts var invalidateInputSchema = object({ tags: union([pipe(array(string()), minLength(1)), literal("all")]) }); async function assertInvalidateInput(ctx) { const { output, success } = safeParse(invalidateInputSchema, await ctx.req.json(), { abortEarly: true }); if (!success) { return ctx.text("Invalid input", 400); } return output; } // ../../dev/server/src/schema.ts import { Buffer } from "buffer"; var SCHEMAS_BY_HASH = /* @__PURE__ */ new Map(); async function hashSchema(base64Schema) { const encoder = new TextEncoder(); const data = encoder.encode(base64Schema); const hashBuffer = await crypto.subtle.digest("SHA-256", data); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join(""); return hashHex; } function assertSchema(ctx) { const schemaHash = ctx.req.param("schemaHash"); const schemas = SCHEMAS_BY_HASH.get(schemaHash); if (schemas == null) { return ctx.json({ EngineNotStarted: { reason: "SchemaMissing" } }, 404); } return { schemaHash, schemas }; } var datasourceBlockRegex = /datasource\s+db\s+\{\s*provider\s*=\s*"postgres(!?ql)?"\s+url\s*=\s*.+\s*\}/; async function overrideDatasource(base64Schema, connectionString) { const schema = Buffer.from(base64Schema, "base64").toString("utf8"); const override = `datasource db { provider = "postgresql" url = "${connectionString.toString()}" }`; const schemaWithOverride = schema.replace(datasourceBlockRegex, override); const overrideHash = await hashSchema(schemaWithOverride); return { base64Override: Buffer.from(schemaWithOverride, "utf8").toString("base64"), overrideHash }; } // ../../dev/server/src/tracing.ts function getTracingHeaders(ctx) { const { req } = ctx; return { traceparent: req.header("traceparent"), ["X-capture-telemetry"]: req.header("X-capture-telemetry") }; } // ../../dev/server/src/transaction.ts var transactionOptionsSchema = object({ isolation_level: optional(string()), max_wait: pipe(number(), integer(), minValue(0)), timeout: pipe(number(), integer(), minValue(0)) }); async function assertTransactionOptions(ctx) { const { issues, output, success } = safeParse(transactionOptionsSchema, await ctx.req.json(), { abortEarly: true }); if (!success) { return ctx.json({ EngineNotStarted: { reason: "InvalidRequest", issues } }, 400); } return output; } var transactionSchema = looseObject({ id: union([string(), number()]) }); function assertTransaction(thing, ctx) { const { output, success } = safeParse(transactionSchema, thing); if (!success) { return ctx.json({ EngineMalfunction: {} }, 500); } return output; } // ../../dev/server/src/accelerate.ts var accelerateRoute = new Hono(); accelerateRoute.post("/invalidate", validator("header", apiKeyValidator), async (ctx) => { const invlidateInput = await assertInvalidateInput(ctx); if (invlidateInput instanceof Response) { return invlidateInput; } return ctx.body(null); }); var SCHEMAFUL_BASE_PATH = "/:clientVersion/:schemaHash"; var schemafulRoute = accelerateRoute.basePath(SCHEMAFUL_BASE_PATH); accelerateRoute.route("/", schemafulRoute); var GRAPHQL_PATHS = ["/graphql", "/itx/:transactionId/graphql"]; schemafulRoute.on("POST", [...GRAPHQL_PATHS], validator("header", apiKeyValidator), async (ctx) => { const { req } = ctx; try { const engine = await getEngine(ctx); if (engine instanceof Response) { return engine; } const query = await req.text(); const transactionId = req.param("transactionId"); const results = await engine.request(query, { ...getTracingHeaders(ctx), ["X-transaction-id"]: transactionId }); return ctx.text(results); } catch (error) { return handleEngineError(error, ctx); } }); schemafulRoute.basePath("/itx/:transactionId").on("POST", ["/commit", "/rollback"], validator("header", apiKeyValidator), async (ctx) => { const { req } = ctx; try { const engine = await getEngine(ctx); if (engine instanceof Response) { return engine; } const action = req.routePath.split("/").filter(Boolean).at(-1); const method = `${action}Transaction`; const transactionId = req.param("transactionId"); const response = await engine[method](transactionId, getTracingHeaders(ctx)); return ctx.json(response); } catch (error) { return handleEngineError(error, ctx); } }); schemafulRoute.put("/schema", validator("header", apiKeyValidator), async (ctx) => { const { req } = ctx; const base64Schema = await req.text(); if (!base64Schema) { return ctx.text("Missing schema", 400); } const schemaHash = req.param("schemaHash"); const schemas = SCHEMAS_BY_HASH.get(schemaHash); if (schemas == null) { if (schemaHash !== await hashSchema(base64Schema)) { return ctx.text("Schema hash mismatch", 400); } const override = await overrideDatasource(base64Schema, ctx.get("db").prismaORMConnectionString); SCHEMAS_BY_HASH.set(schemaHash, { base64Original: base64Schema, ...override }); return ctx.text(schemaHash); } if (base64Schema !== schemas.base64Original) { return ctx.text("Schema mismatch", 400); } return ctx.text(schemaHash); }); schemafulRoute.post("/transaction/start", validator("header", apiKeyValidator), async (ctx) => { const { req } = ctx; const transactionOptions = await assertTransactionOptions(ctx); if (transactionOptions instanceof Response) { return transactionOptions; } try { const engine = await getEngine(ctx); if (engine instanceof Response) { return engine; } const response = await engine.startTransaction(transactionOptions, getTracingHeaders(ctx)); const transaction = assertTransaction(response, ctx); if (transaction instanceof Response) { return transaction; } const { id } = transaction; const clientVersion = req.param("clientVersion"); const port = ctx.get("port"); const protocol = ctx.get("protocol"); const schemaHash = req.param("schemaHash"); return ctx.json({ ...response, "data-proxy": { endpoint: `${protocol}://localhost:${port}/${clientVersion}/${schemaHash}/itx/${id}` } }); } catch (error) { return handleEngineError(error, ctx); } }); async function getEngine(ctx) { const { req } = ctx; const schema = assertSchema(ctx); if (schema instanceof Response) { return schema; } const { base64Override, overrideHash } = schema.schemas; return await Engine.get({ base64Schema: base64Override, clientVersion: process.env.PRISMA_DEV_FORCE_CLIENT_VERSION || req.param("clientVersion"), debug: ctx.get("debug"), platform: ctx.get("platform"), schemaHash: overrideHash }); } export { accelerateRoute };