Skip to content

Instantly share code, notes, and snippets.

@Radiergummi
Last active November 16, 2019 12:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Radiergummi/986ab80f36daf6a16b40fdf4cbec7e9a to your computer and use it in GitHub Desktop.
Save Radiergummi/986ab80f36daf6a16b40fdf4cbec7e9a to your computer and use it in GitHub Desktop.
Cloudflare worker deployment
'use strict';
require('dotenv').config({ path: `${ __dirname }/../.env` });
const axios = require('axios');
const fs = require('fs');
const esprima = require('esprima');
const Cloudflare = require('./Cloudflare');
const packageJson = require('../../package');
const { AUTH_EMAIL, AUTH_KEY, ZONE_ID } = process.env;
( async function init () {
const workerName = packageJson.name;
const cloudflare = new Cloudflare(ZONE_ID, AUTH_EMAIL, AUTH_KEY);
const script = fs
.readFileSync(`${ __dirname }/../dist/index.js`, 'utf8')
.toString();
try {
esprima.parseScript(script);
} catch ( error ) {
if ( !error.lineNumber ) {
console.error(`Script is invalid: ${ error.message }. No line number given.`);
process.exit(2);
}
const sourceSlice = script
.split('\n')
.slice(error.lineNumber - 4, error.lineNumber + 3)
.map(( line, index ) => {
const lineNumber = error.lineNumber - 3 + index;
const prefixedLine = `${ lineNumber.toString().padStart(4, ' ') } | ${ line }`;
return lineNumber === error.lineNumber
? `\x1b[31;1m${ prefixedLine }\x1b[0m`
: `\x1b[2m${ prefixedLine }\x1b[0m`;
})
.join('\n');
console.error(`Script is invalid: ${ error.message }\n\n${ sourceSlice }\n`);
process.exit(1);
}
try {
await cloudflare.uploadScript(workerName, script);
} catch ( error ) {
console.error(`Worker upload failed: ${ error.message }`);
process.exit(1);
}
return console.info(`Worker upload successful`);
} )();
'use strict';
const axios = require('axios');
class Cloudflare {
constructor ( zone, emailAddress, apiKey ) {
this._zone = zone;
this._emailAddress = emailAddress;
this._apiKey = apiKey;
this._client = axios.create({
headers: {
'x-auth-email': this._emailAddress,
'x-auth-key': this._apiKey,
},
baseURL: `https://api.cloudflare.com/client/v4/zones/${ this._zone }`,
});
}
/**
* Uploads a script to Cloudflare
*
* @param {string} name Name of the script to upload
* @param {string|Buffer} script Script to upload
* @return {Promise<string>}
*/
async uploadScript ( name, script ) {
return this._request(
'put',
`/workers/scripts/${ name }`,
Buffer.from(script),
{
'content-type': `application/javascript`,
},
);
}
/**
* Performs a request against the Cloudflare API
*
* @param {string} method Request method
* @param {string} url Request URI. Base URL will be appended
* @param {string|null} [body] Optional request body
* @param {object} [headers] Optional request headers
* @param {object} [config] Optional axios configuration
* @return {Promise<Object|string>} Response result property if successful
* @private
*/
async _request ( method, url, body = null, headers = {}, config = {} ) {
let response;
try {
response = await this._client[ method ](url, body, { headers, ...config });
if ( !response.data.success || !response.data.result ) {
// noinspection ExceptionCaughtLocallyJS
throw new Error('Invalid response');
}
} catch ( error ) {
if ( error.response ) {
if ( error.response.data && error.response.data.errors ) {
throw new Error(error.response.data.errors.map(error => `[${ error.code }] ${ error.message }`).join('\n'));
}
throw new Error(`Request failed: Could not parse error response: ${ JSON.stringify(error.response.data, null, 2) }`);
}
throw new Error(`Request failed: ${ error.message }`);
}
return response.data.result;
}
}
module.exports = Cloudflare;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment