mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Compare commits
	
		
			33 Commits
		
	
	
		
			3.1.7
			...
			undo-histo
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | c294532152 | ||
|  | 960af87fb0 | ||
|  | de7339ae97 | ||
|  | 0995af62b6 | ||
|  | c2e03a40b4 | ||
|  | 29ed5b2792 | ||
|  | e39216e65a | ||
|  | 7ac7f9b4c8 | ||
|  | 4709eb9d49 | ||
|  | c13b8266dd | ||
|  | bd58431603 | ||
|  | 9a3cb0b2b5 | ||
|  | 6beae5a806 | ||
|  | a0636632a1 | ||
|  | 5dfa47ab6c | ||
|  | ade4679e8c | ||
|  | 410b938442 | ||
|  | 19dcc3a683 | ||
|  | 20d067c1ea | ||
|  | 9526566799 | ||
|  | 0b9dd82c91 | ||
|  | 19213434f9 | ||
|  | 014691346a | ||
|  | 6738b95c29 | ||
|  | 6a8230ec1e | ||
|  | 5679d264b6 | ||
|  | 37265cf4ef | ||
|  | 8a63275989 | ||
|  | 7fc64a84e8 | ||
|  | 02f7cdd5aa | ||
|  | d7dcceef60 | ||
|  | ae5e1570ae | ||
|  | 3ca045394a | 
							
								
								
									
										16
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,3 +1,19 @@ | ||||
| #### 3.1.9: Maintenance Release | ||||
|  | ||||
|  - Prevent subflow being added to itself (#4654) @knolleary | ||||
|  - Fix use of spawn on windows with cmd files (#4652) @knolleary | ||||
|  - Guard refresh of unknown subflow (#4640) @knolleary | ||||
|  - Fix subflow module sending messages to debug sidebar (#4642) @knolleary | ||||
|  | ||||
| #### 3.1.8: Maintenance Release | ||||
|  | ||||
|  - Add validation and error handling on subflow instance properties (#4632) @knolleary | ||||
|  - Hide import/export context menu if disabled in theme (#4633) @knolleary | ||||
|  - Show change indicator on subflow tabs (#4631) @knolleary | ||||
|  - Bump dependencies (#4630) @knolleary | ||||
|  - Reset workspace index when clearing nodes (#4619) @knolleary | ||||
|  - Remove typo in global config (#4613) @kazuhitoyokoi | ||||
|  | ||||
| #### 3.1.7: Maintenance Release | ||||
|  | ||||
|  - Add Japanese translation for v3.1.6 (#4603) @kazuhitoyokoi | ||||
|   | ||||
							
								
								
									
										10
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "node-red", | ||||
|     "version": "3.1.7", | ||||
|     "version": "3.1.9", | ||||
|     "description": "Low-code programming for event-driven applications", | ||||
|     "homepage": "https://nodered.org", | ||||
|     "license": "Apache-2.0", | ||||
| @@ -41,7 +41,7 @@ | ||||
|         "cors": "2.8.5", | ||||
|         "cronosjs": "1.7.1", | ||||
|         "denque": "2.1.0", | ||||
|         "express": "4.18.2", | ||||
|         "express": "4.19.2", | ||||
|         "express-session": "1.17.3", | ||||
|         "form-data": "4.0.0", | ||||
|         "fs-extra": "11.1.1", | ||||
| @@ -64,7 +64,7 @@ | ||||
|         "mqtt": "4.3.7", | ||||
|         "multer": "1.4.5-lts.1", | ||||
|         "mustache": "4.2.0", | ||||
|         "node-red-admin": "^3.1.2", | ||||
|         "node-red-admin": "^3.1.3", | ||||
|         "node-watch": "0.7.4", | ||||
|         "nopt": "5.0.0", | ||||
|         "oauth2orize": "1.11.1", | ||||
| @@ -74,7 +74,7 @@ | ||||
|         "passport-oauth2-client-password": "0.1.2", | ||||
|         "raw-body": "2.5.2", | ||||
|         "semver": "7.5.4", | ||||
|         "tar": "6.1.13", | ||||
|         "tar": "6.2.1", | ||||
|         "tough-cookie": "4.1.3", | ||||
|         "uglify-js": "3.17.4", | ||||
|         "uuid": "9.0.0", | ||||
| @@ -112,7 +112,7 @@ | ||||
|         "mermaid": "^10.4.0", | ||||
|         "minami": "1.2.3", | ||||
|         "mocha": "9.2.2", | ||||
|         "node-red-node-test-helper": "^0.3.2", | ||||
|         "node-red-node-test-helper": "^0.3.3", | ||||
|         "nodemon": "2.0.20", | ||||
|         "proxy": "^1.0.2", | ||||
|         "sass": "1.62.1", | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/editor-api", | ||||
|     "version": "3.1.7", | ||||
|     "version": "3.1.9", | ||||
|     "license": "Apache-2.0", | ||||
|     "main": "./lib/index.js", | ||||
|     "repository": { | ||||
| @@ -16,14 +16,14 @@ | ||||
|         } | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "@node-red/util": "3.1.7", | ||||
|         "@node-red/editor-client": "3.1.7", | ||||
|         "@node-red/util": "3.1.9", | ||||
|         "@node-red/editor-client": "3.1.9", | ||||
|         "bcryptjs": "2.4.3", | ||||
|         "body-parser": "1.20.2", | ||||
|         "clone": "2.1.2", | ||||
|         "cors": "2.8.5", | ||||
|         "express-session": "1.17.3", | ||||
|         "express": "4.18.2", | ||||
|         "express": "4.19.2", | ||||
|         "memorystore": "1.6.7", | ||||
|         "mime": "3.0.0", | ||||
|         "multer": "1.4.5-lts.1", | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/editor-client", | ||||
|     "version": "3.1.7", | ||||
|     "version": "3.1.9", | ||||
|     "license": "Apache-2.0", | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
|   | ||||
| @@ -706,11 +706,36 @@ RED.history = (function() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     function markEventDirty (evt) { | ||||
|         // This isn't 100% thorough - just covers the main move/edit/delete cases | ||||
|         evt.dirty = true | ||||
|         if (evt.multi) { | ||||
|             for (let i = 0; i < evt.events.length-1; i++) { | ||||
|                 markEventDirty(evt.events[i]) | ||||
|             } | ||||
|         } else if (evt.t === 'move') { | ||||
|             for (let i=0;i<evt.nodes.length;i++) { | ||||
|                 evt.nodes[i].moved = true | ||||
|             } | ||||
|         } else if (evt.t === 'edit') { | ||||
|             evt.changed = true | ||||
|         } else if (evt.t === 'delete') { | ||||
|             if (evt.nodes) { | ||||
|                 for (let i=0;i<evt.nodes.length;i++) { | ||||
|                     evt.nodes[i].changed = true | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return { | ||||
|         //TODO: this function is a placeholder until there is a 'save' event that can be listened to | ||||
|         markAllDirty: function() { | ||||
|             for (var i=0;i<undoHistory.length;i++) { | ||||
|             // A deploy has happened meaning any undo into the history will represent | ||||
|             // an undeployed change - regardless of what it was when the event was recorded. | ||||
|             // This goes back through the history any marks them all as being dirty events | ||||
|             // and also ensures individual node states are marked dirty | ||||
|             for (let i=0;i<undoHistory.length;i++) { | ||||
|                 undoHistory[i].dirty = true; | ||||
|                 markEventDirty(undoHistory[i]) | ||||
|             } | ||||
|         }, | ||||
|         list: function() { | ||||
|   | ||||
| @@ -547,12 +547,16 @@ RED.nodes = (function() { | ||||
|              * @param {String} z tab id | ||||
|              */ | ||||
|             checkTabState: function (z) { | ||||
|                 const ws = workspaces[z] | ||||
|                 const ws = workspaces[z] || subflows[z] | ||||
|                 if (ws) { | ||||
|                     const contentsChanged = tabDirtyMap[z].size > 0 || tabDeletedNodesMap[z].size > 0 | ||||
|                     if (Boolean(ws.contentsChanged) !== contentsChanged) { | ||||
|                         ws.contentsChanged = contentsChanged | ||||
|                         if (ws.type === 'tab') { | ||||
|                             RED.events.emit("flows:change", ws); | ||||
|                         } else { | ||||
|                             RED.events.emit("subflows:change", ws); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| @@ -1025,7 +1029,22 @@ RED.nodes = (function() { | ||||
|         RED.nodes.registerType("subflow:"+sf.id, { | ||||
|             defaults:{ | ||||
|                 name:{value:""}, | ||||
|                 env:{value:[]} | ||||
|                 env:{value:[], validate: function(value) { | ||||
|                     const errors = [] | ||||
|                     if (value) { | ||||
|                         value.forEach(env => { | ||||
|                             const r = RED.utils.validateTypedProperty(env.value, env.type) | ||||
|                             if (r !== true) { | ||||
|                                 errors.push(env.name+': '+r) | ||||
|                             } | ||||
|                         }) | ||||
|                     } | ||||
|                     if (errors.length === 0) { | ||||
|                         return true | ||||
|                     } else { | ||||
|                         return errors | ||||
|                     } | ||||
|                 }} | ||||
|             }, | ||||
|             icon: function() { return sf.icon||"subflow.svg" }, | ||||
|             category: sf.category || "subflows", | ||||
|   | ||||
| @@ -118,10 +118,16 @@ RED.contextMenu = (function () { | ||||
|                     onselect: 'core:split-wire-with-link-nodes', | ||||
|                     disabled: !canEdit || !hasLinks | ||||
|                 }, | ||||
|                 null, | ||||
|                 null | ||||
|             ) | ||||
|             if (RED.settings.theme("menu.menu-item-import-library", true)) { | ||||
|                 insertOptions.push( | ||||
|                     { onselect: 'core:show-import-dialog', label: RED._('common.label.import')}, | ||||
|                     { onselect: 'core:show-examples-import-dialog', label: RED._('menu.label.importExample') } | ||||
|                 ) | ||||
|             } | ||||
|  | ||||
|  | ||||
|             if (hasSelection && canEdit) { | ||||
|                 const nodeOptions = [] | ||||
|                 if (!hasMultipleSelection && !isGroup) { | ||||
| @@ -194,8 +200,14 @@ RED.contextMenu = (function () { | ||||
|                 { onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !canEdit || !RED.view.clipboard() }, | ||||
|                 { onselect: 'core:delete-selection', label: RED._('keyboard.deleteSelected'), disabled: !canEdit || !canDelete }, | ||||
|                 { onselect: 'core:delete-selection-and-reconnect', label: RED._('keyboard.deleteReconnect'), disabled: !canEdit || !canDelete }, | ||||
|                 { onselect: 'core:show-export-dialog', label: RED._("menu.label.export") }, | ||||
|                 { onselect: 'core:select-all-nodes', label: RED._("keyboard.selectAll") }, | ||||
|             ) | ||||
|             if (RED.settings.theme("menu.menu-item-export-library", true)) { | ||||
|                 menuItems.push( | ||||
|                     { onselect: 'core:show-export-dialog', label: RED._("menu.label.export") } | ||||
|                 ) | ||||
|             } | ||||
|             menuItems.push( | ||||
|                 { onselect: 'core:select-all-nodes', label: RED._("keyboard.selectAll") } | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -612,7 +612,10 @@ RED.deploy = (function() { | ||||
|                 } | ||||
|             }); | ||||
|             RED.nodes.eachSubflow(function (subflow) { | ||||
|                 if (subflow.changed) { | ||||
|                     subflow.changed = false; | ||||
|                     RED.events.emit("subflows:change", subflow); | ||||
|                 } | ||||
|             }); | ||||
|             RED.nodes.eachWorkspace(function (ws) { | ||||
|                 if (ws.changed || ws.added) { | ||||
|   | ||||
| @@ -1623,8 +1623,8 @@ RED.editor = (function() { | ||||
|                         } | ||||
|  | ||||
|                         if (!isSameObj(old_env, new_env)) { | ||||
|                             editing_node.env = new_env; | ||||
|                             editState.changes.env = editing_node.env; | ||||
|                             editing_node.env = new_env; | ||||
|                             editState.changed = true; | ||||
|                         } | ||||
|  | ||||
|   | ||||
| @@ -158,9 +158,11 @@ RED.sidebar.help = (function() { | ||||
|  | ||||
|     function refreshSubflow(sf) { | ||||
|         var item = treeList.treeList('get',"node-type:subflow:"+sf.id); | ||||
|         if (item) { | ||||
|             item.subflowLabel = sf._def.label().toLowerCase(); | ||||
|             item.treeList.replaceElement(getNodeLabel({_def:sf._def,type:sf._def.label()})); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function hideTOC() { | ||||
|         var tocButton = $('#red-ui-sidebar-help-show-toc') | ||||
|   | ||||
| @@ -646,6 +646,7 @@ RED.view = (function() { | ||||
|                 } | ||||
|                 d3.event = event; | ||||
|                 var selected_tool = $(ui.draggable[0]).attr("data-palette-type"); | ||||
|                 try { | ||||
|                     var result = createNode(selected_tool); | ||||
|                     if (!result) { | ||||
|                         return; | ||||
| @@ -761,6 +762,13 @@ RED.view = (function() { | ||||
|                     if (nn._def.autoedit) { | ||||
|                         RED.editor.edit(nn); | ||||
|                     } | ||||
|                 } catch (error) { | ||||
|                     if (error.code != "NODE_RED") { | ||||
|                         RED.notify(RED._("notification.error",{message:error.toString()}),"error"); | ||||
|                     } else { | ||||
|                         RED.notify(RED._("notification.error",{message:error.message}),"error"); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|         chart.on("focus", function() { | ||||
| @@ -2159,9 +2167,9 @@ RED.view = (function() { | ||||
|                     if (n.ox !== n.n.x || n.oy !== n.n.y || addedToGroup) { | ||||
|                         // This node has moved or added to a group | ||||
|                         if (rehomedNodes.has(n)) { | ||||
|                             moveAndChangedGroupEvent.nodes.push({...n}) | ||||
|                             moveAndChangedGroupEvent.nodes.push({...n, moved: n.n.moved}) | ||||
|                         } else { | ||||
|                             moveEvent.nodes.push({...n}) | ||||
|                             moveEvent.nodes.push({...n, moved: n.n.moved}) | ||||
|                         } | ||||
|                         n.n.dirty = true; | ||||
|                         n.n.moved = true; | ||||
| @@ -6063,14 +6071,19 @@ RED.view = (function() { | ||||
|      function createNode(type, x, y, z) { | ||||
|         const wasDirty = RED.nodes.dirty() | ||||
|         var m = /^subflow:(.+)$/.exec(type); | ||||
|         var activeSubflow = z ? RED.nodes.subflow(z) : null; | ||||
|         var activeSubflow = (z || RED.workspaces.active()) ? RED.nodes.subflow(z || RED.workspaces.active()) : null; | ||||
|  | ||||
|         if (activeSubflow && m) { | ||||
|             var subflowId = m[1]; | ||||
|             let err | ||||
|             if (subflowId === activeSubflow.id) { | ||||
|                 throw new Error(RED._("notification.error", { message: RED._("notification.errors.cannotAddSubflowToItself") })) | ||||
|                 err = new Error(RED._("notification.errors.cannotAddSubflowToItself")) | ||||
|             } else if (RED.nodes.subflowContains(m[1], activeSubflow.id)) { | ||||
|                 err = new Error(RED._("notification.errors.cannotAddCircularReference")) | ||||
|             } | ||||
|             if (RED.nodes.subflowContains(m[1], activeSubflow.id)) { | ||||
|                 throw new Error(RED._("notification.error", { message: RED._("notification.errors.cannotAddCircularReference") })) | ||||
|             if (err) { | ||||
|                 err.code = 'NODE_RED' | ||||
|                 throw err | ||||
|             } | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -491,6 +491,11 @@ RED.workspaces = (function() { | ||||
|         createWorkspaceTabs(); | ||||
|         RED.events.on("sidebar:resize",workspace_tabs.resize); | ||||
|  | ||||
|         RED.events.on("workspace:clear", () => { | ||||
|             // Reset the index used to generate new flow names | ||||
|             workspaceIndex = 0 | ||||
|         }) | ||||
|  | ||||
|         RED.actions.add("core:show-next-tab",function() { | ||||
|             var oldActive = activeWorkspace; | ||||
|             workspace_tabs.nextTab(); | ||||
| @@ -657,6 +662,9 @@ RED.workspaces = (function() { | ||||
|         RED.events.on("flows:change", (ws) => { | ||||
|             $("#red-ui-tab-"+(ws.id.replace(".","-"))).toggleClass('red-ui-workspace-changed',!!(ws.contentsChanged || ws.changed || ws.added)); | ||||
|         }) | ||||
|         RED.events.on("subflows:change", (ws) => { | ||||
|             $("#red-ui-tab-"+(ws.id.replace(".","-"))).toggleClass('red-ui-workspace-changed',!!(ws.contentsChanged || ws.changed || ws.added)); | ||||
|         }) | ||||
|  | ||||
|         hideWorkspace(); | ||||
|     } | ||||
|   | ||||
| @@ -378,7 +378,7 @@ | ||||
|                             return { id: id, label: RED.nodes.workspace(id).label } //flow id + name | ||||
|                         } else { | ||||
|                             const instanceNode = RED.nodes.node(id) | ||||
|                             const pathLabel = (instanceNode.name || RED.nodes.subflow(instanceNode.type.substring(8)).name) | ||||
|                             const pathLabel = (instanceNode.name || RED.nodes.subflow(instanceNode.type.substring(8))?.name || instanceNode.type) | ||||
|                             return { id: id, label: pathLabel } | ||||
|                         } | ||||
|                     }) | ||||
|   | ||||
| @@ -20,6 +20,7 @@ module.exports = function(RED) { | ||||
|     var exec = require('child_process').exec; | ||||
|     var fs = require('fs'); | ||||
|     var isUtf8 = require('is-utf8'); | ||||
|     const isWindows = process.platform === 'win32' | ||||
|  | ||||
|     function ExecNode(n) { | ||||
|         RED.nodes.createNode(this,n); | ||||
| @@ -85,9 +86,12 @@ module.exports = function(RED) { | ||||
|                         } | ||||
|                     }); | ||||
|                     var cmd = arg.shift(); | ||||
|                     // Since 18.20.2/20.12.2, it is invalid to call spawn on Windows with a .bat/.cmd file | ||||
|                     // without using shell: true.  | ||||
|                     const opts = isWindows ? { ...node.spawnOpt, shell: true } : node.spawnOpt | ||||
|                     /* istanbul ignore else  */ | ||||
|                     node.debug(cmd+" ["+arg+"]"); | ||||
|                     child = spawn(cmd,arg,node.spawnOpt); | ||||
|                     child = spawn(cmd,arg,opts); | ||||
|                     node.status({fill:"blue",shape:"dot",text:"pid:"+child.pid}); | ||||
|                     var unknownCommand = (child.pid === undefined); | ||||
|                     if (node.timer !== 0) { | ||||
|   | ||||
| @@ -103,7 +103,7 @@ | ||||
|     <h4>Automatic mode</h4> | ||||
|     <p>Automatic mode uses the <code>parts</code> property of incoming messages to | ||||
|        determine how the sequence should be joined. This allows it to automatically | ||||
|        reverse the action of a <b>split</b> node. | ||||
|        reverse the action of a <b>split</b> node.</p> | ||||
|  | ||||
|     <h4>Manual mode</h4> | ||||
|     <p>When configured to join in manual mode, the node is able to join sequences | ||||
|   | ||||
| @@ -1,3 +1,3 @@ | ||||
| <script type="text/html" data-help-name="global-config"> | ||||
|     <p>大域的なフローの設定を保持するノード。大域的な環境変数の定義を含みます。</p> | ||||
| </script>p | ||||
| </script> | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/nodes", | ||||
|     "version": "3.1.7", | ||||
|     "version": "3.1.9", | ||||
|     "license": "Apache-2.0", | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
|   | ||||
| @@ -273,7 +273,7 @@ async function installModule(moduleDetails) { | ||||
|                 let extraArgs = triggerPayload.args || []; | ||||
|                 let args = ['install', ...extraArgs, installSpec] | ||||
|                 log.trace(NPM_COMMAND + JSON.stringify(args)); | ||||
|                 return exec.run(NPM_COMMAND, args, { cwd: installDir },true) | ||||
|                 return exec.run(NPM_COMMAND, args, { cwd: installDir, shell: true },true) | ||||
|             } else { | ||||
|                 log.trace("skipping npm install"); | ||||
|             } | ||||
|   | ||||
| @@ -25,12 +25,15 @@ const registryUtil = require("./util"); | ||||
| const library = require("./library"); | ||||
| const {exec,log,events,hooks} = require("@node-red/util"); | ||||
| const child_process = require('child_process'); | ||||
| const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'; | ||||
| let installerEnabled = false; | ||||
|  | ||||
| const isWindows = process.platform === 'win32' | ||||
| const npmCommand =  isWindows ? 'npm.cmd' : 'npm'; | ||||
|  | ||||
| let installerEnabled = false; | ||||
| let settings; | ||||
|  | ||||
| const moduleRe = /^(@[^/@]+?[/])?[^/@]+?$/; | ||||
| const slashRe = process.platform === "win32" ? /\\|[/]/ : /[/]/; | ||||
| const slashRe = isWindows ? /\\|[/]/ : /[/]/; | ||||
| const pkgurlRe = /^(https?|git(|\+https?|\+ssh|\+file)):\/\//; | ||||
| const localtgzRe = /^([a-zA-Z]:|\/).+tgz$/; | ||||
|  | ||||
| @@ -225,7 +228,7 @@ async function installModule(module,version,url) { | ||||
|                 let extraArgs = triggerPayload.args || []; | ||||
|                 let args = ['install', ...extraArgs, installName] | ||||
|                 log.trace(npmCommand + JSON.stringify(args)); | ||||
|                 return exec.run(npmCommand,args,{ cwd: installDir}, true) | ||||
|                 return exec.run(npmCommand,args,{ cwd: installDir, shell: true }, true) | ||||
|             } else { | ||||
|                 log.trace("skipping npm install"); | ||||
|             } | ||||
| @@ -260,7 +263,7 @@ async function installModule(module,version,url) { | ||||
|                 log.warn("------------------------------------------"); | ||||
|                 e = new Error(log._("server.install.install-failed")+": "+err.toString()); | ||||
|                 if (err.hook === "postInstall") { | ||||
|                     return exec.run(npmCommand,["remove",module],{ cwd: installDir}, false).finally(() => { | ||||
|                     return exec.run(npmCommand,["remove",module],{ cwd: installDir, shell: true }, false).finally(() => { | ||||
|                         throw e; | ||||
|                     }) | ||||
|                 } | ||||
| @@ -356,7 +359,7 @@ async function getModuleVersionFromNPM(module, version) { | ||||
|     } | ||||
|  | ||||
|     return new Promise((resolve, reject) => { | ||||
|         child_process.execFile(npmCommand,['info','--json',installName],function(err,stdout,stderr) { | ||||
|         child_process.execFile(npmCommand,['info','--json',installName],{ shell: true },function(err,stdout,stderr) { | ||||
|             try { | ||||
|                 if (!stdout) { | ||||
|                     log.warn(log._("server.install.install-failed-not-found",{name:module})); | ||||
| @@ -511,7 +514,7 @@ function uninstallModule(module) { | ||||
|                     let extraArgs = triggerPayload.args || []; | ||||
|                     let args = ['remove', ...extraArgs, module] | ||||
|                     log.trace(npmCommand + JSON.stringify(args)); | ||||
|                     return exec.run(npmCommand,args,{ cwd: installDir}, true) | ||||
|                     return exec.run(npmCommand,args,{ cwd: installDir, shell: true }, true) | ||||
|                 } else { | ||||
|                     log.trace("skipping npm uninstall"); | ||||
|                 } | ||||
| @@ -578,7 +581,7 @@ async function checkPrereq() { | ||||
|         installerEnabled = false; | ||||
|     } else { | ||||
|         return new Promise(resolve => { | ||||
|             child_process.execFile(npmCommand,['-v'],function(err,stdout) { | ||||
|             child_process.execFile(npmCommand,['-v'],{ shell: true },function(err,stdout) { | ||||
|                 if (err) { | ||||
|                     log.info(log._("server.palette-editor.npm-not-found")); | ||||
|                     installerEnabled = false; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/registry", | ||||
|     "version": "3.1.7", | ||||
|     "version": "3.1.9", | ||||
|     "license": "Apache-2.0", | ||||
|     "main": "./lib/index.js", | ||||
|     "repository": { | ||||
| @@ -16,11 +16,11 @@ | ||||
|         } | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "@node-red/util": "3.1.7", | ||||
|         "@node-red/util": "3.1.9", | ||||
|         "clone": "2.1.2", | ||||
|         "fs-extra": "11.1.1", | ||||
|         "semver": "7.5.4", | ||||
|         "tar": "6.1.13", | ||||
|         "tar": "6.2.1", | ||||
|         "uglify-js": "3.17.4" | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -106,15 +106,23 @@ async function evaluateEnvProperties(flow, env, credentials) { | ||||
|                             result = { value: result, __clone__: true} | ||||
|                         } | ||||
|                         evaluatedEnv[name] = result | ||||
|                     } else { | ||||
|                         evaluatedEnv[name] = undefined | ||||
|                         flow.error(`Error evaluating env property '${name}': ${err.toString()}`) | ||||
|                     } | ||||
|                     resolve() | ||||
|                 }); | ||||
|             })) | ||||
|         } else { | ||||
|             try { | ||||
|                 value = redUtil.evaluateNodeProperty(value, type, {_flow: flow}, null, null); | ||||
|                 if (typeof value  === 'object') { | ||||
|                     value = { value: value, __clone__: true} | ||||
|                 } | ||||
|             } catch (err) { | ||||
|                 value = undefined | ||||
|                 flow.error(`Error evaluating env property '${name}': ${err.toString()}`) | ||||
|             } | ||||
|         } | ||||
|         evaluatedEnv[name] = value | ||||
|     } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/runtime", | ||||
|     "version": "3.1.7", | ||||
|     "version": "3.1.9", | ||||
|     "license": "Apache-2.0", | ||||
|     "main": "./lib/index.js", | ||||
|     "repository": { | ||||
| @@ -16,11 +16,11 @@ | ||||
|         } | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "@node-red/registry": "3.1.7", | ||||
|         "@node-red/util": "3.1.7", | ||||
|         "@node-red/registry": "3.1.9", | ||||
|         "@node-red/util": "3.1.9", | ||||
|         "async-mutex": "0.4.0", | ||||
|         "clone": "2.1.2", | ||||
|         "express": "4.18.2", | ||||
|         "express": "4.19.2", | ||||
|         "fs-extra": "11.1.1", | ||||
|         "json-stringify-safe": "5.0.1" | ||||
|     } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@node-red/util", | ||||
|     "version": "3.1.7", | ||||
|     "version": "3.1.9", | ||||
|     "license": "Apache-2.0", | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
|   | ||||
							
								
								
									
										14
									
								
								packages/node_modules/node-red/package.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								packages/node_modules/node-red/package.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "node-red", | ||||
|     "version": "3.1.7", | ||||
|     "version": "3.1.9", | ||||
|     "description": "Low-code programming for event-driven applications", | ||||
|     "homepage": "https://nodered.org", | ||||
|     "license": "Apache-2.0", | ||||
| @@ -31,15 +31,15 @@ | ||||
|         "flow" | ||||
|     ], | ||||
|     "dependencies": { | ||||
|         "@node-red/editor-api": "3.1.7", | ||||
|         "@node-red/runtime": "3.1.7", | ||||
|         "@node-red/util": "3.1.7", | ||||
|         "@node-red/nodes": "3.1.7", | ||||
|         "@node-red/editor-api": "3.1.9", | ||||
|         "@node-red/runtime": "3.1.9", | ||||
|         "@node-red/util": "3.1.9", | ||||
|         "@node-red/nodes": "3.1.9", | ||||
|         "basic-auth": "2.0.1", | ||||
|         "bcryptjs": "2.4.3", | ||||
|         "express": "4.18.2", | ||||
|         "express": "4.19.2", | ||||
|         "fs-extra": "11.1.1", | ||||
|         "node-red-admin": "^3.1.2", | ||||
|         "node-red-admin": "^3.1.3", | ||||
|         "nopt": "5.0.0", | ||||
|         "semver": "7.5.4" | ||||
|     }, | ||||
|   | ||||
| @@ -60,6 +60,7 @@ describe('HTTP Request Node', function() { | ||||
|     function startServer(done) { | ||||
|         testPort += 1; | ||||
|         testServer = stoppable(http.createServer(testApp)); | ||||
|         const promises = [] | ||||
|         testServer.listen(testPort,function(err) { | ||||
|             testSslPort += 1; | ||||
|             console.log("ssl port", testSslPort); | ||||
| @@ -81,13 +82,17 @@ describe('HTTP Request Node', function() { | ||||
|                 */ | ||||
|             }; | ||||
|             testSslServer = stoppable(https.createServer(sslOptions,testApp)); | ||||
|             console.log('> start testSslServer') | ||||
|             promises.push(new Promise((resolve, reject) => { | ||||
|                 testSslServer.listen(testSslPort, function(err){ | ||||
|                     console.log(' done testSslServer') | ||||
|                     if (err) { | ||||
|                     console.log(err); | ||||
|                         reject(err) | ||||
|                     } else { | ||||
|                     console.log("started testSslServer"); | ||||
|                         resolve() | ||||
|                     } | ||||
|                 }); | ||||
|             })) | ||||
|  | ||||
|             testSslClientPort += 1; | ||||
|             var sslClientOptions = { | ||||
| @@ -97,10 +102,17 @@ describe('HTTP Request Node', function() { | ||||
|                 requestCert: true | ||||
|             }; | ||||
|             testSslClientServer = stoppable(https.createServer(sslClientOptions, testApp)); | ||||
|             console.log('> start testSslClientServer') | ||||
|             promises.push(new Promise((resolve, reject) => { | ||||
|                 testSslClientServer.listen(testSslClientPort, function(err){ | ||||
|                 console.log("ssl-client", err) | ||||
|                     console.log(' done testSslClientServer') | ||||
|                     if (err) { | ||||
|                         reject(err) | ||||
|                     } else { | ||||
|                         resolve() | ||||
|                     } | ||||
|                 }); | ||||
|  | ||||
|             })) | ||||
|             testProxyPort += 1; | ||||
|             testProxyServer = stoppable(httpProxy(http.createServer())) | ||||
|  | ||||
| @@ -109,7 +121,17 @@ describe('HTTP Request Node', function() { | ||||
|                     res.setHeader("x-testproxy-header", "foobar") | ||||
|                 } | ||||
|             }) | ||||
|             testProxyServer.listen(testProxyPort) | ||||
|             console.log('> testProxyServer') | ||||
|             promises.push(new Promise((resolve, reject) => { | ||||
|                 testProxyServer.listen(testProxyPort, function(err) { | ||||
|                     console.log(' done testProxyServer') | ||||
|                     if (err) { | ||||
|                         reject(err) | ||||
|                     } else { | ||||
|                         resolve() | ||||
|                     } | ||||
|                 }) | ||||
|             })) | ||||
|  | ||||
|             testProxyAuthPort += 1 | ||||
|             testProxyServerAuth = stoppable(httpProxy(http.createServer())) | ||||
| @@ -131,9 +153,19 @@ describe('HTTP Request Node', function() { | ||||
|                     res.setHeader("x-testproxy-header", "foobar") | ||||
|                 } | ||||
|             }) | ||||
|             testProxyServerAuth.listen(testProxyAuthPort) | ||||
|             console.log('> testProxyServerAuth') | ||||
|             promises.push(new Promise((resolve, reject) => { | ||||
|                 testProxyServerAuth.listen(testProxyAuthPort, function(err) { | ||||
|                     console.log(' done testProxyServerAuth') | ||||
|                     if (err) { | ||||
|                         reject(err) | ||||
|                     } else { | ||||
|                         resolve() | ||||
|                     } | ||||
|                 }) | ||||
|             })) | ||||
|  | ||||
|             done(err); | ||||
|             Promise.all(promises).then(() => { done() }).catch(done) | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| @@ -429,7 +461,11 @@ describe('HTTP Request Node', function() { | ||||
|             if (err) { | ||||
|                 done(err); | ||||
|             } | ||||
|             helper.startServer(done); | ||||
|             console.log('> helper.startServer') | ||||
|             helper.startServer(function(err) { | ||||
|                 console.log('> helper started') | ||||
|                 done(err) | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user