UNPKG

@graphql-tools/prisma-loader

Version:

A set of utils for faster development of GraphQL tools

298 lines (297 loc) • 11.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.concatName = exports.PrismaDefinitionClass = void 0; const tslib_1 = require("tslib"); const yaml_js_1 = require("./yaml.js"); const fs = tslib_1.__importStar(require("fs")); const dotenv = tslib_1.__importStar(require("dotenv")); const path = tslib_1.__importStar(require("path")); // eslint-disable-next-line // @ts-ignore const jsonwebtoken_1 = tslib_1.__importDefault(require("jsonwebtoken")); const Cluster_js_1 = require("./Cluster.js"); const chalk_1 = tslib_1.__importDefault(require("chalk")); const yamlComment_js_1 = require("./utils/yamlComment.js"); const parseEndpoint_js_1 = require("./utils/parseEndpoint.js"); class PrismaDefinitionClass { constructor(env, definitionPath, envVars = process.env, out) { this.secrets = null; this.definitionPath = definitionPath; if (definitionPath) { this.definitionDir = path.dirname(definitionPath); } this.env = env; this.out = out; this.envVars = envVars; } async load(args, envPath, graceful) { if (args['project']) { const flagPath = path.resolve(String(args['project'])); try { fs.accessSync(flagPath); } catch (_a) { throw new Error(`Prisma definition path specified by --project '${flagPath}' does not exist`); } this.definitionPath = flagPath; this.definitionDir = path.dirname(flagPath); await this.loadDefinition(args, graceful); this.validate(); return; } if (envPath) { try { fs.accessSync(envPath); } catch (_b) { envPath = path.join(process.cwd(), envPath); } try { fs.accessSync(envPath); } catch (_c) { throw new Error(`--env-file path '${envPath}' does not exist`); } } dotenv.config({ path: envPath }); if (this.definitionPath) { await this.loadDefinition(args, graceful); this.validate(); } else { throw new Error(`Couldn’t find \`prisma.yml\` file. Are you in the right directory?`); } } async loadDefinition(args, graceful) { const { definition, rawJson } = await (0, yaml_js_1.readDefinition)(this.definitionPath, args, this.out, this.envVars, graceful); this.rawEndpoint = rawJson.endpoint; this.definition = definition; this.rawJson = rawJson; this.definitionString = fs.readFileSync(this.definitionPath, 'utf-8'); this.typesString = this.getTypesString(this.definition); const secrets = this.definition.secret; this.secrets = secrets ? secrets.replace(/\s/g, '').split(',') : null; } get endpoint() { return (this.definition && this.definition.endpoint) || process.env['PRISMA_MANAGEMENT_API_ENDPOINT']; } get clusterBaseUrl() { if (!this.definition || !this.endpoint) { return undefined; } const { clusterBaseUrl } = (0, parseEndpoint_js_1.parseEndpoint)(this.endpoint); return clusterBaseUrl; } get service() { if (!this.definition) { return undefined; } if (!this.endpoint) { return undefined; } const { service } = (0, parseEndpoint_js_1.parseEndpoint)(this.endpoint); return service; } get stage() { if (!this.definition) { return undefined; } if (!this.endpoint) { return undefined; } const { stage } = (0, parseEndpoint_js_1.parseEndpoint)(this.endpoint); return stage; } get cluster() { if (!this.definition) { return undefined; } if (!this.endpoint) { return undefined; } const { clusterName } = (0, parseEndpoint_js_1.parseEndpoint)(this.endpoint); return clusterName; } validate() { // shared clusters need a workspace const clusterName = this.getClusterName(); const cluster = this.env.clusterByName(clusterName); if (this.definition && clusterName && cluster && cluster.shared && !cluster.isPrivate && !this.getWorkspace() && clusterName !== 'shared-public-demo') { throw new Error(`Your \`cluster\` property in the prisma.yml is missing the workspace slug. Make sure that your \`cluster\` property looks like this: ${chalk_1.default.bold('<workspace>/<cluster-name>')}. You can also remove the cluster property from the prisma.yml and execute ${chalk_1.default.bold.green('prisma deploy')} again, to get that value auto-filled.`); } if (this.definition && this.definition.endpoint && clusterName && cluster && cluster.shared && !cluster.isPrivate && !this.getWorkspace() && clusterName !== 'shared-public-demo') { throw new Error(`The provided endpoint ${this.definition.endpoint} points to a demo cluster, but is missing the workspace slug. A valid demo endpoint looks like this: https://eu1.prisma.sh/myworkspace/service-name/stage-name`); } if (this.definition && this.definition.endpoint && !this.definition.endpoint.startsWith('http')) { throw new Error(`${chalk_1.default.bold(this.definition.endpoint)} is not a valid endpoint. It must start with http:// or https://`); } } getToken(serviceName, stageName) { if (this.secrets) { const data = { data: { service: `${serviceName}@${stageName}`, roles: ['admin'], }, }; return jsonwebtoken_1.default.sign(data, this.secrets[0], { expiresIn: '7d', }); } return undefined; } async getCluster(_ = false) { if (this.definition && this.endpoint) { const clusterData = (0, parseEndpoint_js_1.parseEndpoint)(this.endpoint); const cluster = await this.getClusterByEndpoint(clusterData); this.env.removeCluster(clusterData.clusterName); this.env.addCluster(cluster); return cluster; } return undefined; } findClusterByBaseUrl(baseUrl) { var _a; return (_a = this.env.clusters) === null || _a === void 0 ? void 0 : _a.find(c => c.baseUrl.toLowerCase() === baseUrl); } async getClusterByEndpoint(data) { if (data.clusterBaseUrl && !process.env['PRISMA_MANAGEMENT_API_SECRET']) { const cluster = this.findClusterByBaseUrl(data.clusterBaseUrl); if (cluster) { return cluster; } } const { clusterName, clusterBaseUrl, isPrivate, local, shared, workspaceSlug } = data; // if the cluster could potentially be served by the cloud api, fetch the available // clusters from the cloud api if (!local) { await this.env.fetchClusters(); const cluster = this.findClusterByBaseUrl(data.clusterBaseUrl); if (cluster) { return cluster; } } return new Cluster_js_1.Cluster(this.out, clusterName, clusterBaseUrl, shared || isPrivate ? this.env.cloudSessionKey : undefined, local, shared, isPrivate, workspaceSlug); } getTypesString(definition) { const typesPaths = definition.datamodel ? Array.isArray(definition.datamodel) ? definition.datamodel : [definition.datamodel] : []; let allTypes = ''; for (const unresolvedTypesPath of typesPaths) { const typesPath = path.join(this.definitionDir, unresolvedTypesPath); try { fs.accessSync(typesPath); const types = fs.readFileSync(typesPath, 'utf-8'); allTypes += types + '\n'; } catch (_a) { throw new Error(`The types definition file "${typesPath}" could not be found.`); } } return allTypes; } getClusterName() { return this.cluster || null; } getWorkspace() { if (this.definition && this.endpoint) { const { workspaceSlug } = (0, parseEndpoint_js_1.parseEndpoint)(this.endpoint); if (workspaceSlug) { return workspaceSlug; } } return null; } async getDeployName() { const cluster = await this.getCluster(); return concatName(cluster, this.service, this.getWorkspace()); } getSubscriptions() { if (this.definition && this.definition.subscriptions) { return Object.entries(this.definition.subscriptions).map(([name, subscription]) => { const url = typeof subscription.webhook === 'string' ? subscription.webhook : subscription.webhook.url; const headers = typeof subscription.webhook === 'string' ? [] : transformHeaders(subscription.webhook.headers); let query = subscription.query; if (subscription.query.endsWith('.graphql')) { const queryPath = path.join(this.definitionDir, subscription.query); try { fs.accessSync(queryPath); } catch (_a) { throw new Error(`Subscription query ${queryPath} provided in subscription "${name}" in prisma.yml does not exist.`); } query = fs.readFileSync(queryPath, 'utf-8'); } return { name, query, headers, url, }; }); } return []; } replaceEndpoint(newEndpoint) { this.definitionString = (0, yamlComment_js_1.replaceYamlValue)(this.definitionString, 'endpoint', newEndpoint); fs.writeFileSync(this.definitionPath, this.definitionString); } addDatamodel(datamodel) { this.definitionString += `\ndatamodel: ${datamodel}`; fs.writeFileSync(this.definitionPath, this.definitionString); this.definition.datamodel = datamodel; } async getEndpoint(serviceInput, stageInput) { const cluster = await this.getCluster(); const service = serviceInput || this.service; const stage = stageInput || this.stage; const workspace = this.getWorkspace(); if (service && stage && cluster) { return cluster.getApiEndpoint(service, stage, workspace); } return null; } getHooks(hookType) { if (this.definition && this.definition.hooks && this.definition.hooks[hookType]) { const hooks = this.definition.hooks[hookType]; if (typeof hooks !== 'string' && !Array.isArray(hooks)) { throw new Error(`Hook ${hookType} provided in prisma.yml must be string or an array of strings.`); } return typeof hooks === 'string' ? [hooks] : hooks; } return []; } } exports.PrismaDefinitionClass = PrismaDefinitionClass; function concatName(cluster, name, workspace) { if (cluster.shared) { const workspaceString = workspace ? `${workspace}~` : ''; return `${workspaceString}${name}`; } return name; } exports.concatName = concatName; function transformHeaders(headers) { if (!headers) { return []; } return Object.entries(headers).map(([name, value]) => ({ name, value })); }