@graphql-tools/prisma-loader
Version:
A set of utils for faster development of GraphQL tools
254 lines (253 loc) • 9.29 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isLocal = exports.Environment = void 0;
const tslib_1 = require("tslib");
const Cluster_js_1 = require("./Cluster.js");
const fs = tslib_1.__importStar(require("fs"));
const yaml = tslib_1.__importStar(require("js-yaml"));
const ClusterNotFound_js_1 = require("./errors/ClusterNotFound.js");
const Variables_js_1 = require("./Variables.js");
const Output_js_1 = require("./Output.js");
const path = tslib_1.__importStar(require("path"));
require("isomorphic-fetch");
const ClusterNotSet_js_1 = require("./errors/ClusterNotSet.js");
const constants_js_1 = require("./constants.js");
const getProxyAgent_js_1 = require("./utils/getProxyAgent.js");
// eslint-disable-next-line
// @ts-ignore
const jsonwebtoken_1 = tslib_1.__importDefault(require("jsonwebtoken"));
const debug_1 = tslib_1.__importDefault(require("debug"));
const debug = (0, debug_1.default)('Environment');
class Environment {
constructor(home, out = new Output_js_1.Output(), version) {
this.sharedClusters = ['prisma-eu1', 'prisma-us1'];
this.clusterEndpointMap = constants_js_1.clusterEndpointMap;
this.globalRC = {};
this.clustersFetched = false;
this.out = out;
this.home = home;
this.version = version;
this.rcPath = path.join(this.home, '.prisma/config.yml');
fs.mkdirSync(path.dirname(this.rcPath), { recursive: true });
}
_getClusters() {
const clusters = this.clusters;
if (clusters === undefined) {
throw new Error(`Cannot get clusters. Did you forget to call "Environment.load()"?`);
}
return clusters;
}
async load() {
await this.loadGlobalRC();
}
get cloudSessionKey() {
return process.env['PRISMA_CLOUD_SESSION_KEY'] || this.globalRC.cloudSessionKey;
}
async renewToken() {
if (this.cloudSessionKey) {
const data = jsonwebtoken_1.default.decode(this.cloudSessionKey);
if (!data.exp) {
return;
}
const timeLeft = data.exp * 1000 - Date.now();
if (timeLeft < 1000 * 60 * 60 * 24 && timeLeft > 0) {
try {
const res = await this.requestCloudApi(`
mutation {
renewToken
}
`);
if (res.renewToken) {
this.globalRC.cloudSessionKey = res.renewToken;
this.saveGlobalRC();
}
}
catch (e) {
debug(e);
}
}
}
}
async fetchClusters() {
if (!this.clustersFetched && this.cloudSessionKey) {
const renewPromise = this.renewToken();
try {
const res = (await Promise.race([
this.requestCloudApi(`
query prismaCliGetClusters {
me {
memberships {
workspace {
id
slug
clusters {
id
name
connectInfo {
endpoint
}
customConnectionInfo {
endpoint
}
}
}
}
}
}
`),
// eslint-disable-next-line
new Promise((_, r) => setTimeout(() => r(), 6000)),
]));
if (!res) {
return;
}
if (res.me && res.me.memberships && Array.isArray(res.me.memberships)) {
// clean up all prisma-eu1 and prisma-us1 clusters if they already exist
this.clusters = this._getClusters().filter(c => c.name !== 'prisma-eu1' && c.name !== 'prisma-us1');
for (const m of res.me.memberships) {
for (const cluster of m.workspace.clusters) {
const endpoint = cluster.connectInfo
? cluster.connectInfo.endpoint
: cluster.customConnectionInfo
? cluster.customConnectionInfo.endpoint
: this.clusterEndpointMap[cluster.name];
this.addCluster(new Cluster_js_1.Cluster(this.out, cluster.name, endpoint, this.globalRC.cloudSessionKey, false, ['prisma-eu1', 'prisma-us1'].includes(cluster.name), !['prisma-eu1', 'prisma-us1'].includes(cluster.name), m.workspace.slug));
}
}
}
}
catch (e) {
debug(e);
}
await renewPromise;
}
}
clusterByName(name, throws = false) {
if (!this.clusters) {
return;
}
const cluster = this.clusters.find(c => c.name === name);
if (!throws) {
return cluster;
}
if (!cluster) {
if (!name) {
throw new ClusterNotSet_js_1.ClusterNotSet();
}
throw new ClusterNotFound_js_1.ClusterNotFound(name);
}
return cluster;
}
setToken(token) {
this.globalRC.cloudSessionKey = token;
}
addCluster(cluster) {
const clusters = this._getClusters();
const existingClusterIndex = clusters.findIndex(c => {
if (cluster.workspaceSlug) {
return c.workspaceSlug === cluster.workspaceSlug && c.name === cluster.name;
}
else {
return c.name === cluster.name;
}
});
if (existingClusterIndex > -1) {
clusters.splice(existingClusterIndex, 1);
}
clusters.push(cluster);
}
removeCluster(name) {
this.clusters = this._getClusters().filter(c => c.name !== name);
}
saveGlobalRC() {
const rc = {
cloudSessionKey: this.globalRC.cloudSessionKey ? this.globalRC.cloudSessionKey.trim() : undefined,
clusters: this.getLocalClusterConfig(),
};
// parse & stringify to rm undefined for yaml parser
const rcString = yaml.dump(JSON.parse(JSON.stringify(rc)));
fs.writeFileSync(this.rcPath, rcString);
}
setActiveCluster(cluster) {
this.activeCluster = cluster;
}
async loadGlobalRC() {
if (this.rcPath) {
try {
fs.accessSync(this.rcPath);
const globalFile = fs.readFileSync(this.rcPath, 'utf-8');
await this.parseGlobalRC(globalFile);
}
catch (_a) {
await this.parseGlobalRC();
}
}
else {
await this.parseGlobalRC();
}
}
async parseGlobalRC(globalFile) {
if (globalFile) {
this.globalRC = await this.loadYaml(globalFile, this.rcPath);
}
this.clusters = this.initClusters(this.globalRC);
}
async loadYaml(file, filePath = null) {
if (file) {
let content;
try {
content = yaml.load(file);
}
catch (e) {
throw new Error(`Yaml parsing error in ${filePath}: ${e.message}`);
}
const variables = new Variables_js_1.Variables(filePath || 'no filepath provided', this.args, this.out);
content = await variables.populateJson(content);
return content;
}
else {
return {};
}
}
initClusters(rc) {
const sharedClusters = this.getSharedClusters(rc);
return [...sharedClusters];
}
getSharedClusters(rc) {
return this.sharedClusters.map(clusterName => {
return new Cluster_js_1.Cluster(this.out, clusterName, this.clusterEndpointMap[clusterName], rc && rc.cloudSessionKey, false, true);
});
}
getLocalClusterConfig() {
return this._getClusters()
.filter(c => !c.shared && c.clusterSecret !== this.cloudSessionKey && !c.isPrivate)
.reduce((acc, cluster) => {
return {
...acc,
[cluster.name]: {
host: cluster.baseUrl,
clusterSecret: cluster.clusterSecret,
},
};
}, {});
}
async requestCloudApi(query) {
const res = await fetch('https://api.cloud.prisma.sh', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cloudSessionKey}`,
'X-Cli-Version': this.version,
},
body: JSON.stringify({
query,
}),
proxy: (0, getProxyAgent_js_1.getProxyAgent)('https://api.cloud.prisma.sh'),
});
const json = await res.json();
return json.data;
}
}
exports.Environment = Environment;
const isLocal = (hostname) => hostname.includes('localhost') || hostname.includes('127.0.0.1');
exports.isLocal = isLocal;