@tom2012/cc-web 1.5.11 → 1.5.14
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/backend/dist/backup/config.d.ts +8 -0
- package/backend/dist/backup/config.d.ts.map +1 -0
- package/backend/dist/backup/config.js +104 -0
- package/backend/dist/backup/config.js.map +1 -0
- package/backend/dist/backup/engine.d.ts +22 -0
- package/backend/dist/backup/engine.d.ts.map +1 -0
- package/backend/dist/backup/engine.js +280 -0
- package/backend/dist/backup/engine.js.map +1 -0
- package/backend/dist/backup/providers/dropbox.d.ts +25 -0
- package/backend/dist/backup/providers/dropbox.d.ts.map +1 -0
- package/backend/dist/backup/providers/dropbox.js +319 -0
- package/backend/dist/backup/providers/dropbox.js.map +1 -0
- package/backend/dist/backup/providers/google-drive.d.ts +29 -0
- package/backend/dist/backup/providers/google-drive.d.ts.map +1 -0
- package/backend/dist/backup/providers/google-drive.js +305 -0
- package/backend/dist/backup/providers/google-drive.js.map +1 -0
- package/backend/dist/backup/providers/index.d.ts +3 -0
- package/backend/dist/backup/providers/index.d.ts.map +1 -0
- package/backend/dist/backup/providers/index.js +19 -0
- package/backend/dist/backup/providers/index.js.map +1 -0
- package/backend/dist/backup/providers/onedrive.d.ts +29 -0
- package/backend/dist/backup/providers/onedrive.d.ts.map +1 -0
- package/backend/dist/backup/providers/onedrive.js +316 -0
- package/backend/dist/backup/providers/onedrive.js.map +1 -0
- package/backend/dist/backup/scheduler.d.ts +6 -0
- package/backend/dist/backup/scheduler.d.ts.map +1 -0
- package/backend/dist/backup/scheduler.js +53 -0
- package/backend/dist/backup/scheduler.js.map +1 -0
- package/backend/dist/backup/types.d.ts +68 -0
- package/backend/dist/backup/types.d.ts.map +1 -0
- package/backend/dist/backup/types.js +4 -0
- package/backend/dist/backup/types.js.map +1 -0
- package/backend/dist/index.d.ts.map +1 -1
- package/backend/dist/index.js +74 -10
- package/backend/dist/index.js.map +1 -1
- package/backend/dist/routes/backup.d.ts +4 -0
- package/backend/dist/routes/backup.d.ts.map +1 -0
- package/backend/dist/routes/backup.js +175 -0
- package/backend/dist/routes/backup.js.map +1 -0
- package/backend/dist/routes/projects.d.ts.map +1 -1
- package/backend/dist/routes/projects.js +14 -0
- package/backend/dist/routes/projects.js.map +1 -1
- package/backend/dist/routes/sounds.d.ts +3 -0
- package/backend/dist/routes/sounds.d.ts.map +1 -0
- package/backend/dist/routes/sounds.js +283 -0
- package/backend/dist/routes/sounds.js.map +1 -0
- package/backend/package-lock.json +662 -20
- package/backend/package.json +8 -0
- package/bin/ccweb.js +33 -0
- package/frontend/dist/assets/index-D7gjxQKB.css +32 -0
- package/frontend/dist/assets/index-Dg1NcsQH.js +489 -0
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
- package/frontend/dist/assets/index-CQjbS4zv.css +0 -32
- package/frontend/dist/assets/index-C_RCd4kd.js +0 -434
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A self-hosted web application (and macOS Electron desktop app) that provides a browser-based interface for [Claude Code](https://docs.anthropic.com/en/docs/claude-code) CLI sessions. Create projects, each with a persistent terminal running Claude Code, and interact with them through a real-time terminal UI.
|
|
4
4
|
|
|
5
|
-
**Current version**: v1.5.
|
|
5
|
+
**Current version**: v1.5.14 | [GitHub](https://github.com/zbc0315/cc-web) | MIT License
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
@@ -19,6 +19,9 @@ A self-hosted web application (and macOS Electron desktop app) that provides a b
|
|
|
19
19
|
- **In-app Updates**: Check GitHub releases, download, and install without leaving the app
|
|
20
20
|
- **Localhost Auto-auth**: Local access skips login entirely; JWT only required for remote access
|
|
21
21
|
- **Auto Port Switching**: Backend tries ports 3001–3020 and reports the actual port
|
|
22
|
+
- **Network Access Modes**: Local only (127.0.0.1), LAN (private IPs), or public — selectable at startup
|
|
23
|
+
- **Cloud Backup**: Incremental backup to Google Drive, OneDrive, or Dropbox (multi-provider parallel upload, scheduled or manual)
|
|
24
|
+
- **Ambient Sound**: Background sounds (singing bowl, rain, wind, stream, etc.) that play when LLM is active, with custom upload support
|
|
22
25
|
- **Dark/Light Theme**: Toggle between themes
|
|
23
26
|
|
|
24
27
|
## Prerequisites
|
|
@@ -47,6 +50,9 @@ On first launch you'll be prompted to set a username and password. The server au
|
|
|
47
50
|
ccweb # start (interactive prompts)
|
|
48
51
|
ccweb start --daemon # start in background, no prompts
|
|
49
52
|
ccweb start --foreground # start in foreground, no prompts
|
|
53
|
+
ccweb start --local # local only (default, most secure)
|
|
54
|
+
ccweb start --lan # allow LAN access
|
|
55
|
+
ccweb start --public # allow public access
|
|
50
56
|
ccweb stop # stop background server
|
|
51
57
|
ccweb status # show PID, port, data location
|
|
52
58
|
ccweb open # open browser to running server
|
|
@@ -113,6 +119,9 @@ Browser (React/Vite :5173 dev | Express :3001 prod)
|
|
|
113
119
|
| `routes/update.ts` | `GET /check-running`, `POST /prepare` (save memory → wait idle → stop all) |
|
|
114
120
|
| `routes/filesystem.ts` | Directory browser, file read/write |
|
|
115
121
|
| `routes/shortcuts.ts` | Global shortcut CRUD with inheritance |
|
|
122
|
+
| `routes/backup.ts` | Cloud backup API (providers, OAuth, backup trigger, schedule) |
|
|
123
|
+
| `routes/sounds.ts` | Sound file API: presets, download, upload, streaming |
|
|
124
|
+
| `backup/` | CloudProvider implementations (Google Drive, OneDrive, Dropbox), engine, scheduler |
|
|
116
125
|
|
|
117
126
|
### Frontend (`frontend/src/`)
|
|
118
127
|
|
|
@@ -122,6 +131,9 @@ Browser (React/Vite :5173 dev | Express :3001 prod)
|
|
|
122
131
|
| `pages/LoginPage.tsx` | Login form, auto-login on localhost |
|
|
123
132
|
| `pages/DashboardPage.tsx` | Project grid, new/open project, fullscreen toggle, update button |
|
|
124
133
|
| `pages/ProjectPage.tsx` | Three-panel layout: FileTree \| WebTerminal \| RightPanel |
|
|
134
|
+
| `pages/SettingsPage.tsx` | Settings: cloud accounts, backup strategy, backup history |
|
|
135
|
+
| `components/SoundPlayer.tsx` | Audio playback engine (fade in/out, loop/interval modes) |
|
|
136
|
+
| `components/SoundSelector.tsx` | Sound selection and configuration UI popover |
|
|
125
137
|
| `components/WebTerminal.tsx` | xterm.js terminal with fit addon |
|
|
126
138
|
| `components/RightPanel.tsx` | Three tabs: Shortcuts / History / Graph |
|
|
127
139
|
| `components/ShortcutPanel.tsx` | Project + global shortcuts, dialog editor for add/edit |
|
|
@@ -206,6 +218,13 @@ Localhost WebSocket connections are pre-authenticated — no `auth` message need
|
|
|
206
218
|
| `GET/PUT` | `/api/filesystem/file` | Read/write files |
|
|
207
219
|
| `GET` | `/api/update/check-running` | Check if processes are running |
|
|
208
220
|
| `POST` | `/api/update/prepare` | Save memory, wait idle, stop all |
|
|
221
|
+
| `GET/POST/DELETE` | `/api/backup/providers` | Cloud backup provider CRUD |
|
|
222
|
+
| `GET` | `/api/backup/auth/:id/url` | Get OAuth2 authorization URL |
|
|
223
|
+
| `GET` | `/api/backup/auth/callback` | OAuth2 redirect callback |
|
|
224
|
+
| `POST` | `/api/backup/run/:projectId` | Trigger manual backup |
|
|
225
|
+
| `GET/PUT` | `/api/backup/schedule` | Backup schedule config |
|
|
226
|
+
| `GET/PUT` | `/api/backup/excludes` | Exclude patterns |
|
|
227
|
+
| `GET` | `/api/backup/history` | Backup history |
|
|
209
228
|
|
|
210
229
|
## macOS Desktop App (Electron)
|
|
211
230
|
|
|
@@ -255,6 +274,7 @@ Environment variables:
|
|
|
255
274
|
|----------|---------|---------|
|
|
256
275
|
| `CCWEB_DATA_DIR` | Override data directory | `data/` relative to backend |
|
|
257
276
|
| `CCWEB_PORT` | Preferred server port | `3001` |
|
|
277
|
+
| `CCWEB_ACCESS_MODE` | Network access mode (`local`/`lan`/`public`) | `local` |
|
|
258
278
|
|
|
259
279
|
## Build & Release
|
|
260
280
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BackupConfig, BackupHistoryEntry, BackupState } from './types';
|
|
2
|
+
export declare function getBackupConfig(): BackupConfig;
|
|
3
|
+
export declare function saveBackupConfig(config: BackupConfig): void;
|
|
4
|
+
export declare function getBackupHistory(): BackupHistoryEntry[];
|
|
5
|
+
export declare function addBackupHistory(entry: BackupHistoryEntry): void;
|
|
6
|
+
export declare function getBackupState(projectFolderPath: string): BackupState;
|
|
7
|
+
export declare function saveBackupState(projectFolderPath: string, state: BackupState): void;
|
|
8
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/backup/config.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAkBxE,wBAAgB,eAAe,IAAI,YAAY,CAO9C;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAE3D;AAED,wBAAgB,gBAAgB,IAAI,kBAAkB,EAAE,CAOvD;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAKhE;AAED,wBAAgB,cAAc,CAAC,iBAAiB,EAAE,MAAM,GAAG,WAAW,CAQrE;AAED,wBAAgB,eAAe,CAAC,iBAAiB,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAInF"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// backend/src/backup/config.ts
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.getBackupConfig = getBackupConfig;
|
|
38
|
+
exports.saveBackupConfig = saveBackupConfig;
|
|
39
|
+
exports.getBackupHistory = getBackupHistory;
|
|
40
|
+
exports.addBackupHistory = addBackupHistory;
|
|
41
|
+
exports.getBackupState = getBackupState;
|
|
42
|
+
exports.saveBackupState = saveBackupState;
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const DATA_DIR = process.env.CCWEB_DATA_DIR || path.join(__dirname, '../../../data');
|
|
46
|
+
const BACKUP_CONFIG_FILE = path.join(DATA_DIR, 'backup-config.json');
|
|
47
|
+
const BACKUP_HISTORY_FILE = path.join(DATA_DIR, 'backup-history.json');
|
|
48
|
+
function atomicWriteSync(filePath, data) {
|
|
49
|
+
const tmpPath = filePath + `.tmp.${process.pid}`;
|
|
50
|
+
fs.writeFileSync(tmpPath, data, 'utf-8');
|
|
51
|
+
fs.renameSync(tmpPath, filePath);
|
|
52
|
+
}
|
|
53
|
+
const DEFAULT_CONFIG = {
|
|
54
|
+
providers: [],
|
|
55
|
+
schedule: { enabled: false, intervalMinutes: 60 },
|
|
56
|
+
excludePatterns: ['node_modules', '.git', 'dist', 'build', '*.log', '.DS_Store', '*.tmp', '.venv', '__pycache__', '.env'],
|
|
57
|
+
};
|
|
58
|
+
function getBackupConfig() {
|
|
59
|
+
if (!fs.existsSync(BACKUP_CONFIG_FILE))
|
|
60
|
+
return { ...DEFAULT_CONFIG, providers: [] };
|
|
61
|
+
try {
|
|
62
|
+
return JSON.parse(fs.readFileSync(BACKUP_CONFIG_FILE, 'utf-8'));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return { ...DEFAULT_CONFIG, providers: [] };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function saveBackupConfig(config) {
|
|
69
|
+
atomicWriteSync(BACKUP_CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
70
|
+
}
|
|
71
|
+
function getBackupHistory() {
|
|
72
|
+
if (!fs.existsSync(BACKUP_HISTORY_FILE))
|
|
73
|
+
return [];
|
|
74
|
+
try {
|
|
75
|
+
return JSON.parse(fs.readFileSync(BACKUP_HISTORY_FILE, 'utf-8'));
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function addBackupHistory(entry) {
|
|
82
|
+
const history = getBackupHistory();
|
|
83
|
+
history.unshift(entry);
|
|
84
|
+
if (history.length > 100)
|
|
85
|
+
history.length = 100;
|
|
86
|
+
atomicWriteSync(BACKUP_HISTORY_FILE, JSON.stringify(history, null, 2));
|
|
87
|
+
}
|
|
88
|
+
function getBackupState(projectFolderPath) {
|
|
89
|
+
const file = path.join(projectFolderPath, '.ccweb', 'backup-state.json');
|
|
90
|
+
if (!fs.existsSync(file))
|
|
91
|
+
return { lastBackupTime: null, files: {} };
|
|
92
|
+
try {
|
|
93
|
+
return JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return { lastBackupTime: null, files: {} };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function saveBackupState(projectFolderPath, state) {
|
|
100
|
+
const dir = path.join(projectFolderPath, '.ccweb');
|
|
101
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
102
|
+
atomicWriteSync(path.join(dir, 'backup-state.json'), JSON.stringify(state, null, 2));
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/backup/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BackupHistoryEntry } from './types';
|
|
2
|
+
export interface BackupProgress {
|
|
3
|
+
projectId: string;
|
|
4
|
+
projectName: string;
|
|
5
|
+
providerId: string;
|
|
6
|
+
providerLabel: string;
|
|
7
|
+
status: 'scanning' | 'uploading' | 'deleting' | 'done' | 'error';
|
|
8
|
+
filesUploaded: number;
|
|
9
|
+
filesDeleted: number;
|
|
10
|
+
filesTotal: number;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
export type ProgressCallback = (progress: BackupProgress) => void;
|
|
14
|
+
export declare function computeHash(filePath: string): string;
|
|
15
|
+
export declare function shouldExclude(relativePath: string, patterns: string[]): boolean;
|
|
16
|
+
export declare function scanDirectory(dirPath: string, excludePatterns: string[], basePath?: string): Map<string, {
|
|
17
|
+
mtime: number;
|
|
18
|
+
size: number;
|
|
19
|
+
}>;
|
|
20
|
+
export declare function runBackup(projectId: string, onProgress?: ProgressCallback): Promise<BackupHistoryEntry[]>;
|
|
21
|
+
export declare function runBackupAll(onProgress?: ProgressCallback): Promise<BackupHistoryEntry[]>;
|
|
22
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/backup/engine.ts"],"names":[],"mappings":"AAOA,OAAO,EAA4C,kBAAkB,EAAkB,MAAM,SAAS,CAAC;AAKvG,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC;IACjE,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,cAAc,KAAK,IAAI,CAAC;AAElE,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIpD;AAED,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAe/E;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,EAAE,EACzB,QAAQ,CAAC,EAAE,MAAM,GAChB,GAAG,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAsC9C;AAED,wBAAsB,SAAS,CAC7B,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,gBAAgB,GAC5B,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAsL/B;AAED,wBAAsB,YAAY,CAAC,UAAU,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAc/F"}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// backend/src/backup/engine.ts
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.computeHash = computeHash;
|
|
38
|
+
exports.shouldExclude = shouldExclude;
|
|
39
|
+
exports.scanDirectory = scanDirectory;
|
|
40
|
+
exports.runBackup = runBackup;
|
|
41
|
+
exports.runBackupAll = runBackupAll;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const crypto = __importStar(require("crypto"));
|
|
45
|
+
const minimatch_1 = require("minimatch");
|
|
46
|
+
const uuid_1 = require("uuid");
|
|
47
|
+
const config_1 = require("./config");
|
|
48
|
+
const providers_1 = require("./providers");
|
|
49
|
+
const config_2 = require("../config");
|
|
50
|
+
function computeHash(filePath) {
|
|
51
|
+
const content = fs.readFileSync(filePath);
|
|
52
|
+
const hash = crypto.createHash('sha256').update(content).digest('hex');
|
|
53
|
+
return `sha256:${hash}`;
|
|
54
|
+
}
|
|
55
|
+
function shouldExclude(relativePath, patterns) {
|
|
56
|
+
const segments = relativePath.split('/');
|
|
57
|
+
for (const pattern of patterns) {
|
|
58
|
+
// Match full relative path
|
|
59
|
+
if ((0, minimatch_1.minimatch)(relativePath, pattern, { dot: true, matchBase: true })) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
// Match each path segment individually
|
|
63
|
+
for (const segment of segments) {
|
|
64
|
+
if ((0, minimatch_1.minimatch)(segment, pattern, { dot: true, matchBase: true })) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
function scanDirectory(dirPath, excludePatterns, basePath) {
|
|
72
|
+
const result = new Map();
|
|
73
|
+
const base = basePath ?? dirPath;
|
|
74
|
+
let entries;
|
|
75
|
+
try {
|
|
76
|
+
entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
for (const entry of entries) {
|
|
82
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
83
|
+
const relativePath = path.relative(base, fullPath).replace(/\\/g, '/');
|
|
84
|
+
if (shouldExclude(relativePath, excludePatterns)) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (entry.isDirectory()) {
|
|
88
|
+
const subResult = scanDirectory(fullPath, excludePatterns, base);
|
|
89
|
+
for (const [relPath, info] of subResult) {
|
|
90
|
+
result.set(relPath, info);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else if (entry.isFile()) {
|
|
94
|
+
try {
|
|
95
|
+
const stat = fs.statSync(fullPath);
|
|
96
|
+
result.set(relativePath, {
|
|
97
|
+
mtime: stat.mtimeMs,
|
|
98
|
+
size: stat.size,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// Skip unreadable files
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
async function runBackup(projectId, onProgress) {
|
|
109
|
+
const config = (0, config_1.getBackupConfig)();
|
|
110
|
+
const authorizedProviders = config.providers.filter((p) => p.tokens);
|
|
111
|
+
if (authorizedProviders.length === 0) {
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
const projects = (0, config_2.getProjects)();
|
|
115
|
+
const project = projects.find((p) => p.id === projectId && !p.archived);
|
|
116
|
+
if (!project) {
|
|
117
|
+
throw new Error(`Project ${projectId} not found or archived`);
|
|
118
|
+
}
|
|
119
|
+
if (!fs.existsSync(project.folderPath)) {
|
|
120
|
+
throw new Error(`Project folder does not exist: ${project.folderPath}`);
|
|
121
|
+
}
|
|
122
|
+
const excludePatterns = config.excludePatterns ?? [];
|
|
123
|
+
// Step 1: Scan local files
|
|
124
|
+
const scanned = scanDirectory(project.folderPath, excludePatterns);
|
|
125
|
+
// Step 2: Load previous backup state
|
|
126
|
+
const prevState = (0, config_1.getBackupState)(project.folderPath);
|
|
127
|
+
// Step 3: Determine which files need uploading (changed or new)
|
|
128
|
+
const newFiles = {};
|
|
129
|
+
const toUpload = []; // relative paths
|
|
130
|
+
for (const [relPath, { mtime, size }] of scanned) {
|
|
131
|
+
const prev = prevState.files[relPath];
|
|
132
|
+
if (prev && prev.mtime === mtime && prev.size === size) {
|
|
133
|
+
// Unchanged: keep previous snapshot
|
|
134
|
+
newFiles[relPath] = prev;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
// Changed or new: compute hash
|
|
138
|
+
const fullPath = path.join(project.folderPath, relPath);
|
|
139
|
+
let hash;
|
|
140
|
+
try {
|
|
141
|
+
hash = computeHash(fullPath);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// Unreadable file, skip
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (prev && prev.hash === hash) {
|
|
148
|
+
// Content unchanged, just update mtime/size
|
|
149
|
+
newFiles[relPath] = { mtime, size, hash };
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// Content changed: queue for upload
|
|
153
|
+
newFiles[relPath] = { mtime, size, hash };
|
|
154
|
+
toUpload.push(relPath);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Step 4: Detect deletions (files in prev state no longer present locally)
|
|
159
|
+
const toDelete = [];
|
|
160
|
+
for (const relPath of Object.keys(prevState.files)) {
|
|
161
|
+
if (!scanned.has(relPath)) {
|
|
162
|
+
toDelete.push(relPath);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const totalFiles = scanned.size;
|
|
166
|
+
const startTime = new Date().toISOString();
|
|
167
|
+
const results = [];
|
|
168
|
+
// Step 5: Run backup for each provider in parallel
|
|
169
|
+
const providerResults = await Promise.all(authorizedProviders.map(async (providerConfig) => {
|
|
170
|
+
const provider = (0, providers_1.createProvider)(providerConfig);
|
|
171
|
+
let filesUploaded = 0;
|
|
172
|
+
let filesDeleted = 0;
|
|
173
|
+
let entryStatus = 'success';
|
|
174
|
+
let errorMsg;
|
|
175
|
+
const reportProgress = (status, uploaded = filesUploaded, deleted = filesDeleted) => {
|
|
176
|
+
onProgress?.({
|
|
177
|
+
projectId,
|
|
178
|
+
projectName: project.name,
|
|
179
|
+
providerId: providerConfig.id,
|
|
180
|
+
providerLabel: providerConfig.label,
|
|
181
|
+
status,
|
|
182
|
+
filesUploaded: uploaded,
|
|
183
|
+
filesDeleted: deleted,
|
|
184
|
+
filesTotal: totalFiles,
|
|
185
|
+
});
|
|
186
|
+
};
|
|
187
|
+
try {
|
|
188
|
+
await provider.ensureAuth();
|
|
189
|
+
// Create base remote directory
|
|
190
|
+
const baseRemotePath = `CCWeb/${project.name}`;
|
|
191
|
+
await provider.mkdir(baseRemotePath);
|
|
192
|
+
// Upload changed files
|
|
193
|
+
reportProgress('uploading');
|
|
194
|
+
for (const relPath of toUpload) {
|
|
195
|
+
const localPath = path.join(project.folderPath, relPath);
|
|
196
|
+
const remotePath = `${baseRemotePath}/${relPath}`;
|
|
197
|
+
// Ensure parent directory exists
|
|
198
|
+
const remoteDir = path.dirname(remotePath).replace(/\\/g, '/');
|
|
199
|
+
if (remoteDir !== baseRemotePath) {
|
|
200
|
+
await provider.mkdir(remoteDir);
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
await provider.uploadFile(localPath, remotePath);
|
|
204
|
+
filesUploaded++;
|
|
205
|
+
reportProgress('uploading');
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
// Continue on individual file error
|
|
209
|
+
entryStatus = 'partial';
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// Delete orphaned remote files
|
|
213
|
+
reportProgress('deleting', filesUploaded, filesDeleted);
|
|
214
|
+
for (const relPath of toDelete) {
|
|
215
|
+
const remotePath = `${baseRemotePath}/${relPath}`;
|
|
216
|
+
try {
|
|
217
|
+
await provider.deleteFile(remotePath);
|
|
218
|
+
filesDeleted++;
|
|
219
|
+
reportProgress('deleting', filesUploaded, filesDeleted);
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
// Ignore delete errors (file may already be gone)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
reportProgress('done', filesUploaded, filesDeleted);
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
entryStatus = 'failed';
|
|
229
|
+
errorMsg = err?.message ?? String(err);
|
|
230
|
+
reportProgress('error', filesUploaded, filesDeleted);
|
|
231
|
+
}
|
|
232
|
+
const endTime = new Date().toISOString();
|
|
233
|
+
const entry = {
|
|
234
|
+
id: (0, uuid_1.v4)(),
|
|
235
|
+
projectId,
|
|
236
|
+
projectName: project.name,
|
|
237
|
+
providerId: providerConfig.id,
|
|
238
|
+
providerType: providerConfig.type,
|
|
239
|
+
providerLabel: providerConfig.label,
|
|
240
|
+
startTime,
|
|
241
|
+
endTime,
|
|
242
|
+
status: entryStatus,
|
|
243
|
+
filesUploaded,
|
|
244
|
+
filesDeleted,
|
|
245
|
+
filesTotal: totalFiles,
|
|
246
|
+
error: errorMsg,
|
|
247
|
+
};
|
|
248
|
+
return { entry, success: entryStatus !== 'failed' };
|
|
249
|
+
}));
|
|
250
|
+
// Step 6: If any provider succeeded, save new backup state
|
|
251
|
+
const anySuccess = providerResults.some((r) => r.success);
|
|
252
|
+
if (anySuccess) {
|
|
253
|
+
const newState = {
|
|
254
|
+
lastBackupTime: new Date().toISOString(),
|
|
255
|
+
files: newFiles,
|
|
256
|
+
};
|
|
257
|
+
(0, config_1.saveBackupState)(project.folderPath, newState);
|
|
258
|
+
}
|
|
259
|
+
// Step 7: Save history entries and collect results
|
|
260
|
+
for (const { entry } of providerResults) {
|
|
261
|
+
(0, config_1.addBackupHistory)(entry);
|
|
262
|
+
results.push(entry);
|
|
263
|
+
}
|
|
264
|
+
return results;
|
|
265
|
+
}
|
|
266
|
+
async function runBackupAll(onProgress) {
|
|
267
|
+
const projects = (0, config_2.getProjects)().filter((p) => !p.archived);
|
|
268
|
+
const allResults = [];
|
|
269
|
+
for (const project of projects) {
|
|
270
|
+
try {
|
|
271
|
+
const entries = await runBackup(project.id, onProgress);
|
|
272
|
+
allResults.push(...entries);
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
// Continue with other projects
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return allResults;
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/backup/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { CloudProvider, ProviderConfig, ProviderTokens, RemoteFile } from '../types';
|
|
2
|
+
export declare class DropboxProvider implements CloudProvider {
|
|
3
|
+
config: ProviderConfig;
|
|
4
|
+
private dbx;
|
|
5
|
+
constructor(config: ProviderConfig);
|
|
6
|
+
private initClient;
|
|
7
|
+
private client;
|
|
8
|
+
/**
|
|
9
|
+
* Normalize a path to Dropbox format:
|
|
10
|
+
* - Root is empty string ''
|
|
11
|
+
* - All other paths start with '/' and have no trailing slash
|
|
12
|
+
*/
|
|
13
|
+
private normPath;
|
|
14
|
+
getAuthUrl(redirectUri: string): string;
|
|
15
|
+
handleCallback(code: string, redirectUri: string): Promise<ProviderTokens>;
|
|
16
|
+
refreshToken(): Promise<ProviderTokens>;
|
|
17
|
+
isAuthorized(): boolean;
|
|
18
|
+
ensureAuth(): Promise<void>;
|
|
19
|
+
listFiles(remotePath: string): Promise<RemoteFile[]>;
|
|
20
|
+
uploadFile(localPath: string, remotePath: string): Promise<void>;
|
|
21
|
+
deleteFile(remotePath: string): Promise<void>;
|
|
22
|
+
mkdir(remotePath: string): Promise<void>;
|
|
23
|
+
downloadFile(remotePath: string, localPath: string): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=dropbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dropbox.d.ts","sourceRoot":"","sources":["../../../src/backup/providers/dropbox.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AASrF,qBAAa,eAAgB,YAAW,aAAa;IACnD,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,CAAC,GAAG,CAAwB;gBAEvB,MAAM,EAAE,cAAc;IAOlC,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,MAAM;IAOd;;;;OAIG;IACH,OAAO,CAAC,QAAQ;IAOhB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAUjC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IA8C1E,YAAY,IAAI,OAAO,CAAC,cAAc,CAAC;IAiD7C,YAAY,IAAI,OAAO;IAIjB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAa3B,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAuCpD,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8EhE,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7C,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBxC,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAoBzE"}
|