@processlink/node-red-contrib-processlink 1.2.0 → 1.2.2

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.
@@ -4,7 +4,10 @@
4
4
  "Bash(git add:*)",
5
5
  "Bash(git commit -m \"$\\(cat <<''EOF''\nAdd folder/area support to upload API\n\n- Add areaId and folderId params to /api/upload endpoint\n- Add API key auth to /api/sites/[siteId]/folders endpoint\n- Add new /api/sites/[siteId]/areas endpoint with API key auth\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
6
6
  "Bash(git commit -m \"$\\(cat <<''EOF''\nAdd location selector for file uploads \\(v1.2.0\\)\n\n- Add Location dropdown showing Area > Folder hierarchy\n- Fetch areas and folders from Files API with API key auth\n- Send areaId and folderId in upload requests\n- Update README documentation\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
7
- "Bash(npm publish:*)"
7
+ "Bash(npm publish:*)",
8
+ "WebFetch(domain:files.processlink.com.au)",
9
+ "Bash(git commit:*)",
10
+ "Bash(npm view:*)"
8
11
  ]
9
12
  }
10
13
  }
package/CLAUDE.md ADDED
@@ -0,0 +1,63 @@
1
+ # CLAUDE.md - AI Assistant Guidelines
2
+
3
+ ## Critical: This is a Published NPM Package
4
+
5
+ This package (`@processlink/node-red-contrib-processlink`) is **published to NPM** and used by real customers in production Node-RED environments. Changes here can break many people's workflows.
6
+
7
+ ### Before Making Any Changes
8
+
9
+ 1. **Understand the impact** - Changes affect all users who update the package
10
+ 2. **Backwards compatibility** - Existing node configurations must continue to work
11
+ 3. **Test thoroughly** - Test in a real Node-RED instance before publishing
12
+ 4. **Version carefully** - Follow semver (patch for fixes, minor for features, major for breaking changes)
13
+
14
+ ### Publishing Checklist
15
+
16
+ Before running `npm publish`:
17
+ - [ ] Test all nodes in Node-RED editor (deploy, configure, run)
18
+ - [ ] Verify existing flows still work after update
19
+ - [ ] Check browser console for JavaScript errors
20
+ - [ ] Test error handling paths
21
+ - [ ] Update version in package.json appropriately
22
+ - [ ] Document changes in commit message
23
+
24
+ ## Architecture Notes
25
+
26
+ ### Node-RED Security Model
27
+
28
+ **Important**: Credentials (API keys, passwords) are stored server-side only and are NEVER accessible from the browser/editor HTML code.
29
+
30
+ - `node.credentials.apiKey` - Only accessible in `.js` files (server-side)
31
+ - `configNode.credentials` - Always `undefined` in `.html` files (client-side)
32
+
33
+ To access credentials from the editor, create an admin HTTP endpoint:
34
+ ```javascript
35
+ // In the .js file
36
+ RED.httpAdmin.get("/your-endpoint/:id", function(req, res) {
37
+ const node = RED.nodes.getNode(req.params.id);
38
+ const apiKey = node.credentials?.apiKey; // Access credentials here
39
+ // Make API calls server-side, return results to client
40
+ });
41
+ ```
42
+
43
+ ### File Structure
44
+
45
+ ```
46
+ nodes/
47
+ config/
48
+ processlink-config.js # Shared credentials config node
49
+ processlink-config.html
50
+ files/
51
+ processlink-files-upload.js # File upload node
52
+ processlink-files-upload.html
53
+ system/
54
+ processlink-system-info.js # System info node
55
+ processlink-system-info.html
56
+ ```
57
+
58
+ ### Node-RED Conventions
59
+
60
+ - Dual outputs: First output for success, second for errors
61
+ - Status indicators: green=success, yellow=processing, red=error
62
+ - Config nodes: Store shared credentials, referenced by other nodes
63
+ - Always use `send` and `done` callbacks for proper async handling
@@ -4,6 +4,8 @@
4
4
  */
5
5
 
6
6
  module.exports = function (RED) {
7
+ const https = require("https");
8
+
7
9
  function ProcessLinkConfigNode(config) {
8
10
  RED.nodes.createNode(this, config);
9
11
  this.name = config.name;
@@ -16,4 +18,95 @@ module.exports = function (RED) {
16
18
  apiKey: { type: "password" },
17
19
  },
18
20
  });
21
+
22
+ // Admin endpoint to fetch locations (areas and folders) for a config node
23
+ RED.httpAdmin.get("/processlink/locations/:id", function (req, res) {
24
+ const configNode = RED.nodes.getNode(req.params.id);
25
+ if (!configNode) {
26
+ return res.status(404).json({ error: "Config node not found" });
27
+ }
28
+
29
+ const siteId = configNode.siteId;
30
+ const apiKey = configNode.credentials?.apiKey;
31
+
32
+ if (!siteId || !apiKey) {
33
+ return res.status(400).json({ error: "Config not ready" });
34
+ }
35
+
36
+ const baseUrl = `/api/sites/${siteId}`;
37
+ const headers = {
38
+ Authorization: `Bearer ${apiKey}`,
39
+ };
40
+
41
+ // Fetch both areas and folders
42
+ let areasData = [];
43
+ let foldersData = [];
44
+ let completed = 0;
45
+ let hasError = false;
46
+
47
+ function checkComplete() {
48
+ completed++;
49
+ if (completed === 2 && !hasError) {
50
+ res.json({ areas: areasData, folders: foldersData });
51
+ }
52
+ }
53
+
54
+ // Fetch areas
55
+ const areasReq = https.request(
56
+ {
57
+ hostname: "files.processlink.com.au",
58
+ path: `${baseUrl}/areas`,
59
+ method: "GET",
60
+ headers: headers,
61
+ },
62
+ (areasRes) => {
63
+ let data = "";
64
+ areasRes.on("data", (chunk) => (data += chunk));
65
+ areasRes.on("end", () => {
66
+ try {
67
+ areasData = JSON.parse(data);
68
+ } catch (e) {
69
+ areasData = [];
70
+ }
71
+ checkComplete();
72
+ });
73
+ }
74
+ );
75
+ areasReq.on("error", () => {
76
+ if (!hasError) {
77
+ hasError = true;
78
+ res.status(500).json({ error: "Failed to fetch areas" });
79
+ }
80
+ });
81
+ areasReq.end();
82
+
83
+ // Fetch folders
84
+ const foldersReq = https.request(
85
+ {
86
+ hostname: "files.processlink.com.au",
87
+ path: `${baseUrl}/folders`,
88
+ method: "GET",
89
+ headers: headers,
90
+ },
91
+ (foldersRes) => {
92
+ let data = "";
93
+ foldersRes.on("data", (chunk) => (data += chunk));
94
+ foldersRes.on("end", () => {
95
+ try {
96
+ foldersData = JSON.parse(data);
97
+ } catch (e) {
98
+ foldersData = [];
99
+ }
100
+ checkComplete();
101
+ });
102
+ }
103
+ );
104
+ foldersReq.on("error", () => {
105
+ if (!hasError) {
106
+ hasError = true;
107
+ res.status(500).json({ error: "Failed to fetch folders" });
108
+ }
109
+ });
110
+ foldersReq.end();
111
+ });
19
112
  };
@@ -46,16 +46,13 @@
46
46
 
47
47
  $location.html('<option value="">Loading...</option>');
48
48
 
49
- var baseUrl = "https://files.processlink.com.au/api/sites/" + configNode.siteId;
50
- var headers = { "Authorization": "Bearer " + configNode.credentials.apiKey };
51
-
52
- // Fetch both areas and folders in parallel
53
- $.when(
54
- $.ajax({ url: baseUrl + "/areas", method: "GET", headers: headers }),
55
- $.ajax({ url: baseUrl + "/folders", method: "GET", headers: headers })
56
- ).done(function (areasResult, foldersResult) {
57
- var areas = areasResult[0] || [];
58
- var folders = foldersResult[0] || [];
49
+ // Fetch locations via server-side endpoint (credentials are not accessible client-side)
50
+ $.ajax({
51
+ url: "processlink/locations/" + configId,
52
+ method: "GET",
53
+ }).done(function (result) {
54
+ var areas = result.areas || [];
55
+ var folders = result.folders || [];
59
56
 
60
57
  // Build current selection key for matching
61
58
  var currentAreaId = node.areaId || "";
@@ -130,7 +127,8 @@
130
127
  $location.html(options);
131
128
  }).fail(function (xhr) {
132
129
  console.error("Failed to load locations:", xhr.responseText);
133
- $location.html('<option value="|">Site root (default)</option><option disabled>-- Failed to load --</option>');
130
+ // Still allow site root if API fails
131
+ $location.html('<option value="|">Site root (default)</option><option disabled>-- Failed to load locations --</option>');
134
132
  });
135
133
  }
136
134
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.2.0",
6
+ "version": "1.2.2",
7
7
  "description": "Node-RED nodes for Process Link platform integration - upload files, send notifications, and connect to industrial automation systems",
8
8
  "keywords": [
9
9
  "node-red",