🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@chargebee/chargebee-apps-shared

Package Overview
Dependencies
Maintainers
4
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@chargebee/chargebee-apps-shared - npm Package Compare versions

Comparing version
1.0.0
to
1.0.1
+6
-0
CHANGELOG.md
# @chargebee/chargebee-apps-shared
## [1.0.1] - 2026-07-24
### Fixed
- Local modules imported via relative paths (e.g., require('./helper')) now execute within the entry handler’s sandbox, allowing them to share the same environment variables and logging configuration.
## [1.0.0] - 2026-07-09

@@ -4,0 +10,0 @@

+57
-7

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

import vm from 'vm';
import { CBFileSystem } from '../node/file-system';
import { AllowedModule, Manifest } from '../types/common';
interface UserModuleCacheEntry {
exports: any;
}
type SandboxRequire = (moduleName: string) => any;
type MakeSandboxRequire = (parentDir: string) => SandboxRequire;
/**

@@ -19,8 +25,12 @@ * DependencyManager handles isolated npm installations for user projects

/**
* Creates a safe require function that uses isolated node_modules
* Creates a safe require function that uses isolated node_modules.
* When vmContext is provided, relative user modules are compiled and run in that
* context so they share sandbox process/console with the entry handler.
* Allowlisted packages always load via native Node require.
* @param {string} projectPath - Path to the user project
* @param {AllowedModule[]} allowedModules - List of allowed modules
* @param {vm.Context} [vmContext] - Shared VM context for relative user modules
* @returns {Function} Safe require function
*/
createIsolatedRequire(projectPath: string, allowedModules: AllowedModule[]): (moduleName: string) => any;
createIsolatedRequire(projectPath: string, allowedModules: AllowedModule[], vmContext?: vm.Context): SandboxRequire;
/**

@@ -45,9 +55,48 @@ * Creates or updates package.json for the project

/**
* Gets the relative path require.
* @param moduleName - Name of the module to require
* @param handlerPath - Path to the handler directory
* @returns
* Loads a relative user module. With a VM context, the module is compiled in the
* sandbox so it shares process/console with the entry handler; otherwise native require is used.
* @param {string} moduleName - Relative module id (./ or ../)
* @param {string} parentDir - Directory of the requiring module
* @param {string} handlerPath - Path to the handler directory (containment root)
* @param {{ vmContext: vm.Context, makeRequire: MakeSandboxRequire, cache: Map<string, UserModuleCacheEntry> }} [vmOptions] - VM load options
* @returns {any} Module exports
*/
protected getRelativePathRequire(moduleName: string, handlerPath: string): any;
protected getRelativePathRequire(moduleName: string, parentDir: string, handlerPath: string, vmOptions?: {
vmContext: vm.Context;
makeRequire: MakeSandboxRequire;
cache: Map<string, UserModuleCacheEntry>;
}): any;
/**
* Resolves a relative user module path and ensures it stays under handlerPath.
* Supports direct files, `.js` extension fallback, and directory → `index.js`.
* Containment is enforced on both lexical and canonical (realpath) paths so
* symlinks cannot escape the handler root.
* @param {string} moduleName - Relative module id
* @param {string} parentDir - Directory of the requiring module
* @param {string} handlerPath - Handler directory root
* @returns {string} Absolute path to the module file
*/
protected resolveRelativeUserModulePath(moduleName: string, parentDir: string, handlerPath: string): string;
/**
* Lexical containment check (no symlink resolution).
* @param {string} candidatePath - Absolute path to validate
* @param {string} handlerPath - Handler directory root
*/
protected assertPathInsideHandler(candidatePath: string, handlerPath: string): void;
/**
* Canonical containment check using realpath so symlink targets outside handler are rejected.
* @param {string} candidatePath - Absolute path to validate (must exist)
* @param {string} handlerPath - Handler directory root
*/
protected assertCanonicalPathInsideHandler(candidatePath: string, handlerPath: string): void;
/**
* Compiles and runs a user module inside the shared VM context (CommonJS wrapper).
* @param {string} filename - Absolute path to the module file
* @param {vm.Context} vmContext - Shared sandbox context
* @param {MakeSandboxRequire} makeRequire - Factory for nested sandbox require
* @param {Map<string, UserModuleCacheEntry>} cache - Per-execution module cache
* @returns {any} Module exports
*/
protected runUserModuleInVm(filename: string, vmContext: vm.Context, makeRequire: MakeSandboxRequire, cache: Map<string, UserModuleCacheEntry>): any;
/**
* Gets the generic dependency require. Unless there are special cases like ES modules, this should work for all dependencies.

@@ -69,1 +118,2 @@ * @param moduleName - Name of the module to require

}
export {};
+3
-1

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

"use strict";var __importDefault=this&&this.__importDefault||function(a){return a&&a.__esModule?a:{default:a}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.DependencyManager=void 0;const child_process_1=require("child_process"),path_1=__importDefault(require("path")),semver_1=__importDefault(require("semver")),internal_logger_1=require("../logger/internal-logger");class DependencyManager{constructor(s){this.fileSystem=s,this.installed=!1}async ensureDependencies(s,n){if(!n.dependencies||Object.keys(n.dependencies).length===0){internal_logger_1.__logger.debug("No dependencies to install");return}if(this.installed){internal_logger_1.__logger.debug("Dependencies already installed for this project");return}const e=path_1.default.join(s,"handler"),i=path_1.default.join(e,"package.json");try{this.fileSystem.existsSync(e)||this.fileSystem.mkdirSync(e,{recursive:!0}),await this.createPackageJson(i,n.dependencies),await this.installDependencies(e),this.installed=!0,internal_logger_1.__logger.info(`Installed ${Object.keys(n.dependencies).length} dependencies for project`)}catch(t){const r=t;throw internal_logger_1.__logger.error("Failed to install dependencies:",r.message),new Error(`Dependency installation failed: ${r.message}`)}}createIsolatedRequire(s,n){const e=path_1.default.resolve(s,"handler"),i=path_1.default.join(e,"node_modules");return t=>{if(t.startsWith("./"))return this.getRelativePathRequire(t,e);if(t.includes("/"))return this.getGenericDependencyRequire(t,n,i);const r=this.validateAndGetModulePath(n,i,t);try{return this.tryLoadCommonJSAlternative(t,r)}catch(o){const l=o;throw new Error(`Failed to load module "${t}": ${l.message}`)}}}async createPackageJson(s,n){const e={dependencies:{...n}},i=JSON.stringify(e,null,2);this.fileSystem.writeFileSync(s,i),internal_logger_1.__logger.debug("Created/updated package.json")}async installDependencies(s){try{(0,child_process_1.execSync)("npm install --ignore-scripts --no-audit --no-fund --loglevel=error",{cwd:s,stdio:"pipe",timeout:6e4}),internal_logger_1.__logger.debug("npm install completed successfully")}catch(n){const e=n;throw new Error(`npm install failed: ${e.message}`)}}tryLoadCommonJSAlternative(s,n){const e=require(n);if(e&&typeof e=="object"&&e.__esModule&&typeof e!="function"){internal_logger_1.__logger.debug(`ES module detected for ${s} (loaded but has named exports), looking for CommonJS alternative`);const i=path_1.default.join(n,"package.json");if(this.fileSystem.existsSync(i)){const t=JSON.parse(this.fileSystem.readFileSync(i,"utf8"));if(t.exports&&t.exports["."]){const r=t.exports["."];if(r.require){const o=path_1.default.resolve(n,r.require);return internal_logger_1.__logger.debug(`Trying CommonJS path: ${r.require}`),require(o)}if(r.default&&r.default.require){const o=path_1.default.resolve(n,r.default.require);return internal_logger_1.__logger.debug(`Trying default CommonJS path: ${r.default.require}`),require(o)}}if(t.main){const r=path_1.default.resolve(n,t.main);return internal_logger_1.__logger.debug(`Trying main field: ${t.main}`),require(r)}}return internal_logger_1.__logger.error(`No CommonJS alternative found for ${s}, using ES module as-is`),e}return e}getRelativePathRequire(s,n){const e=path_1.default.normalize(s);if(e.includes(".."))throw new Error("Path traversal not allowed in relative imports");const i=path_1.default.resolve(n,e);if(!i.startsWith(n))throw new Error("Relative import path resolves outside of handler directory");let t=i;if(!this.fileSystem.existsSync(i)){const r=i+".js";if(this.fileSystem.existsSync(r))t=r;else throw new Error(`File or module not found: ${s}`)}return require(t)}getGenericDependencyRequire(s,n,e){const i=s.split("/")[0];if(!n.find(o=>o.name===i))throw new Error(`Module "${i}" is not allowed in this environment`);const r=path_1.default.join(e,s);if(!this.fileSystem.existsSync(r))throw new Error(`Module path "${s}" is not installed. Please ensure dependencies are installed.`);return internal_logger_1.__logger.debug(`Loading CommonJS path: ${s}`),require(path_1.default.resolve(r))}validateAndGetModulePath(s,n,e){const i=path_1.default.join(n,e);if(!this.fileSystem.existsSync(i))throw new Error(`Module "${e}" is not installed. Please ensure dependencies are installed.`);const t=s.find(r=>r.name===e);if(!t)throw new Error(`Module "${e}" is not allowed in this environment`);if(t.version)try{const r=path_1.default.join(i,"package.json"),l=JSON.parse(this.fileSystem.readFileSync(r,"utf8")).version;if(!semver_1.default.satisfies(l,t.version))throw new Error(`Module "${e}" version ${l} does not satisfy allowed version constraint ${t.version}`);internal_logger_1.__logger.debug(`Module "${e}" version ${l} satisfies constraint ${t.version}`)}catch(r){const o=r;internal_logger_1.__logger.warn(`Warning: Could not verify version for module "${e}":`,o.message)}else throw new Error(`Configuration error: Allowed module "${e}" does not have a version constraint`);return path_1.default.resolve(i)}}exports.DependencyManager=DependencyManager;
"use strict";var __importDefault=this&&this.__importDefault||function(d){return d&&d.__esModule?d:{default:d}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.DependencyManager=void 0;const child_process_1=require("child_process"),path_1=__importDefault(require("path")),semver_1=__importDefault(require("semver")),vm_1=__importDefault(require("vm")),internal_logger_1=require("../logger/internal-logger");class DependencyManager{constructor(t){this.fileSystem=t,this.installed=!1}async ensureDependencies(t,s){if(!s.dependencies||Object.keys(s.dependencies).length===0){internal_logger_1.__logger.debug("No dependencies to install");return}if(this.installed){internal_logger_1.__logger.debug("Dependencies already installed for this project");return}const e=path_1.default.join(t,"handler"),r=path_1.default.join(e,"package.json");try{this.fileSystem.existsSync(e)||this.fileSystem.mkdirSync(e,{recursive:!0}),await this.createPackageJson(r,s.dependencies),await this.installDependencies(e),this.installed=!0,internal_logger_1.__logger.info(`Installed ${Object.keys(s.dependencies).length} dependencies for project`)}catch(o){const n=o;throw internal_logger_1.__logger.error("Failed to install dependencies:",n.message),new Error(`Dependency installation failed: ${n.message}`)}}createIsolatedRequire(t,s,e){const r=path_1.default.resolve(t,"handler"),o=path_1.default.join(r,"node_modules"),n=new Map,i=l=>a=>{if(a.startsWith("./")||a.startsWith("../"))return this.getRelativePathRequire(a,l,r,e?{vmContext:e,makeRequire:i,cache:n}:void 0);if(a.includes("/"))return this.getGenericDependencyRequire(a,s,o);const c=this.validateAndGetModulePath(s,o,a);try{return this.tryLoadCommonJSAlternative(a,c)}catch(u){const h=u;throw new Error(`Failed to load module "${a}": ${h.message}`)}};return i(r)}async createPackageJson(t,s){const e={dependencies:{...s}},r=JSON.stringify(e,null,2);this.fileSystem.writeFileSync(t,r),internal_logger_1.__logger.debug("Created/updated package.json")}async installDependencies(t){try{(0,child_process_1.execSync)("npm install --ignore-scripts --no-audit --no-fund --loglevel=error",{cwd:t,stdio:"pipe",timeout:6e4}),internal_logger_1.__logger.debug("npm install completed successfully")}catch(s){const e=s;throw new Error(`npm install failed: ${e.message}`)}}tryLoadCommonJSAlternative(t,s){const e=require(s);if(e&&typeof e=="object"&&e.__esModule&&typeof e!="function"){internal_logger_1.__logger.debug(`ES module detected for ${t} (loaded but has named exports), looking for CommonJS alternative`);const r=path_1.default.join(s,"package.json");if(this.fileSystem.existsSync(r)){const o=JSON.parse(this.fileSystem.readFileSync(r,"utf8"));if(o.exports&&o.exports["."]){const n=o.exports["."];if(n.require){const i=path_1.default.resolve(s,n.require);return internal_logger_1.__logger.debug(`Trying CommonJS path: ${n.require}`),require(i)}if(n.default&&n.default.require){const i=path_1.default.resolve(s,n.default.require);return internal_logger_1.__logger.debug(`Trying default CommonJS path: ${n.default.require}`),require(i)}}if(o.main){const n=path_1.default.resolve(s,o.main);return internal_logger_1.__logger.debug(`Trying main field: ${o.main}`),require(n)}}return internal_logger_1.__logger.error(`No CommonJS alternative found for ${t}, using ES module as-is`),e}return e}getRelativePathRequire(t,s,e,r){const o=this.resolveRelativeUserModulePath(t,s,e);return r?this.runUserModuleInVm(o,r.vmContext,r.makeRequire,r.cache):require(o)}resolveRelativeUserModulePath(t,s,e){const r=path_1.default.resolve(s,t);this.assertPathInsideHandler(r,e);let o=r;if(this.fileSystem.existsSync(r)){if(this.fileSystem.statSync(r).isDirectory()){const n=path_1.default.join(r,"index.js");if(this.fileSystem.existsSync(n))o=n;else throw new Error(`File or module not found: ${t}`)}}else{const n=r+".js";if(this.fileSystem.existsSync(n))o=n;else throw new Error(`File or module not found: ${t}`)}return this.assertPathInsideHandler(o,e),this.assertCanonicalPathInsideHandler(o,e),o}assertPathInsideHandler(t,s){if(t!==s&&!t.startsWith(s+path_1.default.sep))throw new Error("Relative import path resolves outside of handler directory")}assertCanonicalPathInsideHandler(t,s){let e,r;try{e=this.fileSystem.realpathSync(t),r=this.fileSystem.realpathSync(s)}catch{throw new Error("Relative import path resolves outside of handler directory")}if(e!==r&&!e.startsWith(r+path_1.default.sep))throw new Error("Relative import path resolves outside of handler directory")}runUserModuleInVm(t,s,e,r){const o=r.get(t);if(o)return o.exports;const n={exports:{}};r.set(t,n);try{const l=`(function (exports, require, module, __filename, __dirname) {
${this.fileSystem.readFileSync(t,"utf8")}
})`,a=vm_1.default.runInContext(l,s,{filename:t,displayErrors:!0}),c=path_1.default.dirname(t),u=e(c);return a.call(n.exports,n.exports,u,n,t,c),n.exports}catch(i){throw r.delete(t),i}}getGenericDependencyRequire(t,s,e){const r=t.split("/")[0];if(!s.find(i=>i.name===r))throw new Error(`Module "${r}" is not allowed in this environment`);const n=path_1.default.join(e,t);if(!this.fileSystem.existsSync(n))throw new Error(`Module path "${t}" is not installed. Please ensure dependencies are installed.`);return internal_logger_1.__logger.debug(`Loading CommonJS path: ${t}`),require(path_1.default.resolve(n))}validateAndGetModulePath(t,s,e){const r=path_1.default.join(s,e);if(!this.fileSystem.existsSync(r))throw new Error(`Module "${e}" is not installed. Please ensure dependencies are installed.`);const o=t.find(n=>n.name===e);if(!o)throw new Error(`Module "${e}" is not allowed in this environment`);if(o.version)try{const n=path_1.default.join(r,"package.json"),l=JSON.parse(this.fileSystem.readFileSync(n,"utf8")).version;if(!semver_1.default.satisfies(l,o.version))throw new Error(`Module "${e}" version ${l} does not satisfy allowed version constraint ${o.version}`);internal_logger_1.__logger.debug(`Module "${e}" version ${l} satisfies constraint ${o.version}`)}catch(n){const i=n;internal_logger_1.__logger.warn(`Warning: Could not verify version for module "${e}":`,i.message)}else throw new Error(`Configuration error: Allowed module "${e}" does not have a version constraint`);return path_1.default.resolve(r)}}exports.DependencyManager=DependencyManager;

@@ -34,2 +34,4 @@ import fs, { Stats } from 'fs';

lstatSync: (path: string) => Stats;
/** Resolves all symbolic links and returns the canonical absolute path. */
realpathSync: (path: string) => string;
/** Renames a file or directory. */

@@ -63,2 +65,3 @@ renameSync: (oldPath: string, newPath: string) => void;

lstatSync(path: string): Stats;
realpathSync(path: string): string;
renameSync(oldPath: string, newPath: string): void;

@@ -65,0 +68,0 @@ cpSync(src: string, dest: string, options?: {

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

"use strict";var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.FileSystemService=void 0;const fs_1=__importDefault(require("fs"));class FileSystemService{existsSync(e){return fs_1.default.existsSync(e)}readdirSync(e,r){return fs_1.default.readdirSync(e,r)}mkdirSync(e,r){fs_1.default.mkdirSync(e,r)}unlinkSync(e){fs_1.default.unlinkSync(e)}rmdirSync(e){fs_1.default.rmdirSync(e)}statSync(e){return fs_1.default.statSync(e)}createWriteStream(e){return fs_1.default.createWriteStream(e)}readFileSync(e,r){return fs_1.default.readFileSync(e,r)}writeFileSync(e,r){fs_1.default.writeFileSync(e,r)}copyFileSync(e,r){fs_1.default.copyFileSync(e,r)}lstatSync(e){return fs_1.default.lstatSync(e)}renameSync(e,r){try{fs_1.default.renameSync(e,r)}catch(c){if(c.code==="EXDEV")try{fs_1.default.cpSync(e,r,{recursive:!0}),fs_1.default.rmSync(e,{recursive:!0,force:!0})}catch(u){try{fs_1.default.rmSync(r,{recursive:!0,force:!0})}catch{}throw u}else throw c}}cpSync(e,r,c){fs_1.default.cpSync(e,r,c)}}exports.FileSystemService=FileSystemService;
"use strict";var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.FileSystemService=void 0;const fs_1=__importDefault(require("fs"));class FileSystemService{existsSync(e){return fs_1.default.existsSync(e)}readdirSync(e,r){return fs_1.default.readdirSync(e,r)}mkdirSync(e,r){fs_1.default.mkdirSync(e,r)}unlinkSync(e){fs_1.default.unlinkSync(e)}rmdirSync(e){fs_1.default.rmdirSync(e)}statSync(e){return fs_1.default.statSync(e)}createWriteStream(e){return fs_1.default.createWriteStream(e)}readFileSync(e,r){return fs_1.default.readFileSync(e,r)}writeFileSync(e,r){fs_1.default.writeFileSync(e,r)}copyFileSync(e,r){fs_1.default.copyFileSync(e,r)}lstatSync(e){return fs_1.default.lstatSync(e)}realpathSync(e){return fs_1.default.realpathSync(e)}renameSync(e,r){try{fs_1.default.renameSync(e,r)}catch(c){if(c.code==="EXDEV")try{fs_1.default.cpSync(e,r,{recursive:!0}),fs_1.default.rmSync(e,{recursive:!0,force:!0})}catch(n){try{fs_1.default.rmSync(r,{recursive:!0,force:!0})}catch{}throw n}else throw c}}cpSync(e,r,c){fs_1.default.cpSync(e,r,c)}}exports.FileSystemService=FileSystemService;

@@ -56,5 +56,6 @@ import { ICBLogger } from '../logger/cb-logger';

* @param projectPath - Path to the user project
* @param vmContext - Optional shared VM context for relative user modules
* @returns A safe require function
*/
createSafeRequire(projectPath: string): (moduleName: string) => any;
createSafeRequire(projectPath: string, vmContext?: object): (moduleName: string) => any;
/**

@@ -61,0 +62,0 @@ * Creates a secure sandbox environment for code execution

{
"name": "@chargebee/chargebee-apps-shared",
"version": "1.0.0",
"version": "1.0.1",
"description": "Shared interfaces and utilities for Chargebee Apps CLI",

@@ -5,0 +5,0 @@ "main": "dist/index.js",