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

@chargebee/chargebee-apps

Package Overview
Dependencies
Maintainers
4
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@chargebee/chargebee-apps - npm Package Compare versions

Comparing version
0.0.1
to
0.0.3
+1
-73
dist/api/iparams.routes.js

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

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.setupIparamsRoutes = setupIparamsRoutes;
const chargebee_apps_shared_1 = require("@chargebee/chargebee-apps-shared");
const registry_1 = require("../registry");
const REGISTRY = registry_1.PublicCliRegistry.getInstance();
const __logger = REGISTRY.logger;
/**
* Sets up all iparams-related API routes
*/
function setupIparamsRoutes(app, userCodeDir, fileSystem) {
const service = new chargebee_apps_shared_1.IparamsService(fileSystem);
app.get('/api/iparams', (_req, res) => {
try {
return res.json({ iparams: service.loadIparamDefns(userCodeDir) });
}
catch (error) {
__logger.error('Error: Failed to load iparams.json', error);
const rawContent = error.rawContent ?? null;
return res.status(400).json({
error: 'Failed to load iparams.json',
message: error instanceof Error ? error.message : 'Unknown error',
rawContent
});
}
});
app.post('/api/iparams', (req, res) => {
try {
const iparamDefns = req.body.iparams;
service.saveIparamDefns(userCodeDir, iparamDefns);
return res.json({ success: true, message: 'Iparams saved successfully' });
}
catch (error) {
__logger.error('Error: Failed to save iparams', error);
return res.status(400).json({
error: 'Failed to save iparams',
message: error instanceof Error ? error.message : 'Unknown error'
});
}
});
app.get('/api/iparams/inputs', (_req, res) => {
try {
return res.json({ inputs: service.loadInputs(userCodeDir) });
}
catch (error) {
__logger.error('Error: Failed to load iparams.local.json', error);
return res.status(400).json({
error: 'Failed to load iparams.local.json',
message: error instanceof Error ? error.message : 'Unknown error'
});
}
});
app.post('/api/iparams/inputs', (req, res) => {
try {
service.saveInputs(userCodeDir, req.body.inputs);
return res.json({ success: true, message: 'Inputs saved successfully' });
}
catch (error) {
if (error instanceof chargebee_apps_shared_1.MissingRequiredParamsError) {
return res.status(400).json({
valid: false,
missing: error.missing,
message: error.message
});
}
__logger.error('Error: Failed to save iparams inputs', error);
return res.status(400).json({
error: 'Failed to save iparams inputs',
message: error instanceof Error ? error.message : 'Unknown error'
});
}
});
}
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.setupIparamsRoutes=setupIparamsRoutes;const chargebee_apps_shared_1=require("@chargebee/chargebee-apps-shared"),registry_1=require("../registry"),REGISTRY=registry_1.PublicCliRegistry.getInstance(),__logger=REGISTRY.logger;function setupIparamsRoutes(a,t,n){const o=new chargebee_apps_shared_1.IparamsService(n);a.get("/api/iparams",(e,s)=>{try{return s.json({iparams:o.loadIparamDefns(t)})}catch(r){__logger.error("Error: Failed to load iparams.json",r);const i=r.rawContent??null;return s.status(400).json({error:"Failed to load iparams.json",message:r instanceof Error?r.message:"Unknown error",rawContent:i})}}),a.post("/api/iparams",(e,s)=>{try{const r=e.body.iparams;return o.saveIparamDefns(t,r),s.json({success:!0,message:"Iparams saved successfully"})}catch(r){return __logger.error("Error: Failed to save iparams",r),s.status(400).json({error:"Failed to save iparams",message:r instanceof Error?r.message:"Unknown error"})}}),a.get("/api/iparams/inputs",(e,s)=>{try{return s.json({inputs:o.loadInputs(t)})}catch(r){return __logger.error("Error: Failed to load iparams.local.json",r),s.status(400).json({error:"Failed to load iparams.local.json",message:r instanceof Error?r.message:"Unknown error"})}}),a.post("/api/iparams/inputs",(e,s)=>{try{return o.saveInputs(t,e.body.inputs),s.json({success:!0,message:"Inputs saved successfully"})}catch(r){return r instanceof chargebee_apps_shared_1.MissingRequiredParamsError?s.status(400).json({valid:!1,missing:r.missing,message:r.message}):(__logger.error("Error: Failed to save iparams inputs",r),s.status(400).json({error:"Failed to save iparams inputs",message:r instanceof Error?r.message:"Unknown error"}))}})}

@@ -1,339 +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.setupServer = setupServer;
exports.invokeEventHandler = invokeEventHandler;
exports.setupApiRoutes = setupApiRoutes;
exports.setupAppRoutes = setupAppRoutes;
const chargebee_apps_libs_1 = require("@chargebee/chargebee-apps-libs");
const chargebee_apps_shared_1 = require("@chargebee/chargebee-apps-shared");
const express_1 = __importDefault(require("express"));
const path_1 = __importDefault(require("path"));
const registry_1 = require("../registry");
const iparams_routes_1 = require("./iparams.routes");
// Create a singleton instance of PathResolver
const pathResolver = new chargebee_apps_shared_1.PathResolver();
// Get UI directory paths using centralized path resolver
const WEB_STATIC_DIR = pathResolver.getPublicLibsUiWebDir();
// Configurable path variables
const PATHS = {
WEB_STATIC_DIR,
MAIN_HTML_FILE: 'index.html',
HANDLER_FILE: 'handler/handler.js',
MANIFEST_FILE: 'manifest.json',
TEST_DATA_DIR: 'test_data',
};
const REGISTRY = registry_1.PublicCliRegistry.getInstance();
const __logger = REGISTRY.logger;
/**
* Sets up and start an Express server for the serverless app tester
* @param {number} port - The port number to run the server on
* @param {string} userCodeDir - The user code directory where logs should be stored
* @param {CBFileSystem} fileSystem - The filesystem implementation to use
* @param {CBProcess} processService - The process implementation to use
* @param {DependencyManager} dependencyManager - The dependency manager implementation to use
*/
function setupServer(port, userCodeDir, fileSystem = REGISTRY.fileSystem, processService = REGISTRY.process, dependencyManager = REGISTRY.dependencyManager) {
const app = (0, express_1.default)();
app.disable('x-powered-by');
// Create a single CBLogger instance for the entire server session
const sessionLogger = (0, chargebee_apps_libs_1.createCBPublicLogger)(fileSystem, processService, userCodeDir);
// CORS middleware
app.use((_req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
// JSON parsing
app.use(express_1.default.json());
// Static files
app.use(express_1.default.static(PATHS.WEB_STATIC_DIR));
// API Routes
setupApiRoutes(app, sessionLogger, userCodeDir, fileSystem, processService, dependencyManager);
// Iparams Routes
(0, iparams_routes_1.setupIparamsRoutes)(app, userCodeDir, fileSystem);
// App Routes
setupAppRoutes(app, fileSystem);
// Start server
const server = app.listen(port, () => {
__logger.info(`Server is running on \x1b[4mhttp://localhost:${port}\x1b[0m`);
});
// Graceful shutdown
processService.on('SIGINT', () => {
__logger.info('Shutting down server...');
server.close(() => {
__logger.info('Server stopped!');
processService.exit(0);
});
});
processService.on('uncaughtException', async (err) => {
__logger.error(`Uncaught exception thrown: ${err.message}`);
if (err && err.stack) {
__logger.error(`Stack Trace: ${err.stack}`);
}
processService.exit(1);
});
// Handle server errors
server.on('error', (error) => {
if (error.code === 'EADDRINUSE') {
__logger.error(`Port ${port} is already in use. Try a different port with --port option.`);
}
else {
__logger.error('Server error:', error);
}
processService.exit(1);
});
return server;
}
/**
* Invokes an event handler based on the event data
* @param {EventRecord} eventData - The event data containing event_type and payload
* @param {ICBLogger} sessionLogger - The logger instance for this server session
* @param {string} userCodeDir - The user code directory
* @param {CBFileSystem} fileSystem - The filesystem implementation to use
* @param {DependencyManager} dependencyManager - The dependency manager implementation to use
* @returns {Promise<any>} The result from the handler function
* @throws {Error} If handler file, manifest, or handler function is not found
*/
async function invokeEventHandler(eventData, sessionLogger, userCodeDir, fileSystem, dependencyManager) {
const iparamsService = new chargebee_apps_shared_1.IparamsService(fileSystem);
const hasIparamsFile = iparamsService.iparamsFileExists(userCodeDir);
let iparams;
if (hasIparamsFile) {
try {
iparams = iparamsService.validateAndGetInputsForExecution(userCodeDir);
}
catch (error) {
if (error instanceof chargebee_apps_shared_1.MissingRequiredParamsError) {
throw error;
}
const err = error;
return {
success: false,
error: `Parameters validation failed: ${err.message}`,
stack: err.stack
};
}
}
const configLoader = new chargebee_apps_libs_1.ConfigLoader(fileSystem);
const allowedModules = configLoader.loadAllowedModules();
const packageValidator = new chargebee_apps_shared_1.PackageValidator(fileSystem);
const manifestValidator = new chargebee_apps_shared_1.ManifestValidator(allowedModules, fileSystem);
const sandbox = new chargebee_apps_libs_1.PublicSandboxWrapper(allowedModules, fileSystem, packageValidator, dependencyManager, manifestValidator);
const payload = hasIparamsFile
? { event: eventData, iparams: iparams ?? {} }
: { event: eventData };
return await sandbox.execute(userCodeDir, payload, sessionLogger);
}
/**
* Sets up all API routes for the serverless app tester
* @param {Application} app - Express application instance
* @param {ICBLogger} sessionLogger - The logger instance for this server session
* @param {string} userCodeDir - The user code directory
* @param {CBFileSystem} fileSystem - The filesystem implementation to use
* @param {CBProcess} process - The process implementation to use
* @param {DependencyManager} dependencyManager - The dependency manager implementation to use
*/
function setupApiRoutes(app, sessionLogger, userCodeDir, fileSystem, process, dependencyManager) {
// Get list of available test data files
app.get('/api/manifest', (_req, res, next) => {
const testDataDir = path_1.default.join(process.cwd(), PATHS.TEST_DATA_DIR);
const manifestPath = path_1.default.join(process.cwd(), PATHS.MANIFEST_FILE);
const handlerPath = path_1.default.join(process.cwd(), PATHS.HANDLER_FILE);
try {
// Check if manifest.json exists
const configLoader = new chargebee_apps_libs_1.ConfigLoader(fileSystem);
const allowedModules = configLoader.loadAllowedModules();
const manifestValidator = new chargebee_apps_shared_1.ManifestValidator(allowedModules, fileSystem);
const manifestData = manifestValidator.validateAndGetManifestFile(manifestPath);
// Load manifest to get configured events
const configuredEvents = Object.keys(manifestData.events || {});
// Check if handler.js exists
const handlerExists = fileSystem.existsSync(handlerPath);
// Check if test data directory exists
const testDataExists = fileSystem.existsSync(testDataDir);
let testDataFiles = [];
if (testDataExists) {
testDataFiles = fileSystem.readdirSync(testDataDir)
.filter((file) => file.endsWith('.json'))
.map((file) => file.replace('.json', ''));
}
// Analyze each configured event
const events = configuredEvents.map(eventType => {
const eventConfig = manifestData.events[eventType];
const handlerName = eventConfig ? eventConfig.handler : null;
const hasTestData = testDataFiles.includes(eventType);
// Check if handler function exists in handler.js
let hasHandlerFunction = false;
if (handlerExists && handlerName) {
try {
delete require.cache[require.resolve(handlerPath)];
const handlerModule = require(handlerPath);
hasHandlerFunction = typeof handlerModule[handlerName] === 'function';
}
catch (error) {
__logger.error(`Error checking handler function ${handlerName}:`, error.message);
hasHandlerFunction = false;
}
}
else {
__logger.info(`Handler check skipped for ${eventType}: handlerExists=${handlerExists}, handlerName=${handlerName}`);
}
return {
event_type: eventType,
handler: {
name: handlerName,
exists: hasHandlerFunction,
},
has_test_data: hasTestData,
};
});
// Return all configured events with their status
const response = {
events: events,
dependencies: manifestData.dependencies || {}
};
res.json(response);
}
catch (error) {
__logger.error('Error: Failed to get manifest', error);
if (error instanceof Error && error.message && error.message.includes('manifest.json not found')) {
__logger.error(`Manifest file not found: ${manifestPath}`);
res.status(404).json({
error: 'Manifest file not found',
message: error.message
});
}
else {
res.status(500).json({
error: 'Internal server error',
message: error instanceof Error && error.message ? error.message : error
});
}
next(error);
res.status(500).json({ error: 'Failed to read test data directory' });
}
});
// Get specific test data file
app.get('/api/test-data/:eventType', (req, res) => {
const { eventType } = req.params;
if (!eventType) {
res.status(400).json({ error: 'Event type is required' });
return;
}
const sanitizedEventType = path_1.default.basename(eventType);
// Validate: ensure eventType doesn't contain path separators
if (sanitizedEventType !== eventType || /[\/\\]/.test(eventType)) {
res.status(400).json({
error: 'Invalid event type',
message: 'Event type must not contain path separators'
});
return;
}
// Construct paths
const testDataDir = path_1.default.resolve(process.cwd(), PATHS.TEST_DATA_DIR);
const testDataFile = path_1.default.resolve(testDataDir, `${sanitizedEventType}.json`);
// Security check: Verify the resolved path is within the test_data directory
if (!testDataFile.startsWith(testDataDir + path_1.default.sep)) {
res.status(400).json({
error: 'Invalid event type',
message: 'Access denied'
});
return;
}
try {
if (fileSystem.existsSync(testDataFile)) {
const data = fileSystem.readFileSync(testDataFile, 'utf8');
res.json(JSON.parse(data));
}
else {
res.status(404).json({
error: `Test data for event '${sanitizedEventType}' not found`,
path: testDataFile,
message: 'Check if the test_data directory exists in your app directory'
});
}
}
catch (error) {
res.status(500).json({ error: 'Failed to read test data file' });
}
});
// Invoke serverless function
app.post('/api/invoke', async (req, res) => {
try {
const eventData = req.body;
const result = await invokeEventHandler(eventData, sessionLogger, userCodeDir, fileSystem, dependencyManager);
if (result.success) {
return res.json({ status: 'success' });
}
__logger.error(`✗ Handler execution failed: ${result.error}`);
return res.status(500).json({ error: 'Uncaught exception thrown while invoking function', message: result.error, stack: result.stack });
}
catch (error) {
if (error instanceof chargebee_apps_shared_1.MissingRequiredParamsError) {
const paramText = error.missing.length > 1 ? 'parameters' : 'parameter';
__logger.error(`✗ Missing required ${paramText}: ${error.missing.join(', ')}. Please provide values for these parameters in iparams.local.json`);
return res.status(400).json({
error: 'Parameters validation failed',
message: error.message,
missingParams: error.missing,
showPopup: true
});
}
__logger.error('Error: Failed to invoke event handler', error);
const errMsg = error instanceof Error ? error.message : '';
const errorMap = {
'Handler function': { status: 400, error: 'Handler function not found' },
'No handler configured': { status: 400, error: 'No handler configured' },
'handler.js not found': { status: 404, error: 'Handler file not found' },
'manifest.json not found': { status: 404, error: 'Manifest file not found' }
};
for (const [key, { status, error: errorMsg }] of Object.entries(errorMap)) {
if (errMsg.includes(key)) {
return res.status(status).json({ error: errorMsg, message: errMsg });
}
}
return res.status(500).json({
error: 'Internal server error',
message: errMsg || error
});
}
});
// Handle 404 for API routes
app.all('/api', (_req, res) => {
__logger.info('API endpoint not found');
res.status(404).json({ error: 'API endpoint not found' });
});
}
/**
* Sets up application routes for serving the web UI
* @param {Application} app - Express application instance
* @param {CBFileSystem} fileSystem - The filesystem implementation to use
*/
function setupAppRoutes(app, fileSystem) {
// Serve index.html for all other routes (SPA support)
app.get('/', (_req, res) => {
const indexPath = path_1.default.join(PATHS.WEB_STATIC_DIR, PATHS.MAIN_HTML_FILE);
if (fileSystem.existsSync(indexPath)) {
res.sendFile(indexPath);
}
else {
res.status(404).send('Web UI not found. Please check the file path.');
}
});
// Error handling middleware
app.use((error, _req, res, _next) => {
// Only log and respond if headers haven't been sent yet
if (!res.headersSent) {
__logger.error('Error: Failed to handle middleware', error);
res.status(500).json({
error: 'Internal server error',
message: error.message
});
}
// If headers already sent, error was already handled - don't log again
});
}
"use strict";var __importDefault=this&&this.__importDefault||function(n){return n&&n.__esModule?n:{default:n}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.setupServer=setupServer,exports.invokeEventHandler=invokeEventHandler,exports.setupApiRoutes=setupApiRoutes,exports.setupAppRoutes=setupAppRoutes;const chargebee_apps_libs_1=require("@chargebee/chargebee-apps-libs"),chargebee_apps_shared_1=require("@chargebee/chargebee-apps-shared"),express_1=__importDefault(require("express")),path_1=__importDefault(require("path")),registry_1=require("../registry"),iparams_routes_1=require("./iparams.routes"),pathResolver=new chargebee_apps_shared_1.PathResolver,WEB_STATIC_DIR=pathResolver.getPublicLibsUiWebDir(),PATHS={WEB_STATIC_DIR,MAIN_HTML_FILE:"index.html",HANDLER_FILE:"handler/handler.js",MANIFEST_FILE:"manifest.json",TEST_DATA_DIR:"test_data"},REGISTRY=registry_1.PublicCliRegistry.getInstance(),__logger=REGISTRY.logger;function setupServer(n,f,o=REGISTRY.fileSystem,t=REGISTRY.process,i=REGISTRY.dependencyManager){const c=(0,express_1.default)();c.disable("x-powered-by");const u=(0,chargebee_apps_libs_1.createCBPublicLogger)(o,t,f);c.use((e,s,l)=>{s.header("Access-Control-Allow-Origin","*"),s.header("Access-Control-Allow-Methods","GET, POST, OPTIONS"),s.header("Access-Control-Allow-Headers","Content-Type"),l()}),c.use(express_1.default.json()),c.use(express_1.default.static(PATHS.WEB_STATIC_DIR)),setupApiRoutes(c,u,f,o,t,i),(0,iparams_routes_1.setupIparamsRoutes)(c,f,o),setupAppRoutes(c,o);const r=c.listen(n,()=>{__logger.info(`Server is running on \x1B[4mhttp://localhost:${n}\x1B[0m`)});return t.on("SIGINT",()=>{__logger.info("Shutting down server..."),r.close(()=>{__logger.info("Server stopped!"),t.exit(0)})}),t.on("uncaughtException",async e=>{__logger.error(`Uncaught exception thrown: ${e.message}`),e&&e.stack&&__logger.error(`Stack Trace: ${e.stack}`),t.exit(1)}),r.on("error",e=>{e.code==="EADDRINUSE"?__logger.error(`Port ${n} is already in use. Try a different port with --port option.`):__logger.error("Server error:",e),t.exit(1)}),r}async function invokeEventHandler(n,f,o,t,i){const c=new chargebee_apps_shared_1.IparamsService(t),u=c.iparamsFileExists(o);let r;if(u)try{r=c.validateAndGetInputsForExecution(o)}catch(_){if(_ instanceof chargebee_apps_shared_1.MissingRequiredParamsError)throw _;const g=_;return{success:!1,error:`Parameters validation failed: ${g.message}`,stack:g.stack}}const s=new chargebee_apps_libs_1.ConfigLoader(t).loadAllowedModules(),l=new chargebee_apps_shared_1.PackageValidator(t),d=new chargebee_apps_shared_1.ManifestValidator(s,t),a=new chargebee_apps_libs_1.PublicSandboxWrapper(s,t,l,i,d),h=u?{event:n,iparams:r??{}}:{event:n};return await a.execute(o,h,f)}function setupApiRoutes(n,f,o,t,i,c){n.get("/api/manifest",(u,r,e)=>{const s=path_1.default.join(i.cwd(),PATHS.TEST_DATA_DIR),l=path_1.default.join(i.cwd(),PATHS.MANIFEST_FILE),d=path_1.default.join(i.cwd(),PATHS.HANDLER_FILE);try{const h=new chargebee_apps_libs_1.ConfigLoader(t).loadAllowedModules(),g=new chargebee_apps_shared_1.ManifestValidator(h,t).validateAndGetManifestFile(l),A=Object.keys(g.events||{}),E=t.existsSync(d),T=t.existsSync(s);let I=[];T&&(I=t.readdirSync(s).filter(p=>p.endsWith(".json")).map(p=>p.replace(".json","")));const w={events:A.map(p=>{const j=g.events[p],m=j?j.handler:null,M=I.includes(p);let v=!1;if(E&&m)try{delete require.cache[require.resolve(d)],v=typeof require(d)[m]=="function"}catch(x){__logger.error(`Error checking handler function ${m}:`,x.message),v=!1}else __logger.info(`Handler check skipped for ${p}: handlerExists=${E}, handlerName=${m}`);return{event_type:p,handler:{name:m,exists:v},has_test_data:M}}),dependencies:g.dependencies||{}};r.json(w)}catch(a){__logger.error("Error: Failed to get manifest",a),a instanceof Error&&a.message&&a.message.includes("manifest.json not found")?(__logger.error(`Manifest file not found: ${l}`),r.status(404).json({error:"Manifest file not found",message:a.message})):r.status(500).json({error:"Internal server error",message:a instanceof Error&&a.message?a.message:a}),e(a),r.status(500).json({error:"Failed to read test data directory"})}}),n.get("/api/test-data/:eventType",(u,r)=>{const{eventType:e}=u.params;if(!e){r.status(400).json({error:"Event type is required"});return}const s=path_1.default.basename(e);if(s!==e||/[\/\\]/.test(e)){r.status(400).json({error:"Invalid event type",message:"Event type must not contain path separators"});return}const l=path_1.default.resolve(i.cwd(),PATHS.TEST_DATA_DIR),d=path_1.default.resolve(l,`${s}.json`);if(!d.startsWith(l+path_1.default.sep)){r.status(400).json({error:"Invalid event type",message:"Access denied"});return}try{if(t.existsSync(d)){const a=t.readFileSync(d,"utf8");r.json(JSON.parse(a))}else r.status(404).json({error:`Test data for event '${s}' not found`,path:d,message:"Check if the test_data directory exists in your app directory"})}catch{r.status(500).json({error:"Failed to read test data file"})}}),n.post("/api/invoke",async(u,r)=>{try{const e=u.body,s=await invokeEventHandler(e,f,o,t,c);return s.success?r.json({status:"success"}):(__logger.error(`\u2717 Handler execution failed: ${s.error}`),r.status(500).json({error:"Uncaught exception thrown while invoking function",message:s.error,stack:s.stack}))}catch(e){if(e instanceof chargebee_apps_shared_1.MissingRequiredParamsError){const d=e.missing.length>1?"parameters":"parameter";return __logger.error(`\u2717 Missing required ${d}: ${e.missing.join(", ")}. Please provide values for these parameters in iparams.local.json`),r.status(400).json({error:"Parameters validation failed",message:e.message,missingParams:e.missing,showPopup:!0})}__logger.error("Error: Failed to invoke event handler",e);const s=e instanceof Error?e.message:"",l={"Handler function":{status:400,error:"Handler function not found"},"No handler configured":{status:400,error:"No handler configured"},"handler.js not found":{status:404,error:"Handler file not found"},"manifest.json not found":{status:404,error:"Manifest file not found"}};for(const[d,{status:a,error:h}]of Object.entries(l))if(s.includes(d))return r.status(a).json({error:h,message:s});return r.status(500).json({error:"Internal server error",message:s||e})}}),n.all("/api",(u,r)=>{__logger.info("API endpoint not found"),r.status(404).json({error:"API endpoint not found"})})}function setupAppRoutes(n,f){n.get("/",(o,t)=>{const i=path_1.default.join(PATHS.WEB_STATIC_DIR,PATHS.MAIN_HTML_FILE);f.existsSync(i)?t.sendFile(i):t.status(404).send("Web UI not found. Please check the file path.")}),n.use((o,t,i,c)=>{i.headersSent||(__logger.error("Error: Failed to handle middleware",o),i.status(500).json({error:"Internal server error",message:o.message}))})}

@@ -1,102 +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.createCommand = exports.CreateCommand = void 0;
const chargebee_apps_shared_1 = require("@chargebee/chargebee-apps-shared");
const path_1 = __importDefault(require("path"));
const registry_1 = require("../registry");
// Create a singleton instance of PathResolver
const pathResolver = new chargebee_apps_shared_1.PathResolver();
/**
* Main create command class
*/
class CreateCommand {
constructor(fileSystem, process) {
const registry = registry_1.PublicCliRegistry.getInstance();
this.fileSystem = fileSystem || registry.fileSystem;
this.process = process || registry.process;
// Get templates directory path using centralized path resolver
const templatesPath = pathResolver.getPublicLibsTemplatesDir();
this.templateService = new chargebee_apps_shared_1.TemplateService(this.fileSystem, templatesPath);
}
/**
* Creates a new serverless application from a template
* @param {CreateOptions} options - The options for the create command
* @param {string} appDir - The directory where the app will be created
*/
execute(options, appDir) {
const template = options.template;
chargebee_apps_shared_1.__logger.info('Creating new application...');
const targetDir = path_1.default.resolve(appDir);
// Validate app directory
this.validate(targetDir, appDir, template);
// Create project
this.createProject(targetDir, template);
}
/**
* Validates the app directory
* @param targetDir - The directory where the app will be created
* @param appDir - The original app directory argument
* @param template - The template name to use for scaffolding
*/
validate(targetDir, appDir, template) {
const defaultTemplate = 'serverless-node-starter-app';
// Show which template is being used
if (template === defaultTemplate) {
chargebee_apps_shared_1.__logger.info(`Using default template: ${template}`);
}
else {
chargebee_apps_shared_1.__logger.info(`Using template: ${template}`);
}
// Validate template
if (!this.templateService.validateTemplate(template)) {
const availableTemplates = this.templateService.getAvailableTemplates();
chargebee_apps_shared_1.__logger.error(`Error: Template '${template}' not found.`);
chargebee_apps_shared_1.__logger.error(`Available templates: ${availableTemplates.join(', ')}`);
this.process.exit(1);
}
// Validate app directory
try {
const conflicts = this.templateService.validateAppDirectory(targetDir, appDir, template);
if (conflicts.length > 0) {
chargebee_apps_shared_1.__logger.error(`Error: The following files already exist in the current directory:`);
conflicts.forEach(file => chargebee_apps_shared_1.__logger.error(` - ${file}`));
chargebee_apps_shared_1.__logger.error(`Please remove these files or use a different directory.`);
this.process.exit(1);
}
}
catch (error) {
chargebee_apps_shared_1.__logger.error(`Error: ${error.message}`);
chargebee_apps_shared_1.__logger.error(`Use a different directory name or clear the existing directory first.`);
this.process.exit(1);
}
}
/**
* Creates a new serverless application from a template
* @param targetDir - The directory where the app will be created
* @param template - The template name to use for scaffolding
*/
createProject(targetDir, template) {
try {
if (!this.fileSystem.existsSync(targetDir)) {
this.fileSystem.mkdirSync(targetDir, { recursive: true });
}
// Copy template files
const templatePath = this.templateService.getTemplatePath(template);
this.templateService.copyTemplateFiles(templatePath, targetDir);
chargebee_apps_shared_1.__logger.success(`Successfully created app in '${targetDir}' using template '${template}'`);
chargebee_apps_shared_1.__logger.info(`Directory: ${targetDir}`);
chargebee_apps_shared_1.__logger.info('Project structure:');
this.templateService.printProjectStructure(targetDir);
}
catch (error) {
chargebee_apps_shared_1.__logger.error(`Error creating app: ${error}`);
this.process.exit(1);
}
}
}
exports.CreateCommand = CreateCommand;
// Export for use in commands/index.ts
exports.createCommand = new CreateCommand();
"use strict";var __importDefault=this&&this.__importDefault||function(i){return i&&i.__esModule?i:{default:i}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.createCommand=exports.CreateCommand=void 0;const chargebee_apps_shared_1=require("@chargebee/chargebee-apps-shared"),path_1=__importDefault(require("path")),registry_1=require("../registry"),pathResolver=new chargebee_apps_shared_1.PathResolver;class CreateCommand{constructor(r,t){const e=registry_1.PublicCliRegistry.getInstance();this.fileSystem=r||e.fileSystem,this.process=t||e.process;const o=pathResolver.getPublicLibsTemplatesDir();this.templateService=new chargebee_apps_shared_1.TemplateService(this.fileSystem,o)}execute(r,t){const e=r.template;chargebee_apps_shared_1.__logger.info("Creating new application...");const o=path_1.default.resolve(t);this.validate(o,t,e),this.createProject(o,e)}validate(r,t,e){if(e==="serverless-node-starter-app"?chargebee_apps_shared_1.__logger.info(`Using default template: ${e}`):chargebee_apps_shared_1.__logger.info(`Using template: ${e}`),!this.templateService.validateTemplate(e)){const s=this.templateService.getAvailableTemplates();chargebee_apps_shared_1.__logger.error(`Error: Template '${e}' not found.`),chargebee_apps_shared_1.__logger.error(`Available templates: ${s.join(", ")}`),this.process.exit(1)}try{const s=this.templateService.validateAppDirectory(r,t,e);s.length>0&&(chargebee_apps_shared_1.__logger.error("Error: The following files already exist in the current directory:"),s.forEach(a=>chargebee_apps_shared_1.__logger.error(` - ${a}`)),chargebee_apps_shared_1.__logger.error("Please remove these files or use a different directory."),this.process.exit(1))}catch(s){chargebee_apps_shared_1.__logger.error(`Error: ${s.message}`),chargebee_apps_shared_1.__logger.error("Use a different directory name or clear the existing directory first."),this.process.exit(1)}}createProject(r,t){try{this.fileSystem.existsSync(r)||this.fileSystem.mkdirSync(r,{recursive:!0});const e=this.templateService.getTemplatePath(t);this.templateService.copyTemplateFiles(e,r),chargebee_apps_shared_1.__logger.success(`Successfully created app in '${r}' using template '${t}'`),chargebee_apps_shared_1.__logger.info(`Directory: ${r}`),chargebee_apps_shared_1.__logger.info("Project structure:"),this.templateService.printProjectStructure(r)}catch(e){chargebee_apps_shared_1.__logger.error(`Error creating app: ${e}`),this.process.exit(1)}}}exports.CreateCommand=CreateCommand,exports.createCommand=new CreateCommand;

@@ -1,93 +0,7 @@

'use strict';
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.setupCLI = setupCLI;
const commander_1 = require("commander");
const package_json_1 = __importDefault(require("../../package.json"));
const create_1 = require("./create");
const package_1 = require("./package");
const run_1 = require("./run");
const chargebee_apps_shared_1 = require("@chargebee/chargebee-apps-shared");
const registry_1 = require("../registry");
/**
* Sets up the CLI program with all available commands
* @returns {Command} The configured CLI program
*/
function setupCLI() {
const registry = registry_1.PublicCliRegistry.getInstance();
const pathResolver = new chargebee_apps_shared_1.PathResolver();
const templatesPath = pathResolver.getPublicLibsTemplatesDir();
const templateService = new chargebee_apps_shared_1.TemplateService(registry.fileSystem, templatesPath);
const availableTemplates = templateService.getAvailableTemplates();
const program = new commander_1.Command();
program
.name('chargebee-apps')
.description('Chargebee Apps CLI - Create, test, and package serverless applications')
.version(package_json_1.default.version)
.usage('<command> <directory> [options]')
.showHelpAfterError()
.showSuggestionAfterError()
.addHelpCommand()
.configureHelp({
sortSubcommands: true,
sortOptions: true,
subcommandTerm: (cmd) => {
const args = cmd.registeredArguments.map(arg => {
return arg.required ? `<${arg.name()}>` : `[${arg.name()}]`;
}).join(' ');
const hasOptions = cmd.options.length > 0;
return `${cmd.name()}${args ? ' ' + args : ''}${hasOptions ? ' [options]' : ''}`;
}
});
program
.command('create')
.usage('<directory> [options]')
.summary('Create a new application')
.description('Create a new application from a template')
.argument('<directory>', 'Path where the new application will be created')
.option('--template <template>', 'Template to scaffold from', package_json_1.default.config.defaultTemplate)
.addHelpText('after', '\n' + [
'Available Templates:',
...availableTemplates.map(t => ` - ${t}`),
'',
'Examples:',
' chargebee-apps create my-app',
' chargebee-apps create ./projects/new-app --template serverless-node-starter-app',
' chargebee-apps create ./projects/my-app-with-iparams --template serverless-node-starter-app-with-iparams'
].join('\n'))
.action((directory, options) => create_1.createCommand.execute(options, directory));
program
.command('run')
.usage('<directory> [options]')
.summary('Start a local development server')
.description('Start a local development server to test your serverless application')
.argument('<directory>', 'Path to the application directory to run')
.option('-p, --port <port>', 'Port to run the server on', package_json_1.default.config.defaultPort.toString())
.addHelpText('after', '\n' + [
'Examples:',
' chargebee-apps run .',
' chargebee-apps run ./my-app',
' chargebee-apps run ./my-app --port 15001',
' chargebee-apps run ./my-app -p 15001'
].join('\n'))
.action(async (directory, options) => {
await run_1.runCommand.execute(options, directory);
});
program
.command('package')
.usage('<directory> [options]')
.summary('Package an application')
.description('Package a serverless application into a zip file')
.argument('<directory>', 'Path to the application directory to package')
.option('--name <name>', 'Custom name for the package (without extension)', package_json_1.default.config.defaultPackageName)
.addHelpText('after', '\n' + [
'Examples:',
' chargebee-apps package .',
' chargebee-apps package ./my-app',
' chargebee-apps package ./my-app --name my-app-v1.0.0'
].join('\n'))
.action(async (directory, options) => await package_1.packageCommand.execute(directory, options));
return program;
}
"use strict";var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.setupCLI=setupCLI;const commander_1=require("commander"),package_json_1=__importDefault(require("../../package.json")),create_1=require("./create"),package_1=require("./package"),run_1=require("./run"),chargebee_apps_shared_1=require("@chargebee/chargebee-apps-shared"),registry_1=require("../registry");function setupCLI(){const t=registry_1.PublicCliRegistry.getInstance(),o=new chargebee_apps_shared_1.PathResolver().getPublicLibsTemplatesDir(),n=new chargebee_apps_shared_1.TemplateService(t.fileSystem,o).getAvailableTemplates(),r=new commander_1.Command;return r.name("chargebee-apps").description("Chargebee Apps CLI - Create, test, and package serverless applications").version(package_json_1.default.version).usage("<command> <directory> [options]").showHelpAfterError().showSuggestionAfterError().addHelpCommand().configureHelp({sortSubcommands:!0,sortOptions:!0,subcommandTerm:e=>{const a=e.registeredArguments.map(p=>p.required?`<${p.name()}>`:`[${p.name()}]`).join(" "),s=e.options.length>0;return`${e.name()}${a?" "+a:""}${s?" [options]":""}`}}),r.command("create").usage("<directory> [options]").summary("Create a new application").description("Create a new application from a template").argument("<directory>","Path where the new application will be created").option("--template <template>","Template to scaffold from",package_json_1.default.config.defaultTemplate).addHelpText("after",`
`+["Available Templates:",...n.map(e=>` - ${e}`),"","Examples:"," chargebee-apps create my-app"," chargebee-apps create ./projects/new-app --template serverless-node-starter-app"," chargebee-apps create ./projects/my-app-with-iparams --template serverless-node-starter-app-with-iparams"].join(`
`)).action((e,a)=>create_1.createCommand.execute(a,e)),r.command("run").usage("<directory> [options]").summary("Start a local development server").description("Start a local development server to test your serverless application").argument("<directory>","Path to the application directory to run").option("-p, --port <port>","Port to run the server on",package_json_1.default.config.defaultPort.toString()).addHelpText("after",`
`+["Examples:"," chargebee-apps run ."," chargebee-apps run ./my-app"," chargebee-apps run ./my-app --port 15001"," chargebee-apps run ./my-app -p 15001"].join(`
`)).action(async(e,a)=>{await run_1.runCommand.execute(a,e)}),r.command("package").usage("<directory> [options]").summary("Package an application").description("Package a serverless application into a zip file").argument("<directory>","Path to the application directory to package").option("--name <name>","Custom name for the package (without extension)",package_json_1.default.config.defaultPackageName).addHelpText("after",`
`+["Examples:"," chargebee-apps package ."," chargebee-apps package ./my-app"," chargebee-apps package ./my-app --name my-app-v1.0.0"].join(`
`)).action(async(e,a)=>await package_1.packageCommand.execute(e,a)),r}

@@ -1,93 +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.packageCommand = exports.PackageCommand = void 0;
const chargebee_apps_shared_1 = require("@chargebee/chargebee-apps-shared");
const chalk_1 = __importDefault(require("chalk"));
const path_1 = __importDefault(require("path"));
const registry_1 = require("../registry");
/**
* Package configuration for file inclusion rules
* Only includes essential files needed for the serverless application
*/
const PACKAGE_CONFIG = {
include: {
directories: [
{
name: '.', // Root directory - only include specific files
includeFiles: ['manifest.json', 'iparams.json'], // Include manifest.json and iparams.json
excludeSubdirs: ['node_modules', 'dist', 'handler', 'test_data', 'types']
},
{
name: 'handler',
allowedExtensions: ['.js', '.json'],
excludeSubdirs: ['node_modules'],
excludeFiles: ['package.json', 'package-lock.json']
}
]
}
};
/**
* Main package command class
*/
class PackageCommand {
constructor(fileSystem, process, fileManagementService, packageValidator, archiveService) {
const registry = registry_1.PublicCliRegistry.getInstance();
this.fileSystem = fileSystem || registry.fileSystem;
this.process = process || registry.process;
this.fileManagementService = fileManagementService || new chargebee_apps_shared_1.FileManagementService(this.fileSystem, PACKAGE_CONFIG);
this.packageValidator = packageValidator || new chargebee_apps_shared_1.PackageValidator(this.fileSystem);
this.archiveService = archiveService || new chargebee_apps_shared_1.ArchiveService(this.fileSystem);
}
/**
* Packages a serverless application into a zip file
* @param {string} appDir - The application directory to package
* @param {string} packageName - The name of the package
*/
async execute(appDir, options) {
const targetDir = path_1.default.resolve(appDir);
const appName = path_1.default.basename(targetDir);
chargebee_apps_shared_1.__logger.info('Packaging serverless application...');
chargebee_apps_shared_1.__logger.info(`App directory: ${targetDir}`);
// Validate app directory
this.validate(targetDir);
chargebee_apps_shared_1.__logger.info(chalk_1.default.green('✓ Valid application directory'));
// Determine output path
const outputPath = this.fileManagementService.determineOutputPath(targetDir, appName, options.name);
// Clean existing packages in dist directory
this.fileManagementService.cleanExistingPackages(targetDir);
try {
const filesToPackage = this.fileManagementService.collectFilesToPackage(targetDir);
await this.archiveService.createZipPackage(filesToPackage, targetDir, outputPath);
}
catch (error) {
const err = error;
chargebee_apps_shared_1.__logger.error(`Error while creating zip: ${err.message}`);
this.process.exit(1);
}
// Create the zip package
chargebee_apps_shared_1.__logger.info(chalk_1.default.green(`✓ Package created successfully: ${outputPath}`));
chargebee_apps_shared_1.__logger.info(`Package size: ${this.fileManagementService.getFileSize(outputPath)}`);
}
validate(targetDir) {
if (!this.packageValidator.validateAppDirectoryExists(targetDir)) {
chargebee_apps_shared_1.__logger.error('✗ Application directory does not exist');
this.process.exit(1);
}
if (!this.packageValidator.validateManifestExists(targetDir)) {
chargebee_apps_shared_1.__logger.error('✗ manifest.json not found in the specified directory');
chargebee_apps_shared_1.__logger.info('Make sure you are running the command from a valid serverless app directory');
this.process.exit(1);
}
if (!this.packageValidator.validateHandlerExists(targetDir)) {
chargebee_apps_shared_1.__logger.error('✗ handler.js not found in the specified directory');
chargebee_apps_shared_1.__logger.info('Make sure you are running the command from a valid serverless app directory');
this.process.exit(1);
}
}
}
exports.PackageCommand = PackageCommand;
// Export for use in commands/index.ts
exports.packageCommand = new PackageCommand();
"use strict";var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.packageCommand=exports.PackageCommand=void 0;const chargebee_apps_shared_1=require("@chargebee/chargebee-apps-shared"),chalk_1=__importDefault(require("chalk")),path_1=__importDefault(require("path")),registry_1=require("../registry"),PACKAGE_CONFIG={include:{directories:[{name:".",includeFiles:["manifest.json","iparams.json"],excludeSubdirs:["node_modules","dist","handler","test_data","types"]},{name:"handler",allowedExtensions:[".js",".json"],excludeSubdirs:["node_modules"],excludeFiles:["package.json","package-lock.json"]}]}};class PackageCommand{constructor(a,s,e,o,r){const i=registry_1.PublicCliRegistry.getInstance();this.fileSystem=a||i.fileSystem,this.process=s||i.process,this.fileManagementService=e||new chargebee_apps_shared_1.FileManagementService(this.fileSystem,PACKAGE_CONFIG),this.packageValidator=o||new chargebee_apps_shared_1.PackageValidator(this.fileSystem),this.archiveService=r||new chargebee_apps_shared_1.ArchiveService(this.fileSystem)}async execute(a,s){const e=path_1.default.resolve(a),o=path_1.default.basename(e);chargebee_apps_shared_1.__logger.info("Packaging serverless application..."),chargebee_apps_shared_1.__logger.info(`App directory: ${e}`),this.validate(e),chargebee_apps_shared_1.__logger.info(chalk_1.default.green("\u2713 Valid application directory"));const r=this.fileManagementService.determineOutputPath(e,o,s.name);this.fileManagementService.cleanExistingPackages(e);try{const i=this.fileManagementService.collectFilesToPackage(e);await this.archiveService.createZipPackage(i,e,r)}catch(i){const c=i;chargebee_apps_shared_1.__logger.error(`Error while creating zip: ${c.message}`),this.process.exit(1)}chargebee_apps_shared_1.__logger.info(chalk_1.default.green(`\u2713 Package created successfully: ${r}`)),chargebee_apps_shared_1.__logger.info(`Package size: ${this.fileManagementService.getFileSize(r)}`)}validate(a){this.packageValidator.validateAppDirectoryExists(a)||(chargebee_apps_shared_1.__logger.error("\u2717 Application directory does not exist"),this.process.exit(1)),this.packageValidator.validateManifestExists(a)||(chargebee_apps_shared_1.__logger.error("\u2717 manifest.json not found in the specified directory"),chargebee_apps_shared_1.__logger.info("Make sure you are running the command from a valid serverless app directory"),this.process.exit(1)),this.packageValidator.validateHandlerExists(a)||(chargebee_apps_shared_1.__logger.error("\u2717 handler.js not found in the specified directory"),chargebee_apps_shared_1.__logger.info("Make sure you are running the command from a valid serverless app directory"),this.process.exit(1))}}exports.PackageCommand=PackageCommand,exports.packageCommand=new PackageCommand;

@@ -1,106 +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.runCommand = exports.RunCommand = void 0;
const chargebee_apps_libs_1 = require("@chargebee/chargebee-apps-libs");
const chargebee_apps_shared_1 = require("@chargebee/chargebee-apps-shared");
const chalk_1 = __importDefault(require("chalk"));
const path_1 = __importDefault(require("path"));
const routes_1 = require("../api/routes");
const registry_1 = require("../registry");
/**
* Main run command class
*/
class RunCommand {
constructor(fileSystem, process, dependencyManager) {
const registry = registry_1.PublicCliRegistry.getInstance();
this.process = process || registry.process;
this.fileSystem = fileSystem || registry.fileSystem;
this.portService = new chargebee_apps_libs_1.PortService();
this.packageValidator = new chargebee_apps_shared_1.PackageValidator(registry.fileSystem);
this.dependencyManager = dependencyManager || registry.dependencyManager;
this.iparamsService = new chargebee_apps_shared_1.IparamsService(registry.fileSystem);
}
/**
* Starts the local development server for testing serverless applications
* @param {string} options - The options for the run command
* @param {string} appDir - The application directory to run
*/
async execute(options, appDir) {
const port = options.port;
if (!this.portService.isValidPort(port)) {
chargebee_apps_shared_1.__logger.error('Invalid port number: ' + port);
this.process.exit(1);
}
const portNumber = this.portService.parsePort(port);
const targetDir = path_1.default.resolve(appDir);
chargebee_apps_shared_1.__logger.info('Starting development server...');
chargebee_apps_shared_1.__logger.info('');
chargebee_apps_shared_1.__logger.info(`App directory: ${targetDir}`);
chargebee_apps_shared_1.__logger.info(`Port: ${portNumber}`);
chargebee_apps_shared_1.__logger.info('');
this.validate(targetDir);
await this.installDependencies(targetDir);
// Change to the app directory before starting the server
this.process.chdir(targetDir);
chargebee_apps_shared_1.__logger.info(chalk_1.default.green(`✓ Server started successfully on http://localhost:${portNumber}`));
chargebee_apps_shared_1.__logger.info(`Press Ctrl+C to stop the server`);
chargebee_apps_shared_1.__logger.info('');
// Start the actual API server
(0, routes_1.setupServer)(portNumber, targetDir, this.fileSystem, this.process, this.dependencyManager);
}
/**
* Validates manifest and installs dependencies using manifest.dependencies.
*/
async installDependencies(targetDir) {
try {
const configLoader = new chargebee_apps_libs_1.ConfigLoader(this.fileSystem);
const allowedModules = configLoader.loadAllowedModules();
const manifestValidator = new chargebee_apps_shared_1.ManifestValidator(allowedModules, this.fileSystem);
const manifestPath = path_1.default.join(targetDir, 'manifest.json');
const manifest = manifestValidator.validateAndGetManifestFile(manifestPath);
await this.dependencyManager.ensureDependencies(targetDir, manifest);
}
catch (error) {
const err = error;
chargebee_apps_shared_1.__logger.error('✗ Failed to install dependencies');
chargebee_apps_shared_1.__logger.error(err.message);
this.process.exit(1);
}
}
validate(targetDir) {
// Check if the directory exists
if (!this.packageValidator.validateAppDirectoryExists(targetDir)) {
chargebee_apps_shared_1.__logger.error('✗ Application directory does not exist');
this.process.exit(1);
}
// Check if it's a valid serverless app directory
if (!this.packageValidator.validateManifestExists(targetDir)) {
chargebee_apps_shared_1.__logger.error('✗ manifest.json not found in the specified directory');
chargebee_apps_shared_1.__logger.error('Make sure you are running the command from a valid serverless app directory');
this.process.exit(1);
}
// Check if the handler.js file exists
if (!this.packageValidator.validateHandlerExists(targetDir)) {
chargebee_apps_shared_1.__logger.error('✗ handler.js not found in the specified directory');
chargebee_apps_shared_1.__logger.error('Make sure you are running the command from a valid serverless app directory');
this.process.exit(1);
}
if (this.iparamsService.iparamsFileExists(targetDir)) {
try {
this.iparamsService.validateIparamDefns(targetDir);
chargebee_apps_shared_1.__logger.debug('✓ iparams.json is valid');
}
catch (error) {
chargebee_apps_shared_1.__logger.error('✗ Invalid iparams.json');
chargebee_apps_shared_1.__logger.error(error.message);
this.process.exit(1);
}
}
}
}
exports.RunCommand = RunCommand;
// Export for use in commands/index.ts
exports.runCommand = new RunCommand();
"use strict";var __importDefault=this&&this.__importDefault||function(o){return o&&o.__esModule?o:{default:o}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.runCommand=exports.RunCommand=void 0;const chargebee_apps_libs_1=require("@chargebee/chargebee-apps-libs"),chargebee_apps_shared_1=require("@chargebee/chargebee-apps-shared"),chalk_1=__importDefault(require("chalk")),path_1=__importDefault(require("path")),routes_1=require("../api/routes"),registry_1=require("../registry");class RunCommand{constructor(e,t,s){const r=registry_1.PublicCliRegistry.getInstance();this.process=t||r.process,this.fileSystem=e||r.fileSystem,this.portService=new chargebee_apps_libs_1.PortService,this.packageValidator=new chargebee_apps_shared_1.PackageValidator(r.fileSystem),this.dependencyManager=s||r.dependencyManager,this.iparamsService=new chargebee_apps_shared_1.IparamsService(r.fileSystem)}async execute(e,t){const s=e.port;this.portService.isValidPort(s)||(chargebee_apps_shared_1.__logger.error("Invalid port number: "+s),this.process.exit(1));const r=this.portService.parsePort(s),i=path_1.default.resolve(t);chargebee_apps_shared_1.__logger.info("Starting development server..."),chargebee_apps_shared_1.__logger.info(""),chargebee_apps_shared_1.__logger.info(`App directory: ${i}`),chargebee_apps_shared_1.__logger.info(`Port: ${r}`),chargebee_apps_shared_1.__logger.info(""),this.validate(i),await this.installDependencies(i),this.process.chdir(i),chargebee_apps_shared_1.__logger.info(chalk_1.default.green(`\u2713 Server started successfully on http://localhost:${r}`)),chargebee_apps_shared_1.__logger.info("Press Ctrl+C to stop the server"),chargebee_apps_shared_1.__logger.info(""),(0,routes_1.setupServer)(r,i,this.fileSystem,this.process,this.dependencyManager)}async installDependencies(e){try{const s=new chargebee_apps_libs_1.ConfigLoader(this.fileSystem).loadAllowedModules(),r=new chargebee_apps_shared_1.ManifestValidator(s,this.fileSystem),i=path_1.default.join(e,"manifest.json"),a=r.validateAndGetManifestFile(i);await this.dependencyManager.ensureDependencies(e,a)}catch(t){const s=t;chargebee_apps_shared_1.__logger.error("\u2717 Failed to install dependencies"),chargebee_apps_shared_1.__logger.error(s.message),this.process.exit(1)}}validate(e){if(this.packageValidator.validateAppDirectoryExists(e)||(chargebee_apps_shared_1.__logger.error("\u2717 Application directory does not exist"),this.process.exit(1)),this.packageValidator.validateManifestExists(e)||(chargebee_apps_shared_1.__logger.error("\u2717 manifest.json not found in the specified directory"),chargebee_apps_shared_1.__logger.error("Make sure you are running the command from a valid serverless app directory"),this.process.exit(1)),this.packageValidator.validateHandlerExists(e)||(chargebee_apps_shared_1.__logger.error("\u2717 handler.js not found in the specified directory"),chargebee_apps_shared_1.__logger.error("Make sure you are running the command from a valid serverless app directory"),this.process.exit(1)),this.iparamsService.iparamsFileExists(e))try{this.iparamsService.validateIparamDefns(e),chargebee_apps_shared_1.__logger.debug("\u2713 iparams.json is valid")}catch(t){chargebee_apps_shared_1.__logger.error("\u2717 Invalid iparams.json"),chargebee_apps_shared_1.__logger.error(t.message),this.process.exit(1)}}}exports.RunCommand=RunCommand,exports.runCommand=new RunCommand;
#!/usr/bin/env node
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const commands_1 = require("./commands");
const program = (0, commands_1.setupCLI)();
program.parse();
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const commands_1=require("./commands"),program=(0,commands_1.setupCLI)();program.parse();

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

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PublicCliRegistry = void 0;
const chargebee_apps_shared_1 = require("@chargebee/chargebee-apps-shared");
/**
* Public CLI Registry - Configures all dependencies for public CLI
*/
class PublicCliRegistry {
constructor() {
// Initialize with public implementations
this._fileSystem = new chargebee_apps_shared_1.FileSystemService();
this._process = new chargebee_apps_shared_1.ProcessService();
this._dependencyManager = new chargebee_apps_shared_1.DependencyManager(this._fileSystem);
// Initialize logger with public CLI configuration
const loggerConfig = {
useJsonFormat: false
};
this._logger = new chargebee_apps_shared_1.InternalLogger(loggerConfig);
}
static getInstance() {
if (!PublicCliRegistry.instance) {
PublicCliRegistry.instance = new PublicCliRegistry();
}
return PublicCliRegistry.instance;
}
get fileSystem() {
return this._fileSystem;
}
get process() {
return this._process;
}
get dependencyManager() {
return this._dependencyManager;
}
get logger() {
return this._logger;
}
}
exports.PublicCliRegistry = PublicCliRegistry;
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.PublicCliRegistry=void 0;const chargebee_apps_shared_1=require("@chargebee/chargebee-apps-shared");class PublicCliRegistry{constructor(){this._fileSystem=new chargebee_apps_shared_1.FileSystemService,this._process=new chargebee_apps_shared_1.ProcessService,this._dependencyManager=new chargebee_apps_shared_1.DependencyManager(this._fileSystem);const e={useJsonFormat:!1};this._logger=new chargebee_apps_shared_1.InternalLogger(e)}static getInstance(){return PublicCliRegistry.instance||(PublicCliRegistry.instance=new PublicCliRegistry),PublicCliRegistry.instance}get fileSystem(){return this._fileSystem}get process(){return this._process}get dependencyManager(){return this._dependencyManager}get logger(){return this._logger}}exports.PublicCliRegistry=PublicCliRegistry;
+3
-3
{
"name": "@chargebee/chargebee-apps",
"version": "0.0.1",
"version": "0.0.3",
"description": "Chargebee Apps CLI tool that enables you to create, test and package the applications",

@@ -32,4 +32,4 @@ "main": "dist/index.js",

"dependencies": {
"@chargebee/chargebee-apps-libs": "0.0.1",
"@chargebee/chargebee-apps-shared": "0.0.1",
"@chargebee/chargebee-apps-libs": "0.0.3",
"@chargebee/chargebee-apps-shared": "0.0.3",
"archiver": "^7.0.1",

@@ -36,0 +36,0 @@ "chalk": "^4.1.2",

+40
-38
# Chargebee Apps CLI Developer Guide
The Chargebee Apps CLI is a command-line tool for building private serverless applications that extend Chargebee Billing. Use it to scaffold a new app, implement and test event handlers locally, and package the app into a ZIP file. When your app is ready, upload it to the Apps portal in Chargebee Billing to publish it privately to your site.
> **Chargebee Apps CLI is in early access.** Request access for enabling it on your test site.
The Chargebee Apps CLI is a command-line tool for building private serverless applications that extend Chargebee Billing. Use it to scaffold a new app, implement and test event handlers locally, and package the app into a ZIP file. When your app is ready, contact support to publish it privately to your site.
In Chargebee, a serverless application (also called an app) is a set of Node.js event handlers that run in Chargebee's hosted environment in response to Chargebee events. You write only the handler logic; Chargebee runs it automatically when a matching event occurs, so there is no server or infrastructure for you to provision, scale, or maintain.

@@ -63,12 +65,14 @@

| File or folder | Standard template | iParams template | Packaged | Purpose |
| --- | --- | --- | --- | --- |
| `manifest.json` | Yes | Yes | Yes | Maps Chargebee events to handler functions and declares npm dependencies. |
| `handler/handler.js` | Yes | Yes | Yes | Contains your core event-handling logic. |
| `iparams.json` | No | Yes | Yes | iParams template only. Defines the installation parameter schema. |
| `iparams.local.json` | No | Yes | No | iParams template only. Stores local test values, keyed by section name. |
| `test_data/` | Yes | Yes | No | Mock JSON event payloads used only for local testing. |
| `.env` | Yes | Yes | No | Local system environment variables. |
| `logs/cb.log` | Yes | Yes | No | Local development log file. |
| File or folder | Standard template | iParams template | Packaged | Purpose |
| -------------------- | ----------------- | ---------------- | -------- | ------------------------------------------------------------------------- |
| `manifest.json` | Yes | Yes | Yes | Maps Chargebee events to handler functions and declares npm dependencies. |
| `handler/handler.js` | Yes | Yes | Yes | Contains your core event-handling logic. |
| `iparams.json` | No | Yes | Yes | iParams template only. Defines the installation parameter schema. |
| `iparams.local.json` | No | Yes | No | iParams template only. Stores local test values, keyed by section name. |
| `test_data/` | Yes | Yes | No | Mock JSON event payloads used only for local testing. |
| `.env` | Yes | Yes | No | Local system environment variables. |
| `logs/cb.log` | Yes | Yes | No | Local development log file. |
### manifest.json — App configuration

@@ -82,2 +86,3 @@

"description": "A clear description of what your serverless app does",
"github_url": "https://github.com/your-org/your-repo",
"events": {

@@ -99,3 +104,3 @@ "customer_created": {

- **Handler names:** Each `handler` value must match a function exported from `handler/handler.js`.
- **Dependencies:** Only `chargebee` and `axios` are currently supported. For any additional npm packages, [contact the Chargebee support team](https://www.chargebee.com/docs/billing/2.0/kb/getting-started/how-to-contact-chargebees-support-team).
- **Dependencies:** Only `chargebee` and `axios` are currently supported. For any additional npm packages, contact the Chargebee support team.

@@ -137,3 +142,3 @@ ### handler/handler.js — Application logic

```plain text
```plain
MKPLC_CB_READ_ONLY_API=your_read_only_api_key_here

@@ -146,5 +151,5 @@ MKPLC_CB_READ_WRITE_API=your_read_write_api_key_here

<Note>
These environment variables are different from installation parameters (iParams). Environment variables are standard system values that Chargebee injects automatically and require no user action. iParams are user-defined settings that an installer provides when they install or update the app.
</Note>
> **Note**
>
> These environment variables are different from installation parameters (iParams). Environment variables are standard system values that Chargebee injects automatically and require no user action. iParams are user-defined settings that an installer provides when they install or update the app.

@@ -178,13 +183,15 @@ ## Define installation parameters (iParams)

| Type | Input or use case |
| --- | --- |
| `TEXT` | String (maximum 250 characters) for names, labels, and non-sensitive keys. |
| `SECRET` | String (maximum 250 characters) for passwords and API tokens. Encrypted at rest. Never log these values. |
| `URL` | Enforces valid `http://` or `https://` webhook and API endpoints. |
| `NUMBER` | Integer or decimal values for percentages, limits, and counts. |
| `BOOLEAN` | `true` or `false` toggles for feature flags. |
| `DROPDOWN` | Single selection from the choices in the `options` array. |
| `MULTISELECT_DROPDOWN` | Multiple selections from the choices in the `options` array. |
| `DATE` | Enforces `YYYY-MM-DD` formatting for expiry or start dates. |
| Type | Input or use case |
| ---------------------- | -------------------------------------------------------------------------------------------------------- |
| `TEXT` | String (maximum 250 characters) for names, labels, and non-sensitive keys. |
| `SECRET` | String (maximum 250 characters) for passwords and API tokens. Encrypted at rest. Never log these values. |
| `URL` | Enforces valid `http://` or `https://` webhook and API endpoints. |
| `NUMBER` | Integer or decimal values for percentages, limits, and counts. |
| `BOOLEAN` | `true` or `false` toggles for feature flags. |
| `DROPDOWN` | Single selection from the choices in the `options` array. |
| `MULTISELECT_DROPDOWN` | Multiple selections from the choices in the `options` array. |
| `DATE` | Enforces `YYYY-MM-DD` formatting for expiry or start dates. |
### Example: CRM schema with URL and SECRET

@@ -237,5 +244,5 @@

<Note>
`iparams.local.json` is never packaged. In production, users provide these values when they install or update the app.
</Note>
> **Note**
>
> `iparams.local.json` is never packaged. In production, users provide these values when they install or update the app.

@@ -287,3 +294,3 @@ ## Run and test locally

```plain text
```plain
my-first-app/

@@ -296,11 +303,6 @@ └── dist/

After you package your app, upload the ZIP file to the Apps portal in Chargebee Billing.
> **Note**
>
> To publish your app privately to your Chargebee site, [contact support](https://www.chargebee.com/docs/billing/2.0/kb/getting-started/how-to-contact-chargebees-support-team) with your packaged ZIP file.
1. In Chargebee Billing, go to **Apps** to open the Apps portal.
2. Click **Create App**.
3. On the **Upload Package** step, upload your app's `.zip` file. Click the upload area to browse, or drag and drop the file.
4. On the **Review Details** step, review your app's details.
5. Submit the app. Its status changes to **Under Review**.
6. When the review is complete, the **Result** step shows the outcome.
After your app is published, it appears in the Apps portal list, where you can track each app's type (private or public) and status, and manage updates.
Official documentation: [Chargebee Apps CLI Developer Guide](https://www.chargebee.com/docs/billing/2.0/chargebee-apps/cli-developer-guide)