jsonql-contract
Version:
JS API / command line tool to generate the contract.json for jsonql
171 lines (157 loc) • 5.33 kB
JavaScript
// porting back from jsonql-koa to grab the NODE_ENV.json and remove the files information to public use
const { join } = require('path')
const fsx = require('fs-extra')
const { merge } = require('lodash')
// const { JsonqlError } = require('jsonql-errors')
const { isObjectHasKey } = require('jsonql-params-validator')
const {
SOCKET_NAME,
QUERY_NAME,
MUTATION_NAME,
AUTH_NAME,
SOCKET_AUTH_NAME,
NAMESAPCE_PROP_KEY,
FILE_PROP_KEY,
PUBLIC_KEY,
STANDALONE_PROP_KEY
} = require('jsonql-constants')
// const colors = require('colors/safe')
const { getDebug, removeSrvAuthFromContract } = require('../utils')
const debug = getDebug('public-contract')
/**
* we need to remove the file info from the contract if this is for public
* @param {object} json contract
* @param {object} config options
* @return {string} contract without the file field
*/
const cleanForPublic = (json, config) => {
const {
enableAuth,
loginHandlerName,
logoutHandlerName
} = config
for (let type in json) {
for (let fn in json[type]) {
delete json[type][fn][FILE_PROP_KEY]
// @TODO for query and mutation we should remove the namespaces etc, they are for socket
switch (type) {
case QUERY_NAME:
case MUTATION_NAME:
if (isObjectHasKey(json[type][fn], NAMESAPCE_PROP_KEY)) {
delete json[type][fn][NAMESAPCE_PROP_KEY]
}
if (isObjectHasKey(json[type][fn], PUBLIC_KEY)) {
if (!json[type][fn][PUBLIC_KEY]) {
delete json[type][fn][PUBLIC_KEY]
}
}
break
case SOCKET_NAME: // for socket it doesn't care about this key
if (isObjectHasKey(json[type][fn], PUBLIC_KEY)) {
delete json[type][fn][PUBLIC_KEY]
}
break
default:
// nothing to do
}
}
}
// @TODO when socket is not in standalone mode all the auth method
// login, logout should not get expose to the client
// at this point there is no SOCKET_AUTH_NAME yet, we need to take this out
json = removeSrvAuthFromContract(json, AUTH_NAME, config)
// this is ugly because it happens in two places, need to refactor this bit at the very end
if (config[STANDALONE_PROP_KEY] !== true) {
delete json[SOCKET_AUTH_NAME]
} else {
json = removeSrvAuthFromContract(json, SOCKET_AUTH_NAME, config)
}
// if it's not enableAuth then remove all of these
const handlers = [loginHandlerName, logoutHandlerName]
if (!enableAuth) {
for (let j = 0; j < handlers.length; ++j) {
if (json[AUTH_NAME][handlers[j]]) {
delete json[AUTH_NAME][handlers[j]]
}
}
}
// @TODO there are several more new features, interceptor, external, plugins, middlewares
// don't need this in the public json
delete json.sourceType
// export
return json
}
/**
* @TODO
* using the NODE_ENV to check if there is extra contract file
* @param {string} contractDir directory store contract
* @return {object} empty object when nothing
*/
function getEnvContractFile(contractDir) {
const nodeEnv = process.env.NODE_ENV
const overwriteContractFile = join(contractDir, [nodeEnv, 'json'].join('.'))
if (fsx.existsSync(overwriteContractFile)) {
debug('found env contract')
return fsx.readJsonSync(overwriteContractFile)
}
return {}
}
/**
* When this contract contain a socket field
* then we can use this to inject extra into it
* @param {object} contractJson the partially generated contract file
* @param {object} helloContract the helloWorld contract
* @return {object} the contract with socket part added helloWorld (or more later)
*/
function processSocketContract(contractJson, helloContract) {
if (contractJson[SOCKET_NAME]) {
// debug('processSocketContract', contractJson[SOCKET_NAME], contractJson[SOCKET_AUTH_NAME])
const helloWorldPart = helloContract[QUERY_NAME]
return merge(contractJson, {
[SOCKET_NAME]: helloWorldPart
})
}
return contractJson
}
/**
* add an expired timstamp to the public contract
* @param {object} config configuration
* @param {object} contractJson the generated contract
* @return {object} empty then nothing
*/
function getExpired(config, contractJson) {
const { expired } = config
const { timestamp } = contractJson
// the timestamp now comes with milsecond ...
if (expired && expired > timestamp) {
return { expired }
}
return {}
}
/**
* the actual public contract generator
* @param {object} config the original config
* @param {object} contractJson the raw json file
* @return {string} json
*/
function publicContractGenerator(config, contractJson) {
const helloContract = fsx.readJsonSync(join(__dirname, 'hello-world.json'))
// env contract file - this should not get written to file
// @TODO disable this feature for now and decide if we need it later
// const extraContracts = {}
// const extraContracts = config.raw ? getEnvContractFile(contractDir) : {};
const expiredEntry = getExpired(config, contractJson)
const contract = merge(
{},
helloContract,
processSocketContract(contractJson, helloContract),
// extraContracts,
expiredEntry
)
// export
return cleanForPublic(contract, config)
}
module.exports = {
removeSrvAuthFromContract,
publicContractGenerator
}