@kadi.build/file-manager 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -1
- package/package.json +4 -1
- package/src/ConfigManager.js +80 -8
package/README.md
CHANGED
|
@@ -202,7 +202,27 @@ Configuration is loaded from multiple sources (in priority order):
|
|
|
202
202
|
|
|
203
203
|
1. Constructor options
|
|
204
204
|
2. Environment variables (prefixed with `KADI_`)
|
|
205
|
-
3.
|
|
205
|
+
3. `config.yml` file (walks up from CWD — looks for `file-manager:` section)
|
|
206
|
+
4. `.env` file (walks up from CWD — legacy fallback)
|
|
207
|
+
|
|
208
|
+
### config.yml
|
|
209
|
+
|
|
210
|
+
Place a `config.yml` in your project root (or any parent directory):
|
|
211
|
+
|
|
212
|
+
```yaml
|
|
213
|
+
file-manager:
|
|
214
|
+
local_root: ./
|
|
215
|
+
default_upload_directory: ./uploads
|
|
216
|
+
default_download_directory: ./downloads
|
|
217
|
+
default_temp_directory: ./temp
|
|
218
|
+
max_file_size: 1073741824
|
|
219
|
+
watch_debounce_ms: 100
|
|
220
|
+
watch_max_watchers: 10
|
|
221
|
+
compression_format: zip
|
|
222
|
+
compression_level: 6
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Environment Variables (overrides)
|
|
206
226
|
|
|
207
227
|
| Variable | Description | Default |
|
|
208
228
|
|----------|-------------|---------|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kadi.build/file-manager",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Complete local and remote file management with watching and compression",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -38,6 +38,9 @@
|
|
|
38
38
|
"ssh2": "^1.15.0",
|
|
39
39
|
"ssh2-sftp-client": "^9.1.0"
|
|
40
40
|
},
|
|
41
|
+
"optionalDependencies": {
|
|
42
|
+
"js-yaml": "^4.1.0"
|
|
43
|
+
},
|
|
41
44
|
"devDependencies": {
|
|
42
45
|
"fs-extra": "^11.2.0"
|
|
43
46
|
},
|
package/src/ConfigManager.js
CHANGED
|
@@ -3,12 +3,28 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Handles configuration for file operations only.
|
|
5
5
|
* Simplified from the monolith ConfigManager - no tunnel/server config.
|
|
6
|
+
*
|
|
7
|
+
* Configuration resolution order (later wins):
|
|
8
|
+
* 1. Built-in defaults
|
|
9
|
+
* 2. Walk-up config.yml → "file-manager" section
|
|
10
|
+
* 3. Walk-up .env file → fallback when no config.yml found
|
|
11
|
+
* 4. Environment variables (KADI_<KEY> or bare <KEY>)
|
|
12
|
+
* 5. Passed options (constructor/load)
|
|
6
13
|
*/
|
|
7
14
|
|
|
8
15
|
import { promises as fs } from 'fs';
|
|
16
|
+
import { readFileSync, existsSync } from 'fs';
|
|
9
17
|
import path from 'path';
|
|
10
18
|
import os from 'os';
|
|
11
19
|
|
|
20
|
+
let yaml;
|
|
21
|
+
try {
|
|
22
|
+
const m = await import('js-yaml');
|
|
23
|
+
yaml = m.default || m;
|
|
24
|
+
} catch {
|
|
25
|
+
yaml = null;
|
|
26
|
+
}
|
|
27
|
+
|
|
12
28
|
class ConfigManager {
|
|
13
29
|
constructor() {
|
|
14
30
|
this.config = {};
|
|
@@ -72,14 +88,11 @@ class ConfigManager {
|
|
|
72
88
|
// Apply defaults
|
|
73
89
|
this.config = { ...this.defaults };
|
|
74
90
|
|
|
75
|
-
// Load from .
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
} catch (error) {
|
|
81
|
-
// .env file not found, that's fine
|
|
82
|
-
}
|
|
91
|
+
// Load from config.yml (walk-up discovery) — "file-manager" section
|
|
92
|
+
this._loadFromConfigYml();
|
|
93
|
+
|
|
94
|
+
// Load from .env file if it exists (walk-up fallback)
|
|
95
|
+
await this._loadFromEnvFile();
|
|
83
96
|
|
|
84
97
|
// Load from environment variables
|
|
85
98
|
this._loadFromEnvironment();
|
|
@@ -106,6 +119,65 @@ class ConfigManager {
|
|
|
106
119
|
return this;
|
|
107
120
|
}
|
|
108
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Walk up from CWD looking for config.yml and load the "file-manager" section.
|
|
124
|
+
*/
|
|
125
|
+
_loadFromConfigYml() {
|
|
126
|
+
if (!yaml) return;
|
|
127
|
+
|
|
128
|
+
const configPath = this._walkUpFind('config.yml');
|
|
129
|
+
if (!configPath) return;
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
const parsed = yaml.load(readFileSync(configPath, 'utf8'));
|
|
133
|
+
const section = parsed && parsed['file-manager'];
|
|
134
|
+
if (!section || typeof section !== 'object') return;
|
|
135
|
+
|
|
136
|
+
// Map YAML snake_case keys to UPPER_CASE config keys
|
|
137
|
+
for (const [ymlKey, ymlVal] of Object.entries(section)) {
|
|
138
|
+
const upperKey = ymlKey.toUpperCase();
|
|
139
|
+
if (this.defaults.hasOwnProperty(upperKey)) {
|
|
140
|
+
this.config[upperKey] = this._parseValue(String(ymlVal), this.defaults[upperKey]);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
} catch {
|
|
144
|
+
// config.yml parse failure — continue with other sources
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Walk up from CWD looking for a .env file and load it.
|
|
150
|
+
*/
|
|
151
|
+
async _loadFromEnvFile() {
|
|
152
|
+
const envPath = this._walkUpFind('.env');
|
|
153
|
+
if (!envPath) return;
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
const envContent = await fs.readFile(envPath, 'utf8');
|
|
157
|
+
this._parseEnvContent(envContent);
|
|
158
|
+
} catch {
|
|
159
|
+
// .env file not found or unreadable, that's fine
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Walk up from startDir looking for a filename.
|
|
165
|
+
* @param {string} filename
|
|
166
|
+
* @param {string} [startDir]
|
|
167
|
+
* @returns {string|null}
|
|
168
|
+
*/
|
|
169
|
+
_walkUpFind(filename, startDir) {
|
|
170
|
+
let dir = startDir || process.cwd();
|
|
171
|
+
while (true) {
|
|
172
|
+
const candidate = path.join(dir, filename);
|
|
173
|
+
if (existsSync(candidate)) return candidate;
|
|
174
|
+
const parent = path.dirname(dir);
|
|
175
|
+
if (parent === dir) break;
|
|
176
|
+
dir = parent;
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
|
|
109
181
|
_parseEnvContent(content) {
|
|
110
182
|
const lines = content.split('\n');
|
|
111
183
|
for (const line of lines) {
|