@rljson/fs-agent 0.0.60 → 0.0.61

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.
@@ -300,6 +300,16 @@ export declare class FsAgent {
300
300
  /** Files written vs left alone by the current {@link restore}. */
301
301
  private _restoreWritten;
302
302
  private _restoreSkipped;
303
+ /**
304
+ * Absolute paths deleted here since the last announcement.
305
+ *
306
+ * The mirror of {@link _announcedFiles}. Between a local unlink and the push
307
+ * that announces it, this node's advertised state still CONTAINS the file —
308
+ * so a peer pushing in that window descends from a state the file is in, and
309
+ * an apply re-creates it. The local scan then sees the file present, and the
310
+ * deletion is never announced at all: silently undone, everywhere.
311
+ */
312
+ private readonly _pendingDeletes;
303
313
  /**
304
314
  * The states this node has held, oldest first.
305
315
  *
@@ -783,6 +793,16 @@ export declare class FsAgent {
783
793
  * @returns True when every declared parent is a state this node has left.
784
794
  */
785
795
  private _senderIsBehind;
796
+ /**
797
+ * Marks an incoming tree's files as known to the network.
798
+ *
799
+ * A union, not a replacement: {@link _rememberAnnounced} answers "what this
800
+ * node has told the network", and this answers "what the network has told
801
+ * this node". Both make a file prunable; neither alone is the whole set, and
802
+ * treating the first as the whole set is what made deletions vanish.
803
+ * @param tree - The tree just applied.
804
+ */
805
+ private _rememberReceived;
786
806
  private _rememberAnnounced;
787
807
  private _adoptAppliedRef;
788
808
  /**
package/dist/fs-agent.js CHANGED
@@ -1154,6 +1154,16 @@ class FsAgent {
1154
1154
  /** Files written vs left alone by the current {@link restore}. */
1155
1155
  _restoreWritten = 0;
1156
1156
  _restoreSkipped = 0;
1157
+ /**
1158
+ * Absolute paths deleted here since the last announcement.
1159
+ *
1160
+ * The mirror of {@link _announcedFiles}. Between a local unlink and the push
1161
+ * that announces it, this node's advertised state still CONTAINS the file —
1162
+ * so a peer pushing in that window descends from a state the file is in, and
1163
+ * an apply re-creates it. The local scan then sees the file present, and the
1164
+ * deletion is never announced at all: silently undone, everywhere.
1165
+ */
1166
+ _pendingDeletes = /* @__PURE__ */ new Set();
1157
1167
  /**
1158
1168
  * The states this node has held, oldest first.
1159
1169
  *
@@ -1605,6 +1615,10 @@ ${err.stack}` : String(err);
1605
1615
  this._restoreSkipped++;
1606
1616
  return;
1607
1617
  }
1618
+ if (this._pendingDeletes.has(filePath)) {
1619
+ this._restoreSkipped++;
1620
+ return;
1621
+ }
1608
1622
  let fileBlob;
1609
1623
  try {
1610
1624
  fileBlob = await this._bs.getBlob(meta.blobId);
@@ -2046,9 +2060,12 @@ ${err.stack}` : String(err);
2046
2060
  this._flushDeferredRescan = () => {
2047
2061
  if (!this._rescanDeferred) return;
2048
2062
  this._rescanDeferred = false;
2049
- debouncedSync({ type: "safety-rescan" });
2063
+ debouncedSync({ type: "safety-rescan", path: "." });
2050
2064
  };
2051
2065
  const debouncedSync = (change) => {
2066
+ if (change?.type === "deleted" && change.path !== ".") {
2067
+ this._pendingDeletes.add(join(this._rootPath, change.path));
2068
+ }
2052
2069
  if (change?.type === "safety-rescan" && this._remoteApplyInFlight) {
2053
2070
  this._rescanDeferred = true;
2054
2071
  return;
@@ -2411,11 +2428,26 @@ ${err.stack}` : String(err);
2411
2428
  (ref) => ref !== this._currentRef && ref !== this._lastAppliedRef && this._stateHistory.includes(ref)
2412
2429
  );
2413
2430
  }
2431
+ /**
2432
+ * Marks an incoming tree's files as known to the network.
2433
+ *
2434
+ * A union, not a replacement: {@link _rememberAnnounced} answers "what this
2435
+ * node has told the network", and this answers "what the network has told
2436
+ * this node". Both make a file prunable; neither alone is the whole set, and
2437
+ * treating the first as the whole set is what made deletions vanish.
2438
+ * @param tree - The tree just applied.
2439
+ */
2440
+ _rememberReceived(tree) {
2441
+ for (const path of this._getFileContentMap(tree).keys()) {
2442
+ this._announcedFiles.add(join(this._rootPath, path));
2443
+ }
2444
+ }
2414
2445
  _rememberAnnounced(tree) {
2415
2446
  this._announcedFiles.clear();
2416
2447
  for (const path of this._getFileContentMap(tree).keys()) {
2417
2448
  this._announcedFiles.add(join(this._rootPath, path));
2418
2449
  }
2450
+ this._pendingDeletes.clear();
2419
2451
  }
2420
2452
  _adoptAppliedRef(connector, treeRef) {
2421
2453
  if (this._lastAppliedRef && this._lastAppliedRef !== treeRef) {
@@ -2619,6 +2651,7 @@ ${err.stack}` : String(err);
2619
2651
  this._adoptAppliedRef(connector, treeRef);
2620
2652
  this._currentRef = postRestoreRef;
2621
2653
  this._persistCurrentRef(postRestoreRef);
2654
+ this._rememberReceived(incomingTree);
2622
2655
  const postRestoreFiles = this._getFileContentMap(postRestoreTree);
2623
2656
  const incomingFiles = this._getFileContentMap(incomingTree);
2624
2657
  let hasNewsOfOurOwn = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rljson/fs-agent",
3
- "version": "0.0.60",
3
+ "version": "0.0.61",
4
4
  "description": "Rljson fs-agent description",
5
5
  "homepage": "https://github.com/rljson/fs-agent",
6
6
  "bugs": "https://github.com/rljson/fs-agent/issues",