Skip to main content
Glama

Prisma MCP Server

Official
by prisma
Apache 2.0
4
44,192
  • Linux
  • Apple
downloadZip.ts4.98 kB
import fs from 'node:fs' import path from 'node:path' import zlib from 'node:zlib' import Debug from '@prisma/debug' import hasha from 'hasha' import fetch from 'node-fetch' import retry from 'p-retry' import tempy from 'tempy' import { getProxyAgent } from './getProxyAgent' import { overwriteFile } from './utils' const debug = Debug('prisma:fetch-engine:downloadZip') const rimraf = (path: string) => fs.promises.rm(path, { force: true, recursive: true }) export type DownloadResult = { lastModified: string sha256: string | null zippedSha256: string | null } async function fetchChecksum(url: string): Promise<string | null> { try { const checksumUrl = `${url}.sha256` const response = await fetch(checksumUrl, { agent: getProxyAgent(url), }) if (!response.ok) { let errorMessage = `Failed to fetch sha256 checksum at ${checksumUrl} - ${response.status} ${response.statusText}` if (!process.env.PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING) { errorMessage += `\n\nIf you need to ignore this error (e.g. in an offline environment), set the PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING environment variable to a truthy value.\nExample: PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING=1` } throw new Error(errorMessage) } const body = await response.text() // We get a string like this: // "3c82ee6cd9fedaec18a5e7cd3fc41f8c6b3dd32575dc13443d96aab4bd018411 query-engine.gz\n" // So we split it by whitespace and just get the hash, as that's what we're interested in const [checksum] = body.split(/\s+/) if (!/^[a-f0-9]{64}$/gi.test(checksum)) { throw new Error(`Unable to parse checksum from ${checksumUrl} - response body: ${body}`) } return checksum } catch (error) { if (process.env.PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING) { debug( `fetchChecksum() failed and was ignored as the PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING environment variable is truthy.\nError: ${error}`, ) return null } throw error } } export async function downloadZip( url: string, target: string, progressCb?: (progress: number) => void, ): Promise<DownloadResult> { const tmpDir = tempy.directory() const partial = path.join(tmpDir, 'partial') // We try 3 times, // Once + 2 retries const RETRIES_COUNT = 2 const [zippedSha256, sha256] = await retry( async () => { return await Promise.all([fetchChecksum(url), fetchChecksum(url.slice(0, url.length - 3))]) }, { retries: RETRIES_COUNT, onFailedAttempt: (err) => debug('An error occurred while downloading the checksums files', err), }, ) const result = await retry( async () => { const response = await fetch(url, { compress: false, agent: getProxyAgent(url), }) if (!response.ok) { throw new Error(`Failed to fetch the engine file at ${url} - ${response.status} ${response.statusText}`) } const lastModified = response.headers.get('last-modified')! const size = parseFloat(response.headers.get('content-length') as string) const ws = fs.createWriteStream(partial) // eslint-disable-next-line no-async-promise-executor return await new Promise(async (resolve, reject) => { let bytesRead = 0 if (response.body === null) { return reject(new Error(`Failed to fetch the engine file at ${url} - response.body is null`)) } response.body.once('error', reject).on('data', (chunk) => { bytesRead += chunk.length if (size && progressCb) { progressCb(bytesRead / size) } }) const gunzip = zlib.createGunzip() gunzip.on('error', reject) const zipStream = response.body.pipe(gunzip) const zippedHashPromise = hasha.fromStream(response.body, { algorithm: 'sha256', }) const hashPromise = hasha.fromStream(zipStream, { algorithm: 'sha256', }) zipStream.pipe(ws) ws.on('error', reject).on('close', () => { resolve({ lastModified, sha256, zippedSha256 }) }) const hash = await hashPromise const zippedHash = await zippedHashPromise if (zippedSha256 !== null && zippedSha256 !== zippedHash) { return reject(new Error(`sha256 checksum of ${url} (zipped) should be ${zippedSha256} but is ${zippedHash}`)) } if (sha256 !== null && sha256 !== hash) { return reject(new Error(`sha256 checksum of ${url} (unzipped) should be ${sha256} but is ${hash}`)) } }) }, { retries: RETRIES_COUNT, onFailedAttempt: (err) => debug('An error occurred while downloading the engine file', err), }, ) await overwriteFile(partial, target) // it's ok if the unlink fails try { await rimraf(partial) await rimraf(tmpDir) } catch (e) { debug(e) } return result as DownloadResult }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/prisma/prisma'

If you have feedback or need assistance with the MCP directory API, please join our Discord server