@chargebee/chargebee-apps 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.
package/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2011-2024 Chargebee, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person
6
+ obtaining a copy of this software and associated documentation
7
+ files (the "Software"), to deal in the Software without
8
+ restriction, including without limitation the rights to use,
9
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the
11
+ Software is furnished to do so, subject to the following
12
+ conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
+ OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,472 @@
1
+ # @chargebee/chargebee-apps
2
+
3
+ The official CLI tool for creating, testing, and packaging serverless applications for Chargebee Apps.
4
+
5
+ **CLI Command Name**: `chargebee-apps`
6
+
7
+ ## Overview
8
+
9
+ The Chargebee Apps CLI is a comprehensive command-line tool that enables developers to build, test, and package serverless applications for Chargebee Apps platform. It provides a complete local development environment with web UI, secure sandbox execution, and automated packaging capabilities.
10
+
11
+ ## Installation
12
+
13
+ ### Global Installation (Recommended)
14
+ ```bash
15
+ npm install -g @chargebee/chargebee-apps
16
+ ```
17
+
18
+ ### Local Installation
19
+ ```bash
20
+ npm install @chargebee/chargebee-apps
21
+ npx chargebee-apps --help
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ```bash
27
+ # 1. Create a new serverless application
28
+ chargebee-apps create my-app
29
+
30
+ # 2. Run the application locally with web UI
31
+ chargebee-apps run my-app
32
+
33
+ # 3. Open http://localhost:15000 to test your handlers
34
+
35
+ # 4. Package for deployment
36
+ chargebee-apps package my-app
37
+ ```
38
+
39
+ ## Commands
40
+
41
+ ### `create <directory>`
42
+
43
+ Creates a new serverless application from a template.
44
+
45
+ ```bash
46
+ chargebee-apps create my-app
47
+ chargebee-apps create my-app --template serverless-node-starter-app
48
+ chargebee-apps create my-app --template serverless-node-starter-app-with-iparams
49
+ ```
50
+
51
+ **Options:**
52
+ - `--template <name>` - Template to use (default: `serverless-node-starter-app`)
53
+ - `serverless-node-starter-app` — basic event handlers
54
+ - `serverless-node-starter-app-with-iparams` — includes support for installation parameters
55
+
56
+ **What it creates:**
57
+ - `manifest.json` - Application configuration
58
+ - `handler/handler.js` - Event handler implementations
59
+ - `test_data/` - Sample event data for testing
60
+ - `types/types.d.ts` - TypeScript definitions
61
+ - `jsconfig.json` - JavaScript project configuration
62
+
63
+ ### `run <directory>`
64
+
65
+ Starts a local development server for testing your application.
66
+
67
+ ```bash
68
+ chargebee-apps run my-app
69
+ chargebee-apps run my-app --port 3000
70
+ ```
71
+
72
+ **Options:**
73
+ - `-p, --port <port>` - Port to run the server on (default: `15000`)
74
+
75
+ **Features:**
76
+ - **Web UI**: Interactive testing interface at `http://localhost:15000`
77
+ - **Iparams UI**: Edit sectioned parameter definitions and local values (when using the iparams template)
78
+ - **API Endpoints**: RESTful API for programmatic testing
79
+ - **Real-time Testing**: Execute handlers with custom event data
80
+ - **Iparam validation**: Validates `iparams.json` on startup when present
81
+ - **Error Handling**: Clear error messages and debugging info
82
+
83
+ **Web UI Features:**
84
+ - Event type selection from your manifest
85
+ - JSON editor with syntax highlighting
86
+ - Auto-loading of sample test data
87
+ - Real-time execution results
88
+ - Error reporting and debugging
89
+
90
+ ### `package <directory>`
91
+
92
+ Creates a deployment-ready zip package of your application.
93
+
94
+ ```bash
95
+ chargebee-apps package my-app
96
+ chargebee-apps package my-app --name production-v1.0.0
97
+ ```
98
+
99
+ **Options:**
100
+ - `--name <name>` - Custom package name (without .zip extension)
101
+
102
+ **Package Contents:**
103
+ - `manifest.json` - Application configuration
104
+ - `iparams.json` - Parameter definitions (when present)
105
+ - `handler/` - All JavaScript and JSON files from handler directory
106
+ - Excludes: development files, node_modules, test files, `iparams.local.json`
107
+
108
+ **Output:**
109
+ - Creates `dist/` directory in your app
110
+ - Generates `{app-name}.zip` or custom named package
111
+ - Displays package size and contents
112
+
113
+ ## Application Structure
114
+
115
+ ### Required Files
116
+
117
+ #### `manifest.json`
118
+ Defines your application configuration and event handlers.
119
+
120
+ ```json
121
+ {
122
+ "events": {
123
+ "customer_created": {
124
+ "handler": "customerCreateHandler"
125
+ },
126
+ "subscription_created": {
127
+ "handler": "subscriptionCreatedHandler"
128
+ }
129
+ },
130
+ "dependencies": {
131
+ "lodash": "^4.17.21"
132
+ }
133
+ }
134
+ ```
135
+
136
+ #### `handler/handler.js`
137
+ Contains your event handler implementations. Each handler receives a single `payload` object with `payload.event` (event data) and, when iparams are defined, `payload.iparams.<section>.<param>` (installation parameters).
138
+
139
+ ```javascript
140
+ module.exports = {
141
+ customerCreateHandler: function(payload) {
142
+ console.log('Customer created:', payload.event.content.customer.email);
143
+ console.log('Processing fee (%):', payload.iparams.processing_fee_configuration.fee_percentage);
144
+ return {
145
+ status: 'success',
146
+ message: 'Customer processed successfully'
147
+ };
148
+ },
149
+
150
+ subscriptionCreatedHandler: function(payload) {
151
+ console.log('Subscription created:', payload.event.content.subscription.id);
152
+ console.log('Late payment fee (%):', payload.iparams.late_payment_fee_configuration.fee_percentage);
153
+ return {
154
+ status: 'success',
155
+ message: 'Subscription processed successfully'
156
+ };
157
+ }
158
+ };
159
+ ```
160
+
161
+ ### Optional Files
162
+
163
+ #### `test_data/`
164
+ Sample event data files for testing (JSON format).
165
+
166
+ ```
167
+ test_data/
168
+ ├── customer_created.json
169
+ ├── subscription_created.json
170
+ └── invoice_generated.json
171
+ ```
172
+
173
+ #### `types/types.d.ts`
174
+ TypeScript definitions for better development experience.
175
+
176
+ ```typescript
177
+ interface HandlerPayload {
178
+ event: EventRecord;
179
+ iparams?: Record<string, Record<string, string | number | boolean | string[]>>;
180
+ }
181
+ ```
182
+
183
+ #### `iparams.json` and `iparams.local.json` (optional)
184
+ For apps that need user-configurable settings beyond the three system env vars. Parameters are grouped into **sections**:
185
+
186
+ - **`iparams.json`** — schema under `installation_parameters.sections[]` (packaged for deployment)
187
+ - **`iparams.local.json`** — local test values keyed by section name (not packaged)
188
+
189
+ Handlers access values as `payload.iparams.<section_name>.<param_name>`. An empty `{}` in either file means no iparams are defined.
190
+
191
+ See the [iparams template README](../public-libs/templates/serverless-node-starter-app-with-iparams/README.md#installation-parameters-iparams) for the full schema, validation rules, and examples.
192
+
193
+ ## API Reference
194
+
195
+ When running the development server, these endpoints are available:
196
+
197
+ ### `GET /`
198
+ Serves the web UI for interactive testing.
199
+
200
+ ### `GET /api/manifest`
201
+ Returns application manifest and handler validation status.
202
+
203
+ **Response:**
204
+ ```json
205
+ {
206
+ "events": [
207
+ {
208
+ "event_type": "customer_created",
209
+ "handler": {
210
+ "name": "customerCreateHandler",
211
+ "exists": true
212
+ },
213
+ "has_test_data": true
214
+ }
215
+ ]
216
+ }
217
+ ```
218
+
219
+ ### `GET /api/test-data/:eventType`
220
+ Returns sample test data for the specified event type.
221
+
222
+ ### `POST /api/invoke`
223
+ Executes a handler with provided event data.
224
+
225
+ **Request:**
226
+ ```json
227
+ {
228
+ "event_type": "customer_created",
229
+ "id": "evt_123",
230
+ "occurred_at": "2024-01-01T00:00:00Z",
231
+ "customer": {
232
+ "email": "test@example.com"
233
+ }
234
+ }
235
+ ```
236
+
237
+ **Response:**
238
+ ```json
239
+ {
240
+ "status": "success"
241
+ }
242
+ ```
243
+
244
+ ### `GET /api/iparams`
245
+ Returns the sectioned parameter definitions from `iparams.json`.
246
+
247
+ ### `POST /api/iparams`
248
+ Saves validated parameter definitions to `iparams.json`.
249
+
250
+ **Request body:** `{ "iparams": { "installation_parameters": { "sections": [...] } } }`
251
+
252
+ ### `GET /api/iparams/inputs`
253
+ Returns parameter values from `iparams.local.json` (keyed by section).
254
+
255
+ ### `POST /api/iparams/inputs`
256
+ Validates and saves parameter values to `iparams.local.json`.
257
+
258
+ **Request body:** `{ "inputs": { "<section_name>": { "<param_name>": <value> } } }`
259
+
260
+ ## Development Workflow
261
+
262
+ ### 1. Project Creation
263
+ ```bash
264
+ # Create new project
265
+ chargebee-apps create my-serverless-app
266
+ cd my-serverless-app
267
+
268
+ # Examine the generated structure
269
+ ls -la
270
+ ```
271
+
272
+ ### 2. Local Development
273
+ ```bash
274
+ # Start development server
275
+ chargebee-apps run . --port 3000
276
+
277
+ # Open web UI in browser
278
+ open http://localhost:3000
279
+ ```
280
+
281
+ ### 3. Testing
282
+ - Use the web UI to test different event types
283
+ - Modify handler code and refresh to see changes
284
+ - Check console logs for handler output
285
+ - Use custom JSON data for edge case testing
286
+
287
+ ### 4. Packaging
288
+ ```bash
289
+ # Create deployment package
290
+ chargebee-apps package . --name production-v1.0.0
291
+
292
+ # Verify package contents
293
+ unzip -l dist/production-v1.0.0.zip
294
+ ```
295
+
296
+ ## Advanced Usage
297
+
298
+ ### Custom Templates
299
+ You can create custom templates by placing them in the templates directory:
300
+
301
+ ```
302
+ templates/
303
+ └── my-custom-template/
304
+ ├── manifest.json
305
+ ├── handler/
306
+ │ └── handler.js
307
+ └── README.md
308
+ ```
309
+
310
+ ### Environment Configuration
311
+ The CLI respects these environment variables:
312
+
313
+ - `MKPLC_CB_READ_ONLY_API` - Chargebee read-only API key for accessing Chargebee data without modifications
314
+ - `MKPLC_CB_READ_WRITE_API` - Chargebee read-write API key for full access to modify Chargebee data
315
+ - `MKPLC_SITE_DOMAIN` - Chargebee site domain (e.g., `your-site.chargebee.com`) that gets passed to the application handlers
316
+ - `CB_LOG_LEVEL` - Controls logging verbosity (DEBUG, INFO, WARN, ERROR)
317
+ - `NODE_ENV` - Affects development vs production behavior
318
+
319
+ ### Programmatic API Testing
320
+
321
+ ```bash
322
+ # Test via curl
323
+ curl -X POST http://localhost:15000/api/invoke \
324
+ -H "Content-Type: application/json" \
325
+ -d '{
326
+ "event_type": "customer_created",
327
+ "customer": {"email": "test@example.com"}
328
+ }'
329
+ ```
330
+
331
+ ### Multiple Applications
332
+ ```bash
333
+ # Run multiple apps on different ports
334
+ chargebee-apps run app1 --port 3001
335
+ chargebee-apps run app2 --port 3002
336
+ chargebee-apps run app3 --port 3003
337
+ ```
338
+
339
+ ## Troubleshooting
340
+
341
+ ### Common Issues
342
+
343
+ #### "Application directory does not exist"
344
+ Make sure you're running commands from the correct directory or providing the correct path.
345
+
346
+ #### "manifest.json not found"
347
+ Ensure your application has a valid `manifest.json` file in the root directory.
348
+
349
+ #### "handler.js not found"
350
+ Make sure you have a `handler/handler.js` file with your event handler implementations.
351
+
352
+ #### "Invalid port number"
353
+ Port must be a valid number between 1 and 65535.
354
+
355
+ #### "Port already in use"
356
+ Choose a different port using the `--port` option.
357
+
358
+ ### Debug Mode
359
+ ```bash
360
+ CB_LOG_LEVEL=DEBUG chargebee-apps run my-app
361
+ ```
362
+
363
+ ### Getting Help
364
+ ```bash
365
+ chargebee-apps --help
366
+ chargebee-apps create --help
367
+ chargebee-apps run --help
368
+ chargebee-apps package --help
369
+ ```
370
+
371
+ ## Package Structure
372
+
373
+ - [`src/commands/`](src/commands/README.md) - CLI command implementations (create, run, package)
374
+ - [`src/api/`](src/api/README.md) - Express server with web UI and API endpoints
375
+ - `src/registry.ts` - Dependency injection registry
376
+ - `tests/unit/` - Unit tests for CLI commands
377
+ - `tests/integration/` - Integration tests for end-to-end workflows
378
+
379
+ ## Architecture
380
+
381
+ ### Dependencies
382
+ The public CLI uses these core packages:
383
+ - `@chargebee/chargebee-apps-shared` - Common interfaces and types
384
+ - `@chargebee/chargebee-apps-libs` - Local development implementations
385
+
386
+ ### Security
387
+ - **Sandboxed Execution**: User code runs in isolated VM contexts
388
+ - **Module Whitelisting**: Only approved npm modules can be used
389
+ - **Path Restrictions**: File operations are limited to safe directories
390
+ - **Input Validation**: All user inputs are validated before processing
391
+
392
+ ### Performance
393
+ - **Fast Startup**: Optimized for quick development iterations
394
+ - **Efficient Packaging**: Only includes necessary files in packages
395
+ - **Caching**: Configuration and dependencies are cached for performance
396
+
397
+ ## Examples
398
+
399
+ ### Basic Handler
400
+ ```javascript
401
+ // handler/handler.js
402
+ module.exports = {
403
+ customerCreateHandler: function(event) {
404
+ // Process customer creation
405
+ const customer = event.customer;
406
+
407
+ console.log(`New customer: ${customer.email}`);
408
+
409
+ // Return response
410
+ return {
411
+ status: 'success',
412
+ message: `Customer ${customer.email} processed`
413
+ };
414
+ }
415
+ };
416
+ ```
417
+
418
+ ### Using Dependencies
419
+ ```javascript
420
+ // handler/handler.js
421
+ const _ = require('lodash');
422
+
423
+ module.exports = {
424
+ dataProcessHandler: function(event) {
425
+ // Use lodash for data manipulation
426
+ const processedData = _.map(event.data, item => ({
427
+ id: item.id,
428
+ name: _.capitalize(item.name),
429
+ timestamp: new Date().toISOString()
430
+ }));
431
+
432
+ return {
433
+ status: 'success',
434
+ processed_count: processedData.length,
435
+ data: processedData
436
+ };
437
+ }
438
+ };
439
+ ```
440
+
441
+ ### Error Handling
442
+ ```javascript
443
+ // handler/handler.js
444
+ module.exports = {
445
+ robustHandler: function(event) {
446
+ try {
447
+ // Process event
448
+ if (!event.required_field) {
449
+ throw new Error('Missing required field');
450
+ }
451
+
452
+ // Business logic here
453
+ const result = processBusinessLogic(event);
454
+
455
+ return {
456
+ status: 'success',
457
+ result: result
458
+ };
459
+ } catch (error) {
460
+ console.error('Handler error:', error.message);
461
+ return {
462
+ status: 'error',
463
+ message: error.message
464
+ };
465
+ }
466
+ }
467
+ };
468
+ ```
469
+
470
+ ## Version History
471
+
472
+ See [CHANGELOG.md](CHANGELOG.md) for detailed version history.
package/SECURITY.md ADDED
@@ -0,0 +1,8 @@
1
+ # Security Policy
2
+
3
+ At Chargebee, we take data integrity and security very seriously. Due to the nature of the product and service we provide, we are committed to working with individuals to stay updated on the latest security techniques and fix any security weakness in our application or infrastructure reported to us responsibly by external parties.
4
+
5
+ https://www.chargebee.com/security/responsible-disclosure-policy/
6
+
7
+ ## Reporting a vulnerability
8
+ Reach out to us at security@chargebee.com. Please do not open GitHub issues or pull requests as this makes the problem immediately visible to everyone, including malicious actors. Chargebee's security team will triage your report and respond according to its impact.
package/bin/index.js ADDED
@@ -0,0 +1 @@
1
+ require("../dist/index.js");
@@ -0,0 +1,6 @@
1
+ import { CBFileSystem } from '@chargebee/chargebee-apps-shared';
2
+ import { Application } from 'express';
3
+ /**
4
+ * Sets up all iparams-related API routes
5
+ */
6
+ export declare function setupIparamsRoutes(app: Application, userCodeDir: string, fileSystem: CBFileSystem): void;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setupIparamsRoutes = setupIparamsRoutes;
4
+ const chargebee_apps_shared_1 = require("@chargebee/chargebee-apps-shared");
5
+ const registry_1 = require("../registry");
6
+ const REGISTRY = registry_1.PublicCliRegistry.getInstance();
7
+ const __logger = REGISTRY.logger;
8
+ /**
9
+ * Sets up all iparams-related API routes
10
+ */
11
+ function setupIparamsRoutes(app, userCodeDir, fileSystem) {
12
+ const service = new chargebee_apps_shared_1.IparamsService(fileSystem);
13
+ app.get('/api/iparams', (_req, res) => {
14
+ try {
15
+ return res.json({ iparams: service.loadIparamDefns(userCodeDir) });
16
+ }
17
+ catch (error) {
18
+ __logger.error('Error: Failed to load iparams.json', error);
19
+ const rawContent = error.rawContent ?? null;
20
+ return res.status(400).json({
21
+ error: 'Failed to load iparams.json',
22
+ message: error instanceof Error ? error.message : 'Unknown error',
23
+ rawContent
24
+ });
25
+ }
26
+ });
27
+ app.post('/api/iparams', (req, res) => {
28
+ try {
29
+ const iparamDefns = req.body.iparams;
30
+ service.saveIparamDefns(userCodeDir, iparamDefns);
31
+ return res.json({ success: true, message: 'Iparams saved successfully' });
32
+ }
33
+ catch (error) {
34
+ __logger.error('Error: Failed to save iparams', error);
35
+ return res.status(400).json({
36
+ error: 'Failed to save iparams',
37
+ message: error instanceof Error ? error.message : 'Unknown error'
38
+ });
39
+ }
40
+ });
41
+ app.get('/api/iparams/inputs', (_req, res) => {
42
+ try {
43
+ return res.json({ inputs: service.loadInputs(userCodeDir) });
44
+ }
45
+ catch (error) {
46
+ __logger.error('Error: Failed to load iparams.local.json', error);
47
+ return res.status(400).json({
48
+ error: 'Failed to load iparams.local.json',
49
+ message: error instanceof Error ? error.message : 'Unknown error'
50
+ });
51
+ }
52
+ });
53
+ app.post('/api/iparams/inputs', (req, res) => {
54
+ try {
55
+ service.saveInputs(userCodeDir, req.body.inputs);
56
+ return res.json({ success: true, message: 'Inputs saved successfully' });
57
+ }
58
+ catch (error) {
59
+ if (error instanceof chargebee_apps_shared_1.MissingRequiredParamsError) {
60
+ return res.status(400).json({
61
+ valid: false,
62
+ missing: error.missing,
63
+ message: error.message
64
+ });
65
+ }
66
+ __logger.error('Error: Failed to save iparams inputs', error);
67
+ return res.status(400).json({
68
+ error: 'Failed to save iparams inputs',
69
+ message: error instanceof Error ? error.message : 'Unknown error'
70
+ });
71
+ }
72
+ });
73
+ }
@@ -0,0 +1,39 @@
1
+ import { CBFileSystem, CBProcess, DependencyManager, EventRecord, ICBLogger } from '@chargebee/chargebee-apps-shared';
2
+ import { Application } from 'express';
3
+ import * as http from "http";
4
+ /**
5
+ * Sets up and start an Express server for the serverless app tester
6
+ * @param {number} port - The port number to run the server on
7
+ * @param {string} userCodeDir - The user code directory where logs should be stored
8
+ * @param {CBFileSystem} fileSystem - The filesystem implementation to use
9
+ * @param {CBProcess} processService - The process implementation to use
10
+ * @param {DependencyManager} dependencyManager - The dependency manager implementation to use
11
+ */
12
+ export declare function setupServer(port: number, userCodeDir: string, fileSystem?: CBFileSystem, processService?: CBProcess, dependencyManager?: DependencyManager): http.Server;
13
+ /**
14
+ * Invokes an event handler based on the event data
15
+ * @param {EventRecord} eventData - The event data containing event_type and payload
16
+ * @param {ICBLogger} sessionLogger - The logger instance for this server session
17
+ * @param {string} userCodeDir - The user code directory
18
+ * @param {CBFileSystem} fileSystem - The filesystem implementation to use
19
+ * @param {DependencyManager} dependencyManager - The dependency manager implementation to use
20
+ * @returns {Promise<any>} The result from the handler function
21
+ * @throws {Error} If handler file, manifest, or handler function is not found
22
+ */
23
+ export declare function invokeEventHandler(eventData: EventRecord, sessionLogger: ICBLogger, userCodeDir: string, fileSystem: CBFileSystem, dependencyManager: DependencyManager): Promise<any>;
24
+ /**
25
+ * Sets up all API routes for the serverless app tester
26
+ * @param {Application} app - Express application instance
27
+ * @param {ICBLogger} sessionLogger - The logger instance for this server session
28
+ * @param {string} userCodeDir - The user code directory
29
+ * @param {CBFileSystem} fileSystem - The filesystem implementation to use
30
+ * @param {CBProcess} process - The process implementation to use
31
+ * @param {DependencyManager} dependencyManager - The dependency manager implementation to use
32
+ */
33
+ export declare function setupApiRoutes(app: Application, sessionLogger: ICBLogger, userCodeDir: string, fileSystem: CBFileSystem, process: CBProcess, dependencyManager: DependencyManager): void;
34
+ /**
35
+ * Sets up application routes for serving the web UI
36
+ * @param {Application} app - Express application instance
37
+ * @param {CBFileSystem} fileSystem - The filesystem implementation to use
38
+ */
39
+ export declare function setupAppRoutes(app: Application, fileSystem: CBFileSystem): void;