diff --git a/package.json b/package.json index 3e0c3a8..9d1eaba 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,11 @@ "version": "0.0.0", "main": "dist/index.js", "typings": "dist/index.d.ts", - "repository": - "git@github.com:graphql-boilerplates/graphql-boilerplate-install.git", + "repository": "git@github.com:graphql-boilerplates/graphql-boilerplate-install.git", "author": "Johannes Schickling ", - "contributors": ["Kim Brandwijk "], + "contributors": [ + "Kim Brandwijk " + ], "license": "MIT", "scripts": { "prepublishOnly": "npm run build", @@ -18,7 +19,9 @@ }, "dependencies": { "cross-spawn": "5.1.0", - "npm-run": "4.1.2" + "node-fetch": "^2.1.2", + "npm-run": "4.1.2", + "sillyname": "^0.1.0" }, "devDependencies": { "@types/node": "8.5.7", diff --git a/src/index.ts b/src/index.ts index 2ffae91..aba51ee 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,2 @@ export { replaceInFile, replaceInFiles } from './utils' -export { deploy, writeEnv, getInfo } from './prisma' \ No newline at end of file +export { deploy, writeEnv, getInfo, makeSandboxEndpoint } from './prisma' diff --git a/src/ping.ts b/src/ping.ts new file mode 100644 index 0000000..2ff2625 --- /dev/null +++ b/src/ping.ts @@ -0,0 +1,64 @@ +import * as fetch from 'node-fetch' +export type Region = 'EU_WEST_1' | 'US_WEST_2' + +const regionMap = { + EU_WEST_1: 'eu1', + US_WEST_2: 'us1', +} + +async function runPing(url: string): Promise { + const pingUrl = async () => { + const start = Date.now() + + if (process.env.NODE_ENV !== 'test') { + await fetch(url) + } + + return Date.now() - start + } + const pings = await Promise.all([0, 0].map(pingUrl)) + + return sum(pings) / pings.length +} + +export const regions: Region[] = ['EU_WEST_1', 'US_WEST_2'] + +export async function getFastestRegion(): Promise { + const pingResults = await Promise.all( + regions.map(async (region: Region) => { + const ping = await runPing(getPingUrl(region)) + return { + region, + ping, + } + }), + ) + + const fastestRegion: { region: Region; ping: number } = pingResults.reduce( + (min, curr) => { + if (curr.ping < min.ping) { + return curr + } + return min + }, + { region: 'EU_WEST_1', ping: Infinity }, + ) + + return regionMap[fastestRegion.region] +} + +export const getDynamoUrl = (region: string) => + `http://dynamodb.${region.toLowerCase().replace(/_/g, '-')}.amazonaws.com` + +const getPingUrl = (region: string) => + `${getDynamoUrl(region)}/ping?x=${randomString()}` + +function sum(arr) { + return arr.reduce((acc, curr) => acc + curr, 0) +} + +function randomString() { + return Math.random() + .toString(36) + .substring(7) +} diff --git a/src/prisma.ts b/src/prisma.ts index c33da4b..df442e7 100644 --- a/src/prisma.ts +++ b/src/prisma.ts @@ -1,5 +1,7 @@ import * as fs from 'fs' import { spawn } from './utils' +import * as sillyname from 'sillyname' +import { getFastestRegion } from './ping' export async function deploy(silent: boolean) { const options = { stdio: silent ? 'pipe' : 'inherit' } @@ -27,10 +29,30 @@ export async function writeEnv() { '.env', `\ PRISMA_SECRET=${endpointInfo.secret} -PRISMA_STAGE=${endpointInfo.stage} -PRISMA_CLUSTER=${endpointInfo.cluster} PRISMA_ENDPOINT=${endpointInfo.httpEndpoint}`, ) }) .catch(err => console.error(err)) } + +export async function makeSandboxEndpoint(project: string) { + const region = await getFastestRegion() + return `https://${region}.prisma.sh/public-${getSillyName()}/${project}/dev` +} + +function getSillyName() { + return `${slugify(sillyname()).split('-')[0]}-${Math.round( + Math.random() * 1000, + )}` +} + +function slugify(text) { + return text + .toString() + .toLowerCase() + .replace(/\s+/g, '-') // Replace spaces with - + .replace(/[^\w\-]+/g, '') // Remove all non-word chars + .replace(/\-\-+/g, '-') // Replace multiple - with single - + .replace(/^-+/, '') // Trim - from start of text + .replace(/-+$/, '') // Trim - from end of text +} diff --git a/yarn.lock b/yarn.lock index 3c43210..7237ca1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -148,6 +148,10 @@ mkdirp@^0.5.1: dependencies: minimist "0.0.8" +node-fetch@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5" + npm-path@^2.0.2, npm-path@^2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/npm-path/-/npm-path-2.0.4.tgz#c641347a5ff9d6a09e4d9bce5580c4f505278e64" @@ -217,6 +221,10 @@ shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" +sillyname@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/sillyname/-/sillyname-0.1.0.tgz#cfd98858e2498671347775efe3bb5141f46c87d6" + source-map-support@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.0.tgz#2018a7ad2bdf8faf2691e5fddab26bed5a2bacab"