@chargebee/chargebee-apps-shared
Advanced tools
@@ -1,150 +0,1 @@ | ||
| "use strict"; | ||
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| var desc = Object.getOwnPropertyDescriptor(m, k); | ||
| if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
| desc = { enumerable: true, get: function() { return m[k]; } }; | ||
| } | ||
| Object.defineProperty(o, k2, desc); | ||
| }) : (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| o[k2] = m[k]; | ||
| })); | ||
| var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
| Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
| }) : function(o, v) { | ||
| o["default"] = v; | ||
| }); | ||
| var __importStar = (this && this.__importStar) || (function () { | ||
| var ownKeys = function(o) { | ||
| ownKeys = Object.getOwnPropertyNames || function (o) { | ||
| var ar = []; | ||
| for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; | ||
| return ar; | ||
| }; | ||
| return ownKeys(o); | ||
| }; | ||
| return function (mod) { | ||
| if (mod && mod.__esModule) return mod; | ||
| var result = {}; | ||
| if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); | ||
| __setModuleDefault(result, mod); | ||
| return result; | ||
| }; | ||
| })(); | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.EnvironmentConfig = exports.EnvironmentType = void 0; | ||
| const path_1 = __importDefault(require("path")); | ||
| const fs = __importStar(require("fs")); | ||
| /** | ||
| * Environment type enum | ||
| */ | ||
| var EnvironmentType; | ||
| (function (EnvironmentType) { | ||
| EnvironmentType["DEVELOPMENT"] = "development"; | ||
| EnvironmentType["PRODUCTION"] = "production"; | ||
| })(EnvironmentType || (exports.EnvironmentType = EnvironmentType = {})); | ||
| /** | ||
| * Environment configuration class that detects the current environment | ||
| * @class EnvironmentConfig | ||
| * @implements {IEnvironmentConfig} | ||
| * | ||
| * @description | ||
| * This class provides environment detection based on multiple indicators: | ||
| * 1. NODE_ENV environment variable | ||
| * 2. Presence of workspace structure (workspaces field in package.json) | ||
| * 3. Module resolution capability (can resolve published packages) | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const envConfig = new EnvironmentConfig(); | ||
| * if (envConfig.isDevelopment()) { | ||
| * console.log('Running in development mode'); | ||
| * } | ||
| * ``` | ||
| */ | ||
| class EnvironmentConfig { | ||
| constructor() { | ||
| this.environment = this.detectEnvironment(); | ||
| } | ||
| /** | ||
| * Detects the current environment based on various indicators | ||
| * @returns {EnvironmentType} The detected environment type | ||
| * @private | ||
| */ | ||
| detectEnvironment() { | ||
| // Check NODE_ENV first | ||
| const nodeEnv = process.env['NODE_ENV']?.toLowerCase(); | ||
| if (nodeEnv === 'production') { | ||
| return EnvironmentType.PRODUCTION; | ||
| } | ||
| if (nodeEnv === 'development') { | ||
| return EnvironmentType.DEVELOPMENT; | ||
| } | ||
| // If NODE_ENV is not set, detect based on workspace structure | ||
| // In development, we should be in a monorepo with workspaces | ||
| // In production, packages are published and installed independently | ||
| try { | ||
| const currentDir = __dirname; | ||
| const projectRoot = this.findProjectRoot(currentDir); | ||
| if (projectRoot) { | ||
| const packageJsonPath = path_1.default.join(projectRoot, 'package.json'); | ||
| if (fs.existsSync(packageJsonPath)) { | ||
| const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); | ||
| // If workspaces field exists, we're in development | ||
| if (packageJson.workspaces) { | ||
| return EnvironmentType.DEVELOPMENT; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| catch (error) { | ||
| // If we can't find workspace structure, assume production | ||
| } | ||
| // Default to production if we can't determine | ||
| return EnvironmentType.PRODUCTION; | ||
| } | ||
| /** | ||
| * Finds the project root by traversing up the directory tree | ||
| * @param {string} startDir - Directory to start searching from | ||
| * @returns {string | null} Path to project root or null if not found | ||
| * @private | ||
| */ | ||
| findProjectRoot(startDir) { | ||
| let currentDir = startDir; | ||
| const root = path_1.default.parse(currentDir).root; | ||
| while (currentDir !== root) { | ||
| const packageJsonPath = path_1.default.join(currentDir, 'package.json'); | ||
| if (fs.existsSync(packageJsonPath)) { | ||
| return currentDir; | ||
| } | ||
| currentDir = path_1.default.dirname(currentDir); | ||
| } | ||
| return null; | ||
| } | ||
| /** | ||
| * Gets the current environment type | ||
| * @returns {EnvironmentType} The current environment | ||
| */ | ||
| getEnvironment() { | ||
| return this.environment; | ||
| } | ||
| /** | ||
| * Checks if running in development mode | ||
| * @returns {boolean} True if in development mode | ||
| */ | ||
| isDevelopment() { | ||
| return this.environment === EnvironmentType.DEVELOPMENT; | ||
| } | ||
| /** | ||
| * Checks if running in production mode | ||
| * @returns {boolean} True if in production mode | ||
| */ | ||
| isProduction() { | ||
| return this.environment === EnvironmentType.PRODUCTION; | ||
| } | ||
| } | ||
| exports.EnvironmentConfig = EnvironmentConfig; | ||
| "use strict";var __createBinding=this&&this.__createBinding||(Object.create?(function(n,e,t,r){r===void 0&&(r=t);var o=Object.getOwnPropertyDescriptor(e,t);(!o||("get"in o?!e.__esModule:o.writable||o.configurable))&&(o={enumerable:!0,get:function(){return e[t]}}),Object.defineProperty(n,r,o)}):(function(n,e,t,r){r===void 0&&(r=t),n[r]=e[t]})),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?(function(n,e){Object.defineProperty(n,"default",{enumerable:!0,value:e})}):function(n,e){n.default=e}),__importStar=this&&this.__importStar||(function(){var n=function(e){return n=Object.getOwnPropertyNames||function(t){var r=[];for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&(r[r.length]=o);return r},n(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=n(e),o=0;o<r.length;o++)r[o]!=="default"&&__createBinding(t,e,r[o]);return __setModuleDefault(t,e),t}})(),__importDefault=this&&this.__importDefault||function(n){return n&&n.__esModule?n:{default:n}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.EnvironmentConfig=exports.EnvironmentType=void 0;const path_1=__importDefault(require("path")),fs=__importStar(require("fs"));var EnvironmentType;(function(n){n.DEVELOPMENT="development",n.PRODUCTION="production"})(EnvironmentType||(exports.EnvironmentType=EnvironmentType={}));class EnvironmentConfig{constructor(){this.environment=this.detectEnvironment()}detectEnvironment(){const e=process.env.NODE_ENV?.toLowerCase();if(e==="production")return EnvironmentType.PRODUCTION;if(e==="development")return EnvironmentType.DEVELOPMENT;try{const t=__dirname,r=this.findProjectRoot(t);if(r){const o=path_1.default.join(r,"package.json");if(fs.existsSync(o)&&JSON.parse(fs.readFileSync(o,"utf8")).workspaces)return EnvironmentType.DEVELOPMENT}}catch{}return EnvironmentType.PRODUCTION}findProjectRoot(e){let t=e;const r=path_1.default.parse(t).root;for(;t!==r;){const o=path_1.default.join(t,"package.json");if(fs.existsSync(o))return t;t=path_1.default.dirname(t)}return null}getEnvironment(){return this.environment}isDevelopment(){return this.environment===EnvironmentType.DEVELOPMENT}isProduction(){return this.environment===EnvironmentType.PRODUCTION}}exports.EnvironmentConfig=EnvironmentConfig; |
@@ -1,247 +0,1 @@ | ||
| "use strict"; | ||
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| var desc = Object.getOwnPropertyDescriptor(m, k); | ||
| if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
| desc = { enumerable: true, get: function() { return m[k]; } }; | ||
| } | ||
| Object.defineProperty(o, k2, desc); | ||
| }) : (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| o[k2] = m[k]; | ||
| })); | ||
| var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
| Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
| }) : function(o, v) { | ||
| o["default"] = v; | ||
| }); | ||
| var __importStar = (this && this.__importStar) || (function () { | ||
| var ownKeys = function(o) { | ||
| ownKeys = Object.getOwnPropertyNames || function (o) { | ||
| var ar = []; | ||
| for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; | ||
| return ar; | ||
| }; | ||
| return ownKeys(o); | ||
| }; | ||
| return function (mod) { | ||
| if (mod && mod.__esModule) return mod; | ||
| var result = {}; | ||
| if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); | ||
| __setModuleDefault(result, mod); | ||
| return result; | ||
| }; | ||
| })(); | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.PathResolver = exports.PathType = void 0; | ||
| const path_1 = __importDefault(require("path")); | ||
| const fs = __importStar(require("fs")); | ||
| const environment_1 = require("./environment"); | ||
| /** | ||
| * Path type enum for different package paths | ||
| */ | ||
| var PathType; | ||
| (function (PathType) { | ||
| /** Root directory of the CLI workspace */ | ||
| PathType["CLI_ROOT"] = "CLI_ROOT"; | ||
| /** Private application distribution directory */ | ||
| PathType["PRIVATE_APP_DIST"] = "PRIVATE_APP_DIST"; | ||
| /** Private application root directory */ | ||
| PathType["PRIVATE_APP_ROOT"] = "PRIVATE_APP_ROOT"; | ||
| /** Public libs templates directory */ | ||
| PathType["PUBLIC_LIBS_TEMPLATES"] = "PUBLIC_LIBS_TEMPLATES"; | ||
| /** Public libs UI web directory */ | ||
| PathType["PUBLIC_LIBS_UI_WEB"] = "PUBLIC_LIBS_UI_WEB"; | ||
| })(PathType || (exports.PathType = PathType = {})); | ||
| /** | ||
| * Path resolver class for resolving paths based on environment | ||
| * @class PathResolver | ||
| * @implements {IPathResolver} | ||
| * | ||
| * @description | ||
| * This class provides centralized path resolution for all packages in the CLI. | ||
| * It detects the environment (development vs production) and resolves paths accordingly: | ||
| * - In development: Uses workspace-relative paths | ||
| * - In production: Uses require.resolve to find installed packages | ||
| * | ||
| * This eliminates the need for try-catch error handling scattered across the codebase. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const pathResolver = new PathResolver(); | ||
| * const templatesDir = pathResolver.getPublicLibsTemplatesDir(); | ||
| * console.log(`Templates directory: ${templatesDir}`); | ||
| * ``` | ||
| */ | ||
| class PathResolver { | ||
| constructor(envConfig) { | ||
| this.cliRoot = null; | ||
| this.envConfig = envConfig || new environment_1.EnvironmentConfig(); | ||
| } | ||
| /** | ||
| * Resolves a path based on the path type and environment | ||
| * @param {PathType} pathType - Type of path to resolve | ||
| * @returns {string} Resolved path | ||
| * @throws {Error} If path cannot be resolved | ||
| */ | ||
| resolvePath(pathType) { | ||
| switch (pathType) { | ||
| case PathType.CLI_ROOT: | ||
| return this.getCliRoot(); | ||
| case PathType.PRIVATE_APP_DIST: | ||
| return this.getPrivateAppDistDir(); | ||
| case PathType.PRIVATE_APP_ROOT: | ||
| return this.getPrivateAppRootDir(); | ||
| case PathType.PUBLIC_LIBS_TEMPLATES: | ||
| return this.getPublicLibsTemplatesDir(); | ||
| case PathType.PUBLIC_LIBS_UI_WEB: | ||
| return this.getPublicLibsUiWebDir(); | ||
| default: | ||
| throw new Error(`Unknown path type: ${pathType}`); | ||
| } | ||
| } | ||
| /** | ||
| * Gets the CLI workspace root path | ||
| * @returns {string} Path to CLI workspace root | ||
| */ | ||
| getCliRoot() { | ||
| if (this.cliRoot) { | ||
| return this.cliRoot; | ||
| } | ||
| if (this.envConfig.isDevelopment()) { | ||
| // Development: Find the project root by looking for package.json with workspaces | ||
| this.cliRoot = this.findProjectRootWithWorkspaces(__dirname); | ||
| } | ||
| else { | ||
| // Production: Use the package installation directory | ||
| // In production, packages are installed via npm and there's no workspace structure | ||
| this.cliRoot = path_1.default.resolve(__dirname, '../..'); | ||
| } | ||
| return this.cliRoot; | ||
| } | ||
| /** | ||
| * Gets the private application distribution directory path | ||
| * @returns {string} Path to private application dist directory | ||
| */ | ||
| getPrivateAppDistDir() { | ||
| if (this.envConfig.isDevelopment()) { | ||
| // Development: Use workspace path | ||
| const cliRoot = this.getCliRoot(); | ||
| return path_1.default.join(cliRoot, 'packages', 'private-application', 'dist'); | ||
| } | ||
| else { | ||
| // Production: Find the installed package | ||
| try { | ||
| const resolvedPath = require.resolve('@chargebee-private/chargebee-apps-private-application'); | ||
| return path_1.default.dirname(resolvedPath); | ||
| } | ||
| catch (error) { | ||
| throw new Error('Failed to resolve private-application path. ' + | ||
| 'Ensure @chargebee-private/chargebee-apps-private-application is installed.'); | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * Gets the private application root directory path | ||
| * @returns {string} Path to private application root directory | ||
| */ | ||
| getPrivateAppRootDir() { | ||
| if (this.envConfig.isDevelopment()) { | ||
| // Development: Use workspace path | ||
| const cliRoot = this.getCliRoot(); | ||
| return path_1.default.join(cliRoot, 'packages', 'private-application'); | ||
| } | ||
| else { | ||
| // Production: Find the installed package root | ||
| try { | ||
| const packageJsonPath = require.resolve('@chargebee-private/chargebee-apps-private-application/package.json'); | ||
| return path_1.default.dirname(packageJsonPath); | ||
| } | ||
| catch (error) { | ||
| throw new Error('Failed to resolve private-application root path. ' + | ||
| 'Ensure @chargebee-private/chargebee-apps-private-application is installed.'); | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * Gets the public libs templates directory path | ||
| * @returns {string} Path to public libs templates directory | ||
| */ | ||
| getPublicLibsTemplatesDir() { | ||
| if (this.envConfig.isDevelopment()) { | ||
| // Development: Use workspace path | ||
| const cliRoot = this.getCliRoot(); | ||
| return path_1.default.join(cliRoot, 'packages', 'public-libs', 'templates'); | ||
| } | ||
| else { | ||
| // Production: Find the installed package and get templates from package root | ||
| try { | ||
| const publicLibsPath = require.resolve('@chargebee/chargebee-apps-libs'); | ||
| const packageRoot = path_1.default.dirname(path_1.default.dirname(publicLibsPath)); | ||
| return path_1.default.join(packageRoot, 'templates'); | ||
| } | ||
| catch (error) { | ||
| throw new Error('Failed to resolve public-libs templates path. ' + | ||
| 'Ensure @chargebee/chargebee-apps-libs is installed.'); | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * Gets the public libs UI web directory path | ||
| * @returns {string} Path to public libs UI web directory | ||
| */ | ||
| getPublicLibsUiWebDir() { | ||
| if (this.envConfig.isDevelopment()) { | ||
| // Development: Use workspace path | ||
| const cliRoot = this.getCliRoot(); | ||
| return path_1.default.join(cliRoot, 'packages', 'public-libs', 'ui', 'web'); | ||
| } | ||
| else { | ||
| // Production: Find the installed package and get UI from package root | ||
| try { | ||
| const publicLibsPath = require.resolve('@chargebee/chargebee-apps-libs'); | ||
| const packageRoot = path_1.default.dirname(path_1.default.dirname(publicLibsPath)); | ||
| return path_1.default.join(packageRoot, 'ui', 'web'); | ||
| } | ||
| catch (error) { | ||
| throw new Error('Failed to resolve public-libs UI web path. ' + | ||
| 'Ensure @chargebee/chargebee-apps-libs is installed.'); | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * Finds the project root by looking for package.json with workspaces | ||
| * @param {string} startDir - Directory to start searching from | ||
| * @returns {string} Path to project root | ||
| * @throws {Error} If project root cannot be found | ||
| * @private | ||
| */ | ||
| findProjectRootWithWorkspaces(startDir) { | ||
| let currentDir = startDir; | ||
| const root = path_1.default.parse(currentDir).root; | ||
| while (currentDir !== root) { | ||
| const packageJsonPath = path_1.default.join(currentDir, 'package.json'); | ||
| if (fs.existsSync(packageJsonPath)) { | ||
| try { | ||
| const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); | ||
| if (packageJson.workspaces) { | ||
| return currentDir; | ||
| } | ||
| } | ||
| catch (error) { | ||
| // Continue searching if package.json is invalid | ||
| } | ||
| } | ||
| const parent = path_1.default.dirname(currentDir); | ||
| if (parent === currentDir) { | ||
| break; | ||
| } | ||
| currentDir = parent; | ||
| } | ||
| throw new Error('Could not find project root with workspaces'); | ||
| } | ||
| } | ||
| exports.PathResolver = PathResolver; | ||
| "use strict";var __createBinding=this&&this.__createBinding||(Object.create?(function(r,e,t,i){i===void 0&&(i=t);var a=Object.getOwnPropertyDescriptor(e,t);(!a||("get"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[t]}}),Object.defineProperty(r,i,a)}):(function(r,e,t,i){i===void 0&&(i=t),r[i]=e[t]})),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?(function(r,e){Object.defineProperty(r,"default",{enumerable:!0,value:e})}):function(r,e){r.default=e}),__importStar=this&&this.__importStar||(function(){var r=function(e){return r=Object.getOwnPropertyNames||function(t){var i=[];for(var a in t)Object.prototype.hasOwnProperty.call(t,a)&&(i[i.length]=a);return i},r(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var i=r(e),a=0;a<i.length;a++)i[a]!=="default"&&__createBinding(t,e,i[a]);return __setModuleDefault(t,e),t}})(),__importDefault=this&&this.__importDefault||function(r){return r&&r.__esModule?r:{default:r}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.PathResolver=exports.PathType=void 0;const path_1=__importDefault(require("path")),fs=__importStar(require("fs")),environment_1=require("./environment");var PathType;(function(r){r.CLI_ROOT="CLI_ROOT",r.PRIVATE_APP_DIST="PRIVATE_APP_DIST",r.PRIVATE_APP_ROOT="PRIVATE_APP_ROOT",r.PUBLIC_LIBS_TEMPLATES="PUBLIC_LIBS_TEMPLATES",r.PUBLIC_LIBS_UI_WEB="PUBLIC_LIBS_UI_WEB"})(PathType||(exports.PathType=PathType={}));class PathResolver{constructor(e){this.cliRoot=null,this.envConfig=e||new environment_1.EnvironmentConfig}resolvePath(e){switch(e){case PathType.CLI_ROOT:return this.getCliRoot();case PathType.PRIVATE_APP_DIST:return this.getPrivateAppDistDir();case PathType.PRIVATE_APP_ROOT:return this.getPrivateAppRootDir();case PathType.PUBLIC_LIBS_TEMPLATES:return this.getPublicLibsTemplatesDir();case PathType.PUBLIC_LIBS_UI_WEB:return this.getPublicLibsUiWebDir();default:throw new Error(`Unknown path type: ${e}`)}}getCliRoot(){return this.cliRoot?this.cliRoot:(this.envConfig.isDevelopment()?this.cliRoot=this.findProjectRootWithWorkspaces(__dirname):this.cliRoot=path_1.default.resolve(__dirname,"../.."),this.cliRoot)}getPrivateAppDistDir(){if(this.envConfig.isDevelopment()){const e=this.getCliRoot();return path_1.default.join(e,"packages","private-application","dist")}else try{const e=require.resolve("@chargebee-private/chargebee-apps-private-application");return path_1.default.dirname(e)}catch{throw new Error("Failed to resolve private-application path. Ensure @chargebee-private/chargebee-apps-private-application is installed.")}}getPrivateAppRootDir(){if(this.envConfig.isDevelopment()){const e=this.getCliRoot();return path_1.default.join(e,"packages","private-application")}else try{const e=require.resolve("@chargebee-private/chargebee-apps-private-application/package.json");return path_1.default.dirname(e)}catch{throw new Error("Failed to resolve private-application root path. Ensure @chargebee-private/chargebee-apps-private-application is installed.")}}getPublicLibsTemplatesDir(){if(this.envConfig.isDevelopment()){const e=this.getCliRoot();return path_1.default.join(e,"packages","public-libs","templates")}else try{const e=require.resolve("@chargebee/chargebee-apps-libs"),t=path_1.default.dirname(path_1.default.dirname(e));return path_1.default.join(t,"templates")}catch{throw new Error("Failed to resolve public-libs templates path. Ensure @chargebee/chargebee-apps-libs is installed.")}}getPublicLibsUiWebDir(){if(this.envConfig.isDevelopment()){const e=this.getCliRoot();return path_1.default.join(e,"packages","public-libs","ui","web")}else try{const e=require.resolve("@chargebee/chargebee-apps-libs"),t=path_1.default.dirname(path_1.default.dirname(e));return path_1.default.join(t,"ui","web")}catch{throw new Error("Failed to resolve public-libs UI web path. Ensure @chargebee/chargebee-apps-libs is installed.")}}findProjectRootWithWorkspaces(e){let t=e;const i=path_1.default.parse(t).root;for(;t!==i;){const a=path_1.default.join(t,"package.json");if(fs.existsSync(a))try{if(JSON.parse(fs.readFileSync(a,"utf8")).workspaces)return t}catch{}const o=path_1.default.dirname(t);if(o===t)break;t=o}throw new Error("Could not find project root with workspaces")}}exports.PathResolver=PathResolver; |
@@ -1,257 +0,1 @@ | ||
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.DependencyManager = void 0; | ||
| const child_process_1 = require("child_process"); | ||
| const path_1 = __importDefault(require("path")); | ||
| const semver_1 = __importDefault(require("semver")); | ||
| const internal_logger_1 = require("../logger/internal-logger"); | ||
| /** | ||
| * DependencyManager handles isolated npm installations for user projects | ||
| * Public implementation for managing dependencies in development environment | ||
| */ | ||
| class DependencyManager { | ||
| constructor(fileSystem) { | ||
| this.fileSystem = fileSystem; | ||
| this.installed = false; | ||
| } | ||
| /** | ||
| * Ensures dependencies are installed for a user project | ||
| * @param {string} projectPath - Path to the user project directory | ||
| * @param {Manifest} manifest - The project manifest containing dependencies | ||
| * @returns {Promise<void>} | ||
| */ | ||
| async ensureDependencies(projectPath, manifest) { | ||
| if (!manifest.dependencies || Object.keys(manifest.dependencies).length === 0) { | ||
| internal_logger_1.__logger.debug('No dependencies to install'); | ||
| return; | ||
| } | ||
| // Check if already installed | ||
| if (this.installed) { | ||
| internal_logger_1.__logger.debug('Dependencies already installed for this project'); | ||
| return; | ||
| } | ||
| const handlerPath = path_1.default.join(projectPath, 'handler'); | ||
| const packageJsonPath = path_1.default.join(handlerPath, 'package.json'); | ||
| try { | ||
| // Create handler directory if it doesn't exist | ||
| if (!this.fileSystem.existsSync(handlerPath)) { | ||
| this.fileSystem.mkdirSync(handlerPath, { recursive: true }); | ||
| } | ||
| // Create or update package.json | ||
| await this.createPackageJson(packageJsonPath, manifest.dependencies); | ||
| // Install dependencies | ||
| await this.installDependencies(handlerPath); | ||
| // Mark as installed | ||
| this.installed = true; | ||
| internal_logger_1.__logger.info(`Installed ${Object.keys(manifest.dependencies).length} dependencies for project`); | ||
| } | ||
| catch (error) { | ||
| const err = error; | ||
| internal_logger_1.__logger.error('Failed to install dependencies:', err.message); | ||
| throw new Error(`Dependency installation failed: ${err.message}`); | ||
| } | ||
| } | ||
| /** | ||
| * Creates a safe require function that uses isolated node_modules | ||
| * @param {string} projectPath - Path to the user project | ||
| * @param {AllowedModule[]} allowedModules - List of allowed modules | ||
| * @returns {Function} Safe require function | ||
| */ | ||
| createIsolatedRequire(projectPath, allowedModules) { | ||
| const handlerPath = path_1.default.resolve(projectPath, 'handler'); | ||
| const nodeModulesPath = path_1.default.join(handlerPath, 'node_modules'); | ||
| return (moduleName) => { | ||
| // Check if the module is a relative path | ||
| if (moduleName.startsWith('./')) { | ||
| // Normalize the path to prevent path traversal attacks | ||
| return this.getRelativePathRequire(moduleName, handlerPath); | ||
| } | ||
| // Handle direct CommonJS paths (e.g., 'axios/dist/node/axios.cjs') | ||
| if (moduleName.includes('/')) { | ||
| // Extract the base module name | ||
| return this.getGenericDependencyRequire(moduleName, allowedModules, nodeModulesPath); | ||
| } | ||
| // Verify version if constraint is specified | ||
| const resolvedModulePath = this.validateAndGetModulePath(allowedModules, nodeModulesPath, moduleName); | ||
| try { | ||
| // Check if this is an ES module that loaded but doesn't have the expected interface | ||
| // This happens when ES modules export named exports instead of a default function | ||
| // Try to load the module and handle ES module issues with cjs (if available) else fallback to the ES module | ||
| return this.tryLoadCommonJSAlternative(moduleName, resolvedModulePath); | ||
| } | ||
| catch (error) { | ||
| const err = error; | ||
| throw new Error(`Failed to load module "${moduleName}": ${err.message}`); | ||
| } | ||
| }; | ||
| } | ||
| /** | ||
| * Creates or updates package.json for the project | ||
| * @param {string} packageJsonPath - Path to package.json | ||
| * @param {Record<string, string>} dependencies - Dependencies from manifest | ||
| */ | ||
| async createPackageJson(packageJsonPath, dependencies) { | ||
| const packageJson = { | ||
| dependencies: { ...dependencies } | ||
| }; | ||
| const content = JSON.stringify(packageJson, null, 2); | ||
| this.fileSystem.writeFileSync(packageJsonPath, content); | ||
| internal_logger_1.__logger.debug('Created/updated package.json'); | ||
| } | ||
| /** | ||
| * Installs dependencies using npm | ||
| * @param {string} handlerPath - Path to the handler directory | ||
| */ | ||
| async installDependencies(handlerPath) { | ||
| try { | ||
| (0, child_process_1.execSync)('npm install --ignore-scripts --no-audit --no-fund --loglevel=error', { | ||
| cwd: handlerPath, | ||
| stdio: 'pipe', | ||
| timeout: 60000 // 60 second timeout | ||
| }); | ||
| internal_logger_1.__logger.debug('npm install completed successfully'); | ||
| } | ||
| catch (error) { | ||
| const err = error; | ||
| throw new Error(`npm install failed: ${err.message}`); | ||
| } | ||
| } | ||
| /** | ||
| * Tries to load a CommonJS alternative for an ES module. This is a fallback for when the common JS is not the default export. | ||
| * @param moduleName - Name of the module to require | ||
| * @param resolvedModulePath - Path to the resolved module | ||
| * @returns | ||
| */ | ||
| tryLoadCommonJSAlternative(moduleName, resolvedModulePath) { | ||
| const module = require(resolvedModulePath); | ||
| if (module && typeof module === 'object' && module.__esModule && typeof module !== 'function') { | ||
| internal_logger_1.__logger.debug(`ES module detected for ${moduleName} (loaded but has named exports), looking for CommonJS alternative`); | ||
| const packageJsonPath = path_1.default.join(resolvedModulePath, 'package.json'); | ||
| if (this.fileSystem.existsSync(packageJsonPath)) { | ||
| const packageJson = JSON.parse(this.fileSystem.readFileSync(packageJsonPath, 'utf8')); | ||
| // Try to find CommonJS export from package.json exports | ||
| if (packageJson.exports && packageJson.exports['.']) { | ||
| const exports = packageJson.exports['.']; | ||
| // Try direct require field | ||
| if (exports.require) { | ||
| const cjsPath = path_1.default.resolve(resolvedModulePath, exports.require); | ||
| internal_logger_1.__logger.debug(`Trying CommonJS path: ${exports.require}`); | ||
| return require(cjsPath); | ||
| } | ||
| // Try nested default.require (like axios) | ||
| if (exports.default && exports.default.require) { | ||
| const cjsPath = path_1.default.resolve(resolvedModulePath, exports.default.require); | ||
| internal_logger_1.__logger.debug(`Trying default CommonJS path: ${exports.default.require}`); | ||
| return require(cjsPath); | ||
| } | ||
| } | ||
| // Try to find CommonJS entry point from main field | ||
| if (packageJson.main) { | ||
| const mainPath = path_1.default.resolve(resolvedModulePath, packageJson.main); | ||
| internal_logger_1.__logger.debug(`Trying main field: ${packageJson.main}`); | ||
| return require(mainPath); | ||
| } | ||
| } | ||
| // If we can't find a CommonJS alternative, return the ES module as-is | ||
| internal_logger_1.__logger.error(`No CommonJS alternative found for ${moduleName}, using ES module as-is`); | ||
| return module; | ||
| } | ||
| return module; | ||
| } | ||
| /** | ||
| * Gets the relative path require. | ||
| * @param moduleName - Name of the module to require | ||
| * @param handlerPath - Path to the handler directory | ||
| * @returns | ||
| */ | ||
| getRelativePathRequire(moduleName, handlerPath) { | ||
| const normalizedPath = path_1.default.normalize(moduleName); | ||
| // Check for any path traversal attempts after normalization | ||
| if (normalizedPath.includes('..')) { | ||
| throw new Error('Path traversal not allowed in relative imports'); | ||
| } | ||
| // Resolve the path relative to handlerPath | ||
| const resolvedPath = path_1.default.resolve(handlerPath, normalizedPath); | ||
| // Validate that the resolved path is within the handlerPath directory | ||
| if (!resolvedPath.startsWith(handlerPath)) { | ||
| throw new Error('Relative import path resolves outside of handler directory'); | ||
| } | ||
| // Check if the file exists and determine the correct path to require | ||
| let finalPath = resolvedPath; | ||
| if (!this.fileSystem.existsSync(resolvedPath)) { | ||
| const jsPath = resolvedPath + ".js"; | ||
| if (this.fileSystem.existsSync(jsPath)) { | ||
| finalPath = jsPath; // Use the .js path that actually exists | ||
| } | ||
| else { | ||
| throw new Error(`File or module not found: ${moduleName}`); | ||
| } | ||
| } | ||
| return require(finalPath); | ||
| } | ||
| /** | ||
| * Gets the generic dependency require. Unless there are special cases like ES modules, this should work for all dependencies. | ||
| * @param moduleName - Name of the module to require | ||
| * @param allowedModules - List of allowed modules | ||
| * @param nodeModulesPath - Path to the node_modules directory | ||
| * @returns | ||
| */ | ||
| getGenericDependencyRequire(moduleName, allowedModules, nodeModulesPath) { | ||
| const baseModuleName = moduleName.split('/')[0]; | ||
| // Check if the base module is allowed | ||
| const allowedModule = allowedModules.find(module => module.name === baseModuleName); | ||
| if (!allowedModule) { | ||
| throw new Error(`Module "${baseModuleName}" is not allowed in this environment`); | ||
| } | ||
| // Check if the full path exists in project's node_modules | ||
| const fullModulePath = path_1.default.join(nodeModulesPath, moduleName); | ||
| if (!this.fileSystem.existsSync(fullModulePath)) { | ||
| throw new Error(`Module path "${moduleName}" is not installed. Please ensure dependencies are installed.`); | ||
| } | ||
| internal_logger_1.__logger.debug(`Loading CommonJS path: ${moduleName}`); | ||
| return require(path_1.default.resolve(fullModulePath)); | ||
| } | ||
| /** | ||
| * Validates and gets the resolved path to the module. | ||
| * @param allowedModules - List of allowed modules | ||
| * @param nodeModulesPath - Path to the node_modules directory | ||
| * @param moduleName - Name of the module to validate | ||
| * @returns Path to the module | ||
| */ | ||
| validateAndGetModulePath(allowedModules, nodeModulesPath, moduleName) { | ||
| // Check if module is installed in project's node_modules | ||
| const modulePath = path_1.default.join(nodeModulesPath, moduleName); | ||
| if (!this.fileSystem.existsSync(modulePath)) { | ||
| throw new Error(`Module "${moduleName}" is not installed. Please ensure dependencies are installed.`); | ||
| } | ||
| // Check if module is allowed | ||
| const allowedModule = allowedModules.find(module => module.name === moduleName); | ||
| if (!allowedModule) { | ||
| throw new Error(`Module "${moduleName}" is not allowed in this environment`); | ||
| } | ||
| if (allowedModule.version) { | ||
| try { | ||
| const packageJsonPath = path_1.default.join(modulePath, 'package.json'); | ||
| const packageJson = JSON.parse(this.fileSystem.readFileSync(packageJsonPath, 'utf8')); | ||
| const installedVersion = packageJson.version; | ||
| if (!semver_1.default.satisfies(installedVersion, allowedModule.version)) { | ||
| throw new Error(`Module "${moduleName}" version ${installedVersion} does not satisfy allowed version constraint ${allowedModule.version}`); | ||
| } | ||
| internal_logger_1.__logger.debug(`Module "${moduleName}" version ${installedVersion} satisfies constraint ${allowedModule.version}`); | ||
| } | ||
| catch (error) { | ||
| const err = error; | ||
| internal_logger_1.__logger.warn(`Warning: Could not verify version for module "${moduleName}":`, err.message); | ||
| } | ||
| } | ||
| else { | ||
| throw new Error(`Configuration error: Allowed module "${moduleName}" does not have a version constraint`); | ||
| } | ||
| // Fallback to the module path, might or might not work for some dependencies. | ||
| return path_1.default.resolve(modulePath); | ||
| } | ||
| } | ||
| exports.DependencyManager = DependencyManager; | ||
| "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; |
+1
-17
@@ -1,17 +0,1 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.MissingRequiredParamsError = void 0; | ||
| /** | ||
| * Error thrown when required installation parameters are missing. | ||
| * Carries the list of missing parameter names for API responses. | ||
| */ | ||
| class MissingRequiredParamsError extends Error { | ||
| constructor(missing) { | ||
| const params = missing.join(', '); | ||
| super(`Missing required parameter${missing.length > 1 ? 's' : ''}: ${params}`); | ||
| this.name = 'MissingRequiredParamsError'; | ||
| this.missing = missing; | ||
| Object.setPrototypeOf(this, MissingRequiredParamsError.prototype); | ||
| } | ||
| } | ||
| exports.MissingRequiredParamsError = MissingRequiredParamsError; | ||
| "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.MissingRequiredParamsError=void 0;class MissingRequiredParamsError extends Error{constructor(r){const e=r.join(", ");super(`Missing required parameter${r.length>1?"s":""}: ${e}`),this.name="MissingRequiredParamsError",this.missing=r,Object.setPrototypeOf(this,MissingRequiredParamsError.prototype)}}exports.MissingRequiredParamsError=MissingRequiredParamsError; |
+1
-36
@@ -1,36 +0,1 @@ | ||
| "use strict"; | ||
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| var desc = Object.getOwnPropertyDescriptor(m, k); | ||
| if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
| desc = { enumerable: true, get: function() { return m[k]; } }; | ||
| } | ||
| Object.defineProperty(o, k2, desc); | ||
| }) : (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| o[k2] = m[k]; | ||
| })); | ||
| var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
| for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| // Export all shared interfaces and types | ||
| __exportStar(require("./config/environment"), exports); | ||
| __exportStar(require("./errors"), exports); | ||
| __exportStar(require("./config/path-resolver"), exports); | ||
| __exportStar(require("./dependency/dependency-manager"), exports); | ||
| __exportStar(require("./libs/archive-service"), exports); | ||
| __exportStar(require("./libs/file-management-service"), exports); | ||
| __exportStar(require("./libs/iparams-service"), exports); | ||
| __exportStar(require("./libs/template-service"), exports); | ||
| __exportStar(require("./logger/cb-logger"), exports); | ||
| __exportStar(require("./logger/internal-logger"), exports); | ||
| __exportStar(require("./node/file-system"), exports); | ||
| __exportStar(require("./node/process"), exports); | ||
| __exportStar(require("./sandbox/sandbox-context"), exports); | ||
| __exportStar(require("./sandbox/sandbox-wrapper"), exports); | ||
| __exportStar(require("./types/common"), exports); | ||
| __exportStar(require("./validator/manifest-validator"), exports); | ||
| __exportStar(require("./validator/package-validator"), exports); | ||
| __exportStar(require("./validator/iparams-inputs-validator"), exports); | ||
| __exportStar(require("./validator/iparam-defns-validator"), exports); | ||
| "use strict";var __createBinding=this&&this.__createBinding||(Object.create?(function(i,r,e,t){t===void 0&&(t=e);var o=Object.getOwnPropertyDescriptor(r,e);(!o||("get"in o?!r.__esModule:o.writable||o.configurable))&&(o={enumerable:!0,get:function(){return r[e]}}),Object.defineProperty(i,t,o)}):(function(i,r,e,t){t===void 0&&(t=e),i[t]=r[e]})),__exportStar=this&&this.__exportStar||function(i,r){for(var e in i)e!=="default"&&!Object.prototype.hasOwnProperty.call(r,e)&&__createBinding(r,i,e)};Object.defineProperty(exports,"__esModule",{value:!0}),__exportStar(require("./config/environment"),exports),__exportStar(require("./errors"),exports),__exportStar(require("./config/path-resolver"),exports),__exportStar(require("./dependency/dependency-manager"),exports),__exportStar(require("./libs/archive-service"),exports),__exportStar(require("./libs/file-management-service"),exports),__exportStar(require("./libs/iparams-service"),exports),__exportStar(require("./libs/template-service"),exports),__exportStar(require("./logger/cb-logger"),exports),__exportStar(require("./logger/internal-logger"),exports),__exportStar(require("./node/file-system"),exports),__exportStar(require("./node/process"),exports),__exportStar(require("./sandbox/sandbox-context"),exports),__exportStar(require("./sandbox/sandbox-wrapper"),exports),__exportStar(require("./types/common"),exports),__exportStar(require("./validator/manifest-validator"),exports),__exportStar(require("./validator/package-validator"),exports),__exportStar(require("./validator/iparams-inputs-validator"),exports),__exportStar(require("./validator/iparam-defns-validator"),exports); |
@@ -1,145 +0,1 @@ | ||
| "use strict"; | ||
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| var desc = Object.getOwnPropertyDescriptor(m, k); | ||
| if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
| desc = { enumerable: true, get: function() { return m[k]; } }; | ||
| } | ||
| Object.defineProperty(o, k2, desc); | ||
| }) : (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| o[k2] = m[k]; | ||
| })); | ||
| var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
| Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
| }) : function(o, v) { | ||
| o["default"] = v; | ||
| }); | ||
| var __importStar = (this && this.__importStar) || (function () { | ||
| var ownKeys = function(o) { | ||
| ownKeys = Object.getOwnPropertyNames || function (o) { | ||
| var ar = []; | ||
| for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; | ||
| return ar; | ||
| }; | ||
| return ownKeys(o); | ||
| }; | ||
| return function (mod) { | ||
| if (mod && mod.__esModule) return mod; | ||
| var result = {}; | ||
| if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); | ||
| __setModuleDefault(result, mod); | ||
| return result; | ||
| }; | ||
| })(); | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.ArchiveService = void 0; | ||
| const archiver_1 = __importDefault(require("archiver")); | ||
| const path_1 = __importDefault(require("path")); | ||
| const internal_logger_1 = require("../logger/internal-logger"); | ||
| const yauzl = __importStar(require("yauzl")); | ||
| const fs_1 = __importDefault(require("fs")); | ||
| const fs_2 = require("fs"); | ||
| /** | ||
| * Archive service for managing zip file creation and extraction | ||
| */ | ||
| class ArchiveService { | ||
| constructor(fileSystem) { | ||
| this.fileSystem = fileSystem; | ||
| } | ||
| /** | ||
| * Creates the zip package | ||
| * @param {string[]} files - Array of files to package | ||
| * @param {string} appDir - The application directory | ||
| * @param {string} outputPath - The output path for the package | ||
| */ | ||
| createZipPackage(files, appDir, outputPath) { | ||
| return new Promise((resolve, reject) => { | ||
| const output = this.fileSystem.createWriteStream(outputPath); | ||
| const archive = (0, archiver_1.default)('zip'); | ||
| output.on('close', () => { | ||
| internal_logger_1.__logger.info(`Archive created: ${archive.pointer()} total bytes`); | ||
| resolve(); | ||
| }); | ||
| output.on('error', (err) => { | ||
| internal_logger_1.__logger.error('Error writing to output file:', err); | ||
| reject(err); | ||
| }); | ||
| archive.on('error', (err) => { | ||
| internal_logger_1.__logger.error('Error creating archive:', err); | ||
| reject(err); | ||
| }); | ||
| archive.pipe(output); | ||
| // Add files to the archive | ||
| files.forEach(file => { | ||
| const filePath = path_1.default.join(appDir, file); | ||
| if (this.fileSystem.existsSync(filePath)) { | ||
| archive.file(filePath, { name: file }); | ||
| internal_logger_1.__logger.info(` - Added: ${file}`); | ||
| } | ||
| }); | ||
| archive.finalize(); | ||
| }); | ||
| } | ||
| /** | ||
| * Extract zip file to specified directory using yauzl | ||
| * @param {string} zipFilePath - Path to the zip file | ||
| * @param {string} extractDir - Directory to extract contents to | ||
| */ | ||
| extractZipFile(zipFilePath, extractDir) { | ||
| return new Promise((resolve, reject) => { | ||
| yauzl.open(zipFilePath, { lazyEntries: true }, (err, zipfile) => { | ||
| if (err) { | ||
| internal_logger_1.__logger.error('Error opening zip file:', err); | ||
| reject(err); | ||
| return; | ||
| } | ||
| zipfile.readEntry(); | ||
| zipfile.on('entry', (entry) => { | ||
| if (/\/$/.test(entry.fileName)) { | ||
| // Directory entry | ||
| const dirPath = path_1.default.join(extractDir, entry.fileName); | ||
| fs_1.default.mkdirSync(dirPath, { recursive: true }); | ||
| zipfile.readEntry(); | ||
| } | ||
| else { | ||
| // File entry | ||
| zipfile.openReadStream(entry, (err, readStream) => { | ||
| if (err) { | ||
| internal_logger_1.__logger.error('Error opening read stream:', err); | ||
| reject(err); | ||
| return; | ||
| } | ||
| const filePath = path_1.default.join(extractDir, entry.fileName); | ||
| const dirPath = path_1.default.dirname(filePath); | ||
| // Ensure directory exists | ||
| fs_1.default.mkdirSync(dirPath, { recursive: true }); | ||
| const writeStream = (0, fs_2.createWriteStream)(filePath); | ||
| readStream.pipe(writeStream); | ||
| writeStream.on('close', () => { | ||
| internal_logger_1.__logger.info(`Extracted: ${entry.fileName}`); | ||
| zipfile.readEntry(); | ||
| }); | ||
| writeStream.on('error', (err) => { | ||
| internal_logger_1.__logger.error('Error writing to file:', err); | ||
| reject(err); | ||
| }); | ||
| }); | ||
| } | ||
| }); | ||
| zipfile.on('end', () => { | ||
| internal_logger_1.__logger.info('Extraction completed'); | ||
| resolve(); | ||
| }); | ||
| zipfile.on('error', (err) => { | ||
| internal_logger_1.__logger.error('Error processing zip file:', err); | ||
| reject(err); | ||
| }); | ||
| }); | ||
| }); | ||
| } | ||
| } | ||
| exports.ArchiveService = ArchiveService; | ||
| "use strict";var __createBinding=this&&this.__createBinding||(Object.create?(function(i,e,n,t){t===void 0&&(t=n);var r=Object.getOwnPropertyDescriptor(e,n);(!r||("get"in r?!e.__esModule:r.writable||r.configurable))&&(r={enumerable:!0,get:function(){return e[n]}}),Object.defineProperty(i,t,r)}):(function(i,e,n,t){t===void 0&&(t=n),i[t]=e[n]})),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?(function(i,e){Object.defineProperty(i,"default",{enumerable:!0,value:e})}):function(i,e){i.default=e}),__importStar=this&&this.__importStar||(function(){var i=function(e){return i=Object.getOwnPropertyNames||function(n){var t=[];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[t.length]=r);return t},i(e)};return function(e){if(e&&e.__esModule)return e;var n={};if(e!=null)for(var t=i(e),r=0;r<t.length;r++)t[r]!=="default"&&__createBinding(n,e,t[r]);return __setModuleDefault(n,e),n}})(),__importDefault=this&&this.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.ArchiveService=void 0;const archiver_1=__importDefault(require("archiver")),path_1=__importDefault(require("path")),internal_logger_1=require("../logger/internal-logger"),yauzl=__importStar(require("yauzl")),fs_1=__importDefault(require("fs")),fs_2=require("fs");class ArchiveService{constructor(e){this.fileSystem=e}createZipPackage(e,n,t){return new Promise((r,c)=>{const u=this.fileSystem.createWriteStream(t),a=(0,archiver_1.default)("zip");u.on("close",()=>{internal_logger_1.__logger.info(`Archive created: ${a.pointer()} total bytes`),r()}),u.on("error",o=>{internal_logger_1.__logger.error("Error writing to output file:",o),c(o)}),a.on("error",o=>{internal_logger_1.__logger.error("Error creating archive:",o),c(o)}),a.pipe(u),e.forEach(o=>{const l=path_1.default.join(n,o);this.fileSystem.existsSync(l)&&(a.file(l,{name:o}),internal_logger_1.__logger.info(` - Added: ${o}`))}),a.finalize()})}extractZipFile(e,n){return new Promise((t,r)=>{yauzl.open(e,{lazyEntries:!0},(c,u)=>{if(c){internal_logger_1.__logger.error("Error opening zip file:",c),r(c);return}u.readEntry(),u.on("entry",a=>{if(/\/$/.test(a.fileName)){const o=path_1.default.join(n,a.fileName);fs_1.default.mkdirSync(o,{recursive:!0}),u.readEntry()}else u.openReadStream(a,(o,l)=>{if(o){internal_logger_1.__logger.error("Error opening read stream:",o),r(o);return}const f=path_1.default.join(n,a.fileName),g=path_1.default.dirname(f);fs_1.default.mkdirSync(g,{recursive:!0});const s=(0,fs_2.createWriteStream)(f);l.pipe(s),s.on("close",()=>{internal_logger_1.__logger.info(`Extracted: ${a.fileName}`),u.readEntry()}),s.on("error",_=>{internal_logger_1.__logger.error("Error writing to file:",_),r(_)})})}),u.on("end",()=>{internal_logger_1.__logger.info("Extraction completed"),t()}),u.on("error",a=>{internal_logger_1.__logger.error("Error processing zip file:",a),r(a)})})})}}exports.ArchiveService=ArchiveService; |
@@ -1,189 +0,1 @@ | ||
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.FileManagementService = void 0; | ||
| const internal_logger_1 = require("../logger/internal-logger"); | ||
| const path_1 = __importDefault(require("path")); | ||
| /** | ||
| * File management service for handling file operations | ||
| */ | ||
| class FileManagementService { | ||
| constructor(fileSystem, packageConfig) { | ||
| this.fileSystem = fileSystem; | ||
| this.packageConfig = packageConfig; | ||
| } | ||
| /** | ||
| * Collects essential files for the serverless application package | ||
| * Only includes files and directories specified in packageConfig | ||
| * @param {string} appDir - The application directory | ||
| * @returns {string[]} Array of file paths to package | ||
| */ | ||
| collectFilesToPackage(appDir) { | ||
| const files = []; | ||
| // Process directories specified in packageConfig | ||
| this.packageConfig.include.directories.forEach(dirConfig => { | ||
| if (dirConfig.name === '.') { | ||
| // Handle root directory case - collect files directly from appDir | ||
| const rootFiles = this.getFilesRecursively(appDir, dirConfig); | ||
| files.push(...rootFiles); | ||
| } | ||
| else { | ||
| // Handle subdirectory case | ||
| const dirPath = path_1.default.join(appDir, dirConfig.name); | ||
| if (this.fileSystem.existsSync(dirPath)) { | ||
| const dirFiles = this.getFilesRecursively(dirPath, dirConfig); | ||
| // Add directory files with directory prefix | ||
| dirFiles.forEach((file) => { | ||
| files.push(`${dirConfig.name}/${file}`); | ||
| }); | ||
| } | ||
| else { | ||
| throw new Error(`Directory ${dirPath} does not exist`); | ||
| } | ||
| } | ||
| }); | ||
| internal_logger_1.__logger.info(`Collected ${files.length} files to package`); | ||
| internal_logger_1.__logger.info(` - Directories: ${this.packageConfig.include.directories.map(d => d.name).join(', ')}`); | ||
| return files; | ||
| } | ||
| /** | ||
| * Cleans all files and folders inside the dist directory | ||
| * @param {string} appDir - The application directory | ||
| */ | ||
| cleanExistingPackages(appDir) { | ||
| const distDir = path_1.default.join(appDir, 'dist'); | ||
| if (!this.fileSystem.existsSync(distDir)) { | ||
| this.fileSystem.mkdirSync(distDir, { recursive: true }); | ||
| return; | ||
| } | ||
| const files = this.fileSystem.readdirSync(distDir); | ||
| if (files.length > 0) { | ||
| internal_logger_1.__logger.info(`Cleaning ${files.length} item(s) in dist directory...`); | ||
| files.forEach(item => { | ||
| const itemPath = path_1.default.join(distDir, item); | ||
| const stat = this.fileSystem.statSync(itemPath); | ||
| if (stat.isDirectory()) { | ||
| this.deleteDirectoryRecursively(itemPath); | ||
| internal_logger_1.__logger.info(` - Removed directory: ${item}/`); | ||
| } | ||
| else { | ||
| this.fileSystem.unlinkSync(itemPath); | ||
| } | ||
| }); | ||
| } | ||
| } | ||
| /** | ||
| * Determines the output path for the package | ||
| * @param {string} appDir - The application directory | ||
| * @param {string} appName - The application name | ||
| * @param {PackageOptions} options - Package options | ||
| * @returns {string} The output path for the package | ||
| */ | ||
| determineOutputPath(appDir, appName, packageName) { | ||
| const distDir = path_1.default.join(appDir, 'dist'); | ||
| packageName = packageName || appName; | ||
| const zipFileName = `${packageName}.zip`; | ||
| return path_1.default.join(distDir, zipFileName); | ||
| } | ||
| /** | ||
| * Gets the file size in a human-readable format | ||
| * @param {string} filePath - The file path | ||
| * @returns {string} Human-readable file size | ||
| */ | ||
| getFileSize(filePath) { | ||
| const stats = this.fileSystem.statSync(filePath); | ||
| const bytes = stats.size; | ||
| if (bytes === 0) { | ||
| return '0 Bytes'; | ||
| } | ||
| const k = 1024; | ||
| const sizes = ['Bytes', 'KB', 'MB', 'GB']; | ||
| const i = Math.floor(Math.log(bytes) / Math.log(k)); | ||
| return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; | ||
| } | ||
| /** | ||
| * Collects files recursively from a directory based on directory-specific configurations | ||
| * @param {string} dir - The directory to scan | ||
| * @param {DirectoryConfig} dirConfig - Directory configuration with file inclusion/exclusion rules | ||
| * @returns {string[]} Array of file paths relative to the scanned directory | ||
| */ | ||
| getFilesRecursively(dir, dirConfig) { | ||
| const files = []; | ||
| // Get configuration values | ||
| const allowedExtensions = dirConfig.allowedExtensions || []; | ||
| const excludeSubdirs = dirConfig.excludeSubdirs || []; | ||
| const includeFiles = dirConfig.includeFiles || []; | ||
| const excludeFiles = dirConfig.excludeFiles || []; | ||
| const scanDirectory = (currentDir, baseDir) => { | ||
| const items = this.fileSystem.readdirSync(currentDir); | ||
| for (const item of items) { | ||
| const itemPath = path_1.default.join(currentDir, item); | ||
| const lstat = this.fileSystem.lstatSync(itemPath); | ||
| // Skip symlinks — they may be broken (e.g. .bin/ entries in Docker overlay fs) | ||
| if (lstat.isSymbolicLink()) { | ||
| continue; | ||
| } | ||
| const stat = this.fileSystem.statSync(itemPath); | ||
| if (stat.isDirectory()) { | ||
| // Skip excluded subdirectories | ||
| if (!excludeSubdirs.includes(item)) { | ||
| scanDirectory(itemPath, baseDir); | ||
| } | ||
| } | ||
| else { | ||
| // Apply file inclusion/exclusion logic | ||
| if (item && typeof item === 'string') { | ||
| const relativePath = path_1.default.relative(baseDir, itemPath); | ||
| let shouldInclude = false; | ||
| // Priority 1: Check specific file inclusion (highest priority) | ||
| if (includeFiles.length > 0) { | ||
| shouldInclude = includeFiles.includes(item); | ||
| } | ||
| // Priority 2: Check extension-based inclusion (if no specific files defined) | ||
| else if (allowedExtensions.length > 0) { | ||
| const ext = path_1.default.extname(item).toLowerCase(); | ||
| shouldInclude = allowedExtensions.includes(ext); | ||
| } | ||
| // Priority 3: Include all files if no inclusion rules defined | ||
| else { | ||
| shouldInclude = true; | ||
| } | ||
| // Apply exclusion rules (always applied if file was included) | ||
| if (shouldInclude && excludeFiles.length > 0) { | ||
| shouldInclude = !excludeFiles.includes(item); | ||
| } | ||
| if (shouldInclude) { | ||
| files.push(relativePath); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| if (this.fileSystem.existsSync(dir)) { | ||
| scanDirectory(dir, dir); | ||
| } | ||
| return files; | ||
| } | ||
| /** | ||
| * Recursively deletes a directory and all its contents | ||
| * @param {string} dirPath - The directory path to delete | ||
| */ | ||
| deleteDirectoryRecursively(dirPath) { | ||
| const files = this.fileSystem.readdirSync(dirPath); | ||
| for (const file of files) { | ||
| const filePath = path_1.default.join(dirPath, file); | ||
| const stat = this.fileSystem.statSync(filePath); | ||
| if (stat.isDirectory()) { | ||
| this.deleteDirectoryRecursively(filePath); | ||
| } | ||
| else { | ||
| this.fileSystem.unlinkSync(filePath); | ||
| } | ||
| } | ||
| // Remove the empty directory | ||
| this.fileSystem.rmdirSync(dirPath); | ||
| } | ||
| } | ||
| exports.FileManagementService = FileManagementService; | ||
| "use strict";var __importDefault=this&&this.__importDefault||function(r){return r&&r.__esModule?r:{default:r}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.FileManagementService=void 0;const internal_logger_1=require("../logger/internal-logger"),path_1=__importDefault(require("path"));class FileManagementService{constructor(i,t){this.fileSystem=i,this.packageConfig=t}collectFilesToPackage(i){const t=[];return this.packageConfig.include.directories.forEach(e=>{if(e.name==="."){const s=this.getFilesRecursively(i,e);t.push(...s)}else{const s=path_1.default.join(i,e.name);if(this.fileSystem.existsSync(s))this.getFilesRecursively(s,e).forEach(n=>{t.push(`${e.name}/${n}`)});else throw new Error(`Directory ${s} does not exist`)}}),internal_logger_1.__logger.info(`Collected ${t.length} files to package`),internal_logger_1.__logger.info(` - Directories: ${this.packageConfig.include.directories.map(e=>e.name).join(", ")}`),t}cleanExistingPackages(i){const t=path_1.default.join(i,"dist");if(!this.fileSystem.existsSync(t)){this.fileSystem.mkdirSync(t,{recursive:!0});return}const e=this.fileSystem.readdirSync(t);e.length>0&&(internal_logger_1.__logger.info(`Cleaning ${e.length} item(s) in dist directory...`),e.forEach(s=>{const l=path_1.default.join(t,s);this.fileSystem.statSync(l).isDirectory()?(this.deleteDirectoryRecursively(l),internal_logger_1.__logger.info(` - Removed directory: ${s}/`)):this.fileSystem.unlinkSync(l)}))}determineOutputPath(i,t,e){const s=path_1.default.join(i,"dist");e=e||t;const l=`${e}.zip`;return path_1.default.join(s,l)}getFileSize(i){const e=this.fileSystem.statSync(i).size;if(e===0)return"0 Bytes";const s=1024,l=["Bytes","KB","MB","GB"],n=Math.floor(Math.log(e)/Math.log(s));return parseFloat((e/Math.pow(s,n)).toFixed(2))+" "+l[n]}getFilesRecursively(i,t){const e=[],s=t.allowedExtensions||[],l=t.excludeSubdirs||[],n=t.includeFiles||[],f=t.excludeFiles||[],u=(y,h)=>{const d=this.fileSystem.readdirSync(y);for(const o of d){const a=path_1.default.join(y,o);if(this.fileSystem.lstatSync(a).isSymbolicLink())continue;if(this.fileSystem.statSync(a).isDirectory())l.includes(o)||u(a,h);else if(o&&typeof o=="string"){const S=path_1.default.relative(h,a);let c=!1;if(n.length>0)c=n.includes(o);else if(s.length>0){const g=path_1.default.extname(o).toLowerCase();c=s.includes(g)}else c=!0;c&&f.length>0&&(c=!f.includes(o)),c&&e.push(S)}}};return this.fileSystem.existsSync(i)&&u(i,i),e}deleteDirectoryRecursively(i){const t=this.fileSystem.readdirSync(i);for(const e of t){const s=path_1.default.join(i,e);this.fileSystem.statSync(s).isDirectory()?this.deleteDirectoryRecursively(s):this.fileSystem.unlinkSync(s)}this.fileSystem.rmdirSync(i)}}exports.FileManagementService=FileManagementService; |
@@ -1,136 +0,1 @@ | ||
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.IparamsService = void 0; | ||
| const path_1 = __importDefault(require("path")); | ||
| const errors_1 = require("../errors"); | ||
| const iparams_inputs_validator_1 = require("../validator/iparams-inputs-validator"); | ||
| const iparam_defns_validator_1 = require("../validator/iparam-defns-validator"); | ||
| const validator_utils_1 = require("../validator/validator-utils"); | ||
| /** | ||
| * Service for managing parameters | ||
| * Handles loading, validation, and management of iparams and inputs | ||
| */ | ||
| class IparamsService { | ||
| constructor(fileSystem) { | ||
| this.fileSystem = fileSystem; | ||
| this.iparamDefnsValidator = new iparam_defns_validator_1.IparamDefnsValidator(fileSystem); | ||
| this.inputsValidator = new iparams_inputs_validator_1.IparamInputsValidator(fileSystem); | ||
| } | ||
| getIparamsFilePath(appDir) { | ||
| return path_1.default.join(appDir, 'iparams.json'); | ||
| } | ||
| getInputsFilePath(appDir) { | ||
| return path_1.default.join(appDir, 'iparams.local.json'); | ||
| } | ||
| /** | ||
| * Checks if iparams.json file exists | ||
| * @param {string} appDir - The application directory | ||
| * @returns {boolean} True if the file exists | ||
| */ | ||
| iparamsFileExists(appDir) { | ||
| return this.fileSystem.existsSync(this.getIparamsFilePath(appDir)); | ||
| } | ||
| /** | ||
| * Loads and validates the iparamDefns | ||
| * @param {string} appDir - The application directory | ||
| * @returns {IparamDefns} The validated iparamDefns | ||
| * @throws {Error} If the iparamDefns is invalid or cannot be read | ||
| */ | ||
| loadIparamDefns(appDir) { | ||
| return this.iparamDefnsValidator.validateAndGetIparamDefnsFile(this.getIparamsFilePath(appDir)); | ||
| } | ||
| /** | ||
| * Loads iparam inputs (without validation against defns). Validates file shape only. | ||
| * @param {string} appDir - The application directory | ||
| * @returns {IparamInputs} The loaded inputs | ||
| * @throws {Error} If `iparams.local.json` is missing, invalid JSON, or not a plain object | ||
| */ | ||
| loadInputs(appDir) { | ||
| return this.inputsValidator.validateAndGetIparamInputsFile(this.getInputsFilePath(appDir)); | ||
| } | ||
| /** | ||
| * Merges inputs with defaults per section. | ||
| * @param {IparamInputs} inputs - The provided input values | ||
| * @param {IparamDefns} iparamDefns - The iparam defns | ||
| * @returns {IparamInputs} The merged inputs with defaults applied | ||
| * @throws {MissingRequiredParamsError} When required parameters are missing | ||
| */ | ||
| mergeInputsWithDefaults(inputs, iparamDefns) { | ||
| const mergedInputs = {}; | ||
| const missingRequired = []; | ||
| for (const section of iparamDefns.installation_parameters?.sections ?? []) { | ||
| const sectionInputs = inputs[section.name] ?? {}; | ||
| const mergedSection = {}; | ||
| for (const param of section.parameters) { | ||
| const value = sectionInputs[param.name]; | ||
| const hasValue = iparams_inputs_validator_1.IparamInputsValidator.isProvidedIparamInputValue(value); | ||
| if (hasValue) { | ||
| mergedSection[param.name] = value; | ||
| continue; | ||
| } | ||
| if (param.default !== undefined && param.default !== null) { | ||
| mergedSection[param.name] = param.default; | ||
| continue; | ||
| } | ||
| if (param.required) { | ||
| missingRequired.push(`${section.name}.${param.name}`); | ||
| } | ||
| } | ||
| if (Object.keys(mergedSection).length > 0) { | ||
| mergedInputs[section.name] = mergedSection; | ||
| } | ||
| } | ||
| if (missingRequired.length > 0) { | ||
| throw new errors_1.MissingRequiredParamsError(missingRequired); | ||
| } | ||
| return mergedInputs; | ||
| } | ||
| /** | ||
| * Loads inputs and defns, validates inputs against defns, merges with defaults, returns resolved iparams. | ||
| * @param {string} appDir - The application directory | ||
| * @returns {IparamInputs} The merged inputs with defaults applied | ||
| * @throws {Error} If validation fails, or required parameters are missing and have no defaults | ||
| */ | ||
| validateAndGetInputsForExecution(appDir) { | ||
| const inputs = this.loadInputs(appDir); | ||
| const iparamDefns = this.loadIparamDefns(appDir); | ||
| this.inputsValidator.validateInputs(inputs, iparamDefns); | ||
| return this.mergeInputsWithDefaults(inputs, iparamDefns); | ||
| } | ||
| /** | ||
| * Saves the iparamDefns to file | ||
| * @param {string} appDir - The application directory | ||
| * @param {IparamDefns} iparamDefns - The iparamDefns to save | ||
| * @throws {Error} If the iparamDefns is invalid or cannot be written | ||
| */ | ||
| saveIparamDefns(appDir, iparamDefns) { | ||
| (0, validator_utils_1.ensureFileExists)(this.fileSystem, this.getIparamsFilePath(appDir)); | ||
| this.iparamDefnsValidator.validate(iparamDefns); | ||
| this.fileSystem.writeFileSync(this.getIparamsFilePath(appDir), JSON.stringify(iparamDefns, null, '\t')); | ||
| } | ||
| /** | ||
| * Loads defns and merges inputs, ensures iparams.local.json exists, then writes. | ||
| * @param {string} appDir - The application directory | ||
| * @param {IparamInputs} inputs - The raw input values from the request | ||
| * @throws {Error} If iparams.json or iparams.local.json is missing, or validation fails | ||
| */ | ||
| saveInputs(appDir, inputs) { | ||
| const iparamDefns = this.loadIparamDefns(appDir); | ||
| this.inputsValidator.validateInputs(inputs, iparamDefns); | ||
| const mergedInputs = this.mergeInputsWithDefaults(inputs, iparamDefns); | ||
| (0, validator_utils_1.ensureFileExists)(this.fileSystem, this.getInputsFilePath(appDir)); | ||
| this.fileSystem.writeFileSync(this.getInputsFilePath(appDir), JSON.stringify(mergedInputs, null, '\t')); | ||
| } | ||
| /** | ||
| * Validates iparams file without loading it | ||
| * @param {string} appDir - The application directory | ||
| * @throws {Error} If the iparamDefns is invalid | ||
| */ | ||
| validateIparamDefns(appDir) { | ||
| this.iparamDefnsValidator.validateAndGetIparamDefnsFile(this.getIparamsFilePath(appDir)); | ||
| } | ||
| } | ||
| exports.IparamsService = IparamsService; | ||
| "use strict";var __importDefault=this&&this.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.IparamsService=void 0;const path_1=__importDefault(require("path")),errors_1=require("../errors"),iparams_inputs_validator_1=require("../validator/iparams-inputs-validator"),iparam_defns_validator_1=require("../validator/iparam-defns-validator"),validator_utils_1=require("../validator/validator-utils");class IparamsService{constructor(t){this.fileSystem=t,this.iparamDefnsValidator=new iparam_defns_validator_1.IparamDefnsValidator(t),this.inputsValidator=new iparams_inputs_validator_1.IparamInputsValidator(t)}getIparamsFilePath(t){return path_1.default.join(t,"iparams.json")}getInputsFilePath(t){return path_1.default.join(t,"iparams.local.json")}iparamsFileExists(t){return this.fileSystem.existsSync(this.getIparamsFilePath(t))}loadIparamDefns(t){return this.iparamDefnsValidator.validateAndGetIparamDefnsFile(this.getIparamsFilePath(t))}loadInputs(t){return this.inputsValidator.validateAndGetIparamInputsFile(this.getInputsFilePath(t))}mergeInputsWithDefaults(t,a){const e={},r=[];for(const n of a.installation_parameters?.sections??[]){const o=t[n.name]??{},l={};for(const s of n.parameters){const u=o[s.name];if(iparams_inputs_validator_1.IparamInputsValidator.isProvidedIparamInputValue(u)){l[s.name]=u;continue}if(s.default!==void 0&&s.default!==null){l[s.name]=s.default;continue}s.required&&r.push(`${n.name}.${s.name}`)}Object.keys(l).length>0&&(e[n.name]=l)}if(r.length>0)throw new errors_1.MissingRequiredParamsError(r);return e}validateAndGetInputsForExecution(t){const a=this.loadInputs(t),e=this.loadIparamDefns(t);return this.inputsValidator.validateInputs(a,e),this.mergeInputsWithDefaults(a,e)}saveIparamDefns(t,a){(0,validator_utils_1.ensureFileExists)(this.fileSystem,this.getIparamsFilePath(t)),this.iparamDefnsValidator.validate(a),this.fileSystem.writeFileSync(this.getIparamsFilePath(t),JSON.stringify(a,null," "))}saveInputs(t,a){const e=this.loadIparamDefns(t);this.inputsValidator.validateInputs(a,e);const r=this.mergeInputsWithDefaults(a,e);(0,validator_utils_1.ensureFileExists)(this.fileSystem,this.getInputsFilePath(t)),this.fileSystem.writeFileSync(this.getInputsFilePath(t),JSON.stringify(r,null," "))}validateIparamDefns(t){this.iparamDefnsValidator.validateAndGetIparamDefnsFile(this.getIparamsFilePath(t))}}exports.IparamsService=IparamsService; |
@@ -1,152 +0,1 @@ | ||
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.TemplateService = void 0; | ||
| const path_1 = __importDefault(require("path")); | ||
| const internal_logger_1 = require("../logger/internal-logger"); | ||
| /** | ||
| * Template service for managing templates across different CLI packages | ||
| */ | ||
| class TemplateService { | ||
| constructor(fileSystem, templatesDir) { | ||
| this.fileSystem = fileSystem; | ||
| this.templatesDir = templatesDir; | ||
| } | ||
| /** | ||
| * Validates template exists | ||
| * @param {string} template - Template name to validate | ||
| * @returns {boolean} True if template is valid | ||
| */ | ||
| validateTemplate(template) { | ||
| const availableTemplates = this.getAvailableTemplates(); | ||
| return availableTemplates.includes(template); | ||
| } | ||
| /** | ||
| * Validates app directory for conflicts | ||
| * @param {string} targetDir - Target directory path | ||
| * @param {string} appDir - Original app directory argument | ||
| * @param {string} template - Template name | ||
| * @returns {string[]} Array of conflicting files (empty if no conflicts) | ||
| */ | ||
| validateAppDirectory(targetDir, appDir, template) { | ||
| if (!this.fileSystem.existsSync(targetDir)) { | ||
| return []; | ||
| } | ||
| if (appDir === '.') { | ||
| // When using current directory, check for conflicting files | ||
| const templatePath = path_1.default.join(this.templatesDir, template); | ||
| const templateFiles = this.getTemplateFiles(templatePath); | ||
| const existingFiles = this.fileSystem.readdirSync(targetDir); | ||
| return templateFiles.filter(file => existingFiles.includes(file)); | ||
| } | ||
| else { | ||
| // For other directories, check if not empty | ||
| const files = this.fileSystem.readdirSync(targetDir); | ||
| if (files.length > 0) { | ||
| throw new Error(`Directory '${targetDir}' already exists and is not empty.`); | ||
| } | ||
| return []; | ||
| } | ||
| } | ||
| /** | ||
| * Gets a list of available templates from the templates directory | ||
| * @returns {string[]} Array of template names | ||
| */ | ||
| getAvailableTemplates() { | ||
| if (!this.fileSystem.existsSync(this.templatesDir)) { | ||
| internal_logger_1.__logger.warn(`Templates directory not found: ${this.templatesDir}`); | ||
| return []; | ||
| } | ||
| const templates = this.fileSystem.readdirSync(this.templatesDir, { withFileTypes: true }) | ||
| .filter(dirent => dirent.isDirectory()) | ||
| .map(dirent => dirent.name); | ||
| return templates; | ||
| } | ||
| /** | ||
| * Gets the full path to a specific template | ||
| * @param {string} template - Template name | ||
| * @returns {string} Full path to the template directory | ||
| */ | ||
| getTemplatePath(template) { | ||
| return path_1.default.join(this.templatesDir, template); | ||
| } | ||
| /** | ||
| * Gets the templates directory path | ||
| * @returns {string} Path to the templates directory | ||
| */ | ||
| getTemplatesDirectory() { | ||
| return this.templatesDir; | ||
| } | ||
| /** | ||
| * Recursively collects all files from a template directory | ||
| * @param {string} templatePath - Path to the template directory | ||
| * @returns {string[]} Array of file paths relative to template root | ||
| */ | ||
| getTemplateFiles(templatePath) { | ||
| const files = []; | ||
| const collectFiles = (dir, basePath = '') => { | ||
| const items = this.fileSystem.readdirSync(dir); | ||
| for (const item of items) { | ||
| const sourcePath = path_1.default.join(dir, item); | ||
| const relativePath = path_1.default.join(basePath, item); | ||
| const stat = this.fileSystem.statSync(sourcePath); | ||
| if (stat.isDirectory()) { | ||
| collectFiles(sourcePath, relativePath); | ||
| } | ||
| else { | ||
| files.push(relativePath); | ||
| } | ||
| } | ||
| }; | ||
| collectFiles(templatePath); | ||
| return files; | ||
| } | ||
| /** | ||
| * Recursively copies all files from template directory to target directory | ||
| * @param {string} templatePath - Source template directory path | ||
| * @param {string} targetPath - Target directory path | ||
| */ | ||
| copyTemplateFiles(templatePath, targetPath) { | ||
| const items = this.fileSystem.readdirSync(templatePath); | ||
| for (const item of items) { | ||
| const sourcePath = path_1.default.join(templatePath, item); | ||
| const destPath = path_1.default.join(targetPath, item); | ||
| const stat = this.fileSystem.statSync(sourcePath); | ||
| if (stat.isDirectory()) { | ||
| this.fileSystem.mkdirSync(destPath, { recursive: true }); | ||
| this.copyTemplateFiles(sourcePath, destPath); | ||
| } | ||
| else { | ||
| this.fileSystem.copyFileSync(sourcePath, destPath); | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * Prints a tree-like structure of the project directory | ||
| * @param {string} dir - Directory path to print structure for | ||
| * @param {string} [indent=''] - Current indentation level | ||
| */ | ||
| printProjectStructure(dir, indent = '') { | ||
| const items = this.fileSystem.readdirSync(dir); | ||
| for (let i = 0; i < items.length; i++) { | ||
| const item = items[i]; | ||
| const itemPath = path_1.default.join(dir, item || ''); | ||
| const stat = this.fileSystem.statSync(itemPath); | ||
| const isDirectory = stat.isDirectory(); | ||
| const isLastItem = i === items.length - 1; | ||
| // Tree characters | ||
| const treeChar = isLastItem ? '└── ' : '├── '; | ||
| const nextIndent = isLastItem ? ' ' : '│ '; | ||
| // File/directory name | ||
| const name = isDirectory ? item + '/' : item; | ||
| const coloredName = name; | ||
| internal_logger_1.__logger.info(`${indent}${treeChar}${coloredName}`); | ||
| if (isDirectory) { | ||
| this.printProjectStructure(itemPath, indent + nextIndent); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| exports.TemplateService = TemplateService; | ||
| "use strict";var __importDefault=this&&this.__importDefault||function(a){return a&&a.__esModule?a:{default:a}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.TemplateService=void 0;const path_1=__importDefault(require("path")),internal_logger_1=require("../logger/internal-logger");class TemplateService{constructor(e,t){this.fileSystem=e,this.templatesDir=t}validateTemplate(e){return this.getAvailableTemplates().includes(e)}validateAppDirectory(e,t,r){if(!this.fileSystem.existsSync(e))return[];if(t==="."){const s=path_1.default.join(this.templatesDir,r),i=this.getTemplateFiles(s),l=this.fileSystem.readdirSync(e);return i.filter(n=>l.includes(n))}else{if(this.fileSystem.readdirSync(e).length>0)throw new Error(`Directory '${e}' already exists and is not empty.`);return[]}}getAvailableTemplates(){return this.fileSystem.existsSync(this.templatesDir)?this.fileSystem.readdirSync(this.templatesDir,{withFileTypes:!0}).filter(t=>t.isDirectory()).map(t=>t.name):(internal_logger_1.__logger.warn(`Templates directory not found: ${this.templatesDir}`),[])}getTemplatePath(e){return path_1.default.join(this.templatesDir,e)}getTemplatesDirectory(){return this.templatesDir}getTemplateFiles(e){const t=[],r=(s,i="")=>{const l=this.fileSystem.readdirSync(s);for(const n of l){const o=path_1.default.join(s,n),c=path_1.default.join(i,n);this.fileSystem.statSync(o).isDirectory()?r(o,c):t.push(c)}};return r(e),t}copyTemplateFiles(e,t){const r=this.fileSystem.readdirSync(e);for(const s of r){const i=path_1.default.join(e,s),l=path_1.default.join(t,s);this.fileSystem.statSync(i).isDirectory()?(this.fileSystem.mkdirSync(l,{recursive:!0}),this.copyTemplateFiles(i,l)):this.fileSystem.copyFileSync(i,l)}}printProjectStructure(e,t=""){const r=this.fileSystem.readdirSync(e);for(let s=0;s<r.length;s++){const i=r[s],l=path_1.default.join(e,i||""),o=this.fileSystem.statSync(l).isDirectory(),c=s===r.length-1,m=c?"\u2514\u2500\u2500 ":"\u251C\u2500\u2500 ",f=c?" ":"\u2502 ",p=o?i+"/":i;internal_logger_1.__logger.info(`${t}${m}${p}`),o&&this.printProjectStructure(l,t+f)}}}exports.TemplateService=TemplateService; |
@@ -1,13 +0,1 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.LogLevel = void 0; | ||
| /** | ||
| * Log levels enum for consistent logging across packages | ||
| */ | ||
| var LogLevel; | ||
| (function (LogLevel) { | ||
| LogLevel["ERROR"] = "ERROR"; | ||
| LogLevel["WARN"] = "WARN"; | ||
| LogLevel["INFO"] = "INFO"; | ||
| LogLevel["DEBUG"] = "DEBUG"; | ||
| })(LogLevel || (exports.LogLevel = LogLevel = {})); | ||
| "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.LogLevel=void 0;var LogLevel;(function(e){e.ERROR="ERROR",e.WARN="WARN",e.INFO="INFO",e.DEBUG="DEBUG"})(LogLevel||(exports.LogLevel=LogLevel={})); |
@@ -1,146 +0,2 @@ | ||
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.__logger = exports.InternalLogger = void 0; | ||
| const cb_logger_1 = require("./cb-logger"); | ||
| const winston_1 = __importDefault(require("winston")); | ||
| /** | ||
| * Winston-based InternalLogger provides logging capabilities for the Chargebee Apps CLI itself | ||
| * This is separate from the user-facing cb-logger and uses Winston for structured logging | ||
| * Shared implementation for both public and private CLI packages | ||
| */ | ||
| class InternalLogger { | ||
| constructor(config = {}) { | ||
| this.config = { | ||
| useJsonFormat: false, | ||
| ...config | ||
| }; | ||
| this.logger = this.createWinstonLogger(); | ||
| } | ||
| /** | ||
| * Creates a Winston logger instance with appropriate formatting | ||
| * @returns {winston.Logger} The configured Winston logger | ||
| */ | ||
| createWinstonLogger() { | ||
| const logLevel = process.env['CB_LOG_LEVEL'] || cb_logger_1.LogLevel.INFO; | ||
| // Create custom format based on configuration | ||
| const customFormat = winston_1.default.format.combine(winston_1.default.format.timestamp(), winston_1.default.format.errors({ stack: true }), this.config.useJsonFormat ? this.createJsonFormat() : this.createTextFormat()); | ||
| return winston_1.default.createLogger({ | ||
| level: logLevel.toLowerCase(), | ||
| format: customFormat, | ||
| transports: [ | ||
| new winston_1.default.transports.Console({}) | ||
| ] | ||
| }); | ||
| } | ||
| /** | ||
| * Creates JSON format for structured logging | ||
| * @returns {winston.Logform.Format} The JSON format | ||
| */ | ||
| createJsonFormat() { | ||
| return winston_1.default.format.combine(winston_1.default.format.timestamp(), winston_1.default.format.printf((info) => { | ||
| const logEntry = { | ||
| timestamp: info['timestamp'], | ||
| level: info.level, | ||
| service: 'Internal', | ||
| message: info.message | ||
| }; | ||
| // Include all additional context from child loggers | ||
| Object.keys(info).forEach(key => { | ||
| if (!['timestamp', 'level', 'message', 'stack'].includes(key)) { | ||
| logEntry[key] = info[key]; | ||
| } | ||
| }); | ||
| if (info['stack']) { | ||
| logEntry.stack = info['stack']; | ||
| } | ||
| return JSON.stringify(logEntry); | ||
| })); | ||
| } | ||
| /** | ||
| * Creates text format for human-readable logging | ||
| * @returns {winston.Logform.Format} The text format | ||
| */ | ||
| createTextFormat() { | ||
| return winston_1.default.format.combine(winston_1.default.format.timestamp(), winston_1.default.format.colorize(), winston_1.default.format.printf((info) => { | ||
| const timestamp = info['timestamp']; | ||
| const level = info.level; | ||
| const service = 'Internal'; | ||
| const message = info.message; | ||
| const stack = info['stack'] ? `\n${info['stack']}` : ''; | ||
| // Build context string from additional properties | ||
| const contextParts = []; | ||
| Object.keys(info).forEach(key => { | ||
| if (!['timestamp', 'level', 'message', 'stack'].includes(key)) { | ||
| contextParts.push(`${key}=${info[key]}`); | ||
| } | ||
| }); | ||
| const contextStr = contextParts.length > 0 ? ` [${contextParts.join(', ')}]` : ''; | ||
| return `${timestamp} [${level}] [${service}]${contextStr} ${message}${stack}`; | ||
| })); | ||
| } | ||
| /** | ||
| * Logs an informational message | ||
| * @param {...any} args - The message arguments to log | ||
| */ | ||
| info(...args) { | ||
| const message = args.join(' '); | ||
| this.logger.info(message); | ||
| } | ||
| /** | ||
| * Logs a warning message | ||
| * @param {...any} args - The message arguments to log | ||
| */ | ||
| warn(...args) { | ||
| const message = args.join(' '); | ||
| this.logger.warn(message); | ||
| } | ||
| /** | ||
| * Logs an error message | ||
| * @param {...any} args - The message arguments to log | ||
| */ | ||
| error(...args) { | ||
| const message = args.join(' '); | ||
| this.logger.error(message); | ||
| } | ||
| /** | ||
| * Logs a debug message | ||
| * @param {...any} args - The message arguments to log | ||
| */ | ||
| debug(...args) { | ||
| const message = args.join(' '); | ||
| this.logger.debug(message); | ||
| } | ||
| /** | ||
| * Logs a success message (alias for info with success indicator) | ||
| * @param {...any} args - The message arguments to log | ||
| */ | ||
| success(...args) { | ||
| const message = args.join(' '); | ||
| this.logger.info(`✅ ${message}`); | ||
| } | ||
| /** | ||
| * Logs a failure message (alias for error with failure indicator) | ||
| * @param {...any} args - The message arguments to log | ||
| */ | ||
| failure(...args) { | ||
| const message = args.join(' '); | ||
| this.logger.error(`❌ ${message}`); | ||
| } | ||
| /** | ||
| * Creates a child logger with additional context | ||
| * @param {ChildLoggerContext} context - Additional context to include in all log messages | ||
| * @returns {InternalLogger} A new InternalLogger instance with the child context | ||
| */ | ||
| child(context) { | ||
| const childLogger = new InternalLogger(this.config); | ||
| // Create a Winston child logger with the provided context | ||
| childLogger.logger = this.logger.child(context); | ||
| return childLogger; | ||
| } | ||
| } | ||
| exports.InternalLogger = InternalLogger; | ||
| // Create a singleton instance for default logger | ||
| exports.__logger = new InternalLogger(); | ||
| "use strict";var __importDefault=this&&this.__importDefault||function(r){return r&&r.__esModule?r:{default:r}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.__logger=exports.InternalLogger=void 0;const cb_logger_1=require("./cb-logger"),winston_1=__importDefault(require("winston"));class InternalLogger{constructor(e={}){this.config={useJsonFormat:!1,...e},this.logger=this.createWinstonLogger()}createWinstonLogger(){const e=process.env.CB_LOG_LEVEL||cb_logger_1.LogLevel.INFO,t=winston_1.default.format.combine(winston_1.default.format.timestamp(),winston_1.default.format.errors({stack:!0}),this.config.useJsonFormat?this.createJsonFormat():this.createTextFormat());return winston_1.default.createLogger({level:e.toLowerCase(),format:t,transports:[new winston_1.default.transports.Console({})]})}createJsonFormat(){return winston_1.default.format.combine(winston_1.default.format.timestamp(),winston_1.default.format.printf(e=>{const t={timestamp:e.timestamp,level:e.level,service:"Internal",message:e.message};return Object.keys(e).forEach(s=>{["timestamp","level","message","stack"].includes(s)||(t[s]=e[s])}),e.stack&&(t.stack=e.stack),JSON.stringify(t)}))}createTextFormat(){return winston_1.default.format.combine(winston_1.default.format.timestamp(),winston_1.default.format.colorize(),winston_1.default.format.printf(e=>{const t=e.timestamp,s=e.level,n="Internal",c=e.message,l=e.stack?` | ||
| ${e.stack}`:"",o=[];Object.keys(e).forEach(a=>{["timestamp","level","message","stack"].includes(a)||o.push(`${a}=${e[a]}`)});const g=o.length>0?` [${o.join(", ")}]`:"";return`${t} [${s}] [${n}]${g} ${c}${l}`}))}info(...e){const t=e.join(" ");this.logger.info(t)}warn(...e){const t=e.join(" ");this.logger.warn(t)}error(...e){const t=e.join(" ");this.logger.error(t)}debug(...e){const t=e.join(" ");this.logger.debug(t)}success(...e){const t=e.join(" ");this.logger.info(`\u2705 ${t}`)}failure(...e){const t=e.join(" ");this.logger.error(`\u274C ${t}`)}child(e){const t=new InternalLogger(this.config);return t.logger=this.logger.child(e),t}}exports.InternalLogger=InternalLogger,exports.__logger=new InternalLogger; |
@@ -1,76 +0,1 @@ | ||
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.FileSystemService = void 0; | ||
| const fs_1 = __importDefault(require("fs")); | ||
| /** | ||
| * FileSystemService provides a class-based implementation of the FileSystem interface. | ||
| * Use this for dependency injection for all the filesystem operations, and for testing we can use custom implemenatation if needed. | ||
| */ | ||
| class FileSystemService { | ||
| existsSync(path) { | ||
| return fs_1.default.existsSync(path); | ||
| } | ||
| readdirSync(path, options) { | ||
| return fs_1.default.readdirSync(path, options); | ||
| } | ||
| mkdirSync(path, options) { | ||
| fs_1.default.mkdirSync(path, options); | ||
| } | ||
| unlinkSync(path) { | ||
| fs_1.default.unlinkSync(path); | ||
| } | ||
| rmdirSync(path) { | ||
| fs_1.default.rmdirSync(path); | ||
| } | ||
| statSync(path) { | ||
| return fs_1.default.statSync(path); | ||
| } | ||
| createWriteStream(path) { | ||
| return fs_1.default.createWriteStream(path); | ||
| } | ||
| readFileSync(path, encoding) { | ||
| return fs_1.default.readFileSync(path, encoding); | ||
| } | ||
| writeFileSync(path, data) { | ||
| fs_1.default.writeFileSync(path, data); | ||
| } | ||
| copyFileSync(src, dest) { | ||
| fs_1.default.copyFileSync(src, dest); | ||
| } | ||
| lstatSync(path) { | ||
| return fs_1.default.lstatSync(path); | ||
| } | ||
| renameSync(oldPath, newPath) { | ||
| try { | ||
| fs_1.default.renameSync(oldPath, newPath); | ||
| } | ||
| catch (err) { | ||
| if (err.code === 'EXDEV') { | ||
| // Cross-device rename (e.g. Docker overlay filesystem) — fall back to copy + delete | ||
| try { | ||
| fs_1.default.cpSync(oldPath, newPath, { recursive: true }); | ||
| fs_1.default.rmSync(oldPath, { recursive: true, force: true }); | ||
| } | ||
| catch (copyErr) { | ||
| try { | ||
| fs_1.default.rmSync(newPath, { recursive: true, force: true }); | ||
| } | ||
| catch { | ||
| // best-effort cleanup; ignore errors | ||
| } | ||
| throw copyErr; | ||
| } | ||
| } | ||
| else { | ||
| throw err; | ||
| } | ||
| } | ||
| } | ||
| cpSync(src, dest, options) { | ||
| fs_1.default.cpSync(src, dest, options); | ||
| } | ||
| } | ||
| 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)}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; |
+1
-25
@@ -1,25 +0,1 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.ProcessService = void 0; | ||
| /** | ||
| * ProcessService provides a class-based implementation of the Process interface. | ||
| * Use this for dependency injection for all the process operations, and for testing we can use custom implemenatation if needed. | ||
| */ | ||
| class ProcessService { | ||
| chdir(path) { | ||
| process.chdir(path); | ||
| } | ||
| cwd() { | ||
| return process.cwd(); | ||
| } | ||
| exit(code) { | ||
| process.exit(code); | ||
| } | ||
| on(event, listener) { | ||
| process.on(event, listener); | ||
| } | ||
| get env() { | ||
| return process.env; | ||
| } | ||
| } | ||
| exports.ProcessService = ProcessService; | ||
| "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ProcessService=void 0;class ProcessService{chdir(e){process.chdir(e)}cwd(){return process.cwd()}exit(e){process.exit(e)}on(e,r){process.on(e,r)}get env(){return process.env}}exports.ProcessService=ProcessService; |
@@ -1,48 +0,1 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.sandboxContext = exports.SandboxContext = void 0; | ||
| const async_hooks_1 = require("async_hooks"); | ||
| /** | ||
| * SandboxContext manages the execution context for sandboxed code execution | ||
| * using AsyncLocalStorage to maintain correlation between event and site information | ||
| */ | ||
| class SandboxContext { | ||
| constructor() { | ||
| this.asyncLocalStorage = new async_hooks_1.AsyncLocalStorage(); | ||
| } | ||
| /** | ||
| * Creates a new execution context with event and site information | ||
| * @param {Object} contextData - The context data containing event and site information | ||
| * @param {string} contextData.eventId - The unique identifier for the event | ||
| * @param {string} contextData.eventType - The type of the event (e.g., 'customer_created') | ||
| * @param {string} contextData.site - The site/tenant identifier in Chargebee | ||
| * @param {Function} callback - The function to execute within this context | ||
| * @returns {Promise<any>} The result of the callback execution | ||
| */ | ||
| async run(contextData, callback) { | ||
| const context = { | ||
| eventId: contextData.eventId || 'unknown', | ||
| eventType: contextData.eventType || 'unknown', | ||
| startTime: new Date().toISOString(), | ||
| }; | ||
| return this.asyncLocalStorage.run(context, () => callback()); | ||
| } | ||
| /** | ||
| * Gets the current execution context | ||
| * @returns {Object|null} The current context or null if not in an execution context | ||
| */ | ||
| getCurrentContext() { | ||
| return this.asyncLocalStorage.getStore(); | ||
| } | ||
| /** | ||
| * Checks if there is an active execution context | ||
| * @returns {boolean} True if there is an active context, false otherwise | ||
| */ | ||
| hasContext() { | ||
| return this.asyncLocalStorage.getStore() !== undefined; | ||
| } | ||
| } | ||
| exports.SandboxContext = SandboxContext; | ||
| // Create a singleton instance | ||
| exports.sandboxContext = new SandboxContext(); | ||
| exports.default = exports.sandboxContext; | ||
| "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.sandboxContext=exports.SandboxContext=void 0;const async_hooks_1=require("async_hooks");class SandboxContext{constructor(){this.asyncLocalStorage=new async_hooks_1.AsyncLocalStorage}async run(t,e){const n={eventId:t.eventId||"unknown",eventType:t.eventType||"unknown",startTime:new Date().toISOString()};return this.asyncLocalStorage.run(n,()=>e())}getCurrentContext(){return this.asyncLocalStorage.getStore()}hasContext(){return this.asyncLocalStorage.getStore()!==void 0}}exports.SandboxContext=SandboxContext,exports.sandboxContext=new SandboxContext,exports.default=exports.sandboxContext; |
@@ -1,2 +0,1 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| "use strict";Object.defineProperty(exports,"__esModule",{value:!0}); |
+1
-20
@@ -1,20 +0,1 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.VALID_IPARAM_TYPES = exports.IPARAM_TYPE_VALUE_MAP = void 0; | ||
| /** | ||
| * Map of iparam `type` identifiers to placeholder values. | ||
| * Keys match valid `type` values in `iparams.json`; each value’s TypeScript type is the allowed | ||
| * JSON shape for that type in definition defaults and `iparams.local.json`. | ||
| */ | ||
| exports.IPARAM_TYPE_VALUE_MAP = { | ||
| NUMBER: 0, | ||
| TEXT: '', | ||
| DROPDOWN: '', | ||
| MULTISELECT_DROPDOWN: [], | ||
| DATE: '', | ||
| URL: '', | ||
| BOOLEAN: false, | ||
| SECRET: '' | ||
| }; | ||
| /** Valid `type` strings for runtime checks. */ | ||
| exports.VALID_IPARAM_TYPES = Object.keys(exports.IPARAM_TYPE_VALUE_MAP); | ||
| "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.VALID_IPARAM_TYPES=exports.IPARAM_TYPE_VALUE_MAP=void 0,exports.IPARAM_TYPE_VALUE_MAP={NUMBER:0,TEXT:"",DROPDOWN:"",MULTISELECT_DROPDOWN:[],DATE:"",URL:"",BOOLEAN:!1,SECRET:""},exports.VALID_IPARAM_TYPES=Object.keys(exports.IPARAM_TYPE_VALUE_MAP); |
@@ -1,52 +0,1 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.IPARAM_URL_ALLOWED_PROTOCOLS = exports.IPARAM_VALUE_MAX_LENGTHS = exports.OPTIONS_LIMITS = exports.IPARAM_DEFN_MAX_LENGTHS = exports.IPARAMS_MAX_COUNT = exports.IPARAMS_INSTALLATION_PARAMETERS_ALLOWED_KEYS = exports.IPARAMS_SECTIONS_LABEL = exports.IPARAMS_JSON_FILENAME = exports.IPARAMS_ROOT_ALLOWED_KEYS = exports.IPARAMS_INSTALLATION_PARAMETERS_LABEL = void 0; | ||
| /** | ||
| * Allowed top-level keys in `iparams.json`. | ||
| */ | ||
| exports.IPARAMS_INSTALLATION_PARAMETERS_LABEL = 'installation_parameters'; | ||
| exports.IPARAMS_ROOT_ALLOWED_KEYS = [exports.IPARAMS_INSTALLATION_PARAMETERS_LABEL]; | ||
| /** | ||
| * File name for iparam definitions in an app directory. | ||
| */ | ||
| exports.IPARAMS_JSON_FILENAME = 'iparams.json'; | ||
| /** | ||
| * Label for the `sections` array in validation error messages. | ||
| */ | ||
| exports.IPARAMS_SECTIONS_LABEL = 'sections'; | ||
| /** | ||
| * Allowed keys under `installation_parameters` in `iparams.json`. | ||
| */ | ||
| exports.IPARAMS_INSTALLATION_PARAMETERS_ALLOWED_KEYS = [exports.IPARAMS_SECTIONS_LABEL]; | ||
| /** | ||
| * Maximum number of parameter definitions allowed in a single `iparams.json` array. | ||
| */ | ||
| exports.IPARAMS_MAX_COUNT = 20; | ||
| /** | ||
| * Central limits for iparam definition fields (`iparams.json`). | ||
| */ | ||
| exports.IPARAM_DEFN_MAX_LENGTHS = { | ||
| NAME: 50, | ||
| DISPLAY_NAME: 50, | ||
| DESCRIPTION: 250 | ||
| }; | ||
| /** | ||
| * Limits for DROPDOWN and MULTISELECT_DROPDOWN `options` arrays in definitions. | ||
| */ | ||
| exports.OPTIONS_LIMITS = { | ||
| MAX_COUNT: 20, | ||
| MAX_OPTION_LENGTH: 250 | ||
| }; | ||
| /** | ||
| * Max lengths for iparam input values when validating `iparams.local.json` / runtime inputs. | ||
| */ | ||
| exports.IPARAM_VALUE_MAX_LENGTHS = { | ||
| TEXT: 250, | ||
| SECRET: 250, | ||
| URL: 250, | ||
| DATE: 10 | ||
| }; | ||
| /** | ||
| * Allowed {@link URL#protocol} values for iparam type `URL`. | ||
| */ | ||
| exports.IPARAM_URL_ALLOWED_PROTOCOLS = ['http:', 'https:']; | ||
| "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.IPARAM_URL_ALLOWED_PROTOCOLS=exports.IPARAM_VALUE_MAX_LENGTHS=exports.OPTIONS_LIMITS=exports.IPARAM_DEFN_MAX_LENGTHS=exports.IPARAMS_MAX_COUNT=exports.IPARAMS_INSTALLATION_PARAMETERS_ALLOWED_KEYS=exports.IPARAMS_SECTIONS_LABEL=exports.IPARAMS_JSON_FILENAME=exports.IPARAMS_ROOT_ALLOWED_KEYS=exports.IPARAMS_INSTALLATION_PARAMETERS_LABEL=void 0,exports.IPARAMS_INSTALLATION_PARAMETERS_LABEL="installation_parameters",exports.IPARAMS_ROOT_ALLOWED_KEYS=[exports.IPARAMS_INSTALLATION_PARAMETERS_LABEL],exports.IPARAMS_JSON_FILENAME="iparams.json",exports.IPARAMS_SECTIONS_LABEL="sections",exports.IPARAMS_INSTALLATION_PARAMETERS_ALLOWED_KEYS=[exports.IPARAMS_SECTIONS_LABEL],exports.IPARAMS_MAX_COUNT=20,exports.IPARAM_DEFN_MAX_LENGTHS={NAME:50,DISPLAY_NAME:50,DESCRIPTION:250},exports.OPTIONS_LIMITS={MAX_COUNT:20,MAX_OPTION_LENGTH:250},exports.IPARAM_VALUE_MAX_LENGTHS={TEXT:250,SECRET:250,URL:250,DATE:10},exports.IPARAM_URL_ALLOWED_PROTOCOLS=["http:","https:"]; |
@@ -1,291 +0,1 @@ | ||
| "use strict"; | ||
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| var desc = Object.getOwnPropertyDescriptor(m, k); | ||
| if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
| desc = { enumerable: true, get: function() { return m[k]; } }; | ||
| } | ||
| Object.defineProperty(o, k2, desc); | ||
| }) : (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| o[k2] = m[k]; | ||
| })); | ||
| var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
| Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
| }) : function(o, v) { | ||
| o["default"] = v; | ||
| }); | ||
| var __importStar = (this && this.__importStar) || (function () { | ||
| var ownKeys = function(o) { | ||
| ownKeys = Object.getOwnPropertyNames || function (o) { | ||
| var ar = []; | ||
| for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; | ||
| return ar; | ||
| }; | ||
| return ownKeys(o); | ||
| }; | ||
| return function (mod) { | ||
| if (mod && mod.__esModule) return mod; | ||
| var result = {}; | ||
| if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); | ||
| __setModuleDefault(result, mod); | ||
| return result; | ||
| }; | ||
| })(); | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.IparamDefnsValidator = void 0; | ||
| const common_1 = require("../types/common"); | ||
| const iparam_constants_1 = require("./iparam-constants"); | ||
| const iparams_inputs_validator_1 = require("./iparams-inputs-validator"); | ||
| const validatorUtils = __importStar(require("./validator-utils")); | ||
| /** | ||
| * Validator for iparamDefns | ||
| * Validates the sectioned iparams.json schema | ||
| */ | ||
| class IparamDefnsValidator { | ||
| constructor(fileSystem) { | ||
| this.fileSystem = fileSystem; | ||
| this.inputsValidator = new iparams_inputs_validator_1.IparamInputsValidator(fileSystem); | ||
| } | ||
| /** | ||
| * Validates and loads the iparamDefns from a file | ||
| * @param {string} path - Path to the iparams.json file | ||
| * @returns {IparamDefns} The validated iparamDefns | ||
| * @throws {Error} If the iparamDefns is invalid or cannot be read | ||
| */ | ||
| validateAndGetIparamDefnsFile(path) { | ||
| validatorUtils.ensureFileExists(this.fileSystem, path); | ||
| try { | ||
| const iparamDefns = JSON.parse(this.fileSystem.readFileSync(path, 'utf8')); | ||
| try { | ||
| this.validate(iparamDefns); | ||
| return iparamDefns; | ||
| } | ||
| catch (validationError) { | ||
| const err = new Error(validationError.message); | ||
| err.rawContent = iparamDefns; | ||
| throw err; | ||
| } | ||
| } | ||
| catch (error) { | ||
| if (error.rawContent !== undefined) { | ||
| throw error; | ||
| } | ||
| if (error instanceof SyntaxError) { | ||
| throw new Error(`Failed to parse ${iparam_constants_1.IPARAMS_JSON_FILENAME}: ${error.message}`); | ||
| } | ||
| throw new Error(`Failed to read ${iparam_constants_1.IPARAMS_JSON_FILENAME}: ${error.message}`); | ||
| } | ||
| } | ||
| /** | ||
| * Validates an iparamDefns object | ||
| * @param {IparamDefns} iparamDefns - The iparamDefns object to validate | ||
| * @throws {Error} If the iparamDefns is invalid | ||
| */ | ||
| validate(iparamDefns) { | ||
| if (!iparamDefns || typeof iparamDefns !== 'object' || Array.isArray(iparamDefns)) { | ||
| throw new Error(`${iparam_constants_1.IPARAMS_JSON_FILENAME} must be an object`); | ||
| } | ||
| this.rejectUnknownKeys(iparamDefns, iparam_constants_1.IPARAMS_ROOT_ALLOWED_KEYS, iparam_constants_1.IPARAMS_JSON_FILENAME); | ||
| if (!Object.prototype.hasOwnProperty.call(iparamDefns, iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL)) { | ||
| return; | ||
| } | ||
| const installationParameters = iparamDefns.installation_parameters; | ||
| if (!installationParameters || typeof installationParameters !== 'object' || Array.isArray(installationParameters)) { | ||
| throw new Error(`${iparam_constants_1.IPARAMS_JSON_FILENAME} must include ${iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL} as an object containing a ${iparam_constants_1.IPARAMS_SECTIONS_LABEL} array`); | ||
| } | ||
| this.rejectUnknownKeys(installationParameters, iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_ALLOWED_KEYS, iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL); | ||
| if (!Object.prototype.hasOwnProperty.call(installationParameters, iparam_constants_1.IPARAMS_SECTIONS_LABEL)) { | ||
| throw new Error(`${iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL} must include ${iparam_constants_1.IPARAMS_SECTIONS_LABEL} in ${iparam_constants_1.IPARAMS_JSON_FILENAME}`); | ||
| } | ||
| const sections = installationParameters.sections; | ||
| if (!Array.isArray(sections)) { | ||
| throw new Error(`${iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL}.${iparam_constants_1.IPARAMS_SECTIONS_LABEL} must be an array of section objects`); | ||
| } | ||
| if (sections.length === 0) { | ||
| throw new Error(`${iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL}.${iparam_constants_1.IPARAMS_SECTIONS_LABEL} must contain at least one section`); | ||
| } | ||
| for (let i = 0; i < sections.length; i++) { | ||
| this.validateSection(sections[i], i); | ||
| } | ||
| const totalParamCount = sections.reduce((count, section) => count + section.parameters.length, 0); | ||
| if (totalParamCount > iparam_constants_1.IPARAMS_MAX_COUNT) { | ||
| throw new Error(`${iparam_constants_1.IPARAMS_JSON_FILENAME} cannot define more than ${iparam_constants_1.IPARAMS_MAX_COUNT} parameters (found ${totalParamCount})`); | ||
| } | ||
| const sectionNames = sections.map((section) => section.name.trim()); | ||
| const seenSectionNames = new Set(); | ||
| const duplicateSections = []; | ||
| for (const name of sectionNames) { | ||
| if (seenSectionNames.has(name)) | ||
| duplicateSections.push(name); | ||
| else | ||
| seenSectionNames.add(name); | ||
| } | ||
| if (duplicateSections.length > 0) { | ||
| throw new Error(`Duplicate section names found: ${duplicateSections.join(', ')}`); | ||
| } | ||
| for (const section of sections) { | ||
| const paramNames = section.parameters.map((param) => param.name.trim()); | ||
| const seenParamNames = new Set(); | ||
| const duplicateParams = []; | ||
| for (const name of paramNames) { | ||
| if (seenParamNames.has(name)) | ||
| duplicateParams.push(name); | ||
| else | ||
| seenParamNames.add(name); | ||
| } | ||
| if (duplicateParams.length > 0) { | ||
| throw new Error(`Duplicate parameter names found in section "${section.name}": ${duplicateParams.join(', ')}`); | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * Validates a single section definition | ||
| * @param {any} section - The section definition to validate | ||
| * @param {number} index - The index of the section in the array (for error messages) | ||
| * @throws {Error} If the section is invalid | ||
| */ | ||
| validateSection(section, index) { | ||
| if (!section || typeof section !== 'object') { | ||
| throw new Error(`Section at index ${index} must be an object`); | ||
| } | ||
| const sectionName = this.validateSectionName(section, index); | ||
| this.requireNonEmptyStringField(section, sectionName, 'display_name', iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.DISPLAY_NAME, 'Section'); | ||
| this.requireNonEmptyStringField(section, sectionName, 'description', iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.DESCRIPTION, 'Section'); | ||
| const parameters = section['parameters']; | ||
| if (!Array.isArray(parameters)) { | ||
| throw new Error(`Section "${sectionName}": "parameters" must be an array`); | ||
| } | ||
| if (parameters.length === 0) { | ||
| throw new Error(`Section "${sectionName}": "parameters" must contain at least one parameter`); | ||
| } | ||
| for (let i = 0; i < parameters.length; i++) { | ||
| this.validateParameter(parameters[i], sectionName, i); | ||
| } | ||
| } | ||
| /** | ||
| * Validates a single parameter definition | ||
| * @param {any} param - The parameter definition to validate | ||
| * @param {string} sectionName - Parent section name for error messages | ||
| * @param {number} index - The index of the parameter in the section (for error messages) | ||
| * @throws {Error} If the parameter is invalid | ||
| */ | ||
| validateParameter(param, sectionName, index) { | ||
| if (!param || typeof param !== 'object') { | ||
| throw new Error(`Section "${sectionName}": parameter at index ${index} must be an object`); | ||
| } | ||
| const paramName = this.validateParamName(param, sectionName, index); | ||
| const sectionDotParam = `${sectionName}.${paramName}`; | ||
| this.requireNonEmptyStringField(param, sectionDotParam, 'display_name', iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.DISPLAY_NAME); | ||
| this.requireNonEmptyStringField(param, sectionDotParam, 'description', iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.DESCRIPTION); | ||
| this.validateType(param, sectionDotParam); | ||
| if (param.required !== undefined && typeof param.required !== 'boolean') { | ||
| throw new Error(`Parameter "${sectionDotParam}": "required" must be a boolean`); | ||
| } | ||
| this.validateOptions(param, sectionDotParam); | ||
| if (param.type === 'SECRET' && param.default !== undefined && param.default !== null) { | ||
| throw new Error(`Parameter "${sectionDotParam}": SECRET type cannot have a default value`); | ||
| } | ||
| this.validateDefaultValue(param, sectionDotParam); | ||
| } | ||
| requireNonEmptyStringField(entity, entityName, fieldName, maxLength, entityLabel = 'Parameter') { | ||
| const value = entity[fieldName]; | ||
| if (!validatorUtils.isNonEmptyString(value)) { | ||
| throw new Error(`${entityLabel} "${entityName}": "${fieldName}" must be a non-empty string`); | ||
| } | ||
| const trimmed = value.trim(); | ||
| if (maxLength !== undefined && trimmed.length > maxLength) { | ||
| throw new Error(`${entityLabel} "${entityName}": "${fieldName}" cannot exceed ${maxLength} characters`); | ||
| } | ||
| } | ||
| rejectUnknownKeys(entity, allowedKeys, entityLabel) { | ||
| for (const key of Object.keys(entity)) { | ||
| if (!allowedKeys.includes(key)) { | ||
| throw new Error(`${entityLabel} must only contain ${allowedKeys.map((k) => `"${k}"`).join(', ')}`); | ||
| } | ||
| } | ||
| } | ||
| validateSectionName(section, index) { | ||
| const name = section['name']; | ||
| if (!validatorUtils.isNonEmptyString(name)) { | ||
| throw new Error(`Section at index ${index}: "name" must be a non-empty string`); | ||
| } | ||
| const sectionName = name.trim(); | ||
| if (!/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(sectionName)) { | ||
| throw new Error(`Section "${sectionName}": "name" can only contain letters, numbers, underscores, and hyphens, and must start with a letter or underscore`); | ||
| } | ||
| if (sectionName.length > iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.NAME) { | ||
| throw new Error(`Section "${sectionName}": "name" must be between 1 and ${iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.NAME} characters`); | ||
| } | ||
| return sectionName; | ||
| } | ||
| validateParamName(param, sectionName, index) { | ||
| const name = param['name']; | ||
| if (!validatorUtils.isNonEmptyString(name)) { | ||
| throw new Error(`Section "${sectionName}": parameter at index ${index}: "name" must be a non-empty string`); | ||
| } | ||
| const paramName = name.trim(); | ||
| if (!/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(paramName)) { | ||
| throw new Error(`Parameter "${sectionName}.${paramName}": "name" can only contain letters, numbers, underscores, and hyphens, and must start with a letter or underscore`); | ||
| } | ||
| if (paramName.length > iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.NAME) { | ||
| throw new Error(`Parameter "${sectionName}.${paramName}": "name" must be between 1 and ${iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.NAME} characters`); | ||
| } | ||
| return paramName; | ||
| } | ||
| validateType(param, sectionDotParam) { | ||
| const type = param['type']; | ||
| if (!type || !common_1.VALID_IPARAM_TYPES.includes(type)) { | ||
| throw new Error(`Parameter "${sectionDotParam}": "type" must be one of: ${common_1.VALID_IPARAM_TYPES.join(', ')}`); | ||
| } | ||
| } | ||
| validateOptions(param, sectionDotParam) { | ||
| const paramType = param['type']; | ||
| if (paramType !== 'DROPDOWN' && paramType !== 'MULTISELECT_DROPDOWN') { | ||
| if (Object.prototype.hasOwnProperty.call(param, 'options')) { | ||
| throw new Error(`Parameter "${sectionDotParam}": "options" is only allowed for DROPDOWN and MULTISELECT_DROPDOWN types`); | ||
| } | ||
| return; | ||
| } | ||
| const options = param['options']; | ||
| if (!options || !Array.isArray(options) || options.length === 0) { | ||
| throw new Error(`Parameter "${sectionDotParam}": "options" is required and must be a non-empty array of strings for ${paramType} type`); | ||
| } | ||
| if (options.length > iparam_constants_1.OPTIONS_LIMITS.MAX_COUNT) { | ||
| throw new Error(`Parameter "${sectionDotParam}": "options" cannot exceed ${iparam_constants_1.OPTIONS_LIMITS.MAX_COUNT} items for ${paramType} type`); | ||
| } | ||
| const seenTrimmedOptions = new Set(); | ||
| for (let i = 0; i < options.length; i++) { | ||
| if (typeof options[i] !== 'string') { | ||
| throw new Error(`Parameter "${sectionDotParam}": option at index ${i} must be a string`); | ||
| } | ||
| const optionStr = options[i].trim(); | ||
| if (optionStr === '') { | ||
| throw new Error(`Parameter "${sectionDotParam}": option at index ${i} cannot be an empty string`); | ||
| } | ||
| if (seenTrimmedOptions.has(optionStr)) { | ||
| throw new Error(`Parameter "${sectionDotParam}": "options" must not contain duplicate entries`); | ||
| } | ||
| seenTrimmedOptions.add(optionStr); | ||
| if (optionStr.length > iparam_constants_1.OPTIONS_LIMITS.MAX_OPTION_LENGTH) { | ||
| throw new Error(`Parameter "${sectionDotParam}": option at index ${i} cannot exceed ${iparam_constants_1.OPTIONS_LIMITS.MAX_OPTION_LENGTH} characters`); | ||
| } | ||
| } | ||
| } | ||
| validateDefaultValue(param, sectionDotParam) { | ||
| const defaultValue = param['default']; | ||
| if (defaultValue === undefined || defaultValue === null) | ||
| return; | ||
| if (typeof defaultValue === 'string' && defaultValue.trim() === '') { | ||
| throw new Error(`Parameter "${sectionDotParam}": default value cannot be an empty string. Either remove the "default" key, set it to null, or provide a non-empty value.`); | ||
| } | ||
| try { | ||
| this.inputsValidator.validateParamValue(param, defaultValue, sectionDotParam); | ||
| } | ||
| catch (error) { | ||
| const msg = error.message.replace(/\bvalue\b/g, 'default value'); | ||
| throw new Error(msg); | ||
| } | ||
| } | ||
| } | ||
| exports.IparamDefnsValidator = IparamDefnsValidator; | ||
| "use strict";var __createBinding=this&&this.__createBinding||(Object.create?(function(s,e,t,r){r===void 0&&(r=t);var n=Object.getOwnPropertyDescriptor(e,t);(!n||("get"in n?!e.__esModule:n.writable||n.configurable))&&(n={enumerable:!0,get:function(){return e[t]}}),Object.defineProperty(s,r,n)}):(function(s,e,t,r){r===void 0&&(r=t),s[r]=e[t]})),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?(function(s,e){Object.defineProperty(s,"default",{enumerable:!0,value:e})}):function(s,e){s.default=e}),__importStar=this&&this.__importStar||(function(){var s=function(e){return s=Object.getOwnPropertyNames||function(t){var r=[];for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(r[r.length]=n);return r},s(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=s(e),n=0;n<r.length;n++)r[n]!=="default"&&__createBinding(t,e,r[n]);return __setModuleDefault(t,e),t}})();Object.defineProperty(exports,"__esModule",{value:!0}),exports.IparamDefnsValidator=void 0;const common_1=require("../types/common"),iparam_constants_1=require("./iparam-constants"),iparams_inputs_validator_1=require("./iparams-inputs-validator"),validatorUtils=__importStar(require("./validator-utils"));class IparamDefnsValidator{constructor(e){this.fileSystem=e,this.inputsValidator=new iparams_inputs_validator_1.IparamInputsValidator(e)}validateAndGetIparamDefnsFile(e){validatorUtils.ensureFileExists(this.fileSystem,e);try{const t=JSON.parse(this.fileSystem.readFileSync(e,"utf8"));try{return this.validate(t),t}catch(r){const n=new Error(r.message);throw n.rawContent=t,n}}catch(t){throw t.rawContent!==void 0?t:t instanceof SyntaxError?new Error(`Failed to parse ${iparam_constants_1.IPARAMS_JSON_FILENAME}: ${t.message}`):new Error(`Failed to read ${iparam_constants_1.IPARAMS_JSON_FILENAME}: ${t.message}`)}}validate(e){if(!e||typeof e!="object"||Array.isArray(e))throw new Error(`${iparam_constants_1.IPARAMS_JSON_FILENAME} must be an object`);if(this.rejectUnknownKeys(e,iparam_constants_1.IPARAMS_ROOT_ALLOWED_KEYS,iparam_constants_1.IPARAMS_JSON_FILENAME),!Object.prototype.hasOwnProperty.call(e,iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL))return;const t=e.installation_parameters;if(!t||typeof t!="object"||Array.isArray(t))throw new Error(`${iparam_constants_1.IPARAMS_JSON_FILENAME} must include ${iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL} as an object containing a ${iparam_constants_1.IPARAMS_SECTIONS_LABEL} array`);if(this.rejectUnknownKeys(t,iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_ALLOWED_KEYS,iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL),!Object.prototype.hasOwnProperty.call(t,iparam_constants_1.IPARAMS_SECTIONS_LABEL))throw new Error(`${iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL} must include ${iparam_constants_1.IPARAMS_SECTIONS_LABEL} in ${iparam_constants_1.IPARAMS_JSON_FILENAME}`);const r=t.sections;if(!Array.isArray(r))throw new Error(`${iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL}.${iparam_constants_1.IPARAMS_SECTIONS_LABEL} must be an array of section objects`);if(r.length===0)throw new Error(`${iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL}.${iparam_constants_1.IPARAMS_SECTIONS_LABEL} must contain at least one section`);for(let o=0;o<r.length;o++)this.validateSection(r[o],o);const n=r.reduce((o,l)=>o+l.parameters.length,0);if(n>iparam_constants_1.IPARAMS_MAX_COUNT)throw new Error(`${iparam_constants_1.IPARAMS_JSON_FILENAME} cannot define more than ${iparam_constants_1.IPARAMS_MAX_COUNT} parameters (found ${n})`);const a=r.map(o=>o.name.trim()),i=new Set,c=[];for(const o of a)i.has(o)?c.push(o):i.add(o);if(c.length>0)throw new Error(`Duplicate section names found: ${c.join(", ")}`);for(const o of r){const l=o.parameters.map(A=>A.name.trim()),E=new Set,u=[];for(const A of l)E.has(A)?u.push(A):E.add(A);if(u.length>0)throw new Error(`Duplicate parameter names found in section "${o.name}": ${u.join(", ")}`)}}validateSection(e,t){if(!e||typeof e!="object")throw new Error(`Section at index ${t} must be an object`);const r=this.validateSectionName(e,t);this.requireNonEmptyStringField(e,r,"display_name",iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.DISPLAY_NAME,"Section"),this.requireNonEmptyStringField(e,r,"description",iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.DESCRIPTION,"Section");const n=e.parameters;if(!Array.isArray(n))throw new Error(`Section "${r}": "parameters" must be an array`);if(n.length===0)throw new Error(`Section "${r}": "parameters" must contain at least one parameter`);for(let a=0;a<n.length;a++)this.validateParameter(n[a],r,a)}validateParameter(e,t,r){if(!e||typeof e!="object")throw new Error(`Section "${t}": parameter at index ${r} must be an object`);const n=this.validateParamName(e,t,r),a=`${t}.${n}`;if(this.requireNonEmptyStringField(e,a,"display_name",iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.DISPLAY_NAME),this.requireNonEmptyStringField(e,a,"description",iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.DESCRIPTION),this.validateType(e,a),e.required!==void 0&&typeof e.required!="boolean")throw new Error(`Parameter "${a}": "required" must be a boolean`);if(this.validateOptions(e,a),e.type==="SECRET"&&e.default!==void 0&&e.default!==null)throw new Error(`Parameter "${a}": SECRET type cannot have a default value`);this.validateDefaultValue(e,a)}requireNonEmptyStringField(e,t,r,n,a="Parameter"){const i=e[r];if(!validatorUtils.isNonEmptyString(i))throw new Error(`${a} "${t}": "${r}" must be a non-empty string`);const c=i.trim();if(n!==void 0&&c.length>n)throw new Error(`${a} "${t}": "${r}" cannot exceed ${n} characters`)}rejectUnknownKeys(e,t,r){for(const n of Object.keys(e))if(!t.includes(n))throw new Error(`${r} must only contain ${t.map(a=>`"${a}"`).join(", ")}`)}validateSectionName(e,t){const r=e.name;if(!validatorUtils.isNonEmptyString(r))throw new Error(`Section at index ${t}: "name" must be a non-empty string`);const n=r.trim();if(!/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(n))throw new Error(`Section "${n}": "name" can only contain letters, numbers, underscores, and hyphens, and must start with a letter or underscore`);if(n.length>iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.NAME)throw new Error(`Section "${n}": "name" must be between 1 and ${iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.NAME} characters`);return n}validateParamName(e,t,r){const n=e.name;if(!validatorUtils.isNonEmptyString(n))throw new Error(`Section "${t}": parameter at index ${r}: "name" must be a non-empty string`);const a=n.trim();if(!/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(a))throw new Error(`Parameter "${t}.${a}": "name" can only contain letters, numbers, underscores, and hyphens, and must start with a letter or underscore`);if(a.length>iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.NAME)throw new Error(`Parameter "${t}.${a}": "name" must be between 1 and ${iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.NAME} characters`);return a}validateType(e,t){const r=e.type;if(!r||!common_1.VALID_IPARAM_TYPES.includes(r))throw new Error(`Parameter "${t}": "type" must be one of: ${common_1.VALID_IPARAM_TYPES.join(", ")}`)}validateOptions(e,t){const r=e.type;if(r!=="DROPDOWN"&&r!=="MULTISELECT_DROPDOWN"){if(Object.prototype.hasOwnProperty.call(e,"options"))throw new Error(`Parameter "${t}": "options" is only allowed for DROPDOWN and MULTISELECT_DROPDOWN types`);return}const n=e.options;if(!n||!Array.isArray(n)||n.length===0)throw new Error(`Parameter "${t}": "options" is required and must be a non-empty array of strings for ${r} type`);if(n.length>iparam_constants_1.OPTIONS_LIMITS.MAX_COUNT)throw new Error(`Parameter "${t}": "options" cannot exceed ${iparam_constants_1.OPTIONS_LIMITS.MAX_COUNT} items for ${r} type`);const a=new Set;for(let i=0;i<n.length;i++){if(typeof n[i]!="string")throw new Error(`Parameter "${t}": option at index ${i} must be a string`);const c=n[i].trim();if(c==="")throw new Error(`Parameter "${t}": option at index ${i} cannot be an empty string`);if(a.has(c))throw new Error(`Parameter "${t}": "options" must not contain duplicate entries`);if(a.add(c),c.length>iparam_constants_1.OPTIONS_LIMITS.MAX_OPTION_LENGTH)throw new Error(`Parameter "${t}": option at index ${i} cannot exceed ${iparam_constants_1.OPTIONS_LIMITS.MAX_OPTION_LENGTH} characters`)}}validateDefaultValue(e,t){const r=e.default;if(r!=null){if(typeof r=="string"&&r.trim()==="")throw new Error(`Parameter "${t}": default value cannot be an empty string. Either remove the "default" key, set it to null, or provide a non-empty value.`);try{this.inputsValidator.validateParamValue(e,r,t)}catch(n){const a=n.message.replace(/\bvalue\b/g,"default value");throw new Error(a)}}}}exports.IparamDefnsValidator=IparamDefnsValidator; |
@@ -1,289 +0,1 @@ | ||
| "use strict"; | ||
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| var desc = Object.getOwnPropertyDescriptor(m, k); | ||
| if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
| desc = { enumerable: true, get: function() { return m[k]; } }; | ||
| } | ||
| Object.defineProperty(o, k2, desc); | ||
| }) : (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| o[k2] = m[k]; | ||
| })); | ||
| var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
| Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
| }) : function(o, v) { | ||
| o["default"] = v; | ||
| }); | ||
| var __importStar = (this && this.__importStar) || (function () { | ||
| var ownKeys = function(o) { | ||
| ownKeys = Object.getOwnPropertyNames || function (o) { | ||
| var ar = []; | ||
| for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; | ||
| return ar; | ||
| }; | ||
| return ownKeys(o); | ||
| }; | ||
| return function (mod) { | ||
| if (mod && mod.__esModule) return mod; | ||
| var result = {}; | ||
| if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); | ||
| __setModuleDefault(result, mod); | ||
| return result; | ||
| }; | ||
| })(); | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.IparamInputsValidator = void 0; | ||
| const errors_1 = require("../errors"); | ||
| const internal_logger_1 = require("../logger/internal-logger"); | ||
| const iparam_constants_1 = require("./iparam-constants"); | ||
| const validatorUtils = __importStar(require("./validator-utils")); | ||
| /** | ||
| * Validator for parameter inputs | ||
| * Validates input values against the sectioned iparamDefns | ||
| */ | ||
| class IparamInputsValidator { | ||
| constructor(fileSystem) { | ||
| this.fileSystem = fileSystem; | ||
| } | ||
| /** | ||
| * Validates whether the value counts as a provided input. | ||
| * Not whether it is allowed by iparam definitions—that is handled by {@link IparamInputsValidator.validateInputs}. | ||
| */ | ||
| static isProvidedIparamInputValue(value) { | ||
| if (value === undefined || value === null) | ||
| return false; | ||
| if (typeof value === 'string') | ||
| return value.trim() !== ''; | ||
| if (Array.isArray(value)) | ||
| return value.length > 0; | ||
| return true; | ||
| } | ||
| /** | ||
| * Validates and loads the iparam inputs from a file (no validation against iparamDefns). | ||
| * Only ensures the file is valid JSON and the root value is an object. | ||
| * @param {string} path - Path to the iparams.local.json file | ||
| * @returns {IparamInputs} The loaded inputs | ||
| * @throws {Error} If the file does not exist, cannot be read or parsed, or root is not an object | ||
| */ | ||
| validateAndGetIparamInputsFile(path) { | ||
| validatorUtils.ensureFileExists(this.fileSystem, path); | ||
| try { | ||
| const inputs = JSON.parse(this.fileSystem.readFileSync(path, 'utf8')); | ||
| if (typeof inputs !== 'object' || Array.isArray(inputs)) { | ||
| throw new Error('iparams.local.json must be an object'); | ||
| } | ||
| return inputs; | ||
| } | ||
| catch (error) { | ||
| if (error instanceof SyntaxError) { | ||
| throw new Error(`Failed to parse iparams.local.json: ${error.message}`); | ||
| } | ||
| throw new Error(`Failed to read iparams.local.json: ${error.message}`); | ||
| } | ||
| } | ||
| /** | ||
| * Ensures the inputs value is a plain object | ||
| * @param {any} inputs - The value to check | ||
| * @throws {Error} If inputs is not a plain object | ||
| */ | ||
| ensureInputsIsObject(inputs) { | ||
| if (inputs === null || typeof inputs !== 'object' || Array.isArray(inputs)) { | ||
| throw new Error('Inputs must be an object'); | ||
| } | ||
| } | ||
| /** | ||
| * Validates inputs against the iparamDefns (without applying defaults) | ||
| * Only validates provided values, does not include defaults in the result | ||
| * @param {IparamInputs} inputs - The input values to validate | ||
| * @param {IparamDefns} iparamDefns - The iparamDefns | ||
| * @returns {IparamInputs} The validated inputs (only provided values, no defaults) | ||
| * @throws {Error} If validation fails | ||
| * @throws {MissingRequiredParamsError} If required parameters are missing | ||
| */ | ||
| validateInputs(inputs, iparamDefns) { | ||
| this.ensureInputsIsObject(inputs); | ||
| const validatedInputs = {}; | ||
| const missingRequired = []; | ||
| const sections = iparamDefns.installation_parameters?.sections ?? []; | ||
| const sectionByName = new Map(sections.map((section) => [section.name, section])); | ||
| for (const section of sections) { | ||
| const sectionInputs = inputs[section.name]; | ||
| if (sectionInputs !== undefined && sectionInputs !== null) { | ||
| if (typeof sectionInputs !== 'object' || Array.isArray(sectionInputs)) { | ||
| throw new Error(`Section "${section.name}": inputs must be an object`); | ||
| } | ||
| } | ||
| const sectionObject = {}; | ||
| for (const param of section.parameters) { | ||
| const sectionDotParam = `${section.name}.${param.name}`; | ||
| const value = sectionInputs?.[param.name]; | ||
| if (IparamInputsValidator.isProvidedIparamInputValue(value)) { | ||
| this.validateParamValue(param, value, sectionDotParam); | ||
| sectionObject[param.name] = value; | ||
| } | ||
| else if (param.required && (param.default === undefined || param.default === null)) { | ||
| missingRequired.push(sectionDotParam); | ||
| } | ||
| } | ||
| if (Object.keys(sectionObject).length > 0) { | ||
| validatedInputs[section.name] = sectionObject; | ||
| } | ||
| } | ||
| if (missingRequired.length > 0) { | ||
| throw new errors_1.MissingRequiredParamsError(missingRequired); | ||
| } | ||
| for (const [sectionName, sectionInputs] of Object.entries(inputs)) { | ||
| const section = sectionByName.get(sectionName); | ||
| if (!section) { | ||
| internal_logger_1.__logger.warn(`Unknown section "${sectionName}" will be ignored`); | ||
| continue; | ||
| } | ||
| if (sectionInputs === undefined || sectionInputs === null) | ||
| continue; | ||
| if (typeof sectionInputs !== 'object' || Array.isArray(sectionInputs)) | ||
| continue; | ||
| const knownParamNames = new Set(section.parameters.map((param) => param.name)); | ||
| for (const key of Object.keys(sectionInputs)) { | ||
| if (!knownParamNames.has(key)) { | ||
| internal_logger_1.__logger.warn(`Unknown parameter "${sectionName}.${key}" will be ignored`); | ||
| } | ||
| } | ||
| } | ||
| return validatedInputs; | ||
| } | ||
| /** | ||
| * Validates a single parameter value against its parameter definition. | ||
| * @param {IparamDefn} param - The parameter definition | ||
| * @param {any} value - The value to validate | ||
| * @param {string} [sectionDotParam] - Optional section.param identifier for error messages (e.g. processing_fee_configuration.fee_percentage) | ||
| * @throws {Error} If the value is invalid | ||
| */ | ||
| validateParamValue(param, value, sectionDotParam = param.name) { | ||
| switch (param.type) { | ||
| case 'NUMBER': | ||
| this.validateNumber(sectionDotParam, value); | ||
| break; | ||
| case 'TEXT': | ||
| this.requireNonEmptyString(sectionDotParam, value, iparam_constants_1.IPARAM_VALUE_MAX_LENGTHS.TEXT); | ||
| break; | ||
| case 'SECRET': | ||
| this.requireNonEmptyString(sectionDotParam, value, iparam_constants_1.IPARAM_VALUE_MAX_LENGTHS.SECRET); | ||
| break; | ||
| case 'BOOLEAN': | ||
| this.validateBoolean(sectionDotParam, value); | ||
| break; | ||
| case 'URL': | ||
| this.validateUrl(sectionDotParam, value); | ||
| break; | ||
| case 'DATE': | ||
| this.validateDate(sectionDotParam, value); | ||
| break; | ||
| case 'DROPDOWN': | ||
| this.validateDropdown(param, value, sectionDotParam); | ||
| break; | ||
| case 'MULTISELECT_DROPDOWN': | ||
| this.validateMultiselectDropdown(param, value, sectionDotParam); | ||
| break; | ||
| default: { | ||
| const exhaustive = param.type; | ||
| throw new Error(`Parameter "${sectionDotParam}": unknown type "${exhaustive}"`); | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * Requires value to be a non-empty string, optionally with max length. | ||
| * @throws {Error} If not a string, empty after trim, or exceeds maxLength | ||
| */ | ||
| requireNonEmptyString(paramName, value, maxLength) { | ||
| if (!validatorUtils.isNonEmptyString(value)) { | ||
| throw new Error(`Parameter "${paramName}": value must be a non-empty string`); | ||
| } | ||
| if (maxLength !== undefined && value.length > maxLength) { | ||
| throw new Error(`Parameter "${paramName}": value cannot exceed ${maxLength} characters`); | ||
| } | ||
| } | ||
| /** | ||
| * Requires value to be one of the allowed options. | ||
| */ | ||
| requireInOptions(paramName, value, options) { | ||
| if (options.length === 0 || options.includes(value)) | ||
| return; | ||
| throw new Error(`Parameter "${paramName}": value must be one of: ${options.join(', ')}`); | ||
| } | ||
| validateNumber(paramName, value) { | ||
| if (typeof value !== 'number' || !Number.isFinite(value)) { | ||
| throw new Error(`Parameter "${paramName}": value must be a finite number`); | ||
| } | ||
| if (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER) { | ||
| throw new Error(`Parameter "${paramName}": value must be within the range of ${Number.MIN_SAFE_INTEGER} to ${Number.MAX_SAFE_INTEGER}`); | ||
| } | ||
| } | ||
| validateBoolean(paramName, value) { | ||
| if (typeof value !== 'boolean') { | ||
| throw new Error(`Parameter "${paramName}": value must be a boolean`); | ||
| } | ||
| } | ||
| validateUrl(paramName, value) { | ||
| this.requireNonEmptyString(paramName, value, iparam_constants_1.IPARAM_VALUE_MAX_LENGTHS.URL); | ||
| let parsed; | ||
| try { | ||
| parsed = new URL(value); | ||
| } | ||
| catch { | ||
| throw new Error(`Parameter "${paramName}": value must be a valid URL`); | ||
| } | ||
| if (!iparam_constants_1.IPARAM_URL_ALLOWED_PROTOCOLS.some((p) => p === parsed.protocol)) { | ||
| throw new Error(`Parameter "${paramName}": value must be a valid URL with protocol ${iparam_constants_1.IPARAM_URL_ALLOWED_PROTOCOLS.join(' or ')}`); | ||
| } | ||
| } | ||
| validateDate(paramName, value) { | ||
| this.requireNonEmptyString(paramName, value, iparam_constants_1.IPARAM_VALUE_MAX_LENGTHS.DATE); | ||
| const str = value; | ||
| if (!/^\d{4}-\d{2}-\d{2}$/.test(str)) { | ||
| throw new Error(`Parameter "${paramName}": value must be a valid date in YYYY-MM-DD format (e.g., 2025-12-31)`); | ||
| } | ||
| const [y, m, d] = str.split('-').map(Number); | ||
| const dateObj = new Date(Date.UTC(y, m - 1, d)); | ||
| if (isNaN(dateObj.getTime()) || | ||
| dateObj.getUTCFullYear() !== y || | ||
| dateObj.getUTCMonth() !== m - 1 || | ||
| dateObj.getUTCDate() !== d) { | ||
| throw new Error(`Parameter "${paramName}": value must be a valid date in YYYY-MM-DD format (e.g., 2025-12-31)`); | ||
| } | ||
| } | ||
| validateDropdown(param, value, sectionDotParam) { | ||
| if (typeof value !== 'string') { | ||
| throw new Error(`Parameter "${sectionDotParam}": value must be a string for DROPDOWN type`); | ||
| } | ||
| this.requireNonEmptyString(sectionDotParam, value); | ||
| if (param.options) | ||
| this.requireInOptions(sectionDotParam, value, param.options); | ||
| } | ||
| validateMultiselectDropdown(param, value, sectionDotParam) { | ||
| if (!Array.isArray(value)) { | ||
| throw new Error(`Parameter "${sectionDotParam}": value must be an array of strings for MULTISELECT_DROPDOWN type`); | ||
| } | ||
| if (value.length === 0) { | ||
| throw new Error(`Parameter "${sectionDotParam}": value must be a non-empty array of strings for MULTISELECT_DROPDOWN type`); | ||
| } | ||
| const seenTrimmed = new Set(); | ||
| for (let i = 0; i < value.length; i++) { | ||
| try { | ||
| this.requireNonEmptyString(sectionDotParam, value[i]); | ||
| if (param.options) | ||
| this.requireInOptions(sectionDotParam, value[i], param.options); | ||
| } | ||
| catch (error) { | ||
| const msg = error.message.replace(/\bvalue\b/g, `value array item at index ${i}`); | ||
| throw new Error(msg); | ||
| } | ||
| const trimmed = value[i].trim(); | ||
| if (seenTrimmed.has(trimmed)) { | ||
| throw new Error(`Parameter "${sectionDotParam}": multiselect value must not contain duplicate entries`); | ||
| } | ||
| seenTrimmed.add(trimmed); | ||
| } | ||
| } | ||
| } | ||
| exports.IparamInputsValidator = IparamInputsValidator; | ||
| "use strict";var __createBinding=this&&this.__createBinding||(Object.create?(function(s,e,r,t){t===void 0&&(t=r);var n=Object.getOwnPropertyDescriptor(e,r);(!n||("get"in n?!e.__esModule:n.writable||n.configurable))&&(n={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(s,t,n)}):(function(s,e,r,t){t===void 0&&(t=r),s[t]=e[r]})),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?(function(s,e){Object.defineProperty(s,"default",{enumerable:!0,value:e})}):function(s,e){s.default=e}),__importStar=this&&this.__importStar||(function(){var s=function(e){return s=Object.getOwnPropertyNames||function(r){var t=[];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(t[t.length]=n);return t},s(e)};return function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var t=s(e),n=0;n<t.length;n++)t[n]!=="default"&&__createBinding(r,e,t[n]);return __setModuleDefault(r,e),r}})();Object.defineProperty(exports,"__esModule",{value:!0}),exports.IparamInputsValidator=void 0;const errors_1=require("../errors"),internal_logger_1=require("../logger/internal-logger"),iparam_constants_1=require("./iparam-constants"),validatorUtils=__importStar(require("./validator-utils"));class IparamInputsValidator{constructor(e){this.fileSystem=e}static isProvidedIparamInputValue(e){return e==null?!1:typeof e=="string"?e.trim()!=="":Array.isArray(e)?e.length>0:!0}validateAndGetIparamInputsFile(e){validatorUtils.ensureFileExists(this.fileSystem,e);try{const r=JSON.parse(this.fileSystem.readFileSync(e,"utf8"));if(typeof r!="object"||Array.isArray(r))throw new Error("iparams.local.json must be an object");return r}catch(r){throw r instanceof SyntaxError?new Error(`Failed to parse iparams.local.json: ${r.message}`):new Error(`Failed to read iparams.local.json: ${r.message}`)}}ensureInputsIsObject(e){if(e===null||typeof e!="object"||Array.isArray(e))throw new Error("Inputs must be an object")}validateInputs(e,r){this.ensureInputsIsObject(e);const t={},n=[],o=r.installation_parameters?.sections??[],l=new Map(o.map(i=>[i.name,i]));for(const i of o){const a=e[i.name];if(a!=null&&(typeof a!="object"||Array.isArray(a)))throw new Error(`Section "${i.name}": inputs must be an object`);const f={};for(const u of i.parameters){const c=`${i.name}.${u.name}`,d=a?.[u.name];IparamInputsValidator.isProvidedIparamInputValue(d)?(this.validateParamValue(u,d,c),f[u.name]=d):u.required&&(u.default===void 0||u.default===null)&&n.push(c)}Object.keys(f).length>0&&(t[i.name]=f)}if(n.length>0)throw new errors_1.MissingRequiredParamsError(n);for(const[i,a]of Object.entries(e)){const f=l.get(i);if(!f){internal_logger_1.__logger.warn(`Unknown section "${i}" will be ignored`);continue}if(a==null||typeof a!="object"||Array.isArray(a))continue;const u=new Set(f.parameters.map(c=>c.name));for(const c of Object.keys(a))u.has(c)||internal_logger_1.__logger.warn(`Unknown parameter "${i}.${c}" will be ignored`)}return t}validateParamValue(e,r,t=e.name){switch(e.type){case"NUMBER":this.validateNumber(t,r);break;case"TEXT":this.requireNonEmptyString(t,r,iparam_constants_1.IPARAM_VALUE_MAX_LENGTHS.TEXT);break;case"SECRET":this.requireNonEmptyString(t,r,iparam_constants_1.IPARAM_VALUE_MAX_LENGTHS.SECRET);break;case"BOOLEAN":this.validateBoolean(t,r);break;case"URL":this.validateUrl(t,r);break;case"DATE":this.validateDate(t,r);break;case"DROPDOWN":this.validateDropdown(e,r,t);break;case"MULTISELECT_DROPDOWN":this.validateMultiselectDropdown(e,r,t);break;default:{const n=e.type;throw new Error(`Parameter "${t}": unknown type "${n}"`)}}}requireNonEmptyString(e,r,t){if(!validatorUtils.isNonEmptyString(r))throw new Error(`Parameter "${e}": value must be a non-empty string`);if(t!==void 0&&r.length>t)throw new Error(`Parameter "${e}": value cannot exceed ${t} characters`)}requireInOptions(e,r,t){if(!(t.length===0||t.includes(r)))throw new Error(`Parameter "${e}": value must be one of: ${t.join(", ")}`)}validateNumber(e,r){if(typeof r!="number"||!Number.isFinite(r))throw new Error(`Parameter "${e}": value must be a finite number`);if(r>Number.MAX_SAFE_INTEGER||r<Number.MIN_SAFE_INTEGER)throw new Error(`Parameter "${e}": value must be within the range of ${Number.MIN_SAFE_INTEGER} to ${Number.MAX_SAFE_INTEGER}`)}validateBoolean(e,r){if(typeof r!="boolean")throw new Error(`Parameter "${e}": value must be a boolean`)}validateUrl(e,r){this.requireNonEmptyString(e,r,iparam_constants_1.IPARAM_VALUE_MAX_LENGTHS.URL);let t;try{t=new URL(r)}catch{throw new Error(`Parameter "${e}": value must be a valid URL`)}if(!iparam_constants_1.IPARAM_URL_ALLOWED_PROTOCOLS.some(n=>n===t.protocol))throw new Error(`Parameter "${e}": value must be a valid URL with protocol ${iparam_constants_1.IPARAM_URL_ALLOWED_PROTOCOLS.join(" or ")}`)}validateDate(e,r){this.requireNonEmptyString(e,r,iparam_constants_1.IPARAM_VALUE_MAX_LENGTHS.DATE);const t=r;if(!/^\d{4}-\d{2}-\d{2}$/.test(t))throw new Error(`Parameter "${e}": value must be a valid date in YYYY-MM-DD format (e.g., 2025-12-31)`);const[n,o,l]=t.split("-").map(Number),i=new Date(Date.UTC(n,o-1,l));if(isNaN(i.getTime())||i.getUTCFullYear()!==n||i.getUTCMonth()!==o-1||i.getUTCDate()!==l)throw new Error(`Parameter "${e}": value must be a valid date in YYYY-MM-DD format (e.g., 2025-12-31)`)}validateDropdown(e,r,t){if(typeof r!="string")throw new Error(`Parameter "${t}": value must be a string for DROPDOWN type`);this.requireNonEmptyString(t,r),e.options&&this.requireInOptions(t,r,e.options)}validateMultiselectDropdown(e,r,t){if(!Array.isArray(r))throw new Error(`Parameter "${t}": value must be an array of strings for MULTISELECT_DROPDOWN type`);if(r.length===0)throw new Error(`Parameter "${t}": value must be a non-empty array of strings for MULTISELECT_DROPDOWN type`);const n=new Set;for(let o=0;o<r.length;o++){try{this.requireNonEmptyString(t,r[o]),e.options&&this.requireInOptions(t,r[o],e.options)}catch(i){const a=i.message.replace(/\bvalue\b/g,`value array item at index ${o}`);throw new Error(a)}const l=r[o].trim();if(n.has(l))throw new Error(`Parameter "${t}": multiselect value must not contain duplicate entries`);n.add(l)}}}exports.IparamInputsValidator=IparamInputsValidator; |
@@ -1,138 +0,1 @@ | ||
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.ManifestValidator = void 0; | ||
| const semver_1 = __importDefault(require("semver")); | ||
| const internal_logger_1 = require("../logger/internal-logger"); | ||
| /** | ||
| * ManifestValidator provides validation for Chargebee Apps application manifests | ||
| * Public implementation for validating user applications | ||
| */ | ||
| class ManifestValidator { | ||
| constructor(allowedModulesConfig, fileSystem) { | ||
| this.allowedModules = allowedModulesConfig || []; | ||
| this.fileSystem = fileSystem; | ||
| } | ||
| /** | ||
| * Validates a manifest file from disk | ||
| * @param {string} path - Path to the manifest.json file | ||
| * @returns {Object} The validated manifest | ||
| * @throws {Error} If manifest file is invalid or cannot be read | ||
| */ | ||
| validateAndGetManifestFile(path) { | ||
| if (!this.fileSystem.existsSync(path)) { | ||
| throw new Error(`manifest.json not found in user code directory`); | ||
| } | ||
| try { | ||
| const manifestContent = this.fileSystem.readFileSync(path, 'utf8'); | ||
| const manifest = JSON.parse(manifestContent); | ||
| this.validate(manifest); | ||
| return manifest; | ||
| } | ||
| catch (error) { | ||
| if (error instanceof SyntaxError) { | ||
| throw new Error(`Failed to parse manifest file: ${error.message}`); | ||
| } | ||
| const err = error; | ||
| throw new Error(`Failed to read manifest file: ${err.message}`); | ||
| } | ||
| } | ||
| /** | ||
| * Validates a complete manifest object | ||
| * @param {Manifest} manifest - The manifest object to validate | ||
| * @returns {Manifest} The validated manifest | ||
| * @throws {Error} If manifest is invalid | ||
| */ | ||
| validate(manifest) { | ||
| // Basic structure validation | ||
| this.validateBasicStructure(manifest); | ||
| // Events validation | ||
| this.validateEvents(manifest); | ||
| // Dependencies validation | ||
| this.validateDependencies(manifest); | ||
| // Metadata validation | ||
| this.validateMetadata(manifest); | ||
| } | ||
| /** | ||
| * Validates the basic structure of the manifest | ||
| * @param {Object} manifest - The manifest object | ||
| * @throws {Error} If basic structure is invalid | ||
| */ | ||
| validateBasicStructure(manifest) { | ||
| if (!manifest || typeof manifest !== 'object') { | ||
| throw new Error('Manifest must be a valid object'); | ||
| } | ||
| if (manifest.events && typeof manifest.events !== 'object') { | ||
| throw new Error('Events mapping must be an object'); | ||
| } | ||
| if (manifest.dependencies && typeof manifest.dependencies !== 'object') { | ||
| throw new Error('Dependencies must be an object'); | ||
| } | ||
| } | ||
| /** | ||
| * Validates the events configuration | ||
| * @param {Object} manifest - The manifest object | ||
| * @throws {Error} If events configuration is invalid | ||
| */ | ||
| validateEvents(manifest) { | ||
| if (!manifest.events) { | ||
| throw new Error('Invalid manifest: missing "events" mapping'); | ||
| } | ||
| for (const [eventType, handler] of Object.entries(manifest.events)) { | ||
| if (!handler || typeof handler !== 'object') { | ||
| throw new Error(`Handler name for event "${eventType}" must be a non-empty string`); | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * Validates the dependencies configuration | ||
| * @param {Object} manifest - The manifest object | ||
| * @throws {Error} If dependencies are invalid | ||
| */ | ||
| validateDependencies(manifest) { | ||
| if (!manifest.dependencies) { | ||
| return; // Dependencies are optional | ||
| } | ||
| if (typeof manifest.dependencies !== 'object') { | ||
| throw new Error('Invalid manifest: "dependencies" must be an object'); | ||
| } | ||
| for (const [depName, depVersion] of Object.entries(manifest.dependencies)) { | ||
| if (typeof depName !== 'string' || typeof depVersion !== 'string') { | ||
| throw new Error(`Invalid dependency in manifest: "${depName}" must have string name and version`); | ||
| } | ||
| // Check if module is allowed | ||
| const allowedModule = this.allowedModules.find(module => module.name === depName); | ||
| if (!allowedModule) { | ||
| throw new Error(`Dependency "${depName}" is not allowed in this environment`); | ||
| } | ||
| // Validate version range | ||
| if (!semver_1.default.validRange(depVersion)) { | ||
| throw new Error(`Invalid version range "${depVersion}" for dependency "${depName}"`); | ||
| } | ||
| // Check version constraints if specified | ||
| if (allowedModule.version) { | ||
| if (!semver_1.default.satisfies(depVersion, allowedModule.version)) { | ||
| internal_logger_1.__logger.warn(`Dependency "${depName}" version range "${depVersion}" differs from allowed version constraint "${allowedModule.version}" - proceeding with warning`); | ||
| } | ||
| } | ||
| else { | ||
| throw new Error(`Configuration error: Allowed module "${depName}" does not have a version constraint`); | ||
| } | ||
| internal_logger_1.__logger.debug(`Dependency "${depName}" version "${depVersion}" is allowed`); | ||
| } | ||
| internal_logger_1.__logger.debug(`Validated ${Object.keys(manifest.dependencies).length} dependencies in manifest`); | ||
| } | ||
| /** | ||
| * Validates the metadata fields | ||
| * @param {Object} manifest - The manifest object | ||
| */ | ||
| validateMetadata(manifest) { | ||
| // Check for reasonable limits | ||
| if (manifest.dependencies && Object.keys(manifest.dependencies).length > 10) { | ||
| internal_logger_1.__logger.warn('Large number of dependencies detected - consider minimizing dependencies for better performance'); | ||
| } | ||
| } | ||
| } | ||
| exports.ManifestValidator = ManifestValidator; | ||
| "use strict";var __importDefault=this&&this.__importDefault||function(r){return r&&r.__esModule?r:{default:r}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.ManifestValidator=void 0;const semver_1=__importDefault(require("semver")),internal_logger_1=require("../logger/internal-logger");class ManifestValidator{constructor(e,n){this.allowedModules=e||[],this.fileSystem=n}validateAndGetManifestFile(e){if(!this.fileSystem.existsSync(e))throw new Error("manifest.json not found in user code directory");try{const n=this.fileSystem.readFileSync(e,"utf8"),t=JSON.parse(n);return this.validate(t),t}catch(n){if(n instanceof SyntaxError)throw new Error(`Failed to parse manifest file: ${n.message}`);const t=n;throw new Error(`Failed to read manifest file: ${t.message}`)}}validate(e){this.validateBasicStructure(e),this.validateEvents(e),this.validateDependencies(e),this.validateMetadata(e)}validateBasicStructure(e){if(!e||typeof e!="object")throw new Error("Manifest must be a valid object");if(e.events&&typeof e.events!="object")throw new Error("Events mapping must be an object");if(e.dependencies&&typeof e.dependencies!="object")throw new Error("Dependencies must be an object")}validateEvents(e){if(!e.events)throw new Error('Invalid manifest: missing "events" mapping');for(const[n,t]of Object.entries(e.events))if(!t||typeof t!="object")throw new Error(`Handler name for event "${n}" must be a non-empty string`)}validateDependencies(e){if(e.dependencies){if(typeof e.dependencies!="object")throw new Error('Invalid manifest: "dependencies" must be an object');for(const[n,t]of Object.entries(e.dependencies)){if(typeof n!="string"||typeof t!="string")throw new Error(`Invalid dependency in manifest: "${n}" must have string name and version`);const i=this.allowedModules.find(o=>o.name===n);if(!i)throw new Error(`Dependency "${n}" is not allowed in this environment`);if(!semver_1.default.validRange(t))throw new Error(`Invalid version range "${t}" for dependency "${n}"`);if(i.version)semver_1.default.satisfies(t,i.version)||internal_logger_1.__logger.warn(`Dependency "${n}" version range "${t}" differs from allowed version constraint "${i.version}" - proceeding with warning`);else throw new Error(`Configuration error: Allowed module "${n}" does not have a version constraint`);internal_logger_1.__logger.debug(`Dependency "${n}" version "${t}" is allowed`)}internal_logger_1.__logger.debug(`Validated ${Object.keys(e.dependencies).length} dependencies in manifest`)}}validateMetadata(e){e.dependencies&&Object.keys(e.dependencies).length>10&&internal_logger_1.__logger.warn("Large number of dependencies detected - consider minimizing dependencies for better performance")}}exports.ManifestValidator=ManifestValidator; |
@@ -1,43 +0,1 @@ | ||
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.PackageValidator = void 0; | ||
| const path_1 = __importDefault(require("path")); | ||
| /** | ||
| * Package validator for validating app structure. | ||
| * This primarily validates the app directory and the structure of the app which developer bundles and uploads to Chargebee. | ||
| */ | ||
| class PackageValidator { | ||
| constructor(fileSystem) { | ||
| this.fileSystem = fileSystem; | ||
| } | ||
| /** | ||
| * Validates that the app directory exists | ||
| * @param {string} targetDir - Target directory path | ||
| * @returns {boolean} True if directory exists | ||
| */ | ||
| validateAppDirectoryExists(targetDir) { | ||
| return this.fileSystem.existsSync(targetDir); | ||
| } | ||
| /** | ||
| * Validates that manifest.json exists in the app directory | ||
| * @param {string} targetDir - Target directory path | ||
| * @returns {boolean} True if manifest.json exists | ||
| */ | ||
| validateManifestExists(targetDir) { | ||
| const manifestPath = path_1.default.join(targetDir, 'manifest.json'); | ||
| return this.fileSystem.existsSync(manifestPath); | ||
| } | ||
| /** | ||
| * Validates that handler.js exists in the app directory | ||
| * @param {string} targetDir - Target directory path | ||
| * @returns {boolean} True if handler.js exists | ||
| */ | ||
| validateHandlerExists(targetDir) { | ||
| const handlerPath = path_1.default.join(targetDir, 'handler', 'handler.js'); | ||
| return this.fileSystem.existsSync(handlerPath); | ||
| } | ||
| } | ||
| exports.PackageValidator = PackageValidator; | ||
| "use strict";var __importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.PackageValidator=void 0;const path_1=__importDefault(require("path"));class PackageValidator{constructor(t){this.fileSystem=t}validateAppDirectoryExists(t){return this.fileSystem.existsSync(t)}validateManifestExists(t){const s=path_1.default.join(t,"manifest.json");return this.fileSystem.existsSync(s)}validateHandlerExists(t){const s=path_1.default.join(t,"handler","handler.js");return this.fileSystem.existsSync(s)}}exports.PackageValidator=PackageValidator; |
@@ -1,26 +0,1 @@ | ||
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.isNonEmptyString = isNonEmptyString; | ||
| exports.ensureFileExists = ensureFileExists; | ||
| const path_1 = __importDefault(require("path")); | ||
| /** | ||
| * True only when `value` is a string and is not empty or whitespace-only after trim. | ||
| * Logically the opposite of `(typeof value !== 'string' || value.trim() === '')`. | ||
| * @param {unknown} value - Value to check | ||
| * @returns {value is string} Whether `value` is a usable non-empty string | ||
| */ | ||
| function isNonEmptyString(value) { | ||
| return typeof value === 'string' && value.trim() !== ''; | ||
| } | ||
| /** | ||
| * Throws if `filePath` does not exist on the given filesystem. | ||
| * Message uses the file basename, e.g. `iparams.json not found`. | ||
| */ | ||
| function ensureFileExists(fileSystem, filePath) { | ||
| if (!fileSystem.existsSync(filePath)) { | ||
| throw new Error(`${path_1.default.basename(filePath)} not found`); | ||
| } | ||
| } | ||
| "use strict";var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.isNonEmptyString=isNonEmptyString,exports.ensureFileExists=ensureFileExists;const path_1=__importDefault(require("path"));function isNonEmptyString(t){return typeof t=="string"&&t.trim()!==""}function ensureFileExists(t,e){if(!t.existsSync(e))throw new Error(`${path_1.default.basename(e)} not found`)} |
+1
-1
| { | ||
| "name": "@chargebee/chargebee-apps-shared", | ||
| "version": "0.0.1", | ||
| "version": "0.0.3", | ||
| "description": "Shared interfaces and utilities for Chargebee Apps CLI", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 6 instances
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances
99335
-37.94%1415
-61.94%22
1000%2
100%