Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/API/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
"array",
"number"
],
"alias": ["stopExitCodes"],
"docDescription": "List of exit codes that should allow the process to stop (skip autorestart)."
},
"watch_delay": {
Expand Down
28 changes: 27 additions & 1 deletion lib/God/ForkMode.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,32 @@ var cst = require('../../constants.js');
* @param {} God
* @return
*/
/**
* Sanitize pm2_env object for use as child process environment variables.
* Filters out non-primitive values (objects, arrays, functions) that would
* be stringified to "[object Object]" or similar when passed as env vars.
* @method sanitizeProcessEnv
* @param {Object} pm2_env - The PM2 environment object
* @return {Object} A new object containing only string-safe environment variables
*/
function sanitizeProcessEnv(pm2_env) {
var sanitized = {};

Object.keys(pm2_env).forEach(function(key) {
var value = pm2_env[key];
if (value === null || value === undefined) {
return;
}
// Only pass primitive types that can be safely represented as strings
var type = typeof value;
if (type === 'string' || type === 'number' || type === 'boolean') {
sanitized[key] = String(value);
}
});

return sanitized;
}

module.exports = function ForkMode(God) {
/**
* For all apps - FORK MODE
Expand Down Expand Up @@ -94,7 +120,7 @@ module.exports = function ForkMode(God) {

try {
var options = {
env : pm2_env,
env : sanitizeProcessEnv(pm2_env),
detached : true,
cwd : pm2_env.pm_cwd || process.cwd(),
stdio : ['pipe', 'pipe', 'pipe', 'ipc'] //Same as fork() in node core
Expand Down
47 changes: 43 additions & 4 deletions lib/tools/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,56 @@ var Config = module.exports = {
/**
* Filter / Alias options
*/
/**
* Convert a snake_case string to camelCase.
* @method snakeToCamel
* @param {String} str
* @return {String}
*/
function snakeToCamel(str) {
return str.replace(/_([a-z])/g, function(match, letter) {
return letter.toUpperCase();
});
}

/**
* Filter commander options and map them to schema keys.
* Supports explicit aliases defined in the schema as well as
* automatic camelCase matching (e.g. commander's --stop-exit-codes
* becomes stopExitCodes which maps to schema key stop_exit_codes).
* @method filterOptions
* @param {Object} cmd - Commander options object
* @return {Object} Filtered configuration object with schema keys
*/
Config.filterOptions = function(cmd) {
var conf = {};
var schema = this.schema;

for (var key in schema) {
// Check explicit aliases defined in schema
var aliases = schema[key].alias;
aliases && aliases.forEach(function(alias){
if (typeof(cmd[alias]) !== 'undefined') {
conf[key] || (conf[key] = cmd[alias]);
if (aliases) {
if (!Array.isArray(aliases)) {
aliases = [aliases];
}
});
aliases.forEach(function(alias){
if (typeof(cmd[alias]) !== 'undefined') {
conf[key] || (conf[key] = cmd[alias]);
}
});
}

// Check camelCase version of the schema key
// (commander.js converts --stop-exit-codes to stopExitCodes)
var camelKey = snakeToCamel(key);
if (camelKey !== key && typeof(cmd[camelKey]) !== 'undefined') {
conf[key] || (conf[key] = cmd[camelKey]);
}

// Check if the schema key itself exists directly on cmd
if (typeof(cmd[key]) !== 'undefined') {
conf[key] || (conf[key] = cmd[key]);
}
}

return conf;
Expand Down