Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

low

Package Overview
Dependencies
Maintainers
1
Versions
41
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

low - npm Package Compare versions

Comparing version 1.0.4 to 1.1.1

docs/classes/_connectors_connector_.connector.html

123

lib/cache-managers/cache-manager.js
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -14,58 +23,66 @@ const crypto_1 = require("crypto");

}
async makeKey(config, context) {
let data = '';
for (const path of config.keyProperties) {
const part = object_compiler_1.ObjectCompiler.objectPath(context, path);
data += JSON.stringify(part);
}
const hash = crypto_1.createHash('sha1')
.update(data)
.digest('hex');
return {
partition: config.partition,
key: hash
};
makeKey(config, context) {
return __awaiter(this, void 0, void 0, function* () {
let data = '';
for (const path of config.keyProperties) {
const part = object_compiler_1.ObjectCompiler.objectPath(context, path);
data += JSON.stringify(part);
}
const hash = crypto_1.createHash('sha1')
.update(data)
.digest('hex');
return {
partition: config.partition,
key: hash
};
});
}
async getItem(cacheKey) {
if (!this.CACHE.hasOwnProperty(cacheKey.partition)) {
this.CACHE[cacheKey.partition] = {};
return null;
}
if (!this.CACHE[cacheKey.partition].hasOwnProperty(cacheKey.key)) {
return null;
}
const expires = this.CACHE[cacheKey.partition][cacheKey.key].expires;
const now = new Date();
if (expires < now) {
delete this.CACHE[cacheKey.partition][cacheKey.key];
return null;
}
this.CACHE[cacheKey.partition][cacheKey.key].touched = now;
return this.CACHE[cacheKey.partition][cacheKey.key].data;
getItem(cacheKey) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.CACHE.hasOwnProperty(cacheKey.partition)) {
this.CACHE[cacheKey.partition] = {};
return null;
}
if (!this.CACHE[cacheKey.partition].hasOwnProperty(cacheKey.key)) {
return null;
}
const expires = this.CACHE[cacheKey.partition][cacheKey.key].expires;
const now = new Date();
if (expires < now) {
delete this.CACHE[cacheKey.partition][cacheKey.key];
return null;
}
this.CACHE[cacheKey.partition][cacheKey.key].touched = now;
return this.CACHE[cacheKey.partition][cacheKey.key].data;
});
}
async setItem(cacheKey, item, ttl) {
if (!this.CACHE.hasOwnProperty(cacheKey.partition)) {
this.CACHE[cacheKey.partition] = {};
}
const now = new Date();
const expires = new Date(+new Date() + ttl);
if (!this.CACHE[cacheKey.partition].hasOwnProperty(cacheKey.key)) {
this.CACHE[cacheKey.partition][cacheKey.key] = {
data: item,
created: now,
updated: now,
expires: expires,
touched: new Date(0)
};
}
else {
this.CACHE[cacheKey.partition][cacheKey.key].data = item;
this.CACHE[cacheKey.partition][cacheKey.key].updated = now;
this.CACHE[cacheKey.partition][cacheKey.key].expires = expires;
}
setItem(cacheKey, item, ttl) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.CACHE.hasOwnProperty(cacheKey.partition)) {
this.CACHE[cacheKey.partition] = {};
}
const now = new Date();
const expires = new Date(+new Date() + ttl);
if (!this.CACHE[cacheKey.partition].hasOwnProperty(cacheKey.key)) {
this.CACHE[cacheKey.partition][cacheKey.key] = {
data: item,
created: now,
updated: now,
expires: expires,
touched: new Date(0)
};
}
else {
this.CACHE[cacheKey.partition][cacheKey.key].data = item;
this.CACHE[cacheKey.partition][cacheKey.key].updated = now;
this.CACHE[cacheKey.partition][cacheKey.key].expires = expires;
}
});
}
async bust(partition) {
if (this.CACHE.hasOwnProperty(partition)) {
delete this.CACHE[partition];
}
flush(partition) {
return __awaiter(this, void 0, void 0, function* () {
if (this.CACHE.hasOwnProperty(partition)) {
delete this.CACHE[partition];
}
});
}

@@ -72,0 +89,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const module_1 = require("../module");
const object_compiler_1 = require("../object-compiler");
//import { Log } from '../log';
class Doer extends module_1.Module {
async execute(context, task) {
try {
let cacheManager;
let cacheKey;
if (task.cacheConfig) {
cacheManager = this.env.getCacheManager(task.cacheConfig.cacheManager);
cacheKey = await cacheManager.makeKey(task.cacheConfig, context);
const cachedItem = await cacheManager.getItem(cacheKey);
if (cachedItem) {
context.data[task.name] = cachedItem;
return;
execute(context, task) {
return __awaiter(this, void 0, void 0, function* () {
try {
//Log.info(context, this.moduleType, `Executing task ${task.name}`);
let cacheManager;
let cacheKey;
if (task.cacheConfig) {
//Log.info(context, this.moduleType, `Loading cache manager '${task.cacheConfig.cacheManager}`);
cacheManager = this.env.getCacheManager(task.cacheConfig.cacheManager);
cacheKey = yield cacheManager.makeKey(task.cacheConfig, context);
const cachedItem = yield cacheManager.getItem(cacheKey);
if (cachedItem) {
//Log.info(context, 'Found cached item');
//Log.log(context, 'Found cached item', cachedItem);
context.data[task.name] = cachedItem;
return;
}
}
const coreConfig = yield object_compiler_1.ObjectCompiler.compile(task.config, context);
const output = yield this.main(context, task, coreConfig);
context.data[task.name] = output;
if (cacheManager && cacheKey) {
yield cacheManager.setItem(cacheKey, output, task.cacheConfig.ttl);
}
}
const coreConfig = await object_compiler_1.ObjectCompiler.compile(task.config, context);
const output = await this.main(context, task, coreConfig);
context.data[task.name] = output;
if (cacheManager && cacheKey) {
await cacheManager.setItem(cacheKey, output, task.cacheConfig.ttl);
catch (err) {
context.errors[task.name] = err;
if (task.throwError) {
throw err;
}
}
}
catch (err) {
context.errors[task.name] = err;
}
});
}
async main(context, taskConfig, coreConfig) {
return coreConfig;
main(context, taskConfig, coreConfig) {
return __awaiter(this, void 0, void 0, function* () {
return coreConfig;
});
}

@@ -33,0 +54,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -6,19 +15,24 @@ const doer_1 = require("./doer");

class MultiDoer extends doer_1.Doer {
async main(context, taskConfig, multiDoerTasks) {
for (const multiDoerTask of multiDoerTasks) {
const doer = this.env.getDoer(multiDoerTask.task.doer);
await doer.execute(context, multiDoerTask.task);
if (multiDoerTask.branch) {
const branchConfig = await object_compiler_1.ObjectCompiler.compile(multiDoerTask.branch, context);
if (!branchConfig.taskName) {
throw new Error(`Invalid BranchConfig for task '${multiDoerTask.task.name}'`);
main(context, taskConfig, multiDoerTasks) {
return __awaiter(this, void 0, void 0, function* () {
for (const multiDoerTask of multiDoerTasks) {
const task = typeof multiDoerTask.task === 'string' ?
this.env.getTask(multiDoerTask.task) :
multiDoerTask.task;
const doer = this.env.getDoer(task.doer);
yield doer.execute(context, task);
if (multiDoerTask.branch) {
const branchConfig = yield object_compiler_1.ObjectCompiler.compile(multiDoerTask.branch, context);
if (!branchConfig.taskName) {
throw new Error(`Invalid BranchConfig for task '${task.name}'`);
}
const branchTask = this.env.getTask(branchConfig.taskName);
const branchDoer = this.env.getDoer(branchTask.doer);
yield branchDoer.execute(context, branchTask);
if (branchConfig.haltAfterExecution) {
break;
}
}
const branchTask = this.env.getTask(branchConfig.taskName);
const branchDoer = this.env.getDoer(branchTask.doer);
await branchDoer.execute(context, branchTask);
if (branchConfig.haltAfterExecution) {
break;
}
}
}
});
}

@@ -25,0 +39,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const boundary_1 = require("./boundaries/boundary");
const connector_1 = require("./connectors/connector");
const cache_manager_1 = require("./cache-managers/cache-manager");

@@ -12,4 +21,6 @@ const doer_1 = require("./doers/doer");

const url_parser_1 = require("./parsers/url-parser");
const querystring_parser_1 = require("./parsers/querystring-parser");
const renderer_1 = require("./renderers/renderer");
const multi_doer_1 = require("./doers/multi-doer");
const log_1 = require("./log");
/**

@@ -43,8 +54,9 @@ * The Environment class is the core of a `low` system.

this.ready = false;
this.logLevel = log_1.LogLevel.ERROR;
/**
* A collection of [[Boundary]] modules. Boundaries are gateways from
* A collection of [[Connector]] modules. Connectors are gateways from
* your application or external sources to run tasks in the `low` Environment
*/
this.boundaries = {
Boundary: new boundary_1.Boundary()
this.connectors = {
Connector: new connector_1.Connector()
};

@@ -75,3 +87,4 @@ /**

StringParser: new string_parser_1.StringParser(),
UrlParser: new url_parser_1.UrlParser()
UrlParser: new url_parser_1.UrlParser(),
QuerystringParser: new querystring_parser_1.QuerystringParser(),
};

@@ -86,5 +99,5 @@ /**

};
if (modules.boundaries) {
for (const mod of modules.boundaries) {
this.boundaries[mod.moduleType] = mod;
if (modules.connectors) {
for (const mod of modules.connectors) {
this.connectors[mod.moduleType] = mod;
}

@@ -124,40 +137,41 @@ }

loadSecrets(secretsName) {
//TODO: What the heck actually happens when you try to access `process`
// in a browser. Need more checks around this
const secretsVar = process.env[secretsName];
if (!secretsVar)
if (!process) {
console.warn('No `process` object for environment variables. Probably in a browser');
return;
if (secretsVar.indexOf('{') > -1) {
this.secrets = JSON.parse(secretsVar);
}
else {
//This will obviously not work in the browser so be sure to set
//your secretsName variable properly. Don't like doing `require`
//but not sure how else to make `fs` conditional. Moar research!
const fs = require('fs');
const secretsJson = fs.readFileSync(secretsVar).toString();
this.secrets = JSON.parse(secretsJson);
if (!process.env.hasOwnProperty(secretsName)) {
console.warn(`No environment variable named '${secretsName}'.`);
return;
}
const secretsVar = process.env[secretsName] || '{}';
this.secrets = JSON.parse(secretsVar);
}
async init() {
for (const mod of Object.values(this.boundaries)) {
await mod.init(this);
}
for (const mod of Object.values(this.cacheManagers)) {
await mod.init(this);
}
for (const mod of Object.values(this.doers)) {
await mod.init(this);
}
for (const mod of Object.values(this.parsers)) {
await mod.init(this);
}
for (const mod of Object.values(this.renderers)) {
await mod.init(this);
}
const taskReport = this.checkTasks();
if (taskReport) {
throw new Error(`There are one or more task configuration problems\n${taskReport}`);
}
this.ready = true;
init() {
return __awaiter(this, void 0, void 0, function* () {
for (const mod of Object.values(this.connectors)) {
yield mod.init(this);
}
for (const mod of Object.values(this.cacheManagers)) {
yield mod.init(this);
}
for (const mod of Object.values(this.doers)) {
yield mod.init(this);
}
for (const mod of Object.values(this.parsers)) {
yield mod.init(this);
}
for (const mod of Object.values(this.renderers)) {
yield mod.init(this);
}
const taskReport = this.checkTasks();
if (taskReport) {
throw new Error(`There are one or more task configuration problems\n${taskReport}`);
}
this.ready = true;
if (this.config.startupTask) {
const task = this.getTask(this.config.startupTask);
const connector = this.getConnector('Connector');
yield connector.runTask(task, {}, {});
}
});
}

@@ -190,11 +204,11 @@ checkTasks() {

}
getBoundary(name) {
if (!this.boundaries.hasOwnProperty(name)) {
throw new Error(`No Boundary called '${name}' loaded`);
getConnector(name) {
if (!this.connectors.hasOwnProperty(name)) {
throw new Error(`No Connector called '${name}' loaded`);
}
const boundary = this.boundaries[name];
if (!boundary.isReady) {
throw new Error(`The Boundary called '${name}' is loaded but not ready. Has the environment been initialised?`);
const connector = this.connectors[name];
if (!connector.isReady) {
throw new Error(`The Connector called '${name}' is loaded but not ready. Has the environment been initialised?`);
}
return boundary;
return connector;
}

@@ -250,4 +264,26 @@ getCacheManager(name) {

}
destroy() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.ready) {
return;
}
for (const mod of Object.values(this.connectors)) {
yield mod.destroy();
}
for (const mod of Object.values(this.cacheManagers)) {
yield mod.destroy();
}
for (const mod of Object.values(this.doers)) {
yield mod.destroy();
}
for (const mod of Object.values(this.parsers)) {
yield mod.destroy();
}
for (const mod of Object.values(this.renderers)) {
yield mod.destroy();
}
});
}
}
exports.Environment = Environment;
//# sourceMappingURL=environment.js.map
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
//import { Log } from './log';
class Module {
constructor() {
this.secrets = {};
this.config = {};
this.ready = false;
this._ready = false;
}

@@ -15,2 +23,14 @@ get env() {

}
get config() {
if (!this._config) {
throw new Error('No Config have been set. Has this Module been setup correctly?');
}
return this._config;
}
get secrets() {
if (!this._secrets) {
throw new Error('No Secrets have been set. Has this Module been setup correctly?');
}
return this._secrets;
}
get moduleType() {

@@ -20,18 +40,29 @@ return this.constructor.name;

get isReady() {
return this.ready;
return this._ready;
}
async init(env) {
if (this.ready) {
await this.destroy();
this.ready = false;
}
this._env = env;
this.config = env.config.modules && env.config.modules[this.moduleType] || {};
this.secrets = env.secrets.modules && env.secrets.modules[this.moduleType] || {};
await this.setup();
this.ready = true;
init(env) {
return __awaiter(this, void 0, void 0, function* () {
//Log.log(env, this.moduleType, `Initialising`);
if (this._ready) {
//Log.warn(env, this.moduleType, 'Module already initialised. Destroying and re-initialising');
yield this.destroy();
this._ready = false;
}
this._env = env;
this._config = env.config.modules && env.config.modules[this.moduleType] || {};
//Log.log(env, this.moduleType, `Set config:`, this.config);
this._secrets = env.secrets.modules && env.secrets.modules[this.moduleType] || {};
//Log.log(env, this.moduleType, `Set secrets:`, this.secrets);
yield this.setup();
this._ready = true;
//Log.log(env, this.moduleType, `Module ready`);
});
}
async setup() { return; }
setup() {
return __awaiter(this, void 0, void 0, function* () { return; });
}
;
async destroy() { return; }
destroy() {
return __awaiter(this, void 0, void 0, function* () { return; });
}
;

@@ -38,0 +69,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
//TODO: Should this be a Module or is that going to far?
//I'm leaning on No because this is a bit fundamental and secret-sauce
class ObjectCompiler {
static isTemplate(property) {
return property && (property.hasOwnProperty('__template') || property.hasOwnProperty('__templatePath'));
return typeof property === 'object' && property !== null && property.hasOwnProperty('__template');
}
static async compile(config, context, specialProperties) {
if (typeof config !== 'object') {
return config;
}
//May not be necessary
let output = JSON.parse(JSON.stringify(config));
if (specialProperties) {
for (const prop of specialProperties) {
const property = ObjectCompiler.objectPath(output, prop);
output[prop] = await ObjectCompiler.compileProperty(property, context);
static compile(config, context, specialProperties) {
return __awaiter(this, void 0, void 0, function* () {
if (typeof config !== 'object' || config === null) {
return config;
}
}
else {
output = await ObjectCompiler.compileProperty(output, context);
}
return output;
}
static async compileProperty(property, context) {
const resolvedProperty = ObjectCompiler.resolvePointer(property, context);
if (ObjectCompiler.isTemplate(resolvedProperty)) {
const renderer = context.env.getRenderer(resolvedProperty.__renderer);
return await renderer.render(resolvedProperty, context);
}
if (Array.isArray(resolvedProperty)) {
const compiled = [];
for (const item of resolvedProperty) {
const resolved = await ObjectCompiler.compileProperty(item, context);
compiled.push(resolved);
//May not be necessary
let output = JSON.parse(JSON.stringify(config));
if (specialProperties) {
for (const prop of specialProperties) {
const property = ObjectCompiler.objectPath(output, prop);
output[prop] = yield ObjectCompiler.compileProperty(property, context);
}
}
return compiled;
}
if (typeof resolvedProperty === 'object') {
const output = {};
for (const [key, value] of Object.entries(resolvedProperty)) {
output[key] = await ObjectCompiler.compileProperty(value, context);
else {
output = yield ObjectCompiler.compileProperty(output, context);
}
return output;
}
return resolvedProperty;
});
}
static compileProperty(property, context) {
return __awaiter(this, void 0, void 0, function* () {
const resolvedProperty = ObjectCompiler.resolvePointer(property, context);
if (ObjectCompiler.isTemplate(resolvedProperty)) {
const renderer = context.env.getRenderer(resolvedProperty.__renderer || 'Renderer');
return yield renderer.render(resolvedProperty, context);
}
if (Array.isArray(resolvedProperty)) {
const compiled = [];
for (const item of resolvedProperty) {
const spread = typeof item === 'object' && item !== null && item.hasOwnProperty('__spread');
const resolved = yield ObjectCompiler.compileProperty(item, context);
if (spread && Array.isArray(resolved)) {
compiled.push(...resolved);
}
else {
compiled.push(resolved);
}
}
return compiled;
}
if (typeof resolvedProperty === 'object' && resolvedProperty !== null && !resolvedProperty.hasOwnProperty('__doNotCompile')) {
const output = {};
for (const [key, value] of Object.entries(resolvedProperty)) {
const spread = typeof value === 'object' && value !== null && value.hasOwnProperty('__spread');
const resolved = yield ObjectCompiler.compileProperty(value, context);
if (spread && typeof resolved === 'object' && resolved !== null) {
for (const [resolvedKey, resolvedValue] of Object.entries(resolved)) {
output[resolvedKey] = resolvedValue;
}
}
else {
//Not sure why I need to cast value to any here. I'm already checking above that the key "__key" exists on it
const keyConfig = typeof value === 'object' && value !== null && value.hasOwnProperty('__key') && value.__key || null;
if (keyConfig) {
keyConfig.__parser = 'StringParser';
const renderer = context.env.getRenderer(keyConfig.__renderer || 'Renderer');
const renderedKey = yield renderer.render(value.__key, Object.assign(Object.assign({}, context), { resolvedValue: value }));
output[renderedKey] = resolved;
}
else {
output[key] = resolved;
}
}
}
return output;
}
return resolvedProperty;
});
}
static resolvePointer(property, context) {

@@ -67,4 +103,4 @@ if (!property || !property.hasOwnProperty('__pointer'))

}
exports.ObjectCompiler = ObjectCompiler;
ObjectCompiler.objectPathCache = {};
exports.ObjectCompiler = ObjectCompiler;
//# sourceMappingURL=object-compiler.js.map
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -33,46 +42,48 @@ const parser_1 = require("./parser");

}
async parse(input, config) {
try {
if (config.interperateStrings && typeof input === 'string') {
if (Array.isArray(config.interperateStrings)) {
return config.interperateStrings.includes(input.toLowerCase());
}
else if (config.interperateStrings.hasOwnProperty('regex')) {
const regex = new RegExp(config.interperateStrings.regex, config.interperateStrings.options || 'ig');
return regex.test(input);
}
else {
return this.trueStrings.includes(input.toLowerCase());
}
}
else if (config.emptyObjectsAsFalse && typeof input === 'object') {
if (Array.isArray(input)) {
if (config.removeObjectNullValues) {
return input.filter(item => item !== null && typeof item !== 'undefined').length > 0;
parse(input, config) {
return __awaiter(this, void 0, void 0, function* () {
try {
if (config.interperateStrings && typeof input === 'string') {
if (Array.isArray(config.interperateStrings)) {
return config.interperateStrings.includes(input.toLowerCase());
}
else if (config.interperateStrings.hasOwnProperty('regex')) {
const regex = new RegExp(config.interperateStrings.regex, config.interperateStrings.options || 'ig');
return regex.test(input);
}
else {
return input.length > 0;
return this.trueStrings.includes(input.toLowerCase());
}
}
else {
if (config.removeObjectNullValues) {
return Object.values(input).filter(value => value !== null && typeof value !== 'undefined').length > 0;
else if (config.emptyObjectsAsFalse && typeof input === 'object') {
if (Array.isArray(input)) {
if (config.removeObjectNullValues) {
return input.filter(item => item !== null && typeof item !== 'undefined').length > 0;
}
else {
return input.length > 0;
}
}
else {
return Object.keys(input).length > 0;
if (config.removeObjectNullValues) {
return Object.values(input).filter(value => value !== null && typeof value !== 'undefined').length > 0;
}
else {
return Object.keys(input).length > 0;
}
}
}
else {
return Boolean(input);
}
}
else {
return Boolean(input);
catch (err) {
if (typeof config.defaultValue === 'boolean') {
return config.defaultValue;
}
else {
throw err;
}
}
}
catch (err) {
if (typeof config.defaultValue === 'boolean') {
return config.defaultValue;
}
else {
throw err;
}
}
});
}

@@ -79,0 +90,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const parser_1 = require("./parser");
class FloatParser extends parser_1.Parser {
async parse(input, config) {
const output = parseFloat(input);
if (Number.isNaN(output) && config.defaultValue) {
return config.defaultValue;
}
else {
return output;
}
parse(input, config) {
return __awaiter(this, void 0, void 0, function* () {
const output = parseFloat(input);
if (Number.isNaN(output) && config.defaultValue) {
return config.defaultValue;
}
else {
return output;
}
});
}

@@ -14,0 +25,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const parser_1 = require("./parser");
class IntegerParser extends parser_1.Parser {
async parse(input, config) {
const output = parseInt(input, config.radix || 10);
if (Number.isNaN(output) && config.defaultValue) {
return config.defaultValue;
}
else {
return output;
}
parse(input, config) {
return __awaiter(this, void 0, void 0, function* () {
const output = parseInt(input, config.radix || 10);
if (Number.isNaN(output) && config.defaultValue) {
return config.defaultValue;
}
else {
return output;
}
});
}

@@ -14,0 +25,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const parser_1 = require("./parser");
class JsonParser extends parser_1.Parser {
async parse(input, config) {
try {
if (typeof input === 'string') {
return JSON.parse(input);
parse(input, config) {
return __awaiter(this, void 0, void 0, function* () {
try {
if (typeof input === 'string') {
return JSON.parse(input);
}
else {
return input;
}
}
else {
return input;
catch (err) {
if (config.hasOwnProperty('defaultValue')) {
return config.defaultValue;
}
else {
throw err;
}
}
}
catch (err) {
if (config.hasOwnProperty('defaultValue')) {
return config.defaultValue;
}
else {
throw err;
}
}
});
}

@@ -23,0 +34,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -10,14 +19,16 @@ const module_1 = require("../module");

class Parser extends module_1.Module {
async parse(input, config) {
if (typeof input === 'undefined' || input === null) {
if (typeof config.defaultValue === 'undefined' || config.defaultValue === null) {
return null;
parse(input, config) {
return __awaiter(this, void 0, void 0, function* () {
if (typeof input === 'undefined' || input === null) {
if (typeof config.defaultValue === 'undefined' || config.defaultValue === null) {
return null;
}
else {
return config.defaultValue;
}
}
else {
return config.defaultValue;
return input;
}
}
else {
return input;
}
});
}

@@ -24,0 +35,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const parser_1 = require("./parser");
class StringParser extends parser_1.Parser {
async parse(input, config) {
try {
switch (typeof input) {
case ('object'):
return JSON.stringify(input, null, config.spaces);
case ('number'):
switch (config.numberFunction) {
case ('toExponential'):
return input.toExponential(config.fractionDigits || undefined);
case ('toFixed'):
return input.toFixed(config.fractionDigits || undefined);
case ('toLocaleString'):
return input.toLocaleString(config.locales || undefined, config.localeOptions || undefined);
case ('toPrecision'):
return input.toPrecision(config.precision || undefined);
default:
return input.toString(config.radix || undefined);
}
case ('boolean'):
return input === true ? config.trueString || 'true' : config.falseString || 'false';
case ('undefined'):
return config.undefinedString || '';
default:
return input.toString();
parse(input, config) {
return __awaiter(this, void 0, void 0, function* () {
try {
switch (typeof input) {
case ('object'):
return JSON.stringify(input, null, config.spaces);
case ('number'):
switch (config.numberFunction) {
case ('toExponential'):
return input.toExponential(config.fractionDigits || undefined);
case ('toFixed'):
return input.toFixed(config.fractionDigits || undefined);
case ('toLocaleString'):
return input.toLocaleString(config.locales || undefined, config.localeOptions || undefined);
case ('toPrecision'):
return input.toPrecision(config.precision || undefined);
default:
return input.toString(config.radix || undefined);
}
case ('boolean'):
return input === true ? config.trueString || 'true' : config.falseString || 'false';
case ('undefined'):
return config.undefinedString || '';
default:
return input.toString();
}
}
}
catch (err) {
if (typeof config.defaultValue === 'string') {
return config.defaultValue;
catch (err) {
if (typeof config.defaultValue === 'string') {
return config.defaultValue;
}
else {
throw err;
}
}
else {
throw err;
}
}
});
}

@@ -40,0 +51,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -6,14 +15,16 @@ const url_1 = require("url");

class UrlParser extends parser_1.Parser {
async parse(input, config) {
try {
return new url_1.URL(input, config.base || undefined);
}
catch (err) {
if (config.defaultValue) {
return config.defaultValue;
parse(input, config) {
return __awaiter(this, void 0, void 0, function* () {
try {
return new url_1.URL(input, config.base || undefined);
}
else {
throw err;
catch (err) {
if (config.defaultValue) {
return config.defaultValue;
}
else {
throw err;
}
}
}
});
}

@@ -20,0 +31,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const module_1 = require("../module");
class Renderer extends module_1.Module {
async render(config, context) {
const template = await this.getTemplate(config, context);
const rendered = await this.core(template, context);
const parsed = await this.parseRendered(rendered, config);
return parsed;
render(config, context) {
return __awaiter(this, void 0, void 0, function* () {
let cacheManager;
let cacheKey;
if (config.__cacheConfig) {
cacheManager = this.env.getCacheManager(config.__cacheConfig.cacheManager);
cacheKey = yield cacheManager.makeKey(config.__cacheConfig, context);
const cachedItem = yield cacheManager.getItem(cacheKey);
if (cachedItem !== null) {
return cachedItem;
}
}
const template = yield this.getTemplate(config, context);
const rendered = yield this.core(template, context);
const parsed = yield this.parseRendered(rendered, config);
if (cacheManager && cacheKey) {
yield cacheManager.setItem(cacheKey, parsed, config.__cacheConfig.ttl);
}
return parsed;
});
}
async getTemplate(config, context) {
return config.__template;
getTemplate(config, context) {
return __awaiter(this, void 0, void 0, function* () {
return config.__template;
});
}
async parseRendered(rendered, config) {
if (config.__parser) {
const parser = this.env.getParser(config.__parser);
const parsed = await parser.parse(rendered, config.__parserConfig || {});
return parsed;
}
else {
return rendered;
}
parseRendered(rendered, config) {
return __awaiter(this, void 0, void 0, function* () {
if (config.__parser) {
const parser = this.env.getParser(config.__parser);
const parsed = yield parser.parse(rendered, config.__parserConfig || {});
return parsed;
}
else {
return rendered;
}
});
}
async core(template, context) {
return template;
core(template, context) {
return __awaiter(this, void 0, void 0, function* () {
return template;
});
}

@@ -27,0 +57,0 @@ }

{
"name": "low",
"version": "1.0.4",
"description": "a templating driven low-code framework for rapid application developmnet",
"main": "lib/environment.js",
"version": "1.1.1",
"description": "a templating driven low-code framework for rapid systems development",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"homepage": "https://github.com/low-systems/low#readme",

@@ -13,41 +14,14 @@ "repository": {

"clean": "rm -rf docs/; rm -rf lib/; rm -rf coverage/",
"test": "SECRETS='test-secrets.json' SECRETS_ALT='{ \"modules\": { \"Module\": { \"test\": \"It worked\" } } }' jest --coverage",
"test": "jest --coverage",
"build": "npm run clean && tsc && npm test && typedoc"
},
"keywords": [
"lowcode",
"low",
"low",
"code"
],
"author": {
"name": "Matthew Parry-Wilkes",
"url": "https://tonicblue.co.uk"
"name": "Matthew Parry-Wilkes (@SCVO)",
"url": "https://scvo.org"
},
"license": "GPL-3.0",
"jest": {
"roots": [
"<rootDir>/src"
],
"transform": {
"^.+\\.ts$": "ts-jest"
},
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.ts$",
"moduleFileExtensions": [
"ts",
"js",
"json",
"node"
]
"preset": "ts-jest"
},
"devDependencies": {
"@types/jest": "^24.0.15",
"@types/node": "^12.0.8",
"jest": "^24.8.0",
"ts-jest": "^24.0.2",
"tslint": "^5.17.0",
"typedoc": "^0.14.2",
"typescript": "^3.5.2"
},
"dependencies": {}
"gitHead": "715e3e67d5f82a001c2b0dc6119d3e97cbd848f4"
}

@@ -1,2 +0,4 @@

# low
![low logo](resources/logo.png)
# :point_down: low
> a templating driven low-code framework for rapid application developmnet

@@ -52,5 +54,5 @@

* :white_medium_square: Write some basic modules to make the system usable
* :white_medium_square: HTTP `Boundary`
* :white_medium_square: Cron `Boundary`
* :white_medium_square: RabbitMQ `Boundary`
* :white_medium_square: HTTP `Connector`
* :white_medium_square: Cron `Connector`
* :white_medium_square: RabbitMQ `Connector`
* :white_medium_square: Redis `Cache Manager`

@@ -57,0 +59,0 @@ * :white_medium_square: Memcached `Cache Manager`

import { CacheConfig } from './cache-manager';
import { Context, Environment } from '../environment';
process.env.SECRETS = '{}';
test('should be able to create a valid key', async () => {

@@ -127,3 +129,3 @@ const env = new Environment({}, [], {

test('should be able to bust partition', async () => {
test('should be able to flush partition', async () => {
const env = new Environment({}, [], {

@@ -156,7 +158,7 @@ metadata: {

expect(cacheManager.CACHE).toHaveProperty(config.partition);
await cacheManager.bust(config.partition);
await cacheManager.flush(config.partition);
expect(cacheManager.CACHE).not.toHaveProperty(config.partition);
});
test('should do nothing when busting a non-existent partition', async () => {
test('should do nothing when flushing a non-existent partition', async () => {
const env = new Environment({}, [], {

@@ -189,3 +191,3 @@ metadata: {

expect(cacheManager.CACHE).toHaveProperty(config.partition);
await cacheManager.bust(config.partition + '-nah');
await cacheManager.flush(config.partition + '-nah');
expect(cacheManager.CACHE).toHaveProperty(config.partition);

@@ -192,0 +194,0 @@ });

@@ -7,3 +7,3 @@ import { createHash } from 'crypto';

export class CacheManager extends Module {
export class CacheManager<C, S> extends Module<C, S> {
private _CACHE: MemoryCache = {};

@@ -68,3 +68,3 @@ get CACHE(): MemoryCache {

async bust(partition: string): Promise<void> {
async flush(partition: string): Promise<void> {
if (this.CACHE.hasOwnProperty(partition)) {

@@ -76,2 +76,3 @@ delete this.CACHE[partition];

//TODO: Perhaps move all but `cacheManager` into a `config` property
export interface CacheConfig {

@@ -78,0 +79,0 @@ cacheManager: string;

import { TaskConfig, Environment } from '../environment';
import { BoundaryContext } from '../boundaries/boundary';
import { ConnectorContext } from '../connectors/connector';
import { CacheConfig } from '../cache-managers/cache-manager';
process.env.SECRETS = '{}';
test('should be able to execute doer and have input echoed', async () => {

@@ -24,5 +26,5 @@ const env = new Environment({}, [], {

const context: BoundaryContext = {
const context: ConnectorContext<any> = {
env: env,
boundary: { config: {}, input: {} },
connector: { config: {}, input: {} },
data: {},

@@ -65,5 +67,5 @@ errors: {}

const context: BoundaryContext = {
const context: ConnectorContext<any> = {
env: env,
boundary: { config: {}, input: {} },
connector: { config: {}, input: {} },
data: {},

@@ -70,0 +72,0 @@ errors: {}

import { Module } from '../module';
import { TaskConfig } from '../environment';
import { BoundaryContext } from '../boundaries/boundary';
import { ConnectorContext } from '../connectors/connector';
import { ObjectCompiler } from '../object-compiler';
import { CacheManager, CacheConfig, CacheKey } from '../cache-managers/cache-manager';
export class Doer extends Module {
async execute(context: BoundaryContext, task: TaskConfig): Promise<void> {
export class Doer<C, S> extends Module<C, S> {
async execute(context: ConnectorContext<any>, task: TaskConfig): Promise<void> {
try {
let cacheManager: CacheManager | undefined;
const env = context.env;
env.info(context, this.moduleType, `Executing task ${task.name}`);
let cacheManager: CacheManager<any, any> | undefined;
let cacheKey: CacheKey | undefined;
if (task.cacheConfig) {
env.info(context, this.moduleType, `Loading cache manager '${task.cacheConfig.cacheManager}`);
cacheManager = this.env.getCacheManager(task.cacheConfig.cacheManager);
cacheKey = await cacheManager.makeKey(task.cacheConfig, context);
const cachedItem = await cacheManager.getItem(cacheKey);
if (cachedItem) {
env.info(context, 'Found cached item');
env.debug(context, 'Found cached item', cachedItem);
context.data[task.name] = cachedItem;

@@ -32,8 +40,12 @@ return;

context.errors[task.name] = err;
if (task.throwError) {
throw err;
}
}
}
async main(context: BoundaryContext, taskConfig: TaskConfig, coreConfig: any): Promise<any> {
async main(context: ConnectorContext<any>, taskConfig: TaskConfig, coreConfig: any): Promise<any> {
this.env.debug(context, this.moduleType, 'Executing main(), returning', coreConfig);
return coreConfig
}
}
import { TaskConfig, Environment } from '../environment';
import { BoundaryContext } from '../boundaries/boundary';
import { ConnectorContext } from '../connectors/connector';
import { LogLevel } from '../loggers/logger';
process.env.SECRETS = '{}';
function taskFactory(name?: string, doer?: string): TaskConfig {

@@ -38,5 +41,5 @@ return {

const context: BoundaryContext = {
const context: ConnectorContext<any> = {
env: env,
boundary: { config: {}, input: {} },
connector: { config: {}, input: {} },
data: {},

@@ -82,5 +85,5 @@ errors: {}

const context: BoundaryContext = {
const context: ConnectorContext<any> = {
env: env,
boundary: { config: {}, input: {} },
connector: { config: {}, input: {} },
data: {},

@@ -127,5 +130,5 @@ errors: {}

const context: BoundaryContext = {
const context: ConnectorContext<any> = {
env: env,
boundary: { config: {}, input: {} },
connector: { config: {}, input: {} },
data: {},

@@ -151,3 +154,3 @@ errors: {}

haltAfterExecution: false,
schmtaskName: 'no-such-task'
taskName: 'no-such-task'
}

@@ -170,5 +173,6 @@ }

const context: BoundaryContext = {
const context: ConnectorContext<any> = {
env: env,
boundary: { config: {}, input: {} },
logLevel: LogLevel.DEBUG,
connector: { config: {}, input: {} },
data: {},

@@ -179,3 +183,3 @@ errors: {}

await doer.execute(context, multiTask);
expect(context.errors['test-multi-doer'].message).toMatch(/Invalid BranchConfig/);
expect(context.errors['test-multi-doer'].message).toMatch(/No Task called/);
});

@@ -210,5 +214,5 @@

const context: BoundaryContext = {
const context: ConnectorContext<any> = {
env: env,
boundary: { config: {}, input: {} },
connector: { config: {}, input: {} },
data: {},

@@ -215,0 +219,0 @@ errors: {}

import { Doer } from './doer';
import { BoundaryContext } from '../boundaries/boundary';
import { ConnectorContext } from '../connectors/connector';
import { TaskConfig } from '../environment';
import { ObjectCompiler } from '../object-compiler';
export class MultiDoer extends Doer {
async main(context: BoundaryContext, taskConfig: TaskConfig, multiDoerTasks: MultiDoerTask[]): Promise<any> {
export class MultiDoer<C, S> extends Doer<C, S> {
async main(context: ConnectorContext<any>, taskConfig: TaskConfig, multiDoerTasks: MultiDoerTask[]): Promise<any> {
this.env.debug(context, this.moduleType, 'Executing main(), returning');
for (const multiDoerTask of multiDoerTasks) {
const doer = this.env.getDoer(multiDoerTask.task.doer);
await doer.execute(context, multiDoerTask.task);
let task: TaskConfig | undefined;
if (typeof multiDoerTask.task === 'string') {
this.env.debug(context, this.moduleType, `Finding task '${multiDoerTask.task}'`);
task = this.env.getTask(multiDoerTask.task);
} else {
task = multiDoerTask.task;
}
this.env.debug(context, this.moduleType, `Finding doer '${task.doer}'`);
const doer = this.env.getDoer(task.doer);
await doer.execute(context, task);
if (multiDoerTask.branch) {
this.env.debug(context, this.moduleType, 'Task executed with BranchConfig, compiling it');
const branchConfig = await ObjectCompiler.compile(multiDoerTask.branch, context) as BranchConfig;
if (!branchConfig.taskName) {
throw new Error(`Invalid BranchConfig for task '${multiDoerTask.task.name}'`);
this.env.debug(context, this.moduleType, 'No branch task given so doing nothing');
} else {
this.env.debug(context, this.moduleType, `Branching to task '${branchConfig.taskName}'`);
const branchTask = this.env.getTask(branchConfig.taskName);
this.env.debug(context, this.moduleType, `Loading branch Doer '${branchTask.doer}'`);
const branchDoer = this.env.getDoer(branchTask.doer);
await branchDoer.execute(context, branchTask);
}
const branchTask = this.env.getTask(branchConfig.taskName);
const branchDoer = this.env.getDoer(branchTask.doer);
await branchDoer.execute(context, branchTask);
if (branchConfig.haltAfterExecution) {
this.env.debug(context, this.moduleType, 'Halting after execution of Branch task');
break;

@@ -30,6 +49,3 @@ }

export interface MultiDoerTask {
task: TaskConfig;
//TODO: Might this get a bit repetative? I know a `Pointer` can go here but
//should I look at a set of overridable "All Task" rules for all tasks
//run by a MultiDoer?
task: TaskConfig | string;
branch?: any;

@@ -39,4 +55,4 @@ }

export interface BranchConfig {
taskName: string;
haltAfterExecution: boolean;
taskName?: string;
haltAfterExecution?: boolean;
}
import { Environment, TaskConfig, Modules } from './environment';
import { Boundary } from './boundaries/boundary';
import { Connector } from './connectors/connector';
import { CacheManager } from './cache-managers/cache-manager';

@@ -8,2 +8,10 @@ import { Doer } from './doers/doer';

process.env.SECRETS = '{}';
beforeAll(() => {
process.env = Object.assign(process.env, {
SECRETS_ALT: '{ "modules": { "Module": { "test": "It worked" } } }'
});
});
test('should create new basic instance of a low environment', () => {

@@ -20,3 +28,3 @@ const env = new Environment({}, [], {});

//Expect all default built in modules to be registered but not ready
expect(() => { env.getBoundary('Boundary').isReady }).toThrow(`The Boundary called 'Boundary' is loaded but not ready. Has the environment been initialised?`);
expect(() => { env.getConnector('Connector').isReady }).toThrow(`The Connector called 'Connector' is loaded but not ready. Has the environment been initialised?`);
expect(() => { env.getCacheManager('CacheManager').isReady }).toThrow(`The Cache Manager called 'CacheManager' is loaded but not ready. Has the environment been initialised?`);

@@ -38,3 +46,3 @@ expect(() => { env.getDoer('Doer').isReady }).toThrow(`The Doer called 'Doer' is loaded but not ready. Has the environment been initialised?`);

//Check all built in modules are now ready
expect(env.getBoundary('Boundary').isReady).toBe(true);
expect(env.getConnector('Connector').isReady).toBe(true);
expect(env.getCacheManager('CacheManager').isReady).toBe(true);

@@ -52,5 +60,5 @@ expect(env.getDoer('Doer').isReady).toBe(true);

test('should not be able to get a none existent Boundary', () => {
test('should not be able to get a none existent Connector', () => {
const env = new Environment({}, [], {});
expect(() => { return env.getBoundary('xyz'); }).toThrow(`No Boundary called 'xyz' loaded`);
expect(() => { return env.getConnector('xyz'); }).toThrow(`No Connector called 'xyz' loaded`);
});

@@ -80,3 +88,3 @@

name: 'test-task',
boundaryConfigs: {},
connectorConfigs: {},
cacheConfig: {

@@ -134,9 +142,9 @@ cacheManager: 'CacheManager',

test('should be able to pass in external Modules when creating an Environment', async () => {
class ExternalBoundary extends Boundary {}
class ExternalCacheManager extends CacheManager {}
class ExternalDoer extends Doer {}
class ExternalConnector extends Connector<any, any, any> {}
class ExternalCacheManager extends CacheManager<any, any> {}
class ExternalDoer extends Doer<any, any> {}
class ExternalParser extends Parser<any> {}
class ExternalRenderer extends Renderer {}
class ExternalRenderer extends Renderer<any, any, any> {}
const externalBoundary = new ExternalBoundary();
const externalConnector = new ExternalConnector();
const externalCacheManager = new ExternalCacheManager();

@@ -148,3 +156,3 @@ const externalDoer = new ExternalDoer();

const modules: Modules = {
boundaries: [ externalBoundary ],
connectors: [ externalConnector ],
cacheManagers: [ externalCacheManager ],

@@ -159,3 +167,3 @@ doers: [ externalDoer ],

expect(env.getBoundary('ExternalBoundary')).toStrictEqual(externalBoundary);
expect(env.getConnector('ExternalConnector')).toStrictEqual(externalConnector);
expect(env.getCacheManager('ExternalCacheManager')).toStrictEqual(externalCacheManager);

@@ -162,0 +170,0 @@ expect(env.getDoer('ExternalDoer')).toStrictEqual(externalDoer);

@@ -1,4 +0,7 @@

import { Boundary } from './boundaries/boundary';
import * as Crypto from 'crypto';
import { Connector } from './connectors/connector';
import { CacheManager, CacheConfig } from './cache-managers/cache-manager';
import { Doer } from './doers/doer';
import { Logger, LogLevel } from './loggers/logger';
import { Parser } from './parsers/parser';

@@ -11,2 +14,3 @@ import { BooleanParser } from './parsers/boolean-parser';

import { UrlParser } from './parsers/url-parser';
import { QuerystringParser } from './parsers/querystring-parser';
import { Renderer } from './renderers/renderer';

@@ -43,8 +47,10 @@ import { MultiDoer } from './doers/multi-doer';

logLevel: LogLevel = LogLevel.ERROR;
/**
* A collection of [[Boundary]] modules. Boundaries are gateways from
* A collection of [[Connector]] modules. Connectors are gateways from
* your application or external sources to run tasks in the `low` Environment
*/
private boundaries: { [boundaryName: string]: Boundary } = {
Boundary: new Boundary()
private connectors: { [connectorName: string]: Connector<any, any, any> } = {
Connector: new Connector()
};

@@ -56,3 +62,3 @@

*/
private cacheManagers: { [cacheManagerName: string]: CacheManager } = {
private cacheManagers: { [cacheManagerName: string]: CacheManager<any, any> } = {
CacheManager: new CacheManager()

@@ -64,3 +70,3 @@ };

*/
private doers: { [doerName: string]: Doer } = {
private doers: { [doerName: string]: Doer<any, any> } = {
Doer: new Doer(),

@@ -70,2 +76,6 @@ MultiDoer: new MultiDoer()

private loggers: { [loggerName: string]: Logger<any, any> } = {
Logger: new Logger()
};
/**

@@ -81,3 +91,4 @@ * A collection of [[Parser]] modules. Parsers ensure that any compiled

StringParser: new StringParser(),
UrlParser: new UrlParser()
UrlParser: new UrlParser(),
QuerystringParser: new QuerystringParser(),
};

@@ -90,3 +101,3 @@

*/
private renderers: { [rendererName: string]: Renderer } = {
private renderers: { [rendererName: string]: Renderer<any, any, any> } = {
Renderer: new Renderer()

@@ -103,5 +114,5 @@ };

constructor(modules: Modules, tasks: TaskConfig[], public config: EnvironmentConfig, secretsName: string = 'SECRETS') {
if (modules.boundaries) {
for (const mod of modules.boundaries) {
this.boundaries[mod.moduleType] = mod;
if (modules.connectors) {
for (const mod of modules.connectors) {
this.connectors[mod.moduleType] = mod;
}

@@ -122,2 +133,8 @@ }

if (modules.loggers) {
for (const mod of modules.loggers) {
this.loggers[mod.moduleType] = mod;
}
}
if (modules.parsers) {

@@ -143,21 +160,19 @@ for (const mod of modules.parsers) {

loadSecrets(secretsName: string) {
//TODO: What the heck actually happens when you try to access `process`
// in a browser. Need more checks around this
const secretsVar = process.env[secretsName];
if (!secretsVar) return;
if (!process) {
console.warn('No `process` object for environment variables. Probably in a browser');
return;
}
if (secretsVar.indexOf('{') > -1) {
this.secrets = JSON.parse(secretsVar);
} else {
//This will obviously not work in the browser so be sure to set
//your secretsName variable properly. Don't like doing `require`
//but not sure how else to make `fs` conditional. Moar research!
const fs = require('fs');
const secretsJson = fs.readFileSync(secretsVar).toString();
this.secrets = JSON.parse(secretsJson);
if (!process.env.hasOwnProperty(secretsName)) {
console.warn(`No environment variable named '${secretsName}'.`);
return;
}
const secretsVar = process.env[secretsName] || '{}';
this.secrets = JSON.parse(secretsVar);
}
async init(): Promise<void> {
for (const mod of Object.values(this.boundaries)) {
for (const mod of Object.values(this.connectors)) {
await mod.init(this);

@@ -174,2 +189,6 @@ }

for (const mod of Object.values(this.loggers)) {
await mod.init(this);
}
for (const mod of Object.values(this.parsers)) {

@@ -189,2 +208,8 @@ await mod.init(this);

this.ready = true;
if (this.config.startupTask) {
const task = this.getTask(this.config.startupTask);
const connector = this.getConnector('Connector');
await connector.runTask(task, {}, {});
}
}

@@ -225,14 +250,14 @@

getBoundary(name: string): Boundary {
if (!this.boundaries.hasOwnProperty(name)) {
throw new Error(`No Boundary called '${name}' loaded`);
getConnector(name: string): Connector<any, any, any> {
if (!this.connectors.hasOwnProperty(name)) {
throw new Error(`No Connector called '${name}' loaded`);
}
const boundary = this.boundaries[name];
if (!boundary.isReady) {
throw new Error(`The Boundary called '${name}' is loaded but not ready. Has the environment been initialised?`);
const connector = this.connectors[name];
if (!connector.isReady) {
throw new Error(`The Connector called '${name}' is loaded but not ready. Has the environment been initialised?`);
}
return boundary;
return connector;
}
getCacheManager(name: string): CacheManager {
getCacheManager(name: string): CacheManager<any, any> {
if (!this.cacheManagers.hasOwnProperty(name)) {

@@ -248,3 +273,3 @@ throw new Error(`No Cache Manager called '${name}' loaded`);

getDoer(name: string): Doer {
getDoer(name: string): Doer<any, any> {
if (!this.doers.hasOwnProperty(name)) {

@@ -271,3 +296,3 @@ throw new Error(`No Doer called '${name}' loaded`);

getRenderer(name: string): Renderer {
getRenderer(name: string): Renderer<any, any, any> {
if (!this.renderers.hasOwnProperty(name)) {

@@ -292,2 +317,98 @@ throw new Error(`No Renderer called '${name}' loaded`);

}
log(context: Context | null, level: LogLevel, ...args: any[]) {
try {
let contextLogLevel = this.logLevel;
if (typeof context === 'object' && context !== null && typeof context.logLevel === 'number') {
contextLogLevel = context.logLevel;
}
if (level < contextLogLevel) {
return false;
}
let label = 'ENVIRONMENT';
if (typeof context === 'object' && context !== null) {
if (typeof context.uid !== 'string') {
context.uid = Crypto.randomBytes(4).toString('hex');
}
label = context.uid;
}
for (const logger of Object.values(this.loggers)) {
switch (level) {
case (LogLevel.DEBUG):
logger.debug(label, ...args).then().catch(err => {
console.error(`Logger Error: '${logger.moduleType}.debug()`, err);
});
break;
case (LogLevel.INFO):
logger.info(label, ...args).then().catch(err => {
console.error(`Logger Error: '${logger.moduleType}.info()`, err);
});
break;
case (LogLevel.WARN):
logger.warn(label, ...args).then().catch(err => {
console.error(`Logger Error: '${logger.moduleType}.warn()`, err);
});
break;
default:
logger.error(label, ...args).then().catch(err => {
console.error(`Logger Error: '${logger.moduleType}.error()`, err);
});
}
}
return true;
} catch (err) {
console.error('Logger Error: Failed to initialise log', context, level, ...args);
return false;
}
}
debug(context: Context | null, ...args: any[]) {
this.log(context, LogLevel.DEBUG, ...args);
}
info(context: Context | null, ...args: any[]) {
this.log(context, LogLevel.INFO, ...args);
}
warn(context: Context | null, ...args: any[]) {
this.log(context, LogLevel.WARN, ...args);
}
error(context: Context | null, ...args: any[]) {
this.log(context, LogLevel.ERROR, ...args);
}
async destroy() {
if (!this.ready) {
return;
}
for (const mod of Object.values(this.connectors)) {
await mod.destroy();
}
for (const mod of Object.values(this.cacheManagers)) {
await mod.destroy();
}
for (const mod of Object.values(this.doers)) {
await mod.destroy();
}
for (const mod of Object.values(this.loggers)) {
await mod.destroy();
}
for (const mod of Object.values(this.parsers)) {
await mod.destroy();
}
for (const mod of Object.values(this.renderers)) {
await mod.destroy();
}
}
}

@@ -298,2 +419,3 @@

modules?: any;
startupTask?: string;
[key: string]: any;

@@ -303,7 +425,8 @@ }

export interface Modules {
boundaries?: Boundary[];
cacheManagers?: CacheManager[];
doers?: Doer[];
connectors?: Connector<any, any, any>[];
cacheManagers?: CacheManager<any, any>[];
doers?: Doer<any, any>[];
loggers?: Logger<any, any>[];
parsers?: Parser<any>[];
renderers?: Renderer[];
renderers?: Renderer<any, any, any>[];
}

@@ -313,3 +436,5 @@

env: Environment;
debug?: boolean;
logLevel?: LogLevel;
uid?: string;
[key: string]: any;
}

@@ -323,4 +448,5 @@

cacheConfig?: CacheConfig;
boundaryConfigs?: { [boundaryName: string]: any };
connectorConfigs?: { [connectorName: string]: any };
specialProperties?: string[];
throwError?: boolean;
}
import { Module } from './module';
import { Environment } from './environment';
beforeAll(() => {
process.env = Object.assign(process.env, {
SECRETS_ALT: '{ "modules": { "Module": { "test": "It worked" } } }'
});
});
test('should be able to construct and initialise a basic Module', async () => {
const mod = new Module();
const env = new Environment({}, [], {});
const env = new Environment({}, [], {}, 'SECRETS_ALT');
expect(mod.moduleType).toBe('Module');

@@ -15,3 +21,3 @@ expect(mod.isReady).toBe(false);

const mod = new Module();
const env = new Environment({}, [], {
const modulesConfig = {
modules: {

@@ -22,6 +28,7 @@ Module: {

}
});
};
const env = new Environment({}, [], modulesConfig, 'SECRETS_ALT');
await mod.init(env);
expect(mod.config.test).toBe('It worked');
expect(mod.secrets.test).toBe('It worked');
expect((mod.config as any).test).toBe('It worked');
expect((mod.secrets as any).test).toBe('It worked');
});

@@ -28,0 +35,0 @@

import { Environment } from './environment';
export class Module {
export class Module<C, S> {
private _env: Environment | undefined;
public get env(): Environment {
get env(): Environment {
if (!this._env) {

@@ -12,5 +12,18 @@ throw new Error('No Environment has been set. Has this Module been setup correctly?');

secrets: any = {};
config: any = {};
private _config: C | undefined;
get config(): C {
if (!this._config) {
throw new Error('No Config have been set. Has this Module been setup correctly?');
}
return this._config;
}
private _secrets: S | undefined;
get secrets(): S {
if (!this._secrets) {
throw new Error('No Secrets have been set. Has this Module been setup correctly?');
}
return this._secrets;
}
get moduleType(): string {

@@ -20,17 +33,28 @@ return this.constructor.name;

protected ready: boolean = false;
private _ready: boolean = false;
get isReady(): boolean {
return this.ready;
return this._ready;
}
async init(env: Environment): Promise<void> {
if (this.ready) {
env.debug(null, this.moduleType, `Initialising`);
if (this._ready) {
env.warn(null, this.moduleType, 'Module already initialised. Destroying and re-initialising');
await this.destroy();
this.ready = false;
this._ready = false;
}
this._env = env;
this.config = env.config.modules && env.config.modules[this.moduleType] || {};
this.secrets = env.secrets.modules && env.secrets.modules[this.moduleType] || {};
this._config = env.config.modules && env.config.modules[this.moduleType] || {};
env.debug(null, this.moduleType, `Set config:`, this.config);
this._secrets = env.secrets.modules && env.secrets.modules[this.moduleType] || {};
env.debug(null, this.moduleType, `Set secrets:`, this.secrets);
await this.setup();
this.ready = true;
this._ready = true;
env.debug(null, this.moduleType, `Module ready`);
}

@@ -37,0 +61,0 @@

import { ObjectCompiler } from './object-compiler';
import { Environment } from './environment';
process.env.SECRETS = '{}';
const env = new Environment({}, [], {

@@ -136,3 +138,3 @@ metadata: {

test('should echo a non-object property when attempting to compile it', async() => {
test('should echo a non-object property when attempting to compile it', async () => {
const input = 'test';

@@ -143,3 +145,3 @@ const output = await ObjectCompiler.compile(input, { env: env });

test('should throw exception when passed a bad pointer', async() => {
test('should throw exception when passed a bad pointer', async () => {
const input = {

@@ -149,2 +151,89 @@ __pointer: 'env.config.metadata.noSuchProperty'

expect(() => { ObjectCompiler.resolvePointer(input, { env: env }); }).toThrow(/Could not resolve pointer/);
});
test('should be able to spread rendered arrays into containing array', async () => {
await env.init();
const input = {
testArray: [
'Item 1',
{
__renderer: 'Renderer',
__template: [
'Rendered Item 1',
'Rendered Item 2'
],
__spread: true
},
'Item 2'
]
};
const expected = {
testArray: [
'Item 1',
'Rendered Item 1',
'Rendered Item 2',
'Item 2'
]
};
const output = await ObjectCompiler.compile(input, { env: env });
expect(output).toEqual(expected);
});
test('should be able to spread rendered objects into containing object', async () => {
await env.init();
const input = {
testObject: {
key1: 'Value 1',
keySpread1: {
__renderer: 'Renderer',
__template: {
renderedKey1: 'Value 1',
renderedKey2: 'Value 2',
},
__spread: true
},
key2: 'Value 2'
}
};
const expected = {
testObject: {
key1: 'Value 1',
renderedKey1: 'Value 1',
renderedKey2: 'Value 2',
key2: 'Value 2'
}
};
const output = await ObjectCompiler.compile(input, { env: env });
expect(output).toEqual(expected);
});
test('should be able to template keys', async () => {
await env.init();
const input = {
testObject: {
key1: 'Value 1',
templatedKey: {
__renderer: 'Renderer',
__template: 'Value 2',
__key: {
__renderer: 'Renderer',
__template: 'key2'
}
}
}
};
const expected = {
testObject: {
key1: 'Value 1',
key2: 'Value 2'
}
};
const output = await ObjectCompiler.compile(input, { env: env });
expect(output).toEqual(expected);
});
import { Context } from './environment';
import { RenderConfig } from './renderers/renderer';
//TODO: Should this be a Module or is that going to far?
//I'm leaning on No because this is a bit fundamental and secret-sauce
export class ObjectCompiler {
static isTemplate(property: any): boolean {
return property && (property.hasOwnProperty('__template') || property.hasOwnProperty('__templatePath'));
return typeof property === 'object' && property !== null && property.hasOwnProperty('__template');
}
static async compile(config: any, context: Context, specialProperties?: string[]): Promise<any> {
if (typeof config !== 'object') {
if (typeof config !== 'object' || config === null) {
return config;

@@ -35,3 +34,3 @@ }

if (ObjectCompiler.isTemplate(resolvedProperty)) {
const renderer = context.env.getRenderer(resolvedProperty.__renderer);
const renderer = context.env.getRenderer(resolvedProperty.__renderer || 'Renderer');
return await renderer.render(resolvedProperty, context);

@@ -43,4 +42,10 @@ }

for (const item of resolvedProperty) {
const spread = typeof item === 'object' && item !== null && item.hasOwnProperty('__spread');
const resolved = await ObjectCompiler.compileProperty(item, context);
compiled.push(resolved);
if (spread && Array.isArray(resolved)) {
compiled.push(...resolved);
} else {
compiled.push(resolved);
}
}

@@ -50,6 +55,25 @@ return compiled;

if (typeof resolvedProperty === 'object') {
if (typeof resolvedProperty === 'object' && resolvedProperty !== null && !resolvedProperty.hasOwnProperty('__doNotCompile')) {
const output: any = {};
for (const [key, value] of Object.entries(resolvedProperty)) {
output[key] = await ObjectCompiler.compileProperty(value, context);
const spread = typeof value === 'object' && value !== null && value.hasOwnProperty('__spread');
const resolved = await ObjectCompiler.compileProperty(value, context);
if (spread && typeof resolved === 'object' && resolved !== null) {
for (const [resolvedKey, resolvedValue] of Object.entries(resolved)) {
output[resolvedKey] = resolvedValue;
}
} else {
//Not sure why I need to cast value to any here. I'm already checking above that the key "__key" exists on it
const keyConfig = typeof value === 'object' && value !== null && value.hasOwnProperty('__key') && (value as any).__key as RenderConfig<any> || null;
if (keyConfig) {
keyConfig.__parser = 'StringParser';
const renderer = context.env.getRenderer(keyConfig.__renderer || 'Renderer');
const renderedKey = await renderer.render((value as any).__key, { ...context, resolvedValue: value });
output[renderedKey] = resolved;
} else {
output[key] = resolved;
}
}
}

@@ -56,0 +80,0 @@ return output;

@@ -8,3 +8,3 @@ import { Module } from '../module';

*/
export class Parser<T> extends Module {
export class Parser<T> extends Module<any, any> {
async parse(input: any, config: ParserConfig<T>): Promise<T|null> {

@@ -11,0 +11,0 @@ if (typeof input === 'undefined' || input === null) {

@@ -98,5 +98,8 @@ import { StringParser } from './string-parser';

//Using `testVal` over `£ 123,456.79` is a hack but Jest keeps telling me that `£ 123,456.79` does not equal `£ 123,456.79`
const testVal = await parser.parse(123456.789, { numberFunction: 'toLocaleString', localeOptions: { style: 'currency', currency: 'GBP' } });
expect(await parser.parse(123456789, { numberFunction: 'toLocaleString', locales: 'en-GB' })).toBe('123,456,789');
expect(await parser.parse(123456.654321, { numberFunction: 'toLocaleString', locales: 'en-GB' })).toBe('123,456.654');
expect(await parser.parse(123456.789, { numberFunction: 'toLocaleString', localeOptions: { style: 'currency', currency: 'GBP' }})).toBe('£ 123,456.79');
expect(await parser.parse(123456.789, { numberFunction: 'toLocaleString', localeOptions: { style: 'currency', currency: 'GBP' }})).toBe(testVal);
expect(await parser.parse(123456.789, { numberFunction: 'toLocaleString', localeOptions: { maximumSignificantDigits: 3 }})).toBe('123,000');

@@ -103,0 +106,0 @@

@@ -0,1 +1,3 @@

import { URL } from 'url';
import { UrlParser } from './url-parser';

@@ -2,0 +4,0 @@

import { Environment, Context } from '../environment';
import { RenderConfig } from './renderer';
process.env.SECRETS = '{}';
test('should echo input with no parser', async () => {

@@ -8,3 +10,3 @@ const env = new Environment({}, [], {});

const renderer = env.getRenderer('Renderer');
const config: RenderConfig = {
const config: RenderConfig<any> = {
__renderer: 'Renderer',

@@ -28,3 +30,3 @@ __template: {

const renderer = env.getRenderer('Renderer');
const config: RenderConfig = {
const config: RenderConfig<any> = {
__renderer: 'Renderer',

@@ -31,0 +33,0 @@ __template: 42,

import { Module } from '../module';
import { ParserConfig } from '../parsers/parser';
import { Context } from '../environment';
import { CacheConfig, CacheManager, CacheKey } from '../cache-managers/cache-manager';
export class Renderer extends Module {
async render(config: RenderConfig, context: Context): Promise<any> {
export class Renderer<C, S, T> extends Module<C, S> {
async render(config: RenderConfig<T>, context: Context): Promise<any> {
let cacheManager: CacheManager<any, any> | undefined;
let cacheKey: CacheKey | undefined;
if (config.__cacheConfig) {
cacheManager = this.env.getCacheManager(config.__cacheConfig.cacheManager);
cacheKey = await cacheManager.makeKey(config.__cacheConfig, context);
const cachedItem = await cacheManager.getItem(cacheKey);
if (cachedItem !== null) {
return cachedItem;
}
}
const template = await this.getTemplate(config, context);

@@ -11,10 +24,14 @@ const rendered = await this.core(template, context);

if (cacheManager && cacheKey) {
await cacheManager.setItem(cacheKey, parsed, (config.__cacheConfig as CacheConfig).ttl);
}
return parsed;
}
async getTemplate(config: RenderConfig, context: Context): Promise<any> {
async getTemplate(config: RenderConfig<T>, context: Context): Promise<any> {
return config.__template;
}
async parseRendered(rendered: any, config: RenderConfig): Promise<any> {
async parseRendered(rendered: any, config: RenderConfig<T>): Promise<any> {
if (config.__parser) {

@@ -34,8 +51,11 @@ const parser = this.env.getParser(config.__parser);

export interface RenderConfig {
__renderer: string;
__template: any;
export interface RenderConfig<T> {
__renderer?: string;
__template: T;
__parser?: string;
__parserConfig?: ParserConfig<any>;
__metaData?: any;
__cacheConfig?: CacheConfig;
__spread?: true;
__key?: RenderConfig<any>
}

@@ -6,7 +6,9 @@ {

"noUnusedLocals": true,
"declaration": true,
"outDir": "lib",
"sourceMap": true,
"strict": true,
"target": "es2017",
"resolveJsonModule": true
"target": "es6",
"resolveJsonModule": true,
"skipLibCheck": true
},

@@ -13,0 +15,0 @@ "compileOnSave": true,

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc