node-red-contrib-influxdb3 1.0.8 → 1.1.0
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/README.md +16 -2
- package/influxdb3.html +49 -4
- package/influxdb3.js +101 -13
- package/lib/line-protocol.js +30 -11
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -64,6 +64,18 @@ Writes data points to InfluxDB v3.
|
|
|
64
64
|
- **Name**: Optional node name
|
|
65
65
|
- **Measurement**: Default measurement name (can be overridden by `msg.measurement`)
|
|
66
66
|
- **Database**: Optional database override (uses connection default if not set)
|
|
67
|
+
- **Partial writes**: Accept the valid lines of a batch even if other lines are rejected (InfluxDB 3 Core/Enterprise only)
|
|
68
|
+
- **No sync**: Respond without waiting for WAL persistence — faster writes without durability confirmation (InfluxDB 3 Core/Enterprise only)
|
|
69
|
+
|
|
70
|
+
#### Partial Writes
|
|
71
|
+
|
|
72
|
+
By default a batch write is all-or-nothing: one invalid line causes InfluxDB to reject the entire batch. With **Partial writes** enabled, InfluxDB writes the valid lines and reports the rejected ones. The node then:
|
|
73
|
+
|
|
74
|
+
- shows a yellow `partial write` status instead of an error
|
|
75
|
+
- logs a warning listing each rejected line and the reason
|
|
76
|
+
- forwards the message with the details attached as `msg.partialWriteErrors`, an array of `{ lineNumber, errorMessage, originalLine }` objects
|
|
77
|
+
|
|
78
|
+
Enabling **Partial writes** or **No sync** routes the write through the InfluxDB v3 API endpoint, which is only available on InfluxDB 3 Core and Enterprise. On other deployments (Cloud Serverless/Dedicated, Clustered) leave both options disabled — writes there use the v2-compatible endpoint, where these options are not supported and would cause writes to fail. When **No sync** is enabled without **Partial writes**, the node keeps the all-or-nothing write semantics.
|
|
67
79
|
|
|
68
80
|
## Usage
|
|
69
81
|
|
|
@@ -80,6 +92,8 @@ msg.payload = "temperature,location=room1 value=21.5";
|
|
|
80
92
|
return msg;
|
|
81
93
|
```
|
|
82
94
|
|
|
95
|
+
> **Note:** raw line protocol strings are passed through unmodified (each line is only sanity-checked). When data comes from an untrusted source, prefer the object formats below — the node escapes measurement, tag and field values automatically.
|
|
96
|
+
|
|
83
97
|
#### 2. Object with Fields and Tags
|
|
84
98
|
|
|
85
99
|
Send an object with explicit `fields` and `tags` properties:
|
|
@@ -102,7 +116,7 @@ return msg;
|
|
|
102
116
|
|
|
103
117
|
#### 3. Simplified Object Format
|
|
104
118
|
|
|
105
|
-
Send an object where all properties
|
|
119
|
+
Send an object where all properties are treated as fields, except the reserved keys `measurement`, `fields`, `tags`, `timestamp` and `integers`:
|
|
106
120
|
|
|
107
121
|
```javascript
|
|
108
122
|
msg.measurement = "environment";
|
|
@@ -416,7 +430,7 @@ The node will display error status and log details to the Node-RED debug panel:
|
|
|
416
430
|
|
|
417
431
|
## Requirements
|
|
418
432
|
|
|
419
|
-
- Node.js
|
|
433
|
+
- Node.js v24.0.0 or higher
|
|
420
434
|
- Node-RED v3.0.0 or higher
|
|
421
435
|
- InfluxDB v3 instance (Cloud or Edge)
|
|
422
436
|
|
package/influxdb3.html
CHANGED
|
@@ -6,7 +6,14 @@
|
|
|
6
6
|
category: 'config',
|
|
7
7
|
defaults: {
|
|
8
8
|
name: { value: '' },
|
|
9
|
-
host: {
|
|
9
|
+
host: {
|
|
10
|
+
value: '',
|
|
11
|
+
required: true,
|
|
12
|
+
validate: function(v) {
|
|
13
|
+
// Accept http(s) URLs or Node-RED ${ENV_VAR} substitution
|
|
14
|
+
return /^https?:\/\/\S+$/.test(v) || /\$\{[^}]+\}/.test(v);
|
|
15
|
+
}
|
|
16
|
+
},
|
|
10
17
|
database: { value: '', required: true },
|
|
11
18
|
tlsRejectUnauthorized: { value: true },
|
|
12
19
|
caCertPath: { value: '' }
|
|
@@ -79,7 +86,9 @@
|
|
|
79
86
|
influxdb: { type: 'influxdb3-config', required: true },
|
|
80
87
|
name: { value: '' },
|
|
81
88
|
measurement: { value: '' },
|
|
82
|
-
database: { value: '' }
|
|
89
|
+
database: { value: '' },
|
|
90
|
+
allowPartialWrites: { value: false },
|
|
91
|
+
noSync: { value: false }
|
|
83
92
|
},
|
|
84
93
|
inputs: 1,
|
|
85
94
|
outputs: 1,
|
|
@@ -110,6 +119,16 @@
|
|
|
110
119
|
<label for="node-input-database"><i class="fa fa-database"></i> Database</label>
|
|
111
120
|
<input type="text" id="node-input-database" placeholder="Override default database (optional)">
|
|
112
121
|
</div>
|
|
122
|
+
<div class="form-row">
|
|
123
|
+
<label for="node-input-allowPartialWrites"><i class="fa fa-tasks"></i> Partial writes</label>
|
|
124
|
+
<input type="checkbox" id="node-input-allowPartialWrites" style="width:auto;">
|
|
125
|
+
<span>Allow partial writes (InfluxDB 3 Core/Enterprise only)</span>
|
|
126
|
+
</div>
|
|
127
|
+
<div class="form-row">
|
|
128
|
+
<label for="node-input-noSync"><i class="fa fa-bolt"></i> No sync</label>
|
|
129
|
+
<input type="checkbox" id="node-input-noSync" style="width:auto;">
|
|
130
|
+
<span>Don't wait for WAL persistence (InfluxDB 3 Core/Enterprise only)</span>
|
|
131
|
+
</div>
|
|
113
132
|
</script>
|
|
114
133
|
|
|
115
134
|
<script type="text/html" data-help-name="influxdb3-write">
|
|
@@ -130,13 +149,17 @@
|
|
|
130
149
|
<dt class="optional">database <span class="property-type">string</span></dt>
|
|
131
150
|
<dd>Override the database configured in the node or connection</dd>
|
|
132
151
|
<dt class="optional">timestamp <span class="property-type">Date | number</span></dt>
|
|
133
|
-
<dd>Timestamp for the data point (if not in payload)</dd>
|
|
152
|
+
<dd>Timestamp for the data point (if not in payload). Numbers are interpreted as <b>milliseconds</b> since the epoch</dd>
|
|
134
153
|
</dl>
|
|
135
154
|
|
|
136
155
|
<h3>Outputs</h3>
|
|
137
156
|
<dl class="message-properties">
|
|
138
157
|
<dt>payload <span class="property-type">object</span></dt>
|
|
139
158
|
<dd>The original payload is passed through</dd>
|
|
159
|
+
<dt class="optional">partialWriteErrors <span class="property-type">array</span></dt>
|
|
160
|
+
<dd>Only set when a partial write occurred (see <b>Partial writes</b> below).
|
|
161
|
+
An array of <code>{ lineNumber, errorMessage, originalLine }</code> objects
|
|
162
|
+
describing the lines InfluxDB rejected</dd>
|
|
140
163
|
</dl>
|
|
141
164
|
|
|
142
165
|
<h3>Details</h3>
|
|
@@ -145,6 +168,9 @@
|
|
|
145
168
|
<h4>Line Protocol Format</h4>
|
|
146
169
|
<p>Send a string in line protocol format:</p>
|
|
147
170
|
<pre>msg.payload = "temperature,location=room1 value=21.5";</pre>
|
|
171
|
+
<p><b>Note:</b> raw line protocol strings are passed through unmodified. When data comes from
|
|
172
|
+
an untrusted source, prefer the object format below — the node escapes measurement, tag and
|
|
173
|
+
field values automatically.</p>
|
|
148
174
|
|
|
149
175
|
<h4>Object Format</h4>
|
|
150
176
|
<p>Send an object with fields and optionally tags:</p>
|
|
@@ -161,7 +187,8 @@
|
|
|
161
187
|
}</pre>
|
|
162
188
|
|
|
163
189
|
<h4>Simplified Object Format</h4>
|
|
164
|
-
<p>Send an object where all properties
|
|
190
|
+
<p>Send an object where all properties are treated as fields, except the reserved keys
|
|
191
|
+
<code>measurement</code>, <code>fields</code>, <code>tags</code>, <code>timestamp</code> and <code>integers</code>:</p>
|
|
165
192
|
<pre>{
|
|
166
193
|
"temperature": 21.5,
|
|
167
194
|
"humidity": 65,
|
|
@@ -202,8 +229,26 @@
|
|
|
202
229
|
<dd>The measurement name to use. Can be overridden by <code>msg.measurement</code></dd>
|
|
203
230
|
<dt>Database</dt>
|
|
204
231
|
<dd>Optional database override. If not set, uses the database from the connection config</dd>
|
|
232
|
+
<dt>Partial writes</dt>
|
|
233
|
+
<dd>When enabled, InfluxDB accepts the valid lines of a batch even if other lines
|
|
234
|
+
are rejected (InfluxDB 3 Core/Enterprise only)</dd>
|
|
235
|
+
<dt>No sync</dt>
|
|
236
|
+
<dd>When enabled, InfluxDB responds without waiting for WAL persistence — faster
|
|
237
|
+
writes but no durability confirmation (InfluxDB 3 Core/Enterprise only)</dd>
|
|
205
238
|
</dl>
|
|
206
239
|
|
|
240
|
+
<h3>Partial writes</h3>
|
|
241
|
+
<p>By default a batch write is all-or-nothing: one invalid line causes InfluxDB to
|
|
242
|
+
reject the entire batch. With <b>Partial writes</b> enabled, the valid lines are
|
|
243
|
+
written and the rejected lines are reported: the node shows a yellow
|
|
244
|
+
<i>partial write</i> status, logs a warning with the per-line errors, and forwards
|
|
245
|
+
the message with the details in <code>msg.partialWriteErrors</code>.</p>
|
|
246
|
+
<p>Enabling <b>Partial writes</b> or <b>No sync</b> sends the write through the
|
|
247
|
+
InfluxDB v3 API endpoint, which is only available on InfluxDB 3 Core and
|
|
248
|
+
Enterprise. On other deployments (Cloud Serverless/Dedicated, Clustered) leave
|
|
249
|
+
both options disabled — writes there use the v2-compatible endpoint, where these
|
|
250
|
+
options are not supported.</p>
|
|
251
|
+
|
|
207
252
|
<h3>Examples</h3>
|
|
208
253
|
<h4>Example 1: Simple temperature reading</h4>
|
|
209
254
|
<pre>msg.measurement = "temperature";
|
package/influxdb3.js
CHANGED
|
@@ -12,10 +12,15 @@ module.exports = function(RED) {
|
|
|
12
12
|
// Point.setTag(name, value)
|
|
13
13
|
// Point.setTimestamp(date)
|
|
14
14
|
// Point.toLineProtocol()
|
|
15
|
-
const { InfluxDBClient, Point } = require('@influxdata/influxdb3-client');
|
|
15
|
+
const { InfluxDBClient, Point, PartialWriteError } = require('@influxdata/influxdb3-client');
|
|
16
16
|
const fs = require('fs');
|
|
17
17
|
const { validateLineProtocol } = require('./lib/line-protocol');
|
|
18
18
|
|
|
19
|
+
// Heuristic bounds for plausible millisecond timestamps. Values outside this
|
|
20
|
+
// range usually mean the source supplied seconds or nanoseconds instead.
|
|
21
|
+
const MS_TIMESTAMP_PLAUSIBLE_MIN = Date.UTC(2000, 0, 1);
|
|
22
|
+
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
|
|
23
|
+
|
|
19
24
|
/**
|
|
20
25
|
* Normalize host URL to ensure it has trailing slash
|
|
21
26
|
* @param {string} host
|
|
@@ -150,6 +155,10 @@ module.exports = function(RED) {
|
|
|
150
155
|
this.influxdb = RED.nodes.getNode(config.influxdb);
|
|
151
156
|
this.measurement = config.measurement;
|
|
152
157
|
this.database = config.database;
|
|
158
|
+
/** @type {boolean} */
|
|
159
|
+
this.allowPartialWrites = config.allowPartialWrites === true;
|
|
160
|
+
/** @type {boolean} */
|
|
161
|
+
this.noSync = config.noSync === true;
|
|
153
162
|
|
|
154
163
|
const node = this;
|
|
155
164
|
let statusTimeout = null;
|
|
@@ -220,7 +229,14 @@ module.exports = function(RED) {
|
|
|
220
229
|
if (typeof value === 'string') {
|
|
221
230
|
// Check for integer suffix e.g. "42i"
|
|
222
231
|
if (/^-?\d+i$/.test(value)) {
|
|
223
|
-
|
|
232
|
+
const parsed = parseInt(value.slice(0, -1), 10);
|
|
233
|
+
if (!Number.isSafeInteger(parsed)) {
|
|
234
|
+
node.warn(
|
|
235
|
+
`Field '${key}': integer value '${value}' exceeds JavaScript's safe integer ` +
|
|
236
|
+
`range and loses precision (stored as ${parsed})${context}.`
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
point.setIntegerField(key, parsed);
|
|
224
240
|
return true;
|
|
225
241
|
}
|
|
226
242
|
point.setStringField(key, value);
|
|
@@ -337,8 +353,19 @@ module.exports = function(RED) {
|
|
|
337
353
|
}
|
|
338
354
|
}
|
|
339
355
|
} else {
|
|
340
|
-
|
|
341
|
-
|
|
356
|
+
if (msg.payload.fields !== null && msg.payload.fields !== undefined) {
|
|
357
|
+
const typeName = Array.isArray(msg.payload.fields)
|
|
358
|
+
? 'Array'
|
|
359
|
+
: typeof msg.payload.fields;
|
|
360
|
+
node.warn(
|
|
361
|
+
`'fields' is present but is not a plain object (${typeName}) (measurement: '${measurement}'). ` +
|
|
362
|
+
`It will be ignored and the other payload properties will be treated as fields.`
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
// Simplified format: treat all non-reserved properties as fields.
|
|
366
|
+
// 'measurement' is reserved too so that array items like
|
|
367
|
+
// { measurement: 'temp', value: 1 } don't write it as a string field.
|
|
368
|
+
const reservedKeys = new Set(['measurement', 'tags', 'timestamp', 'integers', 'fields']);
|
|
342
369
|
for (const [key, value] of Object.entries(msg.payload)) {
|
|
343
370
|
if (!reservedKeys.has(key)) {
|
|
344
371
|
if (addFieldToPoint(point, key, value, integerFields, measurement)) {
|
|
@@ -363,7 +390,27 @@ module.exports = function(RED) {
|
|
|
363
390
|
if (ts instanceof Date && !isNaN(ts.getTime())) {
|
|
364
391
|
point.setTimestamp(ts);
|
|
365
392
|
} else if (typeof ts === 'number' && isFinite(ts) && ts >= 0) {
|
|
366
|
-
|
|
393
|
+
const date = new Date(ts);
|
|
394
|
+
if (isNaN(date.getTime())) {
|
|
395
|
+
// Beyond the representable Date range (±8.64e15 ms) — almost
|
|
396
|
+
// always a nanosecond timestamp passed where ms are expected.
|
|
397
|
+
node.warn(
|
|
398
|
+
`Invalid timestamp: ${ts} is outside the representable date range. ` +
|
|
399
|
+
`Numeric timestamps are interpreted as milliseconds - if the source ` +
|
|
400
|
+
`supplies nanoseconds, convert to milliseconds first. The timestamp ` +
|
|
401
|
+
`was ignored; InfluxDB will assign the write time.`
|
|
402
|
+
);
|
|
403
|
+
} else {
|
|
404
|
+
// 0 is deliberately allowed without a warning (explicit epoch).
|
|
405
|
+
if (ts !== 0 && (ts < MS_TIMESTAMP_PLAUSIBLE_MIN || ts > Date.now() + ONE_DAY_MS)) {
|
|
406
|
+
node.warn(
|
|
407
|
+
`Numeric timestamp ${ts} resolves to ${date.toISOString()}. ` +
|
|
408
|
+
`Numeric timestamps are interpreted as milliseconds - if the source ` +
|
|
409
|
+
`supplies seconds or nanoseconds, convert to milliseconds first.`
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
point.setTimestamp(date);
|
|
413
|
+
}
|
|
367
414
|
} else if (typeof ts === 'string' && ts.trim() !== '') {
|
|
368
415
|
const parsed = new Date(ts);
|
|
369
416
|
if (!isNaN(parsed.getTime())) {
|
|
@@ -385,14 +432,7 @@ module.exports = function(RED) {
|
|
|
385
432
|
return { lineProtocol: lp };
|
|
386
433
|
}
|
|
387
434
|
|
|
388
|
-
// Process incoming messages
|
|
389
435
|
node.on('input', async function(msg, send, done) {
|
|
390
|
-
// For Node-RED 0.x compatibility
|
|
391
|
-
send = send || function(m) { node.send(m); };
|
|
392
|
-
done = done || function(err) {
|
|
393
|
-
if (err) { node.error(err, msg); }
|
|
394
|
-
};
|
|
395
|
-
|
|
396
436
|
try {
|
|
397
437
|
const client = node.influxdb.getClient();
|
|
398
438
|
|
|
@@ -480,8 +520,29 @@ module.exports = function(RED) {
|
|
|
480
520
|
);
|
|
481
521
|
}
|
|
482
522
|
|
|
523
|
+
// Both acceptPartial and noSync exist only on the V3 API endpoint,
|
|
524
|
+
// so opting into either selects it. With neither enabled, no write
|
|
525
|
+
// options are passed and the client default (V2 endpoint) is used,
|
|
526
|
+
// preserving previous behaviour.
|
|
527
|
+
let writeOptions = null;
|
|
528
|
+
if (node.allowPartialWrites || node.noSync) {
|
|
529
|
+
writeOptions = { useV2Api: false };
|
|
530
|
+
if (node.noSync) {
|
|
531
|
+
writeOptions.noSync = true;
|
|
532
|
+
}
|
|
533
|
+
if (!node.allowPartialWrites) {
|
|
534
|
+
// noSync without partial writes: keep the all-or-nothing
|
|
535
|
+
// semantics the V2 endpoint would have provided.
|
|
536
|
+
writeOptions.acceptPartial = false;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
483
540
|
// Write to InfluxDB
|
|
484
|
-
|
|
541
|
+
if (writeOptions) {
|
|
542
|
+
await client.write(lineProtocol, targetDatabase, undefined, writeOptions);
|
|
543
|
+
} else {
|
|
544
|
+
await client.write(lineProtocol, targetDatabase);
|
|
545
|
+
}
|
|
485
546
|
|
|
486
547
|
setStatus({ fill: 'green', shape: 'dot', text: 'written' }, 3000);
|
|
487
548
|
|
|
@@ -489,6 +550,33 @@ module.exports = function(RED) {
|
|
|
489
550
|
done();
|
|
490
551
|
|
|
491
552
|
} catch (error) {
|
|
553
|
+
// The client raises PartialWriteError both when the server accepted
|
|
554
|
+
// the valid lines (partial write occurred) and when it rejected the
|
|
555
|
+
// whole batch (acceptPartial=false). Only the former is a partial
|
|
556
|
+
// success; the server signals it with this specific error text.
|
|
557
|
+
if (node.allowPartialWrites &&
|
|
558
|
+
error instanceof PartialWriteError &&
|
|
559
|
+
typeof error.message === 'string' &&
|
|
560
|
+
error.message.toLowerCase().includes('partial write')) {
|
|
561
|
+
const lineErrors = error.lineErrors || [];
|
|
562
|
+
const detail = lineErrors
|
|
563
|
+
.map((le) => `line ${le.lineNumber}: ${le.errorMessage}`)
|
|
564
|
+
.join('; ');
|
|
565
|
+
node.warn(
|
|
566
|
+
`Partial write: InfluxDB rejected ${lineErrors.length} line(s), ` +
|
|
567
|
+
`the remaining lines were written. ${detail}`
|
|
568
|
+
);
|
|
569
|
+
msg.partialWriteErrors = lineErrors;
|
|
570
|
+
setStatus({
|
|
571
|
+
fill: 'yellow',
|
|
572
|
+
shape: 'dot',
|
|
573
|
+
text: `partial write: ${lineErrors.length} line(s) rejected`
|
|
574
|
+
});
|
|
575
|
+
send(msg);
|
|
576
|
+
done();
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
|
|
492
580
|
const shortMsg = error.message
|
|
493
581
|
? (error.message.length > 80 ? error.message.substring(0, 80) + '...' : error.message)
|
|
494
582
|
: 'unknown error';
|
package/lib/line-protocol.js
CHANGED
|
@@ -6,33 +6,52 @@
|
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Truncate a string for use in error messages.
|
|
11
|
+
* @param {string} str
|
|
12
|
+
* @returns {string}
|
|
13
|
+
*/
|
|
14
|
+
function preview(str) {
|
|
15
|
+
return str.length > 100 ? str.substring(0, 100) + '...' : str;
|
|
16
|
+
}
|
|
17
|
+
|
|
9
18
|
/**
|
|
10
19
|
* Validate that a string looks like InfluxDB line protocol.
|
|
20
|
+
* Multi-line strings (multiple points separated by newlines) are validated
|
|
21
|
+
* line by line; blank lines are allowed and skipped.
|
|
11
22
|
* Returns null if valid, or an error message string if invalid.
|
|
12
23
|
* @param {string} lp - Trimmed line protocol string
|
|
13
24
|
* @returns {string|null}
|
|
14
25
|
*/
|
|
15
26
|
function validateLineProtocol(lp) {
|
|
16
|
-
// Detect JSON-like strings (both valid JSON and JS object notation)
|
|
27
|
+
// Detect JSON-like strings (both valid JSON and JS object notation).
|
|
28
|
+
// Checked against the whole string first, because pretty-printed JSON
|
|
29
|
+
// spans multiple lines.
|
|
17
30
|
if (/^\{[\s\S]*}$/.test(lp) || /^\[[\s\S]*]$/.test(lp)) {
|
|
18
|
-
const preview = lp.length > 100 ? lp.substring(0, 100) + '...' : lp;
|
|
19
31
|
return (
|
|
20
32
|
'The payload appears to be a JSON/object string, not line protocol. ' +
|
|
21
33
|
'If you are sending JSON, ensure msg.payload is a parsed object (not a string). ' +
|
|
22
34
|
'Use a JSON parse node before this node to convert the string to an object. ' +
|
|
23
|
-
`Received string: ${preview}`
|
|
35
|
+
`Received string: ${preview(lp)}`
|
|
24
36
|
);
|
|
25
37
|
}
|
|
26
38
|
|
|
27
|
-
//
|
|
39
|
+
// Each line must have at least: measurement field=value
|
|
28
40
|
// i.e. at least one space and one '=' in the field set
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
)
|
|
41
|
+
const lines = lp.split('\n');
|
|
42
|
+
for (let i = 0; i < lines.length; i++) {
|
|
43
|
+
const line = lines[i].trim();
|
|
44
|
+
if (!line) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (!line.includes(' ') || !line.includes('=')) {
|
|
48
|
+
const where = lines.length > 1 ? `Line ${i + 1} of the payload` : 'The payload string';
|
|
49
|
+
return (
|
|
50
|
+
`${where} does not appear to be valid line protocol. ` +
|
|
51
|
+
'Expected format: measurement[,tag=val] field=val[,field=val] [timestamp]. ' +
|
|
52
|
+
`Received: ${preview(line)}`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
36
55
|
}
|
|
37
56
|
|
|
38
57
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-influxdb3",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Node-RED nodes for InfluxDB v3 integration",
|
|
5
5
|
"main": "influxdb3.js",
|
|
6
6
|
"files": [
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"author": "Stuart B",
|
|
26
26
|
"license": "MIT",
|
|
27
27
|
"engines": {
|
|
28
|
-
"node": ">=
|
|
28
|
+
"node": ">=24.0.0"
|
|
29
29
|
},
|
|
30
30
|
"repository": {
|
|
31
31
|
"type": "git",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@influxdata/influxdb3-client": "^2.
|
|
45
|
+
"@influxdata/influxdb3-client": "^2.3.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@eslint/js": "^10.0.1",
|