@remnic/core 1.1.21 → 1.1.23

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 (103) hide show
  1. package/dist/access-cli.js +15 -15
  2. package/dist/access-http.d.ts +9 -1
  3. package/dist/access-http.js +9 -9
  4. package/dist/access-mcp.d.ts +1 -1
  5. package/dist/access-mcp.js +8 -8
  6. package/dist/access-schema.js +3 -3
  7. package/dist/{access-service-DT9L2DW4.d.ts → access-service-CEyV8XJ5.d.ts} +19 -2
  8. package/dist/access-service.d.ts +1 -1
  9. package/dist/access-service.js +6 -6
  10. package/dist/briefing.js +3 -3
  11. package/dist/causal-consolidation.js +4 -4
  12. package/dist/{chunk-YO3AZEE5.js → chunk-25YQM6XW.js} +3 -3
  13. package/dist/{chunk-TLM762GT.js → chunk-2WIPXV3Y.js} +2 -2
  14. package/dist/{chunk-QOHBYVZG.js → chunk-3F24QTRI.js} +2 -2
  15. package/dist/{chunk-5IQC4OG6.js → chunk-4H6DURG6.js} +2 -2
  16. package/dist/{chunk-NOQ74SJN.js → chunk-7D6O46PF.js} +2 -2
  17. package/dist/{chunk-SLKSC522.js → chunk-7E7SZRPP.js} +2 -2
  18. package/dist/{chunk-7Q2P774N.js → chunk-F33CJ5CH.js} +13 -3
  19. package/dist/chunk-F33CJ5CH.js.map +1 -0
  20. package/dist/{chunk-APW7AQOJ.js → chunk-FHXVW3L4.js} +4 -4
  21. package/dist/{chunk-PFFKUJM2.js → chunk-HWF42K6J.js} +103 -4
  22. package/dist/chunk-HWF42K6J.js.map +1 -0
  23. package/dist/{chunk-FSODDMR2.js → chunk-IANK6Y5W.js} +2 -2
  24. package/dist/{chunk-BYYIIXIJ.js → chunk-JKXFF3NT.js} +361 -29
  25. package/dist/chunk-JKXFF3NT.js.map +1 -0
  26. package/dist/{chunk-P7F6DJPA.js → chunk-MM5EBZVW.js} +42 -5
  27. package/dist/chunk-MM5EBZVW.js.map +1 -0
  28. package/dist/{chunk-GGCJ253V.js → chunk-MVAOT247.js} +8 -8
  29. package/dist/{chunk-SH5S7XYD.js → chunk-MXFBBHJU.js} +72 -2
  30. package/dist/chunk-MXFBBHJU.js.map +1 -0
  31. package/dist/{chunk-SZKCBLS5.js → chunk-PUXCIHRL.js} +2 -2
  32. package/dist/{chunk-2IRT26RZ.js → chunk-QYHQ2JHL.js} +2 -2
  33. package/dist/{chunk-73DAPA62.js → chunk-RA73CTVY.js} +12 -12
  34. package/dist/{chunk-CN4P6SVA.js → chunk-RCZRL5BE.js} +2 -2
  35. package/dist/{chunk-SGIXDVSF.js → chunk-S27EXIHY.js} +2 -2
  36. package/dist/{chunk-5ML4TH3E.js → chunk-TFORLO3O.js} +4 -4
  37. package/dist/{chunk-TOFUTKQN.js → chunk-TR4DK5OH.js} +2 -2
  38. package/dist/{chunk-6ORWKANA.js → chunk-VYU7PXUS.js} +2 -2
  39. package/dist/{chunk-FFU4GMST.js → chunk-WNARATI3.js} +2 -2
  40. package/dist/{chunk-KSFBM6TV.js → chunk-YITUHONZ.js} +2 -2
  41. package/dist/{cli-BN0CkYzI.d.ts → cli-BguVmIwO.d.ts} +1 -1
  42. package/dist/cli.d.ts +2 -2
  43. package/dist/cli.js +18 -18
  44. package/dist/compounding/engine.js +3 -3
  45. package/dist/connectors/codex-materialize-runner.js +3 -3
  46. package/dist/connectors/index.js +3 -3
  47. package/dist/entity-retrieval.js +3 -3
  48. package/dist/index.d.ts +4 -4
  49. package/dist/index.js +26 -24
  50. package/dist/index.js.map +1 -1
  51. package/dist/maintenance/memory-governance.js +3 -3
  52. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  53. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  54. package/dist/mcp-memory-inspector-app.d.ts +1 -1
  55. package/dist/namespaces/migrate.js +4 -4
  56. package/dist/namespaces/storage.js +3 -3
  57. package/dist/offline-sync.d.ts +36 -1
  58. package/dist/offline-sync.js +4 -2
  59. package/dist/operator-toolkit.js +6 -6
  60. package/dist/orchestrator.js +11 -11
  61. package/dist/schemas.d.ts +22 -22
  62. package/dist/secure-store/index.js +2 -2
  63. package/dist/semantic-consolidation.js +4 -4
  64. package/dist/semantic-rule-promotion.js +3 -3
  65. package/dist/semantic-rule-verifier.js +3 -3
  66. package/dist/storage.d.ts +2 -0
  67. package/dist/storage.js +2 -2
  68. package/dist/transfer/types.d.ts +12 -12
  69. package/dist/verified-recall.js +3 -3
  70. package/package.json +1 -1
  71. package/src/access-http.test.ts +176 -0
  72. package/src/access-http.ts +116 -0
  73. package/src/access-service-offline-file-content.test.ts +37 -0
  74. package/src/access-service.ts +70 -0
  75. package/src/index.ts +2 -0
  76. package/src/offline-sync.test.ts +448 -64
  77. package/src/offline-sync.ts +477 -29
  78. package/src/secure-store/secure-fs.ts +84 -3
  79. package/src/storage.ts +12 -0
  80. package/dist/chunk-7Q2P774N.js.map +0 -1
  81. package/dist/chunk-BYYIIXIJ.js.map +0 -1
  82. package/dist/chunk-P7F6DJPA.js.map +0 -1
  83. package/dist/chunk-PFFKUJM2.js.map +0 -1
  84. package/dist/chunk-SH5S7XYD.js.map +0 -1
  85. /package/dist/{chunk-YO3AZEE5.js.map → chunk-25YQM6XW.js.map} +0 -0
  86. /package/dist/{chunk-TLM762GT.js.map → chunk-2WIPXV3Y.js.map} +0 -0
  87. /package/dist/{chunk-QOHBYVZG.js.map → chunk-3F24QTRI.js.map} +0 -0
  88. /package/dist/{chunk-5IQC4OG6.js.map → chunk-4H6DURG6.js.map} +0 -0
  89. /package/dist/{chunk-NOQ74SJN.js.map → chunk-7D6O46PF.js.map} +0 -0
  90. /package/dist/{chunk-SLKSC522.js.map → chunk-7E7SZRPP.js.map} +0 -0
  91. /package/dist/{chunk-APW7AQOJ.js.map → chunk-FHXVW3L4.js.map} +0 -0
  92. /package/dist/{chunk-FSODDMR2.js.map → chunk-IANK6Y5W.js.map} +0 -0
  93. /package/dist/{chunk-GGCJ253V.js.map → chunk-MVAOT247.js.map} +0 -0
  94. /package/dist/{chunk-SZKCBLS5.js.map → chunk-PUXCIHRL.js.map} +0 -0
  95. /package/dist/{chunk-2IRT26RZ.js.map → chunk-QYHQ2JHL.js.map} +0 -0
  96. /package/dist/{chunk-73DAPA62.js.map → chunk-RA73CTVY.js.map} +0 -0
  97. /package/dist/{chunk-CN4P6SVA.js.map → chunk-RCZRL5BE.js.map} +0 -0
  98. /package/dist/{chunk-SGIXDVSF.js.map → chunk-S27EXIHY.js.map} +0 -0
  99. /package/dist/{chunk-5ML4TH3E.js.map → chunk-TFORLO3O.js.map} +0 -0
  100. /package/dist/{chunk-TOFUTKQN.js.map → chunk-TR4DK5OH.js.map} +0 -0
  101. /package/dist/{chunk-6ORWKANA.js.map → chunk-VYU7PXUS.js.map} +0 -0
  102. /package/dist/{chunk-FFU4GMST.js.map → chunk-WNARATI3.js.map} +0 -0
  103. /package/dist/{chunk-KSFBM6TV.js.map → chunk-YITUHONZ.js.map} +0 -0
@@ -10,7 +10,7 @@ import {
10
10
  import {
11
11
  MAGIC_HEADER_SIZE,
12
12
  isEncryptedFile
13
- } from "./chunk-SH5S7XYD.js";
13
+ } from "./chunk-MXFBBHJU.js";
14
14
  import {
15
15
  parseFlexibleIsoTimestamp
16
16
  } from "./chunk-P7FMDTKL.js";
@@ -24,6 +24,7 @@ import {
24
24
  readdir,
25
25
  readFile,
26
26
  rename,
27
+ rm,
27
28
  stat,
28
29
  unlink,
29
30
  writeFile
@@ -34,33 +35,10 @@ var OFFLINE_SYNC_CHANGESET_FORMAT = "remnic.offline-sync.changeset.v1";
34
35
  var OFFLINE_SYNC_STATE_VERSION = 1;
35
36
  var OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES = 64 * 1024 * 1024;
36
37
  var SYNC_INTERNAL_DIR = ".offline-sync";
38
+ var OFFLINE_SYNC_UPLOAD_STAGING_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
37
39
  var EXCLUDED_FILE_NAMES = /* @__PURE__ */ new Set([
38
40
  ".sync-state.json"
39
41
  ]);
40
- var DERIVED_RUNTIME_REL_PATHS = /* @__PURE__ */ new Set([
41
- "state/fact-hashes.ready",
42
- "state/fact-hashes.txt",
43
- "state/buffer-surprise-ledger.jsonl",
44
- "state/buffer.json",
45
- "state/embeddings.json",
46
- "state/index_tags.json",
47
- "state/index_time.json",
48
- "state/last_graph_recall.json",
49
- "state/last_intent.json",
50
- "state/last_qmd_recall.json",
51
- "state/last_recall.json",
52
- "state/lcm.sqlite",
53
- "state/lcm.sqlite-shm",
54
- "state/lcm.sqlite-wal",
55
- "state/memory-lifecycle-ledger.jsonl",
56
- "state/memory-projection.sqlite",
57
- "state/memory-projection.sqlite-shm",
58
- "state/memory-projection.sqlite-wal",
59
- "state/recall_impressions.jsonl"
60
- ]);
61
- var EXCLUDED_REL_PATHS = /* @__PURE__ */ new Set([
62
- ...DERIVED_RUNTIME_REL_PATHS
63
- ]);
64
42
  var EXCLUDED_FILE_PREFIXES = [
65
43
  ".remnic-sync.",
66
44
  ".remnic-sync-state."
@@ -281,17 +259,20 @@ function shouldExcludeRelPath(relPosix, includeTranscripts) {
281
259
  const parts = relPosix.split("/");
282
260
  if (parts.some((part) => DEFAULT_TRANSFER_EXCLUDE_DIRS.has(part))) return true;
283
261
  if (parts.some((part) => part === SYNC_INTERNAL_DIR)) return true;
284
- if (EXCLUDED_REL_PATHS.has(relPosix)) return true;
285
262
  if (!includeTranscripts && parts[0] === "transcripts") return true;
286
263
  const basename = parts[parts.length - 1] ?? "";
287
- if (parts[0] === "state" && basename.includes(".tmp-")) return true;
264
+ if (isCanonicalRuntimeStatePath(parts) && basename.includes(".tmp-")) return true;
288
265
  if (EXCLUDED_FILE_NAMES.has(basename)) return true;
289
266
  return EXCLUDED_FILE_PREFIXES.some((prefix) => basename.startsWith(prefix));
290
267
  }
291
268
  function shouldIgnoreIncomingRuntimePath(relPosix) {
292
269
  const parts = relPosix.split("/");
293
270
  const basename = parts[parts.length - 1] ?? "";
294
- return DERIVED_RUNTIME_REL_PATHS.has(relPosix) || parts[0] === "state" && basename.includes(".tmp-");
271
+ return isCanonicalRuntimeStatePath(parts) && basename.includes(".tmp-");
272
+ }
273
+ function isCanonicalRuntimeStatePath(parts) {
274
+ if (parts[0] === "state") return true;
275
+ return parts[0] === "namespaces" && parts.length >= 4 && parts[2] === "state";
295
276
  }
296
277
  function filterBaseFilesForMode(files, includeTranscripts) {
297
278
  return files.filter((file) => !shouldExcludeRelPath(file.path, includeTranscripts));
@@ -469,6 +450,9 @@ async function readOfflineSyncFileContentChunk(options) {
469
450
  }
470
451
  async function buildOfflineSyncChangeset(options) {
471
452
  const includeTranscripts = options.includeTranscripts !== false;
453
+ const excludedPaths = new Set(
454
+ (options.excludePaths ?? []).map((relPath) => normalizeRelativePath(relPath, "excludePaths[]"))
455
+ );
472
456
  const base = byPath(filterBaseFilesForMode(
473
457
  normalizeFileStates(options.baseFiles),
474
458
  includeTranscripts
@@ -484,6 +468,7 @@ async function buildOfflineSyncChangeset(options) {
484
468
  const currentMap = byPath(current.files);
485
469
  const changes = [];
486
470
  for (const relPath of unionPaths(base, currentMap)) {
471
+ if (excludedPaths.has(relPath)) continue;
487
472
  const baseEntry = base.get(relPath);
488
473
  const currentEntry = currentMap.get(relPath);
489
474
  if (currentEntry && currentEntry.sha256 !== baseEntry?.sha256) {
@@ -866,6 +851,352 @@ async function writeSafeFile(root, relPath, content, writeFileHook) {
866
851
  throw error;
867
852
  }
868
853
  }
854
+ async function applyOfflineSyncFileContentChunk(options) {
855
+ const root = await ensureSyncRoot(options.root, "applyOfflineSyncFileContentChunk");
856
+ const sourceId = normalizeSourceId(options.sourceId, "sourceId");
857
+ const relPath = normalizeRelativePath(options.path, "path");
858
+ const includeTranscripts = options.includeTranscripts !== false;
859
+ if (shouldExcludeRelPath(relPath, includeTranscripts)) {
860
+ throw new Error(`offline sync file content path is excluded: ${relPath}`);
861
+ }
862
+ const sha256 = assertSha256(options.sha256, "sha256");
863
+ const bytes = assertNonNegativeInteger(options.bytes, "bytes");
864
+ const mtimeMs = assertNonNegativeFinite(options.mtimeMs, "mtimeMs");
865
+ const offset = options.offset === void 0 ? 0 : assertNonNegativeInteger(options.offset, "offset");
866
+ const baseSha256 = options.baseSha256 === void 0 ? void 0 : assertSha256(options.baseSha256, "baseSha256");
867
+ if (!Buffer.isBuffer(options.content)) {
868
+ throw new Error("content must be a Buffer");
869
+ }
870
+ if (options.content.length > OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES) {
871
+ throw new Error(
872
+ `content chunk must be ${OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES} bytes or fewer`
873
+ );
874
+ }
875
+ if (bytes > 0 && options.content.length === 0) {
876
+ throw new Error("content chunk must be non-empty before EOF");
877
+ }
878
+ if (offset > bytes || offset + options.content.length > bytes) {
879
+ throw new Error(`content chunk range exceeds declared file size for ${relPath}`);
880
+ }
881
+ if (options.writeFile && !options.writeFileChunks) {
882
+ throw new Error("offline sync upload storage hooks require writeFileChunks");
883
+ }
884
+ if (options.writeFile && !options.writeStagingFile) {
885
+ throw new Error("offline sync upload storage hooks require writeStagingFile");
886
+ }
887
+ if (offset === 0) {
888
+ await pruneOfflineUploadStaging(root);
889
+ }
890
+ const upload = await writeOfflineUploadChunk({
891
+ root,
892
+ sourceId,
893
+ relPath,
894
+ sha256,
895
+ bytes,
896
+ offset,
897
+ content: options.content,
898
+ readFile: options.readFile,
899
+ writeFile: options.writeFile,
900
+ writeStagingFile: options.writeStagingFile
901
+ });
902
+ const done = offset + options.content.length === bytes;
903
+ const baseResult = {
904
+ path: relPath,
905
+ sha256,
906
+ bytes,
907
+ mtimeMs,
908
+ offset,
909
+ chunkBytes: options.content.length,
910
+ done
911
+ };
912
+ if (!done) {
913
+ return {
914
+ ...baseResult,
915
+ applied: false,
916
+ skipped: false
917
+ };
918
+ }
919
+ const digest = await digestOfflineUploadStagingContent({
920
+ root,
921
+ upload,
922
+ readFile: options.readFile
923
+ });
924
+ if (digest.sha256 !== sha256 || digest.bytes !== bytes) {
925
+ await cleanupOfflineUpload(upload).catch(() => {
926
+ });
927
+ throw new Error(`offline sync upload checksum mismatch for ${relPath}`);
928
+ }
929
+ const currentSnapshot = await buildOfflineSyncSnapshotForPaths({
930
+ root: root.abs,
931
+ sourceId: "local",
932
+ paths: [relPath],
933
+ includeContent: false,
934
+ includeTranscripts,
935
+ readFile: options.readFile
936
+ });
937
+ const currentFile = currentSnapshot.files[0];
938
+ const uploadedState = {
939
+ path: relPath,
940
+ sha256,
941
+ bytes,
942
+ mtimeMs
943
+ };
944
+ try {
945
+ if (currentFile?.sha256 === sha256) {
946
+ return {
947
+ ...baseResult,
948
+ applied: false,
949
+ skipped: true,
950
+ currentFile: toFileState(currentFile)
951
+ };
952
+ }
953
+ if (!baseSha256 && currentFile) {
954
+ const conflict = await recordConflict({
955
+ root,
956
+ relPath,
957
+ reason: "remote_exists_for_local_create",
958
+ localSha256: currentFile.sha256,
959
+ incomingSha256: sha256,
960
+ writeConflictCopies: false,
961
+ sourceId,
962
+ writeFile: options.writeFile
963
+ });
964
+ return {
965
+ ...baseResult,
966
+ applied: false,
967
+ skipped: false,
968
+ conflict,
969
+ currentFile: toFileState(currentFile)
970
+ };
971
+ }
972
+ if (baseSha256 && currentFile?.sha256 !== baseSha256) {
973
+ const conflict = await recordConflict({
974
+ root,
975
+ relPath,
976
+ reason: currentFile ? "remote_changed_for_local_update" : "remote_deleted_for_local_update",
977
+ baseSha256,
978
+ localSha256: currentFile?.sha256,
979
+ incomingSha256: sha256,
980
+ writeConflictCopies: false,
981
+ sourceId,
982
+ writeFile: options.writeFile
983
+ });
984
+ return {
985
+ ...baseResult,
986
+ applied: false,
987
+ skipped: false,
988
+ conflict,
989
+ ...currentFile ? { currentFile: toFileState(currentFile) } : {}
990
+ };
991
+ }
992
+ await writeSafeFileFromUpload(root, relPath, upload, options.readFile, options.writeFileChunks);
993
+ return {
994
+ ...baseResult,
995
+ applied: true,
996
+ skipped: false,
997
+ currentFile: uploadedState
998
+ };
999
+ } finally {
1000
+ await cleanupOfflineUpload(upload).catch(() => {
1001
+ });
1002
+ }
1003
+ }
1004
+ function offlineUploadRelPath(options) {
1005
+ const key = hashText([
1006
+ options.sourceId,
1007
+ options.relPath,
1008
+ options.sha256,
1009
+ String(options.bytes)
1010
+ ].join("\0"));
1011
+ return `${SYNC_INTERNAL_DIR}/uploads/${key}.part`;
1012
+ }
1013
+ async function offlineUploadPath(root, options) {
1014
+ const relPath = offlineUploadRelPath(options);
1015
+ return {
1016
+ kind: "single",
1017
+ relPath,
1018
+ filePath: await resolveSafeArchiveTarget(root, relPath)
1019
+ };
1020
+ }
1021
+ async function offlineUploadChunkPath(root, options) {
1022
+ const uploadRelPath = offlineUploadRelPath(options);
1023
+ const relPath = `${uploadRelPath}/${String(options.offset).padStart(20, "0")}.part`;
1024
+ return {
1025
+ kind: "chunks",
1026
+ relPath,
1027
+ filePath: await resolveSafeArchiveTarget(root, relPath)
1028
+ };
1029
+ }
1030
+ async function writeOfflineUploadChunk(options) {
1031
+ if ((options.writeFile || options.writeStagingFile) && !options.readFile) {
1032
+ throw new Error("offline sync upload chunk storage hooks require readFile");
1033
+ }
1034
+ const uploadRoot = {
1035
+ ...await offlineUploadPath(options.root, options),
1036
+ kind: "chunks"
1037
+ };
1038
+ if (options.offset === 0) {
1039
+ await rm(uploadRoot.filePath, { recursive: true, force: true }).catch(() => {
1040
+ });
1041
+ } else {
1042
+ const existing = await stat(uploadRoot.filePath).catch((error) => {
1043
+ if (error.code === "ENOENT") return null;
1044
+ throw error;
1045
+ });
1046
+ if (!existing || !existing.isDirectory()) {
1047
+ throw new Error(`offline sync upload is missing initial chunk for ${options.relPath}`);
1048
+ }
1049
+ }
1050
+ const chunk = await offlineUploadChunkPath(options.root, { ...options, offset: options.offset });
1051
+ const writeStagingFile = options.writeStagingFile ?? options.writeFile;
1052
+ if (writeStagingFile) {
1053
+ await writeOfflineUploadContent({
1054
+ root: options.root,
1055
+ relPath: chunk.relPath,
1056
+ filePath: chunk.filePath,
1057
+ content: options.content,
1058
+ writeFile: writeStagingFile
1059
+ });
1060
+ return uploadRoot;
1061
+ }
1062
+ await mkdir(path.dirname(chunk.filePath), { recursive: true });
1063
+ const existingChunk = await lstat(chunk.filePath).catch((error) => {
1064
+ if (error.code === "ENOENT") return null;
1065
+ throw error;
1066
+ });
1067
+ if (existingChunk?.isSymbolicLink()) {
1068
+ throw new Error(`offline sync upload chunk is a symlink: ${chunk.relPath}`);
1069
+ }
1070
+ await writeFile(chunk.filePath, options.content, { mode: 384 });
1071
+ return uploadRoot;
1072
+ }
1073
+ async function pruneOfflineUploadStaging(root) {
1074
+ const uploadsRelPath = `${SYNC_INTERNAL_DIR}/uploads`;
1075
+ const uploadsPath = await resolveSafeArchiveTarget(root, uploadsRelPath);
1076
+ const entries = await readdir(uploadsPath, { withFileTypes: true }).catch((error) => {
1077
+ if (error.code === "ENOENT") return [];
1078
+ throw error;
1079
+ });
1080
+ const now = Date.now();
1081
+ await Promise.all(entries.map(async (entry) => {
1082
+ if (!/^[a-f0-9]{64}\.part$/i.test(entry.name)) return;
1083
+ const relPath = `${uploadsRelPath}/${entry.name}`;
1084
+ const filePath = await resolveSafeArchiveTarget(root, relPath);
1085
+ const info = await lstat(filePath).catch((error) => {
1086
+ if (error.code === "ENOENT") return null;
1087
+ throw error;
1088
+ });
1089
+ if (!info) return;
1090
+ if (now - info.mtimeMs <= OFFLINE_SYNC_UPLOAD_STAGING_MAX_AGE_MS) return;
1091
+ await rm(filePath, { recursive: true, force: true });
1092
+ }));
1093
+ }
1094
+ async function* readOfflineUploadStagingChunks(options) {
1095
+ if (options.upload.kind === "single") {
1096
+ yield await readOfflineUploadContent({
1097
+ root: options.root,
1098
+ relPath: options.upload.relPath,
1099
+ filePath: options.upload.filePath,
1100
+ readFile: options.readFile
1101
+ });
1102
+ return;
1103
+ }
1104
+ const entries = await readdir(options.upload.filePath);
1105
+ const chunkNames = entries.filter((entry) => /^\d{20}\.part$/.test(entry)).sort();
1106
+ if (chunkNames.length === 0) {
1107
+ throw new Error(`offline sync upload is missing chunks for ${options.upload.relPath}`);
1108
+ }
1109
+ let expectedOffset = 0;
1110
+ for (const chunkName of chunkNames) {
1111
+ const offset = Number(chunkName.slice(0, 20));
1112
+ if (!Number.isSafeInteger(offset) || offset !== expectedOffset) {
1113
+ throw new Error(
1114
+ `offline sync upload offset mismatch for ${options.upload.relPath}: expected ${expectedOffset}, got ${offset}`
1115
+ );
1116
+ }
1117
+ const relPath = `${options.upload.relPath}/${chunkName}`;
1118
+ const filePath = await resolveSafeArchiveTarget(options.root, relPath);
1119
+ const content = await readOfflineUploadContent({
1120
+ root: options.root,
1121
+ relPath,
1122
+ filePath,
1123
+ readFile: options.readFile
1124
+ });
1125
+ expectedOffset += content.length;
1126
+ yield content;
1127
+ }
1128
+ }
1129
+ async function digestOfflineUploadStagingContent(options) {
1130
+ const hash = createHash("sha256");
1131
+ let bytes = 0;
1132
+ for await (const chunk of readOfflineUploadStagingChunks(options)) {
1133
+ hash.update(chunk);
1134
+ bytes += chunk.length;
1135
+ }
1136
+ return { sha256: hash.digest("hex"), bytes };
1137
+ }
1138
+ async function writeSafeFileFromUpload(root, relPath, upload, readFile2, writeFileChunks) {
1139
+ const target = await resolveSafeArchiveTarget(root, relPath);
1140
+ const chunks = readOfflineUploadStagingChunks({ root, upload, readFile: readFile2 });
1141
+ if (writeFileChunks) {
1142
+ await writeFileChunks({ root: root.abs, path: relPath, filePath: target, chunks });
1143
+ return;
1144
+ }
1145
+ await mkdir(path.dirname(target), { recursive: true });
1146
+ const tmp = path.join(
1147
+ path.dirname(target),
1148
+ `.remnic-sync.${process.pid}.${randomUUID()}.tmp`
1149
+ );
1150
+ const handle = await open(tmp, "w", 384);
1151
+ try {
1152
+ for await (const chunk of chunks) {
1153
+ if (chunk.length > 0) await handle.write(chunk);
1154
+ }
1155
+ await handle.close();
1156
+ const targetStat = await lstat(target).catch((error) => {
1157
+ if (error.code === "ENOENT") return null;
1158
+ throw error;
1159
+ });
1160
+ if (targetStat?.isSymbolicLink()) {
1161
+ throw new Error(`offline sync target is a symlink: ${relPath}`);
1162
+ }
1163
+ await rename(tmp, target);
1164
+ } catch (error) {
1165
+ await handle.close().catch(() => {
1166
+ });
1167
+ await unlink(tmp).catch(() => {
1168
+ });
1169
+ throw error;
1170
+ }
1171
+ }
1172
+ async function cleanupOfflineUpload(upload) {
1173
+ if (upload.kind === "chunks") {
1174
+ await rm(upload.filePath, { recursive: true, force: true });
1175
+ return;
1176
+ }
1177
+ await unlink(upload.filePath).catch((error) => {
1178
+ if (error.code === "ENOENT") return;
1179
+ throw error;
1180
+ });
1181
+ }
1182
+ async function readOfflineUploadContent(options) {
1183
+ if (options.readFile) {
1184
+ return options.readFile({
1185
+ root: options.root.abs,
1186
+ path: options.relPath,
1187
+ filePath: options.filePath
1188
+ });
1189
+ }
1190
+ return readFile(options.filePath);
1191
+ }
1192
+ async function writeOfflineUploadContent(options) {
1193
+ await options.writeFile({
1194
+ root: options.root.abs,
1195
+ path: options.relPath,
1196
+ filePath: options.filePath,
1197
+ content: options.content
1198
+ });
1199
+ }
869
1200
  async function deleteSafeFile(root, relPath, deleteFile) {
870
1201
  const target = await resolveSafeArchiveTarget(root, relPath);
871
1202
  if (deleteFile) {
@@ -976,6 +1307,7 @@ export {
976
1307
  summarizeOfflineSyncPendingChanges,
977
1308
  applyOfflineSyncSnapshot,
978
1309
  applyOfflineSyncChangeset,
1310
+ applyOfflineSyncFileContentChunk,
979
1311
  defaultOfflineSyncStatePath,
980
1312
  readOfflineSyncState,
981
1313
  writeOfflineSyncState,
@@ -983,4 +1315,4 @@ export {
983
1315
  normalizeOfflineSyncState,
984
1316
  fileStatesFromSnapshot
985
1317
  };
986
- //# sourceMappingURL=chunk-BYYIIXIJ.js.map
1318
+ //# sourceMappingURL=chunk-JKXFF3NT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/offline-sync.ts"],"sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport {\n lstat,\n mkdir,\n open,\n readdir,\n readFile,\n rename,\n rm,\n stat,\n unlink,\n writeFile,\n} from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n DEFAULT_TRANSFER_EXCLUDE_DIRS,\n} from \"./transfer/exclusions.js\";\nimport { isEncryptedFile, MAGIC_HEADER_SIZE } from \"./secure-store/secure-fs.js\";\nimport {\n prepareSafeArchiveRoot,\n resolveSafeArchiveTarget,\n sha256Bytes,\n validateArchiveRelativePath,\n type SafeArchiveRoot,\n} from \"./transfer/fs-utils.js\";\nimport { parseFlexibleIsoTimestamp } from \"./utils/iso-timestamp.js\";\n\nexport const OFFLINE_SYNC_SNAPSHOT_FORMAT = \"remnic.offline-sync.snapshot.v1\";\nexport const OFFLINE_SYNC_CHANGESET_FORMAT = \"remnic.offline-sync.changeset.v1\";\nexport const OFFLINE_SYNC_STATE_VERSION = 1;\nexport const OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES = 64 * 1024 * 1024;\n\nexport interface OfflineSyncFileState {\n path: string;\n sha256: string;\n /** Byte length of the transferable content, after any readFile hook such as secure-store decryption. */\n bytes: number;\n mtimeMs: number;\n}\n\nexport interface OfflineSyncFileRecord extends OfflineSyncFileState {\n contentBase64?: string;\n}\n\nexport interface OfflineSyncSnapshot {\n format: typeof OFFLINE_SYNC_SNAPSHOT_FORMAT;\n schemaVersion: 1;\n createdAt: string;\n sourceId: string;\n includeTranscripts: boolean;\n files: OfflineSyncFileRecord[];\n}\n\nexport type OfflineSyncChange =\n | {\n type: \"upsert\";\n path: string;\n baseSha256?: string;\n file: OfflineSyncFileRecord & { contentBase64: string };\n }\n | {\n type: \"delete\";\n path: string;\n baseSha256: string;\n };\n\nexport interface OfflineSyncChangeset {\n format: typeof OFFLINE_SYNC_CHANGESET_FORMAT;\n schemaVersion: 1;\n createdAt: string;\n sourceId: string;\n includeTranscripts: boolean;\n changes: OfflineSyncChange[];\n}\n\nexport interface OfflineSyncState {\n version: typeof OFFLINE_SYNC_STATE_VERSION;\n remoteId: string;\n namespace?: string;\n includeTranscripts: boolean;\n lastSyncedAt: string;\n baseFiles: OfflineSyncFileState[];\n}\n\nexport interface OfflineSyncConflict {\n path: string;\n reason:\n | \"both_modified\"\n | \"local_deleted_remote_modified\"\n | \"local_modified_remote_deleted\"\n | \"remote_exists_for_local_create\"\n | \"remote_changed_for_local_update\"\n | \"remote_deleted_for_local_update\"\n | \"remote_changed_for_local_delete\";\n baseSha256?: string;\n localSha256?: string;\n incomingSha256?: string;\n conflictPath?: string;\n}\n\nexport interface OfflineSyncApplySnapshotResult {\n upserted: number;\n deleted: number;\n skipped: number;\n pendingLocal: number;\n conflicts: OfflineSyncConflict[];\n nextBaseFiles: OfflineSyncFileState[];\n}\n\nexport interface OfflineSyncApplyChangesetResult {\n appliedUpserts: number;\n appliedDeletes: number;\n skipped: number;\n conflicts: OfflineSyncConflict[];\n currentFiles: OfflineSyncFileState[];\n}\n\nexport interface OfflineSyncChangesetSummary {\n upserts: number;\n deletes: number;\n total: number;\n}\n\nexport interface OfflineSyncFileTarget {\n root: string;\n path: string;\n filePath: string;\n}\n\nexport interface OfflineSyncFileWriteTarget extends OfflineSyncFileTarget {\n content: Buffer;\n}\n\nexport interface OfflineSyncFileWriteChunksTarget extends OfflineSyncFileTarget {\n chunks: AsyncIterable<Buffer>;\n}\n\nexport interface OfflineSyncFileStagingWriteTarget extends OfflineSyncFileWriteTarget {}\n\nexport interface OfflineSyncFileContentChunk extends Omit<OfflineSyncFileState, \"sha256\"> {\n sha256?: string;\n offset: number;\n chunkBytes: number;\n content: Buffer;\n}\n\nexport interface OfflineSyncApplyFileContentChunkResult {\n path: string;\n sha256: string;\n bytes: number;\n mtimeMs: number;\n offset: number;\n chunkBytes: number;\n done: boolean;\n applied: boolean;\n skipped: boolean;\n conflict?: OfflineSyncConflict;\n currentFile?: OfflineSyncFileState;\n}\n\ninterface OfflineUploadStaging {\n kind: \"single\" | \"chunks\";\n relPath: string;\n filePath: string;\n}\n\ninterface OfflineSyncFileRecordOptions {\n root: SafeArchiveRoot;\n relPath: string;\n filePath: string;\n includeContent: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n}\n\nconst SYNC_INTERNAL_DIR = \".offline-sync\";\nconst OFFLINE_SYNC_UPLOAD_STAGING_MAX_AGE_MS = 24 * 60 * 60 * 1000;\nconst EXCLUDED_FILE_NAMES = new Set([\n \".sync-state.json\",\n]);\n\nconst EXCLUDED_FILE_PREFIXES = [\n \".remnic-sync.\",\n \".remnic-sync-state.\",\n];\n\nfunction hashText(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction sha256Buffer(buffer: Buffer): { sha256: string; bytes: number } {\n return sha256Bytes(buffer);\n}\n\nfunction compareByPath<T extends { path: string }>(left: T, right: T): number {\n return left.path.localeCompare(right.path);\n}\n\nfunction assertSha256(value: unknown, field: string): string {\n if (typeof value !== \"string\" || !/^[a-f0-9]{64}$/i.test(value)) {\n throw new Error(`${field} must be a 64-character sha256 hex string`);\n }\n return value.toLowerCase();\n}\n\nfunction assertNonNegativeInteger(value: unknown, field: string): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n !Number.isInteger(value) ||\n value < 0\n ) {\n throw new Error(`${field} must be a non-negative integer`);\n }\n return value;\n}\n\nfunction assertNonNegativeFinite(value: unknown, field: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n throw new Error(`${field} must be a non-negative finite number`);\n }\n return value;\n}\n\nfunction assertBoolean(value: unknown, field: string): boolean {\n if (typeof value !== \"boolean\") {\n throw new Error(`${field} must be a boolean`);\n }\n return value;\n}\n\nfunction normalizeSourceId(value: unknown, field: string): string {\n if (typeof value !== \"string\" || value.trim().length === 0 || value.length > 512) {\n throw new Error(`${field} must be a non-empty string no longer than 512 characters`);\n }\n return value.trim();\n}\n\nfunction normalizeFileState(input: unknown, fieldPrefix: string): OfflineSyncFileState {\n if (!input || typeof input !== \"object\" || Array.isArray(input)) {\n throw new Error(`${fieldPrefix} must be an object`);\n }\n const obj = input as Record<string, unknown>;\n const relPath = normalizeRelativePath(obj.path, `${fieldPrefix}.path`);\n return {\n path: relPath,\n sha256: assertSha256(obj.sha256, `${fieldPrefix}.sha256`),\n bytes: assertNonNegativeInteger(obj.bytes, `${fieldPrefix}.bytes`),\n mtimeMs: assertNonNegativeFinite(obj.mtimeMs, `${fieldPrefix}.mtimeMs`),\n };\n}\n\nfunction normalizeFileRecord(\n input: unknown,\n fieldPrefix: string,\n requireContent: boolean,\n): OfflineSyncFileRecord {\n const state = normalizeFileState(input, fieldPrefix);\n const obj = input as Record<string, unknown>;\n const contentBase64 = obj.contentBase64;\n if (requireContent && typeof contentBase64 !== \"string\") {\n throw new Error(`${fieldPrefix}.contentBase64 is required`);\n }\n if (contentBase64 !== undefined && typeof contentBase64 !== \"string\") {\n throw new Error(`${fieldPrefix}.contentBase64 must be a base64 string`);\n }\n return {\n ...state,\n ...(contentBase64 !== undefined ? { contentBase64 } : {}),\n };\n}\n\nfunction normalizeFileStates(input: readonly unknown[] | undefined): OfflineSyncFileState[] {\n if (!input) return [];\n if (!Array.isArray(input)) {\n throw new Error(\"baseFiles must be an array\");\n }\n return input.map((entry, index) => normalizeFileState(entry, `baseFiles[${index}]`));\n}\n\nexport function normalizeOfflineSyncSnapshot(\n input: unknown,\n options: { requireContent?: boolean } = {},\n): OfflineSyncSnapshot {\n if (!input || typeof input !== \"object\" || Array.isArray(input)) {\n throw new Error(\"offline sync snapshot must be an object\");\n }\n const obj = input as Record<string, unknown>;\n if (obj.format !== OFFLINE_SYNC_SNAPSHOT_FORMAT) {\n throw new Error(`offline sync snapshot format must be ${OFFLINE_SYNC_SNAPSHOT_FORMAT}`);\n }\n if (obj.schemaVersion !== 1) {\n throw new Error(\"offline sync snapshot schemaVersion must be 1\");\n }\n const createdAt = normalizeIsoString(obj.createdAt, \"createdAt\");\n const sourceId = normalizeSourceId(obj.sourceId, \"sourceId\");\n const includeTranscripts = assertBoolean(obj.includeTranscripts, \"includeTranscripts\");\n if (!Array.isArray(obj.files)) {\n throw new Error(\"offline sync snapshot files must be an array\");\n }\n const files = obj.files\n .map((entry, index) =>\n normalizeFileRecord(entry, `files[${index}]`, options.requireContent === true))\n .filter((file) => !shouldIgnoreIncomingRuntimePath(file.path))\n .sort(compareByPath);\n assertUniquePaths(files, \"offline sync snapshot\");\n if (!includeTranscripts) {\n const transcriptPath = files.find((file) => file.path.split(\"/\")[0] === \"transcripts\")?.path;\n if (transcriptPath) {\n throw new Error(\n `offline sync snapshot includeTranscripts is false but contains transcript path: ${transcriptPath}`,\n );\n }\n }\n const excludedPath = files.find((file) => shouldExcludeRelPath(file.path, true))?.path;\n if (excludedPath) {\n throw new Error(`offline sync snapshot contains excluded path: ${excludedPath}`);\n }\n return {\n format: OFFLINE_SYNC_SNAPSHOT_FORMAT,\n schemaVersion: 1,\n createdAt,\n sourceId,\n includeTranscripts,\n files,\n };\n}\n\nexport function normalizeOfflineSyncChangeset(input: unknown): OfflineSyncChangeset {\n if (!input || typeof input !== \"object\" || Array.isArray(input)) {\n throw new Error(\"offline sync changeset must be an object\");\n }\n const obj = input as Record<string, unknown>;\n if (obj.format !== OFFLINE_SYNC_CHANGESET_FORMAT) {\n throw new Error(`offline sync changeset format must be ${OFFLINE_SYNC_CHANGESET_FORMAT}`);\n }\n if (obj.schemaVersion !== 1) {\n throw new Error(\"offline sync changeset schemaVersion must be 1\");\n }\n const createdAt = normalizeIsoString(obj.createdAt, \"createdAt\");\n const sourceId = normalizeSourceId(obj.sourceId, \"sourceId\");\n const includeTranscripts = assertBoolean(obj.includeTranscripts, \"includeTranscripts\");\n if (!Array.isArray(obj.changes)) {\n throw new Error(\"offline sync changeset changes must be an array\");\n }\n const changes = obj.changes.map((entry, index): OfflineSyncChange => {\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) {\n throw new Error(`changes[${index}] must be an object`);\n }\n const change = entry as Record<string, unknown>;\n const type = change.type;\n const relPath = normalizeRelativePath(change.path, `changes[${index}].path`);\n if (type === \"upsert\") {\n const file = normalizeFileRecord(\n change.file,\n `changes[${index}].file`,\n true,\n ) as OfflineSyncFileRecord & { contentBase64: string };\n if (file.path !== relPath) {\n throw new Error(`changes[${index}].file.path must match changes[${index}].path`);\n }\n const baseSha256 =\n change.baseSha256 === undefined\n ? undefined\n : assertSha256(change.baseSha256, `changes[${index}].baseSha256`);\n return {\n type: \"upsert\",\n path: relPath,\n ...(baseSha256 ? { baseSha256 } : {}),\n file,\n };\n }\n if (type === \"delete\") {\n return {\n type: \"delete\",\n path: relPath,\n baseSha256: assertSha256(change.baseSha256, `changes[${index}].baseSha256`),\n };\n }\n throw new Error(`changes[${index}].type must be \"upsert\" or \"delete\"`);\n }).filter((change) => !shouldIgnoreIncomingRuntimePath(change.path));\n assertUniquePaths(changes, \"offline sync changeset\");\n if (!includeTranscripts) {\n const transcriptPath = changes.find((change) => change.path.split(\"/\")[0] === \"transcripts\")?.path;\n if (transcriptPath) {\n throw new Error(\n `offline sync changeset includeTranscripts is false but contains transcript path: ${transcriptPath}`,\n );\n }\n }\n const excludedPath = changes.find((change) => shouldExcludeRelPath(change.path, true))?.path;\n if (excludedPath) {\n throw new Error(`offline sync changeset contains excluded path: ${excludedPath}`);\n }\n return {\n format: OFFLINE_SYNC_CHANGESET_FORMAT,\n schemaVersion: 1,\n createdAt,\n sourceId,\n includeTranscripts,\n changes: changes.sort(compareByPath),\n };\n}\n\nfunction normalizeIsoString(input: unknown, field: string): string {\n if (typeof input !== \"string\" || input.trim().length === 0) {\n throw new Error(`${field} must be an ISO timestamp string`);\n }\n const parsed = parseFlexibleIsoTimestamp(input.trim());\n if (parsed === null) {\n throw new Error(`${field} must be a parseable ISO timestamp`);\n }\n return new Date(parsed).toISOString();\n}\n\nfunction normalizeRelativePath(input: unknown, field: string): string {\n if (typeof input !== \"string\") {\n throw new Error(`${field} must be a POSIX relative path string`);\n }\n return validateArchiveRelativePath(input, field);\n}\n\nfunction assertUniquePaths(entries: readonly { path: string }[], context: string): void {\n const seen = new Set<string>();\n for (const entry of entries) {\n const key = entry.path.toLowerCase();\n if (seen.has(key)) {\n throw new Error(`${context} contains duplicate path: ${entry.path}`);\n }\n seen.add(key);\n }\n}\n\nfunction shouldExcludeRelPath(relPosix: string, includeTranscripts: boolean): boolean {\n const parts = relPosix.split(\"/\");\n if (parts.some((part) => DEFAULT_TRANSFER_EXCLUDE_DIRS.has(part))) return true;\n if (parts.some((part) => part === SYNC_INTERNAL_DIR)) return true;\n if (!includeTranscripts && parts[0] === \"transcripts\") return true;\n const basename = parts[parts.length - 1] ?? \"\";\n if (isCanonicalRuntimeStatePath(parts) && basename.includes(\".tmp-\")) return true;\n if (EXCLUDED_FILE_NAMES.has(basename)) return true;\n return EXCLUDED_FILE_PREFIXES.some((prefix) => basename.startsWith(prefix));\n}\n\nfunction shouldIgnoreIncomingRuntimePath(relPosix: string): boolean {\n const parts = relPosix.split(\"/\");\n const basename = parts[parts.length - 1] ?? \"\";\n return isCanonicalRuntimeStatePath(parts) && basename.includes(\".tmp-\");\n}\n\nfunction isCanonicalRuntimeStatePath(parts: string[]): boolean {\n if (parts[0] === \"state\") return true;\n return parts[0] === \"namespaces\" && parts.length >= 4 && parts[2] === \"state\";\n}\n\nfunction filterBaseFilesForMode(\n files: readonly OfflineSyncFileState[],\n includeTranscripts: boolean,\n): OfflineSyncFileState[] {\n return files.filter((file) => !shouldExcludeRelPath(file.path, includeTranscripts));\n}\n\nasync function readOfflineSyncFileRecord(\n options: OfflineSyncFileRecordOptions,\n): Promise<OfflineSyncFileRecord> {\n const relPath = validateArchiveRelativePath(options.relPath, \"offlineSyncFile.path\");\n const bytes = options.readFile\n ? await options.readFile({ root: options.root.abs, path: relPath, filePath: options.filePath })\n : await readFile(options.filePath);\n const digest = sha256Buffer(bytes);\n const st = await stat(options.filePath);\n return {\n path: relPath,\n sha256: digest.sha256,\n bytes: digest.bytes,\n mtimeMs: st.mtimeMs,\n ...(options.includeContent ? { contentBase64: bytes.toString(\"base64\") } : {}),\n };\n}\n\nasync function fileIsSecureStoreEncrypted(filePath: string): Promise<boolean> {\n const handle = await open(filePath, \"r\");\n try {\n const header = Buffer.alloc(MAGIC_HEADER_SIZE);\n const { bytesRead } = await handle.read(header, 0, header.length, 0);\n return bytesRead >= MAGIC_HEADER_SIZE && isEncryptedFile(header);\n } finally {\n await handle.close();\n }\n}\n\nasync function readPlainFileContentChunk(options: {\n filePath: string;\n offset: number;\n length: number;\n bytes: number;\n}): Promise<Buffer> {\n const chunkBytes = Math.min(options.length, options.bytes - options.offset);\n const chunk = Buffer.alloc(chunkBytes);\n if (chunkBytes === 0) return chunk;\n const handle = await open(options.filePath, \"r\");\n try {\n const { bytesRead } = await handle.read(chunk, 0, chunk.length, options.offset);\n return bytesRead === chunk.length ? chunk : chunk.subarray(0, bytesRead);\n } finally {\n await handle.close();\n }\n}\n\nexport async function buildOfflineSyncSnapshot(options: {\n root: string;\n sourceId: string;\n includeContent?: boolean;\n includeTranscripts?: boolean;\n now?: Date;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n}): Promise<OfflineSyncSnapshot> {\n const rootAbs = path.resolve(options.root);\n const root = await prepareSafeArchiveRoot(rootAbs, \"buildOfflineSyncSnapshot\", \"root\");\n const includeTranscripts = options.includeTranscripts !== false;\n const files: OfflineSyncFileRecord[] = [];\n\n async function walk(dirAbs: string): Promise<void> {\n let entries = await readdir(dirAbs, { withFileTypes: true });\n entries = entries.sort((left, right) => left.name.localeCompare(right.name));\n for (const entry of entries) {\n const abs = path.join(dirAbs, entry.name);\n const relPosix = path.relative(root.abs, abs).split(path.sep).join(\"/\");\n if (shouldExcludeRelPath(relPosix, includeTranscripts)) continue;\n if (entry.isSymbolicLink()) continue;\n if (entry.isDirectory()) {\n await walk(abs);\n continue;\n }\n if (!entry.isFile()) continue;\n files.push(await readOfflineSyncFileRecord({\n root,\n relPath: relPosix,\n filePath: abs,\n includeContent: options.includeContent === true,\n readFile: options.readFile,\n }));\n }\n }\n\n await walk(root.abs);\n\n return {\n format: OFFLINE_SYNC_SNAPSHOT_FORMAT,\n schemaVersion: 1,\n createdAt: (options.now ?? new Date()).toISOString(),\n sourceId: normalizeSourceId(options.sourceId, \"sourceId\"),\n includeTranscripts,\n files: files.sort(compareByPath),\n };\n}\n\nexport async function buildOfflineSyncSnapshotForPaths(options: {\n root: string;\n sourceId: string;\n paths: readonly string[];\n includeContent?: boolean;\n includeTranscripts?: boolean;\n now?: Date;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n}): Promise<OfflineSyncSnapshot> {\n const rootAbs = path.resolve(options.root);\n const root = await prepareSafeArchiveRoot(rootAbs, \"buildOfflineSyncSnapshotForPaths\", \"root\");\n const includeTranscripts = options.includeTranscripts !== false;\n const files: OfflineSyncFileRecord[] = [];\n const seen = new Set<string>();\n\n for (const rawPath of options.paths) {\n const relPath = normalizeRelativePath(rawPath, \"paths[]\");\n if (seen.has(relPath)) continue;\n seen.add(relPath);\n if (shouldExcludeRelPath(relPath, includeTranscripts)) {\n throw new Error(`offline sync snapshot path is excluded: ${relPath}`);\n }\n const filePath = await resolveSafeArchiveTarget(root, relPath);\n const st = await lstat(filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (!st || st.isSymbolicLink() || !st.isFile()) continue;\n files.push(await readOfflineSyncFileRecord({\n root,\n relPath,\n filePath,\n includeContent: options.includeContent === true,\n readFile: options.readFile,\n }));\n }\n\n return {\n format: OFFLINE_SYNC_SNAPSHOT_FORMAT,\n schemaVersion: 1,\n createdAt: (options.now ?? new Date()).toISOString(),\n sourceId: normalizeSourceId(options.sourceId, \"sourceId\"),\n includeTranscripts,\n files: files.sort(compareByPath),\n };\n}\n\nexport async function readOfflineSyncFileContentChunk(options: {\n root: string;\n path: string;\n offset?: number;\n length?: number;\n includeTranscripts?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n}): Promise<OfflineSyncFileContentChunk> {\n const rootAbs = path.resolve(options.root);\n const root = await prepareSafeArchiveRoot(rootAbs, \"readOfflineSyncFileContentChunk\", \"root\");\n const includeTranscripts = options.includeTranscripts !== false;\n const relPath = normalizeRelativePath(options.path, \"path\");\n if (shouldExcludeRelPath(relPath, includeTranscripts)) {\n throw new Error(`offline sync file content path is excluded: ${relPath}`);\n }\n const offset = options.offset === undefined\n ? 0\n : assertNonNegativeInteger(options.offset, \"offset\");\n const requestedLength = options.length === undefined\n ? OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES\n : assertNonNegativeInteger(options.length, \"length\");\n if (requestedLength < 1 || requestedLength > OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES) {\n throw new Error(\n `length must be an integer from 1 to ${OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES}`,\n );\n }\n const filePath = await resolveSafeArchiveTarget(root, relPath);\n const st = await lstat(filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (!st || st.isSymbolicLink() || !st.isFile()) {\n throw new Error(`offline sync file content path not found: ${relPath}`);\n }\n const encrypted = await fileIsSecureStoreEncrypted(filePath);\n if (!encrypted) {\n if (offset > st.size) {\n throw new Error(`offset must be <= file size for ${relPath}`);\n }\n const chunk = await readPlainFileContentChunk({\n filePath,\n offset,\n length: requestedLength,\n bytes: st.size,\n });\n return {\n path: relPath,\n bytes: st.size,\n mtimeMs: st.mtimeMs,\n offset,\n chunkBytes: chunk.length,\n content: chunk,\n };\n }\n if (!options.readFile) {\n throw new Error(`offline sync file content requires a secure-store read hook: ${relPath}`);\n }\n const content = await options.readFile({ root: root.abs, path: relPath, filePath });\n if (offset > content.length) {\n throw new Error(`offset must be <= file size for ${relPath}`);\n }\n const digest = sha256Buffer(content);\n const end = Math.min(content.length, offset + requestedLength);\n const chunk = content.subarray(offset, end);\n return {\n path: relPath,\n sha256: digest.sha256,\n bytes: digest.bytes,\n mtimeMs: st.mtimeMs,\n offset,\n chunkBytes: chunk.length,\n content: Buffer.from(chunk),\n };\n}\n\nexport async function buildOfflineSyncChangeset(options: {\n root: string;\n sourceId: string;\n baseFiles?: readonly OfflineSyncFileState[];\n excludePaths?: readonly string[];\n includeTranscripts?: boolean;\n now?: Date;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n}): Promise<OfflineSyncChangeset> {\n const includeTranscripts = options.includeTranscripts !== false;\n const excludedPaths = new Set(\n (options.excludePaths ?? []).map((relPath) => normalizeRelativePath(relPath, \"excludePaths[]\")),\n );\n const base = byPath(filterBaseFilesForMode(\n normalizeFileStates(options.baseFiles),\n includeTranscripts,\n ));\n const current = await buildOfflineSyncSnapshot({\n root: options.root,\n sourceId: options.sourceId,\n includeContent: false,\n includeTranscripts,\n now: options.now,\n readFile: options.readFile,\n });\n const currentMap = byPath(current.files);\n const changes: OfflineSyncChange[] = [];\n\n for (const relPath of unionPaths(base, currentMap)) {\n if (excludedPaths.has(relPath)) continue;\n const baseEntry = base.get(relPath);\n const currentEntry = currentMap.get(relPath);\n if (currentEntry && currentEntry.sha256 !== baseEntry?.sha256) {\n const file = await buildOfflineSyncSnapshotForPaths({\n root: options.root,\n sourceId: options.sourceId,\n paths: [relPath],\n includeContent: true,\n includeTranscripts,\n now: options.now,\n readFile: options.readFile,\n });\n const record = file.files[0];\n if (!record || typeof record.contentBase64 !== \"string\" || record.sha256 !== currentEntry.sha256) {\n throw new Error(`offline sync file changed while building changeset: ${relPath}`);\n }\n changes.push({\n type: \"upsert\",\n path: relPath,\n ...(baseEntry ? { baseSha256: baseEntry.sha256 } : {}),\n file: record as OfflineSyncFileRecord & { contentBase64: string },\n });\n continue;\n }\n if (!currentEntry && baseEntry) {\n changes.push({\n type: \"delete\",\n path: relPath,\n baseSha256: baseEntry.sha256,\n });\n }\n }\n\n return {\n format: OFFLINE_SYNC_CHANGESET_FORMAT,\n schemaVersion: 1,\n createdAt: (options.now ?? new Date()).toISOString(),\n sourceId: normalizeSourceId(options.sourceId, \"sourceId\"),\n includeTranscripts: current.includeTranscripts,\n changes: changes.sort(compareByPath),\n };\n}\n\nexport function summarizeOfflineSyncChangeset(\n changeset: OfflineSyncChangeset,\n): OfflineSyncChangesetSummary {\n const upserts = changeset.changes.filter((change) => change.type === \"upsert\").length;\n const deletes = changeset.changes.filter((change) => change.type === \"delete\").length;\n return {\n upserts,\n deletes,\n total: changeset.changes.length,\n };\n}\n\nexport async function summarizeOfflineSyncPendingChanges(options: {\n root: string;\n sourceId: string;\n baseFiles?: readonly OfflineSyncFileState[];\n includeTranscripts?: boolean;\n now?: Date;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n}): Promise<OfflineSyncChangesetSummary> {\n const includeTranscripts = options.includeTranscripts !== false;\n const base = byPath(filterBaseFilesForMode(\n normalizeFileStates(options.baseFiles),\n includeTranscripts,\n ));\n const current = await buildOfflineSyncSnapshot({\n root: options.root,\n sourceId: options.sourceId,\n includeContent: false,\n includeTranscripts,\n now: options.now,\n readFile: options.readFile,\n });\n const currentMap = byPath(current.files);\n let upserts = 0;\n let deletes = 0;\n\n for (const relPath of unionPaths(base, currentMap)) {\n const baseEntry = base.get(relPath);\n const currentEntry = currentMap.get(relPath);\n if (currentEntry && currentEntry.sha256 !== baseEntry?.sha256) {\n upserts += 1;\n continue;\n }\n if (!currentEntry && baseEntry) {\n deletes += 1;\n }\n }\n\n return {\n upserts,\n deletes,\n total: upserts + deletes,\n };\n}\n\nexport async function applyOfflineSyncSnapshot(options: {\n root: string;\n snapshot: unknown;\n baseFiles?: readonly OfflineSyncFileState[];\n writeConflictCopies?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n writeFile?: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n deleteFile?: (target: OfflineSyncFileTarget) => Promise<void>;\n}): Promise<OfflineSyncApplySnapshotResult> {\n const snapshot = normalizeOfflineSyncSnapshot(options.snapshot);\n const baseMap = byPath(filterBaseFilesForMode(\n normalizeFileStates(options.baseFiles),\n snapshot.includeTranscripts,\n ));\n const incomingMap = byPath(snapshot.files);\n const incomingBuffers = verifyRecordContents(snapshot.files, \"offline sync snapshot\", {\n requireContent: false,\n });\n const root = await ensureSyncRoot(options.root, \"applyOfflineSyncSnapshot\");\n const current = await buildOfflineSyncSnapshot({\n root: root.abs,\n sourceId: \"local\",\n includeContent: false,\n includeTranscripts: snapshot.includeTranscripts,\n readFile: options.readFile,\n });\n const currentMap = byPath(current.files);\n const nextBase = new Map(baseMap);\n const conflicts: OfflineSyncConflict[] = [];\n let upserted = 0;\n let deleted = 0;\n let skipped = 0;\n let pendingLocal = 0;\n\n for (const relPath of unionPaths(baseMap, incomingMap, currentMap)) {\n const base = baseMap.get(relPath);\n const incoming = incomingMap.get(relPath);\n const currentEntry = currentMap.get(relPath);\n\n if (incoming) {\n if (currentEntry?.sha256 === incoming.sha256) {\n nextBase.set(relPath, toFileState(incoming));\n skipped += 1;\n continue;\n }\n if (!currentEntry && base && incoming.sha256 === base.sha256) {\n nextBase.set(relPath, base);\n pendingLocal += 1;\n skipped += 1;\n continue;\n }\n if (!currentEntry && base && incoming.sha256 !== base.sha256) {\n conflicts.push(await recordConflict({\n root,\n relPath,\n reason: \"local_deleted_remote_modified\",\n baseSha256: base.sha256,\n incomingSha256: incoming.sha256,\n incomingBuffer: options.writeConflictCopies === false\n ? incomingBuffers.get(relPath)\n : requiredBuffer(incomingBuffers, relPath),\n writeConflictCopies: options.writeConflictCopies !== false,\n sourceId: snapshot.sourceId,\n writeFile: options.writeFile,\n }));\n nextBase.set(relPath, base);\n continue;\n }\n if (!currentEntry && !base) {\n await writeSafeFile(root, relPath, requiredBuffer(incomingBuffers, relPath), options.writeFile);\n nextBase.set(relPath, toFileState(incoming));\n upserted += 1;\n continue;\n }\n if (base && currentEntry && currentEntry.sha256 === base.sha256) {\n await writeSafeFile(root, relPath, requiredBuffer(incomingBuffers, relPath), options.writeFile);\n nextBase.set(relPath, toFileState(incoming));\n upserted += 1;\n continue;\n }\n if (base && incoming.sha256 === base.sha256) {\n nextBase.set(relPath, base);\n pendingLocal += 1;\n skipped += 1;\n continue;\n }\n conflicts.push(await recordConflict({\n root,\n relPath,\n reason: base ? \"both_modified\" : \"remote_exists_for_local_create\",\n baseSha256: base?.sha256,\n localSha256: currentEntry?.sha256,\n incomingSha256: incoming.sha256,\n incomingBuffer: options.writeConflictCopies === false\n ? incomingBuffers.get(relPath)\n : requiredBuffer(incomingBuffers, relPath),\n writeConflictCopies: options.writeConflictCopies !== false,\n sourceId: snapshot.sourceId,\n writeFile: options.writeFile,\n }));\n if (base) nextBase.set(relPath, base);\n continue;\n }\n\n if (!currentEntry) {\n nextBase.delete(relPath);\n skipped += 1;\n continue;\n }\n if (base && currentEntry.sha256 === base.sha256) {\n await deleteSafeFile(root, relPath, options.deleteFile);\n nextBase.delete(relPath);\n deleted += 1;\n continue;\n }\n if (base) {\n conflicts.push({\n path: relPath,\n reason: \"local_modified_remote_deleted\",\n baseSha256: base.sha256,\n localSha256: currentEntry.sha256,\n });\n nextBase.set(relPath, base);\n continue;\n }\n pendingLocal += 1;\n skipped += 1;\n }\n\n return {\n upserted,\n deleted,\n skipped,\n pendingLocal,\n conflicts,\n nextBaseFiles: [...nextBase.values()].sort(compareByPath),\n };\n}\n\nexport async function applyOfflineSyncChangeset(options: {\n root: string;\n changeset: unknown;\n writeConflictCopies?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n writeFile?: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n deleteFile?: (target: OfflineSyncFileTarget) => Promise<void>;\n}): Promise<OfflineSyncApplyChangesetResult> {\n let changeset: OfflineSyncChangeset;\n try {\n changeset = normalizeOfflineSyncChangeset(options.changeset);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n message.startsWith(\"offline sync\")\n ? message\n : `offline sync changeset invalid: ${message}`,\n );\n }\n const root = await ensureSyncRoot(options.root, \"applyOfflineSyncChangeset\");\n const records = changeset.changes\n .filter((change): change is Extract<OfflineSyncChange, { type: \"upsert\" }> => change.type === \"upsert\")\n .map((change) => change.file);\n const incomingBuffers = verifyRecordContents(records, \"offline sync changeset\");\n const current = await buildOfflineSyncSnapshot({\n root: root.abs,\n sourceId: \"local\",\n includeContent: false,\n includeTranscripts: changeset.includeTranscripts,\n readFile: options.readFile,\n });\n const currentMap = byPath(current.files);\n const conflicts: OfflineSyncConflict[] = [];\n let appliedUpserts = 0;\n let appliedDeletes = 0;\n let skipped = 0;\n\n for (const change of changeset.changes) {\n const currentEntry = currentMap.get(change.path);\n if (change.type === \"upsert\") {\n if (currentEntry?.sha256 === change.file.sha256) {\n skipped += 1;\n continue;\n }\n if (!change.baseSha256) {\n if (!currentEntry) {\n await writeSafeFile(root, change.path, requiredBuffer(incomingBuffers, change.path), options.writeFile);\n currentMap.set(change.path, toFileState(change.file));\n appliedUpserts += 1;\n continue;\n }\n conflicts.push(await recordConflict({\n root,\n relPath: change.path,\n reason: \"remote_exists_for_local_create\",\n localSha256: currentEntry.sha256,\n incomingSha256: change.file.sha256,\n incomingBuffer: incomingBuffers.get(change.path),\n writeConflictCopies: options.writeConflictCopies !== false,\n sourceId: changeset.sourceId,\n writeFile: options.writeFile,\n }));\n continue;\n }\n if (currentEntry?.sha256 === change.baseSha256) {\n await writeSafeFile(root, change.path, requiredBuffer(incomingBuffers, change.path), options.writeFile);\n currentMap.set(change.path, toFileState(change.file));\n appliedUpserts += 1;\n continue;\n }\n conflicts.push(await recordConflict({\n root,\n relPath: change.path,\n reason: currentEntry ? \"remote_changed_for_local_update\" : \"remote_deleted_for_local_update\",\n baseSha256: change.baseSha256,\n localSha256: currentEntry?.sha256,\n incomingSha256: change.file.sha256,\n incomingBuffer: incomingBuffers.get(change.path),\n writeConflictCopies: options.writeConflictCopies !== false,\n sourceId: changeset.sourceId,\n writeFile: options.writeFile,\n }));\n continue;\n }\n\n if (!currentEntry) {\n skipped += 1;\n continue;\n }\n if (currentEntry.sha256 === change.baseSha256) {\n await deleteSafeFile(root, change.path, options.deleteFile);\n currentMap.delete(change.path);\n appliedDeletes += 1;\n continue;\n }\n conflicts.push({\n path: change.path,\n reason: \"remote_changed_for_local_delete\",\n baseSha256: change.baseSha256,\n localSha256: currentEntry.sha256,\n });\n }\n\n return {\n appliedUpserts,\n appliedDeletes,\n skipped,\n conflicts,\n currentFiles: [...currentMap.values()].sort(compareByPath),\n };\n}\n\nfunction verifyRecordContents(\n records: readonly OfflineSyncFileRecord[],\n context: string,\n options: { requireContent?: boolean } = {},\n): Map<string, Buffer> {\n const buffers = new Map<string, Buffer>();\n for (const record of records) {\n if (typeof record.contentBase64 !== \"string\") {\n if (options.requireContent === false) continue;\n throw new Error(`${context}: contentBase64 is required for ${record.path}`);\n }\n const buffer = Buffer.from(record.contentBase64, \"base64\");\n const digest = sha256Buffer(buffer);\n if (digest.sha256 !== record.sha256 || digest.bytes !== record.bytes) {\n throw new Error(\n `${context}: content checksum mismatch for ${record.path}`,\n );\n }\n buffers.set(record.path, buffer);\n }\n return buffers;\n}\n\nfunction requiredBuffer(buffers: Map<string, Buffer>, relPath: string): Buffer {\n const buffer = buffers.get(relPath);\n if (!buffer) {\n throw new Error(`missing decoded content for ${relPath}`);\n }\n return buffer;\n}\n\nasync function ensureSyncRoot(rootPath: string, errorPrefix: string): Promise<SafeArchiveRoot> {\n const rootAbs = path.resolve(rootPath);\n await mkdir(rootAbs, { recursive: true });\n return prepareSafeArchiveRoot(rootAbs, errorPrefix, \"root\");\n}\n\nfunction byPath<T extends OfflineSyncFileState>(files: readonly T[]): Map<string, T> {\n const out = new Map<string, T>();\n for (const file of files) {\n out.set(validateArchiveRelativePath(file.path, \"offlineSync\"), file);\n }\n return out;\n}\n\nfunction unionPaths(...maps: Array<Map<string, unknown>>): string[] {\n const paths = new Set<string>();\n for (const map of maps) {\n for (const key of map.keys()) paths.add(key);\n }\n return [...paths].sort();\n}\n\nfunction toFileState(file: OfflineSyncFileState): OfflineSyncFileState {\n return {\n path: file.path,\n sha256: file.sha256,\n bytes: file.bytes,\n mtimeMs: file.mtimeMs,\n };\n}\n\nasync function writeSafeFile(\n root: SafeArchiveRoot,\n relPath: string,\n content: Buffer,\n writeFileHook?: (target: OfflineSyncFileWriteTarget) => Promise<void>,\n): Promise<void> {\n const target = await resolveSafeArchiveTarget(root, relPath);\n if (writeFileHook) {\n await writeFileHook({ root: root.abs, path: relPath, filePath: target, content });\n return;\n }\n await mkdir(path.dirname(target), { recursive: true });\n const tmp = path.join(\n path.dirname(target),\n `.remnic-sync.${process.pid}.${randomUUID()}.tmp`,\n );\n await writeFile(tmp, content);\n try {\n const targetStat = await lstat(target).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (targetStat?.isSymbolicLink()) {\n throw new Error(`offline sync target is a symlink: ${relPath}`);\n }\n await rename(tmp, target);\n } catch (error) {\n await unlink(tmp).catch(() => {});\n throw error;\n }\n}\n\nexport async function applyOfflineSyncFileContentChunk(options: {\n root: string;\n sourceId: string;\n path: string;\n sha256: string;\n bytes: number;\n mtimeMs: number;\n offset?: number;\n content: Buffer;\n baseSha256?: string;\n includeTranscripts?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n writeFile?: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n writeStagingFile?: (target: OfflineSyncFileStagingWriteTarget) => Promise<void>;\n writeFileChunks?: (target: OfflineSyncFileWriteChunksTarget) => Promise<void>;\n}): Promise<OfflineSyncApplyFileContentChunkResult> {\n const root = await ensureSyncRoot(options.root, \"applyOfflineSyncFileContentChunk\");\n const sourceId = normalizeSourceId(options.sourceId, \"sourceId\");\n const relPath = normalizeRelativePath(options.path, \"path\");\n const includeTranscripts = options.includeTranscripts !== false;\n if (shouldExcludeRelPath(relPath, includeTranscripts)) {\n throw new Error(`offline sync file content path is excluded: ${relPath}`);\n }\n const sha256 = assertSha256(options.sha256, \"sha256\");\n const bytes = assertNonNegativeInteger(options.bytes, \"bytes\");\n const mtimeMs = assertNonNegativeFinite(options.mtimeMs, \"mtimeMs\");\n const offset = options.offset === undefined\n ? 0\n : assertNonNegativeInteger(options.offset, \"offset\");\n const baseSha256 = options.baseSha256 === undefined\n ? undefined\n : assertSha256(options.baseSha256, \"baseSha256\");\n if (!Buffer.isBuffer(options.content)) {\n throw new Error(\"content must be a Buffer\");\n }\n if (options.content.length > OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES) {\n throw new Error(\n `content chunk must be ${OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES} bytes or fewer`,\n );\n }\n if (bytes > 0 && options.content.length === 0) {\n throw new Error(\"content chunk must be non-empty before EOF\");\n }\n if (offset > bytes || offset + options.content.length > bytes) {\n throw new Error(`content chunk range exceeds declared file size for ${relPath}`);\n }\n if (options.writeFile && !options.writeFileChunks) {\n throw new Error(\"offline sync upload storage hooks require writeFileChunks\");\n }\n if (options.writeFile && !options.writeStagingFile) {\n throw new Error(\"offline sync upload storage hooks require writeStagingFile\");\n }\n if (offset === 0) {\n await pruneOfflineUploadStaging(root);\n }\n\n const upload = await writeOfflineUploadChunk({\n root,\n sourceId,\n relPath,\n sha256,\n bytes,\n offset,\n content: options.content,\n readFile: options.readFile,\n writeFile: options.writeFile,\n writeStagingFile: options.writeStagingFile,\n });\n const done = offset + options.content.length === bytes;\n const baseResult = {\n path: relPath,\n sha256,\n bytes,\n mtimeMs,\n offset,\n chunkBytes: options.content.length,\n done,\n };\n if (!done) {\n return {\n ...baseResult,\n applied: false,\n skipped: false,\n };\n }\n\n const digest = await digestOfflineUploadStagingContent({\n root,\n upload,\n readFile: options.readFile,\n });\n if (digest.sha256 !== sha256 || digest.bytes !== bytes) {\n await cleanupOfflineUpload(upload).catch(() => {});\n throw new Error(`offline sync upload checksum mismatch for ${relPath}`);\n }\n\n const currentSnapshot = await buildOfflineSyncSnapshotForPaths({\n root: root.abs,\n sourceId: \"local\",\n paths: [relPath],\n includeContent: false,\n includeTranscripts,\n readFile: options.readFile,\n });\n const currentFile = currentSnapshot.files[0];\n const uploadedState: OfflineSyncFileState = {\n path: relPath,\n sha256,\n bytes,\n mtimeMs,\n };\n\n try {\n if (currentFile?.sha256 === sha256) {\n return {\n ...baseResult,\n applied: false,\n skipped: true,\n currentFile: toFileState(currentFile),\n };\n }\n if (!baseSha256 && currentFile) {\n const conflict = await recordConflict({\n root,\n relPath,\n reason: \"remote_exists_for_local_create\",\n localSha256: currentFile.sha256,\n incomingSha256: sha256,\n writeConflictCopies: false,\n sourceId,\n writeFile: options.writeFile,\n });\n return {\n ...baseResult,\n applied: false,\n skipped: false,\n conflict,\n currentFile: toFileState(currentFile),\n };\n }\n if (baseSha256 && currentFile?.sha256 !== baseSha256) {\n const conflict = await recordConflict({\n root,\n relPath,\n reason: currentFile ? \"remote_changed_for_local_update\" : \"remote_deleted_for_local_update\",\n baseSha256,\n localSha256: currentFile?.sha256,\n incomingSha256: sha256,\n writeConflictCopies: false,\n sourceId,\n writeFile: options.writeFile,\n });\n return {\n ...baseResult,\n applied: false,\n skipped: false,\n conflict,\n ...(currentFile ? { currentFile: toFileState(currentFile) } : {}),\n };\n }\n\n await writeSafeFileFromUpload(root, relPath, upload, options.readFile, options.writeFileChunks);\n return {\n ...baseResult,\n applied: true,\n skipped: false,\n currentFile: uploadedState,\n };\n } finally {\n await cleanupOfflineUpload(upload).catch(() => {});\n }\n}\n\nfunction offlineUploadRelPath(options: {\n sourceId: string;\n relPath: string;\n sha256: string;\n bytes: number;\n}): string {\n const key = hashText([\n options.sourceId,\n options.relPath,\n options.sha256,\n String(options.bytes),\n ].join(\"\\0\"));\n return `${SYNC_INTERNAL_DIR}/uploads/${key}.part`;\n}\n\nasync function offlineUploadPath(root: SafeArchiveRoot, options: {\n sourceId: string;\n relPath: string;\n sha256: string;\n bytes: number;\n}): Promise<OfflineUploadStaging> {\n const relPath = offlineUploadRelPath(options);\n return {\n kind: \"single\",\n relPath,\n filePath: await resolveSafeArchiveTarget(root, relPath),\n };\n}\n\nasync function offlineUploadChunkPath(root: SafeArchiveRoot, options: {\n sourceId: string;\n relPath: string;\n sha256: string;\n bytes: number;\n offset: number;\n}): Promise<OfflineUploadStaging> {\n const uploadRelPath = offlineUploadRelPath(options);\n const relPath = `${uploadRelPath}/${String(options.offset).padStart(20, \"0\")}.part`;\n return {\n kind: \"chunks\",\n relPath,\n filePath: await resolveSafeArchiveTarget(root, relPath),\n };\n}\n\nasync function writeOfflineUploadChunk(options: {\n root: SafeArchiveRoot;\n sourceId: string;\n relPath: string;\n sha256: string;\n bytes: number;\n offset: number;\n content: Buffer;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n writeFile?: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n writeStagingFile?: (target: OfflineSyncFileStagingWriteTarget) => Promise<void>;\n}): Promise<OfflineUploadStaging> {\n if ((options.writeFile || options.writeStagingFile) && !options.readFile) {\n throw new Error(\"offline sync upload chunk storage hooks require readFile\");\n }\n const uploadRoot = {\n ...(await offlineUploadPath(options.root, options)),\n kind: \"chunks\" as const,\n };\n if (options.offset === 0) {\n await rm(uploadRoot.filePath, { recursive: true, force: true }).catch(() => {});\n } else {\n const existing = await stat(uploadRoot.filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (!existing || !existing.isDirectory()) {\n throw new Error(`offline sync upload is missing initial chunk for ${options.relPath}`);\n }\n }\n const chunk = await offlineUploadChunkPath(options.root, { ...options, offset: options.offset });\n\n const writeStagingFile = options.writeStagingFile ?? options.writeFile;\n if (writeStagingFile) {\n // Storage-backed services provide these hooks so secure-store deployments\n // keep staged partial uploads encrypted at rest without mutating indexes.\n await writeOfflineUploadContent({\n root: options.root,\n relPath: chunk.relPath,\n filePath: chunk.filePath,\n content: options.content,\n writeFile: writeStagingFile,\n });\n return uploadRoot;\n }\n\n await mkdir(path.dirname(chunk.filePath), { recursive: true });\n const existingChunk = await lstat(chunk.filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (existingChunk?.isSymbolicLink()) {\n throw new Error(`offline sync upload chunk is a symlink: ${chunk.relPath}`);\n }\n await writeFile(chunk.filePath, options.content, { mode: 0o600 });\n return uploadRoot;\n}\n\nasync function pruneOfflineUploadStaging(root: SafeArchiveRoot): Promise<void> {\n const uploadsRelPath = `${SYNC_INTERNAL_DIR}/uploads`;\n const uploadsPath = await resolveSafeArchiveTarget(root, uploadsRelPath);\n const entries = await readdir(uploadsPath, { withFileTypes: true }).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw error;\n });\n const now = Date.now();\n await Promise.all(entries.map(async (entry) => {\n if (!/^[a-f0-9]{64}\\.part$/i.test(entry.name)) return;\n const relPath = `${uploadsRelPath}/${entry.name}`;\n const filePath = await resolveSafeArchiveTarget(root, relPath);\n const info = await lstat(filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (!info) return;\n if (now - info.mtimeMs <= OFFLINE_SYNC_UPLOAD_STAGING_MAX_AGE_MS) return;\n await rm(filePath, { recursive: true, force: true });\n }));\n}\n\nasync function* readOfflineUploadStagingChunks(options: {\n root: SafeArchiveRoot;\n upload: OfflineUploadStaging;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n}): AsyncGenerator<Buffer> {\n if (options.upload.kind === \"single\") {\n yield await readOfflineUploadContent({\n root: options.root,\n relPath: options.upload.relPath,\n filePath: options.upload.filePath,\n readFile: options.readFile,\n });\n return;\n }\n\n const entries = await readdir(options.upload.filePath);\n const chunkNames = entries\n .filter((entry) => /^\\d{20}\\.part$/.test(entry))\n .sort();\n if (chunkNames.length === 0) {\n throw new Error(`offline sync upload is missing chunks for ${options.upload.relPath}`);\n }\n let expectedOffset = 0;\n for (const chunkName of chunkNames) {\n const offset = Number(chunkName.slice(0, 20));\n if (!Number.isSafeInteger(offset) || offset !== expectedOffset) {\n throw new Error(\n `offline sync upload offset mismatch for ${options.upload.relPath}: expected ${expectedOffset}, got ${offset}`,\n );\n }\n const relPath = `${options.upload.relPath}/${chunkName}`;\n const filePath = await resolveSafeArchiveTarget(options.root, relPath);\n const content = await readOfflineUploadContent({\n root: options.root,\n relPath,\n filePath,\n readFile: options.readFile,\n });\n expectedOffset += content.length;\n yield content;\n }\n}\n\nasync function digestOfflineUploadStagingContent(options: {\n root: SafeArchiveRoot;\n upload: OfflineUploadStaging;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n}): Promise<{ sha256: string; bytes: number }> {\n const hash = createHash(\"sha256\");\n let bytes = 0;\n for await (const chunk of readOfflineUploadStagingChunks(options)) {\n hash.update(chunk);\n bytes += chunk.length;\n }\n return { sha256: hash.digest(\"hex\"), bytes };\n}\n\nasync function writeSafeFileFromUpload(\n root: SafeArchiveRoot,\n relPath: string,\n upload: OfflineUploadStaging,\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>,\n writeFileChunks?: (target: OfflineSyncFileWriteChunksTarget) => Promise<void>,\n): Promise<void> {\n const target = await resolveSafeArchiveTarget(root, relPath);\n const chunks = readOfflineUploadStagingChunks({ root, upload, readFile });\n if (writeFileChunks) {\n await writeFileChunks({ root: root.abs, path: relPath, filePath: target, chunks });\n return;\n }\n\n await mkdir(path.dirname(target), { recursive: true });\n const tmp = path.join(\n path.dirname(target),\n `.remnic-sync.${process.pid}.${randomUUID()}.tmp`,\n );\n const handle = await open(tmp, \"w\", 0o600);\n try {\n for await (const chunk of chunks) {\n if (chunk.length > 0) await handle.write(chunk);\n }\n await handle.close();\n const targetStat = await lstat(target).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (targetStat?.isSymbolicLink()) {\n throw new Error(`offline sync target is a symlink: ${relPath}`);\n }\n await rename(tmp, target);\n } catch (error) {\n await handle.close().catch(() => {});\n await unlink(tmp).catch(() => {});\n throw error;\n }\n}\n\nasync function cleanupOfflineUpload(upload: OfflineUploadStaging): Promise<void> {\n if (upload.kind === \"chunks\") {\n await rm(upload.filePath, { recursive: true, force: true });\n return;\n }\n await unlink(upload.filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw error;\n });\n}\n\nasync function readOfflineUploadContent(options: {\n root: SafeArchiveRoot;\n relPath: string;\n filePath: string;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n}): Promise<Buffer> {\n if (options.readFile) {\n return options.readFile({\n root: options.root.abs,\n path: options.relPath,\n filePath: options.filePath,\n });\n }\n return readFile(options.filePath);\n}\n\nasync function writeOfflineUploadContent(options: {\n root: SafeArchiveRoot;\n relPath: string;\n filePath: string;\n content: Buffer;\n writeFile: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n}): Promise<void> {\n await options.writeFile({\n root: options.root.abs,\n path: options.relPath,\n filePath: options.filePath,\n content: options.content,\n });\n}\n\nasync function deleteSafeFile(\n root: SafeArchiveRoot,\n relPath: string,\n deleteFile?: (target: OfflineSyncFileTarget) => Promise<void>,\n): Promise<void> {\n const target = await resolveSafeArchiveTarget(root, relPath);\n if (deleteFile) {\n await deleteFile({ root: root.abs, path: relPath, filePath: target });\n return;\n }\n await unlink(target).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw error;\n });\n}\n\nasync function recordConflict(options: {\n root: SafeArchiveRoot;\n relPath: string;\n reason: OfflineSyncConflict[\"reason\"];\n baseSha256?: string;\n localSha256?: string;\n incomingSha256?: string;\n incomingBuffer?: Buffer;\n writeConflictCopies: boolean;\n sourceId: string;\n writeFile?: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n}): Promise<OfflineSyncConflict> {\n let conflictPath: string | undefined;\n if (options.writeConflictCopies && options.incomingBuffer) {\n const sourceHash = hashText(options.sourceId).slice(0, 12);\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n conflictPath = `${SYNC_INTERNAL_DIR}/conflicts/${stamp}-${sourceHash}/${options.relPath}`;\n await writeSafeFile(options.root, conflictPath, options.incomingBuffer, options.writeFile);\n }\n return {\n path: options.relPath,\n reason: options.reason,\n baseSha256: options.baseSha256,\n localSha256: options.localSha256,\n incomingSha256: options.incomingSha256,\n ...(conflictPath ? { conflictPath } : {}),\n };\n}\n\nexport function defaultOfflineSyncStatePath(\n memoryDir: string,\n remoteId: string,\n namespace?: string,\n): string {\n const key = hashText(`${remoteId}\\0${namespace ?? \"\"}`).slice(0, 16);\n return path.join(path.resolve(memoryDir), SYNC_INTERNAL_DIR, \"state\", `${key}.json`);\n}\n\nexport async function readOfflineSyncState(\n statePath: string,\n): Promise<OfflineSyncState | null> {\n let raw: string;\n try {\n raw = await readFile(path.resolve(statePath), \"utf-8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n }\n const parsed = JSON.parse(raw) as unknown;\n return normalizeOfflineSyncState(parsed);\n}\n\nexport async function writeOfflineSyncState(\n statePath: string,\n state: OfflineSyncState,\n): Promise<void> {\n const normalized = normalizeOfflineSyncState(state);\n const target = path.resolve(statePath);\n await mkdir(path.dirname(target), { recursive: true });\n const tmp = path.join(\n path.dirname(target),\n `.remnic-sync-state.${process.pid}.${randomUUID()}.tmp`,\n );\n await writeFile(tmp, JSON.stringify(normalized, null, 2) + \"\\n\", \"utf-8\");\n try {\n await rename(tmp, target);\n } catch (error) {\n await unlink(tmp).catch(() => {});\n throw error;\n }\n}\n\nexport function offlineSyncStateFromSnapshot(options: {\n remoteId: string;\n namespace?: string;\n snapshot: OfflineSyncSnapshot;\n baseFiles?: readonly OfflineSyncFileState[];\n}): OfflineSyncState {\n const snapshot = normalizeOfflineSyncSnapshot(options.snapshot);\n return normalizeOfflineSyncState({\n version: OFFLINE_SYNC_STATE_VERSION,\n remoteId: options.remoteId,\n namespace: options.namespace,\n includeTranscripts: snapshot.includeTranscripts,\n lastSyncedAt: new Date().toISOString(),\n baseFiles: options.baseFiles ?? snapshot.files.map(toFileState),\n });\n}\n\nexport function normalizeOfflineSyncState(input: unknown): OfflineSyncState {\n if (!input || typeof input !== \"object\" || Array.isArray(input)) {\n throw new Error(\"offline sync state must be an object\");\n }\n const obj = input as Record<string, unknown>;\n if (obj.version !== OFFLINE_SYNC_STATE_VERSION) {\n throw new Error(`offline sync state version must be ${OFFLINE_SYNC_STATE_VERSION}`);\n }\n const namespace =\n typeof obj.namespace === \"string\" && obj.namespace.trim().length > 0\n ? obj.namespace.trim()\n : undefined;\n const baseFiles = normalizeFileStates(obj.baseFiles as readonly unknown[] | undefined)\n .sort(compareByPath);\n assertUniquePaths(baseFiles, \"offline sync state\");\n return {\n version: OFFLINE_SYNC_STATE_VERSION,\n remoteId: normalizeSourceId(obj.remoteId, \"remoteId\"),\n ...(namespace ? { namespace } : {}),\n includeTranscripts: assertBoolean(obj.includeTranscripts, \"includeTranscripts\"),\n lastSyncedAt: normalizeIsoString(obj.lastSyncedAt, \"lastSyncedAt\"),\n baseFiles,\n };\n}\n\nexport function fileStatesFromSnapshot(snapshot: OfflineSyncSnapshot): OfflineSyncFileState[] {\n return normalizeOfflineSyncSnapshot(snapshot).files.map(toFileState).sort(compareByPath);\n}\n"],"mappings":"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","names":["chunk","readFile"]}