@inteli.city/node-red-plugin-project-files 1.0.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/CHANGELOG.md ADDED
@@ -0,0 +1,64 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. This project adheres to
4
+ [Semantic Versioning](https://semver.org/).
5
+
6
+ ## [1.1.0] — 2026-06-09
7
+
8
+ Introduced two explicit **operating modes** with distinct, documented filesystem
9
+ boundaries and capabilities.
10
+
11
+ ### Added
12
+ - **Project Mode** — active when a Node-RED project is selected. The active
13
+ project directory is now the authoritative security boundary.
14
+ - **User Directory Mode** — active when Projects are disabled or no project is
15
+ selected. Scope is the Node-RED user directory (`<userDir>`).
16
+ - A **fallback warning bar** shown **only** in User Directory Mode (Project Mode,
17
+ the default, shows no banner so it consumes no file-list space). It states that
18
+ Projects is disabled / no project is active, that the user directory is being
19
+ browsed, and that project-specific tools are unavailable. In Project Mode the
20
+ active project name is shown compactly in the header path (which ellipsizes
21
+ from the left so the project/current folder stays visible in a narrow sidebar).
22
+ - Mode is reported by the `config` and `list` admin endpoints (`mode`,
23
+ `scopeDir`, `projectsEnabled`).
24
+
25
+ ### Changed
26
+ - **Security hardening (Project Mode):** the backend boundary is now the *active
27
+ project* instead of the projects container, so sibling projects and anything
28
+ above the project can no longer be reached, even with crafted paths. The UI
29
+ already locked navigation to the project, so there is **no visible regression**.
30
+ - Dependency/Python routes now always target the **authoritative active project**
31
+ (server-decided), ignoring any client-supplied project name, and return a clear
32
+ "Project Mode only" error in User Directory Mode.
33
+
34
+ ### Migration / behavior change
35
+ - **Only** the *no-active-project* case changes: previously the plugin browsed
36
+ the projects container; it now enters User Directory Mode scoped to `<userDir>`
37
+ and hides the project-only dependency/Python features. **Project Mode
38
+ workflows are unchanged.** No data migration is required.
39
+
40
+ ## [1.0.0] — 2026-06-09
41
+
42
+ First public release as an independent, npm-installable Node-RED plugin.
43
+
44
+ ### Added
45
+ - Public `README.md`, `LICENSE` (MIT), and this changelog.
46
+ - `projectFiles.pythonPath` setting to choose the Python interpreter.
47
+ - Best-effort creation of the scope root (`baseDir`) at startup.
48
+
49
+ ### Changed
50
+ - **Packaging:** removed `private` flag; added npm metadata (license, author,
51
+ repository, keywords, `files` allow-list) so the package can be published and
52
+ installed without copying files manually. All runtime/editor/resource assets
53
+ are included in the published tarball.
54
+ - **Portability:** the Python interpreter (`python3`/`python`), the `pip`
55
+ executable path (POSIX `.venv/bin` and Windows `.venv/Scripts`), and the `npm`
56
+ command (`npm`/`npm.cmd`) are now resolved from `PATH`/platform instead of
57
+ being hard-coded — no hard-coded filesystem assumptions remain.
58
+ - **Security:** error responses are now sanitized and never include absolute
59
+ filesystem paths; the underlying error is logged server-side only.
60
+
61
+ ### Notes
62
+ - Behavior and UI are unchanged from the pre-publication version. There are no
63
+ migrations: your files live in `baseDir`, not in the package, and browser-side
64
+ preferences (word wrap, editor view-state) are preserved.
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or Derivative
95
+ Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and do
117
+ not modify the License. You may add Your own attribution notices
118
+ within Derivative Works that You distribute, alongside or as an
119
+ addendum to the NOTICE text from the Work, provided that such
120
+ additional attribution notices cannot be construed as modifying
121
+ the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,300 @@
1
+ # @inteli.city/node-red-plugin-project-files
2
+
3
+ A Node-RED **sidebar plugin** that adds a *Project Files* tab to the editor for
4
+ browsing and editing the files inside your projects directory — with a built‑in
5
+ code editor (Monaco, with a textarea fallback), drag‑and‑drop upload, per‑project
6
+ Python virtual environments, and project‑local Node package installation.
7
+
8
+ All file and command operations are confined to a single, explicitly defined
9
+ directory tree (the **scope root**). The plugin can never read, write, or execute
10
+ anything outside that tree.
11
+
12
+ ---
13
+
14
+ ## Features
15
+
16
+ - **File browser** in the Node-RED sidebar — navigate folders, sort by name or
17
+ modified time, show/hide dotfiles.
18
+ - **In-editor code editing** with Monaco (syntax highlighting, word wrap) and an
19
+ automatic `<textarea>` fallback when Monaco is unavailable.
20
+ - **File operations** — new file/folder, rename, move (drag a file onto a
21
+ folder), delete, download, copy path.
22
+ - **Drag-and-drop upload** from your computer into the current folder.
23
+ - **Protected files** — Node-RED's own `flows.json`, `flows_cred.json`,
24
+ `package.json`, their `.backup` siblings, and the `.git` directory are
25
+ read-only and cannot be renamed, moved, or deleted from the UI.
26
+ - **Python virtual environments** — create a per-project `.venv` and install a
27
+ `requirements.txt` into it. `.venv/` is auto-added to the project's
28
+ `.gitignore`.
29
+ - **Node packages** — run `npm install` against a project's root `package.json`,
30
+ installing into that project's own `node_modules`.
31
+
32
+ The plugin is designed to complement Node-RED's
33
+ [Projects feature](https://nodered.org/docs/user-guide/projects/) and runs in one
34
+ of two explicit **operating modes** depending on your Node-RED environment (see
35
+ [Operating modes](#operating-modes)).
36
+
37
+ ---
38
+
39
+ ## Requirements
40
+
41
+ | Component | Supported versions |
42
+ | ------------------ | ------------------------------------------------------ |
43
+ | **Node-RED** | `>= 3.0.0` |
44
+ | **Node.js** | `>= 16.0.0` |
45
+ | **Python** *(opt)* | Python 3 on `PATH` (only for the virtual-env features) |
46
+ | **npm** *(opt)* | `npm` on `PATH` (only for Node package install) |
47
+
48
+ Python and npm are **optional** — the file-browser/editor works without them. The
49
+ relevant context-menu actions simply report a clear error if the tool is missing.
50
+
51
+ ---
52
+
53
+ ## Installation
54
+
55
+ Install into an existing Node-RED instance like any other node module.
56
+
57
+ **Using the Node-RED editor** *(recommended)*
58
+ Menu → **Manage palette** → **Install** → search for `@inteli.city/node-red-plugin-project-files`.
59
+
60
+ **Using npm** — from your Node-RED user directory (the one that contains
61
+ `settings.js`, usually `~/.node-red`):
62
+
63
+ ```bash
64
+ cd ~/.node-red
65
+ npm install @inteli.city/node-red-plugin-project-files
66
+ ```
67
+
68
+ Then restart Node-RED. The *Project Files* tab appears in the sidebar
69
+ automatically — there is no manual registration step. The plugin re-loads and
70
+ behaves identically across restarts.
71
+
72
+ > The package ships all of its own assets (runtime, editor HTML, and frontend
73
+ > resources). Nothing needs to be copied manually, and it does not rely on any
74
+ > repository-relative paths.
75
+
76
+ ---
77
+
78
+ ## Configuration
79
+
80
+ All configuration is optional. Add a `projectFiles` block to your Node-RED
81
+ `settings.js`:
82
+
83
+ ```js
84
+ module.exports = {
85
+ // ...existing settings...
86
+
87
+ projectFiles: {
88
+ // Where Node-RED stores projects — used as the Project Mode anchor.
89
+ // Default: <userDir>/projects (the Node-RED Projects directory).
90
+ // (User Directory Mode always uses <userDir> and is not affected by this.)
91
+ baseDir: "/home/user/.node-red/projects",
92
+
93
+ // Maximum size (bytes) for files opened in the editor or saved/uploaded.
94
+ // Default: 50 MiB.
95
+ maxBytes: 50 * 1024 * 1024,
96
+
97
+ // Python interpreter used to create virtual environments.
98
+ // Default: "python3" (or "python" on Windows). Resolved from PATH.
99
+ pythonPath: "python3",
100
+ },
101
+ };
102
+ ```
103
+
104
+ | Setting | Default | Purpose |
105
+ | ------------ | ------------------------------------ | -------------------------------------------------- |
106
+ | `baseDir` | `<userDir>/projects` | Where projects live (Project Mode anchor). |
107
+ | `maxBytes` | `52428800` (50 MiB) | Max size for open/save/upload. |
108
+ | `pythonPath` | `python3` (`python` on Windows) | Interpreter for `python -m venv`. |
109
+
110
+ If `baseDir` does not exist at startup, the plugin attempts to create it
111
+ (non-fatally).
112
+
113
+ ---
114
+
115
+ ## Operating modes
116
+
117
+ The plugin runs in one of **two explicit modes**, chosen automatically from the
118
+ live Node-RED environment and re-evaluated on every request (so switching,
119
+ creating, or closing a project takes effect immediately — no restart).
120
+
121
+ **Project Mode is the primary, default experience and is shown without any
122
+ banner** — a persistent "everything's fine" strip would only waste the limited
123
+ vertical space in the file panel. Instead, the active project name appears
124
+ compactly in the header path (e.g. `…/projects/acme`). A **warning bar appears
125
+ only in the fallback** (User Directory) Mode, where behavior differs from the
126
+ normal project-based workflow. In other words: no news is good news; you only see
127
+ a banner when something is *not* the normal project setup.
128
+
129
+ | | **Project Mode** | **User Directory Mode** |
130
+ | --- | --- | --- |
131
+ | **When** | Node-RED Projects enabled **and** a project is active | Projects disabled, **or** no project is active |
132
+ | **Filesystem boundary** | the active project directory `<projectsDir>/<project>` | the Node-RED user directory `<userDir>` |
133
+ | **Sidebar indicator** | *no banner* — the normal state; the active project name shows compactly in the header path (e.g. `…/projects/acme`) | amber **warning bar**: *“User Directory Mode — …”* |
134
+ | Browse / open / edit / save | ✅ | ✅ |
135
+ | New / rename / move / delete / upload / download | ✅ | ✅ |
136
+ | Protected files (`flows.json`, `flows_cred.json`, `package.json`, `.git`, backups) | ✅ enforced | ✅ enforced |
137
+ | **Python virtual environment** | ✅ create & install into `<project>/.venv` | ❌ unavailable (stated in the UI) |
138
+ | **Node package install** (`npm install`) | ✅ into `<project>/node_modules` | ❌ unavailable (stated in the UI) |
139
+
140
+ Project Mode is the **primary, fully-featured** experience. User Directory Mode
141
+ is a deliberately reduced model — it never pretends a project exists.
142
+
143
+ ### Project Mode
144
+
145
+ Active when Node-RED Projects are enabled and a project is selected. This is the
146
+ **default, fully-featured state and shows no banner**; the active project name is
147
+ visible compactly in the header path. The **active project is the authoritative
148
+ boundary**: you cannot browse, edit, or operate on sibling projects or anything
149
+ above the project, even by crafting paths. All existing project workflows —
150
+ including the Python and Node dependency tools — work exactly as before, at the
151
+ same layout density.
152
+
153
+ > Example: with active project `acme`, the scope is
154
+ > `~/.node-red/projects/acme`. Creating a Python env makes
155
+ > `~/.node-red/projects/acme/.venv`; *Install Node libraries* runs `npm install`
156
+ > in `~/.node-red/projects/acme`.
157
+
158
+ ### User Directory Mode
159
+
160
+ Active when Projects are **disabled**, or enabled but **no project is selected**.
161
+ The scope is the **Node-RED user directory** (`<userDir>`, e.g. `~/.node-red`).
162
+ A noticeable (but non-disruptive) **amber warning bar appears at the top of the
163
+ file panel — only in this mode** — making it explicit that you are *not* inside a
164
+ project. It states that Projects is disabled / no project is active, that the
165
+ plugin is now browsing the Node-RED user directory, and that some
166
+ project-specific features are unavailable. The plugin never falls back to this
167
+ mode silently.
168
+
169
+ - **File browsing and editing are fully available** within `<userDir>`.
170
+ - **Dependency management and Python environments are unavailable.** They are
171
+ inherently project-scoped (a `.venv`/`node_modules` needs a project home that
172
+ is git-ignored and deployable). Rather than guess a location or simulate a
173
+ project, the plugin disables them and says so in the UI. To use them, enable
174
+ Node-RED Projects and open a project.
175
+ - **Heads-up:** `<userDir>` contains Node-RED's own configuration
176
+ (`settings.js`, `.config.*.json`, `flows.json`, …). `flows.json`,
177
+ `flows_cred.json`, `package.json`, and `.git` are protected from
178
+ rename/move/delete and the flow files open read-only, but other config files
179
+ are browsable and editable. If that is not desirable for your deployment,
180
+ enable Projects (to get Project Mode) or restrict editor access via
181
+ `adminAuth`.
182
+
183
+ > Example: with no active project and a default install, the scope is
184
+ > `~/.node-red`. You can edit `~/.node-red/settings.js` or browse
185
+ > `~/.node-red/projects/`, but the *Create Python environment* / *Install*
186
+ > actions do not appear.
187
+
188
+ ---
189
+
190
+ ## Scope model & security
191
+
192
+ Each mode has **exactly one** authoritative filesystem boundary (see the table
193
+ above). The rules below are enforced **identically across every operation** —
194
+ browse, edit, upload, download, rename, move, delete, dependency install, and
195
+ Python-environment operations:
196
+
197
+ - **Every** operation resolves its target against the active boundary and is
198
+ rejected if it falls outside it. There is no operation that uses a different
199
+ or wider boundary.
200
+ - **Path traversal is prevented.** Inputs are normalized and `../` sequences
201
+ cannot escape the boundary; sibling directories that merely share a name
202
+ prefix (e.g. `acme` vs `acme-evil`) are also rejected. In Project Mode this
203
+ includes other projects.
204
+ - **External commands run inside the boundary.** `python -m venv`,
205
+ `pip install`, and `npm install` only run in Project Mode, always with their
206
+ working directory set to the **active project**, writing only to
207
+ `<project>/.venv` and `<project>/node_modules`. A client cannot redirect them
208
+ to another project — the server uses the authoritative active project, not any
209
+ client-supplied name.
210
+ - **Protected files are immutable from the UI.** `flows.json`,
211
+ `flows_cred.json`, `package.json`, their `.backup` siblings, and `.git` cannot
212
+ be renamed, moved, or deleted; `flows*.json` and their backups are opened
213
+ read-only.
214
+ - **Errors are sanitized.** HTTP responses never include absolute filesystem
215
+ paths; the underlying error is logged server-side only. (Output from
216
+ `pip`/`npm` is still surfaced to you, since you need it to diagnose dependency
217
+ problems, and it is confined to your own project.)
218
+ - **Fails safe.** Invalid, missing, or out-of-scope paths return a clear error
219
+ rather than performing a partial or unsafe operation.
220
+
221
+ ### Authentication & authorization
222
+
223
+ All backend endpoints are registered on Node-RED's admin API and respect your
224
+ Node-RED security settings. When `adminAuth` is enabled, requests must be
225
+ authenticated, and the plugin enforces two permissions:
226
+
227
+ | Action | Required permission |
228
+ | --------------------------------------------------- | ----------------------- |
229
+ | Browse, open, stat, download | `projectFiles.read` |
230
+ | Create, save, rename, move, delete, upload, install | `projectFiles.write` |
231
+
232
+ These are satisfied by Node-RED's standard `read`/`write` permission scopes, so
233
+ a user with `*` or `write` permission has full access and a `read`-only user has
234
+ view-only access. With `adminAuth` **disabled** (the default for local
235
+ development), the editor has full access, exactly as Node-RED does itself.
236
+
237
+ > **Operational note:** users who can write files and trigger `pip`/`npm`
238
+ > install effectively can cause code to be written into your projects directory.
239
+ > Grant `projectFiles.write` only to trusted editor users, the same way you
240
+ > would protect deploy/admin access in Node-RED.
241
+
242
+ ---
243
+
244
+ ## Usage
245
+
246
+ 1. Open the Node-RED editor and select the **Project Files** tab in the sidebar.
247
+ 2. Browse the tree on the left; click a file to open it in the editor on the
248
+ right. `Ctrl/Cmd+S` saves.
249
+ 3. Right-click a file or folder for **rename / move / delete / download / copy
250
+ path** and the install actions.
251
+ 4. Drag files from your computer onto the tree to **upload** them into the
252
+ current folder. Drag a row onto a folder to **move** it.
253
+ 5. **Python:** with a project active, use the **Python environment** bar to
254
+ *Create* a `.venv`, then right-click a `requirements.txt` → *Install Python
255
+ libraries*.
256
+ 6. **Node:** right-click a project's root `package.json` → *Install Node
257
+ libraries* to run `npm install` for that project.
258
+
259
+ ---
260
+
261
+ ## Limitations & known caveats
262
+
263
+ - **Text editor only.** Files are opened as UTF‑8 text; binary files are not
264
+ editable in the editor (they can still be uploaded, moved, downloaded, and
265
+ deleted).
266
+ - **Symlinks.** The scope check is path-based. A symlink *inside* the scope root
267
+ that points outside it would be followed by the OS on read/write. Do not place
268
+ untrusted symlinks inside the scope root. (See *Deferred improvements*.)
269
+ - **Single boundary per mode.** The plugin manages one tree at a time (the
270
+ active project, or the user directory); it is not a general, multi-root
271
+ filesystem browser. Dependency/Python tools exist only in Project Mode.
272
+ - **Windows venv/Node.** Paths for `pip` are handled for both POSIX
273
+ (`.venv/bin`) and Windows (`.venv/Scripts`), but the venv/Node features are
274
+ primarily exercised on Linux.
275
+ - **Concurrent edits.** If a file changes on disk while open, the editor shows a
276
+ *"changed on disk"* status; saving overwrites with the editor's content (last
277
+ write wins). No automatic merge is performed.
278
+ - **Default sidebar tab.** On first load the plugin focuses its own sidebar tab.
279
+
280
+ ---
281
+
282
+ ## Upgrading
283
+
284
+ Your data lives in your projects/user directory, **not** inside the package, so
285
+ upgrading (`npm update @inteli.city/node-red-plugin-project-files`) never touches your files.
286
+ Word-wrap and editor view-state preferences are stored in the browser's
287
+ `localStorage` and are likewise preserved.
288
+
289
+ **Upgrading to 1.1 (operating modes).** Project Mode behaves exactly as before —
290
+ no migration, no regression. The only behavior change is for the case where **no
291
+ project is active**: previously the plugin browsed the projects *container*;
292
+ it now enters **User Directory Mode** scoped to `<userDir>` and disables the
293
+ project-only dependency/Python tools (clearly indicated in the UI). Project-Mode
294
+ users are unaffected. See [CHANGELOG.md](./CHANGELOG.md) for details.
295
+
296
+ ---
297
+
298
+ ## License
299
+
300
+ [MIT](./LICENSE)
@@ -0,0 +1,7 @@
1
+ <!-- Project Files sidebar plugin — loads frontend modules in dependency order -->
2
+ <script src="resources/@inteli.city/node-red-plugin-project-files/project-files/style.js"></script>
3
+ <script src="resources/@inteli.city/node-red-plugin-project-files/project-files/prefs.js"></script>
4
+ <script src="resources/@inteli.city/node-red-plugin-project-files/project-files/admin-ajax.js"></script>
5
+ <script src="resources/@inteli.city/node-red-plugin-project-files/project-files/rules.js"></script>
6
+ <script src="resources/@inteli.city/node-red-plugin-project-files/project-files/dialogs.js"></script>
7
+ <script src="resources/@inteli.city/node-red-plugin-project-files/project-files/plugin.js"></script>
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@inteli.city/node-red-plugin-project-files",
3
+ "version": "1.0.0",
4
+ "description": "Node-RED sidebar plugin to browse and edit project files, manage Python virtual environments, and install Node packages — scoped safely to your projects directory.",
5
+ "keywords": [
6
+ "node-red",
7
+ "node-red-plugin",
8
+ "sidebar",
9
+ "files",
10
+ "file-browser",
11
+ "editor",
12
+ "monaco",
13
+ "projects"
14
+ ],
15
+ "license": "Apache-2.0",
16
+ "main": "runtime/admin.js",
17
+ "files": [
18
+ "runtime/",
19
+ "editor/",
20
+ "resources/",
21
+ "README.md",
22
+ "CHANGELOG.md",
23
+ "LICENSE"
24
+ ],
25
+ "node-red": {
26
+ "version": ">=3.0.0",
27
+ "plugins": {
28
+ "project-files": "editor/project-files.html"
29
+ },
30
+ "nodes": {
31
+ "project-files-admin": "runtime/admin.js"
32
+ }
33
+ },
34
+ "engines": {
35
+ "node": ">=16.0.0"
36
+ },
37
+ "scripts": {
38
+ "test": "node --check runtime/admin.js && node --check resources/project-files/plugin.js && echo \"syntax OK\""
39
+ }
40
+ }
@@ -0,0 +1,12 @@
1
+ // Thin wrapper around $.ajax that adds the Node-RED auth headers required by
2
+ // all httpAdmin endpoints when adminAuth is enabled.
3
+ function dsffAjax(method, url, data) {
4
+ return $.ajax({
5
+ method,
6
+ url,
7
+ data: data ? JSON.stringify(data) : undefined,
8
+ contentType: data ? "application/json" : undefined,
9
+ headers: { "Node-RED-API-Version": "v2" },
10
+ xhrFields: { withCredentials: true },
11
+ });
12
+ }