mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
25 Commits
4206-ctrl-
...
loadable-i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
638d0d2f3f | ||
|
|
eb940d6d57 | ||
|
|
9091935d77 | ||
|
|
34e8d2b051 | ||
|
|
0c2ab13c48 | ||
|
|
9489953a8f | ||
|
|
cef3a01042 | ||
|
|
0c042abcab | ||
|
|
a48c57dd17 | ||
|
|
77b235655c | ||
|
|
8dc0261993 | ||
|
|
65d2ad68d3 | ||
|
|
52fde088e9 | ||
|
|
ab6d537c3e | ||
|
|
3a6078a56a | ||
|
|
b0c3fefcab | ||
|
|
2bc739194e | ||
|
|
afb06e8c9a | ||
|
|
2c1274ff76 | ||
|
|
e18721a03e | ||
|
|
aea32cc279 | ||
|
|
ce0feb2f42 | ||
|
|
1f98d19f77 | ||
|
|
9a934c941f | ||
|
|
f7b64b101e |
42
CHANGELOG.md
42
CHANGELOG.md
@@ -1,4 +1,38 @@
|
||||
#### 3.1.0-beta.4: Beta Release
|
||||
#### 3.1.0: Milestone Release
|
||||
|
||||
Editor
|
||||
|
||||
- Default filter to All Catalogues and show nodes for small lists (#4318) @knolleary
|
||||
- Better distinguish between ctrl and meta keys on mac (#4310) @knolleary
|
||||
- Ensure junction appears when filtering quick-add list (#4297) @knolleary
|
||||
- Update message catalogs for JSONata Expression editor (#4287) @kazuhitoyokoi
|
||||
- Add tooltip to relevance sort button in user settings UI (#4288) @kazuhitoyokoi
|
||||
- Capture workspace dirty state when quick-adding junction (#4283) @knolleary
|
||||
- Add docs for $clone function (#4284) @knolleary
|
||||
|
||||
Runtime
|
||||
|
||||
- Dependency updates (#4317) @knolleary
|
||||
- Ensure storage/util.writeFile handles concurrent write attempts (#4316) @knolleary
|
||||
- Migrate http -> https for nodered.org (#4313) @Rotzbua
|
||||
- Add Node 20 to GH Action test matrix (#4305) @Rotzbua
|
||||
- Handle group-scoped nodes inside subflow (#4301) @knolleary
|
||||
- Handle non-url-safe chars in context api (#4298) @knolleary
|
||||
- Fix git pull operation in project feature (#4290) @kazuhitoyokoi
|
||||
- Change linefeed codes in Korean message catalogs (#4286) @kazuhitoyokoi
|
||||
- Fix file permissions of message catalogs (#4285) @kazuhitoyokoi
|
||||
- Update tour (#4278) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- File: Fix handling in file nodes when number is specified as file name (#4267) @kazuhitoyokoi
|
||||
- Function: Adding function timeout to settings file (#4265) (#4309) @knolleary
|
||||
- Function: Fix function setup tab layout (#4299) @knolleary
|
||||
- HTTP Request: Handle 204 in httprequest JSON (#4262) @sammachin
|
||||
- JSON: Fix test cases of JSON node (#4275) @kazuhitoyokoi
|
||||
- MQTT: Remove unnecessary check for clientid if autoUnsub set (#4302) @knolleary
|
||||
|
||||
##### 3.1.0-beta.4: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
@@ -28,7 +62,7 @@
|
||||
- Fix delay node flush issue (#4203) @dceejay
|
||||
- Update status and catch node labels in group mode (#4207) @Steve-Mcl
|
||||
|
||||
#### 3.1.0-beta.3: Beta Release
|
||||
##### 3.1.0-beta.3: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
@@ -63,7 +97,7 @@ Nodes
|
||||
- MQTT: Option to disable MQTT topic unsubscribe on disconnect (#4078) @flying7eleven
|
||||
|
||||
|
||||
#### 3.1.0-beta.2: Beta Release
|
||||
##### 3.1.0-beta.2: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
@@ -113,7 +147,7 @@ Nodes
|
||||
- File Out: Fix extra newline append for multipart file write (#3915) @dceejay
|
||||
- Add validators for complete and link call nodes (#4056) @kazuhitoyokoi
|
||||
|
||||
#### 3.1.0-beta.1: Beta Release
|
||||
##### 3.1.0-beta.1: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# Node-RED
|
||||
|
||||
http://nodered.org
|
||||
https://nodered.org
|
||||
|
||||
[](https://github.com/node-red/node-red/actions?query=branch%3Amaster)
|
||||
|
||||
Low-code programming for event-driven applications.
|
||||
|
||||

|
||||

|
||||
|
||||
## Quick Start
|
||||
|
||||
Check out http://nodered.org/docs/getting-started/ for full instructions on getting
|
||||
Check out https://nodered.org/docs/getting-started/ for full instructions on getting
|
||||
started.
|
||||
|
||||
1. `sudo npm install -g --unsafe-perm node-red`
|
||||
@@ -19,7 +19,7 @@ started.
|
||||
|
||||
## Getting Help
|
||||
|
||||
More documentation can be found [here](http://nodered.org/docs).
|
||||
More documentation can be found [here](https://nodered.org/docs).
|
||||
|
||||
For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||
|
||||
|
||||
16
package.json
16
package.json
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"homepage": "https://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -64,8 +64,8 @@
|
||||
"mqtt": "4.3.7",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"mustache": "4.2.0",
|
||||
"node-red-admin": "^3.0.0",
|
||||
"node-watch": "0.7.3",
|
||||
"node-red-admin": "^3.1.0",
|
||||
"node-watch": "0.7.4",
|
||||
"nopt": "5.0.0",
|
||||
"oauth2orize": "1.11.1",
|
||||
"on-headers": "1.0.2",
|
||||
@@ -73,16 +73,16 @@
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"raw-body": "2.5.2",
|
||||
"semver": "7.5.0",
|
||||
"semver": "7.5.4",
|
||||
"tar": "6.1.13",
|
||||
"tough-cookie": "4.1.2",
|
||||
"tough-cookie": "4.1.3",
|
||||
"uglify-js": "3.17.4",
|
||||
"uuid": "9.0.0",
|
||||
"ws": "7.5.6",
|
||||
"xml2js": "0.6.0"
|
||||
"xml2js": "0.6.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcrypt": "5.1.0"
|
||||
"bcrypt": "5.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dompurify": "2.4.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "3.1.0-beta.4",
|
||||
"@node-red/editor-client": "3.1.0-beta.4",
|
||||
"@node-red/util": "4.0.0-dev",
|
||||
"@node-red/editor-client": "4.0.0-dev",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.20.2",
|
||||
"clone": "2.1.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -731,7 +731,7 @@ var RED = (function() {
|
||||
}
|
||||
menuOptions.push({id:"menu-item-help",
|
||||
label: RED.settings.theme("menu.menu-item-help.label",RED._("menu.label.help")),
|
||||
href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs")
|
||||
href: RED.settings.theme("menu.menu-item-help.url","https://nodered.org/docs")
|
||||
});
|
||||
menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: "core:show-about" });
|
||||
|
||||
|
||||
@@ -494,6 +494,7 @@ RED.palette.editor = (function() {
|
||||
// if there is only 1 catalog, hide the select
|
||||
if (catalogEntries.length > 1) {
|
||||
catalogSelection.prepend(`<option value="all">${RED._('palette.editor.allCatalogs')}</option>`)
|
||||
catalogSelection.val('all')
|
||||
catalogSelection.removeAttr('disabled') // permit the user to select a catalog
|
||||
}
|
||||
// refresh the searchInput counter and trigger a change
|
||||
@@ -523,7 +524,7 @@ RED.palette.editor = (function() {
|
||||
function refreshFilteredItems() {
|
||||
packageList.editableList('empty');
|
||||
var currentFilter = searchInput.searchBox('value').trim();
|
||||
if (currentFilter === ""){
|
||||
if (currentFilter === "" && loadedList.length > 20){
|
||||
packageList.editableList('addItem',{count:loadedList.length})
|
||||
return;
|
||||
}
|
||||
@@ -893,7 +894,7 @@ RED.palette.editor = (function() {
|
||||
delay: 300,
|
||||
change: function() {
|
||||
var searchTerm = $(this).val().trim().toLowerCase();
|
||||
if (searchTerm.length > 0) {
|
||||
if (searchTerm.length > 0 || loadedList.length < 20) {
|
||||
filteredList = loadedList.filter(function(m) {
|
||||
return (m.index.indexOf(searchTerm) > -1);
|
||||
}).map(function(f) { return {info:f}});
|
||||
|
||||
@@ -101,7 +101,7 @@ RED.utils = (function() {
|
||||
|
||||
renderer.code = function (code, lang) {
|
||||
if(lang === "mermaid") {
|
||||
// mermaid diagram rendering
|
||||
// mermaid diagram rendering
|
||||
if (mermaidIsEnabled === undefined) {
|
||||
if (RED.settings.markdownEditor &&
|
||||
RED.settings.markdownEditor.mermaid) {
|
||||
@@ -1118,6 +1118,22 @@ RED.utils = (function() {
|
||||
if (def.category === 'subflows') {
|
||||
return RED.settings.apiRootUrl+"icons/node-red/subflow.svg";
|
||||
}
|
||||
|
||||
if (node?.type) {
|
||||
// this regex might be too restrictive/specific but got to start somewhere
|
||||
const re = new RegExp("^\/"+node.type+"\/icon\/.*\.svg$","i");
|
||||
if (typeof def.icon === "function") {
|
||||
try {
|
||||
const di = def.icon.call(node);
|
||||
if (re.test(di)) { return RED.settings.authTokensSuffix.replace(/-/,'/') + di; }
|
||||
}
|
||||
catch(e) { console.log("Bad Icon",e) }
|
||||
}
|
||||
else {
|
||||
if (re.test(def.icon)) { return RED.settings.authTokensSuffix.replace(/-/,'/') + def.icon; }
|
||||
}
|
||||
}
|
||||
|
||||
return RED.settings.apiRootUrl+"icons/node-red/arrow-in.svg";
|
||||
}
|
||||
|
||||
|
||||
@@ -366,7 +366,7 @@
|
||||
name: {value:"_DEFAULT_"},
|
||||
func: {value:"\nreturn msg;"},
|
||||
outputs: {value:1},
|
||||
timeout:{value:0},
|
||||
timeout:{value:RED.settings.functionTimeout || 0},
|
||||
noerr: {value:0,required:true,
|
||||
validate: function(v, opt) {
|
||||
if (!v) {
|
||||
|
||||
@@ -521,7 +521,8 @@ module.exports = function(RED) {
|
||||
RED.nodes.registerType("function",FunctionNode, {
|
||||
dynamicModuleList: "libs",
|
||||
settings: {
|
||||
functionExternalModules: { value: true, exportable: true }
|
||||
functionExternalModules: { value: true, exportable: true },
|
||||
functionTimeout: { value:0, exportable: true }
|
||||
}
|
||||
});
|
||||
RED.library.register("functions");
|
||||
|
||||
@@ -24,7 +24,6 @@ module.exports = function(RED) {
|
||||
"text/css":"string",
|
||||
"text/html":"string",
|
||||
"text/plain":"string",
|
||||
"text/html":"string",
|
||||
"application/json":"json",
|
||||
"application/octet-stream":"buffer",
|
||||
"application/pdf":"buffer",
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<p>Wenn ein promise-Objekt aus dem Start-Code zurückgegeben wird,
|
||||
beginnt danach die reguläre Verarbeitung der Eingangsnachrichten.</p>
|
||||
<h3>Details</h3>
|
||||
<p>Siehe <a target="_blank" href="http://nodered.org/docs/writing-functions.html">Onlinedokumentation</a>
|
||||
<p>Siehe <a target="_blank" href="https://nodered.org/docs/writing-functions.html">Onlinedokumentation</a>
|
||||
für weitere Informationen zum Schreiben von Funktionen.</p>
|
||||
<h4><b>Nachrichten senden</b></h4>
|
||||
<p>Die Funktion kann die Nachrichten zurückgeben, die sie an die nächsten Nodes im Flow weitergeben möchte,
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<p>If the On Start code returns a Promise object, the node will not start handling messages
|
||||
until the promise is resolved.</p>
|
||||
<h3>Details</h3>
|
||||
<p>See the <a target="_blank" href="http://nodered.org/docs/writing-functions.html">online documentation</a>
|
||||
<p>See the <a target="_blank" href="https://nodered.org/docs/writing-functions.html">online documentation</a>
|
||||
for more information on writing functions.</p>
|
||||
<h4>Sending messages</h4>
|
||||
<p>The function can either return the messages it wants to pass on to the next nodes
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<p>Si le code 'Au démarrage' renvoie un objet Promise (promesse), le noeud ne commencera pas à gérer les messages
|
||||
jusqu'à ce que la promesse soit résolue.</p>
|
||||
<h3>Détails</h3>
|
||||
<p>Voir la <a target="_blank" href="http://nodered.org/docs/writing-functions.html">documentation en ligne</a>
|
||||
<p>Voir la <a target="_blank" href="https://nodered.org/docs/writing-functions.html">documentation en ligne</a>
|
||||
pour plus d'informations sur les fonctions d'écriture.</p>
|
||||
<h4>Envoi de messages</h4>
|
||||
<p>La fonction peut envoyer les messages qu'elle souhaite transmettre aux noeuds suivants
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<p><b>初期化処理</b>タブにはノードの開始時に実行されるコードを、<b>終了処理</b>タブにはノードの終了時に実行されるコードを指定します。</p>
|
||||
<p>初期化処理タブの返却値としてPromiseオブジェクトを返却すると、入力メッセージの処理を開始する前にその完了を待ちます。</p>
|
||||
<h3>詳細</h3>
|
||||
<p>コードの書き方の詳細については、<a target="_blank" href="http://nodered.org/docs/writing-functions.html">オンラインドキュメント</a>を参照してください。</p>
|
||||
<p>コードの書き方の詳細については、<a target="_blank" href="https://nodered.org/docs/writing-functions.html">オンラインドキュメント</a>を参照してください。</p>
|
||||
<h4>メッセージの送信</h4>
|
||||
<p>フロー内の次ノードにメッセージを渡すためには、メッセージを返却するか<code>node.send(messages)</code>を呼び出します。</p>
|
||||
<p>返却/sendの対象は次のとおりです:</p>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<p><code>msg</code>오브젝트는<code>msg.payload</code>프로퍼티에 메시지 본체를 유지하는 것이 관례입니다.</p>
|
||||
<p>보통 코드는 메시지 오브젝트(혹은 여러 메시지 객체)를 반환합니다.후속 플로우의 실행을 정지하고 싶은 경우에는, 오브젝트를 반환하지 않아도 상관없습니다.</p>
|
||||
<h3>상세</h3>
|
||||
<p>코드 쓰는 방식에 대한 자세한 내용은, <a target="_blank" href="http://nodered.org/docs/writing-functions.html">공식 홈페이지</a>를 참조해 주세요.</p>
|
||||
<p>코드 쓰는 방식에 대한 자세한 내용은, <a target="_blank" href="https://nodered.org/docs/writing-functions.html">공식 홈페이지</a>를 참조해 주세요.</p>
|
||||
<h4>메세지 송신</h4>
|
||||
<p>플로우 내의 다음 노드에 메세지를 전달하기 위해서는, 메세지를 반환하거나, <code>node.send(messages)</code>를 호출합니다.</p>
|
||||
<p>반환/send 대상은 다음과 같습니다:</p>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<p>Se o código <b>On Start</b> retornar um objeto do tipo promessa, o nó não começará a tratar as mensagens
|
||||
até que a promessa seja resolvida.</p>
|
||||
<h3>Detalhes</h3>
|
||||
<p>Consulte a <a target="_blank" href="http://nodered.org/docs/writing-functions.html">documentação online</a>
|
||||
<p>Consulte a <a target="_blank" href="https://nodered.org/docs/writing-functions.html">documentação online</a>
|
||||
para obter maiores informações sobre funções de escrita.</p>
|
||||
<h4>Enviando mensagens</h4>
|
||||
<p>A função pode retornar as mensagens que deseja passar para os próximos nós
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
<h3>Подробности</h3>
|
||||
<p>
|
||||
Смотрите <a target="_blank" href="http://nodered.org/docs/writing-functions.html">онлайн-документацию</a> для получения дополнительной информации по написанию функций.
|
||||
Смотрите <a target="_blank" href="https://nodered.org/docs/writing-functions.html">онлайн-документацию</a> для получения дополнительной информации по написанию функций.
|
||||
</p>
|
||||
|
||||
<h4>Отправка сообщений</h4>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<p>通常,<code>msg</code>对象将消息正文保留在<code>msg.payload</code>属性中。</p>
|
||||
<p>该函数一般会返回一个消息对象(或多个消息对象),但也可以为了停止流而什么都不返回。</p>
|
||||
<h3>详细</h3>
|
||||
<p>请参见<a target="_blank" href="http://nodered.org/docs/writing-functions.html">在线文档</a>来获得更多有关编写函数的信息。</p>
|
||||
<p>请参见<a target="_blank" href="https://nodered.org/docs/writing-functions.html">在线文档</a>来获得更多有关编写函数的信息。</p>
|
||||
<h4>传送消息</h4>
|
||||
<p>要将消息传递到流中的下一个节点,请返回消息或调用<code>node.send(messages)</code>。</p>
|
||||
<p>它将返回/send:</p>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<p>通常,<code>msg</code>對象將消息正文保留在<code>msg.payload</code>屬性中。</p>
|
||||
<p>該函數一般會返回一個消息對象(或多個消息對象),但也可以爲了停止流程而什麽都不返回。</p>
|
||||
<h3>詳細</h3>
|
||||
<p>請參見<a target="_blank" href="http://nodered.org/docs/writing-functions.html">在線文檔</a>來獲得更多有關編寫函數的信息。</p>
|
||||
<p>請參見<a target="_blank" href="https://nodered.org/docs/writing-functions.html">在線文檔</a>來獲得更多有關編寫函數的信息。</p>
|
||||
<h4>傳送消息</h4>
|
||||
<p>要將消息傳遞到流程中的下一個節點,請返回消息或調用<code>node.send(messages)</code>。</p>
|
||||
<p>它將返回/send:</p>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/nodes",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -38,13 +38,13 @@
|
||||
"mqtt": "4.3.7",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"mustache": "4.2.0",
|
||||
"node-watch": "0.7.3",
|
||||
"node-watch": "0.7.4",
|
||||
"on-headers": "1.0.2",
|
||||
"raw-body": "2.5.2",
|
||||
"tough-cookie": "4.1.2",
|
||||
"tough-cookie": "4.1.3",
|
||||
"uuid": "9.0.0",
|
||||
"ws": "7.5.6",
|
||||
"xml2js": "0.6.0",
|
||||
"xml2js": "0.6.2",
|
||||
"iconv-lite": "0.6.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/registry",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,10 +16,10 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "3.1.0-beta.4",
|
||||
"@node-red/util": "4.0.0-dev",
|
||||
"clone": "2.1.2",
|
||||
"fs-extra": "11.1.1",
|
||||
"semver": "7.5.0",
|
||||
"semver": "7.5.4",
|
||||
"tar": "6.1.13",
|
||||
"uglify-js": "3.17.4"
|
||||
}
|
||||
|
||||
@@ -71,30 +71,30 @@ function readFile(path,backupPath,emptyResponse,type) {
|
||||
});
|
||||
}
|
||||
|
||||
const writeFileLocks = {}
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Write content to a file using UTF8 encoding.
|
||||
* This forces a fsync before completing to ensure
|
||||
* the write hits disk.
|
||||
*/
|
||||
writeFile: function(path,content,backupPath) {
|
||||
var backupPromise;
|
||||
if (backupPath && fs.existsSync(path)) {
|
||||
backupPromise = fs.copy(path,backupPath);
|
||||
} else {
|
||||
backupPromise = Promise.resolve();
|
||||
writeFile: async function(path,content,backupPath) {
|
||||
if (!writeFileLocks[path]) {
|
||||
writeFileLocks[path] = Promise.resolve()
|
||||
}
|
||||
|
||||
const dirname = fspath.dirname(path);
|
||||
const tempFile = `${path}.$$$`;
|
||||
|
||||
return backupPromise.then(() => {
|
||||
if (backupPath) {
|
||||
const result = writeFileLocks[path].then(async () => {
|
||||
var backupPromise;
|
||||
if (backupPath && fs.existsSync(path)) {
|
||||
await fs.copy(path,backupPath);
|
||||
log.trace(`utils.writeFile - copied ${path} TO ${backupPath}`)
|
||||
}
|
||||
return fs.ensureDir(dirname)
|
||||
}).then(() => {
|
||||
return new Promise(function(resolve,reject) {
|
||||
|
||||
const dirname = fspath.dirname(path);
|
||||
const tempFile = `${path}.$$$`;
|
||||
await fs.ensureDir(dirname)
|
||||
|
||||
await new Promise(function(resolve,reject) {
|
||||
var stream = fs.createWriteStream(tempFile);
|
||||
stream.on('open',function(fd) {
|
||||
stream.write(content,'utf8',function() {
|
||||
@@ -110,10 +110,11 @@ module.exports = {
|
||||
log.warn(log._("storage.localfilesystem.fsync-fail",{path: tempFile, message: err.toString()}));
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}).then(() => {
|
||||
})
|
||||
|
||||
log.trace(`utils.writeFile - written content to ${tempFile}`)
|
||||
return new Promise(function(resolve,reject) {
|
||||
|
||||
await new Promise(function(resolve,reject) {
|
||||
fs.rename(tempFile,path,err => {
|
||||
if (err) {
|
||||
log.warn(log._("storage.localfilesystem.fsync-fail",{path: path, message: err.toString()}));
|
||||
@@ -122,8 +123,10 @@ module.exports = {
|
||||
log.trace(`utils.writeFile - renamed ${tempFile} to ${path}`)
|
||||
resolve();
|
||||
})
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
writeFileLocks[path] = result.catch(() => {})
|
||||
return result
|
||||
},
|
||||
readFile: readFile,
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/runtime",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/registry": "3.1.0-beta.4",
|
||||
"@node-red/util": "3.1.0-beta.4",
|
||||
"@node-red/registry": "4.0.0-dev",
|
||||
"@node-red/util": "4.0.0-dev",
|
||||
"async-mutex": "0.4.0",
|
||||
"clone": "2.1.2",
|
||||
"express": "4.18.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/util",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
8
packages/node_modules/node-red/README.md
vendored
8
packages/node_modules/node-red/README.md
vendored
@@ -1,14 +1,14 @@
|
||||
# Node-RED
|
||||
|
||||
http://nodered.org
|
||||
https://nodered.org
|
||||
|
||||
Low-code programming for event-driven applications.
|
||||
|
||||

|
||||

|
||||
|
||||
## Quick Start
|
||||
|
||||
Check out http://nodered.org/docs/getting-started/ for full instructions on getting
|
||||
Check out https://nodered.org/docs/getting-started/ for full instructions on getting
|
||||
started.
|
||||
|
||||
1. `sudo npm install -g --unsafe-perm node-red`
|
||||
@@ -17,7 +17,7 @@ started.
|
||||
|
||||
## Getting Help
|
||||
|
||||
More documentation can be found [here](http://nodered.org/docs).
|
||||
More documentation can be found [here](https://nodered.org/docs).
|
||||
|
||||
For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||
|
||||
|
||||
16
packages/node_modules/node-red/package.json
vendored
16
packages/node_modules/node-red/package.json
vendored
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"homepage": "https://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -31,17 +31,17 @@
|
||||
"flow"
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/editor-api": "3.1.0-beta.4",
|
||||
"@node-red/runtime": "3.1.0-beta.4",
|
||||
"@node-red/util": "3.1.0-beta.4",
|
||||
"@node-red/nodes": "3.1.0-beta.4",
|
||||
"@node-red/editor-api": "4.0.0-dev",
|
||||
"@node-red/runtime": "4.0.0-dev",
|
||||
"@node-red/util": "4.0.0-dev",
|
||||
"@node-red/nodes": "4.0.0-dev",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"express": "4.18.2",
|
||||
"fs-extra": "11.1.1",
|
||||
"node-red-admin": "^3.0.0",
|
||||
"node-red-admin": "^3.1.0",
|
||||
"nopt": "5.0.0",
|
||||
"semver": "7.5.0"
|
||||
"semver": "7.5.4"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcrypt": "5.1.0"
|
||||
|
||||
2
packages/node_modules/node-red/red.js
vendored
2
packages/node_modules/node-red/red.js
vendored
@@ -88,7 +88,7 @@ if (parsedArgs.help) {
|
||||
console.log(" -?, --help show this help");
|
||||
console.log(" admin <command> run an admin command");
|
||||
console.log("");
|
||||
console.log("Documentation can be found at http://nodered.org");
|
||||
console.log("Documentation can be found at https://nodered.org");
|
||||
process.exit();
|
||||
}
|
||||
|
||||
|
||||
8
packages/node_modules/node-red/settings.js
vendored
8
packages/node_modules/node-red/settings.js
vendored
@@ -71,7 +71,7 @@ module.exports = {
|
||||
******************************************************************************/
|
||||
|
||||
/** To password protect the Node-RED editor and admin API, the following
|
||||
* property can be used. See http://nodered.org/docs/security.html for details.
|
||||
* property can be used. See https://nodered.org/docs/security.html for details.
|
||||
*/
|
||||
//adminAuth: {
|
||||
// type: "credentials",
|
||||
@@ -120,7 +120,7 @@ module.exports = {
|
||||
* including node-red-dashboard, or the static content (httpStatic), the
|
||||
* following properties can be used.
|
||||
* The `pass` field is a bcrypt hash of the password.
|
||||
* See http://nodered.org/docs/security.html#generating-the-password-hash
|
||||
* See https://nodered.org/docs/security.html#generating-the-password-hash
|
||||
*/
|
||||
//httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."},
|
||||
//httpStaticAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."},
|
||||
@@ -444,6 +444,7 @@ module.exports = {
|
||||
* - fileWorkingDirectory
|
||||
* - functionGlobalContext
|
||||
* - functionExternalModules
|
||||
* - functionTimeout
|
||||
* - nodeMessageBufferMaxLength
|
||||
* - ui (for use with Node-RED Dashboard)
|
||||
* - debugUseColors
|
||||
@@ -468,6 +469,9 @@ module.exports = {
|
||||
/** Allow the Function node to load additional npm modules directly */
|
||||
functionExternalModules: true,
|
||||
|
||||
/** Default timeout, in seconds, for the Function node. 0 means no timeout is applied */
|
||||
functionTimeout: 0,
|
||||
|
||||
/** The following property can be used to set predefined values in Global Context.
|
||||
* This allows extra node modules to be made available with in Function node.
|
||||
* For example, the following:
|
||||
|
||||
@@ -1449,6 +1449,34 @@ describe('function node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('check if default function timeout settings are recognized', function (done) {
|
||||
RED.settings.functionTimeout = 0.01;
|
||||
var flow = [{id: "n1",type: "function",timeout: RED.settings.functionTimeout,wires: [["n2"]],func: "while(1==1){};\nreturn msg;"}];
|
||||
helper.load(functionNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.receive({ payload: "foo", topic: "bar" });
|
||||
setTimeout(function () {
|
||||
try {
|
||||
helper.log().called.should.be.true();
|
||||
var logEvents = helper.log().args.filter(function (evt) {
|
||||
return evt[0].type == "function";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
var msg = logEvents[0][0];
|
||||
msg.should.have.property('level', helper.log().ERROR);
|
||||
msg.should.have.property('id', 'n1');
|
||||
msg.should.have.property('type', 'function');
|
||||
should.equal(RED.settings.functionTimeout, 0.01);
|
||||
should.equal(msg.msg.message, 'Script execution timed out after 10ms');
|
||||
delete RED.settings.functionTimeout;
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
});
|
||||
|
||||
describe("finalize function", function() {
|
||||
|
||||
it('should execute', function(done) {
|
||||
@@ -1690,9 +1718,13 @@ describe('function node', function() {
|
||||
describe("init function", function() {
|
||||
|
||||
it('should delay handling messages until init completes', function(done) {
|
||||
const timeoutMS = 200;
|
||||
// Since helper.load uses process.nextTick timers might occasionally finish
|
||||
// a couple of milliseconds too early, so give some leeway to the check.
|
||||
const timeoutCheckMargin = 5;
|
||||
var flow = [{id:"n1",type:"function",wires:[["n2"]],initialize: `
|
||||
return new Promise((resolve,reject) => {
|
||||
setTimeout(resolve,200)
|
||||
setTimeout(resolve, ${timeoutMS});
|
||||
})`,
|
||||
func:"return msg;"
|
||||
},
|
||||
@@ -1705,9 +1737,10 @@ describe('function node', function() {
|
||||
msg.delta = Date.now() - msg.payload;
|
||||
receivedMsgs.push(msg)
|
||||
if (receivedMsgs.length === 5) {
|
||||
var errors = receivedMsgs.filter(msg => msg.delta < 200)
|
||||
let deltas = receivedMsgs.map(msg => msg.delta);
|
||||
var errors = deltas.filter(delta => delta < (timeoutMS - timeoutCheckMargin))
|
||||
if (errors.length > 0) {
|
||||
done(new Error(`Message received before init completed - was ${msg.delta} expected >300`))
|
||||
done(new Error(`Message received before init completed - delta values ${JSON.stringify(deltas)} expected to be > ${timeoutMS - timeoutCheckMargin}`))
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ describe("api/editor/theme", function () {
|
||||
},
|
||||
header: {
|
||||
title: "Test Header Title",
|
||||
url: "http://nodered.org",
|
||||
url: "https://nodered.org",
|
||||
image: "/absolute/path/to/header/image" // or null to remove image
|
||||
},
|
||||
|
||||
@@ -147,7 +147,7 @@ describe("api/editor/theme", function () {
|
||||
context.page.tabicon.should.have.a.property("colour", "#8f008f")
|
||||
context.should.have.a.property("header");
|
||||
context.header.should.have.a.property("title", "Test Header Title");
|
||||
context.header.should.have.a.property("url", "http://nodered.org");
|
||||
context.header.should.have.a.property("url", "https://nodered.org");
|
||||
context.header.should.have.a.property("image", "theme/header/image");
|
||||
context.page.should.have.a.property("css");
|
||||
context.page.css.should.have.lengthOf(1);
|
||||
|
||||
@@ -14,11 +14,33 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var NR_TEST_UTILS = require("nr-test-utils");
|
||||
var util = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem/util");
|
||||
const should = require("should");
|
||||
const NR_TEST_UTILS = require("nr-test-utils");
|
||||
const util = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem/util");
|
||||
const { mkdtemp, readFile } = require('fs/promises');
|
||||
const { join } = require('path');
|
||||
const { tmpdir } = require('os');
|
||||
|
||||
describe('storage/localfilesystem/util', function() {
|
||||
describe('writeFile', function () {
|
||||
it('manages concurrent calls to modify the same file', async function () {
|
||||
const testDirectory = await mkdtemp(join(tmpdir(), 'nr-test-'));
|
||||
const testFile = join(testDirectory, 'foo.txt')
|
||||
const testBackupFile = testFile + '.$$$'
|
||||
|
||||
let counter = 0
|
||||
const promises = [
|
||||
util.writeFile(testFile, `update-${counter++}`, testBackupFile ),
|
||||
util.writeFile(testFile, `update-${counter++}`, testBackupFile ),
|
||||
util.writeFile(testFile, `update-${counter++}`, testBackupFile )
|
||||
]
|
||||
|
||||
await Promise.all(promises)
|
||||
|
||||
const result = await readFile(testFile, { encoding: 'utf-8' })
|
||||
result.should.equal('update-2')
|
||||
})
|
||||
})
|
||||
describe('parseJSON', function() {
|
||||
it('returns parsed JSON', function() {
|
||||
var result = util.parseJSON('{"a":123}');
|
||||
|
||||
Reference in New Issue
Block a user