@ultrst-armada/kloks 1.4.3 → 1.4.4

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 (79) hide show
  1. package/package.json +8 -20
  2. package/packages/audio-midi/dist/index.d.ts +23 -14
  3. package/packages/audio-midi/dist/index.js +170 -45
  4. package/packages/audio-midi/kloks.manifest.json +8 -8
  5. package/packages/audio-midi/package.json +1 -1
  6. package/packages/backend/dist/{WebSocketTransport-CxUzUfwl.d.ts → WebSocketTransport-CHmkJ0tj.d.ts} +109 -2
  7. package/packages/backend/dist/auth/index.js +6 -6
  8. package/packages/backend/dist/chunk-5336MTXD.js +597 -0
  9. package/packages/backend/dist/{chunk-T3NYNBDC.js → chunk-5E6JRFUH.js} +201 -3
  10. package/packages/backend/dist/{chunk-XTWHEZWS.js → chunk-7B24ZWB3.js} +16 -1
  11. package/packages/backend/dist/{chunk-DZ4ZGIZM.js → chunk-JXUSBKJ2.js} +91 -654
  12. package/packages/backend/dist/{chunk-FO6WYLW4.js → chunk-KI3LHMUN.js} +133 -46
  13. package/packages/backend/dist/{chunk-4ZFXEFOE.js → chunk-MPYASJ5A.js} +2 -87
  14. package/packages/backend/dist/{chunk-KX3OTBQ3.js → chunk-OZDYAEH4.js} +0 -114
  15. package/packages/backend/dist/chunk-TY32TUNI.js +376 -0
  16. package/packages/backend/dist/chunk-VDROUXFT.js +116 -0
  17. package/packages/backend/dist/chunk-ZDH4XI7W.js +140 -0
  18. package/packages/backend/dist/client/index.d.ts +2 -3
  19. package/packages/backend/dist/connectivity/index.d.ts +18 -6
  20. package/packages/backend/dist/connectivity/index.js +3 -7
  21. package/packages/backend/dist/index.d.ts +3 -6
  22. package/packages/backend/dist/index.js +101 -91
  23. package/packages/backend/dist/krnl-services.d.ts +84 -7
  24. package/packages/backend/dist/krnl-services.js +40 -12
  25. package/packages/backend/dist/services/index.d.ts +4 -6
  26. package/packages/backend/dist/services/index.js +2 -2
  27. package/packages/backend/dist/srkl/index.js +6 -4
  28. package/packages/backend/dist/storage/index.js +7 -7
  29. package/packages/backend/dist/workspace/index.js +2 -2
  30. package/packages/backend/kloks.manifest.json +47 -45
  31. package/packages/backend/package.json +3 -8
  32. package/packages/client/package.json +1 -1
  33. package/packages/contracts/dist/index.js +5 -10
  34. package/packages/contracts/package.json +1 -1
  35. package/packages/functions/dist/index.d.ts +12 -1
  36. package/packages/functions/dist/index.js +132 -24
  37. package/packages/functions/package.json +1 -1
  38. package/packages/orchestrations/dist/index.d.ts +33 -31
  39. package/packages/orchestrations/dist/index.js +81 -203
  40. package/packages/orchestrations/kloks.manifest.json +10 -2
  41. package/packages/orchestrations/package.json +2 -2
  42. package/packages/services/dist/index.d.ts +51 -1
  43. package/packages/services/dist/index.js +234 -36
  44. package/packages/services/kloks.manifest.json +69 -33
  45. package/packages/services/package.json +1 -1
  46. package/packages/state-graph/dist/{BaseGraph-BvkSYOTw.d.ts → BaseGraph-Bd5F1NMP.d.ts} +1 -1
  47. package/packages/state-graph/dist/{BaseNode-DTcd3K1B.d.ts → BaseNode-DKpGXMy8.d.ts} +6 -0
  48. package/packages/state-graph/dist/{CompatibilityMatrix-Dj-tCWUA.d.ts → CompatibilityMatrix-TiEJ3j3_.d.ts} +1 -1
  49. package/packages/state-graph/dist/domain/index.d.ts +3 -3
  50. package/packages/state-graph/dist/domain/index.js +0 -1
  51. package/packages/state-graph/dist/index.d.ts +40 -8
  52. package/packages/state-graph/dist/index.js +214 -65
  53. package/packages/state-graph/dist/rules/index.d.ts +3 -3
  54. package/packages/state-graph/dist/rules/index.js +0 -1
  55. package/packages/state-graph/dist/spatial/index.d.ts +4 -4
  56. package/packages/state-graph/dist/spatial/index.js +0 -1
  57. package/packages/state-graph/dist/state/index.js +1 -3
  58. package/packages/state-graph/dist/store/index.d.ts +4 -4
  59. package/packages/state-graph/dist/store/index.js +0 -1
  60. package/packages/state-graph/dist/{types-VDoc4FIc.d.ts → types-D5kQSa65.d.ts} +2 -2
  61. package/packages/state-graph/kloks.manifest.json +26 -10
  62. package/packages/state-graph/package.json +2 -8
  63. package/packages/backend/dist/IdempotencyManager-B5MjK871.d.ts +0 -16
  64. package/packages/backend/dist/chunk-25Y7AVTP.js +0 -55
  65. package/packages/backend/dist/chunk-3EPY34R6.js +0 -67
  66. package/packages/backend/dist/chunk-7KNGX522.js +0 -220
  67. package/packages/backend/dist/chunk-FZKBTF34.js +0 -15
  68. package/packages/backend/dist/chunk-QGHDJGYS.js +0 -92
  69. package/packages/backend/dist/chunk-UPFKBBQI.js +0 -138
  70. package/packages/backend/dist/chunk-VQEFULWT.js +0 -88
  71. package/packages/backend/dist/execution/index.d.ts +0 -124
  72. package/packages/backend/dist/execution/index.js +0 -20
  73. package/packages/backend/dist/types-BERZJ93O.d.ts +0 -110
  74. package/packages/state-graph/dist/chunk-3RG5ZIWI.js +0 -10
  75. package/packages/state-graph/dist/chunk-Q5I42UX7.js +0 -0
  76. package/packages/state-graph/dist/chunk-ZTHBPV24.js +0 -267
  77. package/packages/state-graph/dist/execution/index.d.ts +0 -152
  78. package/packages/state-graph/dist/execution/index.js +0 -16
  79. /package/packages/state-graph/dist/{chunk-SHIBCPGQ.js → chunk-EW4ACSZB.js} +0 -0
@@ -1,121 +1,13 @@
1
- // src/workspace/WorkspaceFS.ts
2
- import { SkipoBase } from "@ultrst-armada/kloks/functions";
3
- var WorkspaceFS = class extends SkipoBase {
4
- primary;
5
- syncEngine;
6
- config;
7
- constructor(primary, config, syncEngine) {
8
- super();
9
- this.primary = primary;
10
- this.config = config;
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
  import { neon } from "@neondatabase/serverless";
@@ -343,12 +235,12 @@ async function writeWorkspaceFile(workspace, connection, relativePath, content,
343
235
  await b2UploadFile(keyId, appKey, bucketName, fullKey, buffer, contentType);
344
236
  return;
345
237
  }
346
- const fs3 = await getFs();
347
- const path3 = await getPath();
348
- if (!fs3 || !path3) throw new Error("Local filesystem operations not supported in this runtime.");
349
- const localDir = path3.resolve(process.cwd(), prefix, path3.dirname(cleanRel));
350
- await fs3.mkdir(localDir, { recursive: true });
351
- await fs3.writeFile(path3.resolve(process.cwd(), prefix, cleanRel), buffer);
238
+ const fs = await getFs();
239
+ const path = await getPath();
240
+ if (!fs || !path) throw new Error("Local filesystem operations not supported in this runtime.");
241
+ const localDir = path.resolve(process.cwd(), prefix, path.dirname(cleanRel));
242
+ await fs.mkdir(localDir, { recursive: true });
243
+ await fs.writeFile(path.resolve(process.cwd(), prefix, cleanRel), buffer);
352
244
  }
353
245
  async function readWorkspaceFile(workspace, connection, relativePath) {
354
246
  const cleanRel = relativePath.replace(/^\/+/, "");
@@ -360,12 +252,12 @@ async function readWorkspaceFile(workspace, connection, relativePath) {
360
252
  const fullKey = `${prefix}/${cleanRel}`;
361
253
  return await b2DownloadFile(keyId, appKey, bucketName, fullKey);
362
254
  }
363
- const fs3 = await getFs();
364
- const path3 = await getPath();
365
- if (!fs3 || !path3) return null;
366
- const fullPath = path3.resolve(process.cwd(), prefix, cleanRel);
255
+ const fs = await getFs();
256
+ const path = await getPath();
257
+ if (!fs || !path) return null;
258
+ const fullPath = path.resolve(process.cwd(), prefix, cleanRel);
367
259
  try {
368
- const buf = await fs3.readFile(fullPath);
260
+ const buf = await fs.readFile(fullPath);
369
261
  return new Uint8Array(buf);
370
262
  } catch {
371
263
  return null;
@@ -387,12 +279,12 @@ async function deleteWorkspaceFile(workspace, connection, relativePath) {
387
279
  }
388
280
  return false;
389
281
  }
390
- const fs3 = await getFs();
391
- const path3 = await getPath();
392
- if (!fs3 || !path3) return false;
393
- const fullPath = path3.resolve(process.cwd(), prefix, cleanRel);
282
+ const fs = await getFs();
283
+ const path = await getPath();
284
+ if (!fs || !path) return false;
285
+ const fullPath = path.resolve(process.cwd(), prefix, cleanRel);
394
286
  try {
395
- await fs3.unlink(fullPath);
287
+ await fs.unlink(fullPath);
396
288
  return true;
397
289
  } catch {
398
290
  return false;
@@ -412,19 +304,19 @@ async function listWorkspaceFiles(workspace, connection, subPrefix = "") {
412
304
  uploadTimestamp: f.uploadTimestamp
413
305
  }));
414
306
  }
415
- const fs3 = await getFs();
416
- const path3 = await getPath();
417
- if (!fs3 || !path3) return [];
418
- const baseDir = path3.resolve(process.cwd(), folderPrefix, subPrefix);
307
+ const fs = await getFs();
308
+ const path = await getPath();
309
+ if (!fs || !path) return [];
310
+ const baseDir = path.resolve(process.cwd(), folderPrefix, subPrefix);
419
311
  try {
420
- const entries = await fs3.readdir(baseDir, { withFileTypes: true, recursive: true });
312
+ const entries = await fs.readdir(baseDir, { withFileTypes: true, recursive: true });
421
313
  const result = [];
422
314
  for (const entry of entries) {
423
315
  if (entry.isFile()) {
424
- const full = path3.join(entry.parentPath || baseDir, entry.name);
425
- const st = await fs3.stat(full);
316
+ const full = path.join(entry.parentPath || baseDir, entry.name);
317
+ const st = await fs.stat(full);
426
318
  result.push({
427
- fileName: path3.relative(path3.resolve(process.cwd(), folderPrefix), full),
319
+ fileName: path.relative(path.resolve(process.cwd(), folderPrefix), full),
428
320
  sizeBytes: st.size
429
321
  });
430
322
  }
@@ -443,12 +335,12 @@ async function deleteWorkspaceFolder(workspace, connection) {
443
335
  await b2DeleteFolder(keyId, appKey, bucketName, prefix);
444
336
  return;
445
337
  }
446
- const fs3 = await getFs();
447
- const path3 = await getPath();
448
- if (!fs3 || !path3) return;
449
- const localDir = path3.resolve(process.cwd(), prefix);
338
+ const fs = await getFs();
339
+ const path = await getPath();
340
+ if (!fs || !path) return;
341
+ const localDir = path.resolve(process.cwd(), prefix);
450
342
  try {
451
- await fs3.rm(localDir, { recursive: true, force: true });
343
+ await fs.rm(localDir, { recursive: true, force: true });
452
344
  } catch {
453
345
  }
454
346
  }
@@ -648,73 +540,6 @@ async function renameAppInWorkspaceData(userId, workspaceId, appId, newName, env
648
540
  return await saveWorkspaceData(userId, workspaceId, wsData, env);
649
541
  }
650
542
 
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
543
  // src/core/workspaceCore.ts
719
544
  async function findUserWorkspace(workspaceId, env) {
720
545
  const res = await queryUnifiedDb(`SELECT id, email, username, app_profiles FROM "ultrst-users"`, [], env);
@@ -832,461 +657,84 @@ async function deleteWorkspace(userId, wsId, env) {
832
657
  return { success: true, workspaces: profiles.depm.workspaces };
833
658
  }
834
659
 
835
- // src/workspace/RemoteWorkspaceService.ts
836
- var RemoteWorkspaceService = class {
837
- type = "remote";
838
- async findWorkspace(workspaceId, env) {
839
- return await findUserWorkspace(workspaceId, env);
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) {
660
+ // src/core/workspaceStorageDetailsCore.ts
661
+ async function getWorkspaceStorageDetails(workspaceId, env) {
662
+ if (!workspaceId) return { success: false, error: "workspaceId is required" };
663
+ const { workspace, connection } = await findUserWorkspace(workspaceId, env);
664
+ const folderPrefix = workspace?.localFolderKey || workspace?.localFolderName || (workspace?.workspacePath ? workspace.workspacePath.replace(/^\.\//, "") : workspaceId);
665
+ if (!connection || connection.provider !== "backblaze_b2" && connection.provider !== "BACKBLAZE_B2") {
1015
666
  return {
1016
- success: false,
667
+ success: true,
1017
668
  workspaceId,
1018
- folderKey: workspaceId,
1019
- workingDir: getWorkingWorkspaceDir(),
1020
- persistenceType: "local_fs",
1021
- targetLocation: "Unknown",
1022
- syncedFiles: [],
1023
- uploadedCount: 0,
1024
- downloadedCount: 0,
1025
- syncedAt: nowIso,
1026
- error: `Workspace '${workspaceId}' not found.`
669
+ storageProvider: workspace?.storageProvider || "local_fs",
670
+ connection: connection || null,
671
+ folderPrefix,
672
+ localStats: { exists: false, appsCount: 0, ecosystemsCount: 0 },
673
+ bucket: null,
674
+ files: []
1027
675
  };
1028
676
  }
1029
- const { workspace, user, connection } = match;
1030
- const folderKey = getWorkspaceFolderKey(workspace, user);
1031
- const workingDir = getWorkingWorkspaceDir();
1032
- const isB2 = workspace.storageProvider === "backblaze_b2" || workspace.storageConfig?.type === "b2";
1033
- const syncedFiles = [];
1034
- let uploadedCount = 0;
1035
- let downloadedCount = 0;
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
- }
677
+ const keyId = connection.b2KeyId || connection.keyId;
678
+ const applicationKey = connection.b2ApplicationKey || connection.appKey;
679
+ const bucketName = connection.b2BucketName || workspace.b2BucketName || "ultrst-apps";
680
+ try {
681
+ const buckets = await b2ListBuckets(keyId, applicationKey, void 0, bucketName);
682
+ const bucketObj = buckets.find((b) => b.bucketName === bucketName);
683
+ if (!bucketObj) {
1100
684
  return {
1101
685
  success: true,
1102
686
  workspaceId,
1103
- folderKey,
1104
- workingDir,
1105
- persistenceType: "backblaze_b2",
1106
- targetLocation: `B2://${bucketName}/${folderKey}/`,
1107
- syncedFiles,
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."
687
+ storageProvider: "backblaze_b2",
688
+ connection: { id: connection.id, label: connection.label, provider: connection.provider },
689
+ folderPrefix,
690
+ bucket: { name: bucketName, status: "BUCKET_NOT_FOUND" },
691
+ files: []
1125
692
  };
1126
693
  }
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
- }
694
+ const rawFiles = await b2ListFileNames(keyId, applicationKey, bucketName, `${folderPrefix}/`);
1169
695
  return {
1170
696
  success: true,
1171
697
  workspaceId,
1172
- folderKey,
1173
- workingDir,
1174
- persistenceType: "local_fs",
1175
- targetLocation: vaultDir,
1176
- syncedFiles,
1177
- uploadedCount,
1178
- downloadedCount,
1179
- syncedAt: nowIso
698
+ storageProvider: "backblaze_b2",
699
+ connection: { id: connection.id, label: connection.label, provider: connection.provider },
700
+ folderPrefix,
701
+ bucket: {
702
+ id: bucketObj.bucketId,
703
+ name: bucketObj.bucketName,
704
+ type: bucketObj.bucketType,
705
+ endpoint: connection.b2Endpoint || "s3.eu-central-003.backblazeb2.com",
706
+ region: connection.b2Region || "eu-central-003",
707
+ status: "CONNECTED"
708
+ },
709
+ fileCount: rawFiles.length,
710
+ files: rawFiles.map((f) => ({
711
+ fileName: f.fileName,
712
+ sizeBytes: f.contentLength,
713
+ uploadTimestamp: f.uploadTimestamp
714
+ }))
1180
715
  };
1181
716
  } catch (err) {
1182
717
  return {
1183
718
  success: false,
1184
719
  workspaceId,
1185
- folderKey,
1186
- workingDir,
1187
- persistenceType: "local_fs",
1188
- targetLocation: vaultDir,
1189
- syncedFiles,
1190
- uploadedCount,
1191
- downloadedCount,
1192
- syncedAt: nowIso,
1193
- error: err.message
720
+ storageProvider: "backblaze_b2",
721
+ error: err.message,
722
+ folderPrefix
1194
723
  };
1195
724
  }
1196
725
  }
1197
726
 
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
727
  export {
1282
- WorkspaceFS,
1283
- SyncEngine,
1284
- WorkspaceCloneSyncEngine,
728
+ formatCanonicalWorkspaceFolderName,
729
+ sanitizeWorkspaceName,
1285
730
  cleanDbUrl,
1286
731
  getUnifiedDbUrl,
1287
732
  queryUnifiedDb,
1288
733
  b2ListBuckets,
1289
734
  getB2BucketId,
735
+ b2UploadFile,
736
+ b2DownloadFile,
737
+ b2ListFileNames,
1290
738
  b2DeleteFileVersion,
1291
739
  b2DeleteFolder,
1292
740
  getWorkspaceFolderPrefix,
@@ -1308,16 +756,5 @@ export {
1308
756
  getWorkspaces,
1309
757
  createWorkspace,
1310
758
  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
759
+ deleteWorkspace
1323
760
  };