@tom2012/cc-web 2026.6.17-b → 2026.9.6-c
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.json +96 -21
- package/backend/dist/adapters/claude-adapter.d.ts +4 -0
- package/backend/dist/adapters/claude-adapter.d.ts.map +1 -1
- package/backend/dist/adapters/claude-adapter.js +18 -2
- package/backend/dist/adapters/claude-adapter.js.map +1 -1
- package/backend/dist/adapters/types.d.ts +8 -0
- package/backend/dist/adapters/types.d.ts.map +1 -1
- package/backend/dist/auth.d.ts.map +0 -0
- package/backend/dist/config.d.ts +0 -0
- package/backend/dist/config.js +0 -0
- package/backend/dist/config.js.map +0 -0
- package/backend/dist/hooks-manager.d.ts +0 -1
- package/backend/dist/hooks-manager.d.ts.map +1 -1
- package/backend/dist/hooks-manager.js +19 -19
- package/backend/dist/hooks-manager.js.map +1 -1
- package/backend/dist/index.d.ts.map +1 -1
- package/backend/dist/index.js +76 -1
- package/backend/dist/index.js.map +1 -1
- package/backend/dist/logger.d.ts.map +1 -1
- package/backend/dist/logger.js +3 -0
- package/backend/dist/logger.js.map +1 -1
- package/backend/dist/routes/auth.d.ts +0 -0
- package/backend/dist/routes/auth.d.ts.map +0 -0
- package/backend/dist/routes/auth.js.map +0 -0
- package/backend/dist/routes/projects.d.ts.map +0 -0
- package/backend/dist/routes/projects.js.map +0 -0
- package/backend/dist/session-manager.d.ts +0 -0
- package/backend/dist/session-manager.d.ts.map +0 -0
- package/backend/dist/session-manager.js +0 -0
- package/backend/dist/session-manager.js.map +0 -0
- package/backend/dist/terminal-manager.d.ts +10 -1
- package/backend/dist/terminal-manager.d.ts.map +1 -1
- package/backend/dist/terminal-manager.js +19 -2
- package/backend/dist/terminal-manager.js.map +1 -1
- package/backend/dist/types.d.ts +0 -0
- package/backend/dist/types.d.ts.map +0 -0
- package/backend/dist/types.js +0 -0
- package/backend/dist/types.js.map +0 -0
- package/frontend/dist/assets/{ChatOverlay-Dp1BzsYb.js → ChatOverlay-CymdKeQK.js} +1 -1
- package/frontend/dist/assets/{ClaudeMemPage-CpzMjJnb.js → ClaudeMemPage-BZ4UtUoz.js} +1 -1
- package/frontend/dist/assets/{GraphPreview-DDY1yVOX.js → GraphPreview-21EwV_e_.js} +1 -1
- package/frontend/dist/assets/{MobilePage-BnnE820D.js → MobilePage-99vv9cWh.js} +3 -3
- package/frontend/dist/assets/{NotebookPage-BOiYcs-l.js → NotebookPage-B-mcSRJm.js} +1 -1
- package/frontend/dist/assets/{OfficePreview-C5N2gr8-.js → OfficePreview-C3rHS2Te.js} +2 -2
- package/frontend/dist/assets/{PdfPreview-COG-9AQa.js → PdfPreview-B-toyaoA.js} +1 -1
- package/frontend/dist/assets/{ProjectPage-ARPH_J5o.js → ProjectPage-CShqyrUl.js} +4 -4
- package/frontend/dist/assets/{ProjectSettingsPage-CMWcT-5r.js → ProjectSettingsPage-FxkEGuUP.js} +1 -1
- package/frontend/dist/assets/{SettingsPage-BMrIDtg8.js → SettingsPage-B-bqNp6b.js} +1 -1
- package/frontend/dist/assets/{SkillHubPage-Bq93A7Rt.js → SkillHubPage-DN79j9Is.js} +1 -1
- package/frontend/dist/assets/{check-circle-2-BGT1eH1f.js → check-circle-2-DRT7EX5I.js} +1 -1
- package/frontend/dist/assets/{chevron-down-Bbg11n9i.js → chevron-down-DdtdiM4b.js} +1 -1
- package/frontend/dist/assets/{chevron-left-BmStQriC.js → chevron-left-Chv-EE6G.js} +1 -1
- package/frontend/dist/assets/{file-text-D9WjmbhK.js → file-text-D3ZDULSr.js} +1 -1
- package/frontend/dist/assets/{index-EFhMcMWk.js → index-BIGQ6n-i.js} +2 -2
- package/frontend/dist/assets/index-BpdaJxoa.css +1 -0
- package/frontend/dist/assets/{index-BRqvDxO6.js → index-CH1oLpmL.js} +1 -1
- package/frontend/dist/assets/{index-Bhp9CVTp.js → index-Dbm49BgL.js} +1 -1
- package/frontend/dist/assets/{index-COZnAgez.js → index-xJR85RJZ.js} +1 -1
- package/frontend/dist/assets/{jszip.min-Dyo__hKc.js → jszip.min-CMcZF4_M.js} +1 -1
- package/frontend/dist/assets/{save-CAjdgnp7.js → save-Dhw-I0uF.js} +1 -1
- package/frontend/dist/assets/{search-DmWhhICR.js → search-zoOED2R0.js} +1 -1
- package/frontend/dist/assets/{select-DAfsBGCS.js → select-B7xEE81_.js} +1 -1
- package/frontend/dist/assets/{tabs-zra46FZv.js → tabs-BCHX4LWy.js} +1 -1
- package/frontend/dist/assets/{textarea-BG4Tvy0e.js → textarea-CGPmR1Ae.js} +1 -1
- package/frontend/dist/index.html +2 -2
- package/package.json +36 -10
- package/backend/dist/backup/config.d.ts +0 -10
- package/backend/dist/backup/config.d.ts.map +0 -1
- package/backend/dist/backup/config.js +0 -128
- package/backend/dist/backup/config.js.map +0 -1
- package/backend/dist/backup/engine.d.ts +0 -22
- package/backend/dist/backup/engine.d.ts.map +0 -1
- package/backend/dist/backup/engine.js +0 -298
- package/backend/dist/backup/engine.js.map +0 -1
- package/backend/dist/backup/providers/dropbox.d.ts +0 -25
- package/backend/dist/backup/providers/dropbox.d.ts.map +0 -1
- package/backend/dist/backup/providers/dropbox.js +0 -320
- package/backend/dist/backup/providers/dropbox.js.map +0 -1
- package/backend/dist/backup/providers/google-drive.d.ts +0 -29
- package/backend/dist/backup/providers/google-drive.d.ts.map +0 -1
- package/backend/dist/backup/providers/google-drive.js +0 -303
- package/backend/dist/backup/providers/google-drive.js.map +0 -1
- package/backend/dist/backup/providers/index.d.ts +0 -3
- package/backend/dist/backup/providers/index.d.ts.map +0 -1
- package/backend/dist/backup/providers/index.js +0 -19
- package/backend/dist/backup/providers/index.js.map +0 -1
- package/backend/dist/backup/providers/onedrive.d.ts +0 -29
- package/backend/dist/backup/providers/onedrive.d.ts.map +0 -1
- package/backend/dist/backup/providers/onedrive.js +0 -317
- package/backend/dist/backup/providers/onedrive.js.map +0 -1
- package/backend/dist/backup/scheduler.d.ts +0 -6
- package/backend/dist/backup/scheduler.d.ts.map +0 -1
- package/backend/dist/backup/scheduler.js +0 -55
- package/backend/dist/backup/scheduler.js.map +0 -1
- package/backend/dist/backup/types.d.ts +0 -73
- package/backend/dist/backup/types.d.ts.map +0 -1
- package/backend/dist/backup/types.js +0 -4
- package/backend/dist/backup/types.js.map +0 -1
- package/backend/dist/chat-process-manager.d.ts +0 -45
- package/backend/dist/chat-process-manager.d.ts.map +0 -1
- package/backend/dist/chat-process-manager.js +0 -258
- package/backend/dist/chat-process-manager.js.map +0 -1
- package/backend/dist/flows/runner.d.ts +0 -37
- package/backend/dist/flows/runner.d.ts.map +0 -1
- package/backend/dist/flows/runner.js +0 -660
- package/backend/dist/flows/runner.js.map +0 -1
- package/backend/dist/flows/store.d.ts +0 -40
- package/backend/dist/flows/store.d.ts.map +0 -1
- package/backend/dist/flows/store.js +0 -284
- package/backend/dist/flows/store.js.map +0 -1
- package/backend/dist/flows/types.d.ts +0 -176
- package/backend/dist/flows/types.d.ts.map +0 -1
- package/backend/dist/flows/types.js +0 -25
- package/backend/dist/flows/types.js.map +0 -1
- package/backend/dist/information/condenser.d.ts +0 -12
- package/backend/dist/information/condenser.d.ts.map +0 -1
- package/backend/dist/information/condenser.js +0 -568
- package/backend/dist/information/condenser.js.map +0 -1
- package/backend/dist/information/conversation-sync.d.ts +0 -22
- package/backend/dist/information/conversation-sync.d.ts.map +0 -1
- package/backend/dist/information/conversation-sync.js +0 -500
- package/backend/dist/information/conversation-sync.js.map +0 -1
- package/backend/dist/information/types.d.ts +0 -36
- package/backend/dist/information/types.d.ts.map +0 -1
- package/backend/dist/information/types.js +0 -4
- package/backend/dist/information/types.js.map +0 -1
- package/backend/dist/memory-pool/buoyancy.d.ts +0 -2
- package/backend/dist/memory-pool/buoyancy.d.ts.map +0 -1
- package/backend/dist/memory-pool/buoyancy.js +0 -12
- package/backend/dist/memory-pool/buoyancy.js.map +0 -1
- package/backend/dist/memory-pool/global-pool-manager.d.ts +0 -12
- package/backend/dist/memory-pool/global-pool-manager.d.ts.map +0 -1
- package/backend/dist/memory-pool/global-pool-manager.js +0 -295
- package/backend/dist/memory-pool/global-pool-manager.js.map +0 -1
- package/backend/dist/memory-pool/pool-lock.d.ts +0 -2
- package/backend/dist/memory-pool/pool-lock.d.ts.map +0 -1
- package/backend/dist/memory-pool/pool-lock.js +0 -31
- package/backend/dist/memory-pool/pool-lock.js.map +0 -1
- package/backend/dist/memory-pool/pool-manager.d.ts +0 -57
- package/backend/dist/memory-pool/pool-manager.d.ts.map +0 -1
- package/backend/dist/memory-pool/pool-manager.js +0 -322
- package/backend/dist/memory-pool/pool-manager.js.map +0 -1
- package/backend/dist/memory-pool/templates.d.ts +0 -5
- package/backend/dist/memory-pool/templates.d.ts.map +0 -1
- package/backend/dist/memory-pool/templates.js +0 -234
- package/backend/dist/memory-pool/templates.js.map +0 -1
- package/backend/dist/memory-pool/types.d.ts +0 -61
- package/backend/dist/memory-pool/types.d.ts.map +0 -1
- package/backend/dist/memory-pool/types.js +0 -4
- package/backend/dist/memory-pool/types.js.map +0 -1
- package/backend/dist/plan-control/checker.d.ts +0 -3
- package/backend/dist/plan-control/checker.d.ts.map +0 -1
- package/backend/dist/plan-control/checker.js +0 -103
- package/backend/dist/plan-control/checker.js.map +0 -1
- package/backend/dist/plan-control/executor.d.ts +0 -93
- package/backend/dist/plan-control/executor.d.ts.map +0 -1
- package/backend/dist/plan-control/executor.js +0 -955
- package/backend/dist/plan-control/executor.js.map +0 -1
- package/backend/dist/plan-control/parser.d.ts +0 -12
- package/backend/dist/plan-control/parser.d.ts.map +0 -1
- package/backend/dist/plan-control/parser.js +0 -216
- package/backend/dist/plan-control/parser.js.map +0 -1
- package/backend/dist/plan-control/templates.d.ts +0 -4
- package/backend/dist/plan-control/templates.d.ts.map +0 -1
- package/backend/dist/plan-control/templates.js +0 -271
- package/backend/dist/plan-control/templates.js.map +0 -1
- package/backend/dist/plan-control/types.d.ts +0 -102
- package/backend/dist/plan-control/types.d.ts.map +0 -1
- package/backend/dist/plan-control/types.js +0 -12
- package/backend/dist/plan-control/types.js.map +0 -1
- package/backend/dist/routes/backup.d.ts +0 -4
- package/backend/dist/routes/backup.d.ts.map +0 -1
- package/backend/dist/routes/backup.js +0 -274
- package/backend/dist/routes/backup.js.map +0 -1
- package/backend/dist/routes/flows.d.ts +0 -5
- package/backend/dist/routes/flows.d.ts.map +0 -1
- package/backend/dist/routes/flows.js +0 -457
- package/backend/dist/routes/flows.js.map +0 -1
- package/backend/dist/routes/global-flows.d.ts +0 -3
- package/backend/dist/routes/global-flows.d.ts.map +0 -1
- package/backend/dist/routes/global-flows.js +0 -90
- package/backend/dist/routes/global-flows.js.map +0 -1
- package/backend/dist/routes/information.d.ts +0 -3
- package/backend/dist/routes/information.d.ts.map +0 -1
- package/backend/dist/routes/information.js +0 -159
- package/backend/dist/routes/information.js.map +0 -1
- package/backend/dist/routes/memory-pool.d.ts +0 -3
- package/backend/dist/routes/memory-pool.d.ts.map +0 -1
- package/backend/dist/routes/memory-pool.js +0 -837
- package/backend/dist/routes/memory-pool.js.map +0 -1
- package/backend/dist/routes/plan-control.d.ts +0 -15
- package/backend/dist/routes/plan-control.d.ts.map +0 -1
- package/backend/dist/routes/plan-control.js +0 -337
- package/backend/dist/routes/plan-control.js.map +0 -1
- package/backend/dist/routes/share.d.ts +0 -3
- package/backend/dist/routes/share.d.ts.map +0 -1
- package/backend/dist/routes/share.js +0 -167
- package/backend/dist/routes/share.js.map +0 -1
- package/backend/dist/routes/sounds.d.ts +0 -3
- package/backend/dist/routes/sounds.d.ts.map +0 -1
- package/backend/dist/routes/sounds.js +0 -285
- package/backend/dist/routes/sounds.js.map +0 -1
- package/backend/dist/tracks/__tests__/verify-starter-templates.d.ts +0 -24
- package/backend/dist/tracks/__tests__/verify-starter-templates.d.ts.map +0 -1
- package/backend/dist/tracks/__tests__/verify-starter-templates.js +0 -175
- package/backend/dist/tracks/__tests__/verify-starter-templates.js.map +0 -1
- package/backend/dist/tracks/__tests__/verify-track-cancel.d.ts +0 -23
- package/backend/dist/tracks/__tests__/verify-track-cancel.d.ts.map +0 -1
- package/backend/dist/tracks/__tests__/verify-track-cancel.js +0 -153
- package/backend/dist/tracks/__tests__/verify-track-cancel.js.map +0 -1
- package/backend/dist/tracks/__tests__/verify-track-t1.d.ts +0 -11
- package/backend/dist/tracks/__tests__/verify-track-t1.d.ts.map +0 -1
- package/backend/dist/tracks/__tests__/verify-track-t1.js +0 -293
- package/backend/dist/tracks/__tests__/verify-track-t1.js.map +0 -1
- package/backend/dist/tracks/__tests__/verify-track.d.ts +0 -20
- package/backend/dist/tracks/__tests__/verify-track.d.ts.map +0 -1
- package/backend/dist/tracks/__tests__/verify-track.js +0 -187
- package/backend/dist/tracks/__tests__/verify-track.js.map +0 -1
- package/backend/dist/tracks/registry.d.ts +0 -61
- package/backend/dist/tracks/registry.d.ts.map +0 -1
- package/backend/dist/tracks/registry.js +0 -202
- package/backend/dist/tracks/registry.js.map +0 -1
- package/backend/dist/tracks/track-runner.d.ts +0 -69
- package/backend/dist/tracks/track-runner.d.ts.map +0 -1
- package/backend/dist/tracks/track-runner.js +0 -158
- package/backend/dist/tracks/track-runner.js.map +0 -1
- package/backend/dist/tracks/train-loader.d.ts +0 -44
- package/backend/dist/tracks/train-loader.d.ts.map +0 -1
- package/backend/dist/tracks/train-loader.js +0 -32
- package/backend/dist/tracks/train-loader.js.map +0 -1
- package/backend/dist/tracks/types-train.d.ts +0 -12
- package/backend/dist/tracks/types-train.d.ts.map +0 -1
- package/backend/dist/tracks/types-train.js +0 -13
- package/backend/dist/tracks/types-train.js.map +0 -1
- package/backend/dist/usage-terminal.d.ts +0 -18
- package/backend/dist/usage-terminal.d.ts.map +0 -1
- package/backend/dist/usage-terminal.js +0 -191
- package/backend/dist/usage-terminal.js.map +0 -1
- package/frontend/dist/assets/index-GfCaMXPO.css +0 -1
|
@@ -1,298 +0,0 @@
|
|
|
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
|
-
return new Promise((resolve, reject) => {
|
|
52
|
-
const hash = crypto.createHash('sha256');
|
|
53
|
-
const stream = fs.createReadStream(filePath);
|
|
54
|
-
stream.on('data', (chunk) => hash.update(chunk));
|
|
55
|
-
stream.on('end', () => resolve(`sha256:${hash.digest('hex')}`));
|
|
56
|
-
stream.on('error', reject);
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
function shouldExclude(relativePath, patterns) {
|
|
60
|
-
const segments = relativePath.split('/');
|
|
61
|
-
for (const pattern of patterns) {
|
|
62
|
-
// Match full relative path
|
|
63
|
-
if ((0, minimatch_1.minimatch)(relativePath, pattern, { dot: true, matchBase: true })) {
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
// Match each path segment individually
|
|
67
|
-
for (const segment of segments) {
|
|
68
|
-
if ((0, minimatch_1.minimatch)(segment, pattern, { dot: true, matchBase: true })) {
|
|
69
|
-
return true;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
const MAX_SCAN_DEPTH = 50;
|
|
76
|
-
function scanDirectory(dirPath, excludePatterns, basePath, depth = 0) {
|
|
77
|
-
const result = new Map();
|
|
78
|
-
if (depth > MAX_SCAN_DEPTH)
|
|
79
|
-
return result; // prevent symlink cycles
|
|
80
|
-
const base = basePath ?? dirPath;
|
|
81
|
-
let entries;
|
|
82
|
-
try {
|
|
83
|
-
entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
return result;
|
|
87
|
-
}
|
|
88
|
-
for (const entry of entries) {
|
|
89
|
-
const fullPath = path.join(dirPath, entry.name);
|
|
90
|
-
const relativePath = path.relative(base, fullPath).replace(/\\/g, '/');
|
|
91
|
-
if (shouldExclude(relativePath, excludePatterns)) {
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
if (entry.isDirectory()) {
|
|
95
|
-
const subResult = scanDirectory(fullPath, excludePatterns, base, depth + 1);
|
|
96
|
-
for (const [relPath, info] of subResult) {
|
|
97
|
-
result.set(relPath, info);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
else if (entry.isFile()) {
|
|
101
|
-
try {
|
|
102
|
-
const stat = fs.statSync(fullPath);
|
|
103
|
-
result.set(relativePath, {
|
|
104
|
-
mtime: stat.mtimeMs,
|
|
105
|
-
size: stat.size,
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
// Skip unreadable files
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return result;
|
|
114
|
-
}
|
|
115
|
-
async function runBackup(projectId, onProgress) {
|
|
116
|
-
const config = (0, config_1.getBackupConfig)();
|
|
117
|
-
const authorizedProviders = config.providers.filter((p) => p.tokens);
|
|
118
|
-
if (authorizedProviders.length === 0) {
|
|
119
|
-
return [];
|
|
120
|
-
}
|
|
121
|
-
const projects = (0, config_2.getProjects)();
|
|
122
|
-
const project = projects.find((p) => p.id === projectId && !p.archived);
|
|
123
|
-
if (!project) {
|
|
124
|
-
throw new Error(`Project ${projectId} not found or archived`);
|
|
125
|
-
}
|
|
126
|
-
if (!fs.existsSync(project.folderPath)) {
|
|
127
|
-
throw new Error(`Project folder does not exist: ${project.folderPath}`);
|
|
128
|
-
}
|
|
129
|
-
const excludePatterns = config.excludePatterns ?? [];
|
|
130
|
-
// Step 1: Scan local files
|
|
131
|
-
const scanned = scanDirectory(project.folderPath, excludePatterns);
|
|
132
|
-
// Step 2: Load previous backup state
|
|
133
|
-
const prevState = (0, config_1.getBackupState)(project.folderPath);
|
|
134
|
-
// Step 3: Determine which files need uploading (changed or new)
|
|
135
|
-
const newFiles = {};
|
|
136
|
-
const toUpload = []; // relative paths
|
|
137
|
-
for (const [relPath, { mtime, size }] of scanned) {
|
|
138
|
-
const prev = prevState.files[relPath];
|
|
139
|
-
if (prev && prev.mtime === mtime && prev.size === size) {
|
|
140
|
-
// Unchanged: keep previous snapshot
|
|
141
|
-
newFiles[relPath] = prev;
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
// Changed or new: compute hash
|
|
145
|
-
const fullPath = path.join(project.folderPath, relPath);
|
|
146
|
-
let hash;
|
|
147
|
-
try {
|
|
148
|
-
hash = await computeHash(fullPath);
|
|
149
|
-
}
|
|
150
|
-
catch {
|
|
151
|
-
// Unreadable file, skip
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
if (prev && prev.hash === hash) {
|
|
155
|
-
// Content unchanged, just update mtime/size
|
|
156
|
-
newFiles[relPath] = { mtime, size, hash };
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
// Content changed: queue for upload
|
|
160
|
-
newFiles[relPath] = { mtime, size, hash };
|
|
161
|
-
toUpload.push(relPath);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
// Step 4: Detect deletions (files in prev state no longer present locally)
|
|
166
|
-
const toDelete = [];
|
|
167
|
-
for (const relPath of Object.keys(prevState.files)) {
|
|
168
|
-
if (!scanned.has(relPath)) {
|
|
169
|
-
toDelete.push(relPath);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
const totalFiles = scanned.size;
|
|
173
|
-
const startTime = new Date().toISOString();
|
|
174
|
-
const results = [];
|
|
175
|
-
// Step 5: Run backup for each provider in parallel
|
|
176
|
-
const providerResults = await Promise.all(authorizedProviders.map(async (providerConfig) => {
|
|
177
|
-
const provider = (0, providers_1.createProvider)(providerConfig);
|
|
178
|
-
let filesUploaded = 0;
|
|
179
|
-
let filesDeleted = 0;
|
|
180
|
-
let entryStatus = 'success';
|
|
181
|
-
let errorMsg;
|
|
182
|
-
const reportProgress = (status, uploaded = filesUploaded, deleted = filesDeleted) => {
|
|
183
|
-
onProgress?.({
|
|
184
|
-
projectId,
|
|
185
|
-
projectName: project.name,
|
|
186
|
-
providerId: providerConfig.id,
|
|
187
|
-
providerLabel: providerConfig.label,
|
|
188
|
-
status,
|
|
189
|
-
filesUploaded: uploaded,
|
|
190
|
-
filesDeleted: deleted,
|
|
191
|
-
filesTotal: totalFiles,
|
|
192
|
-
});
|
|
193
|
-
};
|
|
194
|
-
try {
|
|
195
|
-
const tokensBefore = JSON.stringify(providerConfig.tokens);
|
|
196
|
-
await provider.ensureAuth();
|
|
197
|
-
// Persist refreshed tokens to disk if they changed
|
|
198
|
-
// Re-read config to avoid overwriting other providers' token changes
|
|
199
|
-
if (JSON.stringify(providerConfig.tokens) !== tokensBefore) {
|
|
200
|
-
const freshConfig = (0, config_1.getBackupConfig)();
|
|
201
|
-
const freshIdx = freshConfig.providers.findIndex((p) => p.id === providerConfig.id);
|
|
202
|
-
if (freshIdx >= 0) {
|
|
203
|
-
freshConfig.providers[freshIdx] = { ...freshConfig.providers[freshIdx], tokens: providerConfig.tokens };
|
|
204
|
-
(0, config_1.saveBackupConfig)(freshConfig);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
// Create base remote directory
|
|
208
|
-
const baseRemotePath = `CCWeb/${project.name}`;
|
|
209
|
-
await provider.mkdir(baseRemotePath);
|
|
210
|
-
// Upload changed files
|
|
211
|
-
reportProgress('uploading');
|
|
212
|
-
for (const relPath of toUpload) {
|
|
213
|
-
const localPath = path.join(project.folderPath, relPath);
|
|
214
|
-
const remotePath = `${baseRemotePath}/${relPath}`;
|
|
215
|
-
// Ensure parent directory exists
|
|
216
|
-
const remoteDir = path.dirname(remotePath).replace(/\\/g, '/');
|
|
217
|
-
if (remoteDir !== baseRemotePath) {
|
|
218
|
-
await provider.mkdir(remoteDir);
|
|
219
|
-
}
|
|
220
|
-
try {
|
|
221
|
-
await provider.uploadFile(localPath, remotePath);
|
|
222
|
-
filesUploaded++;
|
|
223
|
-
reportProgress('uploading');
|
|
224
|
-
}
|
|
225
|
-
catch (err) {
|
|
226
|
-
// Continue on individual file error
|
|
227
|
-
entryStatus = 'partial';
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
// Delete orphaned remote files
|
|
231
|
-
reportProgress('deleting', filesUploaded, filesDeleted);
|
|
232
|
-
for (const relPath of toDelete) {
|
|
233
|
-
const remotePath = `${baseRemotePath}/${relPath}`;
|
|
234
|
-
try {
|
|
235
|
-
await provider.deleteFile(remotePath);
|
|
236
|
-
filesDeleted++;
|
|
237
|
-
reportProgress('deleting', filesUploaded, filesDeleted);
|
|
238
|
-
}
|
|
239
|
-
catch {
|
|
240
|
-
// Ignore delete errors (file may already be gone)
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
reportProgress('done', filesUploaded, filesDeleted);
|
|
244
|
-
}
|
|
245
|
-
catch (err) {
|
|
246
|
-
entryStatus = 'failed';
|
|
247
|
-
errorMsg = err?.message ?? String(err);
|
|
248
|
-
reportProgress('error', filesUploaded, filesDeleted);
|
|
249
|
-
}
|
|
250
|
-
const endTime = new Date().toISOString();
|
|
251
|
-
const entry = {
|
|
252
|
-
id: (0, uuid_1.v4)(),
|
|
253
|
-
projectId,
|
|
254
|
-
projectName: project.name,
|
|
255
|
-
providerId: providerConfig.id,
|
|
256
|
-
providerType: providerConfig.type,
|
|
257
|
-
providerLabel: providerConfig.label,
|
|
258
|
-
startTime,
|
|
259
|
-
endTime,
|
|
260
|
-
status: entryStatus,
|
|
261
|
-
filesUploaded,
|
|
262
|
-
filesDeleted,
|
|
263
|
-
filesTotal: totalFiles,
|
|
264
|
-
error: errorMsg,
|
|
265
|
-
};
|
|
266
|
-
return { entry, success: entryStatus !== 'failed' };
|
|
267
|
-
}));
|
|
268
|
-
// Step 6: If any provider succeeded, save new backup state
|
|
269
|
-
const anySuccess = providerResults.some((r) => r.success);
|
|
270
|
-
if (anySuccess) {
|
|
271
|
-
const newState = {
|
|
272
|
-
lastBackupTime: new Date().toISOString(),
|
|
273
|
-
files: newFiles,
|
|
274
|
-
};
|
|
275
|
-
(0, config_1.saveBackupState)(project.folderPath, newState);
|
|
276
|
-
}
|
|
277
|
-
// Step 7: Save history entries and collect results
|
|
278
|
-
for (const { entry } of providerResults) {
|
|
279
|
-
(0, config_1.addBackupHistory)(entry);
|
|
280
|
-
results.push(entry);
|
|
281
|
-
}
|
|
282
|
-
return results;
|
|
283
|
-
}
|
|
284
|
-
async function runBackupAll(onProgress) {
|
|
285
|
-
const projects = (0, config_2.getProjects)().filter((p) => !p.archived);
|
|
286
|
-
const allResults = [];
|
|
287
|
-
for (const project of projects) {
|
|
288
|
-
try {
|
|
289
|
-
const entries = await runBackup(project.id, onProgress);
|
|
290
|
-
allResults.push(...entries);
|
|
291
|
-
}
|
|
292
|
-
catch {
|
|
293
|
-
// Continue with other projects
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
return allResults;
|
|
297
|
-
}
|
|
298
|
-
//# sourceMappingURL=engine.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/backup/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,25 +0,0 @@
|
|
|
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, state?: 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
|
|
@@ -1 +0,0 @@
|
|
|
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,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAWjD,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"}
|
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// backend/src/backup/providers/dropbox.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.DropboxProvider = void 0;
|
|
38
|
-
const fs = __importStar(require("fs"));
|
|
39
|
-
const path = __importStar(require("path"));
|
|
40
|
-
const dropbox_1 = require("dropbox");
|
|
41
|
-
const TOKEN_ENDPOINT = 'https://api.dropboxapi.com/oauth2/token';
|
|
42
|
-
// 150 MB threshold: above this use chunked upload session
|
|
43
|
-
const SIMPLE_UPLOAD_MAX = 150 * 1024 * 1024;
|
|
44
|
-
// 8 MB chunk size for upload sessions
|
|
45
|
-
const CHUNK_SIZE = 8 * 1024 * 1024;
|
|
46
|
-
class DropboxProvider {
|
|
47
|
-
constructor(config) {
|
|
48
|
-
this.dbx = null;
|
|
49
|
-
this.config = config;
|
|
50
|
-
if (config.tokens) {
|
|
51
|
-
this.initClient(config.tokens.access_token);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
initClient(accessToken) {
|
|
55
|
-
this.dbx = new dropbox_1.Dropbox({ accessToken });
|
|
56
|
-
}
|
|
57
|
-
client() {
|
|
58
|
-
if (!this.dbx) {
|
|
59
|
-
throw new Error('Dropbox client is not initialized');
|
|
60
|
-
}
|
|
61
|
-
return this.dbx;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Normalize a path to Dropbox format:
|
|
65
|
-
* - Root is empty string ''
|
|
66
|
-
* - All other paths start with '/' and have no trailing slash
|
|
67
|
-
*/
|
|
68
|
-
normPath(remotePath) {
|
|
69
|
-
// Strip leading/trailing slashes then re-add leading slash if non-empty
|
|
70
|
-
const stripped = remotePath.replace(/^\/+|\/+$/g, '');
|
|
71
|
-
if (!stripped)
|
|
72
|
-
return '';
|
|
73
|
-
return '/' + stripped;
|
|
74
|
-
}
|
|
75
|
-
getAuthUrl(redirectUri, state) {
|
|
76
|
-
const params = new URLSearchParams({
|
|
77
|
-
client_id: this.config.clientId,
|
|
78
|
-
response_type: 'code',
|
|
79
|
-
redirect_uri: redirectUri,
|
|
80
|
-
token_access_type: 'offline',
|
|
81
|
-
...(state ? { state } : {}),
|
|
82
|
-
});
|
|
83
|
-
return `https://www.dropbox.com/oauth2/authorize?${params.toString()}`;
|
|
84
|
-
}
|
|
85
|
-
async handleCallback(code, redirectUri) {
|
|
86
|
-
const body = new URLSearchParams({
|
|
87
|
-
code,
|
|
88
|
-
grant_type: 'authorization_code',
|
|
89
|
-
redirect_uri: redirectUri,
|
|
90
|
-
});
|
|
91
|
-
const credentials = Buffer.from(`${this.config.clientId}:${this.config.clientSecret}`).toString('base64');
|
|
92
|
-
const res = await fetch(TOKEN_ENDPOINT, {
|
|
93
|
-
method: 'POST',
|
|
94
|
-
headers: {
|
|
95
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
96
|
-
Authorization: `Basic ${credentials}`,
|
|
97
|
-
},
|
|
98
|
-
body: body.toString(),
|
|
99
|
-
});
|
|
100
|
-
if (!res.ok) {
|
|
101
|
-
const text = await res.text();
|
|
102
|
-
throw new Error(`Dropbox token exchange failed: ${res.status} ${text}`);
|
|
103
|
-
}
|
|
104
|
-
const data = (await res.json());
|
|
105
|
-
if (!data.access_token || !data.refresh_token) {
|
|
106
|
-
throw new Error('Missing tokens in Dropbox OAuth2 callback response');
|
|
107
|
-
}
|
|
108
|
-
const providerTokens = {
|
|
109
|
-
access_token: data.access_token,
|
|
110
|
-
refresh_token: data.refresh_token,
|
|
111
|
-
expiry: new Date(Date.now() + data.expires_in * 1000).toISOString(),
|
|
112
|
-
};
|
|
113
|
-
this.config.tokens = providerTokens;
|
|
114
|
-
this.initClient(providerTokens.access_token);
|
|
115
|
-
return providerTokens;
|
|
116
|
-
}
|
|
117
|
-
async refreshToken() {
|
|
118
|
-
if (!this.config.tokens?.refresh_token) {
|
|
119
|
-
throw new Error('No refresh token available for Dropbox provider');
|
|
120
|
-
}
|
|
121
|
-
const body = new URLSearchParams({
|
|
122
|
-
grant_type: 'refresh_token',
|
|
123
|
-
refresh_token: this.config.tokens.refresh_token,
|
|
124
|
-
});
|
|
125
|
-
const credentials = Buffer.from(`${this.config.clientId}:${this.config.clientSecret}`).toString('base64');
|
|
126
|
-
const res = await fetch(TOKEN_ENDPOINT, {
|
|
127
|
-
method: 'POST',
|
|
128
|
-
headers: {
|
|
129
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
130
|
-
Authorization: `Basic ${credentials}`,
|
|
131
|
-
},
|
|
132
|
-
body: body.toString(),
|
|
133
|
-
});
|
|
134
|
-
if (!res.ok) {
|
|
135
|
-
const text = await res.text();
|
|
136
|
-
throw new Error(`Dropbox token refresh failed: ${res.status} ${text}`);
|
|
137
|
-
}
|
|
138
|
-
const data = (await res.json());
|
|
139
|
-
if (!data.access_token) {
|
|
140
|
-
throw new Error('Failed to refresh Dropbox access token');
|
|
141
|
-
}
|
|
142
|
-
const providerTokens = {
|
|
143
|
-
access_token: data.access_token,
|
|
144
|
-
refresh_token: data.refresh_token ?? this.config.tokens.refresh_token,
|
|
145
|
-
expiry: new Date(Date.now() + data.expires_in * 1000).toISOString(),
|
|
146
|
-
};
|
|
147
|
-
this.config.tokens = providerTokens;
|
|
148
|
-
this.initClient(providerTokens.access_token);
|
|
149
|
-
return providerTokens;
|
|
150
|
-
}
|
|
151
|
-
isAuthorized() {
|
|
152
|
-
return !!(this.config.tokens?.access_token && this.config.tokens?.refresh_token);
|
|
153
|
-
}
|
|
154
|
-
async ensureAuth() {
|
|
155
|
-
if (!this.isAuthorized()) {
|
|
156
|
-
throw new Error('Dropbox provider is not authorized');
|
|
157
|
-
}
|
|
158
|
-
const tokens = this.config.tokens;
|
|
159
|
-
const expiryMs = new Date(tokens.expiry).getTime();
|
|
160
|
-
const nowMs = Date.now();
|
|
161
|
-
// Refresh if within 60 seconds of expiry
|
|
162
|
-
if (expiryMs - nowMs < 60 * 1000) {
|
|
163
|
-
await this.refreshToken();
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
async listFiles(remotePath) {
|
|
167
|
-
await this.ensureAuth();
|
|
168
|
-
const dbxPath = this.normPath(remotePath);
|
|
169
|
-
const results = [];
|
|
170
|
-
let response = await this.client().filesListFolder({ path: dbxPath });
|
|
171
|
-
while (true) {
|
|
172
|
-
for (const entry of response.result.entries) {
|
|
173
|
-
const isDirectory = entry['.tag'] === 'folder';
|
|
174
|
-
const entryPath = entry.path_display ?? entry.path_lower ?? entry.name;
|
|
175
|
-
// Return path relative to remotePath base (strip leading slash)
|
|
176
|
-
const normalizedBase = remotePath.replace(/^\/+|\/+$/g, '');
|
|
177
|
-
const relPath = normalizedBase
|
|
178
|
-
? `${normalizedBase}/${entry.name}`
|
|
179
|
-
: entry.name;
|
|
180
|
-
results.push({
|
|
181
|
-
name: entry.name,
|
|
182
|
-
path: relPath,
|
|
183
|
-
isDirectory,
|
|
184
|
-
size: isDirectory ? 0 : (entry.size ?? 0),
|
|
185
|
-
modifiedTime: isDirectory
|
|
186
|
-
? new Date().toISOString()
|
|
187
|
-
: (entry.server_modified ?? new Date().toISOString()),
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
if (!response.result.has_more)
|
|
191
|
-
break;
|
|
192
|
-
response = await this.client().filesListFolderContinue({
|
|
193
|
-
cursor: response.result.cursor,
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
return results;
|
|
197
|
-
}
|
|
198
|
-
async uploadFile(localPath, remotePath) {
|
|
199
|
-
await this.ensureAuth();
|
|
200
|
-
const dbxPath = this.normPath(remotePath);
|
|
201
|
-
const stat = fs.statSync(localPath);
|
|
202
|
-
const fileSize = stat.size;
|
|
203
|
-
if (fileSize < SIMPLE_UPLOAD_MAX) {
|
|
204
|
-
// Simple upload
|
|
205
|
-
const fileContent = fs.readFileSync(localPath);
|
|
206
|
-
await this.client().filesUpload({
|
|
207
|
-
path: dbxPath,
|
|
208
|
-
mode: { '.tag': 'overwrite' },
|
|
209
|
-
contents: fileContent,
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
else {
|
|
213
|
-
// Chunked upload session
|
|
214
|
-
const fd = fs.openSync(localPath, 'r');
|
|
215
|
-
try {
|
|
216
|
-
// Start upload session with first chunk
|
|
217
|
-
let offset = 0;
|
|
218
|
-
const firstChunkSize = Math.min(CHUNK_SIZE, fileSize);
|
|
219
|
-
const firstChunk = Buffer.alloc(firstChunkSize);
|
|
220
|
-
fs.readSync(fd, firstChunk, 0, firstChunkSize, 0);
|
|
221
|
-
offset += firstChunkSize;
|
|
222
|
-
const startRes = await this.client().filesUploadSessionStart({
|
|
223
|
-
close: false,
|
|
224
|
-
contents: firstChunk,
|
|
225
|
-
});
|
|
226
|
-
const sessionId = startRes.result.session_id;
|
|
227
|
-
// Append remaining chunks
|
|
228
|
-
while (offset < fileSize) {
|
|
229
|
-
const chunkSize = Math.min(CHUNK_SIZE, fileSize - offset);
|
|
230
|
-
const chunk = Buffer.alloc(chunkSize);
|
|
231
|
-
fs.readSync(fd, chunk, 0, chunkSize, offset);
|
|
232
|
-
const isLast = offset + chunkSize >= fileSize;
|
|
233
|
-
if (isLast) {
|
|
234
|
-
// Finish the session
|
|
235
|
-
await this.client().filesUploadSessionFinish({
|
|
236
|
-
cursor: { session_id: sessionId, offset },
|
|
237
|
-
commit: {
|
|
238
|
-
path: dbxPath,
|
|
239
|
-
mode: { '.tag': 'overwrite' },
|
|
240
|
-
},
|
|
241
|
-
contents: chunk,
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
245
|
-
await this.client().filesUploadSessionAppendV2({
|
|
246
|
-
cursor: { session_id: sessionId, offset },
|
|
247
|
-
close: false,
|
|
248
|
-
contents: chunk,
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
offset += chunkSize;
|
|
252
|
-
}
|
|
253
|
-
// Edge case: file exactly one chunk — finish with empty content
|
|
254
|
-
if (fileSize === firstChunkSize) {
|
|
255
|
-
await this.client().filesUploadSessionFinish({
|
|
256
|
-
cursor: { session_id: sessionId, offset },
|
|
257
|
-
commit: {
|
|
258
|
-
path: dbxPath,
|
|
259
|
-
mode: { '.tag': 'overwrite' },
|
|
260
|
-
},
|
|
261
|
-
contents: Buffer.alloc(0),
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
finally {
|
|
266
|
-
fs.closeSync(fd);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
async deleteFile(remotePath) {
|
|
271
|
-
await this.ensureAuth();
|
|
272
|
-
const dbxPath = this.normPath(remotePath);
|
|
273
|
-
try {
|
|
274
|
-
await this.client().filesDeleteV2({ path: dbxPath });
|
|
275
|
-
}
|
|
276
|
-
catch (err) {
|
|
277
|
-
// Ignore path_lookup errors (file not found) — treat as success
|
|
278
|
-
const errObj = err;
|
|
279
|
-
const summary = errObj?.error?.error_summary ?? '';
|
|
280
|
-
if (!summary.startsWith('path_lookup/')) {
|
|
281
|
-
throw err;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
async mkdir(remotePath) {
|
|
286
|
-
await this.ensureAuth();
|
|
287
|
-
const dbxPath = this.normPath(remotePath);
|
|
288
|
-
if (!dbxPath)
|
|
289
|
-
return; // root always exists
|
|
290
|
-
try {
|
|
291
|
-
await this.client().filesCreateFolderV2({ path: dbxPath });
|
|
292
|
-
}
|
|
293
|
-
catch (err) {
|
|
294
|
-
// Ignore path/conflict errors (folder already exists)
|
|
295
|
-
const errObj = err;
|
|
296
|
-
const summary = errObj?.error?.error_summary ?? '';
|
|
297
|
-
if (!summary.startsWith('path/conflict')) {
|
|
298
|
-
throw err;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
async downloadFile(remotePath, localPath) {
|
|
303
|
-
await this.ensureAuth();
|
|
304
|
-
const dbxPath = this.normPath(remotePath);
|
|
305
|
-
const res = await this.client().filesDownload({ path: dbxPath });
|
|
306
|
-
// The SDK returns the binary content as `fileBinary` in the result
|
|
307
|
-
const fileBinary = res.result.fileBinary;
|
|
308
|
-
if (!fileBinary) {
|
|
309
|
-
throw new Error(`Dropbox filesDownload returned no fileBinary for: ${remotePath}`);
|
|
310
|
-
}
|
|
311
|
-
// Ensure parent directory exists
|
|
312
|
-
const parentDir = path.dirname(localPath);
|
|
313
|
-
if (!fs.existsSync(parentDir)) {
|
|
314
|
-
fs.mkdirSync(parentDir, { recursive: true });
|
|
315
|
-
}
|
|
316
|
-
fs.writeFileSync(localPath, fileBinary);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
exports.DropboxProvider = DropboxProvider;
|
|
320
|
-
//# sourceMappingURL=dropbox.js.map
|