@chargebee/chargebee-apps-libs 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +270 -0
  3. package/SECURITY.md +8 -0
  4. package/config/README.md +83 -0
  5. package/config/allowed-modules.json +24 -0
  6. package/dist/config/config-loader.d.ts +24 -0
  7. package/dist/config/config-loader.js +95 -0
  8. package/dist/index.d.ts +4 -0
  9. package/dist/index.js +21 -0
  10. package/dist/libs/port-service.d.ts +18 -0
  11. package/dist/libs/port-service.js +27 -0
  12. package/dist/logger/cb-public-logger.d.ts +59 -0
  13. package/dist/logger/cb-public-logger.js +158 -0
  14. package/dist/sandbox/public-sandbox-wrapper.d.ts +41 -0
  15. package/dist/sandbox/public-sandbox-wrapper.js +208 -0
  16. package/package.json +44 -0
  17. package/templates/serverless-node-starter-app/.env +4 -0
  18. package/templates/serverless-node-starter-app/README.md +290 -0
  19. package/templates/serverless-node-starter-app/handler/handler.js +34 -0
  20. package/templates/serverless-node-starter-app/jsconfig.json +35 -0
  21. package/templates/serverless-node-starter-app/manifest.json +15 -0
  22. package/templates/serverless-node-starter-app/test_data/customer_created.json +51 -0
  23. package/templates/serverless-node-starter-app/test_data/invoice_generated.json +112 -0
  24. package/templates/serverless-node-starter-app/test_data/subscription_created.json +173 -0
  25. package/templates/serverless-node-starter-app/types/types.d.ts +45 -0
  26. package/templates/serverless-node-starter-app-with-iparams/.env +4 -0
  27. package/templates/serverless-node-starter-app-with-iparams/README.md +717 -0
  28. package/templates/serverless-node-starter-app-with-iparams/handler/handler.js +39 -0
  29. package/templates/serverless-node-starter-app-with-iparams/iparams.json +41 -0
  30. package/templates/serverless-node-starter-app-with-iparams/iparams.local.json +9 -0
  31. package/templates/serverless-node-starter-app-with-iparams/jsconfig.json +35 -0
  32. package/templates/serverless-node-starter-app-with-iparams/manifest.json +15 -0
  33. package/templates/serverless-node-starter-app-with-iparams/test_data/customer_created.json +51 -0
  34. package/templates/serverless-node-starter-app-with-iparams/test_data/invoice_generated.json +112 -0
  35. package/templates/serverless-node-starter-app-with-iparams/test_data/subscription_created.json +173 -0
  36. package/templates/serverless-node-starter-app-with-iparams/types/types.d.ts +63 -0
  37. package/ui/README.md +118 -0
  38. package/ui/web/assets/css/main.css +1121 -0
  39. package/ui/web/assets/images/Chargebee-logo.png +0 -0
  40. package/ui/web/assets/js/main.js +61 -0
  41. package/ui/web/assets/js/modules/api.js +97 -0
  42. package/ui/web/assets/js/modules/constants.js +33 -0
  43. package/ui/web/assets/js/modules/editors.js +41 -0
  44. package/ui/web/assets/js/modules/events.js +195 -0
  45. package/ui/web/assets/js/modules/form-utils.js +70 -0
  46. package/ui/web/assets/js/modules/iparams-inputs.js +495 -0
  47. package/ui/web/assets/js/modules/iparams.js +82 -0
  48. package/ui/web/assets/js/modules/ui-utils.js +87 -0
  49. package/ui/web/index.html +164 -0
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.CBPublicLogger = void 0;
7
+ exports.createSafeConsole = createSafeConsole;
8
+ exports.createCBPublicLogger = createCBPublicLogger;
9
+ const chargebee_apps_shared_1 = require("@chargebee/chargebee-apps-shared");
10
+ const path_1 = __importDefault(require("path"));
11
+ const winston_1 = __importDefault(require("winston"));
12
+ /**
13
+ * Public logger implementation for local development
14
+ * This logger provides controlled logging capabilities for sandboxed code execution
15
+ * with correlation context and formatted output using Winston
16
+ */
17
+ class CBPublicLogger {
18
+ constructor(fileSystem, process, userCodeDir) {
19
+ this.userCodeDir = userCodeDir || process.cwd();
20
+ this.fileSystem = fileSystem;
21
+ this.process = process;
22
+ this.logger = this.createWinstonLogger();
23
+ }
24
+ /**
25
+ * Creates a Winston logger with console and file transports
26
+ * @returns {winston.Logger} Configured Winston logger instance
27
+ */
28
+ createWinstonLogger() {
29
+ // Get current log level from environment
30
+ const currentLogLevel = this.process.env['CB_LOG_LEVEL'] || chargebee_apps_shared_1.LogLevel.INFO;
31
+ try {
32
+ // Use the user code directory (where the logs should be stored)
33
+ const logsDir = path_1.default.join(this.userCodeDir, 'logs');
34
+ const logFilePath = path_1.default.join(logsDir, 'cb.log');
35
+ // Create logs directory if it doesn't exist
36
+ if (!this.fileSystem.existsSync(logsDir)) {
37
+ this.fileSystem.mkdirSync(logsDir, { recursive: true });
38
+ }
39
+ // Clear the log file on each run by writing an empty string
40
+ this.fileSystem.writeFileSync(logFilePath, '');
41
+ // Create transports
42
+ const transports = [
43
+ // Console transport for development output
44
+ new winston_1.default.transports.Console({
45
+ level: currentLogLevel.toLowerCase(),
46
+ format: winston_1.default.format.combine(winston_1.default.format.timestamp(), winston_1.default.format.colorize(), winston_1.default.format.errors({ stack: true }), winston_1.default.format.printf((info) => {
47
+ return this.formatMessage(info);
48
+ }))
49
+ }),
50
+ // Single file transport for all logs
51
+ new winston_1.default.transports.File({
52
+ filename: logFilePath,
53
+ level: currentLogLevel.toLowerCase(),
54
+ format: winston_1.default.format.combine(winston_1.default.format.errors({ stack: true }), winston_1.default.format.printf((info) => {
55
+ return this.formatMessage(info);
56
+ }))
57
+ })
58
+ ];
59
+ return winston_1.default.createLogger({
60
+ level: currentLogLevel.toLowerCase(),
61
+ format: winston_1.default.format.combine(winston_1.default.format.timestamp(), winston_1.default.format.errors({ stack: true })),
62
+ transports
63
+ });
64
+ }
65
+ catch (error) {
66
+ // Fallback to console if Winston initialization fails
67
+ chargebee_apps_shared_1.__logger.error('Failed to initialize Winston logger:', error);
68
+ // Return a minimal logger that just logs to console
69
+ return winston_1.default.createLogger({
70
+ level: currentLogLevel.toLowerCase(),
71
+ transports: [
72
+ new winston_1.default.transports.Console({
73
+ format: winston_1.default.format.simple()
74
+ })
75
+ ]
76
+ });
77
+ }
78
+ }
79
+ /**
80
+ * Logs an info message
81
+ * @param {...any[]} args - The message arguments to log
82
+ */
83
+ info(...args) {
84
+ this.logger.info(args.join(' '));
85
+ }
86
+ /**
87
+ * Logs a warning message
88
+ * @param {...any[]} args - The message arguments to log
89
+ */
90
+ warn(...args) {
91
+ this.logger.warn(args.join(' '));
92
+ }
93
+ /**
94
+ * Logs an error message
95
+ * @param {...any[]} args - The message arguments to log
96
+ */
97
+ error(...args) {
98
+ this.logger.error(args.join(' '));
99
+ }
100
+ /**
101
+ * Logs a debug message
102
+ * @param {...any[]} args - The message arguments to log
103
+ */
104
+ debug(...args) {
105
+ this.logger.debug(args.join(' '));
106
+ }
107
+ /**
108
+ * Formats a message with timestamp and level
109
+ * @param {winston.Logform.TransformableInfo} info - The log info
110
+ * @returns {string} The formatted message
111
+ */
112
+ formatMessage(info) {
113
+ const timestamp = info['timestamp'];
114
+ const level = info.level;
115
+ const message = info.message;
116
+ const context = chargebee_apps_shared_1.sandboxContext.getCurrentContext();
117
+ const eventId = context?.eventId || 'unknown';
118
+ const eventType = context?.eventType || 'unknown';
119
+ return `${timestamp} [${level}] [${eventId}] [${eventType}] ${message}`;
120
+ }
121
+ }
122
+ exports.CBPublicLogger = CBPublicLogger;
123
+ /**
124
+ * Creates a safe console object that uses the logger
125
+ * @param {ICBLogger} logger - The logger instance to use
126
+ * @returns {SafeConsole} A safe console object
127
+ */
128
+ function createSafeConsole(logger) {
129
+ return Object.freeze({
130
+ log: (...args) => logger.info(...args),
131
+ info: (...args) => logger.info(...args),
132
+ warn: (...args) => logger.warn(...args),
133
+ error: (...args) => logger.error(...args),
134
+ debug: (...args) => logger.debug(...args),
135
+ // Disable potentially dangerous console methods
136
+ trace: () => { },
137
+ table: () => { },
138
+ time: () => { },
139
+ timeEnd: () => { },
140
+ timeLog: () => { },
141
+ count: () => { },
142
+ countReset: () => { },
143
+ group: () => { },
144
+ groupCollapsed: () => { },
145
+ groupEnd: () => { },
146
+ clear: () => { }
147
+ });
148
+ }
149
+ /**
150
+ * Creates a new CBPublicLogger instance for a specific user code directory
151
+ * @param {CBFileSystem} fileSystem - The filesystem implementation to use
152
+ * @param {CBProcess} process - The process implementation to use
153
+ * @param {string} userCodeDir - The user code directory where logs should be stored
154
+ * @returns {CBPublicLogger} A new CBPublicLogger instance
155
+ */
156
+ function createCBPublicLogger(fileSystem, process, userCodeDir) {
157
+ return new CBPublicLogger(fileSystem, process, userCodeDir);
158
+ }
@@ -0,0 +1,41 @@
1
+ import { AllowedModule, CBFileSystem, DependencyManager, ExecutionResult, HandlerPayload, ICBLogger, ISandboxWrapper, ManifestValidator, PackageValidator, SandboxEnvironment } from '@chargebee/chargebee-apps-shared';
2
+ /**
3
+ * PublicSandboxWrapper provides a secure environment for executing user-provided NodeJS code
4
+ * Public implementation for local development environment
5
+ */
6
+ export declare class PublicSandboxWrapper implements ISandboxWrapper {
7
+ private allowedModules;
8
+ private manifestValidator;
9
+ private packageValidator;
10
+ private fileSystem;
11
+ private dependencyManager;
12
+ constructor(allowedModules: AllowedModule[], fileSystem: CBFileSystem, packageValidator: PackageValidator, dependencyManager: DependencyManager, manifestValidator: ManifestValidator);
13
+ /**
14
+ * Creates a safe require function that uses isolated node_modules
15
+ * @param {string} projectPath - Path to the user project
16
+ * @returns {Function} Safe require function
17
+ */
18
+ createSafeRequire(projectPath: string): (moduleName: string) => any;
19
+ /**
20
+ * Loads environment variables from .env file in the project directory
21
+ * @param {string} projectPath - Path to the user project
22
+ * @returns {Record<string, string>} Environment variables object
23
+ */
24
+ private loadEnvironmentVariables;
25
+ /**
26
+ * Creates a secure sandbox environment for code execution
27
+ * @param {string} projectPath - Path to the user project
28
+ * @param {HandlerPayload} payload - Handler payload (event + iparams) to expose to user code
29
+ * @param {ICBLogger} sessionLogger - Logger instance for this server session
30
+ * @returns {SandboxEnvironment} The sandbox environment object
31
+ */
32
+ createSandbox(projectPath: string, payload: HandlerPayload, sessionLogger: ICBLogger): SandboxEnvironment;
33
+ /**
34
+ * Executes user-provided code in a secure sandbox environment.
35
+ * @param userCodePath - Path to the directory containing user code
36
+ * @param payload - Handler payload (event + iparams) to pass to the user handler
37
+ * @param sessionLogger - The logger instance for this server session
38
+ * @returns {Promise<ExecutionResult>} Execution result with success status and data/error
39
+ */
40
+ execute(userCodePath: string, payload: HandlerPayload, sessionLogger: ICBLogger): Promise<ExecutionResult>;
41
+ }
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.PublicSandboxWrapper = void 0;
40
+ const chargebee_apps_shared_1 = require("@chargebee/chargebee-apps-shared");
41
+ const path_1 = __importDefault(require("path"));
42
+ const vm_1 = __importDefault(require("vm"));
43
+ const dotenv = __importStar(require("dotenv"));
44
+ const cb_public_logger_1 = require("../logger/cb-public-logger");
45
+ /**
46
+ * PublicSandboxWrapper provides a secure environment for executing user-provided NodeJS code
47
+ * Public implementation for local development environment
48
+ */
49
+ class PublicSandboxWrapper {
50
+ constructor(allowedModules, fileSystem, packageValidator, dependencyManager, manifestValidator) {
51
+ this.fileSystem = fileSystem;
52
+ this.packageValidator = packageValidator;
53
+ this.dependencyManager = dependencyManager;
54
+ this.allowedModules = allowedModules;
55
+ this.manifestValidator = manifestValidator;
56
+ }
57
+ /**
58
+ * Creates a safe require function that uses isolated node_modules
59
+ * @param {string} projectPath - Path to the user project
60
+ * @returns {Function} Safe require function
61
+ */
62
+ createSafeRequire(projectPath) {
63
+ return this.dependencyManager.createIsolatedRequire(projectPath, this.allowedModules);
64
+ }
65
+ /**
66
+ * Loads environment variables from .env file in the project directory
67
+ * @param {string} projectPath - Path to the user project
68
+ * @returns {Record<string, string>} Environment variables object
69
+ */
70
+ loadEnvironmentVariables(projectPath) {
71
+ const envPath = path_1.default.join(projectPath, '.env');
72
+ const envVars = {};
73
+ try {
74
+ // Load .env file if it exists
75
+ const result = dotenv.config({ path: envPath });
76
+ if (result.parsed) {
77
+ // Only include MKPLC_CB_READ_ONLY_API and MKPLC_CB_READ_WRITE_API keys
78
+ if (result.parsed['MKPLC_CB_READ_ONLY_API']) {
79
+ envVars['MKPLC_CB_READ_ONLY_API'] = result.parsed['MKPLC_CB_READ_ONLY_API'];
80
+ }
81
+ if (result.parsed['MKPLC_CB_READ_WRITE_API']) {
82
+ envVars['MKPLC_CB_READ_WRITE_API'] = result.parsed['MKPLC_CB_READ_WRITE_API'];
83
+ }
84
+ if (result.parsed['MKPLC_SITE_DOMAIN']) {
85
+ envVars['MKPLC_SITE_DOMAIN'] = result.parsed['MKPLC_SITE_DOMAIN'];
86
+ }
87
+ else {
88
+ envVars['MKPLC_SITE_DOMAIN'] = '';
89
+ }
90
+ }
91
+ }
92
+ catch (error) {
93
+ chargebee_apps_shared_1.__logger.debug(`Failed to load .env file from ${envPath}: ${error}`);
94
+ }
95
+ return envVars;
96
+ }
97
+ /**
98
+ * Creates a secure sandbox environment for code execution
99
+ * @param {string} projectPath - Path to the user project
100
+ * @param {HandlerPayload} payload - Handler payload (event + iparams) to expose to user code
101
+ * @param {ICBLogger} sessionLogger - Logger instance for this server session
102
+ * @returns {SandboxEnvironment} The sandbox environment object
103
+ */
104
+ createSandbox(projectPath, payload, sessionLogger) {
105
+ const moduleObj = { exports: {} };
106
+ const exportsObj = moduleObj.exports;
107
+ // Load environment variables from .env file
108
+ const envVars = this.loadEnvironmentVariables(projectPath);
109
+ const hasIparams = Object.prototype.hasOwnProperty.call(payload, 'iparams');
110
+ const safePayload = Object.freeze(hasIparams
111
+ ? { event: payload.event, iparams: payload.iparams ?? {} }
112
+ : { event: payload.event });
113
+ return {
114
+ // Controlled logging
115
+ console: (0, cb_public_logger_1.createSafeConsole)(sessionLogger),
116
+ // Read-only payload (event + iparams) for handler(payload)
117
+ payload: safePayload,
118
+ // Safe async primitives
119
+ setTimeout,
120
+ clearTimeout,
121
+ setImmediate,
122
+ clearImmediate,
123
+ // CommonJS emulation
124
+ module: moduleObj,
125
+ exports: exportsObj,
126
+ // Controlled module access
127
+ require: this.createSafeRequire(projectPath),
128
+ // Limited process access
129
+ process: {
130
+ cwd: () => process.cwd(),
131
+ env: envVars,
132
+ nextTick: process.nextTick
133
+ },
134
+ // Prevent escape hatches
135
+ global: undefined,
136
+ Buffer: undefined,
137
+ __dirname: undefined,
138
+ __filename: undefined
139
+ };
140
+ }
141
+ /**
142
+ * Executes user-provided code in a secure sandbox environment.
143
+ * @param userCodePath - Path to the directory containing user code
144
+ * @param payload - Handler payload (event + iparams) to pass to the user handler
145
+ * @param sessionLogger - The logger instance for this server session
146
+ * @returns {Promise<ExecutionResult>} Execution result with success status and data/error
147
+ */
148
+ async execute(userCodePath, payload, sessionLogger) {
149
+ try {
150
+ chargebee_apps_shared_1.__logger.debug(`Executing user code from: ${userCodePath}`);
151
+ // Check if required files exist.
152
+ this.packageValidator.validateHandlerExists(userCodePath);
153
+ this.packageValidator.validateManifestExists(userCodePath);
154
+ // Validate manifest file.
155
+ const manifestPath = path_1.default.join(userCodePath, 'manifest.json');
156
+ const manifest = this.manifestValidator.validateAndGetManifestFile(manifestPath);
157
+ // Load user code
158
+ const eventType = payload.event.event_type;
159
+ const eventConfig = manifest.events[eventType];
160
+ if (!eventConfig) {
161
+ throw new Error(`No handler configured for event type: ${eventType}`);
162
+ }
163
+ const handler = eventConfig.handler;
164
+ const handlerPath = path_1.default.join(userCodePath, 'handler', 'handler.js');
165
+ const userCode = this.fileSystem.readFileSync(handlerPath, 'utf8');
166
+ // Create execution context
167
+ const contextData = {
168
+ eventId: payload.event.id || 'unknown',
169
+ eventType: payload.event.event_type || 'unknown',
170
+ };
171
+ return await chargebee_apps_shared_1.sandboxContext.run(contextData, async () => {
172
+ const sandbox = this.createSandbox(userCodePath, payload, sessionLogger);
173
+ const vmContext = vm_1.default.createContext(sandbox);
174
+ // Execute user code and run handler with single payload argument
175
+ const executeCode = `
176
+ (async function() {
177
+ "use strict";
178
+ try {
179
+ ${userCode}
180
+ const handler = module.exports["${handler}"];
181
+ if (typeof handler !== 'function') {
182
+ throw new Error('Handler function "${handler}" not found in handler.js');
183
+ }
184
+ return await handler(payload);
185
+ } catch (error) {
186
+ console.error(error.stack ? error.stack : error);
187
+ throw error;
188
+ }
189
+ })()
190
+ `;
191
+ await vm_1.default.runInContext(executeCode, vmContext, {
192
+ timeout: 15000, // 15 second timeout
193
+ displayErrors: true
194
+ });
195
+ return { success: true, statusCode: 200 };
196
+ });
197
+ }
198
+ catch (error) {
199
+ const err = error;
200
+ return {
201
+ success: false,
202
+ error: `${err.message}`,
203
+ stack: err.stack || undefined
204
+ };
205
+ }
206
+ }
207
+ }
208
+ exports.PublicSandboxWrapper = PublicSandboxWrapper;
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@chargebee/chargebee-apps-libs",
3
+ "version": "0.0.2",
4
+ "description": "Public library implementations for Chargebee Apps CLI",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "templates",
10
+ "config",
11
+ "ui",
12
+ "LICENSE",
13
+ "SECURITY.md"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "clean": "rm -rf dist && rm -rf coverage",
18
+ "test": "jest",
19
+ "test:watch": "jest --watch",
20
+ "test:coverage": "jest --coverage",
21
+ "test:unit": "jest --testPathPattern=tests/unit",
22
+ "minify": "esbuild 'dist/**/*.js' --minify --platform=node --outdir=dist --allow-overwrite"
23
+ },
24
+ "dependencies": {
25
+ "@chargebee/chargebee-apps-shared": "0.0.2",
26
+ "dotenv": "^16.3.1"
27
+ },
28
+ "devDependencies": {
29
+ "@types/jest": "^29.5.0",
30
+ "@types/node": "^24.3.0",
31
+ "@types/dotenv": "^8.2.0",
32
+ "esbuild": "^0.28.1",
33
+ "jest": "^29.5.0",
34
+ "ts-jest": "^29.1.0",
35
+ "typescript": "^5.0.0"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "license": "MIT",
41
+ "engines": {
42
+ "node": ">=22.0.0"
43
+ }
44
+ }
@@ -0,0 +1,4 @@
1
+ # Only these three variables are supported. Replace values for local development only. Do not add new vars.
2
+ MKPLC_CB_READ_ONLY_API=REPLACE_WITH_READ_ONLY_API_KEY
3
+ MKPLC_CB_READ_WRITE_API=REPLACE_WITH_READ_WRITE_API_KEY
4
+ MKPLC_SITE_DOMAIN=REPLACE_WITH_SITE_DOMAIN