@rljson/fs-agent 0.0.8 → 0.0.9

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.
@@ -74,6 +74,8 @@ export interface TimeoutConfig {
74
74
  */
75
75
  debounceMs?: number;
76
76
  }
77
+ /** Filename for sync error log written to the sync folder */
78
+ export declare const SYNC_ERROR_FILE = ".sync-errors.log";
77
79
  /**
78
80
  * Orchestrates filesystem operations with tree structures and blob storage
79
81
  */
@@ -111,6 +113,13 @@ export declare class FsAgent {
111
113
  * Gets the current timeout configuration
112
114
  */
113
115
  get timeouts(): Required<TimeoutConfig>;
116
+ /**
117
+ * Appends a sync error entry to the error log file in the sync folder.
118
+ * Uses synchronous I/O to guarantee the write completes even in catch blocks.
119
+ * @param context - Label identifying where the error occurred
120
+ * @param err - The error value caught
121
+ */
122
+ _writeSyncError(context: string, err: unknown): void;
114
123
  /**
115
124
  * Wraps a promise with a timeout.
116
125
  * Rejects with a descriptive error if the promise does not settle
package/dist/fs-agent.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { BsMem } from "@rljson/bs";
2
2
  import { Route, createTreesTableCfg } from "@rljson/rljson";
3
+ import { watch, appendFileSync } from "fs";
3
4
  import { stat, readFile, mkdir, writeFile, readdir, utimes, rm } from "fs/promises";
4
5
  import { dirname, join, sep } from "path";
5
6
  import { hip } from "@rljson/hash";
6
- import { watch } from "fs";
7
7
  import { Db } from "@rljson/db";
8
8
  import { IoMem, createSocketPair } from "@rljson/io";
9
9
  import { Server, Client } from "@rljson/server";
@@ -486,6 +486,7 @@ const DEFAULT_TIMEOUTS = {
486
486
  syncCallback: 25e3,
487
487
  debounceMs: 300
488
488
  };
489
+ const SYNC_ERROR_FILE = ".sync-errors.log";
489
490
  class FsAgent {
490
491
  _scanner;
491
492
  _adapter;
@@ -505,7 +506,11 @@ class FsAgent {
505
506
  this._db = options.db;
506
507
  this._treeKey = options.treeKey;
507
508
  this._timeouts = { ...DEFAULT_TIMEOUTS, ...options.timeouts };
508
- this._scanner = new FsScanner(rootPath, { ...options, bs: this._bs });
509
+ this._scanner = new FsScanner(rootPath, {
510
+ ...options,
511
+ ignore: [...options.ignore || [], SYNC_ERROR_FILE],
512
+ bs: this._bs
513
+ });
509
514
  this._adapter = new FsBlobAdapter(this._bs);
510
515
  if (this._db && this._treeKey) {
511
516
  this._startAutoSync().catch(() => {
@@ -544,6 +549,23 @@ class FsAgent {
544
549
  get timeouts() {
545
550
  return this._timeouts;
546
551
  }
552
+ /**
553
+ * Appends a sync error entry to the error log file in the sync folder.
554
+ * Uses synchronous I/O to guarantee the write completes even in catch blocks.
555
+ * @param context - Label identifying where the error occurred
556
+ * @param err - The error value caught
557
+ */
558
+ _writeSyncError(context, err) {
559
+ try {
560
+ const ts = (/* @__PURE__ */ new Date()).toISOString();
561
+ const msg = err instanceof Error ? `${err.message}
562
+ ${err.stack}` : String(err);
563
+ const entry = `[${ts}] ${context}: ${msg}
564
+ `;
565
+ appendFileSync(join(this._rootPath, SYNC_ERROR_FILE), entry);
566
+ } catch {
567
+ }
568
+ }
547
569
  /**
548
570
  * Wraps a promise with a timeout.
549
571
  * Rejects with a descriptive error if the promise does not settle
@@ -772,6 +794,14 @@ class FsAgent {
772
794
  if (error instanceof Error && error.message.startsWith("Timeout")) {
773
795
  throw error;
774
796
  }
797
+ const errMsg = error instanceof Error ? error.message : String(error);
798
+ console.warn(
799
+ `[FsAgent] _fetchTreeRecursively: db.get failed for hash=${currentHash.slice(0, 8)}…: ${errMsg}`
800
+ );
801
+ this._writeSyncError(
802
+ `fetchTree/db.get(${currentHash.slice(0, 8)}…)`,
803
+ error
804
+ );
775
805
  continue;
776
806
  }
777
807
  const treeData = result?.rljson?.[treeKey];
@@ -938,7 +968,9 @@ class FsAgent {
938
968
  if (ref) {
939
969
  await this._sendRef(connector, ref);
940
970
  }
941
- } catch {
971
+ } catch (err) {
972
+ console.error("[FsAgent] syncToDb failed:", err);
973
+ this._writeSyncError("syncToDb", err);
942
974
  }
943
975
  }
944
976
  }, this._timeouts.debounceMs);
@@ -1027,12 +1059,21 @@ class FsAgent {
1027
1059
  this._timeouts.fetchTree,
1028
1060
  `syncFromDb → fetchTree(${treeKey}@${treeRef.slice(0, 8)}…)`
1029
1061
  );
1062
+ const incomingNodeCount = incomingTree.trees.size;
1063
+ console.log(
1064
+ `[FsAgent] syncFromDb: fetched tree with ${incomingNodeCount} nodes for ref=${treeRef.slice(0, 8)}…`
1065
+ );
1030
1066
  const currentTree = await FsAgent._withTimeout(
1031
1067
  this.extract(),
1032
1068
  this._timeouts.extract,
1033
1069
  `syncFromDb → extract(${this._rootPath})`
1034
1070
  );
1035
1071
  if (this._treesHaveEquivalentContent(currentTree, incomingTree)) {
1072
+ const incomingFiles = this._getFileContentMap(incomingTree);
1073
+ const currentFiles = this._getFileContentMap(currentTree);
1074
+ console.log(
1075
+ `[FsAgent] syncFromDb: equivalent content, skipping restore (incoming=${incomingFiles.size} entries, current=${currentFiles.size} entries, ref=${treeRef.slice(0, 8)}…)`
1076
+ );
1036
1077
  return;
1037
1078
  }
1038
1079
  await FsAgent._withTimeout(
@@ -1047,7 +1088,9 @@ class FsAgent {
1047
1088
  });
1048
1089
  this._lastSentRef = postRestoreRef;
1049
1090
  this._lastSentContentKey = this._contentKeyFromTree(postRestoreTree);
1050
- } catch {
1091
+ } catch (err) {
1092
+ console.error("[FsAgent] syncFromDb processRef failed:", err);
1093
+ this._writeSyncError("syncFromDb/processRef", err);
1051
1094
  } finally {
1052
1095
  this._scanner.resumeWatch();
1053
1096
  }
@@ -1201,5 +1244,6 @@ export {
1201
1244
  FsBlobAdapter,
1202
1245
  FsDbAdapter,
1203
1246
  FsScanner,
1247
+ SYNC_ERROR_FILE,
1204
1248
  runClientServerSetup
1205
1249
  };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { FsAgent, type FsAgentOptions, type RestoreOptions, type TimeoutConfig, } from './fs-agent.ts';
1
+ export { FsAgent, SYNC_ERROR_FILE, type FsAgentOptions, type RestoreOptions, type TimeoutConfig, } from './fs-agent.ts';
2
2
  export { FsBlobAdapter, type BlobToFileOptions, type FileBlobMeta, type FileToBlobOptions, } from './fs-blob-adapter.ts';
3
3
  export { FsDbAdapter, type StoreFsTreeOptions } from './fs-db-adapter.ts';
4
4
  export { FsScanner, type FsChange, type FsChangeCallback, type FsChangeType, type FsNodeMeta, type FsScanOptions, type FsTree, } from './fs-scanner.ts';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rljson/fs-agent",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
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",