@catmint-fs/core 0.0.0-prealpha.0 → 0.0.0-prealpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -180,7 +180,17 @@ declare class Layer {
180
180
  * Enforce ENOSYS for operations that require symlink support.
181
181
  */
182
182
  private assertSymlinksSupported;
183
+ /**
184
+ * Resolve a virtual path to a real (adapter-level) path by prepending
185
+ * the layer root. Virtual "/" maps to this.root, virtual "/foo" maps
186
+ * to this.root + "/foo", etc.
187
+ */
183
188
  private resolvePath;
189
+ /**
190
+ * Convert a real (adapter-level) path back to a virtual path by stripping
191
+ * the layer root prefix. Used when returning paths to the caller.
192
+ */
193
+ private toVirtualPath;
184
194
  /**
185
195
  * Follow symlinks to resolve the final path. Used by operations that
186
196
  * follow symlinks (readFile, stat, writeFile, chmod, chown, exists).
@@ -211,11 +221,20 @@ declare class Layer {
211
221
  }>;
212
222
  getChanges(): ChangeEntry[];
213
223
  getChangeDetail(path: string): Promise<ChangeDetail | null>;
224
+ /**
225
+ * Convert a ChangeEntry's paths from real to virtual.
226
+ */
227
+ private changeEntryToVirtual;
228
+ /**
229
+ * Convert a ChangeDetail's paths from real to virtual.
230
+ */
231
+ private changeDetailToVirtual;
214
232
  apply(options?: ApplyOptions): Promise<ApplyResult>;
215
233
  private applyBestEffort;
216
234
  private applyTransaction;
217
235
  /**
218
236
  * Convert a flat ChangeDetail back to a ChangeEntry for error reporting.
237
+ * Paths are converted to virtual for user-facing output.
219
238
  */
220
239
  private detailToChangeEntry;
221
240
  /**
package/dist/index.js CHANGED
@@ -454,9 +454,29 @@ var Layer = class {
454
454
  throw new FsError("ENOSYS", "operation not supported: symlinks are disabled");
455
455
  }
456
456
  }
457
+ /**
458
+ * Resolve a virtual path to a real (adapter-level) path by prepending
459
+ * the layer root. Virtual "/" maps to this.root, virtual "/foo" maps
460
+ * to this.root + "/foo", etc.
461
+ */
457
462
  resolvePath(p) {
458
- if (p.startsWith("/")) return p;
459
- return this.root + (this.root.endsWith("/") ? "" : "/") + p;
463
+ const base = this.root.endsWith("/") ? this.root.slice(0, -1) : this.root;
464
+ const virtual = p.startsWith("/") ? p : "/" + p;
465
+ if (virtual === "/") return base || "/";
466
+ return base + virtual;
467
+ }
468
+ /**
469
+ * Convert a real (adapter-level) path back to a virtual path by stripping
470
+ * the layer root prefix. Used when returning paths to the caller.
471
+ */
472
+ toVirtualPath(realPath) {
473
+ const base = this.root.endsWith("/") ? this.root.slice(0, -1) : this.root;
474
+ if (base === "" || base === "/") return realPath;
475
+ if (realPath === base) return "/";
476
+ if (realPath.startsWith(base + "/")) {
477
+ return realPath.substring(base.length);
478
+ }
479
+ return realPath;
460
480
  }
461
481
  /**
462
482
  * Follow symlinks to resolve the final path. Used by operations that
@@ -1090,7 +1110,7 @@ var Layer = class {
1090
1110
  if (!isDir) {
1091
1111
  throw new FsError("ENOTDIR", `not a directory: ${absPath}`);
1092
1112
  }
1093
- const entries = await this.readdir(absPath);
1113
+ const entries = await this.readdir(path2);
1094
1114
  if (entries.length > 0) {
1095
1115
  throw new FsError("ENOTEMPTY", `directory not empty: ${absPath}`);
1096
1116
  }
@@ -1247,12 +1267,56 @@ var Layer = class {
1247
1267
  // --- Changes ---
1248
1268
  getChanges() {
1249
1269
  this.assertNotDisposed();
1250
- return this.ledger.getAll();
1270
+ return this.ledger.getAll().map((entry) => this.changeEntryToVirtual(entry));
1251
1271
  }
1252
1272
  async getChangeDetail(path2) {
1253
1273
  this.assertNotDisposed();
1254
1274
  const absPath = this.resolvePath(path2);
1255
- return this.ledger.getDetail(absPath);
1275
+ const detail = this.ledger.getDetail(absPath);
1276
+ if (!detail) return null;
1277
+ return this.changeDetailToVirtual(detail);
1278
+ }
1279
+ /**
1280
+ * Convert a ChangeEntry's paths from real to virtual.
1281
+ */
1282
+ changeEntryToVirtual(entry) {
1283
+ switch (entry.type) {
1284
+ case "create":
1285
+ return { ...entry, path: this.toVirtualPath(entry.path) };
1286
+ case "update":
1287
+ return { ...entry, path: this.toVirtualPath(entry.path) };
1288
+ case "delete":
1289
+ return { ...entry, path: this.toVirtualPath(entry.path) };
1290
+ case "rename":
1291
+ return { ...entry, from: this.toVirtualPath(entry.from), to: this.toVirtualPath(entry.to) };
1292
+ case "chmod":
1293
+ return { ...entry, path: this.toVirtualPath(entry.path) };
1294
+ case "chown":
1295
+ return { ...entry, path: this.toVirtualPath(entry.path) };
1296
+ case "symlink":
1297
+ return { ...entry, path: this.toVirtualPath(entry.path) };
1298
+ }
1299
+ }
1300
+ /**
1301
+ * Convert a ChangeDetail's paths from real to virtual.
1302
+ */
1303
+ changeDetailToVirtual(detail) {
1304
+ switch (detail.type) {
1305
+ case "create":
1306
+ return { ...detail, path: this.toVirtualPath(detail.path) };
1307
+ case "update":
1308
+ return { ...detail, path: this.toVirtualPath(detail.path) };
1309
+ case "delete":
1310
+ return { ...detail, path: this.toVirtualPath(detail.path) };
1311
+ case "rename":
1312
+ return { ...detail, from: this.toVirtualPath(detail.from), to: this.toVirtualPath(detail.to) };
1313
+ case "chmod":
1314
+ return { ...detail, path: this.toVirtualPath(detail.path) };
1315
+ case "chown":
1316
+ return { ...detail, path: this.toVirtualPath(detail.path) };
1317
+ case "symlink":
1318
+ return { ...detail, path: this.toVirtualPath(detail.path) };
1319
+ }
1256
1320
  }
1257
1321
  // --- Apply ---
1258
1322
  async apply(options) {
@@ -1399,23 +1463,24 @@ var Layer = class {
1399
1463
  }
1400
1464
  /**
1401
1465
  * Convert a flat ChangeDetail back to a ChangeEntry for error reporting.
1466
+ * Paths are converted to virtual for user-facing output.
1402
1467
  */
1403
1468
  detailToChangeEntry(detail) {
1404
1469
  switch (detail.type) {
1405
1470
  case "create":
1406
- return { type: "create", entryType: detail.entryType, path: detail.path };
1471
+ return { type: "create", entryType: detail.entryType, path: this.toVirtualPath(detail.path) };
1407
1472
  case "update":
1408
- return { type: "update", path: detail.path };
1473
+ return { type: "update", path: this.toVirtualPath(detail.path) };
1409
1474
  case "delete":
1410
- return { type: "delete", entryType: detail.entryType, path: detail.path };
1475
+ return { type: "delete", entryType: detail.entryType, path: this.toVirtualPath(detail.path) };
1411
1476
  case "rename":
1412
- return { type: "rename", from: detail.from, to: detail.to };
1477
+ return { type: "rename", from: this.toVirtualPath(detail.from), to: this.toVirtualPath(detail.to) };
1413
1478
  case "chmod":
1414
- return { type: "chmod", path: detail.path, mode: detail.mode };
1479
+ return { type: "chmod", path: this.toVirtualPath(detail.path), mode: detail.mode };
1415
1480
  case "chown":
1416
- return { type: "chown", path: detail.path, uid: detail.uid, gid: detail.gid };
1481
+ return { type: "chown", path: this.toVirtualPath(detail.path), uid: detail.uid, gid: detail.gid };
1417
1482
  case "symlink":
1418
- return { type: "symlink", path: detail.path, target: detail.target };
1483
+ return { type: "symlink", path: this.toVirtualPath(detail.path), target: detail.target };
1419
1484
  }
1420
1485
  }
1421
1486
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@catmint-fs/core",
3
- "version": "0.0.0-prealpha.0",
3
+ "version": "0.0.0-prealpha.2",
4
4
  "description": "Virtual filesystem layer with copy-on-write semantics over a pluggable backing store",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",