@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.
Files changed (56) hide show
  1. package/README.md +21 -1
  2. package/backend/dist/backup/config.d.ts +8 -0
  3. package/backend/dist/backup/config.d.ts.map +1 -0
  4. package/backend/dist/backup/config.js +104 -0
  5. package/backend/dist/backup/config.js.map +1 -0
  6. package/backend/dist/backup/engine.d.ts +22 -0
  7. package/backend/dist/backup/engine.d.ts.map +1 -0
  8. package/backend/dist/backup/engine.js +280 -0
  9. package/backend/dist/backup/engine.js.map +1 -0
  10. package/backend/dist/backup/providers/dropbox.d.ts +25 -0
  11. package/backend/dist/backup/providers/dropbox.d.ts.map +1 -0
  12. package/backend/dist/backup/providers/dropbox.js +319 -0
  13. package/backend/dist/backup/providers/dropbox.js.map +1 -0
  14. package/backend/dist/backup/providers/google-drive.d.ts +29 -0
  15. package/backend/dist/backup/providers/google-drive.d.ts.map +1 -0
  16. package/backend/dist/backup/providers/google-drive.js +305 -0
  17. package/backend/dist/backup/providers/google-drive.js.map +1 -0
  18. package/backend/dist/backup/providers/index.d.ts +3 -0
  19. package/backend/dist/backup/providers/index.d.ts.map +1 -0
  20. package/backend/dist/backup/providers/index.js +19 -0
  21. package/backend/dist/backup/providers/index.js.map +1 -0
  22. package/backend/dist/backup/providers/onedrive.d.ts +29 -0
  23. package/backend/dist/backup/providers/onedrive.d.ts.map +1 -0
  24. package/backend/dist/backup/providers/onedrive.js +316 -0
  25. package/backend/dist/backup/providers/onedrive.js.map +1 -0
  26. package/backend/dist/backup/scheduler.d.ts +6 -0
  27. package/backend/dist/backup/scheduler.d.ts.map +1 -0
  28. package/backend/dist/backup/scheduler.js +53 -0
  29. package/backend/dist/backup/scheduler.js.map +1 -0
  30. package/backend/dist/backup/types.d.ts +68 -0
  31. package/backend/dist/backup/types.d.ts.map +1 -0
  32. package/backend/dist/backup/types.js +4 -0
  33. package/backend/dist/backup/types.js.map +1 -0
  34. package/backend/dist/index.d.ts.map +1 -1
  35. package/backend/dist/index.js +74 -10
  36. package/backend/dist/index.js.map +1 -1
  37. package/backend/dist/routes/backup.d.ts +4 -0
  38. package/backend/dist/routes/backup.d.ts.map +1 -0
  39. package/backend/dist/routes/backup.js +175 -0
  40. package/backend/dist/routes/backup.js.map +1 -0
  41. package/backend/dist/routes/projects.d.ts.map +1 -1
  42. package/backend/dist/routes/projects.js +14 -0
  43. package/backend/dist/routes/projects.js.map +1 -1
  44. package/backend/dist/routes/sounds.d.ts +3 -0
  45. package/backend/dist/routes/sounds.d.ts.map +1 -0
  46. package/backend/dist/routes/sounds.js +283 -0
  47. package/backend/dist/routes/sounds.js.map +1 -0
  48. package/backend/package-lock.json +662 -20
  49. package/backend/package.json +8 -0
  50. package/bin/ccweb.js +33 -0
  51. package/frontend/dist/assets/index-D7gjxQKB.css +32 -0
  52. package/frontend/dist/assets/index-Dg1NcsQH.js +489 -0
  53. package/frontend/dist/index.html +2 -2
  54. package/package.json +1 -1
  55. package/frontend/dist/assets/index-CQjbS4zv.css +0 -32
  56. 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.11 | [GitHub](https://github.com/zbc0315/cc-web) | MIT License
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"}