@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.
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-T3NYNBDC.js → chunk-5E6JRFUH.js} +201 -3
  9. package/packages/backend/dist/{chunk-XTWHEZWS.js → chunk-7B24ZWB3.js} +16 -1
  10. package/packages/backend/dist/chunk-DULUHQ5S.js +597 -0
  11. package/packages/backend/dist/{chunk-4ZFXEFOE.js → chunk-MPYASJ5A.js} +2 -87
  12. package/packages/backend/dist/{chunk-KX3OTBQ3.js → chunk-OZDYAEH4.js} +0 -114
  13. package/packages/backend/dist/{chunk-FO6WYLW4.js → chunk-TQMLJ7NY.js} +131 -44
  14. package/packages/backend/dist/chunk-TY32TUNI.js +376 -0
  15. package/packages/backend/dist/chunk-VDROUXFT.js +116 -0
  16. package/packages/backend/dist/chunk-ZDH4XI7W.js +140 -0
  17. package/packages/backend/dist/{chunk-DZ4ZGIZM.js → chunk-ZO3PZGNQ.js} +96 -655
  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 +98 -88
  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,124 +1,16 @@
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
- import { neon } from "@neondatabase/serverless";
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 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);
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 fs3 = await getFs();
364
- const path3 = await getPath();
365
- if (!fs3 || !path3) return null;
366
- const fullPath = path3.resolve(process.cwd(), prefix, cleanRel);
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 fs3.readFile(fullPath);
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 fs3 = await getFs();
391
- const path3 = await getPath();
392
- if (!fs3 || !path3) return false;
393
- const fullPath = path3.resolve(process.cwd(), prefix, cleanRel);
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 fs3.unlink(fullPath);
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 fs3 = await getFs();
416
- const path3 = await getPath();
417
- if (!fs3 || !path3) return [];
418
- const baseDir = path3.resolve(process.cwd(), folderPrefix, subPrefix);
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 fs3.readdir(baseDir, { withFileTypes: true, recursive: true });
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 = path3.join(entry.parentPath || baseDir, entry.name);
425
- const st = await fs3.stat(full);
320
+ const full = path.join(entry.parentPath || baseDir, entry.name);
321
+ const st = await fs.stat(full);
426
322
  result.push({
427
- fileName: path3.relative(path3.resolve(process.cwd(), folderPrefix), full),
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 fs3 = await getFs();
447
- const path3 = await getPath();
448
- if (!fs3 || !path3) return;
449
- const localDir = path3.resolve(process.cwd(), prefix);
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 fs3.rm(localDir, { recursive: true, force: true });
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/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) {
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: false,
671
+ success: true,
1017
672
  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.`
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 { 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
- }
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
- 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."
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
- folderKey,
1173
- workingDir,
1174
- persistenceType: "local_fs",
1175
- targetLocation: vaultDir,
1176
- syncedFiles,
1177
- uploadedCount,
1178
- downloadedCount,
1179
- syncedAt: nowIso
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
- folderKey,
1186
- workingDir,
1187
- persistenceType: "local_fs",
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
- WorkspaceFS,
1283
- SyncEngine,
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
  };