Comparing version 4.4.3 to 4.5.0
module.exports = { | ||
root: true, | ||
parserOptions: { | ||
// this is required for dynamic import() | ||
ecmaVersion: 2020 | ||
}, | ||
env: { | ||
node: true | ||
}, | ||
extends: [ | ||
'eslint-config-digitalbazaar' | ||
], | ||
extends: ['digitalbazaar', 'digitalbazaar/jsdoc'], | ||
ignorePatterns: ['node_modules/'] | ||
}; |
# bedrock ChangeLog | ||
## 4.5.0 - 2022-03-22 | ||
### Added | ||
- Add `main` export that includes information about the main program | ||
module such as its `filename`. The main program module will be | ||
properly computed on bedrock workers to express not the worker | ||
filename but the filename of the first loaded module, e.g., if | ||
an application `foo.js` calls `bedrock.start`, then `main` includes | ||
the full path `filename` for `foo.js` whether running in the primary | ||
process on a worker process. | ||
### Changed | ||
- Change internal implementation to use ESM + transpile using esm.js to | ||
CommonJS. Should be a non-breaking change. | ||
## 4.4.3 - 2021-12-08 | ||
@@ -4,0 +19,0 @@ |
/*! | ||
* Copyright (c) 2012-2019 Digital Bazaar, Inc. All rights reserved. | ||
* Copyright (c) 2012-2021 Digital Bazaar, Inc. All rights reserved. | ||
*/ | ||
'use strict'; | ||
export const config = {}; | ||
const config = {}; | ||
module.exports = config; | ||
// cli info | ||
@@ -10,0 +7,0 @@ config.cli = {}; |
/*! | ||
* Copyright (c) 2012-2019 Digital Bazaar, Inc. All rights reserved. | ||
* Copyright (c) 2012-2021 Digital Bazaar, Inc. All rights reserved. | ||
*/ | ||
'use strict'; | ||
import {EventEmitter} from 'async-node-events'; | ||
const {EventEmitter} = require('async-node-events'); | ||
const emitter = new EventEmitter(); | ||
emitter.setMaxListeners(Infinity); | ||
emitter.removeAllListeners('maxListenersPassed'); | ||
export {emitter}; | ||
const api = new EventEmitter(); | ||
api.setMaxListeners(Infinity); | ||
api.removeAllListeners('maxListenersPassed'); | ||
module.exports = api; | ||
/** | ||
* Schedules an event to be emitted on the next tick (via process.nextTick). | ||
* | ||
* @return a Promise that resolves to undefined once the event has been emitted | ||
* to all listeners (or to `false` if it was canceled). | ||
* @param {Array} args - The arguments to emit. | ||
* | ||
* @returns {Promise} A Promise that resolves to undefined once the event has | ||
* been emitted to all listeners (or to `false` if it was canceled). | ||
*/ | ||
api.emitLater = function(...args) { | ||
emitter.emitLater = function(...args) { | ||
// emit asynchronously | ||
return new Promise((resolve, reject) => { | ||
process.nextTick(() => { | ||
api.emit(...args).then(resolve, reject); | ||
emitter.emit(...args).then(resolve, reject); | ||
}); | ||
}); | ||
}; |
/*! | ||
* Copyright (c) 2012-2021 Digital Bazaar, Inc. All rights reserved. | ||
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved. | ||
*/ | ||
'use strict'; | ||
const brUtil = require('../util'); | ||
import * as brUtil from '../util.js'; | ||
import * as formatters from './formatters.js'; | ||
import {config} from '../config.js'; | ||
import path from 'path'; | ||
import {promises as fs} from 'fs'; | ||
import uidNumber from 'uid-number'; | ||
import winston from 'winston'; | ||
const cc = brUtil.config.main.computer(); | ||
const config = require('../config'); | ||
const formatters = require('./formatters'); | ||
const fs = require('fs').promises; | ||
const path = require('path'); | ||
const uidNumber = require('uid-number'); | ||
const winston = require('winston'); | ||
@@ -23,3 +21,3 @@ // config filenames | ||
module.exports.init = async ({transports}) => { | ||
export async function init({transports}) { | ||
transports.app = new winston.transports.File({ | ||
@@ -66,3 +64,3 @@ ...config.loggers.app, | ||
transports.error.name = 'error'; | ||
}; | ||
} | ||
@@ -69,0 +67,0 @@ async function _chown(filename) { |
/*! | ||
* Copyright (c) 2012-2020 Digital Bazaar, Inc. All rights reserved. | ||
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved. | ||
*/ | ||
'use strict'; | ||
import jsonStringify from 'fast-safe-stringify'; | ||
import {MESSAGE} from 'triple-beam'; | ||
import winston from 'winston'; | ||
const jsonStringify = require('fast-safe-stringify'); | ||
const {MESSAGE} = require('triple-beam'); | ||
const winston = require('winston'); | ||
const {format} = winston; | ||
const api = {}; | ||
module.exports = api; | ||
api.bedrock = format(info => { | ||
export const bedrock = format(info => { | ||
const {timestamp, workerId, workerPid} = info; | ||
@@ -40,3 +35,4 @@ const stringifiedRest = jsonStringify({ | ||
// this filter is only operative when one of the only/exclude sets is active | ||
api.filterModules = format((info, {excludeModulesSet, onlyModulesSet}) => { | ||
export const filterModules = format(( | ||
info, {excludeModulesSet, onlyModulesSet}) => { | ||
const {module} = info; | ||
@@ -61,3 +57,11 @@ | ||
api.fromConfig = config => { | ||
export const modulePrefix = format(info => { | ||
const {module} = info; | ||
if(module) { | ||
info.message = `[${module}] ${info.message}`; | ||
} | ||
return info; | ||
}); | ||
export function fromConfig(config) { | ||
const {colorize, excludeModules, formatter, onlyModules} = config; | ||
@@ -72,7 +76,7 @@ let fmt; | ||
const onlyModulesSet = onlyModules ? new Set(onlyModules) : false; | ||
fmts.push(api.filterModules({excludeModulesSet, onlyModulesSet})); | ||
fmts.push(filterModules({excludeModulesSet, onlyModulesSet})); | ||
} | ||
fmts.push( | ||
format.timestamp(), | ||
api.modulePrefix(), | ||
modulePrefix(), | ||
); | ||
@@ -82,3 +86,3 @@ if(colorize) { | ||
} | ||
fmts.push(api.bedrock()); | ||
fmts.push(bedrock()); | ||
fmt = format.combine(...fmts); | ||
@@ -101,11 +105,2 @@ } else if(formatter === 'json') { | ||
return fmt; | ||
}; | ||
api.modulePrefix = format(info => { | ||
const {module} = info; | ||
if(module) { | ||
info.message = `[${module}] ${info.message}`; | ||
} | ||
return info; | ||
}); | ||
} |
/*! | ||
* Copyright (c) 2012-2021 Digital Bazaar, Inc. All rights reserved. | ||
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved. | ||
*/ | ||
'use strict'; | ||
import * as fileLogger from './fileLogger.js'; | ||
import * as formatters from './formatters.js'; | ||
import cluster from 'cluster'; | ||
import {config} from '../config.js'; | ||
import crypto from 'crypto'; | ||
import {Mail as WinstonMail} from 'winston-mail'; | ||
import util from 'util'; | ||
import winston from 'winston'; | ||
import {WorkerTransport} from './WorkerTransport.js'; | ||
const cluster = require('cluster'); | ||
const config = require('../config'); | ||
const crypto = require('crypto'); | ||
const fileLogger = require('./fileLogger'); | ||
const formatters = require('./formatters'); | ||
const util = require('util'); | ||
const winston = require('winston'); | ||
const WinstonMail = require('winston-mail').Mail; | ||
const WorkerTransport = require('./WorkerTransport'); | ||
const randomBytes = util.promisify(crypto.randomBytes); | ||
@@ -39,3 +37,3 @@ | ||
// create the container for the primary and all of the workers | ||
const container = new winston.Container(); | ||
export const container = new winston.Container(); | ||
// override get to use a wrapper so loggers that are retrieved via `.get()` | ||
@@ -80,3 +78,2 @@ // prior to logger initialization will receive the updated configuration | ||
}; | ||
module.exports = container; | ||
@@ -141,3 +138,3 @@ if(cluster.isMaster) { | ||
* | ||
* @param worker the worker to attach the message handler to. | ||
* @param {object} worker - The worker to attach the message handler to. | ||
*/ | ||
@@ -183,5 +180,5 @@ container.attach = function(worker) { | ||
* | ||
* @param name the name of the transport to add; if a name has already been | ||
* taken, an error will be thrown. | ||
* @param transport the transport to add. | ||
* @param {string} name - The name of the transport to add; if a name has | ||
* already been taken, an error will be thrown. | ||
* @param {object} transport - The transport to add. | ||
*/ | ||
@@ -188,0 +185,0 @@ container.addTransport = function(name, transport) { |
/*! | ||
* Copyright (c) 2012-2020 Digital Bazaar, Inc. All rights reserved. | ||
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved. | ||
*/ | ||
'use strict'; | ||
import cycle from 'cycle'; | ||
import Transport from 'winston-transport'; | ||
const cycle = require('cycle'); | ||
const Transport = require('winston-transport'); | ||
module.exports = class WorkerTransport extends Transport { | ||
export class WorkerTransport extends Transport { | ||
constructor(config) { | ||
@@ -45,5 +43,5 @@ super(config); | ||
} | ||
}; | ||
} | ||
function _noop() { | ||
} |
487
lib/util.js
/*! | ||
* Copyright (c) 2012-2019 Digital Bazaar, Inc. All rights reserved. | ||
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved. | ||
*/ | ||
'use strict'; | ||
import {config} from './config.js'; | ||
import delay from 'delay'; | ||
import util from 'util'; | ||
import uuid from 'uuid-random'; | ||
const config = require('./config'); | ||
const delay = require('delay'); | ||
const lodashGet = require('lodash.get'); | ||
const lodashSet = require('lodash.set'); | ||
const lodashTemplate = require('lodash.template'); | ||
const lodashToPath = require('lodash.topath'); | ||
const util = require('util'); | ||
const uuid = require('uuid-random'); | ||
// export config utilities under `config` namespace | ||
export * as config from './configUtil.js'; | ||
const api = {}; | ||
module.exports = api; | ||
/** | ||
@@ -23,6 +17,6 @@ * Create a promise which resolves after the specified milliseconds. | ||
*/ | ||
api.delay = delay; | ||
export {delay}; | ||
// BedrockError class | ||
api.BedrockError = function(message, type, details, cause) { | ||
export const BedrockError = function(message, type, details, cause) { | ||
Error.call(this, message); | ||
@@ -35,5 +29,5 @@ Error.captureStackTrace(this, this.constructor); | ||
}; | ||
util.inherits(api.BedrockError, Error); | ||
api.BedrockError.prototype.name = 'BedrockError'; | ||
api.BedrockError.prototype.toObject = function(options) { | ||
util.inherits(BedrockError, Error); | ||
BedrockError.prototype.name = 'BedrockError'; | ||
BedrockError.prototype.toObject = function(options) { | ||
options = options || {}; | ||
@@ -54,12 +48,12 @@ options.public = options.public || false; | ||
// check type of this error | ||
api.BedrockError.prototype.isType = function(type) { | ||
return api.hasValue(this, 'name', type); | ||
BedrockError.prototype.isType = function(type) { | ||
return hasValue(this, 'name', type); | ||
}; | ||
// check type of this error or one of it's causes | ||
api.BedrockError.prototype.hasType = function(type) { | ||
BedrockError.prototype.hasType = function(type) { | ||
return this.isType(type) || this.hasCauseOfType(type); | ||
}; | ||
// check type of error cause or one of it's causes | ||
api.BedrockError.prototype.hasCauseOfType = function(type) { | ||
if(this.cause && this.cause instanceof api.BedrockError) { | ||
BedrockError.prototype.hasCauseOfType = function(type) { | ||
if(this.cause && this.cause instanceof BedrockError) { | ||
return this.cause.hasType(type); | ||
@@ -70,102 +64,11 @@ } | ||
const _genericErrorJSON = { | ||
message: 'An internal server error occurred.', | ||
type: 'bedrock.InternalServerError' | ||
}; | ||
const _errorMessageRegex = /^Error:\s*/; | ||
const _errorAtRegex = /^\s+at\s*/; | ||
/** | ||
* Parse an Error stack property into a JSON structure. | ||
* | ||
* NOTE: Uses some format heuristics and may be fooled by tricky errors. | ||
* | ||
* TODO: look into better stack parsing libraries. | ||
* See: https://github.com/digitalbazaar/bedrock/issues/87 | ||
*/ | ||
function _parseStack(stack) { | ||
try { | ||
const lines = stack.split('\n'); | ||
const messageLines = []; | ||
const atLines = []; | ||
for(let i = 0; i < lines.length; ++i) { | ||
const line = lines[i]; | ||
// push location-like lines to a stack array | ||
if(line.match(_errorAtRegex)) { | ||
atLines.push(line.replace(_errorAtRegex, '')); | ||
} else { | ||
// push everything else to a message array | ||
messageLines.push(line.replace(_errorMessageRegex, '')); | ||
} | ||
} | ||
return { | ||
message: messageLines.join('\n'), | ||
at: atLines | ||
}; | ||
} catch(e) { | ||
// FIXME: add parse error handling | ||
// see: https://github.com/digitalbazaar/bedrock/issues/87 | ||
return stack; | ||
} | ||
} | ||
function _toObject(err, options) { | ||
if(!err) { | ||
return null; | ||
} | ||
if(options.public) { | ||
// public conversion | ||
// FIXME also check if a validation type? | ||
if(err instanceof api.BedrockError && | ||
err.details && err.details.public) { | ||
const details = api.clone(err.details); | ||
delete details.public; | ||
// mask cause if it is not a public bedrock error | ||
let {cause} = err; | ||
if(!(cause && cause instanceof api.BedrockError && | ||
cause.details && cause.details.public)) { | ||
cause = null; | ||
} | ||
return { | ||
message: err.message, | ||
type: err.name, | ||
details, | ||
cause: _toObject(cause, options) | ||
}; | ||
} else { | ||
// non-bedrock error or not public, return generic error | ||
return _genericErrorJSON; | ||
} | ||
} else { | ||
// full private conversion | ||
if(err instanceof api.BedrockError) { | ||
return { | ||
message: err.message, | ||
type: err.name, | ||
details: err.details, | ||
cause: _toObject(err.cause, options) | ||
}; | ||
} else { | ||
return { | ||
message: err.message, | ||
type: err.name, | ||
details: { | ||
inspect: util.inspect(err, false, 10), | ||
stack: _parseStack(err.stack) | ||
}, | ||
cause: null | ||
}; | ||
} | ||
} | ||
} | ||
/** | ||
* Gets the passed date in W3C format (eg: 2011-03-09T21:55:41Z). | ||
* | ||
* @param date the date. | ||
* @param {Date|string|number} [date=new Date] - The date; if passing a number | ||
* use milliseconds since the epoch. | ||
* | ||
* @return the date in W3C format. | ||
* @returns {string} The date in W3C format. | ||
*/ | ||
api.w3cDate = function(date) { | ||
export function w3cDate(date) { | ||
if(date === undefined || date === null) { | ||
@@ -183,3 +86,3 @@ date = new Date(); | ||
_zeroFill(date.getUTCSeconds())); | ||
}; | ||
} | ||
@@ -193,9 +96,10 @@ function _zeroFill(num) { | ||
* | ||
* @param deep (optional), true to do a deep-merge. | ||
* @param target the target object to merge properties into. | ||
* @param objects N objects to merge into the target. | ||
* Arguments: | ||
* `deep` (optional), true to do a deep-merge | ||
* `target` the target object to merge properties into | ||
* `objects` N objects to merge into the target. | ||
* | ||
* @return the default Bedrock JSON-LD context. | ||
* @returns {object} - The extended object. | ||
*/ | ||
api.extend = function() { | ||
export function extend() { | ||
let deep = false; | ||
@@ -213,4 +117,4 @@ let i = 0; | ||
const value = obj[name]; | ||
if(deep && api.isObject(value) && !Array.isArray(value)) { | ||
target[name] = api.extend(true, target[name], value); | ||
if(deep && isObject(value) && !Array.isArray(value)) { | ||
target[name] = extend(true, target[name], value); | ||
} else { | ||
@@ -222,3 +126,3 @@ target[name] = value; | ||
return target; | ||
}; | ||
} | ||
@@ -228,18 +132,19 @@ /** | ||
* | ||
* @param value the value to check. | ||
* @param {*} value - The value to check. | ||
* | ||
* @return true if it is an Object, false if not. | ||
* @returns {boolean} True if it is an Object, false if not. | ||
*/ | ||
api.isObject = function(value) { | ||
export function isObject(value) { | ||
return (Object.prototype.toString.call(value) === '[object Object]'); | ||
}; | ||
} | ||
/** | ||
* Clones a value. If the value is an array or an object it will be deep cloned. | ||
* Clones a value. If the value is an array or an object it will be deep | ||
* cloned. | ||
* | ||
* @param value the value to clone. | ||
* @param {*} value - The value to clone. | ||
* | ||
* @return the clone. | ||
* @returns {*} The clone. | ||
*/ | ||
api.clone = function(value) { | ||
export function clone(value) { | ||
if(value && typeof value === 'object') { | ||
@@ -250,3 +155,3 @@ let rval; | ||
for(let i = 0; i < rval.length; i++) { | ||
rval[i] = api.clone(value[i]); | ||
rval[i] = clone(value[i]); | ||
} | ||
@@ -256,3 +161,3 @@ } else { | ||
for(const j in value) { | ||
rval[j] = api.clone(value[j]); | ||
rval[j] = clone(value[j]); | ||
} | ||
@@ -263,202 +168,10 @@ } | ||
return value; | ||
}; | ||
// config utilities | ||
// config namespace | ||
api.config = {}; | ||
// check if argument looks like a string or array path | ||
function _isPath(maybePath) { | ||
return typeof maybePath === 'string' || Array.isArray(maybePath); | ||
} | ||
// set default for path if it does not exist | ||
function _setDefault(object, path, value) { | ||
// ensure path is array | ||
if(typeof path === 'string') { | ||
path = lodashToPath(path); | ||
} | ||
if(path.length) { | ||
let target = lodashGet(object, path); | ||
if(!target) { | ||
target = value; | ||
lodashSet(object, path, target); | ||
} | ||
return target; | ||
} else { | ||
return object; | ||
} | ||
} | ||
/** | ||
* Wrapper with helpers for config objects. | ||
* | ||
* @param object the config object. | ||
* @param [options] options to use: | ||
* config: parent config object | ||
* locals: object containing variables used for string templates. | ||
* Defaults to main config object. | ||
*/ | ||
api.config.Config = function(object, options) { | ||
this.object = object; | ||
this.options = options || {}; | ||
}; | ||
/** | ||
* Set a path to a value. | ||
* | ||
* Multiple paths can be set at once with an object with many string path keys | ||
* and associated values. | ||
* | ||
* @param path lodash-style string or array path, or an object with many path | ||
* key and value pairs. | ||
* @param value value to set at the path when using single path. | ||
*/ | ||
api.config.Config.prototype.set = function(path, value) { | ||
if(!_isPath(path)) { | ||
Object.keys(path).forEach(key => lodashSet(this.object, key, path[key])); | ||
return; | ||
} | ||
lodashSet(this.object, path, value); | ||
}; | ||
/** | ||
* Set a path to a default value if it does not exist. All elements of the path | ||
* will be initialized as an empty object if they do not exist. | ||
* | ||
* Multiple paths can be set at once with an object with many string path keys | ||
* and associated default values; | ||
* | ||
* Note: To initialize the final element of a path to the empty object even if | ||
* it already exists, use c.set(path, {}); | ||
* | ||
* @param path lodash-style string or array path, or an object with many path | ||
* key and default value pairs. | ||
* @param value default value to set at the path when using a single path. | ||
* @return the last element of the path or a path indexed object with element | ||
* values. | ||
*/ | ||
api.config.Config.prototype.setDefault = function(path, value) { | ||
if(!_isPath(path)) { | ||
const paths = {}; | ||
Object.keys(path).forEach(key => { | ||
paths[key] = _setDefault(this.object, key, path[key]); | ||
}); | ||
return paths; | ||
} | ||
return _setDefault(this.object, path, value); | ||
}; | ||
/** | ||
* Assigns a getter to a config path. When the config path is read, the getter | ||
* will execute and compute the configured value. This is particularly useful | ||
* for config values that depend on other config values; it removes the need | ||
* to update such a value when its dependencies change. | ||
* | ||
* The value can be computed from a function or from a lodash template that | ||
* will be evaluated using `bedrock.config` for its local variables. | ||
* | ||
* @param path lodash-style string or array path, or an object with many path | ||
* key and value pairs. | ||
* @param fnOrExpression a lodash template or a function used to compute the | ||
* path value. | ||
* @param [options] options to use: | ||
* locals: object containing variables used for string templates. | ||
* parentDefault: value for parent if it does not exist. | ||
*/ | ||
api.config.Config.prototype.setComputed = | ||
function(path, fnOrExpression, options) { | ||
if(!_isPath(path)) { | ||
options = fnOrExpression; | ||
Object.keys(path).forEach(key => this.setComputed( | ||
key, path[key], options)); | ||
return; | ||
} | ||
if(typeof fnOrExpression === 'string') { | ||
// handle strings as templates | ||
fnOrExpression = lodashTemplate(fnOrExpression); | ||
} else if(typeof fnOrExpression !== 'function') { | ||
// handle non-string non-functions as simple values | ||
return this.set(path, fnOrExpression); | ||
} | ||
// ensure path is array | ||
if(typeof path === 'string') { | ||
path = lodashToPath(path); | ||
} | ||
// locals | ||
options = options || {}; | ||
const locals = options.locals || this.options.locals || config; | ||
// get target object path | ||
const targetPath = path.slice(0, -1); | ||
// get key | ||
const targetKey = path.slice(-1); | ||
// get or create target parent object | ||
const parentDefault = options.parentDefault || {}; | ||
const target = _setDefault(this.object, targetPath, parentDefault); | ||
// setup property | ||
let _isSet = false; | ||
let _value; | ||
Object.defineProperty(target, targetKey, { | ||
configurable: true, | ||
enumerable: true, | ||
get: () => { | ||
if(_isSet) { | ||
return _value; | ||
} | ||
return fnOrExpression(locals); | ||
}, | ||
set: value => { | ||
_isSet = true; | ||
_value = value; | ||
} | ||
}); | ||
}; | ||
/** | ||
* Create a bound setComputed function for this Config instance. Used to | ||
* simplify code. | ||
* | ||
* let cc = bedrock.util.config.main.computer(); | ||
* cc('...', ...); | ||
* | ||
* @return bound setComputed function. | ||
*/ | ||
api.config.Config.prototype.computer = function() { | ||
return this.setComputed.bind(this); | ||
}; | ||
/** | ||
* Push a getter to an array specified by a config path. See setComputed for an | ||
* explaination of how getters work. | ||
* | ||
* @param path lodash-style string or array path. | ||
* @param fnOrExpression a lodash template or a function used to compute the | ||
* path value. | ||
* @param [options] options to use: | ||
* locals: object containing variables used for string templates. | ||
*/ | ||
api.config.Config.prototype.pushComputed = | ||
function(path, fnOrExpression, options) { | ||
// get target or default array | ||
const target = lodashGet(this.object, path, []); | ||
// add next index | ||
const pushPath = lodashToPath(path); | ||
pushPath.push(target.length); | ||
// use default parent array | ||
const pushOptions = Object.assign({}, options, {parentDefault: []}); | ||
// set computed array element | ||
this.setComputed(pushPath, fnOrExpression, pushOptions); | ||
}; | ||
/** | ||
* Shared wrapper for the standard bedrock config. | ||
*/ | ||
api.config.main = new api.config.Config(config); | ||
/** | ||
* Generates a new v4 UUID. | ||
* | ||
* @return the new v4 UUID. | ||
* @returns {string} The new v4 UUID. | ||
*/ | ||
api.uuid = uuid; | ||
export {uuid}; | ||
@@ -470,7 +183,7 @@ /** | ||
* | ||
* @param value a string of value. | ||
* @param {string} value - The value to convert to a boolean. | ||
* | ||
* @return the boolean conversion of the value. | ||
* @returns {boolean} The boolean conversion of the value. | ||
*/ | ||
api.boolify = function(value) { | ||
export function boolify(value) { | ||
if(typeof value === 'boolean') { | ||
@@ -497,5 +210,5 @@ return value; | ||
throw new Error('Invalid boolean:' + value); | ||
}; | ||
} | ||
api.callbackify = fn => { | ||
export function callbackify(fn) { | ||
const callbackVersion = util.callbackify(fn); | ||
@@ -509,6 +222,6 @@ return function(...args) { | ||
}; | ||
}; | ||
} | ||
// a replacement for jsonld.hasValue | ||
api.hasValue = (obj, key, value) => { | ||
export function hasValue(obj, key, value) { | ||
const t = obj[key]; | ||
@@ -519,2 +232,100 @@ if(Array.isArray(t)) { | ||
return t === value; | ||
} | ||
const _genericErrorJSON = { | ||
message: 'An internal server error occurred.', | ||
type: 'bedrock.InternalServerError' | ||
}; | ||
const _errorMessageRegex = /^Error:\s*/; | ||
const _errorAtRegex = /^\s+at\s*/; | ||
/** | ||
* Parse an Error stack property into an object structure that can be | ||
* serialized to JSON. | ||
* | ||
* NOTE: Uses some format heuristics and may be fooled by tricky errors. | ||
* | ||
* TODO: look into better stack parsing libraries. | ||
* See: https://github.com/digitalbazaar/bedrock/issues/87. | ||
* | ||
* @param {string} stack - The stack trace. | ||
* | ||
* @returns {object} Stack trace as an object. | ||
*/ | ||
function _parseStack(stack) { | ||
try { | ||
const lines = stack.split('\n'); | ||
const messageLines = []; | ||
const atLines = []; | ||
for(let i = 0; i < lines.length; ++i) { | ||
const line = lines[i]; | ||
// push location-like lines to a stack array | ||
if(line.match(_errorAtRegex)) { | ||
atLines.push(line.replace(_errorAtRegex, '')); | ||
} else { | ||
// push everything else to a message array | ||
messageLines.push(line.replace(_errorMessageRegex, '')); | ||
} | ||
} | ||
return { | ||
message: messageLines.join('\n'), | ||
at: atLines | ||
}; | ||
} catch(e) { | ||
// FIXME: add parse error handling | ||
// see: https://github.com/digitalbazaar/bedrock/issues/87 | ||
return stack; | ||
} | ||
} | ||
function _toObject(err, options) { | ||
if(!err) { | ||
return null; | ||
} | ||
if(options.public) { | ||
// public conversion | ||
// FIXME also check if a validation type? | ||
if(err instanceof BedrockError && | ||
err.details && err.details.public) { | ||
const details = clone(err.details); | ||
delete details.public; | ||
// mask cause if it is not a public bedrock error | ||
let {cause} = err; | ||
if(!(cause && cause instanceof BedrockError && | ||
cause.details && cause.details.public)) { | ||
cause = null; | ||
} | ||
return { | ||
message: err.message, | ||
type: err.name, | ||
details, | ||
cause: _toObject(cause, options) | ||
}; | ||
} else { | ||
// non-bedrock error or not public, return generic error | ||
return _genericErrorJSON; | ||
} | ||
} else { | ||
// full private conversion | ||
if(err instanceof BedrockError) { | ||
return { | ||
message: err.message, | ||
type: err.name, | ||
details: err.details, | ||
cause: _toObject(err.cause, options) | ||
}; | ||
} else { | ||
return { | ||
message: err.message, | ||
type: err.name, | ||
details: { | ||
inspect: util.inspect(err, false, 10), | ||
stack: _parseStack(err.stack) | ||
}, | ||
cause: null | ||
}; | ||
} | ||
} | ||
} |
/*! | ||
* Copyright (c) 2012-2021 Digital Bazaar, Inc. All rights reserved. | ||
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved. | ||
*/ | ||
'use strict'; | ||
// wait for initialization options from primary | ||
@@ -20,3 +18,5 @@ process.on('message', init); | ||
require(msg.script); | ||
import(msg.script).catch(e => { | ||
throw e; | ||
}); | ||
} |
{ | ||
"name": "bedrock", | ||
"version": "4.4.3", | ||
"version": "4.5.0", | ||
"description": "A core foundation for rich Web applications.", | ||
@@ -32,2 +32,3 @@ "license": "SEE LICENSE IN LICENSE.md", | ||
"errio": "^1.2.2", | ||
"esm": "^3.2.25", | ||
"fast-safe-stringify": "^2.0.7", | ||
@@ -38,3 +39,2 @@ "lodash.get": "^4.4.2", | ||
"lodash.topath": "^4.5.2", | ||
"pkginfo": "^0.4.1", | ||
"triple-beam": "^1.3.0", | ||
@@ -48,4 +48,7 @@ "uid-number": "0.0.6", | ||
"devDependencies": { | ||
"eslint": "^7.0.0", | ||
"eslint-config-digitalbazaar": "^2.5.0" | ||
"eslint": "^7.32.0", | ||
"eslint-config-digitalbazaar": "^2.8.0", | ||
"eslint-plugin-jsdoc": "^37.9.7", | ||
"jsdoc": "^3.6.10", | ||
"jsdoc-to-markdown": "^7.1.1" | ||
}, | ||
@@ -55,3 +58,3 @@ "engines": { | ||
}, | ||
"main": "./lib/bedrock" | ||
"main": "./lib/index.js" | ||
} |
@@ -7,4 +7,4 @@ { | ||
"test": "node --preserve-symlinks test test", | ||
"coverage": "cross-env NODE_ENV=test nyc --reporter=lcov --reporter=text-summary npm test", | ||
"coverage-ci": "cross-env NODE_ENV=test nyc --reporter=lcovonly npm test", | ||
"coverage": "cross-env NODE_ENV=test ESM_OPTIONS='{cache:false}' nyc --reporter=lcov --reporter=text-summary npm test", | ||
"coverage-ci": "cross-env NODE_ENV=test ESM_OPTIONS='{cache:false}' nyc --reporter=lcovonly npm test", | ||
"coverage-report": "nyc report" | ||
@@ -11,0 +11,0 @@ }, |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
159688
28
2444
2
5
+ Addedesm@^3.2.25
- Removedpkginfo@^0.4.1
- Removedpkginfo@0.4.1(transitive)