@ultrst-armada/kloks 1.4.3 → 1.4.5
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/package.json +8 -20
- package/packages/audio-midi/dist/index.d.ts +23 -14
- package/packages/audio-midi/dist/index.js +170 -45
- package/packages/audio-midi/kloks.manifest.json +8 -8
- package/packages/audio-midi/package.json +1 -1
- package/packages/backend/dist/{WebSocketTransport-CxUzUfwl.d.ts → WebSocketTransport-CHmkJ0tj.d.ts} +109 -2
- package/packages/backend/dist/auth/index.js +6 -6
- package/packages/backend/dist/{chunk-T3NYNBDC.js → chunk-5E6JRFUH.js} +201 -3
- package/packages/backend/dist/{chunk-XTWHEZWS.js → chunk-7B24ZWB3.js} +16 -1
- package/packages/backend/dist/chunk-DULUHQ5S.js +597 -0
- package/packages/backend/dist/{chunk-4ZFXEFOE.js → chunk-MPYASJ5A.js} +2 -87
- package/packages/backend/dist/{chunk-KX3OTBQ3.js → chunk-OZDYAEH4.js} +0 -114
- package/packages/backend/dist/{chunk-FO6WYLW4.js → chunk-TQMLJ7NY.js} +131 -44
- package/packages/backend/dist/chunk-TY32TUNI.js +376 -0
- package/packages/backend/dist/chunk-VDROUXFT.js +116 -0
- package/packages/backend/dist/chunk-ZDH4XI7W.js +140 -0
- package/packages/backend/dist/{chunk-DZ4ZGIZM.js → chunk-ZO3PZGNQ.js} +96 -655
- package/packages/backend/dist/client/index.d.ts +2 -3
- package/packages/backend/dist/connectivity/index.d.ts +18 -6
- package/packages/backend/dist/connectivity/index.js +3 -7
- package/packages/backend/dist/index.d.ts +3 -6
- package/packages/backend/dist/index.js +98 -88
- package/packages/backend/dist/krnl-services.d.ts +84 -7
- package/packages/backend/dist/krnl-services.js +40 -12
- package/packages/backend/dist/services/index.d.ts +4 -6
- package/packages/backend/dist/services/index.js +2 -2
- package/packages/backend/dist/srkl/index.js +6 -4
- package/packages/backend/dist/storage/index.js +7 -7
- package/packages/backend/dist/workspace/index.js +2 -2
- package/packages/backend/kloks.manifest.json +47 -45
- package/packages/backend/package.json +3 -8
- package/packages/client/package.json +1 -1
- package/packages/contracts/dist/index.js +5 -10
- package/packages/contracts/package.json +1 -1
- package/packages/functions/dist/index.d.ts +12 -1
- package/packages/functions/dist/index.js +132 -24
- package/packages/functions/package.json +1 -1
- package/packages/orchestrations/dist/index.d.ts +33 -31
- package/packages/orchestrations/dist/index.js +81 -203
- package/packages/orchestrations/kloks.manifest.json +10 -2
- package/packages/orchestrations/package.json +2 -2
- package/packages/services/dist/index.d.ts +51 -1
- package/packages/services/dist/index.js +234 -36
- package/packages/services/kloks.manifest.json +69 -33
- package/packages/services/package.json +1 -1
- package/packages/state-graph/dist/{BaseGraph-BvkSYOTw.d.ts → BaseGraph-Bd5F1NMP.d.ts} +1 -1
- package/packages/state-graph/dist/{BaseNode-DTcd3K1B.d.ts → BaseNode-DKpGXMy8.d.ts} +6 -0
- package/packages/state-graph/dist/{CompatibilityMatrix-Dj-tCWUA.d.ts → CompatibilityMatrix-TiEJ3j3_.d.ts} +1 -1
- package/packages/state-graph/dist/domain/index.d.ts +3 -3
- package/packages/state-graph/dist/domain/index.js +0 -1
- package/packages/state-graph/dist/index.d.ts +40 -8
- package/packages/state-graph/dist/index.js +214 -65
- package/packages/state-graph/dist/rules/index.d.ts +3 -3
- package/packages/state-graph/dist/rules/index.js +0 -1
- package/packages/state-graph/dist/spatial/index.d.ts +4 -4
- package/packages/state-graph/dist/spatial/index.js +0 -1
- package/packages/state-graph/dist/state/index.js +1 -3
- package/packages/state-graph/dist/store/index.d.ts +4 -4
- package/packages/state-graph/dist/store/index.js +0 -1
- package/packages/state-graph/dist/{types-VDoc4FIc.d.ts → types-D5kQSa65.d.ts} +2 -2
- package/packages/state-graph/kloks.manifest.json +26 -10
- package/packages/state-graph/package.json +2 -8
- package/packages/backend/dist/IdempotencyManager-B5MjK871.d.ts +0 -16
- package/packages/backend/dist/chunk-25Y7AVTP.js +0 -55
- package/packages/backend/dist/chunk-3EPY34R6.js +0 -67
- package/packages/backend/dist/chunk-7KNGX522.js +0 -220
- package/packages/backend/dist/chunk-FZKBTF34.js +0 -15
- package/packages/backend/dist/chunk-QGHDJGYS.js +0 -92
- package/packages/backend/dist/chunk-UPFKBBQI.js +0 -138
- package/packages/backend/dist/chunk-VQEFULWT.js +0 -88
- package/packages/backend/dist/execution/index.d.ts +0 -124
- package/packages/backend/dist/execution/index.js +0 -20
- package/packages/backend/dist/types-BERZJ93O.d.ts +0 -110
- package/packages/state-graph/dist/chunk-3RG5ZIWI.js +0 -10
- package/packages/state-graph/dist/chunk-Q5I42UX7.js +0 -0
- package/packages/state-graph/dist/chunk-ZTHBPV24.js +0 -267
- package/packages/state-graph/dist/execution/index.d.ts +0 -152
- package/packages/state-graph/dist/execution/index.js +0 -16
- /package/packages/state-graph/dist/{chunk-SHIBCPGQ.js → chunk-EW4ACSZB.js} +0 -0
|
@@ -1,124 +1,16 @@
|
|
|
1
|
-
// src/workspace/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
this.syncEngine = syncEngine;
|
|
12
|
-
}
|
|
13
|
-
setPrimary(newPrimary) {
|
|
14
|
-
this.primary = newPrimary;
|
|
15
|
-
}
|
|
16
|
-
setSyncEngine(engine) {
|
|
17
|
-
this.syncEngine = engine;
|
|
18
|
-
}
|
|
19
|
-
async exists(pathStr) {
|
|
20
|
-
return this.primary.exists(pathStr);
|
|
21
|
-
}
|
|
22
|
-
async stat(pathStr) {
|
|
23
|
-
return this.primary.stat(pathStr);
|
|
24
|
-
}
|
|
25
|
-
async list(pathStr = "") {
|
|
26
|
-
return this.primary.list(pathStr);
|
|
27
|
-
}
|
|
28
|
-
async read(pathStr) {
|
|
29
|
-
return this.primary.read(pathStr);
|
|
30
|
-
}
|
|
31
|
-
async readText(pathStr) {
|
|
32
|
-
const data = await this.read(pathStr);
|
|
33
|
-
return Buffer.from(data).toString("utf8");
|
|
34
|
-
}
|
|
35
|
-
async write(pathStr, data) {
|
|
36
|
-
await this.primary.write(pathStr, data);
|
|
37
|
-
if (this.syncEngine && this.config.sync?.enabled && this.config.sync.mode === "on_write") {
|
|
38
|
-
this.syncEngine.syncFile(pathStr).catch((err) => {
|
|
39
|
-
console.warn(`[WorkspaceFS] Async backup sync warning for '${pathStr}':`, err.message);
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
async mkdir(pathStr) {
|
|
44
|
-
await this.primary.mkdir(pathStr);
|
|
45
|
-
}
|
|
46
|
-
async delete(pathStr) {
|
|
47
|
-
await this.primary.delete(pathStr);
|
|
48
|
-
if (this.syncEngine && this.config.sync?.enabled && this.config.sync.deletePropagation) {
|
|
49
|
-
this.syncEngine.deleteFile(pathStr).catch((err) => {
|
|
50
|
-
console.warn(`[WorkspaceFS] Async delete sync warning for '${pathStr}':`, err.message);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
// src/workspace/SyncEngine.ts
|
|
57
|
-
import { SkipoBase as SkipoBase2 } from "@ultrst-armada/kloks/functions";
|
|
58
|
-
var SyncEngine = class extends SkipoBase2 {
|
|
59
|
-
primary;
|
|
60
|
-
backups;
|
|
61
|
-
config;
|
|
62
|
-
constructor(primary, backups, config) {
|
|
63
|
-
super({ name: "SyncEngine" });
|
|
64
|
-
this.primary = primary;
|
|
65
|
-
this.backups = backups;
|
|
66
|
-
this.config = config;
|
|
67
|
-
}
|
|
68
|
-
async syncFile(pathStr) {
|
|
69
|
-
const data = await this.primary.read(pathStr);
|
|
70
|
-
for (const backup of this.backups) {
|
|
71
|
-
try {
|
|
72
|
-
await backup.write(pathStr, data);
|
|
73
|
-
} catch (e) {
|
|
74
|
-
console.error(`[SyncEngine] Failed to sync ${pathStr} to backup:`, e.message);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
async deleteFile(pathStr) {
|
|
79
|
-
for (const backup of this.backups) {
|
|
80
|
-
try {
|
|
81
|
-
await backup.delete(pathStr);
|
|
82
|
-
} catch (e) {
|
|
83
|
-
console.error(`[SyncEngine] Failed to delete ${pathStr} on backup:`, e.message);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
// src/workspace/WorkspaceCloneSyncEngine.ts
|
|
90
|
-
import { SkipoBase as SkipoBase3 } from "@ultrst-armada/kloks/functions";
|
|
91
|
-
var WorkspaceCloneSyncEngine = class extends SkipoBase3 {
|
|
92
|
-
constructor() {
|
|
93
|
-
super({ name: "WorkspaceCloneSyncEngine" });
|
|
94
|
-
}
|
|
95
|
-
async replicateToClones(files, clones, uploadFn) {
|
|
96
|
-
const results = [];
|
|
97
|
-
let totalSynced = 0;
|
|
98
|
-
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
99
|
-
for (const clone of clones) {
|
|
100
|
-
try {
|
|
101
|
-
let count = 0;
|
|
102
|
-
for (const file of files) {
|
|
103
|
-
await uploadFn(clone, file.relPath, file.content, file.contentType);
|
|
104
|
-
count++;
|
|
105
|
-
}
|
|
106
|
-
clone.lastSyncedAt = nowIso;
|
|
107
|
-
clone.filesSynced = count;
|
|
108
|
-
clone.status = "SYNCED";
|
|
109
|
-
results.push({ cloneId: clone.id, label: clone.label, provider: clone.provider, filesSynced: count, status: "SYNCED" });
|
|
110
|
-
totalSynced += count;
|
|
111
|
-
} catch (err) {
|
|
112
|
-
clone.status = "ERROR";
|
|
113
|
-
results.push({ cloneId: clone.id, label: clone.label, provider: clone.provider, filesSynced: 0, status: "ERROR", error: err.message });
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
return { results, totalSynced };
|
|
117
|
-
}
|
|
118
|
-
};
|
|
1
|
+
// src/workspace/WorkspaceCanonical.ts
|
|
2
|
+
function formatCanonicalWorkspaceFolderName(appName, userName, workspaceName) {
|
|
3
|
+
const safeApp = appName.replace(/[^a-zA-Z0-9]/g, "_").toLowerCase();
|
|
4
|
+
const safeUser = userName.replace(/[^a-zA-Z0-9]/g, "_").toLowerCase();
|
|
5
|
+
const safeWs = workspaceName.replace(/[^a-zA-Z0-9]/g, "_").toLowerCase();
|
|
6
|
+
return `ultrst_${safeApp}_${safeUser}_${safeWs}`;
|
|
7
|
+
}
|
|
8
|
+
function sanitizeWorkspaceName(name) {
|
|
9
|
+
return name.replace(/[^a-zA-Z0-9-_\s]/g, "").trim();
|
|
10
|
+
}
|
|
119
11
|
|
|
120
12
|
// src/core/unifiedDb.ts
|
|
121
|
-
|
|
13
|
+
var neon;
|
|
122
14
|
function cleanDbUrl(url) {
|
|
123
15
|
if (!url || typeof url !== "string") return "";
|
|
124
16
|
return url.trim().replace(/^["']|["']$/g, "");
|
|
@@ -136,6 +28,10 @@ async function queryUnifiedDb(sqlText, params = [], env) {
|
|
|
136
28
|
if (!dbUrl) {
|
|
137
29
|
throw new Error("[UnifiedDB] No database URL configured in environment.");
|
|
138
30
|
}
|
|
31
|
+
if (!neon) {
|
|
32
|
+
const mod = await import("@neondatabase/serverless");
|
|
33
|
+
neon = mod.neon;
|
|
34
|
+
}
|
|
139
35
|
const sql = neon(dbUrl);
|
|
140
36
|
try {
|
|
141
37
|
const rows = await (sql.query ? sql.query(sqlText, params) : sql(sqlText, params));
|
|
@@ -343,12 +239,12 @@ async function writeWorkspaceFile(workspace, connection, relativePath, content,
|
|
|
343
239
|
await b2UploadFile(keyId, appKey, bucketName, fullKey, buffer, contentType);
|
|
344
240
|
return;
|
|
345
241
|
}
|
|
346
|
-
const
|
|
347
|
-
const
|
|
348
|
-
if (!
|
|
349
|
-
const localDir =
|
|
350
|
-
await
|
|
351
|
-
await
|
|
242
|
+
const fs = await getFs();
|
|
243
|
+
const path = await getPath();
|
|
244
|
+
if (!fs || !path) throw new Error("Local filesystem operations not supported in this runtime.");
|
|
245
|
+
const localDir = path.resolve(process.cwd(), prefix, path.dirname(cleanRel));
|
|
246
|
+
await fs.mkdir(localDir, { recursive: true });
|
|
247
|
+
await fs.writeFile(path.resolve(process.cwd(), prefix, cleanRel), buffer);
|
|
352
248
|
}
|
|
353
249
|
async function readWorkspaceFile(workspace, connection, relativePath) {
|
|
354
250
|
const cleanRel = relativePath.replace(/^\/+/, "");
|
|
@@ -360,12 +256,12 @@ async function readWorkspaceFile(workspace, connection, relativePath) {
|
|
|
360
256
|
const fullKey = `${prefix}/${cleanRel}`;
|
|
361
257
|
return await b2DownloadFile(keyId, appKey, bucketName, fullKey);
|
|
362
258
|
}
|
|
363
|
-
const
|
|
364
|
-
const
|
|
365
|
-
if (!
|
|
366
|
-
const fullPath =
|
|
259
|
+
const fs = await getFs();
|
|
260
|
+
const path = await getPath();
|
|
261
|
+
if (!fs || !path) return null;
|
|
262
|
+
const fullPath = path.resolve(process.cwd(), prefix, cleanRel);
|
|
367
263
|
try {
|
|
368
|
-
const buf = await
|
|
264
|
+
const buf = await fs.readFile(fullPath);
|
|
369
265
|
return new Uint8Array(buf);
|
|
370
266
|
} catch {
|
|
371
267
|
return null;
|
|
@@ -387,12 +283,12 @@ async function deleteWorkspaceFile(workspace, connection, relativePath) {
|
|
|
387
283
|
}
|
|
388
284
|
return false;
|
|
389
285
|
}
|
|
390
|
-
const
|
|
391
|
-
const
|
|
392
|
-
if (!
|
|
393
|
-
const fullPath =
|
|
286
|
+
const fs = await getFs();
|
|
287
|
+
const path = await getPath();
|
|
288
|
+
if (!fs || !path) return false;
|
|
289
|
+
const fullPath = path.resolve(process.cwd(), prefix, cleanRel);
|
|
394
290
|
try {
|
|
395
|
-
await
|
|
291
|
+
await fs.unlink(fullPath);
|
|
396
292
|
return true;
|
|
397
293
|
} catch {
|
|
398
294
|
return false;
|
|
@@ -412,19 +308,19 @@ async function listWorkspaceFiles(workspace, connection, subPrefix = "") {
|
|
|
412
308
|
uploadTimestamp: f.uploadTimestamp
|
|
413
309
|
}));
|
|
414
310
|
}
|
|
415
|
-
const
|
|
416
|
-
const
|
|
417
|
-
if (!
|
|
418
|
-
const baseDir =
|
|
311
|
+
const fs = await getFs();
|
|
312
|
+
const path = await getPath();
|
|
313
|
+
if (!fs || !path) return [];
|
|
314
|
+
const baseDir = path.resolve(process.cwd(), folderPrefix, subPrefix);
|
|
419
315
|
try {
|
|
420
|
-
const entries = await
|
|
316
|
+
const entries = await fs.readdir(baseDir, { withFileTypes: true, recursive: true });
|
|
421
317
|
const result = [];
|
|
422
318
|
for (const entry of entries) {
|
|
423
319
|
if (entry.isFile()) {
|
|
424
|
-
const full =
|
|
425
|
-
const st = await
|
|
320
|
+
const full = path.join(entry.parentPath || baseDir, entry.name);
|
|
321
|
+
const st = await fs.stat(full);
|
|
426
322
|
result.push({
|
|
427
|
-
fileName:
|
|
323
|
+
fileName: path.relative(path.resolve(process.cwd(), folderPrefix), full),
|
|
428
324
|
sizeBytes: st.size
|
|
429
325
|
});
|
|
430
326
|
}
|
|
@@ -443,12 +339,12 @@ async function deleteWorkspaceFolder(workspace, connection) {
|
|
|
443
339
|
await b2DeleteFolder(keyId, appKey, bucketName, prefix);
|
|
444
340
|
return;
|
|
445
341
|
}
|
|
446
|
-
const
|
|
447
|
-
const
|
|
448
|
-
if (!
|
|
449
|
-
const localDir =
|
|
342
|
+
const fs = await getFs();
|
|
343
|
+
const path = await getPath();
|
|
344
|
+
if (!fs || !path) return;
|
|
345
|
+
const localDir = path.resolve(process.cwd(), prefix);
|
|
450
346
|
try {
|
|
451
|
-
await
|
|
347
|
+
await fs.rm(localDir, { recursive: true, force: true });
|
|
452
348
|
} catch {
|
|
453
349
|
}
|
|
454
350
|
}
|
|
@@ -648,73 +544,6 @@ async function renameAppInWorkspaceData(userId, workspaceId, appId, newName, env
|
|
|
648
544
|
return await saveWorkspaceData(userId, workspaceId, wsData, env);
|
|
649
545
|
}
|
|
650
546
|
|
|
651
|
-
// src/core/workspaceStorageDetailsCore.ts
|
|
652
|
-
async function getWorkspaceStorageDetails(workspaceId, env) {
|
|
653
|
-
if (!workspaceId) return { success: false, error: "workspaceId is required" };
|
|
654
|
-
const { workspace, connection } = await findUserWorkspace(workspaceId, env);
|
|
655
|
-
const folderPrefix = workspace?.localFolderKey || workspace?.localFolderName || (workspace?.workspacePath ? workspace.workspacePath.replace(/^\.\//, "") : workspaceId);
|
|
656
|
-
if (!connection || connection.provider !== "backblaze_b2" && connection.provider !== "BACKBLAZE_B2") {
|
|
657
|
-
return {
|
|
658
|
-
success: true,
|
|
659
|
-
workspaceId,
|
|
660
|
-
storageProvider: workspace?.storageProvider || "local_fs",
|
|
661
|
-
connection: connection || null,
|
|
662
|
-
folderPrefix,
|
|
663
|
-
localStats: { exists: false, appsCount: 0, ecosystemsCount: 0 },
|
|
664
|
-
bucket: null,
|
|
665
|
-
files: []
|
|
666
|
-
};
|
|
667
|
-
}
|
|
668
|
-
const keyId = connection.b2KeyId || connection.keyId;
|
|
669
|
-
const applicationKey = connection.b2ApplicationKey || connection.appKey;
|
|
670
|
-
const bucketName = connection.b2BucketName || workspace.b2BucketName || "ultrst-apps";
|
|
671
|
-
try {
|
|
672
|
-
const buckets = await b2ListBuckets(keyId, applicationKey, void 0, bucketName);
|
|
673
|
-
const bucketObj = buckets.find((b) => b.bucketName === bucketName);
|
|
674
|
-
if (!bucketObj) {
|
|
675
|
-
return {
|
|
676
|
-
success: true,
|
|
677
|
-
workspaceId,
|
|
678
|
-
storageProvider: "backblaze_b2",
|
|
679
|
-
connection: { id: connection.id, label: connection.label, provider: connection.provider },
|
|
680
|
-
folderPrefix,
|
|
681
|
-
bucket: { name: bucketName, status: "BUCKET_NOT_FOUND" },
|
|
682
|
-
files: []
|
|
683
|
-
};
|
|
684
|
-
}
|
|
685
|
-
const rawFiles = await b2ListFileNames(keyId, applicationKey, bucketName, `${folderPrefix}/`);
|
|
686
|
-
return {
|
|
687
|
-
success: true,
|
|
688
|
-
workspaceId,
|
|
689
|
-
storageProvider: "backblaze_b2",
|
|
690
|
-
connection: { id: connection.id, label: connection.label, provider: connection.provider },
|
|
691
|
-
folderPrefix,
|
|
692
|
-
bucket: {
|
|
693
|
-
id: bucketObj.bucketId,
|
|
694
|
-
name: bucketObj.bucketName,
|
|
695
|
-
type: bucketObj.bucketType,
|
|
696
|
-
endpoint: connection.b2Endpoint || "s3.eu-central-003.backblazeb2.com",
|
|
697
|
-
region: connection.b2Region || "eu-central-003",
|
|
698
|
-
status: "CONNECTED"
|
|
699
|
-
},
|
|
700
|
-
fileCount: rawFiles.length,
|
|
701
|
-
files: rawFiles.map((f) => ({
|
|
702
|
-
fileName: f.fileName,
|
|
703
|
-
sizeBytes: f.contentLength,
|
|
704
|
-
uploadTimestamp: f.uploadTimestamp
|
|
705
|
-
}))
|
|
706
|
-
};
|
|
707
|
-
} catch (err) {
|
|
708
|
-
return {
|
|
709
|
-
success: false,
|
|
710
|
-
workspaceId,
|
|
711
|
-
storageProvider: "backblaze_b2",
|
|
712
|
-
error: err.message,
|
|
713
|
-
folderPrefix
|
|
714
|
-
};
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
|
|
718
547
|
// src/core/workspaceCore.ts
|
|
719
548
|
async function findUserWorkspace(workspaceId, env) {
|
|
720
549
|
const res = await queryUnifiedDb(`SELECT id, email, username, app_profiles FROM "ultrst-users"`, [], env);
|
|
@@ -832,461 +661,84 @@ async function deleteWorkspace(userId, wsId, env) {
|
|
|
832
661
|
return { success: true, workspaces: profiles.depm.workspaces };
|
|
833
662
|
}
|
|
834
663
|
|
|
835
|
-
// src/
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
async listWorkspaces(userId, env) {
|
|
842
|
-
return await getWorkspaces(userId, env);
|
|
843
|
-
}
|
|
844
|
-
async createWorkspace(userId, data, env) {
|
|
845
|
-
return await createWorkspace(userId, data, env);
|
|
846
|
-
}
|
|
847
|
-
async updateWorkspace(userId, params, env) {
|
|
848
|
-
return await updateWorkspace(userId, params, env);
|
|
849
|
-
}
|
|
850
|
-
async deleteWorkspace(userId, workspaceId, env) {
|
|
851
|
-
return await deleteWorkspace(userId, workspaceId, env);
|
|
852
|
-
}
|
|
853
|
-
async readFile(workspaceId, filePath, env) {
|
|
854
|
-
const { workspace, connection } = await this.findWorkspace(workspaceId, env);
|
|
855
|
-
if (!workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
|
|
856
|
-
const data = await readWorkspaceFile(workspace, connection, filePath);
|
|
857
|
-
if (!data) throw new Error(`File "${filePath}" not found in workspace "${workspaceId}".`);
|
|
858
|
-
return data;
|
|
859
|
-
}
|
|
860
|
-
async writeFile(workspaceId, filePath, content, env) {
|
|
861
|
-
const { workspace, connection } = await this.findWorkspace(workspaceId, env);
|
|
862
|
-
if (!workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
|
|
863
|
-
await writeWorkspaceFile(workspace, connection, filePath, content);
|
|
864
|
-
const size = typeof content === "string" ? new TextEncoder().encode(content).length : content.byteLength;
|
|
865
|
-
return { success: true, path: filePath, sizeBytes: size };
|
|
866
|
-
}
|
|
867
|
-
async deleteFile(workspaceId, filePath, env) {
|
|
868
|
-
const { workspace, connection } = await this.findWorkspace(workspaceId, env);
|
|
869
|
-
if (!workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
|
|
870
|
-
const deleted = await deleteWorkspaceFile(workspace, connection, filePath);
|
|
871
|
-
return { success: deleted };
|
|
872
|
-
}
|
|
873
|
-
async listFiles(workspaceId, subfolder = "", env) {
|
|
874
|
-
const { workspace, connection } = await this.findWorkspace(workspaceId, env);
|
|
875
|
-
if (!workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
|
|
876
|
-
const files = await listWorkspaceFiles(workspace, connection, subfolder);
|
|
877
|
-
return files.map((f) => ({
|
|
878
|
-
path: f.fileName,
|
|
879
|
-
name: f.fileName.split("/").pop() || f.fileName,
|
|
880
|
-
sizeBytes: f.sizeBytes,
|
|
881
|
-
updatedAt: f.uploadTimestamp
|
|
882
|
-
}));
|
|
883
|
-
}
|
|
884
|
-
};
|
|
885
|
-
var remoteWorkspaceService = new RemoteWorkspaceService();
|
|
886
|
-
|
|
887
|
-
// src/workspace/WorkingWorkspaceService.ts
|
|
888
|
-
import fs2 from "fs";
|
|
889
|
-
import path2 from "path";
|
|
890
|
-
|
|
891
|
-
// src/core/workspaceSyncEngine.ts
|
|
892
|
-
import fs from "fs";
|
|
893
|
-
import path from "path";
|
|
894
|
-
|
|
895
|
-
// src/core/workspaceCanonical.ts
|
|
896
|
-
function formatCanonicalWorkspaceFolderName(appName, userName, workspaceName) {
|
|
897
|
-
const safeApp = (appName || "qwnsr").replace(/[^a-zA-Z0-9]/g, "_").toLowerCase();
|
|
898
|
-
const safeUser = (userName || "user").replace(/[^a-zA-Z0-9]/g, "_").toLowerCase();
|
|
899
|
-
const safeWs = (workspaceName || "workspace").replace(/[^a-zA-Z0-9]/g, "_").toLowerCase();
|
|
900
|
-
return `ultrst_${safeApp}_${safeUser}_${safeWs}`;
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
// src/core/workspaceSyncEngine.ts
|
|
904
|
-
var ACCOUNTS_FILE = path.resolve(".skipo/accounts.json");
|
|
905
|
-
var CONFIG_FILE = path.resolve(".skipo/workspace_config.json");
|
|
906
|
-
function getDefaultWorkingWorkspaceDir() {
|
|
907
|
-
if (process.env.VERCEL || process.env.AWS_LAMBDA_FUNCTION_NAME) {
|
|
908
|
-
return path.join("/tmp", "workspace");
|
|
909
|
-
}
|
|
910
|
-
return path.join(process.cwd(), "workspace");
|
|
911
|
-
}
|
|
912
|
-
function getWorkingWorkspaceConfig() {
|
|
913
|
-
try {
|
|
914
|
-
if (fs.existsSync(CONFIG_FILE)) {
|
|
915
|
-
const raw = fs.readFileSync(CONFIG_FILE, "utf-8");
|
|
916
|
-
const parsed = JSON.parse(raw);
|
|
917
|
-
if (parsed.workingDirectory) {
|
|
918
|
-
return {
|
|
919
|
-
workingDirectory: parsed.workingDirectory,
|
|
920
|
-
autoSyncIntervalMinutes: parsed.autoSyncIntervalMinutes || 5
|
|
921
|
-
};
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
} catch {
|
|
925
|
-
}
|
|
926
|
-
return {
|
|
927
|
-
workingDirectory: getDefaultWorkingWorkspaceDir(),
|
|
928
|
-
autoSyncIntervalMinutes: 5
|
|
929
|
-
};
|
|
930
|
-
}
|
|
931
|
-
function setWorkingWorkspaceConfig(cfg) {
|
|
932
|
-
const current = getWorkingWorkspaceConfig();
|
|
933
|
-
const updated = {
|
|
934
|
-
workingDirectory: (cfg.workingDirectory || current.workingDirectory).trim(),
|
|
935
|
-
autoSyncIntervalMinutes: cfg.autoSyncIntervalMinutes || current.autoSyncIntervalMinutes
|
|
936
|
-
};
|
|
937
|
-
try {
|
|
938
|
-
fs.mkdirSync(path.dirname(CONFIG_FILE), { recursive: true });
|
|
939
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify(updated, null, 2), "utf-8");
|
|
940
|
-
} catch (err) {
|
|
941
|
-
console.warn("[WorkspaceSync] Failed to persist working config:", err);
|
|
942
|
-
}
|
|
943
|
-
return updated;
|
|
944
|
-
}
|
|
945
|
-
function getWorkingWorkspaceDir() {
|
|
946
|
-
const dir = getWorkingWorkspaceConfig().workingDirectory;
|
|
947
|
-
if (!fs.existsSync(dir)) {
|
|
948
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
949
|
-
}
|
|
950
|
-
return dir;
|
|
951
|
-
}
|
|
952
|
-
async function findWorkspaceRecord(workspaceId) {
|
|
953
|
-
try {
|
|
954
|
-
if (fs.existsSync(ACCOUNTS_FILE)) {
|
|
955
|
-
const raw = fs.readFileSync(ACCOUNTS_FILE, "utf-8");
|
|
956
|
-
const accounts = JSON.parse(raw);
|
|
957
|
-
for (const u of Object.values(accounts)) {
|
|
958
|
-
if (Array.isArray(u.workspaces)) {
|
|
959
|
-
const ws = u.workspaces.find((w) => w.id === workspaceId);
|
|
960
|
-
if (ws) {
|
|
961
|
-
const conns = Array.isArray(u.storage_connections) ? u.storage_connections : [];
|
|
962
|
-
const conn = conns.find((c) => c.id === ws.storageConnectionId) || conns[0] || null;
|
|
963
|
-
return { user: u, workspace: ws, connection: conn };
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
} catch {
|
|
969
|
-
}
|
|
970
|
-
try {
|
|
971
|
-
const res = await queryUnifiedDb(`SELECT id, email, username, app_profiles FROM "ultrst-users"`);
|
|
972
|
-
for (const u of res.rows) {
|
|
973
|
-
const profiles = typeof u.app_profiles === "string" ? JSON.parse(u.app_profiles) : u.app_profiles || {};
|
|
974
|
-
const qwnsr = profiles.qwnsr || {};
|
|
975
|
-
const workspaces = Array.isArray(qwnsr.workspaces) ? qwnsr.workspaces : [];
|
|
976
|
-
const ws = workspaces.find((w) => w.id === workspaceId);
|
|
977
|
-
if (ws) {
|
|
978
|
-
const conns = qwnsr.storage_connections || profiles.srkl?.storage_connections || [];
|
|
979
|
-
const conn = conns.find((c) => c.id === ws.storageConnectionId) || conns[0] || null;
|
|
980
|
-
return { user: u, workspace: ws, connection: conn };
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
} catch {
|
|
984
|
-
}
|
|
985
|
-
return null;
|
|
986
|
-
}
|
|
987
|
-
function getWorkspaceFolderKey(workspace, user) {
|
|
988
|
-
if (workspace.localFolderKey) return workspace.localFolderKey;
|
|
989
|
-
if (workspace.localFolderName && workspace.localFolderName.startsWith("ultrst_")) return workspace.localFolderName;
|
|
990
|
-
const userName = user?.username || user?.name || (user?.email ? user.email.split("@")[0] : "user");
|
|
991
|
-
return formatCanonicalWorkspaceFolderName("qwnsr", userName, workspace.name);
|
|
992
|
-
}
|
|
993
|
-
async function collectLocalFiles(dir, baseDir = dir) {
|
|
994
|
-
if (!fs.existsSync(dir)) return [];
|
|
995
|
-
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
996
|
-
const results = [];
|
|
997
|
-
for (const entry of entries) {
|
|
998
|
-
if (entry.name.startsWith(".") && entry.name !== ".bzEmpty") continue;
|
|
999
|
-
const full = path.join(dir, entry.name);
|
|
1000
|
-
if (entry.isDirectory()) {
|
|
1001
|
-
const nested = await collectLocalFiles(full, baseDir);
|
|
1002
|
-
results.push(...nested);
|
|
1003
|
-
} else if (entry.isFile()) {
|
|
1004
|
-
const st = await fs.promises.stat(full);
|
|
1005
|
-
const rel = path.relative(baseDir, full).replace(/\\/g, "/");
|
|
1006
|
-
results.push({ relPath: rel, fullPath: full, mtimeMs: st.mtimeMs, sizeBytes: st.size });
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
return results;
|
|
1010
|
-
}
|
|
1011
|
-
async function syncWorkspace(workspaceId) {
|
|
1012
|
-
const match = await findWorkspaceRecord(workspaceId);
|
|
1013
|
-
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
1014
|
-
if (!match) {
|
|
664
|
+
// src/core/workspaceStorageDetailsCore.ts
|
|
665
|
+
async function getWorkspaceStorageDetails(workspaceId, env) {
|
|
666
|
+
if (!workspaceId) return { success: false, error: "workspaceId is required" };
|
|
667
|
+
const { workspace, connection } = await findUserWorkspace(workspaceId, env);
|
|
668
|
+
const folderPrefix = workspace?.localFolderKey || workspace?.localFolderName || (workspace?.workspacePath ? workspace.workspacePath.replace(/^\.\//, "") : workspaceId);
|
|
669
|
+
if (!connection || connection.provider !== "backblaze_b2" && connection.provider !== "BACKBLAZE_B2") {
|
|
1015
670
|
return {
|
|
1016
|
-
success:
|
|
671
|
+
success: true,
|
|
1017
672
|
workspaceId,
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
downloadedCount: 0,
|
|
1025
|
-
syncedAt: nowIso,
|
|
1026
|
-
error: `Workspace '${workspaceId}' not found.`
|
|
673
|
+
storageProvider: workspace?.storageProvider || "local_fs",
|
|
674
|
+
connection: connection || null,
|
|
675
|
+
folderPrefix,
|
|
676
|
+
localStats: { exists: false, appsCount: 0, ecosystemsCount: 0 },
|
|
677
|
+
bucket: null,
|
|
678
|
+
files: []
|
|
1027
679
|
};
|
|
1028
680
|
}
|
|
1029
|
-
const
|
|
1030
|
-
const
|
|
1031
|
-
const
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
if (isB2) {
|
|
1037
|
-
const creds = workspace.storageConfig || connection?.credentials || connection || {};
|
|
1038
|
-
const keyId = creds.keyId || creds.b2KeyId;
|
|
1039
|
-
const appKey = creds.applicationKey || creds.b2ApplicationKey || creds.appKey;
|
|
1040
|
-
const bucketName = creds.bucketName || creds.b2BucketName || workspace.b2BucketName || "ultrst-apps";
|
|
1041
|
-
if (!keyId || !appKey) {
|
|
1042
|
-
return {
|
|
1043
|
-
success: false,
|
|
1044
|
-
workspaceId,
|
|
1045
|
-
folderKey,
|
|
1046
|
-
workingDir,
|
|
1047
|
-
persistenceType: "backblaze_b2",
|
|
1048
|
-
targetLocation: bucketName,
|
|
1049
|
-
syncedFiles: [],
|
|
1050
|
-
uploadedCount: 0,
|
|
1051
|
-
downloadedCount: 0,
|
|
1052
|
-
syncedAt: nowIso,
|
|
1053
|
-
error: "Missing Backblaze B2 credentials for sync."
|
|
1054
|
-
};
|
|
1055
|
-
}
|
|
1056
|
-
try {
|
|
1057
|
-
const b2Prefix = `${folderKey}/`;
|
|
1058
|
-
const remoteFiles = await b2ListFileNames(keyId, appKey, bucketName, b2Prefix);
|
|
1059
|
-
const remoteMap = /* @__PURE__ */ new Map();
|
|
1060
|
-
for (const rf of remoteFiles) {
|
|
1061
|
-
const cleanName = rf.fileName.slice(b2Prefix.length);
|
|
1062
|
-
if (cleanName) remoteMap.set(cleanName, { fileId: rf.fileId, size: rf.contentLength, timestamp: rf.uploadTimestamp });
|
|
1063
|
-
}
|
|
1064
|
-
const localFiles = await collectLocalFiles(workingDir);
|
|
1065
|
-
const localMap = /* @__PURE__ */ new Map();
|
|
1066
|
-
for (const lf of localFiles) {
|
|
1067
|
-
localMap.set(lf.relPath, lf);
|
|
1068
|
-
}
|
|
1069
|
-
for (const [relPath, rInfo] of remoteMap.entries()) {
|
|
1070
|
-
const lFile = localMap.get(relPath);
|
|
1071
|
-
const shouldDownload = !lFile || rInfo.timestamp > lFile.mtimeMs + 2e3;
|
|
1072
|
-
if (shouldDownload) {
|
|
1073
|
-
const buf = await b2DownloadFile(keyId, appKey, bucketName, `${b2Prefix}${relPath}`);
|
|
1074
|
-
if (buf) {
|
|
1075
|
-
const destPath = path.join(workingDir, relPath);
|
|
1076
|
-
await fs.promises.mkdir(path.dirname(destPath), { recursive: true });
|
|
1077
|
-
await fs.promises.writeFile(destPath, buf);
|
|
1078
|
-
try {
|
|
1079
|
-
const fileTime = new Date(rInfo.timestamp);
|
|
1080
|
-
await fs.promises.utimes(destPath, fileTime, fileTime);
|
|
1081
|
-
} catch {
|
|
1082
|
-
}
|
|
1083
|
-
syncedFiles.push({ fileName: relPath, action: "DOWNLOADED", sizeBytes: buf.byteLength });
|
|
1084
|
-
downloadedCount++;
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
for (const [relPath, lFile] of localMap.entries()) {
|
|
1089
|
-
const rInfo = remoteMap.get(relPath);
|
|
1090
|
-
const shouldUpload = !rInfo || lFile.mtimeMs > rInfo.timestamp + 2e3;
|
|
1091
|
-
if (shouldUpload) {
|
|
1092
|
-
const content = await fs.promises.readFile(lFile.fullPath);
|
|
1093
|
-
await b2UploadFile(keyId, appKey, bucketName, `${b2Prefix}${relPath}`, new Uint8Array(content));
|
|
1094
|
-
syncedFiles.push({ fileName: relPath, action: "UPLOADED", sizeBytes: lFile.sizeBytes });
|
|
1095
|
-
uploadedCount++;
|
|
1096
|
-
} else if (!syncedFiles.some((f) => f.fileName === relPath)) {
|
|
1097
|
-
syncedFiles.push({ fileName: relPath, action: "UP_TO_DATE", sizeBytes: lFile.sizeBytes });
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
681
|
+
const keyId = connection.b2KeyId || connection.keyId;
|
|
682
|
+
const applicationKey = connection.b2ApplicationKey || connection.appKey;
|
|
683
|
+
const bucketName = connection.b2BucketName || workspace.b2BucketName || "ultrst-apps";
|
|
684
|
+
try {
|
|
685
|
+
const buckets = await b2ListBuckets(keyId, applicationKey, void 0, bucketName);
|
|
686
|
+
const bucketObj = buckets.find((b) => b.bucketName === bucketName);
|
|
687
|
+
if (!bucketObj) {
|
|
1100
688
|
return {
|
|
1101
689
|
success: true,
|
|
1102
690
|
workspaceId,
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
uploadedCount,
|
|
1109
|
-
downloadedCount,
|
|
1110
|
-
syncedAt: nowIso
|
|
1111
|
-
};
|
|
1112
|
-
} catch (err) {
|
|
1113
|
-
return {
|
|
1114
|
-
success: false,
|
|
1115
|
-
workspaceId,
|
|
1116
|
-
folderKey,
|
|
1117
|
-
workingDir,
|
|
1118
|
-
persistenceType: "backblaze_b2",
|
|
1119
|
-
targetLocation: bucketName,
|
|
1120
|
-
syncedFiles,
|
|
1121
|
-
uploadedCount,
|
|
1122
|
-
downloadedCount,
|
|
1123
|
-
syncedAt: nowIso,
|
|
1124
|
-
error: err.message || "Backblaze sync failed."
|
|
691
|
+
storageProvider: "backblaze_b2",
|
|
692
|
+
connection: { id: connection.id, label: connection.label, provider: connection.provider },
|
|
693
|
+
folderPrefix,
|
|
694
|
+
bucket: { name: bucketName, status: "BUCKET_NOT_FOUND" },
|
|
695
|
+
files: []
|
|
1125
696
|
};
|
|
1126
697
|
}
|
|
1127
|
-
|
|
1128
|
-
const vaultDir = path.resolve(process.cwd(), folderKey);
|
|
1129
|
-
await fs.promises.mkdir(vaultDir, { recursive: true });
|
|
1130
|
-
try {
|
|
1131
|
-
const vaultFiles = await collectLocalFiles(vaultDir);
|
|
1132
|
-
const vaultMap = new Map(vaultFiles.map((f) => [f.relPath, f]));
|
|
1133
|
-
const workingFiles = await collectLocalFiles(workingDir);
|
|
1134
|
-
const workingMap = new Map(workingFiles.map((f) => [f.relPath, f]));
|
|
1135
|
-
for (const [relPath, vFile] of vaultMap.entries()) {
|
|
1136
|
-
const wFile = workingMap.get(relPath);
|
|
1137
|
-
const shouldDownload = !wFile || vFile.mtimeMs > wFile.mtimeMs + 1e3;
|
|
1138
|
-
if (shouldDownload) {
|
|
1139
|
-
const dest = path.join(workingDir, relPath);
|
|
1140
|
-
await fs.promises.mkdir(path.dirname(dest), { recursive: true });
|
|
1141
|
-
await fs.promises.copyFile(vFile.fullPath, dest);
|
|
1142
|
-
try {
|
|
1143
|
-
const vTime = new Date(vFile.mtimeMs);
|
|
1144
|
-
await fs.promises.utimes(dest, vTime, vTime);
|
|
1145
|
-
} catch {
|
|
1146
|
-
}
|
|
1147
|
-
syncedFiles.push({ fileName: relPath, action: "DOWNLOADED", sizeBytes: vFile.sizeBytes });
|
|
1148
|
-
downloadedCount++;
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
for (const [relPath, wFile] of workingMap.entries()) {
|
|
1152
|
-
const vFile = vaultMap.get(relPath);
|
|
1153
|
-
const shouldUpload = !vFile || wFile.mtimeMs > vFile.mtimeMs + 1e3;
|
|
1154
|
-
if (shouldUpload) {
|
|
1155
|
-
const dest = path.join(vaultDir, relPath);
|
|
1156
|
-
await fs.promises.mkdir(path.dirname(dest), { recursive: true });
|
|
1157
|
-
await fs.promises.copyFile(wFile.fullPath, dest);
|
|
1158
|
-
try {
|
|
1159
|
-
const wTime = new Date(wFile.mtimeMs);
|
|
1160
|
-
await fs.promises.utimes(dest, wTime, wTime);
|
|
1161
|
-
} catch {
|
|
1162
|
-
}
|
|
1163
|
-
syncedFiles.push({ fileName: relPath, action: "UPLOADED", sizeBytes: wFile.sizeBytes });
|
|
1164
|
-
uploadedCount++;
|
|
1165
|
-
} else if (!syncedFiles.some((f) => f.fileName === relPath)) {
|
|
1166
|
-
syncedFiles.push({ fileName: relPath, action: "UP_TO_DATE", sizeBytes: wFile.sizeBytes });
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
698
|
+
const rawFiles = await b2ListFileNames(keyId, applicationKey, bucketName, `${folderPrefix}/`);
|
|
1169
699
|
return {
|
|
1170
700
|
success: true,
|
|
1171
701
|
workspaceId,
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
702
|
+
storageProvider: "backblaze_b2",
|
|
703
|
+
connection: { id: connection.id, label: connection.label, provider: connection.provider },
|
|
704
|
+
folderPrefix,
|
|
705
|
+
bucket: {
|
|
706
|
+
id: bucketObj.bucketId,
|
|
707
|
+
name: bucketObj.bucketName,
|
|
708
|
+
type: bucketObj.bucketType,
|
|
709
|
+
endpoint: connection.b2Endpoint || "s3.eu-central-003.backblazeb2.com",
|
|
710
|
+
region: connection.b2Region || "eu-central-003",
|
|
711
|
+
status: "CONNECTED"
|
|
712
|
+
},
|
|
713
|
+
fileCount: rawFiles.length,
|
|
714
|
+
files: rawFiles.map((f) => ({
|
|
715
|
+
fileName: f.fileName,
|
|
716
|
+
sizeBytes: f.contentLength,
|
|
717
|
+
uploadTimestamp: f.uploadTimestamp
|
|
718
|
+
}))
|
|
1180
719
|
};
|
|
1181
720
|
} catch (err) {
|
|
1182
721
|
return {
|
|
1183
722
|
success: false,
|
|
1184
723
|
workspaceId,
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
targetLocation: vaultDir,
|
|
1189
|
-
syncedFiles,
|
|
1190
|
-
uploadedCount,
|
|
1191
|
-
downloadedCount,
|
|
1192
|
-
syncedAt: nowIso,
|
|
1193
|
-
error: err.message
|
|
724
|
+
storageProvider: "backblaze_b2",
|
|
725
|
+
error: err.message,
|
|
726
|
+
folderPrefix
|
|
1194
727
|
};
|
|
1195
728
|
}
|
|
1196
729
|
}
|
|
1197
730
|
|
|
1198
|
-
// src/workspace/WorkingWorkspaceService.ts
|
|
1199
|
-
var WorkingWorkspaceService = class {
|
|
1200
|
-
constructor(workingDirResolver) {
|
|
1201
|
-
this.workingDirResolver = workingDirResolver;
|
|
1202
|
-
}
|
|
1203
|
-
workingDirResolver;
|
|
1204
|
-
type = "working";
|
|
1205
|
-
getWorkingDir() {
|
|
1206
|
-
return this.workingDirResolver ? this.workingDirResolver() : getWorkingWorkspaceDir();
|
|
1207
|
-
}
|
|
1208
|
-
async findWorkspace(workspaceId, env) {
|
|
1209
|
-
return await findUserWorkspace(workspaceId, env);
|
|
1210
|
-
}
|
|
1211
|
-
async listWorkspaces(userId, env) {
|
|
1212
|
-
return await getWorkspaces(userId, env);
|
|
1213
|
-
}
|
|
1214
|
-
async createWorkspace(userId, data, env) {
|
|
1215
|
-
const res = await createWorkspace(userId, data, env);
|
|
1216
|
-
const dir = this.getWorkingDir();
|
|
1217
|
-
try {
|
|
1218
|
-
await fs2.promises.mkdir(dir, { recursive: true });
|
|
1219
|
-
} catch {
|
|
1220
|
-
}
|
|
1221
|
-
return res;
|
|
1222
|
-
}
|
|
1223
|
-
async updateWorkspace(userId, params, env) {
|
|
1224
|
-
return await updateWorkspace(userId, params, env);
|
|
1225
|
-
}
|
|
1226
|
-
async deleteWorkspace(userId, workspaceId, env) {
|
|
1227
|
-
return await deleteWorkspace(userId, workspaceId, env);
|
|
1228
|
-
}
|
|
1229
|
-
async readFile(_workspaceId, filePath) {
|
|
1230
|
-
const cleanRel = filePath.replace(/^\/+/, "");
|
|
1231
|
-
const fullPath = path2.resolve(this.getWorkingDir(), cleanRel);
|
|
1232
|
-
return await fs2.promises.readFile(fullPath);
|
|
1233
|
-
}
|
|
1234
|
-
async writeFile(_workspaceId, filePath, content) {
|
|
1235
|
-
const cleanRel = filePath.replace(/^\/+/, "");
|
|
1236
|
-
const fullPath = path2.resolve(this.getWorkingDir(), cleanRel);
|
|
1237
|
-
await fs2.promises.mkdir(path2.dirname(fullPath), { recursive: true });
|
|
1238
|
-
const buffer = typeof content === "string" ? Buffer.from(content) : Buffer.from(content.buffer, content.byteOffset, content.byteLength);
|
|
1239
|
-
await fs2.promises.writeFile(fullPath, buffer);
|
|
1240
|
-
return { success: true, path: filePath, sizeBytes: buffer.byteLength };
|
|
1241
|
-
}
|
|
1242
|
-
async deleteFile(_workspaceId, filePath) {
|
|
1243
|
-
const cleanRel = filePath.replace(/^\/+/, "");
|
|
1244
|
-
const fullPath = path2.resolve(this.getWorkingDir(), cleanRel);
|
|
1245
|
-
try {
|
|
1246
|
-
await fs2.promises.unlink(fullPath);
|
|
1247
|
-
return { success: true };
|
|
1248
|
-
} catch {
|
|
1249
|
-
return { success: false };
|
|
1250
|
-
}
|
|
1251
|
-
}
|
|
1252
|
-
async listFiles(_workspaceId, subfolder = "") {
|
|
1253
|
-
const baseDir = path2.resolve(this.getWorkingDir(), subfolder.replace(/^\/+/, ""));
|
|
1254
|
-
if (!fs2.existsSync(baseDir)) return [];
|
|
1255
|
-
const entries = await fs2.promises.readdir(baseDir, { withFileTypes: true });
|
|
1256
|
-
return entries.map((e) => {
|
|
1257
|
-
const full = path2.join(baseDir, e.name);
|
|
1258
|
-
let sizeBytes = 0;
|
|
1259
|
-
let updatedAt = Date.now();
|
|
1260
|
-
try {
|
|
1261
|
-
const s = fs2.statSync(full);
|
|
1262
|
-
sizeBytes = s.size;
|
|
1263
|
-
updatedAt = s.mtimeMs;
|
|
1264
|
-
} catch {
|
|
1265
|
-
}
|
|
1266
|
-
return {
|
|
1267
|
-
path: path2.relative(this.getWorkingDir(), full),
|
|
1268
|
-
name: e.name,
|
|
1269
|
-
isFolder: e.isDirectory(),
|
|
1270
|
-
sizeBytes,
|
|
1271
|
-
updatedAt
|
|
1272
|
-
};
|
|
1273
|
-
});
|
|
1274
|
-
}
|
|
1275
|
-
async sync(workspaceId, _options, _env) {
|
|
1276
|
-
return await syncWorkspace(workspaceId);
|
|
1277
|
-
}
|
|
1278
|
-
};
|
|
1279
|
-
var workingWorkspaceService = new WorkingWorkspaceService();
|
|
1280
|
-
|
|
1281
731
|
export {
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
WorkspaceCloneSyncEngine,
|
|
732
|
+
formatCanonicalWorkspaceFolderName,
|
|
733
|
+
sanitizeWorkspaceName,
|
|
1285
734
|
cleanDbUrl,
|
|
1286
735
|
getUnifiedDbUrl,
|
|
1287
736
|
queryUnifiedDb,
|
|
1288
737
|
b2ListBuckets,
|
|
1289
738
|
getB2BucketId,
|
|
739
|
+
b2UploadFile,
|
|
740
|
+
b2DownloadFile,
|
|
741
|
+
b2ListFileNames,
|
|
1290
742
|
b2DeleteFileVersion,
|
|
1291
743
|
b2DeleteFolder,
|
|
1292
744
|
getWorkspaceFolderPrefix,
|
|
@@ -1308,16 +760,5 @@ export {
|
|
|
1308
760
|
getWorkspaces,
|
|
1309
761
|
createWorkspace,
|
|
1310
762
|
updateWorkspace,
|
|
1311
|
-
deleteWorkspace
|
|
1312
|
-
RemoteWorkspaceService,
|
|
1313
|
-
remoteWorkspaceService,
|
|
1314
|
-
getDefaultWorkingWorkspaceDir,
|
|
1315
|
-
getWorkingWorkspaceConfig,
|
|
1316
|
-
setWorkingWorkspaceConfig,
|
|
1317
|
-
getWorkingWorkspaceDir,
|
|
1318
|
-
findWorkspaceRecord,
|
|
1319
|
-
getWorkspaceFolderKey,
|
|
1320
|
-
syncWorkspace,
|
|
1321
|
-
WorkingWorkspaceService,
|
|
1322
|
-
workingWorkspaceService
|
|
763
|
+
deleteWorkspace
|
|
1323
764
|
};
|