@narumitw/pi-sync 0.53.0 → 0.53.1

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 (38) hide show
  1. package/dist/chunks/{chunk-NGIJQSRE.ts → chunk-FJGNDYGC.ts} +2 -2
  2. package/dist/chunks/{chunk-QTCGWQP3.ts → chunk-QDPED3XJ.ts} +67 -8
  3. package/dist/chunks/{chunk-QTCGWQP3.ts.map → chunk-QDPED3XJ.ts.map} +3 -3
  4. package/dist/chunks/{chunk-FHNISD7A.ts → chunk-SDZCTCYQ.ts} +4 -4
  5. package/dist/chunks/{chunk-I5IG4WV4.ts → chunk-TRCSEIAQ.ts} +2 -2
  6. package/dist/chunks/{chunk-BX3K7YW7.ts → chunk-WFKUKVCP.ts} +2 -2
  7. package/dist/chunks/{chunk-UETBKTDI.ts → chunk-YDVQYUHE.ts} +1 -1
  8. package/dist/chunks/{chunk-UETBKTDI.ts.map → chunk-YDVQYUHE.ts.map} +2 -2
  9. package/dist/chunks/{conflict-review-NK5CM6UA.ts → conflict-review-JANNPKKS.ts} +4 -4
  10. package/dist/chunks/{git-backend-HLGKUQJT.ts → git-backend-FD7AVSK6.ts} +2 -2
  11. package/dist/chunks/{manager-result-dispatcher-35TM3ZR3.ts → manager-result-dispatcher-AAEAYX57.ts} +4 -4
  12. package/dist/chunks/{manager-ui-6AYMNXUP.ts → manager-ui-MHAHAKG3.ts} +7 -7
  13. package/dist/chunks/{remote-selection-ui-BB5SX6P5.ts → remote-selection-ui-Q2HUIBTL.ts} +3 -3
  14. package/dist/chunks/{s3-backend-O2AS3TH6.ts → s3-backend-AQGV6LFT.ts} +18 -4
  15. package/dist/chunks/s3-backend-AQGV6LFT.ts.map +7 -0
  16. package/dist/chunks/{sync-inspection-RLIHUYDV.ts → sync-inspection-K45QVLHB.ts} +3 -3
  17. package/dist/chunks/{sync-operations-RBUOUJWL.ts → sync-operations-Y27F5T7W.ts} +5 -5
  18. package/dist/chunks/{webdav-backend-ETQGSI6I.ts → webdav-backend-TBILVEQK.ts} +2 -2
  19. package/dist/index.ts +5 -5
  20. package/package.json +1 -1
  21. package/src/backends/s3/s3-backend.ts +22 -1
  22. package/src/backends/s3/s3-client.ts +3 -1
  23. package/src/backends/sync-backend.ts +2 -0
  24. package/src/sync/merge-transfer-error.ts +72 -0
  25. package/src/sync/merged-sync.ts +8 -5
  26. package/dist/chunks/s3-backend-O2AS3TH6.ts.map +0 -7
  27. /package/dist/chunks/{chunk-NGIJQSRE.ts.map → chunk-FJGNDYGC.ts.map} +0 -0
  28. /package/dist/chunks/{chunk-FHNISD7A.ts.map → chunk-SDZCTCYQ.ts.map} +0 -0
  29. /package/dist/chunks/{chunk-I5IG4WV4.ts.map → chunk-TRCSEIAQ.ts.map} +0 -0
  30. /package/dist/chunks/{chunk-BX3K7YW7.ts.map → chunk-WFKUKVCP.ts.map} +0 -0
  31. /package/dist/chunks/{conflict-review-NK5CM6UA.ts.map → conflict-review-JANNPKKS.ts.map} +0 -0
  32. /package/dist/chunks/{git-backend-HLGKUQJT.ts.map → git-backend-FD7AVSK6.ts.map} +0 -0
  33. /package/dist/chunks/{manager-result-dispatcher-35TM3ZR3.ts.map → manager-result-dispatcher-AAEAYX57.ts.map} +0 -0
  34. /package/dist/chunks/{manager-ui-6AYMNXUP.ts.map → manager-ui-MHAHAKG3.ts.map} +0 -0
  35. /package/dist/chunks/{remote-selection-ui-BB5SX6P5.ts.map → remote-selection-ui-Q2HUIBTL.ts.map} +0 -0
  36. /package/dist/chunks/{sync-inspection-RLIHUYDV.ts.map → sync-inspection-K45QVLHB.ts.map} +0 -0
  37. /package/dist/chunks/{sync-operations-RBUOUJWL.ts.map → sync-operations-Y27F5T7W.ts.map} +0 -0
  38. /package/dist/chunks/{webdav-backend-ETQGSI6I.ts.map → webdav-backend-TBILVEQK.ts.map} +0 -0
@@ -3,7 +3,7 @@
3
3
  import {
4
4
  runCancellableOperation,
5
5
  showRemoteSelectionReview
6
- } from "./chunk-I5IG4WV4.ts";
6
+ } from "./chunk-TRCSEIAQ.ts";
7
7
  import {
8
8
  safeTerminalText
9
9
  } from "./chunk-AMJRUXFT.ts";
@@ -206,4 +206,4 @@ async function dispatchManagerResult(ctx, initialResult, origin, runRoute, signa
206
206
  export {
207
207
  dispatchManagerResult
208
208
  };
209
- //# sourceMappingURL=chunk-NGIJQSRE.ts.map
209
+ //# sourceMappingURL=chunk-FJGNDYGC.ts.map
@@ -25,7 +25,7 @@ import {
25
25
  } from "./chunk-V6VZ5TLG.ts";
26
26
  import {
27
27
  createSyncBackend
28
- } from "./chunk-FHNISD7A.ts";
28
+ } from "./chunk-SDZCTCYQ.ts";
29
29
  import {
30
30
  applySnapshotTransaction,
31
31
  recoverPendingSnapshotTransactions,
@@ -68,7 +68,7 @@ import {
68
68
  import {
69
69
  SyncBackendConflictError,
70
70
  expectedRemoteHead
71
- } from "./chunk-UETBKTDI.ts";
71
+ } from "./chunk-YDVQYUHE.ts";
72
72
  import {
73
73
  SyncDecisionRequiredError
74
74
  } from "./chunk-7D5SF7P3.ts";
@@ -1017,6 +1017,68 @@ async function applyMergedSnapshot(before, after, protectedPaths, options, valid
1017
1017
  await acquire(0);
1018
1018
  }
1019
1019
 
1020
+ // src/sync/merge-transfer-error.ts
1021
+ var MAX_CAUSES = 4;
1022
+ var MAX_DETAIL_LENGTH = 600;
1023
+ function mergeTransferError(error, backend) {
1024
+ const messages = [];
1025
+ const seen = /* @__PURE__ */ new Set();
1026
+ let current = error;
1027
+ while (current instanceof Error && !seen.has(current) && seen.size < MAX_CAUSES) {
1028
+ seen.add(current);
1029
+ const code = current.code;
1030
+ const status = current.status;
1031
+ const metadata = [
1032
+ typeof code === "string" && /^[A-Z][A-Z0-9_]{1,63}$/u.test(code) ? code : void 0,
1033
+ typeof status === "number" && Number.isInteger(status) && status >= 100 && status <= 599 ? `HTTP ${status}` : void 0
1034
+ ].filter(Boolean);
1035
+ const message = `${current.message}${metadata.length ? ` (${metadata.join(", ")})` : ""}`;
1036
+ if (message && !messages.includes(message)) messages.push(message);
1037
+ current = current.cause;
1038
+ }
1039
+ let detail = messages.join(" \u2192 ") || "No error details available.";
1040
+ for (const secret of credentialVariants(backend)) detail = detail.replaceAll(secret, "[REDACTED]");
1041
+ detail = detail.replace(/\b(Bearer|Basic)\s+[^\s<>"']+/giu, "$1 [REDACTED]");
1042
+ detail = safeTerminalText(detail);
1043
+ if (detail.length > MAX_DETAIL_LENGTH) detail = `${detail.slice(0, MAX_DETAIL_LENGTH)}\u2026 (details truncated)`;
1044
+ return new Error(
1045
+ `Merged transfer interrupted; journal and backup retained. Run /sync sync to reconcile before further mutations. Transfer failure: ${detail}`,
1046
+ { cause: error }
1047
+ );
1048
+ }
1049
+ function credentialVariants(backend) {
1050
+ const secrets = [];
1051
+ let address;
1052
+ switch (backend.type) {
1053
+ case "s3":
1054
+ secrets.push(backend.profile.accessKeyId, backend.profile.secretAccessKey, backend.profile.sessionToken ?? "");
1055
+ address = backend.profile.endpoint;
1056
+ break;
1057
+ case "webdav":
1058
+ secrets.push(
1059
+ backend.profile.username,
1060
+ backend.profile.password,
1061
+ Buffer.from(`${backend.profile.username}:${backend.profile.password}`).toString("base64")
1062
+ );
1063
+ address = backend.profile.url;
1064
+ break;
1065
+ case "git":
1066
+ address = backend.profile.remote;
1067
+ break;
1068
+ }
1069
+ try {
1070
+ const url = new URL(address);
1071
+ secrets.push(url.username, url.password, ...url.searchParams.values());
1072
+ for (const value of [url.username, url.password]) secrets.push(decodeURIComponent(value));
1073
+ } catch {
1074
+ }
1075
+ return [
1076
+ ...new Set(
1077
+ secrets.filter(Boolean).flatMap((value) => [value, encodeURIComponent(value), JSON.stringify(value).slice(1, -1)])
1078
+ )
1079
+ ].sort((left, right) => right.length - left.length);
1080
+ }
1081
+
1020
1082
  // src/sync/partial-progress.ts
1021
1083
  function acceptedMergeFiles(decisions, localFiles, withheld) {
1022
1084
  const localByPath = new Map(localFiles.map((file) => [file.path, file]));
@@ -1559,10 +1621,7 @@ An explicit direction adopts this setup's included-content policy; no automatic
1559
1621
  if (attempt + 1 < MAX_ATTEMPTS) continue;
1560
1622
  throw new Error("Remote changed before commit in all three attempts; retry later.", { cause: error });
1561
1623
  }
1562
- throw new Error(
1563
- "Merged transfer interrupted; journal and backup retained. Run /sync sync to reconcile before further mutations.",
1564
- { cause: error }
1565
- );
1624
+ throw mergeTransferError(error, config.backend);
1566
1625
  }
1567
1626
  const completed = await completeJournal(ctx, config, backend, journal, validate, options.signal, options.auto);
1568
1627
  if (!completed) {
@@ -1605,7 +1664,7 @@ async function completeJournal(ctx, config, backend, journal, validate, signal,
1605
1664
  }
1606
1665
  const snapshotOptions = { ...snapshotOptionsForContext(ctx, config), sessionDir: sessionRoot, signal };
1607
1666
  const head = await backend.readHead(signal);
1608
- if (!journal.committedHead && head && backend.sameRevision(head.revision, journal.expectedHead.revision)) {
1667
+ if (!journal.committedHead && head && (backend.sameRevision(head.revision, journal.expectedHead.revision) || backend.matchesUncommittedRecoveryHead?.(head, journal.expectedHead))) {
1609
1668
  await validate();
1610
1669
  const local = await createSnapshot(config.snapshotIdentity, snapshotOptions);
1611
1670
  if (!sameHashes(fileHashMap(local), fileHashMap(journal.before)) || syncStateFingerprint(await readStateForConfig(config)) !== journal.stateIdentity) {
@@ -1743,4 +1802,4 @@ export {
1743
1802
  createSyncDecision,
1744
1803
  mergeSync
1745
1804
  };
1746
- //# sourceMappingURL=chunk-QTCGWQP3.ts.map
1805
+ //# sourceMappingURL=chunk-QDPED3XJ.ts.map