@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.
- package/dist/fs-agent.d.ts +9 -0
- package/dist/fs-agent.js +48 -4
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/fs-agent.d.ts
CHANGED
|
@@ -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, {
|
|
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';
|