export function listMigrations(directory: string): Promise<Migration[]> { return fs.readdirAsync(directory) .map(R.match(MIGRATION_FILE_REGEXP)) .filter(R.identity) .then(R.groupBy(R.nth<string>(1))) .then(R.mapObj(R.partial(matchesToMigration, directory))) .then(R.values) .then(R.sortBy((migration: Migration) => migration.id)); }
export function readDownSQL(migration: Migration): Promise<string> { if (migration.split) { return fs.readFileAsync(migration.downPath, {encoding: 'utf8'}) .then(R.trim); } return fs.readFileAsync(migration.path, {encoding: 'utf8'}) .then(R.split(MIGRATION_SQL_SPLIT_REGEXP)) .tap(R.partial(assertSQLSections, migration)) .then(R.nth(1)) .then(R.trim); }
export const create = config => { // combine the user's defaults with ours const headers = merge(DEFAULT_HEADERS, config.headers || {}) const combinedConfig = merge(DEFAULT_CONFIG, dissoc('headers', config)) // create the axios instance const instance = axios.create(combinedConfig) const monitors = [] const addMonitor = monitor => { monitors.push(monitor) } const requestTransforms = [] const asyncRequestTransforms = [] const responseTransforms = [] const addRequestTransform = transform => requestTransforms.push(transform) const addAsyncRequestTransform = transform => asyncRequestTransforms.push(transform) const addResponseTransform = transform => responseTransforms.push(transform) // convenience for setting new request headers const setHeader = (name, value) => { headers[name] = value return instance } // sets headers in bulk const setHeaders = headers => { forEach(header => setHeader(header, headers[header]), keys(headers)) return instance } // remove header const deleteHeader = name => { delete headers[name] return instance } /** * Sets a new base URL. */ const setBaseURL = newURL => { instance.defaults.baseURL = newURL return instance } /** * Gets the current base URL used by axios. */ const getBaseURL = () => { return instance.defaults.baseURL } /** * Make the request for GET, HEAD, DELETE */ const doRequestWithoutBody = (method, url, params = {}, axiosConfig = {}) => { return doRequest(merge({ url, params, method }, axiosConfig)) } /** * Make the request for POST, PUT, PATCH */ const doRequestWithBody = (method, url, data = null, axiosConfig = {}) => { return doRequest(merge({ url, method, data }, axiosConfig)) } /** * Make the request with this config! */ const doRequest = async axiosRequestConfig => { axiosRequestConfig.headers = { ...headers, ...axiosRequestConfig.headers, } // add the request transforms if (requestTransforms.length > 0) { // overwrite our axios request with whatever our object looks like now // axiosRequestConfig = doRequestTransforms(requestTransforms, axiosRequestConfig) forEach(transform => transform(axiosRequestConfig), requestTransforms) } // add the async request transforms if (asyncRequestTransforms.length > 0) { for (let index = 0; index < asyncRequestTransforms.length; index++) { const transform = asyncRequestTransforms[index](axiosRequestConfig) if (isPromise(transform)) { await transform } else { await transform(axiosRequestConfig) } } } // after the call, convert the axios response, then execute our monitors const chain = pipe( convertResponse(toNumber(new Date())), // partial(convertResponse, [toNumber(new Date())]), runMonitors, ) return instance .request(axiosRequestConfig) .then(chain) .catch(chain) } /** * Fires after we convert from axios' response into our response. Exceptions * raised for each monitor will be ignored. */ const runMonitors = ourResponse => { monitors.forEach(monitor => { try { monitor(ourResponse) } catch (error) { // all monitor complaints will be ignored } }) return ourResponse } /** * Converts an axios response/error into our response. */ const convertResponse = curry((startedAt: number, axiosResult: AxiosResponse | AxiosError) => { const end: number = toNumber(new Date()) const duration: number = end - startedAt // new in Axios 0.13 -- some data could be buried 1 level now const isError = axiosResult instanceof Error || axios.isCancel(axiosResult) const axiosResponse = axiosResult as AxiosResponse const axiosError = axiosResult as AxiosError const response = isError ? axiosError.response : axiosResponse const status = (response && response.status) || null const problem = isError ? getProblemFromError(axiosResult) : getProblemFromStatus(status) const originalError = isError ? axiosError : null const ok = in200s(status) const config = axiosResult.config || null const headers = (response && response.headers) || null let data = (response && response.data) || null // give an opportunity for anything to the response transforms to change stuff along the way let transformedResponse = { duration, problem, originalError, ok, status, headers, config, data, } if (responseTransforms.length > 0) { forEach(transform => transform(transformedResponse), responseTransforms) } return transformedResponse }) // create the base object const sauce = { axiosInstance: instance, monitors, addMonitor, requestTransforms, asyncRequestTransforms, responseTransforms, addRequestTransform, addAsyncRequestTransform, addResponseTransform, setHeader, setHeaders, deleteHeader, headers, setBaseURL, getBaseURL, get: partial(doRequestWithoutBody, ['get']), delete: partial(doRequestWithoutBody, ['delete']), head: partial(doRequestWithoutBody, ['head']), post: partial(doRequestWithBody, ['post']), put: partial(doRequestWithBody, ['put']), patch: partial(doRequestWithBody, ['patch']), link: partial(doRequestWithoutBody, ['link']), unlink: partial(doRequestWithoutBody, ['unlink']), } // send back the sauce return sauce }
import { findApp } from './util' import { FoundBrowser, Browser } from '../types' import * as linuxHelper from '../linux' import { log } from '../log' import { merge, partial } from 'ramda' const detectCanary = partial(findApp, [ 'Contents/MacOS/Google Chrome Canary', 'com.google.Chrome.canary', 'KSVersion' ]) const detectChrome = partial(findApp, [ 'Contents/MacOS/Google Chrome', 'com.google.Chrome', 'KSVersion' ]) const detectChromium = partial(findApp, [ 'Contents/MacOS/Chromium', 'org.chromium.Chromium', 'CFBundleShortVersionString' ]) type Detectors = { [index: string]: Function } const browsers: Detectors = { chrome: detectChrome, canary: detectCanary, chromium: detectChromium }
* @param secure - True if sanitization is required * @param data - Object representing a user model */ const respond = (secure: boolean, data: User.UserData): User.UserData => secure ? dissoc('password', data) : data; /** * Prepares a user object for database insertion */ export const cleanUserData = formatter(format); /** * Returns a sanitised object representing a user, removing private properties * @param data - A database record representing a user */ export const sanitizedResponse = partial(respond, [true]); /** * Returns a clone of an object representing a user * @param data - A database record representing a user */ export const unsanitizedResponse = partial(respond, [false]); /** * Get a list of active users * @param limit - The number of records to fetch * @param offset - The number of records to skip */ export const get = async (limit: number = 10, offset: number = 0): Promise<User.UserData[]> => { const users = await db.getActiveUsers(limit, offset); return users.map(sanitizedResponse);