@node-red/nodes 2.2.2 → 3.0.0-beta.1
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/core/common/05-junction.html +5 -0
- package/core/common/05-junction.js +12 -0
- package/core/common/20-inject.html +25 -13
- package/core/common/21-debug.html +60 -6
- package/core/common/21-debug.js +57 -27
- package/core/common/60-link.html +66 -29
- package/core/common/60-link.js +169 -20
- package/core/common/lib/debug/debug-utils.js +34 -1
- package/core/function/10-function.html +57 -21
- package/core/function/10-switch.html +3 -1
- package/core/function/10-switch.js +1 -0
- package/core/function/15-change.html +40 -12
- package/core/function/16-range.html +14 -5
- package/core/function/80-template.html +16 -12
- package/core/function/89-delay.html +46 -6
- package/core/function/89-trigger.html +12 -4
- package/core/function/rbe.html +7 -3
- package/core/network/05-tls.html +10 -4
- package/core/network/06-httpproxy.html +10 -1
- package/core/network/10-mqtt.html +73 -17
- package/core/network/10-mqtt.js +191 -80
- package/core/network/21-httpin.html +6 -2
- package/core/network/21-httprequest.html +217 -12
- package/core/network/21-httprequest.js +98 -17
- package/core/network/22-websocket.html +19 -5
- package/core/network/22-websocket.js +16 -13
- package/core/network/31-tcpin.html +47 -10
- package/core/network/31-tcpin.js +8 -3
- package/core/network/32-udp.html +14 -2
- package/core/parsers/70-CSV.html +4 -1
- package/core/parsers/70-JSON.html +3 -2
- package/core/parsers/70-XML.html +2 -1
- package/core/parsers/70-YAML.html +2 -1
- package/core/sequence/17-split.html +5 -1
- package/core/sequence/19-batch.html +28 -4
- package/core/storage/10-file.html +68 -8
- package/core/storage/10-file.js +46 -3
- package/core/storage/23-watch.html +2 -1
- package/core/storage/23-watch.js +21 -43
- package/locales/de/messages.json +1 -0
- package/locales/en-US/common/60-link.html +18 -3
- package/locales/en-US/messages.json +68 -17
- package/locales/en-US/network/21-httprequest.html +1 -1
- package/locales/en-US/storage/10-file.html +6 -2
- package/locales/ja/common/60-link.html +12 -0
- package/locales/ja/messages.json +63 -16
- package/locales/ko/messages.json +1 -0
- package/locales/ru/messages.json +1 -0
- package/locales/zh-CN/messages.json +1 -0
- package/locales/zh-TW/messages.json +1 -0
- package/package.json +12 -12
package/core/network/10-mqtt.js
CHANGED
|
@@ -20,7 +20,30 @@ module.exports = function(RED) {
|
|
|
20
20
|
var isUtf8 = require('is-utf8');
|
|
21
21
|
var HttpsProxyAgent = require('https-proxy-agent');
|
|
22
22
|
var url = require('url');
|
|
23
|
-
|
|
23
|
+
const knownMediaTypes = {
|
|
24
|
+
"text/css":"string",
|
|
25
|
+
"text/html":"string",
|
|
26
|
+
"text/plain":"string",
|
|
27
|
+
"text/html":"string",
|
|
28
|
+
"application/json":"json",
|
|
29
|
+
"application/octet-stream":"buffer",
|
|
30
|
+
"application/pdf":"buffer",
|
|
31
|
+
"application/x-gtar":"buffer",
|
|
32
|
+
"application/x-gzip":"buffer",
|
|
33
|
+
"application/x-tar":"buffer",
|
|
34
|
+
"application/xml":"string",
|
|
35
|
+
"application/zip":"buffer",
|
|
36
|
+
"audio/aac":"buffer",
|
|
37
|
+
"audio/ac3":"buffer",
|
|
38
|
+
"audio/basic":"buffer",
|
|
39
|
+
"audio/mp4":"buffer",
|
|
40
|
+
"audio/ogg":"buffer",
|
|
41
|
+
"image/bmp":"buffer",
|
|
42
|
+
"image/gif":"buffer",
|
|
43
|
+
"image/jpeg":"buffer",
|
|
44
|
+
"image/tiff":"buffer",
|
|
45
|
+
"image/png":"buffer",
|
|
46
|
+
}
|
|
24
47
|
//#region "Supporting functions"
|
|
25
48
|
function matchTopic(ts,t) {
|
|
26
49
|
if (ts == "#") {
|
|
@@ -68,12 +91,21 @@ module.exports = function(RED) {
|
|
|
68
91
|
}
|
|
69
92
|
|
|
70
93
|
/**
|
|
71
|
-
* Test a topic string is valid
|
|
94
|
+
* Test a topic string is valid for subscription
|
|
72
95
|
* @param {string} topic
|
|
73
96
|
* @returns `true` if it is a valid topic
|
|
74
97
|
*/
|
|
75
98
|
function isValidSubscriptionTopic(topic) {
|
|
76
|
-
return /^(#$|(\+|[^+#]*)(\/(\+|[^+#]*))*(\/(\+|#|[^+#]*))?$)/.test(topic)
|
|
99
|
+
return /^(#$|(\+|[^+#]*)(\/(\+|[^+#]*))*(\/(\+|#|[^+#]*))?$)/.test(topic);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Test a topic string is valid for publishing
|
|
104
|
+
* @param {string} topic
|
|
105
|
+
* @returns `true` if it is a valid topic
|
|
106
|
+
*/
|
|
107
|
+
function isValidPublishTopic(topic) {
|
|
108
|
+
return !/[\+#\b\f\n\r\t\v\0]/.test(topic);
|
|
77
109
|
}
|
|
78
110
|
|
|
79
111
|
/**
|
|
@@ -103,7 +135,7 @@ module.exports = function(RED) {
|
|
|
103
135
|
if(src[propName] === "true" || src[propName] === true) {
|
|
104
136
|
dst[propName] = true;
|
|
105
137
|
} else if(src[propName] === "false" || src[propName] === false) {
|
|
106
|
-
dst[propName] =
|
|
138
|
+
dst[propName] = false;
|
|
107
139
|
}
|
|
108
140
|
} else {
|
|
109
141
|
if(def != undefined) dst[propName] = def;
|
|
@@ -188,6 +220,19 @@ module.exports = function(RED) {
|
|
|
188
220
|
*/
|
|
189
221
|
function subscriptionHandler(node, datatype ,topic, payload, packet) {
|
|
190
222
|
const v5 = node.brokerConn.options && node.brokerConn.options.protocolVersion == 5;
|
|
223
|
+
var msg = {topic:topic, payload:null, qos:packet.qos, retain:packet.retain};
|
|
224
|
+
if(v5 && packet.properties) {
|
|
225
|
+
setStrProp(packet.properties, msg, "responseTopic");
|
|
226
|
+
setBufferProp(packet.properties, msg, "correlationData");
|
|
227
|
+
setStrProp(packet.properties, msg, "contentType");
|
|
228
|
+
setIntProp(packet.properties, msg, "messageExpiryInterval", 0);
|
|
229
|
+
setBoolProp(packet.properties, msg, "payloadFormatIndicator");
|
|
230
|
+
setStrProp(packet.properties, msg, "reasonString");
|
|
231
|
+
setUserProperties(packet.properties.userProperties, msg);
|
|
232
|
+
}
|
|
233
|
+
const v5isUtf8 = v5 ? msg.payloadFormatIndicator === true : null;
|
|
234
|
+
const v5HasMediaType = v5 ? !!msg.contentType : null;
|
|
235
|
+
const v5MediaTypeLC = v5 ? (msg.contentType + "").toLowerCase() : null;
|
|
191
236
|
|
|
192
237
|
if (datatype === "buffer") {
|
|
193
238
|
// payload = payload;
|
|
@@ -196,25 +241,65 @@ module.exports = function(RED) {
|
|
|
196
241
|
} else if (datatype === "utf8") {
|
|
197
242
|
payload = payload.toString('utf8');
|
|
198
243
|
} else if (datatype === "json") {
|
|
199
|
-
if (isUtf8(payload)) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
catch(e) {
|
|
244
|
+
if (v5isUtf8 || isUtf8(payload)) {
|
|
245
|
+
try {
|
|
246
|
+
payload = JSON.parse(payload.toString());
|
|
247
|
+
} catch (e) {
|
|
248
|
+
node.error(RED._("mqtt.errors.invalid-json-parse"), { payload: payload, topic: topic, qos: packet.qos, retain: packet.retain }); return;
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
node.error((RED._("mqtt.errors.invalid-json-string")), { payload: payload, topic: topic, qos: packet.qos, retain: packet.retain }); return;
|
|
203
252
|
}
|
|
204
|
-
else { node.error((RED._("mqtt.errors.invalid-json-string")),{payload:payload, topic:topic, qos:packet.qos, retain:packet.retain}); return; }
|
|
205
253
|
} else {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
254
|
+
//"auto" (legacy) or "auto-detect" (new default)
|
|
255
|
+
if (v5isUtf8 || v5HasMediaType) {
|
|
256
|
+
const outputType = knownMediaTypes[v5MediaTypeLC]
|
|
257
|
+
switch (outputType) {
|
|
258
|
+
case "string":
|
|
259
|
+
payload = payload.toString();
|
|
260
|
+
break;
|
|
261
|
+
case "buffer":
|
|
262
|
+
//no change
|
|
263
|
+
break;
|
|
264
|
+
case "json":
|
|
265
|
+
try {
|
|
266
|
+
//since v5 type states this should be JSON, parse it & error out if NOT JSON
|
|
267
|
+
payload = payload.toString()
|
|
268
|
+
const obj = JSON.parse(payload);
|
|
269
|
+
if (datatype === "auto-detect") {
|
|
270
|
+
payload = obj; //as mode is "auto-detect", return the parsed JSON
|
|
271
|
+
}
|
|
272
|
+
} catch (e) {
|
|
273
|
+
node.error(RED._("mqtt.errors.invalid-json-parse"), { payload: payload, topic: topic, qos: packet.qos, retain: packet.retain }); return;
|
|
274
|
+
}
|
|
275
|
+
break;
|
|
276
|
+
default:
|
|
277
|
+
if (v5isUtf8 || isUtf8(payload)) {
|
|
278
|
+
payload = payload.toString(); //auto String
|
|
279
|
+
if (datatype === "auto-detect") {
|
|
280
|
+
try {
|
|
281
|
+
payload = JSON.parse(payload); //auto to parsed object (attempt)
|
|
282
|
+
} catch (e) {
|
|
283
|
+
/* mute error - it simply isnt JSON, just leave payload as a string */
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
} else if (isUtf8(payload)) {
|
|
290
|
+
payload = payload.toString(); //auto String
|
|
291
|
+
if (datatype === "auto-detect") {
|
|
292
|
+
try {
|
|
293
|
+
payload = JSON.parse(payload);
|
|
294
|
+
} catch (e) {
|
|
295
|
+
/* mute error - it simply isnt JSON, just leave payload as a string */
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
} //else {
|
|
299
|
+
//leave as buffer
|
|
300
|
+
//}
|
|
217
301
|
}
|
|
302
|
+
msg.payload = payload;
|
|
218
303
|
if ((node.brokerConn.broker === "localhost")||(node.brokerConn.broker === "127.0.0.1")) {
|
|
219
304
|
msg._topic = topic;
|
|
220
305
|
}
|
|
@@ -264,38 +349,15 @@ module.exports = function(RED) {
|
|
|
264
349
|
msg.messageExpiryInterval = node.messageExpiryInterval;
|
|
265
350
|
}
|
|
266
351
|
}
|
|
267
|
-
if (msg.userProperties && typeof msg.userProperties !== "object") {
|
|
268
|
-
delete msg.userProperties;
|
|
269
|
-
}
|
|
270
|
-
if (hasProperty(msg, "topicAlias") && !isNaN(msg.topicAlias) && (msg.topicAlias === 0 || bsp.topicAliasMaximum === 0 || msg.topicAlias > bsp.topicAliasMaximum)) {
|
|
271
|
-
delete msg.topicAlias;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
352
|
if (hasProperty(msg, "payload")) {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
//NOTE: A value of 0 (in server props topicAliasMaximum) indicates that the Server does not accept any Topic Aliases on this connection
|
|
281
|
-
if (hasProperty(msg, "topicAlias") && !isNaN(msg.topicAlias) && msg.topicAlias >= 0 && bsp.topicAliasMaximum && bsp.topicAliasMaximum >= msg.topicAlias) {
|
|
282
|
-
topicOK = true;
|
|
283
|
-
msg.topic = ""; //must be empty string
|
|
284
|
-
} else if (hasProperty(msg, "responseTopic") && (typeof msg.responseTopic === "string") && (msg.responseTopic !== "")) {
|
|
285
|
-
//TODO: if topic is empty but responseTopic has a string value, use that instead. Is this desirable?
|
|
286
|
-
topicOK = true;
|
|
287
|
-
msg.topic = msg.responseTopic;
|
|
288
|
-
//TODO: delete msg.responseTopic - to prevent it being resent?
|
|
353
|
+
// send the message
|
|
354
|
+
node.brokerConn.publish(msg, function(err) {
|
|
355
|
+
if(err && err.warn) {
|
|
356
|
+
node.warn(err);
|
|
357
|
+
return;
|
|
289
358
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
if (topicOK) {
|
|
294
|
-
node.brokerConn.publish(msg, done); // send the message
|
|
295
|
-
} else {
|
|
296
|
-
node.warn(RED._("mqtt.errors.invalid-topic"));
|
|
297
|
-
done();
|
|
298
|
-
}
|
|
359
|
+
done(err);
|
|
360
|
+
});
|
|
299
361
|
} else {
|
|
300
362
|
done();
|
|
301
363
|
}
|
|
@@ -415,8 +477,12 @@ module.exports = function(RED) {
|
|
|
415
477
|
setIfHasProperty(opts, node, "topicAliasMaximum", init);
|
|
416
478
|
setIfHasProperty(opts, node, "maximumPacketSize", init);
|
|
417
479
|
setIfHasProperty(opts, node, "receiveMaximum", init);
|
|
418
|
-
|
|
419
|
-
|
|
480
|
+
//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116
|
|
481
|
+
if (hasProperty(opts, "userProperties")) {
|
|
482
|
+
node.userProperties = opts.userProperties;
|
|
483
|
+
} else if (hasProperty(opts, "userProps")) {
|
|
484
|
+
node.userProperties = opts.userProps;
|
|
485
|
+
}
|
|
420
486
|
|
|
421
487
|
function createLWT(topic, payload, qos, retain, v5opts, v5SubPropName) {
|
|
422
488
|
let message = undefined;
|
|
@@ -465,7 +531,7 @@ module.exports = function(RED) {
|
|
|
465
531
|
};
|
|
466
532
|
if(hasProperty(opts, "willTopic")) {
|
|
467
533
|
//will v5 properties must be set in the "properties" sub object
|
|
468
|
-
node.options.will = createLWT(opts.willTopic, opts.willPayload, opts.willQos, opts.willRetain, opts.willMsg, "
|
|
534
|
+
node.options.will = createLWT(opts.willTopic, opts.willPayload, opts.willQos, opts.willRetain, opts.willMsg, "properties");
|
|
469
535
|
};
|
|
470
536
|
} else {
|
|
471
537
|
//update options
|
|
@@ -750,32 +816,48 @@ module.exports = function(RED) {
|
|
|
750
816
|
}
|
|
751
817
|
}
|
|
752
818
|
};
|
|
819
|
+
|
|
753
820
|
node.disconnect = function (callback) {
|
|
754
|
-
const _callback = function (
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
node.closing = true;
|
|
758
|
-
node.connecting = false;
|
|
759
|
-
node.connected = false;
|
|
821
|
+
const _callback = function () {
|
|
822
|
+
if(node.connected || node.connecting) {
|
|
823
|
+
setStatusDisconnected(node, true);
|
|
760
824
|
}
|
|
825
|
+
if(node.client) { node.client.removeAllListeners(); }
|
|
826
|
+
node.connecting = false;
|
|
827
|
+
node.connected = false;
|
|
761
828
|
callback && typeof callback == "function" && callback();
|
|
762
829
|
};
|
|
830
|
+
if(!node.client) { return _callback(); }
|
|
831
|
+
if(node.closing) { return _callback(); }
|
|
763
832
|
|
|
764
|
-
|
|
765
|
-
return
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
833
|
+
let waitEnd = (client, ms) => {
|
|
834
|
+
return new Promise( (resolve, reject) => {
|
|
835
|
+
node.closing = true;
|
|
836
|
+
if(!client) {
|
|
837
|
+
resolve();
|
|
838
|
+
} else {
|
|
839
|
+
const t = setTimeout(reject, ms);
|
|
840
|
+
client.end(() => {
|
|
841
|
+
clearTimeout(t);
|
|
842
|
+
resolve()
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
};
|
|
769
847
|
if(node.connected && node.closeMessage) {
|
|
770
848
|
node.publish(node.closeMessage, function (err) {
|
|
771
|
-
node.client.
|
|
772
|
-
|
|
849
|
+
waitEnd(node.client, 2000).then(() => {
|
|
850
|
+
_callback();
|
|
851
|
+
}).catch((e) => {
|
|
852
|
+
_callback();
|
|
853
|
+
})
|
|
773
854
|
});
|
|
774
|
-
} else if(node.connected) {
|
|
775
|
-
node.client.end(endCallBack);
|
|
776
|
-
_callback(true);
|
|
777
855
|
} else {
|
|
778
|
-
|
|
856
|
+
waitEnd(node.client, 2000).then(() => {
|
|
857
|
+
_callback();
|
|
858
|
+
}).catch((e) => {
|
|
859
|
+
_callback();
|
|
860
|
+
})
|
|
779
861
|
}
|
|
780
862
|
}
|
|
781
863
|
node.subscriptionIds = {};
|
|
@@ -857,8 +939,18 @@ module.exports = function(RED) {
|
|
|
857
939
|
qos: msg.qos || 0,
|
|
858
940
|
retain: msg.retain || false
|
|
859
941
|
};
|
|
942
|
+
let topicOK = hasProperty(msg, "topic") && (typeof msg.topic === "string") && (isValidPublishTopic(msg.topic));
|
|
860
943
|
//https://github.com/mqttjs/MQTT.js/blob/master/README.md#mqttclientpublishtopic-message-options-callback
|
|
861
944
|
if(node.options.protocolVersion == 5) {
|
|
945
|
+
const bsp = node.serverProperties || {};
|
|
946
|
+
if (msg.userProperties && typeof msg.userProperties !== "object") {
|
|
947
|
+
delete msg.userProperties;
|
|
948
|
+
}
|
|
949
|
+
if (hasProperty(msg, "topicAlias") && !isNaN(Number(msg.topicAlias))) {
|
|
950
|
+
msg.topicAlias = parseInt(msg.topicAlias);
|
|
951
|
+
} else {
|
|
952
|
+
delete msg.topicAlias;
|
|
953
|
+
}
|
|
862
954
|
options.properties = options.properties || {};
|
|
863
955
|
setStrProp(msg, options.properties, "responseTopic");
|
|
864
956
|
setBufferProp(msg, options.properties, "correlationData");
|
|
@@ -868,29 +960,46 @@ module.exports = function(RED) {
|
|
|
868
960
|
setIntProp(msg, options.properties, "topicAlias", 1, node.serverProperties.topicAliasMaximum || 0);
|
|
869
961
|
setBoolProp(msg, options.properties, "payloadFormatIndicator");
|
|
870
962
|
//FUTURE setIntProp(msg, options.properties, "subscriptionIdentifier", 1, 268435455);
|
|
871
|
-
|
|
872
|
-
|
|
963
|
+
|
|
964
|
+
//check & sanitise topic
|
|
965
|
+
if (topicOK && options.properties.topicAlias) {
|
|
966
|
+
let aliasValid = (bsp.topicAliasMaximum && bsp.topicAliasMaximum >= options.properties.topicAlias);
|
|
967
|
+
if (!aliasValid) {
|
|
873
968
|
done("Invalid topicAlias");
|
|
874
969
|
return
|
|
875
970
|
}
|
|
876
971
|
if (node.topicAliases[options.properties.topicAlias] === msg.topic) {
|
|
877
|
-
msg.topic = ""
|
|
972
|
+
msg.topic = "";
|
|
878
973
|
} else {
|
|
879
|
-
node.topicAliases[options.properties.topicAlias] = msg.topic
|
|
974
|
+
node.topicAliases[options.properties.topicAlias] = msg.topic;
|
|
880
975
|
}
|
|
976
|
+
} else if (!msg.topic && options.properties.responseTopic) {
|
|
977
|
+
msg.topic = msg.responseTopic;
|
|
978
|
+
topicOK = isValidPublishTopic(msg.topic);
|
|
979
|
+
delete msg.responseTopic; //prevent responseTopic being resent?
|
|
881
980
|
}
|
|
882
981
|
}
|
|
883
982
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
983
|
+
if (topicOK) {
|
|
984
|
+
node.client.publish(msg.topic, msg.payload, options, function(err) {
|
|
985
|
+
done && done(err);
|
|
986
|
+
return
|
|
987
|
+
});
|
|
988
|
+
} else {
|
|
989
|
+
const error = new Error(RED._("mqtt.errors.invalid-topic"));
|
|
990
|
+
error.warn = true;
|
|
991
|
+
done(error);
|
|
992
|
+
}
|
|
888
993
|
}
|
|
889
994
|
};
|
|
890
995
|
|
|
891
996
|
node.on('close', function(done) {
|
|
892
|
-
node.
|
|
893
|
-
|
|
997
|
+
node.disconnect(function() {
|
|
998
|
+
if(node.client) {
|
|
999
|
+
node.client.removeAllListeners();
|
|
1000
|
+
}
|
|
1001
|
+
done();
|
|
1002
|
+
});
|
|
894
1003
|
});
|
|
895
1004
|
|
|
896
1005
|
}
|
|
@@ -1067,6 +1176,7 @@ module.exports = function(RED) {
|
|
|
1067
1176
|
node.brokerConn.unsubscribe(node.topic,node.id, removed);
|
|
1068
1177
|
}
|
|
1069
1178
|
node.brokerConn.deregister(node, done);
|
|
1179
|
+
node.brokerConn = null;
|
|
1070
1180
|
} else {
|
|
1071
1181
|
done();
|
|
1072
1182
|
}
|
|
@@ -1131,6 +1241,7 @@ module.exports = function(RED) {
|
|
|
1131
1241
|
node.on('close', function(done) {
|
|
1132
1242
|
if (node.brokerConn) {
|
|
1133
1243
|
node.brokerConn.deregister(node,done);
|
|
1244
|
+
node.brokerConn = null;
|
|
1134
1245
|
} else {
|
|
1135
1246
|
done();
|
|
1136
1247
|
}
|
|
@@ -70,7 +70,8 @@
|
|
|
70
70
|
color:"rgb(231, 231, 174)",
|
|
71
71
|
defaults: {
|
|
72
72
|
name: {value:""},
|
|
73
|
-
url: {value:"",required:true
|
|
73
|
+
url: {value:"", required:true,
|
|
74
|
+
label:RED._("node-red:httpin.label.url")},
|
|
74
75
|
method: {value:"get",required:true},
|
|
75
76
|
upload: {value:false},
|
|
76
77
|
swaggerDoc: {type:"swagger-doc", required:false}
|
|
@@ -146,7 +147,10 @@
|
|
|
146
147
|
color:"rgb(231, 231, 174)",
|
|
147
148
|
defaults: {
|
|
148
149
|
name: {value:""},
|
|
149
|
-
statusCode: {
|
|
150
|
+
statusCode: {
|
|
151
|
+
value:"",
|
|
152
|
+
label: RED._("node-red:httpin.label.status"),
|
|
153
|
+
validate: RED.validators.number(true)},
|
|
150
154
|
headers: {value:{}}
|
|
151
155
|
},
|
|
152
156
|
inputs:1,
|