@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.
- package/.github/workflows/publish.yml +54 -0
- package/assets/nodes/io/array-in-demo.gif +0 -0
- package/assets/nodes/io/array-out-demo.gif +0 -0
- package/assets/nodes/io/array-select-demo.gif +0 -0
- package/docs/nodes/io/array-in.md +119 -0
- package/docs/nodes/io/array-out.md +150 -0
- package/docs/nodes/io/array-select.md +157 -0
- package/docs/nodes/io/queue.md +57 -0
- package/docs/nodes/io/save-file.md +30 -0
- package/docs/nodes/promise-reader/promise-reader.md +60 -0
- package/docs/nodes/util/block-detect.md +46 -0
- package/docs/nodes/util/clean-debug.md +58 -0
- package/lib/node-utils.js +429 -0
- package/nodes/io/array-in.html +110 -0
- package/nodes/io/array-in.js +113 -0
- package/nodes/io/array-out.html +125 -0
- package/nodes/io/array-out.js +213 -0
- package/nodes/io/array-select.html +156 -0
- package/nodes/io/array-select.js +187 -0
- package/nodes/io/queue.html +119 -0
- package/nodes/io/queue.js +191 -0
- package/nodes/io/save-file.html +243 -0
- package/nodes/io/save-file.js +440 -0
- package/nodes/promise-reader/promise-reader.html +100 -0
- package/nodes/promise-reader/promise-reader.js +118 -0
- package/nodes/util/block-detect.html +85 -0
- package/nodes/util/block-detect.js +136 -0
- package/nodes/util/clean-debug.html +201 -0
- package/nodes/util/clean-debug.js +393 -0
- package/package.json +55 -0
- package/readme.md +72 -0
|
@@ -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"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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
|
+

|
|
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
|
+

|
|
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
|
+

|
|
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** — raise a warning in the runtime log when flows or custom code keep the event loop busy for too long.
|
|
10
|
+
- **Profiling new nodes** — temporarily add the node next to experimental flows to confirm they remain non-blocking.
|
|
11
|
+
- **Shared environments** — 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 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** — Event loop delay is within the safe range.
|
|
39
|
+
- **Yellow ring** — Recent samples exceeded the threshold but not enough to trigger an alert yet.
|
|
40
|
+
- **Red dot** — 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 ms*, *error at 500 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.
|