@rosepetal/node-red-contrib-utils 1.1.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.
@@ -0,0 +1,54 @@
1
+ name: Publish Package
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+ workflow_dispatch:
8
+ inputs:
9
+ publish:
10
+ description: 'Publish to npm'
11
+ required: false
12
+ default: 'false'
13
+ type: boolean
14
+
15
+ env:
16
+ NODE_VERSION: '20'
17
+
18
+ jobs:
19
+ publish:
20
+ runs-on: ubuntu-22.04
21
+ if: ${{ startsWith(github.ref, 'refs/tags/v') || github.event.inputs.publish == 'true' }}
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+
25
+ - name: Setup Node.js
26
+ uses: actions/setup-node@v4
27
+ with:
28
+ node-version: ${{ env.NODE_VERSION }}
29
+ registry-url: 'https://registry.npmjs.org'
30
+
31
+ - name: Determine npm dist-tag
32
+ id: dist-tag
33
+ run: |
34
+ ref_name="${GITHUB_REF_NAME}"
35
+ dist_tag="latest"
36
+ if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
37
+ version="${ref_name#v}"
38
+ if [[ "$version" == *-* ]]; then
39
+ pre="${version#*-}"
40
+ preid="${pre%%[.+]*}"
41
+ if [[ -n "$preid" ]]; then
42
+ dist_tag="$preid"
43
+ fi
44
+ fi
45
+ fi
46
+ echo "tag=$dist_tag" >> "$GITHUB_OUTPUT"
47
+ echo "Using dist-tag: $dist_tag"
48
+
49
+ - name: Publish package
50
+ env:
51
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
52
+ PUBLISH_TAG: ${{ steps.dist-tag.outputs.tag }}
53
+ run: |
54
+ npm publish --access public --tag "$PUBLISH_TAG" || echo "Package may already exist"
@@ -0,0 +1,119 @@
1
+ # Array-In Node
2
+
3
+ ## Purpose & Use Cases
4
+
5
+ The `array-in` node collects data from various sources and tags it with position information for ordered array assembly. It works in partnership with the `array-out` node to create structured arrays from multiple parallel data streams.
6
+
7
+ **Real-World Applications:**
8
+ - **Batch Image Processing**: Collect multiple images for simultaneous processing
9
+ - **Data Aggregation**: Combine results from parallel processing pipelines
10
+ - **Multi-Source Analysis**: Merge data from different sensors or inputs
11
+ - **Synchronized Processing**: Ensure data maintains order through parallel workflows
12
+ - **Multi-Camera Systems**: Collect images from multiple cameras in correct sequence
13
+
14
+ ![Array-In Demo](../../../assets/nodes/io/array-in-demo.gif)
15
+
16
+ ## Input/Output Specification
17
+
18
+ ### Inputs
19
+ - **Input Message**: Message containing data at the configured input path
20
+ - **Dynamic Position**: Array position can be resolved from message properties
21
+
22
+ ### Outputs
23
+ The node adds metadata to the message and mirrors the extracted data into the payload only when reading from `msg.payload`. For other input paths, the existing payload remains untouched while the metadata provides access to the collected value:
24
+
25
+ ```javascript
26
+ {
27
+ ...originalMessage,
28
+ payload: any, // Unchanged unless input is msg.payload; when mirrored matches meta.arrayData
29
+ meta: {
30
+ arrayPosition: number, // Index where this data belongs in array
31
+ arrayData: any // The extracted data from input path
32
+ }
33
+ }
34
+ ```
35
+
36
+ ## Configuration Options
37
+
38
+ ### Input From
39
+ - **Default**: `msg.payload`
40
+ - **Options**:
41
+ - `msg.*` - Read from message property
42
+ - `flow.*` - Read from flow context
43
+ - `global.*` - Read from global context
44
+ - **Purpose**: Specifies where to extract the data to be included in the array
45
+
46
+ ### Array Position
47
+ - **Type**: Number or dynamic reference
48
+ - **Options**:
49
+ - **Fixed Number**: Static position (0, 1, 2, ...)
50
+ - **msg.***: Dynamic position from message property
51
+ - **flow.***: Position from flow context
52
+ - **global.***: Position from global context
53
+ - **Range**: Non-negative integers (0-based indexing)
54
+ - **Purpose**: Determines where this data appears in the final array
55
+
56
+ ## Performance Notes
57
+
58
+ ### Array Assembly Strategy
59
+ - **Position Tagging**: Lightweight metadata addition with minimal processing overhead
60
+ - **Memory Efficient**: Only stores references and position information
61
+ - **Parallel Collection**: Multiple array-in nodes can operate simultaneously
62
+ - **Order Preservation**: Maintains correct data sequence regardless of processing timing
63
+
64
+ ### Status Display
65
+ - **Processing Info**: Shows array position and data type
66
+ - **Validation**: Indicates successful data extraction
67
+ - **Error Handling**: Displays warnings for missing data or invalid positions
68
+
69
+ ## Real-World Examples
70
+
71
+ ### Basic Multi-Image Collection
72
+ ```
73
+ [Image-In: photo1.jpg] → [Array-In: pos=0] ┐
74
+ [Image-In: photo2.jpg] → [Array-In: pos=1] ├→ [Array-Out] → [Resize All]
75
+ [Image-In: photo3.jpg] → [Array-In: pos=2] ┘
76
+ ```
77
+ Collect three images into an ordered array for batch processing.
78
+
79
+ ### Dynamic Position Assignment
80
+ ```
81
+ [Process Data] → [Set msg.index] → [Array-In: pos=msg.index] → [Array-Out]
82
+ ```
83
+ Use dynamic positioning based on processing results.
84
+
85
+ ### Mixed Data Sources
86
+ ```
87
+ [msg.image1] → [Array-In: pos=0] ┐
88
+ [flow.image2] → [Array-In: pos=1] ├→ [Array-Out] → [Concat Images]
89
+ [global.image3] → [Array-In: pos=2] ┘
90
+ ```
91
+ Combine data from different context levels.
92
+
93
+ ### Conditional Assembly
94
+ ```
95
+ [Switch] → [Array-In: pos=flow.nextIndex] → [Array-Out]
96
+ ```
97
+ Dynamic array building based on conditions.
98
+
99
+ ## Common Issues & Troubleshooting
100
+
101
+ ### Position Conflicts
102
+ - **Issue**: Multiple nodes using same position
103
+ - **Solution**: Ensure each array-in node has unique position when feeding same array-out
104
+ - **Best Practice**: Use sequential positions starting from 0
105
+
106
+ ### Missing Data
107
+ - **Issue**: Input path contains no data
108
+ - **Result**: `meta.arrayData` set to `null`
109
+ - **Solution**: Verify data exists at specified input path before processing
110
+
111
+ ### Dynamic Position Errors
112
+ - **Issue**: Position resolves to non-integer or negative value
113
+ - **Solution**: Validate dynamic position sources return valid array indices
114
+ - **Check**: Use debug node to verify position values
115
+
116
+ ### Array Gaps
117
+ - **Issue**: Non-sequential positions create sparse arrays
118
+ - **Result**: Array contains undefined elements at missing positions
119
+ - **Solution**: Use sequential positions or handle sparse arrays in downstream nodes
@@ -0,0 +1,150 @@
1
+ # Array-Out Node
2
+
3
+ ## Purpose & Use Cases
4
+
5
+ The `array-out` node serves as the collection point for multiple `array-in` nodes, assembling ordered arrays from parallel data streams. It provides timeout protection and ensures data integrity during the assembly process.
6
+
7
+ **Real-World Applications:**
8
+ - **Batch Image Processing**: Assemble multiple images for simultaneous operations
9
+ - **Multi-Camera Synchronization**: Collect frames from multiple cameras in sequence
10
+ - **Parallel Pipeline Merging**: Combine results from parallel processing workflows
11
+ - **Data Aggregation**: Merge processed data from multiple sources
12
+ - **Quality Control**: Collect inspection results from multiple checkpoints
13
+
14
+ ![Array-Out Demo](../../../assets/nodes/io/array-out-demo.gif)
15
+
16
+ ## Input/Output Specification
17
+
18
+ ### Inputs
19
+ Messages from `array-in` nodes containing:
20
+ ```javascript
21
+ {
22
+ ...originalMessage,
23
+ payload: any, // Fallback data source
24
+ meta: {
25
+ arrayPosition: number, // Position index (0, 1, 2, ...)
26
+ arrayData: any // Preferred data source (takes priority over payload)
27
+ }
28
+ }
29
+ ```
30
+
31
+ **Data Extraction Priority**: The node prefers `msg.meta.arrayData` but falls back to `msg.payload` if arrayData is undefined.
32
+
33
+ ### Outputs
34
+
35
+ #### Output 1 - Complete Array (Success)
36
+ ```javascript
37
+ [data0, data1, data2, ...] // Ordered array of collected data
38
+ ```
39
+
40
+ #### Output 2 - Timeout Data (Error)
41
+ ```javascript
42
+ {
43
+ [outputPath]: [data0, null, data2, ...], // Partial array in configured location
44
+ meta: {
45
+ timeout: true, // Timeout flag
46
+ missingPositions: [1, 4], // Positions that didn't arrive
47
+ collectedPositions: [0, 2, 3], // Positions that were collected
48
+ expectedCount: 5, // Number expected
49
+ collectedCount: 3, // Number actually collected
50
+ elapsed: 5000 // Time elapsed in milliseconds
51
+ }
52
+ }
53
+ ```
54
+
55
+ ## Configuration Options
56
+
57
+ ### Expected Count
58
+ - **Type**: Number (required)
59
+ - **Range**: Minimum 1
60
+ - **Purpose**: Number of array elements required before output
61
+ - **Validation**: Must match the number of connected array-in nodes
62
+ - **Impact**: Array assembly completes when this many elements are collected
63
+
64
+ ### Timeout
65
+ - **Type**: Number (milliseconds)
66
+ - **Default**: 5000ms (5 seconds)
67
+ - **Range**: Minimum 100ms
68
+ - **Purpose**: Maximum wait time for all elements after first message
69
+ - **Behavior**: Sends partial data to output 2 on timeout
70
+
71
+ ### Output Location
72
+ - **Default**: `msg.payload`
73
+ - **Options**:
74
+ - `msg.*` - Store in message property
75
+ - `flow.*` - Store in flow context
76
+ - `global.*` - Store in global context
77
+ - **Purpose**: Where to store the assembled array
78
+
79
+ ## Performance Notes
80
+
81
+ ### Assembly Strategy
82
+ - **Efficient Collection**: Uses position-based indexing for O(1) insertion
83
+ - **Memory Management**: Minimal overhead during collection
84
+ - **Timeout Protection**: Prevents indefinite waiting for missing data
85
+ - **State Reset**: Automatic cleanup between collection cycles
86
+
87
+ ### Status Display
88
+ - **Collection Progress**: Shows number of items collected vs expected
89
+ - **Success Timing**: Displays total assembly time on completion
90
+ - **Timeout Warning**: Indicates when timeout occurs with diagnostic info
91
+
92
+ ## Real-World Examples
93
+
94
+ ### Basic Image Array Assembly
95
+ ```
96
+ [Image-In: img1.jpg] → [Array-In: pos=0] ┐
97
+ [Image-In: img2.jpg] → [Array-In: pos=1] ├→ [Array-Out: count=3, timeout=500] → [Resize: All Images]
98
+ [Image-In: img3.jpg] → [Array-In: pos=2] ┘
99
+ ```
100
+ Collect three images for batch resizing.
101
+
102
+ ### Multi-Camera Frame Collection
103
+ ```
104
+ [Camera 1] → [Array-In: pos=0] ┐
105
+ [Camera 2] → [Array-In: pos=1] ├→ [Array-Out: count=4, timeout=100] → [Sync Analysis]
106
+ [Camera 3] → [Array-In: pos=2] │
107
+ [Camera 4] → [Array-In: pos=3] ┘
108
+ ```
109
+ Synchronize frames from multiple cameras with tight timing.
110
+
111
+ ### Parallel Processing Merge
112
+ ```
113
+ → [Process A] → [Array-In: pos=0] ┐
114
+ → [Process B] → [Array-In: pos=1] ├→ [Array-Out: count=3, timeout=500] → [Combine Results]
115
+ → [Process C] → [Array-In: pos=2] ┘
116
+ ```
117
+ Merge results from parallel processing pipelines.
118
+
119
+ ### Quality Control Assembly
120
+ ```
121
+ [Inspection A] → [Array-In: pos=0] ┐
122
+ [Inspection B] → [Array-In: pos=1] ├→ [Array-Out: timeout=10000] → [Final Report]
123
+ [Inspection C] → [Array-In: pos=2] ┘
124
+ ```
125
+ Collect quality control results with extended timeout.
126
+
127
+ ## Common Issues & Troubleshooting
128
+
129
+ ### Timeout Issues
130
+ - **Issue**: Frequent timeouts preventing array completion
131
+ - **Causes**: Slow upstream processing, network delays, missing data
132
+ - **Solutions**:
133
+ - Increase timeout value for slow processes
134
+ - Add debug nodes to identify bottlenecks
135
+ - Implement fallback logic using output 2
136
+
137
+ ### Count Mismatch
138
+ - **Issue**: Expected count doesn't match number of array-in nodes
139
+ - **Result**: Perpetual waiting or premature completion
140
+ - **Solution**: Verify expected count equals number of connected array-in nodes
141
+
142
+ ### Position Conflicts
143
+ - **Issue**: Multiple array-in nodes using same position
144
+ - **Result**: Data overwrites, array count confusion
145
+ - **Solution**: Ensure each array-in node has unique position
146
+
147
+ ### Missing Metadata
148
+ - **Issue**: Messages arriving without proper meta.arrayPosition
149
+ - **Result**: Messages ignored, incomplete arrays
150
+ - **Solution**: Verify all input messages come from array-in nodes
@@ -0,0 +1,157 @@
1
+ # Array-Select Node
2
+
3
+ ## Purpose & Use Cases
4
+
5
+ The `array-select` node provides powerful array element selection with Python-like slicing syntax. It extracts specific elements, ranges, or patterns from arrays, making it essential for filtering and selecting processed results.
6
+
7
+ **Real-World Applications:**
8
+ - **Result Filtering**: Select best results from batch processing operations
9
+ - **Data Sampling**: Extract samples from large datasets for analysis
10
+ - **Quality Control**: Pick specific items that passed validation
11
+ - **A/B Testing**: Select specific variants for comparison
12
+ - **Image Gallery Creation**: Choose specific images from collections
13
+
14
+ ![Array-Select Demo](../../../assets/nodes/io/array-select-demo.gif)
15
+
16
+ ## Input/Output Specification
17
+
18
+ ### Inputs
19
+ - **Array Data**: Input array from the configured path
20
+ - **Selection String**: Pattern specifying which elements to extract
21
+
22
+ ### Outputs
23
+ - **Single Element**: Direct element output (unless Force Array enabled)
24
+ - **Multiple Elements**: Always output as array
25
+ - **Invalid Selection**: No message sent, warning logged
26
+
27
+ ## Configuration Options
28
+
29
+ ### Input From
30
+ - **Default**: `msg.payload`
31
+ - **Options**:
32
+ - `msg.*` - Read from message property
33
+ - `flow.*` - Read from flow context
34
+ - `global.*` - Read from global context
35
+ - **Validation**: Input must be an array
36
+
37
+ ### Selection Pattern
38
+ - **Type**: String with flexible syntax
39
+ - **Formats**:
40
+ - **Single Index**: `0`, `2`, `-1`
41
+ - **Multiple Indices**: `1,3,5` (comma-separated)
42
+ - **Range**: `1:4` (slice from index 1 to 3)
43
+ - **Step Pattern**: `0::2` (every 2nd element)
44
+ - **Negative Indexing**: `-1` (last), `-2:` (last two)
45
+
46
+ ### Force Array
47
+ - **Type**: Boolean checkbox
48
+ - **Default**: false
49
+ - **Behavior**: When enabled, single elements output as arrays
50
+ - **Use Case**: Ensure consistent array output format
51
+
52
+ ## Performance Notes
53
+
54
+ ### Selection Efficiency
55
+ - **Minimal Memory Copy**: Efficient element extraction without full array duplication
56
+ - **Index Validation**: Fast bounds checking with graceful error handling
57
+ - **Pattern Parsing**: Optimized pattern recognition and processing
58
+ - **Status Display**: Real-time selection information and processing state
59
+
60
+ ### Error Handling
61
+ - **Input Validation**: Comprehensive array and pattern validation
62
+ - **Graceful Degradation**: Invalid indices skipped with warnings
63
+ - **Bounds Checking**: Out-of-range indices handled safely
64
+
65
+ ## Selection Syntax Guide
66
+
67
+ ### Basic Selection
68
+ ```
69
+ Array: ["A", "B", "C", "D", "E"]
70
+
71
+ 0 → "A" // First element
72
+ -1 → "E" // Last element
73
+ 1,3 → ["B", "D"] // Multiple specific indices
74
+ ```
75
+
76
+ ### Range Selection
77
+ ```
78
+ Array: ["A", "B", "C", "D", "E"]
79
+
80
+ 1:4 → ["B", "C", "D"] // Range from 1 to 3
81
+ 0:3 → ["A", "B", "C"] // First three elements
82
+ -2: → ["D", "E"] // Last two elements
83
+ ```
84
+
85
+ ### Step Patterns
86
+ ```
87
+ Array: ["A", "B", "C", "D", "E", "F"]
88
+
89
+ 0::2 → ["A", "C", "E"] // Every 2nd starting at 0
90
+ 1::2 → ["B", "D", "F"] // Every 2nd starting at 1
91
+ 1:5:2 → ["B", "D"] // Range 1-4, every 2nd
92
+ ```
93
+
94
+ ### Advanced Patterns
95
+ ```
96
+ Array: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
97
+
98
+ ::3 → [0, 3, 6, 9] // Every 3rd element
99
+ 2:8:2 → [2, 4, 6] // Range 2-7, step 2
100
+ -3: → [7, 8, 9] // Last 3 elements
101
+ :-3 → [0, 1, 2, 3, 4, 5, 6] // All but last 3
102
+ ```
103
+
104
+ ## Real-World Examples
105
+
106
+ ### Best Result Selection
107
+ ```
108
+ [Batch Process] → [Array-Out] → [Array-Select: "0,2,4"] → [Top Results]
109
+ ```
110
+ Select 1st, 3rd, and 5th results from batch processing.
111
+
112
+ ### Quality Control Sampling
113
+ ```
114
+ [Production Line] → [Array-Out] → [Array-Select: "::10"] → [Quality Check]
115
+ ```
116
+ Sample every 10th item for quality inspection.
117
+
118
+ ### Image Gallery Creation
119
+ ```
120
+ [Image Array] → [Array-Select: "1:6"] → [Display Gallery]
121
+ ```
122
+ Select images 2-6 for gallery display.
123
+
124
+ ### A/B Test Splitting
125
+ ```
126
+ [User Array] → [Array-Select: "0::2"] → [Group A]
127
+ → [Array-Select: "1::2"] → [Group B]
128
+ ```
129
+ Split users into alternating test groups.
130
+
131
+ ### Last N Results
132
+ ```
133
+ [Processing Queue] → [Array-Out] → [Array-Select: "-5:"] → [Recent Results]
134
+ ```
135
+ Get the last 5 processed items.
136
+
137
+ ## Common Issues & Troubleshooting
138
+
139
+ ### Invalid Input Type
140
+ - **Issue**: Input is not an array
141
+ - **Result**: Warning logged, message not sent
142
+ - **Solution**: Verify input is array type, use array-out to create arrays
143
+
144
+ ### Out of Bounds Indices
145
+ - **Issue**: Selection indices exceed array length
146
+ - **Result**: Invalid indices ignored, partial results returned
147
+ - **Example**: Array length 5, selection "1,3,7" returns elements at indices 1,3 only
148
+
149
+ ### Empty Selection Results
150
+ - **Issue**: Selection pattern matches no elements
151
+ - **Result**: Empty array `[]` output
152
+ - **Common Cause**: Range beyond array bounds
153
+
154
+ ### Syntax Errors
155
+ - **Issue**: Invalid selection pattern syntax
156
+ - **Result**: Warning logged, message not sent
157
+ - **Solution**: Verify pattern follows documented syntax
@@ -0,0 +1,57 @@
1
+ # Queue Node
2
+
3
+ ## Purpose & Use Cases
4
+
5
+ The `queue` node buffers incoming messages, enforces a minimum interval between outputs, and discards stale entries. It helps coordinate bursty producers with slower consumers by smoothing throughput and avoiding overload.
6
+
7
+ **Common Scenarios:**
8
+ - Throttle high-frequency image sources before storage or slow analysis stages
9
+ - Prevent downstream rate limits from being exceeded when batch processing arrays
10
+ - Provide simple back-pressure where only a fixed number of messages can be buffered
11
+ - Drop stale detections or frames that are no longer relevant after a timeout
12
+
13
+ ## Input/Output Specification
14
+
15
+ ### Inputs
16
+ - **Incoming Message**: Any Node-RED message to be enqueued.
17
+
18
+ ### Outputs
19
+ - **Queued Message**: Messages are forwarded in FIFO order while respecting the configured interval.
20
+
21
+ When timeout mode is selected, messages that exceed the configured timeout are silently discarded with a warning in the node's log.
22
+
23
+ ## Configuration Options
24
+
25
+ ### Mode
26
+ - **Type**: Dropdown (`Queue Size Limit` / `Timeout`)
27
+ - **Default**: `Queue Size Limit`
28
+ - **Purpose**: Select whether the node enforces a hard buffer capacity or lets messages expire after a timeout; the controls shown below change depending on the selected mode.
29
+
30
+ ### Queue Size Limit
31
+ - **Type**: Number (integer)
32
+ - **Default**: `0` (no limit)
33
+ - **Purpose**: Available only in queue-size mode. Controls how many messages may be enqueued before excess messages are ignored.
34
+
35
+ ### Timeout (ms)
36
+ - **Type**: Number (integer)
37
+ - **Default**: `0` (no timeout)
38
+ - **Purpose**: Available only in timeout mode. Messages that stay longer than this duration are removed before they reach the output.
39
+
40
+ ### Interval (ms)
41
+ - **Type**: Number (integer)
42
+ - **Default**: `0` (no enforced delay)
43
+ - **Purpose**: Minimum time that must elapse between forwarded messages. When set to 0, messages flow out as soon as they are available.
44
+
45
+ ## Behavior & Status
46
+
47
+ - Messages are processed in first-in-first-out order.
48
+ - The node emits messages immediately when the interval requirement has already been satisfied.
49
+ - If necessary, the node waits the remaining interval before releasing the next message.
50
+ - When messages expire due to timeout (and timeout mode is active) they are removed from the queue and a warning is logged.
51
+ - Node status indicates whether the queue is idle, holding messages, or actively sending.
52
+
53
+ ## Best Practices
54
+
55
+ - Pair with Array nodes to control the rate of batch processing pipelines.
56
+ - Use timeouts to keep sensor readings or camera frames current.
57
+ - Combine with Catch or Status nodes to monitor when the queue reaches capacity or drops messages.
@@ -0,0 +1,30 @@
1
+ # save-file
2
+
3
+ Write incoming data to disk as an image, JSON, text, or binary file. The node can auto-detect the best mode from the payload or a provided filename/extension.
4
+
5
+ ## Inputs
6
+ - **payload** (default): Data to write. Supports raw image objects (`{data,width,height,channels,colorSpace}`), encoded image buffers, plain objects/arrays, strings, or buffers.
7
+ - **Alternative path**: Use the *Input* field to read from any `msg`/`flow`/`global` property.
8
+
9
+ ## Properties
10
+ - **Folder** (*str | env | msg | flow | global*) – Destination directory. Created if missing.
11
+ - **Filename** (*str | msg | flow | global*) – Optional name without path separators. If left blank, a timestamped name is generated. If you include an extension here, it is respected.
12
+ - **File Type** (*auto | image | json | text | binary*) – Force the save mode or let the node decide. Auto uses the extension, raw image structure, or Sharp metadata for buffers.
13
+ - **Image Format** (*jpg | png | webp*) – Encoding for image saves. Quality and PNG optimization are available.
14
+ - **JSON Indent** – Spacing for pretty-printed JSON output.
15
+ - **Overwrite protection** – Enabled by default; adds a numeric suffix when the file already exists.
16
+ - **Result to** – Where to store summary metadata `{ path, filename, type, extension, sizeBytes, format? }` (default `msg.savedFile`).
17
+
18
+ ## Behavior
19
+ - Raw image inputs are validated and encoded with Sharp; BGR/BGRA channels are auto-swapped.
20
+ - JSON inputs are pretty-printed; valid JSON strings are kept as-is.
21
+ - Text mode writes stringified content; binary mode writes buffers directly (or stringified when not a buffer).
22
+ - When overwrite protection is enabled, the node keeps adding `_<n>` until a free filename is found.
23
+
24
+ ## Status
25
+ - Shows the final filename, duration, and whether an overwrite was avoided.
26
+
27
+ ## Example flows
28
+ - Save final inference results as `results.json` in `/data/out`.
29
+ - Persist camera frames as WebP by setting *File Type = image* and *Image Format = webp*.
30
+ - Archive arbitrary payloads by pointing *Input* to `msg.myBuffer` and enabling overwrite protection.
@@ -0,0 +1,60 @@
1
+ # Promise Reader Node
2
+
3
+ ## Purpose & Use Cases
4
+
5
+ The `promise-reader` node resolves an array of promises stored on the message, merges their results into the message, and records simple performance timing. It is useful when upstream nodes perform parallel async work (for example, multiple inference calls) and return promises instead of immediate results.
6
+
7
+ **Typical scenarios:**
8
+ - Collect results from multiple asynchronous HTTP or inference requests
9
+ - Merge parallel processing outputs into one message
10
+ - Aggregate timing data across async tasks
11
+
12
+ ## Input/Output Specification
13
+
14
+ ### Inputs
15
+ - **Promise Array**: An array of promises at the configured message path (default `msg.promises`).
16
+
17
+ ### Outputs
18
+ On success, the node merges resolved values into the original message and removes the promise array:
19
+
20
+ ```javascript
21
+ {
22
+ ...originalMessage,
23
+ // resolved values merged into the message
24
+ resultA: {...},
25
+ resultB: {...},
26
+ performance: {
27
+ "promise-reader": {
28
+ startTime: 1680000000000,
29
+ endTime: 1680000000500,
30
+ milliseconds: 500
31
+ }
32
+ }
33
+ }
34
+ ```
35
+
36
+ If the configured field is missing or not an array, the node warns and passes the message through unchanged.
37
+
38
+ ## Configuration Options
39
+
40
+ ### Field to read
41
+ - **Default**: `promises`
42
+ - **Type**: Message path (dot notation supported)
43
+ - **Purpose**: Location of the promise array (e.g. `inference.promises`).
44
+
45
+ ## Behavior
46
+
47
+ - Validates that the field is an array.
48
+ - Ensures every entry is a promise/thenable; otherwise logs an error and stops.
49
+ - Resolves all promises in parallel using `Promise.all()`.
50
+ - Merges resolved objects into the message. If both sides are plain objects, it deep-merges; otherwise later values overwrite earlier ones.
51
+ - Aggregates timing from any resolved value that contains a `performance` object with `startTime` and `endTime` fields.
52
+ - Deletes the original promise array from the message before sending.
53
+
54
+ If any promise rejects, the node logs a warning and does not send an output message.
55
+
56
+ ## Common Issues & Troubleshooting
57
+
58
+ - **Non-array field**: Ensure `msg.promises` (or your configured path) is an array.
59
+ - **Non-promise entries**: Verify each element is a promise or thenable object.
60
+ - **Rejected promise**: Handle errors upstream or add retries so Promise.all can resolve.
@@ -0,0 +1,46 @@
1
+ # Block Detect Node
2
+
3
+ ## Purpose & Use Cases
4
+
5
+ The `block-detect` node gives you a lightweight watchdog that keeps an eye on Node-RED's event loop. When long running synchronous work or runaway CPU usage blocks the event loop, flows become sluggish, timers fire late, and HTTP endpoints stall. Dropping this node anywhere in your workspace makes it easy to detect those situations without wiring any messages.
6
+
7
+ **Typical scenarios**
8
+
9
+ - **Production health checks** &mdash; raise a warning in the runtime log when flows or custom code keep the event loop busy for too long.
10
+ - **Profiling new nodes** &mdash; temporarily add the node next to experimental flows to confirm they remain non-blocking.
11
+ - **Shared environments** &mdash; monitor collaborative / multi-tenant Node-RED instances for noisy neighbours that block everyone else.
12
+
13
+ ## How It Works
14
+
15
+ - The node samples the Node.js [`monitorEventLoopDelay`](https://nodejs.org/api/perf_hooks.html#perf_hooks_monitor_event_loop_delay_options) histogram every *N* milliseconds (default one second).
16
+ - When the measured delay exceeds the configured threshold for a number of consecutive samples, the node writes an alert to the runtime log (`warn`, `error`, or plain `log`) and changes its editor status to red.
17
+ - If `monitorEventLoopDelay` is unavailable (very old Node.js builds), it falls back to measuring timer drift, which still provides a useful signal with minimal CPU overhead.
18
+ - A cooldown timer prevents log flooding when the system stays blocked for longer periods.
19
+
20
+ ## Configuration
21
+
22
+ | Option | Description |
23
+ |--------|-------------|
24
+ | **Threshold (ms)** | Maximum acceptable event loop delay. Samples above this value count as "blocking". Default: `120 ms`. |
25
+ | **Sample interval (ms)** | How often to collect a measurement. Smaller values react faster but use slightly more CPU. Default: `1000 ms`. |
26
+ | **Consecutive hits** | Number of back-to-back samples that must exceed the threshold before an alert fires. Helps filter out one-off spikes. Default: `1`. |
27
+ | **Cooldown (ms)** | Minimum time between alerts so your logs do not get spammed while a problem persists. Default: `30,000 ms`. |
28
+ | **Show live delay metrics** | When enabled (default) the node's status displays the latest average and max delay so you can watch it in real time. |
29
+
30
+ The node has no inputs or outputs and can sit anywhere in your flow.
31
+
32
+ > The watchdog internally samples `monitorEventLoopDelay` with a medium (20&nbsp;ms) resolution, which provides enough fidelity for alerts while keeping CPU overhead negligible.
33
+
34
+ Alerts are always emitted with `node.warn(...)` so they appear in the standard Node-RED log without additional configuration.
35
+
36
+ ## Interpreting the Status
37
+
38
+ - **Green dot** &mdash; Event loop delay is within the safe range.
39
+ - **Yellow ring** &mdash; Recent samples exceeded the threshold but not enough to trigger an alert yet.
40
+ - **Red dot** &mdash; Blocking detected. Check the runtime log for details about the max/avg delay.
41
+
42
+ ## Tips
43
+
44
+ - Run multiple watchdogs with different thresholds (for example *warn at 120&nbsp;ms*, *error at 500&nbsp;ms*) if you want layered alerting.
45
+ - Pair the node with system level monitoring (CPU, memory) to quickly confirm whether the blocking originated from Node-RED or external processes.
46
+ - Because the watchdog is passive and does not emit messages, it is safe to leave it deployed permanently even in large workspaces.