d-drive-cli 2.2.2 → 2.2.3
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 +231 -26
- package/dist/commands/config.js +2 -2
- package/dist/commands/delete.js +4 -0
- package/dist/commands/download.js +2 -0
- package/dist/commands/list.js +12 -3
- package/dist/index.js +2 -2
- package/package.json +8 -8
- package/src/commands/config.ts +2 -2
- package/src/commands/delete.ts +5 -0
- package/src/commands/download.ts +2 -0
- package/src/commands/list.ts +14 -3
- package/src/index.ts +2 -2
package/README.md
CHANGED
|
@@ -70,7 +70,7 @@ drive config -l
|
|
|
70
70
|
#### Upload
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
-
# Upload single file
|
|
73
|
+
# Upload single file (encrypted by default)
|
|
74
74
|
drive upload ./file.txt
|
|
75
75
|
|
|
76
76
|
# Upload to specific folder
|
|
@@ -78,21 +78,22 @@ drive upload ./file.txt /backups/
|
|
|
78
78
|
|
|
79
79
|
# Upload directory recursively
|
|
80
80
|
drive upload ./myproject /backups/ -r
|
|
81
|
-
|
|
82
|
-
# Upload with encryption
|
|
83
|
-
drive upload ./sensitive.txt -e
|
|
84
81
|
```
|
|
85
82
|
|
|
83
|
+
> **Note:** All CLI uploads are **encrypted by default** for security. Files are encrypted server-side using AES-256-GCM encryption before storage.
|
|
84
|
+
|
|
86
85
|
#### Download
|
|
87
86
|
|
|
88
87
|
```bash
|
|
89
|
-
# Download file
|
|
88
|
+
# Download file (automatically decrypted)
|
|
90
89
|
drive download /backups/file.txt
|
|
91
90
|
|
|
92
91
|
# Download to specific location
|
|
93
92
|
drive download /backups/file.txt ./local-file.txt
|
|
94
93
|
```
|
|
95
94
|
|
|
95
|
+
> **Note:** Encrypted files are automatically decrypted during download.
|
|
96
|
+
|
|
96
97
|
#### List
|
|
97
98
|
|
|
98
99
|
```bash
|
|
@@ -108,15 +109,14 @@ drive ls /backups -l
|
|
|
108
109
|
```
|
|
109
110
|
|
|
110
111
|
#### Delete
|
|
111
|
-
|
|
112
|
-
```bash
|
|
113
|
-
# Delete file (with confirmation)
|
|
112
|
+
, moves to recycle bin)
|
|
114
113
|
drive rm /old-file.txt
|
|
115
114
|
|
|
116
115
|
# Force delete without confirmation
|
|
117
116
|
drive rm /old-file.txt -f
|
|
117
|
+
```
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
> **Note:** Deleted files are moved to the recycle bin and can be restored via the web interface. The `-r` flag is accepted but directory deletion operates the same way (moves entire directory to recycle bin).elete directory recursively
|
|
120
120
|
drive rm /old-folder -r
|
|
121
121
|
```
|
|
122
122
|
|
|
@@ -129,26 +129,45 @@ drive cp /backups/file.txt
|
|
|
129
129
|
```
|
|
130
130
|
|
|
131
131
|
### Task Management
|
|
132
|
-
|
|
133
|
-
D-Drive supports SFTP backup tasks that can be managed via CLI.
|
|
132
|
+
Tasks run on a schedule (cron) to automatically backup files from remote SFTP servers.
|
|
134
133
|
|
|
135
134
|
```bash
|
|
136
|
-
# List all tasks
|
|
135
|
+
# List all tasks with status
|
|
137
136
|
drive tasks ls
|
|
138
137
|
|
|
139
|
-
# Run a task immediately
|
|
138
|
+
# Run a task immediately (ignores schedule)
|
|
140
139
|
drive tasks run <task-id>
|
|
141
140
|
|
|
142
141
|
# Stop a running task
|
|
143
142
|
drive tasks stop <task-id>
|
|
144
143
|
|
|
145
|
-
# Enable
|
|
144
|
+
# Enable a task (allows scheduled runs)
|
|
146
145
|
drive tasks enable <task-id>
|
|
146
|
+
|
|
147
|
+
# Disable a task (prevents scheduled runs)
|
|
147
148
|
drive tasks disable <task-id>
|
|
148
149
|
|
|
149
|
-
# Delete a task
|
|
150
|
+
# Delete a task (with confirmation)
|
|
150
151
|
drive tasks rm <task-id>
|
|
151
|
-
|
|
152
|
+
|
|
153
|
+
# Force delete without confirmation
|
|
154
|
+
drive tasks rm <task-id> -f
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Task List Output:**
|
|
158
|
+
```
|
|
159
|
+
📋 SFTP Backup Tasks:
|
|
160
|
+
────────────────────────────────────────────────────────
|
|
161
|
+
ID: clmxyz123...
|
|
162
|
+
Name: Daily Backup
|
|
163
|
+
Status: ✓ Running (5m 23s) | ⏸ Stopped | ✓ Enabled
|
|
164
|
+
Schedule: 0 2 * * * (daily at 2:00 AM)
|
|
165
|
+
SFTP: user@server.example.com:22 → /backups/
|
|
166
|
+
Compression: GZIP | Keep: 5 files
|
|
167
|
+
────────────────────────────────────────────────────────
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
> **Note:** Tasks can only be created/edited via the web interface. The CLI allows management and execution only.ve tasks rm <task-id> -f # Force delete
|
|
152
171
|
```
|
|
153
172
|
|
|
154
173
|
### Info & Status
|
|
@@ -194,10 +213,10 @@ Interactive mode provides a menu-driven interface for all operations.
|
|
|
194
213
|
### Backup a Project
|
|
195
214
|
|
|
196
215
|
```bash
|
|
197
|
-
# Create
|
|
216
|
+
# Create an encrypted backup of your project
|
|
198
217
|
drive upload ./my-project /backups/my-project/ -r
|
|
199
218
|
|
|
200
|
-
# List backups
|
|
219
|
+
# List backups with details
|
|
201
220
|
drive ls /backups/my-project -l
|
|
202
221
|
```
|
|
203
222
|
|
|
@@ -205,29 +224,207 @@ drive ls /backups/my-project -l
|
|
|
205
224
|
|
|
206
225
|
```bash
|
|
207
226
|
#!/bin/bash
|
|
208
|
-
# backup.sh
|
|
227
|
+
# backup.sh - Daily project backup
|
|
209
228
|
|
|
210
229
|
DATE=$(date +%Y-%m-%d)
|
|
211
|
-
|
|
212
|
-
|
|
230
|
+
PROJECT_NAME="my-app"
|
|
231
|
+
|
|
232
|
+
echo "Starting backup for $PROJECT_NAME on $DATE..."
|
|
233
|
+
|
|
234
|
+
# Upload with automatic encryption
|
|
235
|
+
drive upload ./ "/backups/$PROJECT_NAME/$DATE/" -r
|
|
236
|
+
|
|
237
|
+
if [ $? -eq 0 ]; then
|
|
238
|
+
echo "✓ Backup completed successfully: $DATE"
|
|
239
|
+
|
|
240
|
+
# List to verify
|
|
241
|
+
drive ls "/backups/$PROJECT_NAME/" -l
|
|
242
|
+
else
|
|
243
|
+
echo "✗ Backup failed!"
|
|
244
|
+
exit 1
|
|
245
|
+
fi
|
|
246
|
+
```configure the CLI using environment variables instead of `drive config`:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
# Set in your shell profile (~/.bashrc, ~/.zshrc, etc.)
|
|
250
|
+
export DDRIVE_API_KEY=dd_your_api_key_here
|
|
251
|
+
export DDRIVE_API_URL=https://your-server/api
|
|
252
|
+
|
|
253
|
+
# Or use inline for single commands
|
|
254
|
+
DDRIVE_API_KEY=dd_key123 drive ls /
|
|
213
255
|
```
|
|
214
256
|
|
|
215
|
-
|
|
257
|
+
**Variables:**
|
|
258
|
+
- `DDRIVE_API_KEY` - Your D-Drive API key (starts with `dd_`)
|
|
259
|
+
- `DDRIVE_API_URL` - API base URL (default: `https://localhost/api`)
|
|
260
|
+
|
|
261
|
+
**Priority:**
|
|
262
|
+
1. Environment variables (highest)
|
|
263
|
+
2. Config file (`~/.ddrive-cli-config`)
|
|
264
|
+
3. Default values (lowest)
|
|
216
265
|
|
|
266
|
+
**View current configuration:**
|
|
217
267
|
```bash
|
|
268
|
+
drive config --list
|
|
269
|
+
# List available backups
|
|
270
|
+
drive ls /backups/ -l
|
|
271
|
+
|
|
218
272
|
# Download latest backup
|
|
219
273
|
drive download /backups/2026-01-24/data.tar.gz ./restore/
|
|
220
274
|
|
|
221
275
|
# Extract
|
|
222
|
-
tar -xzf ./restore/data.tar.gz
|
|
276
|
+
tar -xzf ./restore/data.tar.gz -C ./restore/
|
|
277
|
+
|
|
278
|
+
echo "Restore complete!"
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Monitor Task Status
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
#!/bin/bash
|
|
285
|
+
# check-tasks.sh - Monitor backup task status
|
|
286
|
+
|
|
287
|
+
echo "Checking SFTP backup tasks..."
|
|
288
|
+
drive tasks ls
|
|
289
|
+
|
|
290
|
+
# Run a specific task
|
|
291
|
+
TASK_ID="clmxyz123..."
|
|
292
|
+
echo "Running task $TASK_ID..."
|
|
293
|
+
drive tasks run $TASK_ID
|
|
294
|
+
**Causes:**
|
|
295
|
+
- Server is not running
|
|
296
|
+
- Incorrect API URL
|
|
297
|
+
- Network/firewall issues
|
|
298
|
+
- SSL/TLS certificate problems
|
|
299
|
+
|
|
300
|
+
**Solutions:**
|
|
301
|
+
```bash
|
|
302
|
+
# Check your configuration
|
|
303
|
+
drive config --list
|
|
304
|
+
|
|
305
|
+
# Test with correct URL (include /api path)
|
|
306
|
+
drive config --url https://your-server/api
|
|
307
|
+
|
|
308
|
+
# Verify server is accessible
|
|
309
|
+
curl https://your-server/api/setup/status
|
|
310
|
+
|
|
311
|
+
# For local development with self-signed certs
|
|
312
|
+
export NODE_TLS_REJECT_UNAUTHORIZED=0 # Not recommended for production!
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### "Invalid API key"
|
|
316
|
+
**Causes:**
|
|
317
|
+
- API key is incorrect or expired
|
|
318
|
+
- Missing `dd_` prefix
|
|
319
|
+
- Extra spaces or characters
|
|
320
|
+
|
|
321
|
+
**Solutions:**
|
|
322
|
+
```bash
|
|
323
|
+
# Generate a new API key:
|
|
324
|
+
# 1. Open D-Drive web interface
|
|
325
|
+
# 2. Go to Settings → API Keys
|
|
326
|
+
# 3. Click "Create API Key"
|
|
327
|
+
# 4. Copy the full key (including dd_ prefix)
|
|
328
|
+
|
|
329
|
+
# Configure with new key
|
|
330
|
+
drive config --key dd_your_new_key_here
|
|
331
|
+
|
|
332
|
+
# Verify it works
|
|
333
|
+
drive info
|
|
223
334
|
```
|
|
224
335
|
|
|
225
|
-
|
|
336
|
+
### "Permission denied"
|
|
337
|
+
**Causes:**
|
|
338
|
+
- Using wrong account/API key
|
|
339
|
+
- File/folder doesn't belong to you
|
|
340
|
+
- Insufficient permissions
|
|
341
|
+
|
|
342
|
+
**Solutions:**
|
|
343
|
+
```bash
|
|
344
|
+
# Check which user you're authenticated as
|
|
345
|
+
drive info
|
|
346
|
+
|
|
347
|
+
# Ensure you're using the correct API key
|
|
348
|
+
drive config --list
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### "File not found" when listing nested folders
|
|
352
|
+
**Causes:**
|
|
353
|
+
- Folder path typo
|
|
354
|
+
- Folder doesn't exist
|
|
355
|
+
- Path should start with /
|
|
356
|
+
|
|
357
|
+
**Solutions:**
|
|
358
|
+
```bash
|
|
359
|
+
# List root to see available folders
|
|
360
|
+
drive ls /
|
|
361
|
+
|
|
362
|
+
# Use absolute paths
|
|
363
|
+
drive ls /backups/subfolder
|
|
364
|
+
|
|
365
|
+
# Use long format to see full paths
|
|
366
|
+
drive ls / -l
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Upload/Download Progress Not Showing
|
|
370
|
+
**Causes:**
|
|
371
|
+
- File is too small (progress skipped)
|
|
372
|
+
- Terminal doesn't support progress bars
|
|
373
|
+
|
|
374
|
+
**Solutions:**
|
|
375
|
+
- Progress bars automatically appear for larger files
|
|
376
|
+
- Check that your terminal supports ANSI escape codes
|
|
377
|
+
- Try in a different terminal (iTerm2, gnome-terminal, etc.)
|
|
226
378
|
|
|
227
|
-
|
|
379
|
+
### Task Won't Run
|
|
380
|
+
**Causes:**
|
|
381
|
+
- Task is disabled
|
|
382
|
+
- Another task instance is already running
|
|
383
|
+
- SFTP credentials are invalid
|
|
384
|
+
- Network connectivity issues
|
|
228
385
|
|
|
386
|
+
**Solutions:**
|
|
229
387
|
```bash
|
|
230
|
-
|
|
388
|
+
# Check task status
|
|
389
|
+
drive tasks ls
|
|
390
|
+
|
|
391
|
+
# Enable if disabled
|
|
392
|
+
drive tasks enable <task-id>
|
|
393
|
+
|
|
394
|
+
# If shows "Running" but stuck, stop and restart
|
|
395
|
+
drive tasks stop <task-id>
|
|
396
|
+
drive tasks run <task-id>
|
|
397
|
+
|
|
398
|
+
# Check server logs for detailed errors
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### npm Installation Issues
|
|
402
|
+
**MacOS/Linux:**
|
|
403
|
+
```bash
|
|
404
|
+
# Permission errors - use one of these methods:
|
|
405
|
+
|
|
406
|
+
# Method 1: Install globally with correct permissions
|
|
407
|
+
sudo npm install -g d-drive-cli
|
|
408
|
+
|
|
409
|
+
# Method 2: Use npx (no installation needed)
|
|
410
|
+
npx d-drive-cli ls /
|
|
411
|
+
|
|
412
|
+
# Method 3: Configure npm to use different directory
|
|
413
|
+
mkdir ~/.npm-global
|
|
414
|
+
npm config set prefix '~/.npm-global'
|
|
415
|
+
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
|
|
416
|
+
source ~/.bashrc
|
|
417
|
+
npm install -g d-drive-cli
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Windows:**
|
|
421
|
+
```powershell
|
|
422
|
+
# Run PowerShell as Administrator
|
|
423
|
+
npm install -g d-drive-cli
|
|
424
|
+
|
|
425
|
+
# Or use npx
|
|
426
|
+
npx d-drive-cli ls /
|
|
427
|
+
```
|
|
231
428
|
export DDRIVE_API_URL=https://your-server/api
|
|
232
429
|
```
|
|
233
430
|
|
|
@@ -249,6 +446,14 @@ export DDRIVE_API_URL=https://your-server/api
|
|
|
249
446
|
|
|
250
447
|
## Changelog
|
|
251
448
|
|
|
449
|
+
### v2.2.3
|
|
450
|
+
- **Bug fixes:**
|
|
451
|
+
- Fixed nested folder path resolution in `list` command
|
|
452
|
+
- Improved API key validation (now uses `/auth/me` endpoint)
|
|
453
|
+
- Added directory deletion warning message
|
|
454
|
+
- Better error messages for directory download attempts
|
|
455
|
+
- **Documentation:** Enhanced CLI README and API docs
|
|
456
|
+
|
|
252
457
|
### v2.2.2
|
|
253
458
|
- **ACTUALLY** fixed double output issue (previous v2.2.1 had wrong fix)
|
|
254
459
|
- Added `process.exit(0)` after help display to prevent Commander.js duplicate
|
package/dist/commands/config.js
CHANGED
|
@@ -26,8 +26,8 @@ async function configCommand(options) {
|
|
|
26
26
|
// Accept keys entered with or without the `dd_` prefix, and strip any accidental "Bearer " prefix
|
|
27
27
|
const rawKey = options.key.replace(/^Bearer\s+/i, '').trim();
|
|
28
28
|
const normalizedKey = rawKey.startsWith('dd_') ? rawKey : `dd_${rawKey}`;
|
|
29
|
-
// Validate API key by calling
|
|
30
|
-
const validateUrl = apiUrl.replace(/\/$/, '') + '/
|
|
29
|
+
// Validate API key by calling /auth/me endpoint (simpler and more reliable)
|
|
30
|
+
const validateUrl = apiUrl.replace(/\/$/, '') + '/auth/me';
|
|
31
31
|
const response = await axios_1.default.get(validateUrl, {
|
|
32
32
|
headers: {
|
|
33
33
|
Authorization: `Bearer ${normalizedKey}`,
|
package/dist/commands/delete.js
CHANGED
|
@@ -23,6 +23,10 @@ async function deleteCommand(remotePath, options) {
|
|
|
23
23
|
}
|
|
24
24
|
const file = files[0];
|
|
25
25
|
spinner.stop();
|
|
26
|
+
// Warn if trying to delete a directory
|
|
27
|
+
if (file.type === 'DIRECTORY') {
|
|
28
|
+
console.log(chalk_1.default.yellow('Warning: This is a directory. All contents will be moved to recycle bin.'));
|
|
29
|
+
}
|
|
26
30
|
// Confirm deletion
|
|
27
31
|
if (!options.force) {
|
|
28
32
|
const answers = await inquirer_1.default.prompt([
|
|
@@ -26,6 +26,8 @@ async function downloadCommand(source, destination = './', options) {
|
|
|
26
26
|
const file = files[0];
|
|
27
27
|
if (file.type === 'DIRECTORY') {
|
|
28
28
|
spinner.fail(chalk_1.default.red('Cannot download directories yet'));
|
|
29
|
+
console.log(chalk_1.default.gray('Tip: Download individual files from the directory instead.'));
|
|
30
|
+
console.log(chalk_1.default.gray('Use: drive ls ' + source + ' -l'));
|
|
29
31
|
return;
|
|
30
32
|
}
|
|
31
33
|
spinner.text = 'Downloading...';
|
package/dist/commands/list.js
CHANGED
|
@@ -61,13 +61,22 @@ async function listCommand(remotePath = '/', options) {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
function findFolderByPath(files, targetPath) {
|
|
64
|
-
//
|
|
65
|
-
const
|
|
64
|
+
// Build full path for each file and match against target
|
|
65
|
+
const normalizedTarget = targetPath.startsWith('/') ? targetPath : '/' + targetPath;
|
|
66
66
|
for (const file of files) {
|
|
67
|
-
if (file.type === 'DIRECTORY' && file.
|
|
67
|
+
if (file.type === 'DIRECTORY' && file.path === normalizedTarget) {
|
|
68
68
|
return file;
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
+
// Fallback: try matching by name only (for root-level folders)
|
|
72
|
+
const pathParts = targetPath.split('/').filter(p => p);
|
|
73
|
+
if (pathParts.length === 1) {
|
|
74
|
+
for (const file of files) {
|
|
75
|
+
if (file.type === 'DIRECTORY' && file.name === pathParts[0]) {
|
|
76
|
+
return file;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
71
80
|
return null;
|
|
72
81
|
}
|
|
73
82
|
function formatFileSize(bytes) {
|
package/dist/index.js
CHANGED
|
@@ -20,8 +20,8 @@ const program = new commander_1.Command();
|
|
|
20
20
|
// ASCII art banner
|
|
21
21
|
const banner = `
|
|
22
22
|
${chalk_1.default.cyan('╔═══════════════════════════════════════╗')}
|
|
23
|
-
${chalk_1.default.cyan('║')} ${chalk_1.default.bold.white('D-Drive CLI')} ${chalk_1.default.gray('v' + (pkg.version || '2.2.0'))} ${chalk_1.default.cyan('║')}
|
|
24
|
-
${chalk_1.default.cyan('║')} ${chalk_1.default.gray('Discord-based cloud storage')} ${chalk_1.default.cyan('║')}
|
|
23
|
+
${chalk_1.default.cyan('║')} ${chalk_1.default.bold.white('D-Drive CLI')} ${chalk_1.default.gray('v' + (pkg.version || '2.2.0'))} ${chalk_1.default.cyan(' ║')}
|
|
24
|
+
${chalk_1.default.cyan('║')} ${chalk_1.default.gray('Discord-based cloud storage')} ${chalk_1.default.cyan(' ║')}
|
|
25
25
|
${chalk_1.default.cyan('╚═══════════════════════════════════════╝')}
|
|
26
26
|
`;
|
|
27
27
|
program
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "d-drive-cli",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.3",
|
|
4
4
|
"description": "D-Drive CLI tool for developers - Discord cloud storage",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -21,23 +21,23 @@
|
|
|
21
21
|
"author": "jasonzli-DEV",
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"commander": "^11.1.0",
|
|
25
24
|
"axios": "^1.6.5",
|
|
26
25
|
"chalk": "^4.1.2",
|
|
27
|
-
"
|
|
26
|
+
"commander": "^11.1.0",
|
|
28
27
|
"conf": "^10.2.0",
|
|
29
|
-
"inquirer": "^8.2.6",
|
|
30
28
|
"form-data": "^4.0.0",
|
|
31
29
|
"fs-extra": "^11.2.0",
|
|
32
30
|
"glob": "^10.3.10",
|
|
31
|
+
"inquirer": "^8.2.6",
|
|
32
|
+
"ora": "^5.4.1",
|
|
33
33
|
"progress": "^2.0.3"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@types/node": "^20.10.7",
|
|
37
|
-
"@types/inquirer": "^8.2.10",
|
|
38
36
|
"@types/fs-extra": "^11.0.4",
|
|
37
|
+
"@types/inquirer": "^8.2.10",
|
|
38
|
+
"@types/node": "^20.10.7",
|
|
39
39
|
"@types/progress": "^2.0.7",
|
|
40
|
-
"
|
|
41
|
-
"
|
|
40
|
+
"ts-node": "^10.9.2",
|
|
41
|
+
"typescript": "^5.9.3"
|
|
42
42
|
}
|
|
43
43
|
}
|
package/src/commands/config.ts
CHANGED
|
@@ -31,8 +31,8 @@ export async function configCommand(options: ConfigOptions) {
|
|
|
31
31
|
const rawKey = options.key.replace(/^Bearer\s+/i, '').trim();
|
|
32
32
|
const normalizedKey = rawKey.startsWith('dd_') ? rawKey : `dd_${rawKey}`;
|
|
33
33
|
|
|
34
|
-
// Validate API key by calling
|
|
35
|
-
const validateUrl = apiUrl.replace(/\/$/, '') + '/
|
|
34
|
+
// Validate API key by calling /auth/me endpoint (simpler and more reliable)
|
|
35
|
+
const validateUrl = apiUrl.replace(/\/$/, '') + '/auth/me';
|
|
36
36
|
const response = await axios.get(validateUrl, {
|
|
37
37
|
headers: {
|
|
38
38
|
Authorization: `Bearer ${normalizedKey}`,
|
package/src/commands/delete.ts
CHANGED
|
@@ -28,6 +28,11 @@ export async function deleteCommand(remotePath: string, options: DeleteOptions)
|
|
|
28
28
|
const file = files[0];
|
|
29
29
|
spinner.stop();
|
|
30
30
|
|
|
31
|
+
// Warn if trying to delete a directory
|
|
32
|
+
if (file.type === 'DIRECTORY') {
|
|
33
|
+
console.log(chalk.yellow('Warning: This is a directory. All contents will be moved to recycle bin.'));
|
|
34
|
+
}
|
|
35
|
+
|
|
31
36
|
// Confirm deletion
|
|
32
37
|
if (!options.force) {
|
|
33
38
|
const answers = await inquirer.prompt([
|
package/src/commands/download.ts
CHANGED
|
@@ -34,6 +34,8 @@ export async function downloadCommand(
|
|
|
34
34
|
|
|
35
35
|
if (file.type === 'DIRECTORY') {
|
|
36
36
|
spinner.fail(chalk.red('Cannot download directories yet'));
|
|
37
|
+
console.log(chalk.gray('Tip: Download individual files from the directory instead.'));
|
|
38
|
+
console.log(chalk.gray('Use: drive ls ' + source + ' -l'));
|
|
37
39
|
return;
|
|
38
40
|
}
|
|
39
41
|
|
package/src/commands/list.ts
CHANGED
|
@@ -71,14 +71,25 @@ export async function listCommand(remotePath: string = '/', options: ListOptions
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
function findFolderByPath(files: any[], targetPath: string): any | null {
|
|
74
|
-
//
|
|
75
|
-
const
|
|
74
|
+
// Build full path for each file and match against target
|
|
75
|
+
const normalizedTarget = targetPath.startsWith('/') ? targetPath : '/' + targetPath;
|
|
76
76
|
|
|
77
77
|
for (const file of files) {
|
|
78
|
-
if (file.type === 'DIRECTORY' && file.
|
|
78
|
+
if (file.type === 'DIRECTORY' && file.path === normalizedTarget) {
|
|
79
79
|
return file;
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
+
|
|
83
|
+
// Fallback: try matching by name only (for root-level folders)
|
|
84
|
+
const pathParts = targetPath.split('/').filter(p => p);
|
|
85
|
+
if (pathParts.length === 1) {
|
|
86
|
+
for (const file of files) {
|
|
87
|
+
if (file.type === 'DIRECTORY' && file.name === pathParts[0]) {
|
|
88
|
+
return file;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
82
93
|
return null;
|
|
83
94
|
}
|
|
84
95
|
|
package/src/index.ts
CHANGED
|
@@ -18,8 +18,8 @@ const program = new Command();
|
|
|
18
18
|
// ASCII art banner
|
|
19
19
|
const banner = `
|
|
20
20
|
${chalk.cyan('╔═══════════════════════════════════════╗')}
|
|
21
|
-
${chalk.cyan('║')} ${chalk.bold.white('D-Drive CLI')} ${chalk.gray('v' + (pkg.version || '2.2.0'))} ${chalk.cyan('║')}
|
|
22
|
-
${chalk.cyan('║')} ${chalk.gray('Discord-based cloud storage')} ${chalk.cyan('║')}
|
|
21
|
+
${chalk.cyan('║')} ${chalk.bold.white('D-Drive CLI')} ${chalk.gray('v' + (pkg.version || '2.2.0'))} ${chalk.cyan(' ║')}
|
|
22
|
+
${chalk.cyan('║')} ${chalk.gray('Discord-based cloud storage')} ${chalk.cyan(' ║')}
|
|
23
23
|
${chalk.cyan('╚═══════════════════════════════════════╝')}
|
|
24
24
|
`;
|
|
25
25
|
|