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

@gasket/core

Package Overview
Dependencies
Maintainers
0
Versions
95
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@gasket/core - npm Package Compare versions

Comparing version 7.0.1-canary.12 to 7.0.1

cjs/gasket.js

229

cjs/engine.js

@@ -5,9 +5,16 @@ "use strict";

});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
GasketEngine: function() {
return GasketEngine;
},
lifecycleMethods: function() {
return lifecycleMethods;
}
});
const _debug = /*#__PURE__*/ _interop_require_default(require("debug"));
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {

@@ -42,18 +49,20 @@ try {

}
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
const debug = (0, _debug.default)('gasket:engine');
let dynamicNamingId = 0;
const lifecycleMethods = [
'exec',
'execSync',
'execWaterfall',
'execWaterfallSync',
'execMap',
'execMapSync',
'execApply',
'execApplySync'
];
class GasketEngine {
/**
* Resolves plugins
* @param plugins
* @private
*/ _registerPlugins(plugins) {
_registerPlugins(plugins) {
// map the plugin name to module contents for easy lookup
this._pluginMap = plugins.reduce((acc, plugin)=>{
// TODO: throw if plugin is not an object
if (typeof plugin !== 'object' || Array.isArray(plugin)) {
throw new Error(`Plugin ${plugin.name} must be an object`);
}
const { name, hooks } = plugin;

@@ -66,2 +75,13 @@ if (!name) {

}
// Add base metadata hook if not present
if (!plugin.hooks.metadata) {
plugin.hooks.metadata = /*#__PURE__*/ function() {
var _ref = _async_to_generator(function*(_, metadata) {
return metadata;
});
return function(_, metadata) {
return _ref.apply(this, arguments);
};
}();
}
acc[name] = plugin;

@@ -98,2 +118,20 @@ return acc;

}
_registerActions() {
this.actions = {};
const actionPluginMap = {};
Object.entries(this._pluginMap).forEach(([pluginName, plugin])=>{
const { actions } = plugin;
if (actions) {
Object.keys(actions).forEach((actionName)=>{
if (actionPluginMap[actionName]) {
// eslint-disable-next-line no-console
console.error(`Action '${actionName}' from '${pluginName}' was registered by '${actionPluginMap[actionName]}'`);
return;
}
actionPluginMap[actionName] = plugin.name;
this.actions[actionName] = actions[actionName];
});
}
});
}
/**

@@ -125,3 +163,5 @@ * Injects additional lifecycle hooks at runtime.

},
callback: handler.bind(null, this)
invoke: (gasket, ...args)=>{
return handler(gasket, ...args);
}
};

@@ -134,2 +174,3 @@ delete this._plans[event];

* plugins to finish.
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -139,7 +180,7 @@ * @param {...*} args Args for hooks

* the order executed
*/ exec(event, ...args) {
*/ exec(gasket, event, ...args) {
return this._execWithCachedPlan({
event,
type: 'exec',
prepare: (hookConfig, trace)=>{
prepare: (hookConfig)=>{
const subscribers = hookConfig.subscribers;

@@ -149,6 +190,7 @@ const executionPlan = [];

this._executeInOrder(hookConfig, (plugin)=>{
pluginThunks[plugin] = (pluginTasks, ...passedArgs)=>{
pluginThunks[plugin] = (passedGasket, pluginTasks, ...passedArgs)=>{
pluginTasks[plugin] = Promise.all(subscribers[plugin].ordering.after.map((dep)=>pluginTasks[dep])).then(()=>{
trace(plugin);
return subscribers[plugin].callback(...passedArgs);
var _passedGasket_traceHookStart;
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event);
return subscribers[plugin].invoke(passedGasket, ...passedArgs);
});

@@ -163,3 +205,3 @@ return pluginTasks[plugin];

const pluginTasks = {};
return Promise.all(executionPlan.map((fn)=>fn(pluginTasks, ...args)));
return Promise.all(executionPlan.map((fn)=>fn(gasket, pluginTasks, ...args)));
}

@@ -173,2 +215,3 @@ });

* possible.
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -178,13 +221,14 @@ * @param {...*} args Args for hooks

* the order executed
*/ execSync(event, ...args) {
*/ execSync(gasket, event, ...args) {
return this._execWithCachedPlan({
event,
type: 'execSync',
prepare: (hookConfig, trace)=>{
prepare: (hookConfig)=>{
const subscribers = hookConfig.subscribers;
const executionPlan = [];
this._executeInOrder(hookConfig, (plugin)=>{
executionPlan.push((...execArgs)=>{
trace(plugin);
return subscribers[plugin].callback(...execArgs);
executionPlan.push((passedGasket, ...execArgs)=>{
var _passedGasket_traceHookStart;
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event);
return subscribers[plugin].invoke(passedGasket, ...execArgs);
});

@@ -195,3 +239,3 @@ });

exec: (executionPlan)=>{
return executionPlan.map((fn)=>fn(...args));
return executionPlan.map((fn)=>fn(gasket, ...args));
}

@@ -205,2 +249,3 @@ });

* present in the map.
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -210,14 +255,15 @@ * @param {...*} args Args for hooks

* the plugin and each value the result from the hook
*/ execMap(event, ...args) {
*/ execMap(gasket, event, ...args) {
return this._execWithCachedPlan({
event,
type: 'execMap',
prepare: (hookConfig, trace)=>{
prepare: (hookConfig)=>{
const subscribers = hookConfig.subscribers;
const executionPlan = {};
this._executeInOrder(hookConfig, (plugin)=>{
executionPlan[plugin] = (pluginTasks, ...passedArgs)=>{
executionPlan[plugin] = (passedGasket, pluginTasks, ...passedArgs)=>{
pluginTasks[plugin] = Promise.all(subscribers[plugin].ordering.after.map((dep)=>pluginTasks[dep])).then(()=>{
trace(plugin);
return subscribers[plugin].callback(...passedArgs);
var _passedGasket_traceHookStart;
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event);
return subscribers[plugin].invoke(passedGasket, ...passedArgs);
});

@@ -233,5 +279,5 @@ return pluginTasks[plugin];

const resultMap = {};
yield Promise.all(Object.entries(executionPlan).map(function() {
yield Promise.all(Object.entries(executionPlan).map(/*#__PURE__*/ function() {
var _ref = _async_to_generator(function*([plugin, thunk]) {
resultMap[plugin] = yield thunk(pluginTasks, ...args);
resultMap[plugin] = yield thunk(gasket, pluginTasks, ...args);
});

@@ -249,2 +295,3 @@ return function(_) {

* Like `execMap`, only all hooks must execute synchronously
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -254,13 +301,14 @@ * @param {...*} args Args for hooks

* the plugin and each value the result from the hook
*/ execMapSync(event, ...args) {
*/ execMapSync(gasket, event, ...args) {
return this._execWithCachedPlan({
event,
type: 'execMapSync',
prepare: (hookConfig, trace)=>{
prepare: (hookConfig)=>{
const subscribers = hookConfig.subscribers;
const executionPlan = [];
this._executeInOrder(hookConfig, (plugin)=>{
executionPlan.push((resultMap, ...passedArgs)=>{
trace(plugin);
resultMap[plugin] = subscribers[plugin].callback(...passedArgs);
executionPlan.push((passedGasket, resultMap, ...passedArgs)=>{
var _passedGasket_traceHookStart;
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event);
resultMap[plugin] = subscribers[plugin].invoke(passedGasket, ...passedArgs);
});

@@ -272,3 +320,3 @@ });

const resultMap = {};
executionPlan.forEach((thunk)=>thunk(resultMap, ...args));
executionPlan.forEach((thunk)=>thunk(gasket, resultMap, ...args));
return resultMap;

@@ -282,2 +330,3 @@ }

* to the next hook. It's like an asynchronous version of `Array.prototype.reduce`.
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -287,14 +336,16 @@ * @param {any} value Value to pass to initial hook

* @returns {Promise} The result of the final executed hook.
*/ execWaterfall(event, value, ...otherArgs) {
*/ execWaterfall(gasket, event, value, ...otherArgs) {
const type = 'execWaterfall';
return this._execWithCachedPlan({
event,
type: 'execWaterfall',
prepare: (hookConfig, trace)=>{
type,
prepare: (hookConfig)=>{
const subscribers = hookConfig.subscribers;
return (passedValue, ...args)=>{
return (passedGasket, passedValue, ...args)=>{
let result = Promise.resolve(passedValue);
this._executeInOrder(hookConfig, (plugin)=>{
result = result.then((nextValue)=>{
trace(plugin);
return subscribers[plugin].callback(nextValue, ...args);
var _passedGasket_traceHookStart;
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event);
return subscribers[plugin].invoke(passedGasket, nextValue, ...args);
});

@@ -306,3 +357,3 @@ });

exec: (executionPlan)=>{
return executionPlan(value, ...otherArgs);
return executionPlan(gasket, value, ...otherArgs);
}

@@ -316,2 +367,3 @@ });

* methods whenever possible.
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -321,13 +373,14 @@ * @param {any} value Value to pass to initial hook

* @returns {Promise} The result of the final executed hook.
*/ execWaterfallSync(event, value, ...otherArgs) {
*/ execWaterfallSync(gasket, event, value, ...otherArgs) {
return this._execWithCachedPlan({
event,
type: 'execWaterfallSync',
prepare: (hookConfig, trace)=>{
prepare: (hookConfig)=>{
const subscribers = hookConfig.subscribers;
return (passedValue, ...args)=>{
return (passedGasket, passedValue, ...args)=>{
let result = passedValue;
this._executeInOrder(hookConfig, (plugin)=>{
trace(plugin);
result = subscribers[plugin].callback(result, ...args);
var _passedGasket_traceHookStart;
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event);
result = subscribers[plugin].invoke(passedGasket, result, ...args);
});

@@ -338,3 +391,3 @@ return result;

exec: (executionPlan)=>{
return executionPlan(value, ...otherArgs);
return executionPlan(gasket, value, ...otherArgs);
}

@@ -347,2 +400,3 @@ });

* the plugin itself.
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -352,7 +406,7 @@ * @param {Function} applyFn Function to apply

* the order executed
*/ execApply(event, applyFn) {
*/ execApply(gasket, event, applyFn) {
return this._execWithCachedPlan({
event,
type: 'execApply',
prepare: (hookConfig, trace)=>{
prepare: (hookConfig)=>{
const subscribers = hookConfig.subscribers;

@@ -362,6 +416,8 @@ const executionPlan = [];

this._executeInOrder(hookConfig, (plugin)=>{
pluginThunks[plugin] = (fn, pluginTasks)=>{
pluginThunks[plugin] = (passedGasket, passedApplyFn, pluginTasks)=>{
const callback = (...args)=>subscribers[plugin].invoke(passedGasket, ...args);
pluginTasks[plugin] = Promise.all(subscribers[plugin].ordering.after.map((dep)=>pluginTasks[dep])).then(()=>{
trace(plugin);
return fn(this._pluginMap[plugin], subscribers[plugin].callback);
var _passedGasket_traceHookStart;
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event);
return passedApplyFn(this._pluginMap[plugin], callback);
});

@@ -376,3 +432,3 @@ return pluginTasks[plugin];

const pluginTasks = {};
return Promise.all(executionPlan.map((fn)=>fn(applyFn, pluginTasks)));
return Promise.all(executionPlan.map((fn)=>fn(gasket, applyFn, pluginTasks)));
}

@@ -383,2 +439,3 @@ });

* Like `execApply`, only all hooks must execute synchronously.
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -388,13 +445,15 @@ * @param {Function} applyFn Function to apply

* the order executed
*/ execApplySync(event, applyFn) {
*/ execApplySync(gasket, event, applyFn) {
return this._execWithCachedPlan({
event,
type: 'execApplySync',
prepare: (hookConfig, trace)=>{
prepare: (hookConfig)=>{
const subscribers = hookConfig.subscribers;
const executionPlan = [];
this._executeInOrder(hookConfig, (plugin)=>{
executionPlan.push((fn)=>{
trace(plugin);
return fn(this._pluginMap[plugin], subscribers[plugin].callback);
executionPlan.push((passedGasket, passApplyFn)=>{
var _passedGasket_traceHookStart;
const callback = (...args)=>subscribers[plugin].invoke(passedGasket, ...args);
(_passedGasket_traceHookStart = passedGasket.traceHookStart) === null || _passedGasket_traceHookStart === void 0 ? void 0 : _passedGasket_traceHookStart.call(passedGasket, plugin, event);
return passApplyFn(this._pluginMap[plugin], callback);
});

@@ -405,3 +464,3 @@ });

exec: (executionPlan)=>{
return executionPlan.map((fn)=>fn(applyFn));
return executionPlan.map((fn)=>fn(gasket, applyFn));
}

@@ -414,20 +473,12 @@ });

* @param {object} options options
* @param options.event
* @param options.type
* @param options.prepare
* @param options.exec
* @param {string} options.event - The event to execute
* @param {string} options.type - The type of execution
* @param {Function} options.prepare - Prepare function
* @param {Function} options.exec - Execution function
* @returns {*} result
*/ _execWithCachedPlan({ event, type, prepare, exec }) {
debug(`${' '.repeat(this._traceDepth++)}${type} ${event}`);
const traceDepth = this._traceDepth;
const trace = (plugin)=>debug(`${' '.repeat(traceDepth)}${plugin}:${event}`);
const hookConfig = this._getHookConfig(event);
const plansByType = this._plans[event] || (this._plans[event] = {});
const plan = plansByType[type] || (plansByType[type] = prepare(hookConfig, trace));
const result = exec(plan);
if (typeof (result === null || result === void 0 ? void 0 : result.finally) === 'function') {
return result.finally(()=>this._traceDepth--);
}
this._traceDepth--;
return result;
const plan = plansByType[type] || (plansByType[type] = prepare(hookConfig));
return exec(plan);
}

@@ -520,16 +571,7 @@ /**

this._plans = {};
this._traceDepth = 0;
this._registerPlugins(plugins);
this._registerHooks();
this._registerActions();
// Allow methods to be called without context (to support destructuring)
[
'exec',
'execWaterfall',
'execMap',
'execApply',
'execSync',
'execWaterfallSync',
'execMapSync',
'execApplySync'
].forEach((method)=>{
lifecycleMethods.forEach((method)=>{
this[method] = this[method].bind(this);

@@ -539,2 +581,1 @@ });

}
const _default = GasketEngine;

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

/* eslint-disable no-console, no-process-env */ "use strict";
"use strict";
Object.defineProperty(exports, "__esModule", {

@@ -12,127 +12,9 @@ value: true

_export(exports, {
GasketEngine: function() {
return _engine.default;
Gasket: function() {
return _gasket.Gasket;
},
makeGasket: function() {
return makeGasket;
return _gasket.makeGasket;
}
});
const _engine = /*#__PURE__*/ _interop_require_default(require("./engine.js"));
const _utils = require("@gasket/utils");
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _async_to_generator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
/**
* Get the environment to use for the gasket instance.
* Defaults to `development`.
* @returns {string} env
*/ function getEnvironment() {
// TODO: enable if cli commands and flags are to be used with v7
// if (flags.env) {
// debug('Environment was passed through command line flags', flags.env);
// return flags.env;
// }
const { GASKET_ENV } = process.env;
if (GASKET_ENV) {
return GASKET_ENV;
}
// TODO: enable if cli commands and flags are to be used with v7
// // special snowflake case to match up `local` env with command unless set
// if (commandId === 'local') {
// debug('Environment defaulting to `local` due to `local` command');
// return 'local';
// }
const { NODE_ENV } = process.env;
if (NODE_ENV) {
console.warn(`No env specified, falling back to NODE_ENV: "${NODE_ENV}".`);
return NODE_ENV;
}
console.warn('No env specified, falling back to "development".');
return 'development';
}
/* eslint-enable no-console, no-process-env */ // TODO: Add JSDoc types
/**
*
* @param instance
*/ function registerActions(instance) {
const actions = {};
const actionPluginMap = {};
instance.execApplySync('actions', function() {
var _ref = _async_to_generator(function*(plugin, handler) {
const results = handler(); // The gasket parameter is automatically applied
if (results) {
Object.keys(results).forEach((actionName)=>{
if (actionPluginMap[actionName]) {
// eslint-disable-next-line no-console
console.error(`Action '${actionName}' from '${plugin.name}' was registered by '${actionPluginMap[actionName]}'`);
return;
}
actionPluginMap[actionName] = plugin.name;
actions[actionName] = results[actionName];
});
}
});
return function(plugin, handler) {
return _ref.apply(this, arguments);
};
}());
return actions;
}
// TODO: Add JSDoc types
class Gasket extends _engine.default {
constructor(gasketConfig){
var _config;
const env = getEnvironment();
const config = (0, _utils.applyConfigOverrides)(gasketConfig, {
env
});
config.env = env;
var _root;
(_root = (_config = config).root) !== null && _root !== void 0 ? _root : _config.root = process.cwd();
// start the engine
super(config.plugins);
this.config = config;
this.command = null;
this.execSync('init');
this.actions = registerActions(this);
this.config = this.execWaterfallSync('configure', config);
}
}
// TODO: Add JSDoc types
/**
*
* @param gasketConfigDefinition
*/ function makeGasket(gasketConfigDefinition) {
return new Gasket(gasketConfigDefinition);
}
const _gasket = require("./gasket.js");

@@ -1,8 +0,11 @@

import debugPkg from 'debug';
let dynamicNamingId = 0;
const debug = debugPkg('gasket:engine');
export const lifecycleMethods = [
'exec', 'execSync',
'execWaterfall', 'execWaterfallSync',
'execMap', 'execMapSync',
'execApply', 'execApplySync'
];
let dynamicNamingId = 0;
class GasketEngine {
export class GasketEngine {
constructor(plugins) {

@@ -15,19 +18,13 @@ if (!plugins || !Array.isArray(plugins) || !plugins.length) {

this._plans = {};
this._traceDepth = 0;
this._registerPlugins(plugins);
this._registerHooks();
this._registerActions();
// Allow methods to be called without context (to support destructuring)
[
'exec', 'execWaterfall', 'execMap', 'execApply',
'execSync', 'execWaterfallSync', 'execMapSync', 'execApplySync'
].forEach(method => { this[method] = this[method].bind(this); });
lifecycleMethods.forEach(method => {
this[method] = this[method].bind(this);
});
}
/**
* Resolves plugins
* @param plugins
* @private
*/
_registerPlugins(plugins) {

@@ -38,3 +35,6 @@

.reduce((acc, plugin) => {
// TODO: throw if plugin is not an object
if (typeof plugin !== 'object' || Array.isArray(plugin)) {
throw new Error(`Plugin ${plugin.name} must be an object`);
}
const { name, hooks } = plugin;

@@ -48,2 +48,7 @@ if (!name) {

// Add base metadata hook if not present
if (!plugin.hooks.metadata) {
plugin.hooks.metadata = async (_, metadata) => metadata;
}
acc[name] = plugin;

@@ -88,2 +93,24 @@ return acc;

_registerActions() {
this.actions = {};
const actionPluginMap = {};
Object.entries(this._pluginMap).forEach(([pluginName, plugin]) => {
const { actions } = plugin;
if (actions) {
Object.keys(actions).forEach(actionName => {
if (actionPluginMap[actionName]) {
// eslint-disable-next-line no-console
console.error(
`Action '${actionName}' from '${pluginName}' was registered by '${actionPluginMap[actionName]}'`
);
return;
}
actionPluginMap[actionName] = plugin.name;
this.actions[actionName] = actions[actionName];
});
}
});
}
/**

@@ -117,3 +144,5 @@ * Injects additional lifecycle hooks at runtime.

},
callback: handler.bind(null, this)
invoke: (gasket, ...args) => {
return handler(gasket, ...args);
}
};

@@ -128,2 +157,3 @@

* plugins to finish.
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -134,7 +164,7 @@ * @param {...*} args Args for hooks

*/
exec(event, ...args) {
exec(gasket, event, ...args) {
return this._execWithCachedPlan({
event,
type: 'exec',
prepare: (hookConfig, trace) => {
prepare: (hookConfig) => {
const subscribers = hookConfig.subscribers;

@@ -144,8 +174,8 @@ const executionPlan = [];

this._executeInOrder(hookConfig, plugin => {
pluginThunks[plugin] = (pluginTasks, ...passedArgs) => {
pluginThunks[plugin] = (passedGasket, pluginTasks, ...passedArgs) => {
pluginTasks[plugin] = Promise
.all(subscribers[plugin].ordering.after.map(dep => pluginTasks[dep]))
.then(() => {
trace(plugin);
return subscribers[plugin].callback(...passedArgs);
passedGasket.traceHookStart?.(plugin, event);
return subscribers[plugin].invoke(passedGasket, ...passedArgs);
});

@@ -161,3 +191,3 @@ return pluginTasks[plugin];

const pluginTasks = {};
return Promise.all(executionPlan.map(fn => fn(pluginTasks, ...args)));
return Promise.all(executionPlan.map(fn => fn(gasket, pluginTasks, ...args)));
}

@@ -172,2 +202,3 @@ });

* possible.
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -178,13 +209,13 @@ * @param {...*} args Args for hooks

*/
execSync(event, ...args) {
execSync(gasket, event, ...args) {
return this._execWithCachedPlan({
event,
type: 'execSync',
prepare: (hookConfig, trace) => {
prepare: (hookConfig) => {
const subscribers = hookConfig.subscribers;
const executionPlan = [];
this._executeInOrder(hookConfig, plugin => {
executionPlan.push((...execArgs) => {
trace(plugin);
return subscribers[plugin].callback(...execArgs);
executionPlan.push((passedGasket, ...execArgs) => {
passedGasket.traceHookStart?.(plugin, event);
return subscribers[plugin].invoke(passedGasket, ...execArgs);
});

@@ -196,3 +227,3 @@ });

exec: executionPlan => {
return executionPlan.map(fn => fn(...args));
return executionPlan.map(fn => fn(gasket, ...args));
}

@@ -207,2 +238,3 @@ });

* present in the map.
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -213,16 +245,16 @@ * @param {...*} args Args for hooks

*/
execMap(event, ...args) {
execMap(gasket, event, ...args) {
return this._execWithCachedPlan({
event,
type: 'execMap',
prepare: (hookConfig, trace) => {
prepare: (hookConfig) => {
const subscribers = hookConfig.subscribers;
const executionPlan = {};
this._executeInOrder(hookConfig, plugin => {
executionPlan[plugin] = (pluginTasks, ...passedArgs) => {
executionPlan[plugin] = (passedGasket, pluginTasks, ...passedArgs) => {
pluginTasks[plugin] = Promise
.all(subscribers[plugin].ordering.after.map(dep => pluginTasks[dep]))
.then(() => {
trace(plugin);
return subscribers[plugin].callback(...passedArgs);
passedGasket.traceHookStart?.(plugin, event);
return subscribers[plugin].invoke(passedGasket, ...passedArgs);
});

@@ -242,3 +274,3 @@ return pluginTasks[plugin];

.map(async ([plugin, thunk]) => {
resultMap[plugin] = await thunk(pluginTasks, ...args);
resultMap[plugin] = await thunk(gasket, pluginTasks, ...args);
})

@@ -253,2 +285,3 @@ );

* Like `execMap`, only all hooks must execute synchronously
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -259,13 +292,13 @@ * @param {...*} args Args for hooks

*/
execMapSync(event, ...args) {
execMapSync(gasket, event, ...args) {
return this._execWithCachedPlan({
event,
type: 'execMapSync',
prepare: (hookConfig, trace) => {
prepare: (hookConfig) => {
const subscribers = hookConfig.subscribers;
const executionPlan = [];
this._executeInOrder(hookConfig, plugin => {
executionPlan.push((resultMap, ...passedArgs) => {
trace(plugin);
resultMap[plugin] = subscribers[plugin].callback(...passedArgs);
executionPlan.push((passedGasket, resultMap, ...passedArgs) => {
passedGasket.traceHookStart?.(plugin, event);
resultMap[plugin] = subscribers[plugin].invoke(passedGasket, ...passedArgs);
});

@@ -278,3 +311,3 @@ });

const resultMap = {};
executionPlan.forEach(thunk => thunk(resultMap, ...args));
executionPlan.forEach(thunk => thunk(gasket, resultMap, ...args));
return resultMap;

@@ -289,2 +322,3 @@ }

* to the next hook. It's like an asynchronous version of `Array.prototype.reduce`.
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -295,10 +329,11 @@ * @param {any} value Value to pass to initial hook

*/
execWaterfall(event, value, ...otherArgs) {
execWaterfall(gasket, event, value, ...otherArgs) {
const type = 'execWaterfall';
return this._execWithCachedPlan({
event,
type: 'execWaterfall',
prepare: (hookConfig, trace) => {
type,
prepare: (hookConfig) => {
const subscribers = hookConfig.subscribers;
return (passedValue, ...args) => {
return (passedGasket, passedValue, ...args) => {
let result = Promise.resolve(passedValue);

@@ -308,4 +343,4 @@

result = result.then((nextValue) => {
trace(plugin);
return subscribers[plugin].callback(nextValue, ...args);
passedGasket.traceHookStart?.(plugin, event);
return subscribers[plugin].invoke(passedGasket, nextValue, ...args);
});

@@ -317,4 +352,4 @@ });

},
exec: executionPlan => {
return executionPlan(value, ...otherArgs);
exec: (executionPlan) => {
return executionPlan(gasket, value, ...otherArgs);
}

@@ -329,2 +364,3 @@ });

* methods whenever possible.
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -335,15 +371,15 @@ * @param {any} value Value to pass to initial hook

*/
execWaterfallSync(event, value, ...otherArgs) {
execWaterfallSync(gasket, event, value, ...otherArgs) {
return this._execWithCachedPlan({
event,
type: 'execWaterfallSync',
prepare: (hookConfig, trace) => {
prepare: (hookConfig) => {
const subscribers = hookConfig.subscribers;
return (passedValue, ...args) => {
return (passedGasket, passedValue, ...args) => {
let result = passedValue;
this._executeInOrder(hookConfig, plugin => {
trace(plugin);
result = subscribers[plugin].callback(result, ...args);
passedGasket.traceHookStart?.(plugin, event);
result = subscribers[plugin].invoke(passedGasket, result, ...args);
});

@@ -355,3 +391,3 @@

exec: executionPlan => {
return executionPlan(value, ...otherArgs);
return executionPlan(gasket, value, ...otherArgs);
}

@@ -365,2 +401,3 @@ });

* the plugin itself.
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -371,7 +408,7 @@ * @param {Function} applyFn Function to apply

*/
execApply(event, applyFn) {
execApply(gasket, event, applyFn) {
return this._execWithCachedPlan({
event,
type: 'execApply',
prepare: (hookConfig, trace) => {
prepare: (hookConfig) => {
const subscribers = hookConfig.subscribers;

@@ -381,8 +418,9 @@ const executionPlan = [];

this._executeInOrder(hookConfig, plugin => {
pluginThunks[plugin] = (fn, pluginTasks) => {
pluginThunks[plugin] = (passedGasket, passedApplyFn, pluginTasks) => {
const callback = (...args) => subscribers[plugin].invoke(passedGasket, ...args);
pluginTasks[plugin] = Promise
.all(subscribers[plugin].ordering.after.map(dep => pluginTasks[dep]))
.then(() => {
trace(plugin);
return fn(this._pluginMap[plugin], subscribers[plugin].callback);
passedGasket.traceHookStart?.(plugin, event);
return passedApplyFn(this._pluginMap[plugin], callback);
});

@@ -398,3 +436,3 @@ return pluginTasks[plugin];

const pluginTasks = {};
return Promise.all(executionPlan.map(fn => fn(applyFn, pluginTasks)));
return Promise.all(executionPlan.map(fn => fn(gasket, applyFn, pluginTasks)));
}

@@ -406,2 +444,3 @@ });

* Like `execApply`, only all hooks must execute synchronously.
* @param {import("@gasket/core").Gasket} gasket - The gasket instance
* @param {string} event The event to execute

@@ -412,13 +451,14 @@ * @param {Function} applyFn Function to apply

*/
execApplySync(event, applyFn) {
execApplySync(gasket, event, applyFn) {
return this._execWithCachedPlan({
event,
type: 'execApplySync',
prepare: (hookConfig, trace) => {
prepare: (hookConfig) => {
const subscribers = hookConfig.subscribers;
const executionPlan = [];
this._executeInOrder(hookConfig, plugin => {
executionPlan.push(fn => {
trace(plugin);
return fn(this._pluginMap[plugin], subscribers[plugin].callback);
this._executeInOrder(hookConfig, (plugin) => {
executionPlan.push((passedGasket, passApplyFn) => {
const callback = (...args) => subscribers[plugin].invoke(passedGasket, ...args);
passedGasket.traceHookStart?.(plugin, event);
return passApplyFn(this._pluginMap[plugin], callback);
});

@@ -429,3 +469,3 @@ });

exec: executionPlan => {
return executionPlan.map(fn => fn(applyFn));
return executionPlan.map(fn => fn(gasket, applyFn));
}

@@ -439,13 +479,9 @@ });

* @param {object} options options
* @param options.event
* @param options.type
* @param options.prepare
* @param options.exec
* @param {string} options.event - The event to execute
* @param {string} options.type - The type of execution
* @param {Function} options.prepare - Prepare function
* @param {Function} options.exec - Execution function
* @returns {*} result
*/
_execWithCachedPlan({ event, type, prepare, exec }) {
debug(`${' '.repeat(this._traceDepth++)}${type} ${event}`);
const traceDepth = this._traceDepth;
const trace = plugin => debug(`${' '.repeat(traceDepth)}${plugin}:${event}`);
const hookConfig = this._getHookConfig(event);

@@ -456,11 +492,6 @@ const plansByType = this._plans[event] || (

const plan = plansByType[type] || (
plansByType[type] = prepare(hookConfig, trace)
plansByType[type] = prepare(hookConfig)
);
const result = exec(plan);
if (typeof result?.finally === 'function') {
return result.finally(() => this._traceDepth--);
}
this._traceDepth--;
return result;
return exec(plan);
}

@@ -560,3 +591,1 @@

}
export default GasketEngine;

@@ -8,2 +8,10 @@ declare module '@gasket/core' {

export type ActionId = keyof GasketActions;
export type ActionHandler<Id extends ActionId> = (
gasket: Gasket,
...args: Parameters<GasketActions[Id]>
) => ReturnType<GasketActions[Id]>;
// To be extended by plugins

@@ -13,4 +21,4 @@ export interface HookExecTypes {

init(): void
actions(): Partial<GasketActions>
configure(config: GasketConfig): GasketConfig
ready(): MaybeAsync<void>
}

@@ -45,2 +53,4 @@

name: string;
version?: string;
description?: string;
dependencies?: Array<string>;

@@ -50,4 +60,10 @@ hooks: {

};
actions?: {
[K in ActionId]?: ActionHandler<K>;
};
metadata?: Record<string, any>;
};
export type Preset = Omit<Plugin, 'actions'>;
// This is the config

@@ -63,2 +79,4 @@ export interface GasketConfig {

actions: GasketActions
exec<Id extends HookId>(

@@ -75,7 +93,7 @@ hook: Id,

...args: Parameters<HookExecTypes[Id]>
): ReturnType<HookExecTypes[Id]>;
): Promise<ResolvedType<ReturnType<HookExecTypes[Id]>>>;
execWaterfallSync<Id extends HookId>(
hook: Id,
...args: Parameters<HookExecTypes[Id]>
): ReturnType<HookExecTypes[Id]>;
): ResolvedType<ReturnType<HookExecTypes[Id]>>;
execApply<Id extends HookId, Return = void>(

@@ -102,2 +120,5 @@ hook: Id,

export interface Gasket extends GasketEngine {
constructor(config: GasketConfigDefinition);
new (config: GasketConfigDefinition): Gasket
command: {

@@ -107,6 +128,9 @@ id: string;

config: GasketConfig;
new (config: GasketConfigDefinition): Gasket
actions: GasketActions
symbol: Symbol;
traceBranch(): GasketTrace
traceRoot(): Gasket
}
export type GasketTrace = Proxy<Gasket>;
type PartialRecursive<T> = T extends Object

@@ -134,2 +158,1 @@ ? { [K in keyof T]?: PartialRecursive<T[K]> } | undefined

}

@@ -1,103 +0,6 @@

/* eslint-disable no-console, no-process-env */
import { Gasket, makeGasket } from './gasket.js';
import GasketEngine from './engine.js';
import { applyConfigOverrides } from '@gasket/utils';
/**
* Get the environment to use for the gasket instance.
* Defaults to `development`.
* @returns {string} env
*/
function getEnvironment(
// flags, commandId, warn
) {
// TODO: enable if cli commands and flags are to be used with v7
// if (flags.env) {
// debug('Environment was passed through command line flags', flags.env);
// return flags.env;
// }
const { GASKET_ENV } = process.env;
if (GASKET_ENV) {
return GASKET_ENV;
}
// TODO: enable if cli commands and flags are to be used with v7
// // special snowflake case to match up `local` env with command unless set
// if (commandId === 'local') {
// debug('Environment defaulting to `local` due to `local` command');
// return 'local';
// }
const { NODE_ENV } = process.env;
if (NODE_ENV) {
console.warn(`No env specified, falling back to NODE_ENV: "${NODE_ENV}".`);
return NODE_ENV;
}
console.warn('No env specified, falling back to "development".');
return 'development';
}
/* eslint-enable no-console, no-process-env */
// TODO: Add JSDoc types
/**
*
* @param instance
*/
function registerActions(instance) {
const actions = {};
const actionPluginMap = {};
instance.execApplySync('actions', async (plugin, handler) => {
const results = handler(); // The gasket parameter is automatically applied
if (results) {
Object.keys(results).forEach(actionName => {
if (actionPluginMap[actionName]) {
// eslint-disable-next-line no-console
console.error(
`Action '${actionName}' from '${plugin.name}' was registered by '${actionPluginMap[actionName]}'`
);
return;
}
actionPluginMap[actionName] = plugin.name;
actions[actionName] = results[actionName];
});
}
});
return actions;
}
// TODO: Add JSDoc types
class Gasket extends GasketEngine {
constructor(gasketConfig) {
const env = getEnvironment();
const config = applyConfigOverrides(gasketConfig, { env });
config.env = env;
config.root ??= process.cwd();
// start the engine
super(config.plugins);
this.config = config;
this.command = null;
this.execSync('init');
this.actions = registerActions(this);
this.config = this.execWaterfallSync('configure', config);
}
}
// TODO: Add JSDoc types
/**
*
* @param gasketConfigDefinition
*/
function makeGasket(gasketConfigDefinition) {
return new Gasket(gasketConfigDefinition);
}
export {
makeGasket,
GasketEngine
Gasket,
makeGasket
};
{
"name": "@gasket/core",
"version": "7.0.1-canary.12",
"version": "7.0.1",
"description": "Entry point to setting up Gasket instances",
"type": "module",
"types": "lib/index.d.ts",
"files": [
"lib",
"cjs",
"docs"
],
"exports": {

@@ -10,11 +17,6 @@ ".": {

"types": "./lib/index.d.ts"
}
},
"./package.json": "./package.json"
},
"types": "lib/index.d.ts",
"files": [
"lib",
"cjs"
],
"scripts": {
"build": "swc lib -d cjs --delete-dir-on-start --strip-leading-paths",
"lint": "eslint .",

@@ -28,2 +30,4 @@ "lint:fix": "npm run lint -- --fix",

"typecheck:watch": "tsc --watch",
"build": "swc lib -d cjs --delete-dir-on-start --strip-leading-paths",
"postbuild": "node -e \"require('fs').writeFileSync('cjs/package.json', '{}')\"",
"prepublishOnly": "npm run build"

@@ -45,6 +49,2 @@ },

"author": "GoDaddy Operating Company, LLC",
"maintainers": [
"Jacob Page <jpage@godaddy.com>",
"Charlie Robbins <charlie.robbins@gmail.com>"
],
"license": "MIT",

@@ -54,3 +54,3 @@ "bugs": {

},
"homepage": "https://github.com/godaddy/gasket/tree/main/packages/gasket-engine",
"homepage": "https://github.com/godaddy/gasket/tree/main/packages/gasket-core",
"dependencies": {

@@ -67,8 +67,8 @@ "debug": "^4.3.4"

"eslint": "^8.56.0",
"eslint-config-godaddy": "^7.1.0",
"eslint-plugin-jest": "^27.6.3",
"eslint-config-godaddy": "^7.1.1",
"eslint-plugin-jest": "^28.6.0",
"eslint-plugin-json": "^3.1.0",
"eslint-plugin-unicorn": "^44.0.0",
"eslint-plugin-unicorn": "^55.0.0",
"jest": "^29.7.0",
"typescript": "^5.4.4"
"typescript": "^5.4.5"
},

@@ -92,6 +92,15 @@ "eslintConfig": {

"no-sync": 0
}
},
"overrides": [
{
"files": [
"test/**/*.js"
],
"rules": {
"jsdoc/require-jsdoc": "off"
}
}
]
},
"type": "module",
"gitHead": "30055cdc6bb04a78c07c5ede230242db17327260"
"gitHead": "0426b7f57bc2618606955912c0f3cd55174f5367"
}

@@ -11,3 +11,3 @@ # @gasket/core

Add a `gasket.mjs` file to the root of your project.
Add a `gasket.js` file to the root of your project.
This can be a `.js` extension if your package.json has the `type` field set to `module`.

@@ -17,3 +17,3 @@ It is also possible to use with a `.ts` extension if you have TypeScript configured.

```js
// gasket.mjs
// gasket.js
import { makeGasket } from '@gasket/core';

@@ -31,3 +31,3 @@ import LoggerPlugin from '@gasket/plugin-logger';

You can now import the Gasket instance from your `gasket.mjs` file into your
You can now import the Gasket instance from your `gasket.js` file into your
application code.

@@ -41,3 +41,3 @@ With a Gasket, you can fire **actions** that will trigger **lifecycles** hooked

(See [Plugins Guide]).
In your `gasket.mjs` file, you can import plugins and add them to the `plugins`
In your `gasket.js` file, you can import plugins and add them to the `plugins`
array of the Gasket configuration.

@@ -50,4 +50,4 @@

1. [init]
2. [actions]
3. [configure]
2. [configure]
2. [ready]

@@ -60,9 +60,9 @@ ### init

```js
// gasket-plugin-example.mjs
// gasket-plugin-example.js
export const name = 'gasket-plugin-example';
const name = 'gasket-plugin-example';
let _initializedTime;
export const hooks = {
const hooks = {
init(gasket) {

@@ -72,2 +72,4 @@ _initializedTime = Date.now();

};
export default { name, hooks };
```

@@ -77,2 +79,76 @@

recommended.
Instead, a plugin can register [actions] that can be executed to retrieve
values the plugin wishes to make available.
### configure
The `configure` lifecycle is the first lifecycle executed when a Gasket is
instantiated.
This allows any [registered plugins] to adjust the configuration before further
lifecycles are executed.
```js
// gasket-plugin-example.js
const name = 'gasket-plugin-example';
const hooks = {
configure(gasket, gasketConfig) {
// Modify the configuration
return {
...gasketConfig,
example: true
};
}
};
export default { name, hooks };
```
In this example, we register an action `getDoodads` that will only execute if the
`example` configuration is set to `true`.
It will then execute the `doodads` lifecycle, allowing any registered plugin to
provide doodads.
### ready
The `ready` lifecycle is the last lifecycle executed and is used to signal that
the Gasket instance is fully initialized and ready to be used.
```js
// gasket-plugin-example.js
const name = 'gasket-plugin-example';
const hooks = {
async ready(gasket) {
console.log('Gasket is ready!');
}
};
export default { name, hooks };
```
## Actions
Plugins can register actions that can be fired by the application code
where the Gasket is imported, or in other plugins.
```js
// gasket-plugin-example.js
const name = 'gasket-plugin-example';
const actions = {
async getDoodads(gasket) {
if (gasket.config.example) {
const dodaads = await gasket.exec('dodaads');
return dodaads.flat()
}
}
};
export default { name, actions };
```
If a plugin needs to make properties available to other plugins, it should

@@ -82,9 +158,15 @@ register an action that can be executed to retrieve the value.

```diff
// gasket-plugin-example.mjs
// gasket-plugin-example.js
export const name = 'gasket-plugin-example';
const name = 'gasket-plugin-example';
let _initializedTime;
+ let _initializedTime;
export const hooks = {
+ const actions = {
+ getInitializedTime() {
+ return _initializedTime;
+ }
+ };
const hooks = {
init(gasket) {

@@ -94,73 +176,96 @@ - gasket.initializedTime = Date.now();

},
+ actions() {
+ return {
+ getInitializedTime() {
+ return _initializedTime;
+ }
+ }
+ },
configure(gasket) {
- const time = gasket.initializedTime;
+ const time = gasket.actions.getInitializedTime();
// do something with time...
}
};
- export default { name, hooks };
+ export default { name, actions, hooks };
```
### actions
## Debugging
The `actions` lifecycle is the second lifecycle executed when a Gasket is created.
This will let plugins register actions that can be fired by the application code
where the Gasket is imported, or in other plugins.
Gasket makes use of the [debug] module to provide various debug outputs. Gasket
packages and plugins use the `gasket` namespace.
```js
// gasket-plugin-example.mjs
```shell
DEBUG=gasket:* npm run start
```
export const name = 'gasket-plugin-example';
### Tracing
export const hooks = {
actions(gasket) {
return {
async getDoodads() {
if(gasket.config.example) {
const dodaads = await gasket.exec('dodaads');
return dodaads.flat()
}
}
}
}
};
You can narrow down to see the action and lifecycle execution order in the
console output under the `gasket:trace` namespace.
```shell
DEBUG=gasket:trace* npm run start
```
### configure
![trace-example.png](docs/trace-example.png)
The `configure` lifecycle is the first lifecycle executed when a Gasket is
instantiated.
This allows any [registered plugins] to adjust the configuration before further
lifecycles are executed.
The following symbols indicate the step and type of execution:
- `⋌` New Trace Branch
- `★` Action Start
- `◆` Synchronous Lifecycle Start
- `◇` Asynchronous Lifecycle Start
- `↪` Plugin lifecycle Hook
When ever the app or a plugin executes a lifecycle or an action, it will be
passed a traceable proxy object, which can be used to follow the execution
path of the application.
Any action or lifecycle that is executed from the root `gasket` object will
start a new trace "branch".
New branches can be created by calling `gasket.traceBranch()` to help debug
certain lifecycle flows.
Additionally, it is possible to start fresh traces by calling
`gasket.traceRoot()`.
This method should will exit the current branch's trace history
and start a fresh.
Use this sparingly only for situations such as tracing handling for new requests.
## Recursion Protection
Gasket uses the trace history to catch and prevent infinite recursion.
If a lifecycle is executed more than once in the same trace history,
it will throw an error and halt the execution.
While it is ok to execute the same action at various steps in an event chain,
you must avoid calling the same **lifecycle** from within itself.
Memoization can help avoid this issue, and using `req` as a key can help for
request-specific memoization, which is also a good performance optimization.
```js
// gasket-plugin-example.mjs
// gasket-plugin-example.js
export const name = 'gasket-plugin-example';
const reqMap = new WeakMap();
export const hooks = {
configure(gasket, gasketConfig) {
// Modify the configuration
return {
...gasketConfig,
example: true
};
const name = 'gasket-plugin-example';
const actions = {
async getDoodads(gasket, req) {
if(!reqMap.has(req)) {
const doodads = await gasket.exec('doodads', req);
reqMap.set(req, doodads);
}
return reqMap.get(req);
}
};
const hooks = {
// ...
};
export default { name, actions, hooks };
```
In this example, we register an action `getDoodads` that will only execute if the
`example` configuration is set to `true`.
It will then execute the `doodads` lifecycle, allowing any registered plugin to
provide doodads.
[init]: #init
[configure]: #configure
[ready]: #ready
[actions]: #actions
[configure]: #configure
[registered plugins]: #registered-plugins
[Plugins Guide]:/packages/gasket-cli/docs/plugins.md
[debug]:https://github.com/debug-js/debug
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