@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
@@ -0,0 +1,597 @@
1
+ import {
2
+ b2DownloadFile,
3
+ b2ListFileNames,
4
+ b2UploadFile,
5
+ createWorkspace,
6
+ deleteWorkspace,
7
+ deleteWorkspaceFile,
8
+ findUserWorkspace,
9
+ getWorkspaces,
10
+ listWorkspaceFiles,
11
+ queryUnifiedDb,
12
+ readWorkspaceFile,
13
+ updateWorkspace,
14
+ writeWorkspaceFile
15
+ } from "./chunk-JXUSBKJ2.js";
16
+
17
+ // src/workspace/WorkspaceFS.ts
18
+ import { SkipoBase } from "@ultrst-armada/kloks/functions";
19
+ var WorkspaceFS = class extends SkipoBase {
20
+ primary;
21
+ syncEngine;
22
+ config;
23
+ constructor(primary, config, syncEngine) {
24
+ super();
25
+ this.primary = primary;
26
+ this.config = config;
27
+ this.syncEngine = syncEngine;
28
+ }
29
+ setPrimary(newPrimary) {
30
+ this.primary = newPrimary;
31
+ }
32
+ setSyncEngine(engine) {
33
+ this.syncEngine = engine;
34
+ }
35
+ async exists(pathStr) {
36
+ return this.primary.exists(pathStr);
37
+ }
38
+ async stat(pathStr) {
39
+ return this.primary.stat(pathStr);
40
+ }
41
+ async list(pathStr = "") {
42
+ return this.primary.list(pathStr);
43
+ }
44
+ async read(pathStr) {
45
+ return this.primary.read(pathStr);
46
+ }
47
+ async readText(pathStr) {
48
+ const data = await this.read(pathStr);
49
+ return Buffer.from(data).toString("utf8");
50
+ }
51
+ async write(pathStr, data) {
52
+ await this.primary.write(pathStr, data);
53
+ if (this.syncEngine && this.config.sync?.enabled && this.config.sync.mode === "on_write") {
54
+ this.syncEngine.syncFile(pathStr).catch((err) => {
55
+ console.warn(`[WorkspaceFS] Async backup sync warning for '${pathStr}':`, err.message);
56
+ });
57
+ }
58
+ }
59
+ async mkdir(pathStr) {
60
+ await this.primary.mkdir(pathStr);
61
+ }
62
+ async delete(pathStr) {
63
+ await this.primary.delete(pathStr);
64
+ if (this.syncEngine && this.config.sync?.enabled && this.config.sync.deletePropagation) {
65
+ this.syncEngine.deleteFile(pathStr).catch((err) => {
66
+ console.warn(`[WorkspaceFS] Async delete sync warning for '${pathStr}':`, err.message);
67
+ });
68
+ }
69
+ }
70
+ };
71
+
72
+ // src/workspace/SyncEngine.ts
73
+ import { SkipoBase as SkipoBase2 } from "@ultrst-armada/kloks/functions";
74
+ var SyncEngine = class extends SkipoBase2 {
75
+ primary;
76
+ backups;
77
+ config;
78
+ constructor(primary, backups, config) {
79
+ super({ name: "SyncEngine" });
80
+ this.primary = primary;
81
+ this.backups = backups;
82
+ this.config = config;
83
+ }
84
+ async syncFile(pathStr) {
85
+ const data = await this.primary.read(pathStr);
86
+ for (const backup of this.backups) {
87
+ try {
88
+ await backup.write(pathStr, data);
89
+ } catch (e) {
90
+ console.error(`[SyncEngine] Failed to sync ${pathStr} to backup:`, e.message);
91
+ }
92
+ }
93
+ }
94
+ async deleteFile(pathStr) {
95
+ for (const backup of this.backups) {
96
+ try {
97
+ await backup.delete(pathStr);
98
+ } catch (e) {
99
+ console.error(`[SyncEngine] Failed to delete ${pathStr} on backup:`, e.message);
100
+ }
101
+ }
102
+ }
103
+ };
104
+
105
+ // src/workspace/WorkspaceCloneSyncEngine.ts
106
+ import { SkipoBase as SkipoBase3 } from "@ultrst-armada/kloks/functions";
107
+ var WorkspaceCloneSyncEngine = class extends SkipoBase3 {
108
+ constructor() {
109
+ super({ name: "WorkspaceCloneSyncEngine" });
110
+ }
111
+ async replicateToClones(files, clones, uploadFn) {
112
+ const results = [];
113
+ let totalSynced = 0;
114
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
115
+ for (const clone of clones) {
116
+ try {
117
+ let count = 0;
118
+ for (const file of files) {
119
+ await uploadFn(clone, file.relPath, file.content, file.contentType);
120
+ count++;
121
+ }
122
+ clone.lastSyncedAt = nowIso;
123
+ clone.filesSynced = count;
124
+ clone.status = "SYNCED";
125
+ results.push({ cloneId: clone.id, label: clone.label, provider: clone.provider, filesSynced: count, status: "SYNCED" });
126
+ totalSynced += count;
127
+ } catch (err) {
128
+ clone.status = "ERROR";
129
+ results.push({ cloneId: clone.id, label: clone.label, provider: clone.provider, filesSynced: 0, status: "ERROR", error: err.message });
130
+ }
131
+ }
132
+ return { results, totalSynced };
133
+ }
134
+ };
135
+
136
+ // src/workspace/RemoteWorkspaceService.ts
137
+ var RemoteWorkspaceService = class {
138
+ type = "remote";
139
+ async findWorkspace(workspaceId, env) {
140
+ return await findUserWorkspace(workspaceId, env);
141
+ }
142
+ async listWorkspaces(userId, env) {
143
+ return await getWorkspaces(userId, env);
144
+ }
145
+ async createWorkspace(userId, data, env) {
146
+ return await createWorkspace(userId, data, env);
147
+ }
148
+ async updateWorkspace(userId, params, env) {
149
+ return await updateWorkspace(userId, params, env);
150
+ }
151
+ async deleteWorkspace(userId, workspaceId, env) {
152
+ return await deleteWorkspace(userId, workspaceId, env);
153
+ }
154
+ async readFile(workspaceId, filePath, env) {
155
+ const { workspace, connection } = await this.findWorkspace(workspaceId, env);
156
+ if (!workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
157
+ const data = await readWorkspaceFile(workspace, connection, filePath);
158
+ if (!data) throw new Error(`File "${filePath}" not found in workspace "${workspaceId}".`);
159
+ return data;
160
+ }
161
+ async writeFile(workspaceId, filePath, content, env) {
162
+ const { workspace, connection } = await this.findWorkspace(workspaceId, env);
163
+ if (!workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
164
+ await writeWorkspaceFile(workspace, connection, filePath, content);
165
+ const size = typeof content === "string" ? new TextEncoder().encode(content).length : content.byteLength;
166
+ return { success: true, path: filePath, sizeBytes: size };
167
+ }
168
+ async deleteFile(workspaceId, filePath, env) {
169
+ const { workspace, connection } = await this.findWorkspace(workspaceId, env);
170
+ if (!workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
171
+ const deleted = await deleteWorkspaceFile(workspace, connection, filePath);
172
+ return { success: deleted };
173
+ }
174
+ async listFiles(workspaceId, subfolder = "", env) {
175
+ const { workspace, connection } = await this.findWorkspace(workspaceId, env);
176
+ if (!workspace) throw new Error(`Workspace "${workspaceId}" not found.`);
177
+ const files = await listWorkspaceFiles(workspace, connection, subfolder);
178
+ return files.map((f) => ({
179
+ path: f.fileName,
180
+ name: f.fileName.split("/").pop() || f.fileName,
181
+ sizeBytes: f.sizeBytes,
182
+ updatedAt: f.uploadTimestamp
183
+ }));
184
+ }
185
+ };
186
+ var remoteWorkspaceService = new RemoteWorkspaceService();
187
+
188
+ // src/workspace/WorkingWorkspaceService.ts
189
+ import fs2 from "fs";
190
+ import path2 from "path";
191
+
192
+ // src/core/workspaceSyncEngine.ts
193
+ import fs from "fs";
194
+ import path from "path";
195
+
196
+ // src/core/workspaceCanonical.ts
197
+ function formatCanonicalWorkspaceFolderName(appName, userName, workspaceName) {
198
+ const safeApp = (appName || "qwnsr").replace(/[^a-zA-Z0-9]/g, "_").toLowerCase();
199
+ const safeUser = (userName || "user").replace(/[^a-zA-Z0-9]/g, "_").toLowerCase();
200
+ const safeWs = (workspaceName || "workspace").replace(/[^a-zA-Z0-9]/g, "_").toLowerCase();
201
+ return `ultrst_${safeApp}_${safeUser}_${safeWs}`;
202
+ }
203
+
204
+ // src/core/workspaceSyncEngine.ts
205
+ var ACCOUNTS_FILE = path.resolve(".skipo/accounts.json");
206
+ var CONFIG_FILE = path.resolve(".skipo/workspace_config.json");
207
+ function getDefaultWorkingWorkspaceDir() {
208
+ if (process.env.VERCEL || process.env.AWS_LAMBDA_FUNCTION_NAME) {
209
+ return path.join("/tmp", "workspace");
210
+ }
211
+ return path.join(process.cwd(), "workspace");
212
+ }
213
+ function getWorkingWorkspaceConfig() {
214
+ try {
215
+ if (fs.existsSync(CONFIG_FILE)) {
216
+ const raw = fs.readFileSync(CONFIG_FILE, "utf-8");
217
+ const parsed = JSON.parse(raw);
218
+ if (parsed.workingDirectory) {
219
+ return {
220
+ workingDirectory: parsed.workingDirectory,
221
+ autoSyncIntervalMinutes: parsed.autoSyncIntervalMinutes || 5
222
+ };
223
+ }
224
+ }
225
+ } catch {
226
+ }
227
+ return {
228
+ workingDirectory: getDefaultWorkingWorkspaceDir(),
229
+ autoSyncIntervalMinutes: 5
230
+ };
231
+ }
232
+ function setWorkingWorkspaceConfig(cfg) {
233
+ const current = getWorkingWorkspaceConfig();
234
+ const updated = {
235
+ workingDirectory: (cfg.workingDirectory || current.workingDirectory).trim(),
236
+ autoSyncIntervalMinutes: cfg.autoSyncIntervalMinutes || current.autoSyncIntervalMinutes
237
+ };
238
+ try {
239
+ fs.mkdirSync(path.dirname(CONFIG_FILE), { recursive: true });
240
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(updated, null, 2), "utf-8");
241
+ } catch (err) {
242
+ console.warn("[WorkspaceSync] Failed to persist working config:", err);
243
+ }
244
+ return updated;
245
+ }
246
+ function getWorkingWorkspaceDir() {
247
+ const dir = getWorkingWorkspaceConfig().workingDirectory;
248
+ if (!fs.existsSync(dir)) {
249
+ fs.mkdirSync(dir, { recursive: true });
250
+ }
251
+ return dir;
252
+ }
253
+ async function findWorkspaceRecord(workspaceId) {
254
+ try {
255
+ if (fs.existsSync(ACCOUNTS_FILE)) {
256
+ const raw = fs.readFileSync(ACCOUNTS_FILE, "utf-8");
257
+ const accounts = JSON.parse(raw);
258
+ for (const u of Object.values(accounts)) {
259
+ if (Array.isArray(u.workspaces)) {
260
+ const ws = u.workspaces.find((w) => w.id === workspaceId);
261
+ if (ws) {
262
+ const conns = Array.isArray(u.storage_connections) ? u.storage_connections : [];
263
+ const conn = conns.find((c) => c.id === ws.storageConnectionId) || conns[0] || null;
264
+ return { user: u, workspace: ws, connection: conn };
265
+ }
266
+ }
267
+ }
268
+ }
269
+ } catch {
270
+ }
271
+ try {
272
+ const res = await queryUnifiedDb(`SELECT id, email, username, app_profiles FROM "ultrst-users"`);
273
+ for (const u of res.rows) {
274
+ const profiles = typeof u.app_profiles === "string" ? JSON.parse(u.app_profiles) : u.app_profiles || {};
275
+ const qwnsr = profiles.qwnsr || {};
276
+ const workspaces = Array.isArray(qwnsr.workspaces) ? qwnsr.workspaces : [];
277
+ const ws = workspaces.find((w) => w.id === workspaceId);
278
+ if (ws) {
279
+ const conns = qwnsr.storage_connections || profiles.srkl?.storage_connections || [];
280
+ const conn = conns.find((c) => c.id === ws.storageConnectionId) || conns[0] || null;
281
+ return { user: u, workspace: ws, connection: conn };
282
+ }
283
+ }
284
+ } catch {
285
+ }
286
+ return null;
287
+ }
288
+ function getWorkspaceFolderKey(workspace, user) {
289
+ if (workspace.localFolderKey) return workspace.localFolderKey;
290
+ if (workspace.localFolderName && workspace.localFolderName.startsWith("ultrst_")) return workspace.localFolderName;
291
+ const userName = user?.username || user?.name || (user?.email ? user.email.split("@")[0] : "user");
292
+ return formatCanonicalWorkspaceFolderName("qwnsr", userName, workspace.name);
293
+ }
294
+ async function collectLocalFiles(dir, baseDir = dir) {
295
+ if (!fs.existsSync(dir)) return [];
296
+ const entries = await fs.promises.readdir(dir, { withFileTypes: true });
297
+ const results = [];
298
+ for (const entry of entries) {
299
+ if (entry.name.startsWith(".") && entry.name !== ".bzEmpty") continue;
300
+ const full = path.join(dir, entry.name);
301
+ if (entry.isDirectory()) {
302
+ const nested = await collectLocalFiles(full, baseDir);
303
+ results.push(...nested);
304
+ } else if (entry.isFile()) {
305
+ const st = await fs.promises.stat(full);
306
+ const rel = path.relative(baseDir, full).replace(/\\/g, "/");
307
+ results.push({ relPath: rel, fullPath: full, mtimeMs: st.mtimeMs, sizeBytes: st.size });
308
+ }
309
+ }
310
+ return results;
311
+ }
312
+ async function syncWorkspace(workspaceId) {
313
+ const match = await findWorkspaceRecord(workspaceId);
314
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
315
+ if (!match) {
316
+ return {
317
+ success: false,
318
+ workspaceId,
319
+ folderKey: workspaceId,
320
+ workingDir: getWorkingWorkspaceDir(),
321
+ persistenceType: "local_fs",
322
+ targetLocation: "Unknown",
323
+ syncedFiles: [],
324
+ uploadedCount: 0,
325
+ downloadedCount: 0,
326
+ syncedAt: nowIso,
327
+ error: `Workspace '${workspaceId}' not found.`
328
+ };
329
+ }
330
+ const { workspace, user, connection } = match;
331
+ const folderKey = getWorkspaceFolderKey(workspace, user);
332
+ const workingDir = getWorkingWorkspaceDir();
333
+ const isB2 = workspace.storageProvider === "backblaze_b2" || workspace.storageConfig?.type === "b2";
334
+ const syncedFiles = [];
335
+ let uploadedCount = 0;
336
+ let downloadedCount = 0;
337
+ if (isB2) {
338
+ const creds = workspace.storageConfig || connection?.credentials || connection || {};
339
+ const keyId = creds.keyId || creds.b2KeyId;
340
+ const appKey = creds.applicationKey || creds.b2ApplicationKey || creds.appKey;
341
+ const bucketName = creds.bucketName || creds.b2BucketName || workspace.b2BucketName || "ultrst-apps";
342
+ if (!keyId || !appKey) {
343
+ return {
344
+ success: false,
345
+ workspaceId,
346
+ folderKey,
347
+ workingDir,
348
+ persistenceType: "backblaze_b2",
349
+ targetLocation: bucketName,
350
+ syncedFiles: [],
351
+ uploadedCount: 0,
352
+ downloadedCount: 0,
353
+ syncedAt: nowIso,
354
+ error: "Missing Backblaze B2 credentials for sync."
355
+ };
356
+ }
357
+ try {
358
+ const b2Prefix = `${folderKey}/`;
359
+ const remoteFiles = await b2ListFileNames(keyId, appKey, bucketName, b2Prefix);
360
+ const remoteMap = /* @__PURE__ */ new Map();
361
+ for (const rf of remoteFiles) {
362
+ const cleanName = rf.fileName.slice(b2Prefix.length);
363
+ if (cleanName) remoteMap.set(cleanName, { fileId: rf.fileId, size: rf.contentLength, timestamp: rf.uploadTimestamp });
364
+ }
365
+ const localFiles = await collectLocalFiles(workingDir);
366
+ const localMap = /* @__PURE__ */ new Map();
367
+ for (const lf of localFiles) {
368
+ localMap.set(lf.relPath, lf);
369
+ }
370
+ for (const [relPath, rInfo] of remoteMap.entries()) {
371
+ const lFile = localMap.get(relPath);
372
+ const shouldDownload = !lFile || rInfo.timestamp > lFile.mtimeMs + 2e3;
373
+ if (shouldDownload) {
374
+ const buf = await b2DownloadFile(keyId, appKey, bucketName, `${b2Prefix}${relPath}`);
375
+ if (buf) {
376
+ const destPath = path.join(workingDir, relPath);
377
+ await fs.promises.mkdir(path.dirname(destPath), { recursive: true });
378
+ await fs.promises.writeFile(destPath, buf);
379
+ try {
380
+ const fileTime = new Date(rInfo.timestamp);
381
+ await fs.promises.utimes(destPath, fileTime, fileTime);
382
+ } catch {
383
+ }
384
+ syncedFiles.push({ fileName: relPath, action: "DOWNLOADED", sizeBytes: buf.byteLength });
385
+ downloadedCount++;
386
+ }
387
+ }
388
+ }
389
+ for (const [relPath, lFile] of localMap.entries()) {
390
+ const rInfo = remoteMap.get(relPath);
391
+ const shouldUpload = !rInfo || lFile.mtimeMs > rInfo.timestamp + 2e3;
392
+ if (shouldUpload) {
393
+ const content = await fs.promises.readFile(lFile.fullPath);
394
+ await b2UploadFile(keyId, appKey, bucketName, `${b2Prefix}${relPath}`, new Uint8Array(content));
395
+ syncedFiles.push({ fileName: relPath, action: "UPLOADED", sizeBytes: lFile.sizeBytes });
396
+ uploadedCount++;
397
+ } else if (!syncedFiles.some((f) => f.fileName === relPath)) {
398
+ syncedFiles.push({ fileName: relPath, action: "UP_TO_DATE", sizeBytes: lFile.sizeBytes });
399
+ }
400
+ }
401
+ return {
402
+ success: true,
403
+ workspaceId,
404
+ folderKey,
405
+ workingDir,
406
+ persistenceType: "backblaze_b2",
407
+ targetLocation: `B2://${bucketName}/${folderKey}/`,
408
+ syncedFiles,
409
+ uploadedCount,
410
+ downloadedCount,
411
+ syncedAt: nowIso
412
+ };
413
+ } catch (err) {
414
+ return {
415
+ success: false,
416
+ workspaceId,
417
+ folderKey,
418
+ workingDir,
419
+ persistenceType: "backblaze_b2",
420
+ targetLocation: bucketName,
421
+ syncedFiles,
422
+ uploadedCount,
423
+ downloadedCount,
424
+ syncedAt: nowIso,
425
+ error: err.message || "Backblaze sync failed."
426
+ };
427
+ }
428
+ }
429
+ const vaultDir = path.resolve(process.cwd(), folderKey);
430
+ await fs.promises.mkdir(vaultDir, { recursive: true });
431
+ try {
432
+ const vaultFiles = await collectLocalFiles(vaultDir);
433
+ const vaultMap = new Map(vaultFiles.map((f) => [f.relPath, f]));
434
+ const workingFiles = await collectLocalFiles(workingDir);
435
+ const workingMap = new Map(workingFiles.map((f) => [f.relPath, f]));
436
+ for (const [relPath, vFile] of vaultMap.entries()) {
437
+ const wFile = workingMap.get(relPath);
438
+ const shouldDownload = !wFile || vFile.mtimeMs > wFile.mtimeMs + 1e3;
439
+ if (shouldDownload) {
440
+ const dest = path.join(workingDir, relPath);
441
+ await fs.promises.mkdir(path.dirname(dest), { recursive: true });
442
+ await fs.promises.copyFile(vFile.fullPath, dest);
443
+ try {
444
+ const vTime = new Date(vFile.mtimeMs);
445
+ await fs.promises.utimes(dest, vTime, vTime);
446
+ } catch {
447
+ }
448
+ syncedFiles.push({ fileName: relPath, action: "DOWNLOADED", sizeBytes: vFile.sizeBytes });
449
+ downloadedCount++;
450
+ }
451
+ }
452
+ for (const [relPath, wFile] of workingMap.entries()) {
453
+ const vFile = vaultMap.get(relPath);
454
+ const shouldUpload = !vFile || wFile.mtimeMs > vFile.mtimeMs + 1e3;
455
+ if (shouldUpload) {
456
+ const dest = path.join(vaultDir, relPath);
457
+ await fs.promises.mkdir(path.dirname(dest), { recursive: true });
458
+ await fs.promises.copyFile(wFile.fullPath, dest);
459
+ try {
460
+ const wTime = new Date(wFile.mtimeMs);
461
+ await fs.promises.utimes(dest, wTime, wTime);
462
+ } catch {
463
+ }
464
+ syncedFiles.push({ fileName: relPath, action: "UPLOADED", sizeBytes: wFile.sizeBytes });
465
+ uploadedCount++;
466
+ } else if (!syncedFiles.some((f) => f.fileName === relPath)) {
467
+ syncedFiles.push({ fileName: relPath, action: "UP_TO_DATE", sizeBytes: wFile.sizeBytes });
468
+ }
469
+ }
470
+ return {
471
+ success: true,
472
+ workspaceId,
473
+ folderKey,
474
+ workingDir,
475
+ persistenceType: "local_fs",
476
+ targetLocation: vaultDir,
477
+ syncedFiles,
478
+ uploadedCount,
479
+ downloadedCount,
480
+ syncedAt: nowIso
481
+ };
482
+ } catch (err) {
483
+ return {
484
+ success: false,
485
+ workspaceId,
486
+ folderKey,
487
+ workingDir,
488
+ persistenceType: "local_fs",
489
+ targetLocation: vaultDir,
490
+ syncedFiles,
491
+ uploadedCount,
492
+ downloadedCount,
493
+ syncedAt: nowIso,
494
+ error: err.message
495
+ };
496
+ }
497
+ }
498
+
499
+ // src/workspace/WorkingWorkspaceService.ts
500
+ var WorkingWorkspaceService = class {
501
+ constructor(workingDirResolver) {
502
+ this.workingDirResolver = workingDirResolver;
503
+ }
504
+ workingDirResolver;
505
+ type = "working";
506
+ getWorkingDir() {
507
+ return this.workingDirResolver ? this.workingDirResolver() : getWorkingWorkspaceDir();
508
+ }
509
+ async findWorkspace(workspaceId, env) {
510
+ return await findUserWorkspace(workspaceId, env);
511
+ }
512
+ async listWorkspaces(userId, env) {
513
+ return await getWorkspaces(userId, env);
514
+ }
515
+ async createWorkspace(userId, data, env) {
516
+ const res = await createWorkspace(userId, data, env);
517
+ const dir = this.getWorkingDir();
518
+ try {
519
+ await fs2.promises.mkdir(dir, { recursive: true });
520
+ } catch {
521
+ }
522
+ return res;
523
+ }
524
+ async updateWorkspace(userId, params, env) {
525
+ return await updateWorkspace(userId, params, env);
526
+ }
527
+ async deleteWorkspace(userId, workspaceId, env) {
528
+ return await deleteWorkspace(userId, workspaceId, env);
529
+ }
530
+ async readFile(_workspaceId, filePath) {
531
+ const cleanRel = filePath.replace(/^\/+/, "");
532
+ const fullPath = path2.resolve(this.getWorkingDir(), cleanRel);
533
+ return await fs2.promises.readFile(fullPath);
534
+ }
535
+ async writeFile(_workspaceId, filePath, content) {
536
+ const cleanRel = filePath.replace(/^\/+/, "");
537
+ const fullPath = path2.resolve(this.getWorkingDir(), cleanRel);
538
+ await fs2.promises.mkdir(path2.dirname(fullPath), { recursive: true });
539
+ const buffer = typeof content === "string" ? Buffer.from(content) : Buffer.from(content.buffer, content.byteOffset, content.byteLength);
540
+ await fs2.promises.writeFile(fullPath, buffer);
541
+ return { success: true, path: filePath, sizeBytes: buffer.byteLength };
542
+ }
543
+ async deleteFile(_workspaceId, filePath) {
544
+ const cleanRel = filePath.replace(/^\/+/, "");
545
+ const fullPath = path2.resolve(this.getWorkingDir(), cleanRel);
546
+ try {
547
+ await fs2.promises.unlink(fullPath);
548
+ return { success: true };
549
+ } catch {
550
+ return { success: false };
551
+ }
552
+ }
553
+ async listFiles(_workspaceId, subfolder = "") {
554
+ const baseDir = path2.resolve(this.getWorkingDir(), subfolder.replace(/^\/+/, ""));
555
+ if (!fs2.existsSync(baseDir)) return [];
556
+ const entries = await fs2.promises.readdir(baseDir, { withFileTypes: true });
557
+ return entries.map((e) => {
558
+ const full = path2.join(baseDir, e.name);
559
+ let sizeBytes = 0;
560
+ let updatedAt = Date.now();
561
+ try {
562
+ const s = fs2.statSync(full);
563
+ sizeBytes = s.size;
564
+ updatedAt = s.mtimeMs;
565
+ } catch {
566
+ }
567
+ return {
568
+ path: path2.relative(this.getWorkingDir(), full),
569
+ name: e.name,
570
+ isFolder: e.isDirectory(),
571
+ sizeBytes,
572
+ updatedAt
573
+ };
574
+ });
575
+ }
576
+ async sync(workspaceId, _options, _env) {
577
+ return await syncWorkspace(workspaceId);
578
+ }
579
+ };
580
+ var workingWorkspaceService = new WorkingWorkspaceService();
581
+
582
+ export {
583
+ WorkspaceFS,
584
+ SyncEngine,
585
+ WorkspaceCloneSyncEngine,
586
+ RemoteWorkspaceService,
587
+ remoteWorkspaceService,
588
+ getDefaultWorkingWorkspaceDir,
589
+ getWorkingWorkspaceConfig,
590
+ setWorkingWorkspaceConfig,
591
+ getWorkingWorkspaceDir,
592
+ findWorkspaceRecord,
593
+ getWorkspaceFolderKey,
594
+ syncWorkspace,
595
+ WorkingWorkspaceService,
596
+ workingWorkspaceService
597
+ };