Merge branch 'dev' into pr_4387

This commit is contained in:
Nick O'Leary
2024-03-21 16:41:24 +00:00
committed by GitHub
349 changed files with 53003 additions and 4221 deletions

View File

@@ -68,6 +68,7 @@ var api = module.exports = {
* @param {String} opts.store - the context store
* @param {String} opts.key - the context key
* @param {Object} opts.req - the request to log (optional)
* @param {Boolean} opts.keysOnly - whether to return keys only
* @return {Promise} - the node information
* @memberof @node-red/runtime_context
*/
@@ -102,6 +103,15 @@ var api = module.exports = {
if (key) {
store = store || availableStores.default;
ctx.get(key,store,function(err, v) {
if (opts.keysOnly) {
if (Array.isArray(v)) {
resolve({ [store]: { format: `array[${v.length}]`}})
} else if (typeof v === 'object') {
resolve({ [store]: { keys: Object.keys(v), format: 'Object' } })
} else {
resolve({ [store]: { keys: [] }})
}
}
var encoded = util.encodeObject({msg:v});
if (store !== availableStores.default) {
encoded.store = store;
@@ -118,32 +128,58 @@ var api = module.exports = {
stores = [store];
}
var result = {};
var c = stores.length;
var errorReported = false;
stores.forEach(function(store) {
exportContextStore(scope,ctx,store,result,function(err) {
if (err) {
// TODO: proper error reporting
if (!errorReported) {
errorReported = true;
runtime.log.audit({event: "context.get",scope:scope,id:id,store:store,key:key,error:"unexpected_error"}, opts.req);
var err = new Error();
err.code = "unexpected_error";
err.status = 400;
return reject(err);
if (opts.keysOnly) {
ctx.keys(store,function(err, keys) {
if (err) {
// TODO: proper error reporting
if (!errorReported) {
errorReported = true;
runtime.log.audit({event: "context.get",scope:scope,id:id,store:store,key:key,error:"unexpected_error"}, opts.req);
var err = new Error();
err.code = "unexpected_error";
err.status = 400;
return reject(err);
}
return
}
result[store] = { keys }
c--;
if (c === 0) {
if (!errorReported) {
runtime.log.audit({event: "context.get",scope:scope,id:id,store:store,key:key},opts.req);
resolve(result);
}
}
})
} else {
exportContextStore(scope,ctx,store,result,function(err) {
if (err) {
// TODO: proper error reporting
if (!errorReported) {
errorReported = true;
runtime.log.audit({event: "context.get",scope:scope,id:id,store:store,key:key,error:"unexpected_error"}, opts.req);
var err = new Error();
err.code = "unexpected_error";
err.status = 400;
return reject(err);
}
return;
}
c--;
if (c === 0) {
if (!errorReported) {
runtime.log.audit({event: "context.get",scope:scope,id:id,store:store,key:key},opts.req);
resolve(result);
return;
}
}
});
c--;
if (c === 0) {
if (!errorReported) {
runtime.log.audit({event: "context.get",scope:scope,id:id,store:store,key:key},opts.req);
resolve(result);
}
}
});
}
})
}
} else {

View File

@@ -99,6 +99,9 @@ var api = module.exports = {
safeSettings.markdownEditor = runtime.settings.editorTheme.markdownEditor || {};
safeSettings.markdownEditor.mermaid = safeSettings.markdownEditor.mermaid || { enabled: true };
}
if (runtime.settings.editorTheme.mermaid) {
safeSettings.mermaid = runtime.settings.editorTheme.mermaid
}
}
safeSettings.libraries = runtime.library.getLibraries();
if (util.isArray(runtime.settings.paletteCategories)) {

View File

@@ -161,7 +161,8 @@ class Flow {
for (let i = 0; i < configNodes.length; i++) {
const node = this.flow.configs[configNodes[i]]
if (node.type === 'global-config' && node.env) {
const nodeEnv = await flowUtil.evaluateEnvProperties(this, node.env, credentials.get(node.id))
const globalCreds = credentials.get(node.id)?.map || {}
const nodeEnv = await flowUtil.evaluateEnvProperties(this, node.env, globalCreds)
this._env = { ...this._env, ...nodeEnv }
}
}
@@ -484,7 +485,7 @@ class Flow {
}
if (!key.startsWith("$parent.")) {
if (this._env.hasOwnProperty(key)) {
return this._env[key]
return (this._env[key] && Object.hasOwn(this._env[key], 'value') && this._env[key].__clone__) ? clone(this._env[key].value) : this._env[key]
}
} else {
key = key.substring(8);

View File

@@ -41,7 +41,7 @@ class Group {
}
if (!key.startsWith("$parent.")) {
if (this._env.hasOwnProperty(key)) {
return this._env[key]
return (this._env[key] && Object.hasOwn(this._env[key], 'value') && this._env[key].__clone__) ? clone(this._env[key].value) : this._env[key]
}
} else {
key = key.substring(8);

View File

@@ -73,9 +73,20 @@ class Subflow extends Flow {
id: subflowInstance.id,
configs: {},
nodes: {},
groups: {},
subflows: {}
}
if (subflowDef.groups) {
// Clone all of the subflow group definitions and give them new IDs
for (i in subflowDef.groups) {
if (subflowDef.groups.hasOwnProperty(i)) {
node = createNodeInSubflow(subflowInstance.id,subflowDef.groups[i]);
node_map[node._alias] = node;
subflowInternalFlowConfig.groups[node.id] = node;
}
}
}
if (subflowDef.configs) {
// Clone all of the subflow config node definitions and give them new IDs
for (i in subflowDef.configs) {
@@ -101,6 +112,7 @@ class Subflow extends Flow {
remapSubflowNodes(subflowInternalFlowConfig.configs,node_map);
remapSubflowNodes(subflowInternalFlowConfig.nodes,node_map);
remapSubflowNodes(subflowInternalFlowConfig.groups,node_map);
// console.log("Instance config\n",JSON.stringify(subflowInternalFlowConfig,"",2));
@@ -200,6 +212,7 @@ class Subflow extends Flow {
var subflowInstanceConfig = {
id: this.subflowInstance.id,
type: this.subflowInstance.type,
g: this.subflowInstance.g,
z: this.subflowInstance.z,
name: this.subflowInstance.name,
wires: [],
@@ -237,7 +250,7 @@ class Subflow extends Flow {
for (j=0;j<wires.length;j++) {
if (wires[j].id != self.subflowDef.id) {
node = self.node_map[wires[j].id];
if (node._originalWires) {
if (node && node._originalWires) {
node.wires = clone(node._originalWires);
}
}
@@ -254,8 +267,10 @@ class Subflow extends Flow {
subflowInstanceModified = true;
} else {
node = self.node_map[wires[j].id];
node.wires[wires[j].port] = node.wires[wires[j].port].concat(newWires[i]);
modifiedNodes[node.id] = node;
if (node) {
node.wires[wires[j].port] = node.wires[wires[j].port].concat(newWires[i]);
modifiedNodes[node.id] = node;
}
}
}
}
@@ -283,10 +298,14 @@ class Subflow extends Flow {
this.node._updateWires(subflowInstanceConfig.wires);
} else {
var node = self.node_map[wires[j].id];
if (!node._originalWires) {
node._originalWires = clone(node.wires);
if (node) {
if (!node._originalWires) {
node._originalWires = clone(node.wires);
}
node.wires[wires[j].port] = (node.wires[wires[j].port]||[]).concat(this.subflowInstance.wires[i]);
} else {
this.error("Unknown node referenced inside subflow: " + wires[j].id)
}
node.wires[wires[j].port] = (node.wires[wires[j].port]||[]).concat(this.subflowInstance.wires[i]);
}
}
}
@@ -302,11 +321,15 @@ class Subflow extends Flow {
this.node._updateWires(subflowInstanceConfig.wires);
} else {
var node = self.node_map[wires[j].id];
if (!node._originalWires) {
node._originalWires = clone(node.wires);
if (node) {
if (!node._originalWires) {
node._originalWires = clone(node.wires);
}
node.wires[wires[j].port] = (node.wires[wires[j].port]||[]);
node.wires[wires[j].port].push(subflowStatusId);
} else {
this.error("Unknown node referenced inside subflow: " + wires[j].id)
}
node.wires[wires[j].port] = (node.wires[wires[j].port]||[]);
node.wires[wires[j].port].push(subflowStatusId);
}
}
}
@@ -353,7 +376,7 @@ class Subflow extends Flow {
}
if (!key.startsWith("$parent.")) {
if (this._env.hasOwnProperty(key)) {
return this._env[key]
return (this._env[key] && Object.hasOwn(this._env[key], 'value') && this._env[key].__clone__) ? clone(this._env[key].value) : this._env[key]
}
} else {
key = key.substring(8);

View File

@@ -374,7 +374,12 @@ async function start(type,diff,muteLog,isDeploy) {
// A modified-type deploy means restarting things that have changed
// Update the global flow
activeFlows['global'].update(activeFlowConfig,activeFlowConfig);
if (activeFlows['global']) {
activeFlows['global'].update(activeFlowConfig,activeFlowConfig);
} else {
log.debug("red/nodes/flows.start : starting flow : global");
activeFlows['global'] = Flow.create(flowAPI,activeFlowConfig);
}
for (id in activeFlowConfig.flows) {
if (activeFlowConfig.flows.hasOwnProperty(id)) {
if (!activeFlowConfig.flows[id].disabled) {

View File

@@ -57,18 +57,20 @@ var EnvVarPropertyRE = /^\${(\S+)}$/;
function mapEnvVarProperties(obj,prop,flow,config) {
var v = obj[prop];
const v = obj[prop];
if (Buffer.isBuffer(v)) {
return;
} else if (Array.isArray(v)) {
for (var i=0;i<v.length;i++) {
for (let i=0;i<v.length;i++) {
mapEnvVarProperties(v,i,flow,config);
}
} else if (typeof obj[prop] === 'string') {
if (obj[prop][0] === "$" && (EnvVarPropertyRE_old.test(v) || EnvVarPropertyRE.test(v)) ) {
var envVar = v.substring(2,v.length-1);
var r = redUtil.getSetting(config, envVar, flow);
obj[prop] = r ? r : obj[prop];
const envVar = v.substring(2,v.length-1);
const r = redUtil.getSetting(config, envVar, flow);
if (r !== undefined && r !== '') {
obj[prop] = r
}
}
} else {
for (var p in v) {
@@ -80,6 +82,7 @@ function mapEnvVarProperties(obj,prop,flow,config) {
}
async function evaluateEnvProperties(flow, env, credentials) {
credentials = credentials || {}
const pendingEvaluations = []
const evaluatedEnv = {}
const envTypes = []
@@ -99,6 +102,9 @@ async function evaluateEnvProperties(flow, env, credentials) {
pendingEvaluations.push(new Promise((resolve, _) => {
redUtil.evaluateNodeProperty(value, 'jsonata', {_flow: flow}, null, (err, result) => {
if (!err) {
if (typeof result === 'object') {
result = { value: result, __clone__: true}
}
evaluatedEnv[name] = result
}
resolve()
@@ -106,12 +112,16 @@ async function evaluateEnvProperties(flow, env, credentials) {
}))
} else {
value = redUtil.evaluateNodeProperty(value, type, {_flow: flow}, null, null);
if (typeof value === 'object') {
value = { value: value, __clone__: true}
}
}
evaluatedEnv[name] = value
}
if (pendingEvaluations.length > 0) {
await Promise.all(pendingEvaluations)
}
// Now loop over the env types and evaluate them properly
for (let i = 0; i < envTypes.length; i++) {
let { name, value, type } = envTypes[i]
// If an env-var wants to lookup itself, delegate straight to the parent
@@ -122,10 +132,25 @@ async function evaluateEnvProperties(flow, env, credentials) {
if (evaluatedEnv.hasOwnProperty(value)) {
value = evaluatedEnv[value]
} else {
value = redUtil.evaluateNodeProperty(value, type, {_flow: flow}, null, null);
value = redUtil.evaluateNodeProperty(value, type, {_flow: {
// Provide a hook so when it tries to look up a flow setting,
// we can insert the just-evaluated value which hasn't yet
// been set on the flow object - otherwise delegate up to the flow
getSetting: function(name) {
if (evaluatedEnv.hasOwnProperty(name)){
return evaluatedEnv[name]
}
return flow.getSetting(name)
}
}}, null, null);
}
if (typeof value === 'object' && !value.__clone__) {
value = { value: value, __clone__: true}
}
evaluatedEnv[name] = value
}
// console.log(evaluatedEnv)
return evaluatedEnv
}

View File

@@ -27,6 +27,7 @@ var express = require("express");
var path = require('path');
var fs = require("fs");
var os = require("os");
const crypto = require("crypto")
const {log,i18n,events,exec,util,hooks} = require("@node-red/util");
@@ -51,7 +52,7 @@ var adminApi = {
var nodeApp;
var adminApp;
var server;
let userSettings;
/**
* Initialise the runtime module.
@@ -61,8 +62,9 @@ var server;
* better abstracted.
* @memberof @node-red/runtime
*/
function init(userSettings,httpServer,_adminApi) {
function init(_userSettings,httpServer,_adminApi) {
server = httpServer;
userSettings = _userSettings
if (server && server.on) {
// Add a listener to the upgrade event so that we can properly timeout connection
@@ -134,7 +136,12 @@ function start() {
.then(function() { return settings.load(storage)})
.then(function() { return library.init(runtime)})
.then(function() {
if (settings.available()) {
if (settings.get('instanceId') === undefined) {
settings.set('instanceId', crypto.randomBytes(8).toString('hex'))
}
userSettings.instanceId = settings.get('instanceId') || ''
}
if (log.metric()) {
runtimeMetricInterval = setInterval(function() {
reportMetrics();
@@ -147,7 +154,7 @@ function start() {
log.info(log._("runtime.version",{component:"Node.js ",version:process.version}));
if (settings.UNSUPPORTED_VERSION) {
log.error("*****************************************************************");
log.error("* "+log._("runtime.unsupported_version",{component:"Node.js",version:process.version,requires: ">=8.9.0"})+" *");
log.error("* "+log._("runtime.unsupported_version",{component:"Node.js",version:process.version,requires: ">=18"})+" *");
log.error("*****************************************************************");
events.emit("runtime-event",{id:"runtime-unsupported-version",payload:{type:"error",text:"notification.errors.unsupportedVersion"},retain:true});
}

View File

@@ -42,6 +42,7 @@ function Node(n) {
this._closeCallbacks = [];
this._inputCallback = null;
this._inputCallbacks = null;
this._expectedDoneCount = 0;
if (n.name) {
this.name = n.name;
@@ -159,6 +160,9 @@ Node.prototype.on = function(event, callback) {
if (event == "close") {
this._closeCallbacks.push(callback);
} else if (event === "input") {
if (callback.length === 3) {
this._expectedDoneCount++
}
if (this._inputCallback) {
this._inputCallbacks = [this._inputCallback, callback];
this._inputCallback = null;
@@ -218,19 +222,17 @@ Node.prototype._emitInput = function(arg) {
} else if (node._inputCallbacks) {
// Multiple callbacks registered. Call each one, tracking eventual completion
var c = node._inputCallbacks.length;
let doneCount = 0
for (var i=0;i<c;i++) {
var cb = node._inputCallbacks[i];
if (cb.length === 2) {
c++;
}
try {
cb.call(
node,
arg,
function() { node.send.apply(node,arguments) },
function(err) {
c--;
if (c === 0) {
doneCount++;
if (doneCount === node._expectedDoneCount) {
node._complete(arg,err);
}
}
@@ -257,6 +259,9 @@ Node.prototype._removeListener = Node.prototype.removeListener;
Node.prototype.removeListener = function(name, listener) {
var index;
if (name === "input") {
if (listener.length === 3) {
this._expectedDoneCount--
}
if (this._inputCallback && this._inputCallback === listener) {
// Removing the only callback
this._inputCallback = null;

View File

@@ -384,10 +384,28 @@ var api = module.exports = {
}
}
} else if (nodeType === "global-config") {
if (JSON.stringify(savedCredentials.map) !== JSON.stringify(newCreds.map)) {
savedCredentials.map = newCreds.map;
dirty = true;
}
savedCredentials.map = savedCredentials.map || {}
const existingCredentialKeys = Object.keys(savedCredentials.map)
const newCredentialKeys = Object.keys(newCreds?.map || [])
existingCredentialKeys.forEach(key => {
if (!newCreds.map?.[key]) {
// This key doesn't exist in the new credentials list - remove
delete savedCredentials.map[key]
delete savedCredentials.map[`has_${key}`]
dirty = true
}
})
newCredentialKeys.forEach(key => {
if (!/^has_/.test(key)) {
if (!savedCredentials.map[key] || newCreds.map[key] !== '__PWRD__') {
// This key either doesn't exist in current saved, or the
// value has been changed
savedCredentials.map[key] = newCreds.map[key]
savedCredentials.map[`has_${key}`] = newCreds.map[`has_${key}`]
dirty = true
}
}
})
} else {
var dashedType = nodeType.replace(/\s+/g, '-');
var definition = credentialsDef[dashedType];

View File

@@ -77,7 +77,7 @@ var storageModuleInterface = {
flows: flows,
credentials: creds
};
result.rev = crypto.createHash('md5').update(JSON.stringify(result.flows)).digest("hex");
result.rev = crypto.createHash('sha256').update(JSON.stringify(result.flows)).digest("hex");
return result;
})
});
@@ -95,7 +95,7 @@ var storageModuleInterface = {
return credentialSavePromise.then(function() {
return storageModule.saveFlows(flows, user).then(function() {
return crypto.createHash('md5').update(JSON.stringify(config.flows)).digest("hex");
return crypto.createHash('sha256').update(JSON.stringify(config.flows)).digest("hex");
})
});
},

View File

@@ -0,0 +1,195 @@
{
"runtime": {
"welcome": "Bienvenid@ a Node-RED",
"version": "__component__ versión: __version__",
"unsupported_version": "Versión no soportada de __component__. Requiere: __requires__ Encontrado: __version__",
"paths": {
"settings": "Fichero de Ajustes : __path__",
"httpStatic": "HTTP Estático : __path__"
}
},
"server": {
"loading": "Cargando paleta de nodos",
"palette-editor": {
"disabled": "Editor de paletas desactivado : ajustes de usuario",
"npm-not-found": "Editor de paletas desactivado : comando npm no encontrado",
"npm-too-old": "Editor de paletas desactivado : versión npm demasiado vieja. Requiere npm >= 3.x"
},
"errors": "Fallo al registrar __count__ tipo de nodo.",
"errors_plural": "Fallo al registrar __count__ tipos de nodo.",
"errors-help": "Ejecutar con -v para más detalles",
"missing-modules": "Faltan módulos de nodos:",
"node-version-mismatch": "El nodo de módulo no puede cargarse en esta versión. Requiere: __version__ ",
"set-has-no-types": "Establece no tiene ningún tipo. nombre: '__name__', módulo: '__module__', fichero: '__file__'",
"type-already-registered": "'__type__' ya registrado por módulo __module__",
"removing-modules": "Eliminando módulos de la configuración",
"added-types": "Tipos de nodos añadidos:",
"removed-types": "Tipos de nodos eliminados:",
"install": {
"invalid": "Nombre de módulo no válido",
"installing": "Instalando módulo: __name__, versión: __version__",
"installed": "Módulo instalado: __name__",
"install-failed": "Error de instalación",
"install-failed-long": "Fallo en la instalación del módulo __name__:",
"install-failed-not-found": "$t(server.install.install-failed-long) módulo no encontrado",
"install-failed-name": "$t(server.install.install-failed-long) nombre de módulo inválido: __name__",
"install-failed-url": "$t(server.install.install-failed-long) URL inválida: __url__",
"post-install-error": "Error ejecutando código 'postInstall':",
"upgrading": "Actualizando módulo: __name__ a la versión: __version__",
"upgraded": "Módulo actualizado: __name__. Reinicia Node-RED para utilizar la nueva versión",
"upgrade-failed-not-found": "$t(server.install.install-failed-long) versión no encontrada",
"uninstalling": "Desinstalando el módulo: __name__",
"uninstall-failed": "Error de desinstalación",
"uninstall-failed-long": "Error en la desinstalación del módulo __name__:",
"uninstalled": "Desinstalando módulo: __name__",
"old-ext-mod-dir-warning": "\n\n---------------------------------------------------------------------\nDirectorio de módulos externos Node-RED 1.3 detectado:\n __oldDir__\nEste directorio ya no se utiliza. Los módulos externos serán reinstalado en tu directorio de usuario Node-RED:__newDir__\nBorra el antiguo directorio externalModules para eliminar este mensaje.\n---------------------------------------------------------------------\n"
},
"deprecatedOption": "__old__ está en DESUSO. Utiliza __new__",
"unable-to-listen": "No se puede escuchar __listenpath__",
"port-in-use": "Error: puerto en uso",
"uncaught-exception": "Excepción no detectada:",
"admin-ui-disabled": "IU de administrador deshabilitado",
"now-running": "El servidor está funcionando en __listenpath__",
"failed-to-start": "No se pudo iniciar el servidor:",
"headless-mode": "Ejecutando en modo sin interfaz",
"httpadminauth-deprecated": "httpAdminAuth está en DESUSO. Utiliza adminAuth",
"https": {
"refresh-interval": "Actualizando la configuración HTTPS cada __interval__ horas",
"settings-refreshed": "La configuración HTTPS del servidor se ha actualizado",
"refresh-failed": "No se pudo actualizar la configuración HTTPS: __message__",
"nodejs-version": "httpsRefreshInterval requiere Node.js 11 o superior",
"function-required": "httpsRefreshInterval requiere que la propiedad HTTPS sea una función"
}
},
"api": {
"flows": {
"error-save": "Error al guardar flujos: __message__",
"error-reload": "Error al recargar flujos: __message__"
},
"library": {
"error-load-entry": "Error al cargar la entrada de la librería '__path__': __message__",
"error-save-entry": "Error al guardar la entrada de la librería '__path__': __message__",
"error-load-flow": "Error al cargar el flujo '__path__': __message__",
"error-save-flow": "Error al guardar el flujo '__path__': __message__"
},
"nodes": {
"enabled": "Tipos de nodo habilitados:",
"disabled": "Tipos de nodo deshabilitados:",
"error-enable": "Fallo al habilitar nodo:"
}
},
"comms": {
"error": "Error del canal de comunicación: __message__",
"error-server": "Error del servidor de comunicación: __message__",
"error-send": "Error de envío de comunicación: __message__"
},
"settings": {
"user-not-available": "No se puede guardar la configuración del usuario: __message__",
"not-available": "Ajustes no disponibles",
"property-read-only": "La propiedad '__prop__' es de sólo lectura",
"readonly-mode": "Ejecución en modo de sólo lectura. Los cambios no se guardarán."
},
"library": {
"unknownLibrary": "Librería desconocida: __library__",
"unknownType": "Tipo de librería desconocida: __type__",
"readOnly": "La librería __library__ es de sólo lectura",
"failedToInit": "Error al inicializar la librería __library__: __error__",
"invalidProperty": "Propiedad inválida __prop__: '__value__'"
},
"nodes": {
"credentials": {
"error": "Error al cargar las credenciales: __message__",
"error-saving": "Error al guardar credenciales: __message__",
"not-registered": "El tipo de credencial '__type__' no está registrado",
"system-key-warning": "\n\n---------------------------------------------------------------------\nTu archivo de credenciales de flujo se cifra utilizando una clave generada por el sistema. Si la clave generada por el sistema se pierde por cualquier motivo, tu archivo de credenciales no será recuperable, tendrás que borrarlo y volver a introducir tus credenciales. Node-RED volverá a cifrar tu archivo de credenciales utilizando la clave elegida la próxima vez que instancias un cambio.\n---------------------------------------------------------------------\n",
"unencrypted": "Usando credenciales no encriptadas",
"encryptedNotFound": "Credenciales encriptadas no encontradas"
},
"flows": {
"safe-mode": "Flujos detenidos en modo seguro. Instancia para iniciar",
"registered-missing": "Falta tipo registrado: __type__",
"error": "Error al cargar flujos: __message__",
"starting-modified-nodes": "Iniciando nodos modificados",
"starting-modified-flows": "Iniciando flujos modificados",
"starting-flows": "Iniciando flujos",
"started-modified-nodes": "Nodos modificados iniciados",
"started-modified-flows": "Flujos modificados iniciados",
"started-flows": "Flujos iniciados",
"stopping-modified-nodes": "Detención de nodos modificados",
"stopping-modified-flows": "Detención de flujos modificados",
"stopping-flows": "Flujos detenidos",
"stopped-modified-nodes": "Nodos modificados detenidos",
"stopped-modified-flows": "Flujos modificados detenidos",
"stopped-flows": "Flujos detenidos",
"stopped": "Detenido",
"stopping-error": "Error al detener el nodo: __message__",
"updated-flows": "Flujos actualizados",
"added-flow": "Añadiendo flujo: __label__",
"updated-flow": "Flujo actualizado: __label__",
"removed-flow": "Flujo eliminado: __label__",
"missing-types": "Esperando a que se registren los tipos que faltan:",
"missing-type-provided": " - __type__ (proporcionado por el módulo npm __module__)",
"missing-type-install-1": "Para instalar cualquiera de estos módulos que faltan, ejecuta:",
"missing-type-install-2": "en el directorio:"
},
"flow": {
"unknown-type": "Tipo desconocido: __type__",
"missing-types": "tipos que faltan",
"error-loop": "El mensaje superó el número máximo de capturas",
"non-message-returned": "El nodo intentó enviar un mensaje del tipo __type__"
},
"index": {
"unrecognised-id": "id no reconocido: __id__",
"type-in-use": "Tipo en uso: __msg__",
"unrecognised-module": "Módulo no reconocido: __module__"
},
"registry": {
"localfilesystem": {
"module-not-found": "No se puede encontrar el módulo '__module__'"
}
}
},
"storage": {
"index": {
"forbidden-flow-name": "nombre de flujo prohibido"
},
"localfilesystem": {
"user-dir": "Directorio de usuario : __path__",
"flows-file": "Archivo de flujos : __path__",
"create": "Creando nuevo archivo __type__",
"empty": "El archivo __type__ existente está vacío",
"invalid": "El archivo __type__ existente no es un JSON válido",
"restore": "Restaurando copia de seguridad de archivo __type__ : __path__",
"restore-fail": "Error al restaurar la copia de seguridad del archivo __type__ : __message__",
"fsync-fail": "Fallo en el volcado del archivo __path__ al disco : __message__",
"warn_name": "Nombre de archivo de flujos indefinido. Generando usando nombre de servidor",
"projects": {
"changing-project": "Configuración del proyecto activo : __project__",
"active-project": "Proyecto activo : __project__",
"projects-directory": "Directorio de proyectos: __projectsDirectory__",
"project-not-found": "Proyecto no encontrado : __project__",
"no-active-project": "No hay proyecto activo: se utiliza el archivo de flujos por defecto",
"disabled": "Proyectos desactivados : editorTheme.projects.enabled=false",
"disabledNoFlag": "Proyectos desactivados : establece editorTheme.projects.enabled=true a habilitado",
"git-not-found": "Proyectos desactivados : comando git no encontrado",
"git-version-old": "Proyectos desactivados : git __version__ no soportada. Requiere 2.x",
"summary": "Un Proyecto Node-RED",
"readme": "### Acerca de\n\nEste es el archivo README.md de tu proyecto. Ayuda a los usuarios a entender qué hace tu proyecto, cómo usarlo y cualquier otra cosa que necesiten saber."
}
}
},
"context": {
"log-store-init": "Almacén de contexto : '__name__' [__info__]",
"error-loading-module": "Error al cargar el almacén de contexto: __message__",
"error-loading-module2": "Error al cargar el almacén de contexto '__module__': __message__",
"error-module-not-defined": "Falta la opción 'module' en el almacén de contexto '__storage__'.",
"error-invalid-module-name": "Nombre de almacén de contexto no válido: '__name__'",
"error-invalid-default-module": "Almacén de contexto por defecto desconocido: '__storage__'",
"unknown-store": "Se ha especificado un almacén de contexto desconocido '__name__'. Usando almacén por defecto.",
"localfilesystem": {
"invalid-json": "JSON no válido en el archivo de contexto '__file__'",
"error-circular": "El contexto __scope__ contiene una referencia circular que no se puede mantener",
"error-write": "Error al escribir el contexto: __message__"
}
}
}

View File

@@ -26,8 +26,8 @@
"removed-types": "Types de noeuds supprimés :",
"install": {
"invalid": "Nom de module invalide",
"installing": "Installation du module : __nom__, version : __version__",
"installed": "Module installé : __nom__",
"installing": "Installation du module : __name__, version : __version__",
"installed": "Module installé : __name__",
"install-failed": "L'installation a échoué",
"install-failed-long": "L'installation du module __name__ a échoué :",
"install-failed-not-found": "Module $t(server.install.install-failed-long) introuvable",
@@ -48,7 +48,7 @@
"port-in-use": "Erreur : port utilisé",
"uncaught-exception": "Exception non reconnue :",
"admin-ui-disabled": "Interface d'administration désactivée",
"now-running": "Le serveur tourne maintenant sur __listenpath__",
"now-running": "Le serveur est disponible à l'adresse __listenpath__",
"failed-to-start": "Échec lors du démarrage du serveur :",
"headless-mode": "Fonctionne en mode sans interface graphique (headless)",
"httpadminauth-deprecated": "L'utilisation de httpAdminAuth est DÉCONSEILLÉE. Utiliser adminAuth à la place",
@@ -100,7 +100,7 @@
"error": "Erreur lors du chargement des identifiants : __message__",
"error-saving": "Erreur lors de l'enregistrement des identifiants : __message__",
"not-registered": "Le type d'identifiant '__type__' n'a pas été enregistré",
"system-key-warning": "\n\n---------------------------------------------------------------------\nVotre fichier contenant les identifiants de flux est chiffré à l'aide d'une clé générée par le système.\n\nSi la clé générée par le système est perdue pour une raison quelconque, votre fichier contenant\nles identifiants ne sera pas récupérable, vous devrez le supprimer et ressaisir vos identifiants.\n\nVous pouvez définir votre propre clé en utilisant l'option 'credentialSecret' dans\nvotre fichier de paramètres. Node-RED rechiffrera alors votre fichier contenant les identifiants\nà l'aide de la clé que vous avez choisie la prochaine fois que vous déploierez une modification.\n---------------------------------------------------------------------\n",
"system-key-warning": "\n\n--------------------------------------------------------------------------------------------------------\nVotre fichier contenant les identifiants de flux est chiffré à l'aide d'une clé générée par le système.\n\nSi la clé générée par le système est perdue pour une raison quelconque, votre fichier contenant\nles identifiants ne sera pas récupérable, vous devrez le supprimer et ressaisir vos identifiants.\n\nVous pouvez définir votre propre clé en utilisant l'option 'credentialSecret' dans\nvotre fichier de paramètres. Node-RED rechiffrera alors votre fichier contenant les identifiants\nà l'aide de la clé que vous avez choisie la prochaine fois que vous déploierez une modification.\n--------------------------------------------------------------------------------------------------------\n",
"unencrypted": "Utilisation d'identifiants non chiffrés",
"encryptedNotFound": "Identifiants chiffrés introuvables"
},

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/runtime",
"version": "4.0.0-dev",
"version": "4.0.0-beta.1",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,8 +16,8 @@
}
],
"dependencies": {
"@node-red/registry": "4.0.0-dev",
"@node-red/util": "4.0.0-dev",
"@node-red/registry": "4.0.0-beta.1",
"@node-red/util": "4.0.0-beta.1",
"async-mutex": "0.4.0",
"clone": "2.1.2",
"express": "4.18.2",