@narumitw/pi-sync 0.54.2 → 0.56.0

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 (194) hide show
  1. package/README.md +40 -15
  2. package/dist/chunks/agent-candidate-3JN6DJKT.ts +26 -0
  3. package/dist/chunks/agent-plan-QCUJWBP4.ts +99 -0
  4. package/dist/chunks/agent-plan-QCUJWBP4.ts.map +7 -0
  5. package/dist/chunks/agent-runner-E2JU2VZ6.ts +182 -0
  6. package/dist/chunks/agent-runner-E2JU2VZ6.ts.map +7 -0
  7. package/dist/chunks/agent-store-A3F6IYWZ.ts +152 -0
  8. package/dist/chunks/agent-store-A3F6IYWZ.ts.map +7 -0
  9. package/dist/chunks/chunk-5Q5SSKNG.ts +128 -0
  10. package/dist/chunks/chunk-5Q5SSKNG.ts.map +7 -0
  11. package/dist/chunks/chunk-5XZOC7FD.ts +215 -0
  12. package/dist/chunks/chunk-5XZOC7FD.ts.map +7 -0
  13. package/dist/chunks/{chunk-IJ6VV6FN.ts → chunk-AAEEHR7H.ts} +31 -87
  14. package/dist/chunks/chunk-AAEEHR7H.ts.map +7 -0
  15. package/dist/chunks/{chunk-CHSIAC4N.ts → chunk-B4QZBDBT.ts} +2 -2
  16. package/dist/chunks/{chunk-CL7BZRRQ.ts → chunk-CRKTAPSL.ts} +8 -8
  17. package/dist/chunks/chunk-DT7M4VQS.ts +69 -0
  18. package/dist/chunks/chunk-DT7M4VQS.ts.map +7 -0
  19. package/dist/chunks/chunk-ED3TYIVW.ts +229 -0
  20. package/dist/chunks/chunk-ED3TYIVW.ts.map +7 -0
  21. package/dist/chunks/{chunk-VHXBCEVF.ts → chunk-EUMINX7L.ts} +6 -6
  22. package/dist/chunks/chunk-FQOSHGJ7.ts +215 -0
  23. package/dist/chunks/chunk-FQOSHGJ7.ts.map +7 -0
  24. package/dist/chunks/chunk-GNH73BJ5.ts +153 -0
  25. package/dist/chunks/chunk-GNH73BJ5.ts.map +7 -0
  26. package/dist/chunks/{chunk-UQ3ALBIB.ts → chunk-GP5DU62N.ts} +8 -9
  27. package/dist/chunks/chunk-GP5DU62N.ts.map +7 -0
  28. package/dist/chunks/{chunk-5RZPINUQ.ts → chunk-GSNPASKB.ts} +2 -2
  29. package/dist/chunks/{chunk-QE7NZZWT.ts → chunk-IWZH5KYS.ts} +23 -7
  30. package/dist/chunks/chunk-IWZH5KYS.ts.map +7 -0
  31. package/dist/chunks/{chunk-5ZWQ33XL.ts → chunk-JJTARUSO.ts} +15 -14
  32. package/dist/chunks/chunk-JJTARUSO.ts.map +7 -0
  33. package/dist/chunks/{chunk-2DI6PDZV.ts → chunk-NLWS55B6.ts} +15 -2
  34. package/dist/chunks/chunk-NLWS55B6.ts.map +7 -0
  35. package/dist/chunks/{chunk-SDZCTCYQ.ts → chunk-OEWQVWLC.ts} +4 -4
  36. package/dist/chunks/{chunk-MYPSMJHJ.ts → chunk-OTZRCKYP.ts} +380 -510
  37. package/dist/chunks/chunk-OTZRCKYP.ts.map +7 -0
  38. package/dist/chunks/{chunk-WFKUKVCP.ts → chunk-OWBAZA6J.ts} +24 -12
  39. package/dist/chunks/chunk-OWBAZA6J.ts.map +7 -0
  40. package/dist/chunks/chunk-PRUEIIK7.ts +24 -0
  41. package/dist/chunks/chunk-PRUEIIK7.ts.map +7 -0
  42. package/dist/chunks/chunk-QGK445K7.ts +21 -0
  43. package/dist/chunks/chunk-QGK445K7.ts.map +7 -0
  44. package/dist/chunks/{chunk-3B4Z2SKV.ts → chunk-QO333NM4.ts} +49 -21
  45. package/dist/chunks/chunk-QO333NM4.ts.map +7 -0
  46. package/dist/chunks/{chunk-4SBTAVFL.ts → chunk-QSHMOL3I.ts} +22 -24
  47. package/dist/chunks/chunk-QSHMOL3I.ts.map +7 -0
  48. package/dist/chunks/chunk-S2FMH5FT.ts +97 -0
  49. package/dist/chunks/chunk-S2FMH5FT.ts.map +7 -0
  50. package/dist/chunks/{chunk-BVVP33U5.ts → chunk-SWRVXVFD.ts} +12 -9
  51. package/dist/chunks/chunk-SWRVXVFD.ts.map +7 -0
  52. package/dist/chunks/{chunk-ZX2Q6THB.ts → chunk-UBV24CG4.ts} +4 -5
  53. package/dist/chunks/chunk-UBV24CG4.ts.map +7 -0
  54. package/dist/chunks/chunk-UOHR7LRO.ts +70 -0
  55. package/dist/chunks/chunk-UOHR7LRO.ts.map +7 -0
  56. package/dist/chunks/{chunk-4QVPTIZB.ts → chunk-UPNVIUBN.ts} +3 -3
  57. package/dist/chunks/chunk-UZPMDLTL.ts +54 -0
  58. package/dist/chunks/chunk-UZPMDLTL.ts.map +7 -0
  59. package/dist/chunks/chunk-VJN7KU4J.ts +350 -0
  60. package/dist/chunks/chunk-VJN7KU4J.ts.map +7 -0
  61. package/dist/chunks/chunk-YHT4YTYG.ts +31 -0
  62. package/dist/chunks/chunk-YHT4YTYG.ts.map +7 -0
  63. package/dist/chunks/{chunk-V6VZ5TLG.ts → chunk-YK52VDXG.ts} +6 -5
  64. package/dist/chunks/chunk-YK52VDXG.ts.map +7 -0
  65. package/dist/chunks/config-KGIYTTXQ.ts +37 -0
  66. package/dist/chunks/{conflict-artifacts-BB2FZMIE.ts → conflict-artifacts-FXFIIBCB.ts} +8 -7
  67. package/dist/chunks/{conflict-review-4PLVLMRO.ts → conflict-review-6WIEQLXW.ts} +31 -24
  68. package/dist/chunks/{conflict-review-4PLVLMRO.ts.map → conflict-review-6WIEQLXW.ts.map} +1 -1
  69. package/dist/chunks/continuous-record-LFRVXQBD.ts +30 -0
  70. package/dist/chunks/continuous-sync-AWAAOXK2.ts +545 -0
  71. package/dist/chunks/continuous-sync-AWAAOXK2.ts.map +7 -0
  72. package/dist/chunks/{file-selection-WZX7HAY2.ts → file-selection-3JJYOVNR.ts} +5 -5
  73. package/dist/chunks/{git-backend-FD7AVSK6.ts → git-backend-KYDZ673X.ts} +28 -32
  74. package/dist/chunks/git-backend-KYDZ673X.ts.map +7 -0
  75. package/dist/chunks/{manager-result-dispatcher-6MQKFCWB.ts → manager-result-dispatcher-AGBBVDDS.ts} +10 -9
  76. package/dist/chunks/{manager-ui-IURS4WXY.ts → manager-ui-KRAW3NE2.ts} +464 -164
  77. package/dist/chunks/manager-ui-KRAW3NE2.ts.map +7 -0
  78. package/dist/chunks/{merge-baseline-store-EVQAAML6.ts → merge-baseline-store-RFCAH7KL.ts} +7 -5
  79. package/dist/chunks/{remote-selection-ui-6LJJ4IMQ.ts → remote-selection-ui-5725JDNC.ts} +9 -8
  80. package/dist/chunks/remote-selection-ui-5725JDNC.ts.map +7 -0
  81. package/dist/chunks/{s3-backend-AQGV6LFT.ts → s3-backend-Y7WSCLJI.ts} +38 -38
  82. package/dist/chunks/s3-backend-Y7WSCLJI.ts.map +7 -0
  83. package/dist/chunks/{setup-switch-KTUWL6DE.ts → setup-switch-E7PHKI6J.ts} +7 -6
  84. package/dist/chunks/setup-switch-E7PHKI6J.ts.map +7 -0
  85. package/dist/chunks/{setup-wizard-GSDPDFC4.ts → setup-wizard-65DROCIJ.ts} +14 -13
  86. package/dist/chunks/setup-wizard-65DROCIJ.ts.map +7 -0
  87. package/dist/chunks/{sync-inspection-K45QVLHB.ts → sync-inspection-XFJOAMJD.ts} +9 -8
  88. package/dist/chunks/sync-inspection-XFJOAMJD.ts.map +7 -0
  89. package/dist/chunks/{sync-operations-47OUX76C.ts → sync-operations-HDUDT5PD.ts} +188 -73
  90. package/dist/chunks/sync-operations-HDUDT5PD.ts.map +7 -0
  91. package/dist/chunks/{webdav-backend-TBILVEQK.ts → webdav-backend-6K26F6LT.ts} +39 -48
  92. package/dist/chunks/webdav-backend-6K26F6LT.ts.map +7 -0
  93. package/dist/index.ts +246 -131
  94. package/dist/index.ts.map +3 -3
  95. package/docs/agent-mode-verification.md +99 -0
  96. package/docs/continuous-sync-verification.md +87 -0
  97. package/docs/settings.md +131 -11
  98. package/docs/tui-contract.md +61 -0
  99. package/package.json +3 -2
  100. package/src/backends/git/git-backend.ts +1 -4
  101. package/src/backends/git/git-runner.ts +1 -5
  102. package/src/backends/s3/s3-backend.ts +3 -25
  103. package/src/backends/s3/s3-client.ts +14 -2
  104. package/src/backends/snapshot-pointer.ts +27 -0
  105. package/src/backends/webdav/webdav-backend.ts +3 -29
  106. package/src/backends/webdav/webdav-client.ts +11 -7
  107. package/src/commands/command-execution.ts +7 -3
  108. package/src/commands/command-handler.ts +15 -3
  109. package/src/commands/command-types.ts +10 -0
  110. package/src/commands/command.ts +4 -1
  111. package/src/settings/config.ts +20 -10
  112. package/src/settings/settings-store.ts +1 -34
  113. package/src/settings/settings-types.ts +10 -0
  114. package/src/settings/settings-validation.ts +4 -1
  115. package/src/snapshot/snapshot-codec.ts +1 -5
  116. package/src/state/lock.ts +13 -10
  117. package/src/state/merge-baseline-store.ts +19 -1
  118. package/src/state/state-directory.ts +8 -1
  119. package/src/sync/agent-candidate.ts +251 -0
  120. package/src/sync/agent-plan.ts +87 -0
  121. package/src/sync/agent-policy.ts +13 -0
  122. package/src/sync/agent-request.ts +17 -0
  123. package/src/sync/agent-runner.ts +188 -0
  124. package/src/sync/agent-store.ts +151 -0
  125. package/src/sync/agent-sync.ts +91 -0
  126. package/src/sync/apply-review.ts +63 -0
  127. package/src/sync/automatic-sync.ts +46 -33
  128. package/src/sync/continuous-errors.ts +85 -0
  129. package/src/sync/continuous-lease.ts +221 -0
  130. package/src/sync/continuous-record.ts +179 -0
  131. package/src/sync/continuous-storage.ts +55 -0
  132. package/src/sync/continuous-sync.ts +516 -0
  133. package/src/sync/continuous-watch.ts +59 -0
  134. package/src/sync/merged-sync.ts +268 -112
  135. package/src/sync/remote-snapshot.ts +2 -3
  136. package/src/sync/settings-merge.ts +19 -3
  137. package/src/sync/setup-switch.ts +1 -5
  138. package/src/sync/startup-check.ts +51 -29
  139. package/src/sync/startup-timings.ts +90 -0
  140. package/src/sync/sync-inspection.ts +16 -5
  141. package/src/sync/sync-mutations.ts +55 -28
  142. package/src/sync/sync-queries.ts +19 -3
  143. package/src/sync/text-merge.ts +3 -3
  144. package/src/sync-extension.ts +75 -19
  145. package/src/ui/agent-mode-setting.ts +91 -0
  146. package/src/ui/manager-state.ts +12 -6
  147. package/src/ui/manager-ui.ts +57 -7
  148. package/src/ui/merge-review.ts +3 -3
  149. package/src/ui/merged-sync-summary.ts +2 -18
  150. package/src/ui/remote-selection-ui.ts +5 -5
  151. package/src/ui/settings-frame.ts +55 -0
  152. package/src/ui/settings-ui.ts +223 -43
  153. package/src/ui/setup/s3-credentials-ui.ts +1 -5
  154. package/src/ui/setup/setup-name-ui.ts +2 -5
  155. package/src/ui/setup/setup-prompts.ts +4 -3
  156. package/src/ui/setup/setup-switcher.ts +2 -0
  157. package/src/ui/sync-behavior.ts +15 -0
  158. package/src/ui/sync-format.ts +69 -38
  159. package/src/ui/sync-setups-ui.ts +3 -5
  160. package/src/ui/transfer-changes.ts +33 -0
  161. package/src/ui/transfer-review.ts +27 -0
  162. package/dist/chunks/chunk-2DI6PDZV.ts.map +0 -7
  163. package/dist/chunks/chunk-3B4Z2SKV.ts.map +0 -7
  164. package/dist/chunks/chunk-4SBTAVFL.ts.map +0 -7
  165. package/dist/chunks/chunk-5ZWQ33XL.ts.map +0 -7
  166. package/dist/chunks/chunk-BVVP33U5.ts.map +0 -7
  167. package/dist/chunks/chunk-IJ6VV6FN.ts.map +0 -7
  168. package/dist/chunks/chunk-MYPSMJHJ.ts.map +0 -7
  169. package/dist/chunks/chunk-ORQRHEEO.ts +0 -362
  170. package/dist/chunks/chunk-ORQRHEEO.ts.map +0 -7
  171. package/dist/chunks/chunk-QE7NZZWT.ts.map +0 -7
  172. package/dist/chunks/chunk-UQ3ALBIB.ts.map +0 -7
  173. package/dist/chunks/chunk-V6VZ5TLG.ts.map +0 -7
  174. package/dist/chunks/chunk-WFKUKVCP.ts.map +0 -7
  175. package/dist/chunks/chunk-ZX2Q6THB.ts.map +0 -7
  176. package/dist/chunks/git-backend-FD7AVSK6.ts.map +0 -7
  177. package/dist/chunks/manager-ui-IURS4WXY.ts.map +0 -7
  178. package/dist/chunks/s3-backend-AQGV6LFT.ts.map +0 -7
  179. package/dist/chunks/setup-wizard-GSDPDFC4.ts.map +0 -7
  180. package/dist/chunks/sync-operations-47OUX76C.ts.map +0 -7
  181. package/dist/chunks/webdav-backend-TBILVEQK.ts.map +0 -7
  182. /package/dist/chunks/{conflict-artifacts-BB2FZMIE.ts.map → agent-candidate-3JN6DJKT.ts.map} +0 -0
  183. /package/dist/chunks/{chunk-CHSIAC4N.ts.map → chunk-B4QZBDBT.ts.map} +0 -0
  184. /package/dist/chunks/{chunk-CL7BZRRQ.ts.map → chunk-CRKTAPSL.ts.map} +0 -0
  185. /package/dist/chunks/{chunk-VHXBCEVF.ts.map → chunk-EUMINX7L.ts.map} +0 -0
  186. /package/dist/chunks/{chunk-5RZPINUQ.ts.map → chunk-GSNPASKB.ts.map} +0 -0
  187. /package/dist/chunks/{chunk-SDZCTCYQ.ts.map → chunk-OEWQVWLC.ts.map} +0 -0
  188. /package/dist/chunks/{chunk-4QVPTIZB.ts.map → chunk-UPNVIUBN.ts.map} +0 -0
  189. /package/dist/chunks/{manager-result-dispatcher-6MQKFCWB.ts.map → config-KGIYTTXQ.ts.map} +0 -0
  190. /package/dist/chunks/{merge-baseline-store-EVQAAML6.ts.map → conflict-artifacts-FXFIIBCB.ts.map} +0 -0
  191. /package/dist/chunks/{remote-selection-ui-6LJJ4IMQ.ts.map → continuous-record-LFRVXQBD.ts.map} +0 -0
  192. /package/dist/chunks/{file-selection-WZX7HAY2.ts.map → file-selection-3JJYOVNR.ts.map} +0 -0
  193. /package/dist/chunks/{setup-switch-KTUWL6DE.ts.map → manager-result-dispatcher-AGBBVDDS.ts.map} +0 -0
  194. /package/dist/chunks/{sync-inspection-K45QVLHB.ts.map → merge-baseline-store-RFCAH7KL.ts.map} +0 -0
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/backends/s3/s3-backend.ts", "../../src/backends/s3/s3-client.ts", "../../src/backends/s3/s3-conditions.ts"],
4
- "sourcesContent": ["import { createHash } from \"node:crypto\";\nimport { encodeKey, posixJoin } from \"../../paths.js\";\nimport { sessionTokenWarnings } from \"../../settings/config.js\";\nimport { decodeSnapshot, encodeSnapshot } from \"../../snapshot/snapshot-codec.js\";\nimport type { Snapshot } from \"../../snapshot/snapshot-types.js\";\nimport { validatePortableSnapshot } from \"../../sync/local-fields.js\";\nimport { syncErrorGuidance } from \"../../sync/sync-error-guidance.js\";\nimport { portableSnapshotSelection } from \"../../sync/sync-policy.js\";\nimport type { LatestPointer, RemoteObject, ResolvedS3Backend } from \"../backend-types.js\";\nimport {\n type BackendDiagnostic,\n type ExpectedRemoteHead,\n type PublishSnapshotOptions,\n type PublishSnapshotResult,\n type RemoteHead,\n type RemoteHistoryEntry,\n type SyncBackend,\n SyncBackendConflictError,\n SyncBackendPublicationOutcomeUnknownError,\n} from \"../sync-backend.js\";\nimport { S3Client, S3HttpError, S3ObjectAlreadyExistsError } from \"./s3-client.js\";\nimport { requireS3Etag, verifyS3Conditions } from \"./s3-conditions.js\";\n\nconst VERSION = 1;\nconst POST_COMMIT_TIMEOUT_MS = 30_000;\n\nexport class S3SyncBackend implements SyncBackend {\n readonly identity: string;\n readonly destination: string;\n readonly capability = \"conditional-required\" as const;\n private readonly checksums = new Map<string, string>();\n private recoveryHead?: { current: string; legacy: string };\n\n constructor(\n private readonly config: ResolvedS3Backend,\n private readonly postCommitTimeoutMs = POST_COMMIT_TIMEOUT_MS,\n ) {\n assertSafeDestination(config);\n this.identity = s3BackendIdentity(config);\n this.destination = s3Destination(config);\n }\n\n sameRevision(left: string, right: string) {\n return left === right;\n }\n\n matchesUncommittedRecoveryHead(current: RemoteHead, recorded: RemoteHead) {\n return (\n this.sameRevision(current.revision, recorded.revision) ||\n (current.snapshotId === recorded.snapshotId &&\n current.snapshotRef === recorded.snapshotRef &&\n current.revision === this.recoveryHead?.current &&\n recorded.revision === this.recoveryHead?.legacy)\n );\n }\n\n async readHead(signal?: AbortSignal): Promise<RemoteHead | undefined> {\n this.recoveryHead = undefined;\n const object = await new S3Client(this.config, signal).getJson<LatestPointer>(latestKey(this.config));\n throwIfAborted(signal);\n if (object.missing) return undefined;\n const pointer = requirePointer(\n object.value,\n \"Remote latest pointer is malformed.\",\n this.config.destination.namespace,\n );\n this.registerChecksum(pointer.snapshot, pointer.sha256);\n const head = remoteHead(pointer, this.identity, object.etag);\n if (object.etag && /^\"[^\"\\r\\n]+\"$/u.test(object.etag)) {\n // Old clients hashed R2's compression-weakened ETag. Bind the alias to the\n // exact current pointer and strong ETag, solely for inactive-journal retirement.\n this.recoveryHead = {\n current: head.revision,\n legacy: remoteHead(pointer, this.identity, `W/${object.etag}`).revision,\n };\n }\n return head;\n }\n\n async readSnapshot(reference: string, signal?: AbortSignal): Promise<Snapshot> {\n const expectedChecksum = this.checksums.get(reference) ?? (await this.resolveChecksum(reference, signal));\n const object = await new S3Client(this.config, signal).getBuffer(snapshotKey(this.config, reference));\n throwIfAborted(signal);\n if (!object.value) throw new Error(`Snapshot not found: ${reference}`);\n if (expectedChecksum && sha256(object.value) !== expectedChecksum) {\n throw new Error(\"Remote snapshot checksum mismatch.\");\n }\n const snapshot = await decodeSnapshot(object.value, { signal });\n if (snapshot.id !== reference || snapshot.profile !== this.config.destination.namespace) {\n throw new Error(\"Remote snapshot identity mismatch.\");\n }\n validateSnapshotBundle(snapshot);\n return snapshot;\n }\n\n async publishSnapshot(\n snapshot: Snapshot,\n expected: ExpectedRemoteHead,\n options: PublishSnapshotOptions = {},\n ): Promise<PublishSnapshotResult> {\n throwIfAborted(options.signal);\n assertSnapshotIdentity(snapshot, this.config.destination.namespace);\n await verifyS3Conditions(this.config, options.signal);\n throwIfAborted(options.signal);\n const stagedKey = snapshotKey(this.config, snapshot.id);\n const encoded = await encodeSnapshot(snapshot);\n throwIfAborted(options.signal);\n const pointer = pointerFor(this.config, snapshot, sha256(encoded));\n const cancellableClient = new S3Client(this.config, options.signal);\n try {\n await cancellableClient.putBuffer(stagedKey, encoded, \"application/gzip\", {\n ifAbsent: true,\n });\n } catch (error) {\n if (!(error instanceof S3ObjectAlreadyExistsError)) throw error;\n const existing = await cancellableClient.getBuffer(stagedKey);\n if (!existing.value || sha256(existing.value) !== pointer.sha256) {\n throw new SyncBackendConflictError(\n `Immutable snapshot id already exists with different content: ${snapshot.id}`,\n );\n }\n }\n const currentObject = await cancellableClient.getJson<LatestPointer>(latestKey(this.config));\n throwIfAborted(options.signal);\n let current: RemoteHead | undefined;\n if (!currentObject.missing) {\n const currentPointer = requirePointer(\n currentObject.value,\n \"Remote latest pointer is malformed.\",\n this.config.destination.namespace,\n );\n this.registerChecksum(currentPointer.snapshot, currentPointer.sha256);\n current = remoteHead(currentPointer, this.identity, currentObject.etag);\n }\n if (!matchesExpected(current, expected)) {\n throw new SyncBackendConflictError(\"Remote changed while pushing. Run /sync pull first, then retry.\", {\n currentHead: current,\n });\n }\n const condition = currentObject.missing ? { ifAbsent: true } : { ifMatch: requireS3Etag(currentObject.etag) };\n throwIfAborted(options.signal);\n options.onCommit?.();\n\n // The active-head PUT is the publication boundary. Do not bind it or its\n // verification to a user-cancellation signal after the boundary begins.\n const commitClient = new S3Client(this.config, AbortSignal.timeout(this.postCommitTimeoutMs));\n try {\n await commitClient.putJson(latestKey(this.config), pointer, condition);\n } catch (error) {\n if (\n error instanceof S3ObjectAlreadyExistsError ||\n (error instanceof S3HttpError && (error.status === 412 || error.status === 409))\n ) {\n throw new SyncBackendConflictError(\"Remote conditional publication was rejected; reread and retry.\", {\n cause: error,\n });\n }\n throw new SyncBackendPublicationOutcomeUnknownError(\n `Remote publication outcome is unknown: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n\n let verifiedObject: RemoteObject<LatestPointer>;\n try {\n verifiedObject = await commitClient.getJson<LatestPointer>(latestKey(this.config));\n } catch (error) {\n throw new SyncBackendPublicationOutcomeUnknownError(\n `Remote snapshot may be active, but publication could not be verified: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n let verifiedPointer: LatestPointer;\n try {\n verifiedPointer = requirePointer(\n verifiedObject.value,\n \"Remote latest pointer is malformed after publication.\",\n this.config.destination.namespace,\n );\n } catch (error) {\n throw new SyncBackendPublicationOutcomeUnknownError(\n `Remote snapshot may be active, but publication verification was malformed: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n if (!samePointer(verifiedPointer, pointer)) {\n throw new SyncBackendConflictError(\n \"Remote latest changed immediately after push. Run /sync status before continuing.\",\n {\n phase: \"after-commit\",\n currentHead: remoteHead(verifiedPointer, this.identity, verifiedObject.etag),\n candidateMayHaveBeenActive: true,\n },\n );\n }\n this.registerChecksum(verifiedPointer.snapshot, verifiedPointer.sha256);\n const head = remoteHead(verifiedPointer, this.identity, verifiedObject.etag);\n const warning = await this.updateHistorySafely(commitClient, pointer);\n return { head, warnings: warning ? [warning] : [] };\n }\n\n async listHistory(signal?: AbortSignal): Promise<RemoteHistoryEntry[]> {\n const object = await new S3Client(this.config, signal).getJson<{\n version: number;\n snapshots: LatestPointer[];\n }>(historyKey(this.config));\n throwIfAborted(signal);\n if (object.missing) return [];\n const pointers = requireHistory(object.value, this.config.destination.namespace);\n for (const pointer of pointers) {\n const known = this.checksums.get(pointer.snapshot);\n if (known && known !== pointer.sha256) {\n throw new Error(\"Remote history conflicts with an already observed snapshot checksum.\");\n }\n }\n for (const pointer of pointers) this.registerChecksum(pointer.snapshot, pointer.sha256);\n return pointers.map(remoteHistoryEntry);\n }\n\n async diagnose(signal?: AbortSignal): Promise<BackendDiagnostic[]> {\n throwIfAborted(signal);\n const diagnostics: BackendDiagnostic[] = [\n {\n key: \"s3-config\",\n level: \"info\",\n message: `s3 config: ok (${this.config.destination.bucket}/${storageRoot(this.config)})`,\n },\n ...sessionTokenWarnings(this.config.profile).map((message) => ({\n key: \"s3-session-token\",\n level: \"warning\" as const,\n message,\n })),\n ];\n const deadline = AbortSignal.timeout(10_000);\n const probeSignal = signal ? AbortSignal.any([signal, deadline]) : deadline;\n try {\n const result = await new S3Client(this.config, probeSignal).diagnoseRead(latestKey(this.config));\n throwIfAborted(probeSignal);\n const messages = {\n readable: \"s3 remote read: HTTP success. Snapshot contents and write access are not tested.\",\n \"missing-key\":\n \"s3 remote read: no snapshot at this path (NoSuchKey). Write access is not tested; verify the bucket and path before first sync.\",\n \"missing-bucket\":\n \"s3 remote read: bucket not found (NoSuchBucket). Create the bucket with your provider or edit the setup's bucket name.\",\n \"unknown-404\":\n \"s3 remote read: HTTP 404; cannot confirm whether the bucket or snapshot is missing. Verify the endpoint, bucket, and path with your provider. Write access is not tested.\",\n };\n diagnostics.push({\n key: \"s3-read\",\n level: result === \"readable\" ? \"info\" : \"warning\",\n message: messages[result],\n });\n } catch (error) {\n throwIfAborted(signal);\n diagnostics.push({\n key: \"s3-read\",\n level: \"warning\",\n message: syncErrorGuidance(deadline.aborted ? new Error(\"S3 diagnostic request timed out.\") : error),\n });\n }\n return diagnostics;\n }\n\n private async resolveChecksum(reference: string, signal?: AbortSignal) {\n await this.readHead(signal);\n const headChecksum = this.checksums.get(reference);\n if (headChecksum) return headChecksum;\n await this.listHistory(signal);\n return this.checksums.get(reference);\n }\n\n private registerChecksum(reference: string, checksum: string) {\n const known = this.checksums.get(reference);\n if (known && known !== checksum) {\n throw new Error(\"Remote snapshot reference was rebound to a different checksum.\");\n }\n this.checksums.set(reference, checksum);\n }\n\n private async updateHistorySafely(client: S3Client, pointer: LatestPointer) {\n try {\n await this.updateHistory(client, pointer);\n return undefined;\n } catch (error) {\n return `Remote snapshot is active, but history could not be updated: ${errorMessage(error)}. Run /sync doctor before relying on history.`;\n }\n }\n\n private async updateHistory(client: S3Client, pointer: LatestPointer) {\n const object = await client.getJson<{ version: number; snapshots: LatestPointer[] }>(historyKey(this.config));\n const snapshots = object.missing ? [] : requireHistory(object.value, this.config.destination.namespace);\n const existing = snapshots.find((snapshot) => snapshot.snapshot === pointer.snapshot);\n if (existing) {\n if (!samePointer(existing, pointer)) throw new Error(\"Remote history rebound an immutable snapshot reference.\");\n return;\n }\n const next = [...snapshots, pointer].slice(-100);\n const condition = object.missing ? { ifAbsent: true } : { ifMatch: requireS3Etag(object.etag) };\n await client.putJson(historyKey(this.config), { version: VERSION, snapshots: next }, condition);\n }\n}\n\nexport function latestKey(config: ResolvedS3Backend) {\n return posixJoin(storageRoot(config), \"latest.json\");\n}\n\nexport function historyKey(config: ResolvedS3Backend) {\n return posixJoin(storageRoot(config), \"history.json\");\n}\n\nexport function snapshotKey(config: ResolvedS3Backend, id: string) {\n requireSnapshotReference(id);\n return posixJoin(storageRoot(config), \"snapshots\", `${id}.json.gz`);\n}\n\nexport function storageRoot(config: ResolvedS3Backend) {\n return config.destination.prefix === \"./\" ? \"\" : config.destination.prefix;\n}\n\nexport function pointerFor(config: ResolvedS3Backend, snapshot: Snapshot, checksum: string): LatestPointer {\n return {\n version: VERSION,\n profile: config.destination.namespace,\n snapshot: snapshot.id,\n sha256: checksum,\n createdAt: snapshot.createdAt,\n machine: snapshot.machine,\n syncSessions: snapshot.syncSessions === true || snapshot.files.some((file) => file.path.startsWith(\"sessions/\")),\n ...(snapshot.selection === undefined ? {} : { selection: snapshot.selection }),\n };\n}\n\nexport function s3BackendIdentity(config: ResolvedS3Backend) {\n const destination = JSON.stringify([\n secretFreeEndpoint(config.profile.endpoint),\n trimSlashes(config.destination.bucket),\n trimSlashes(config.destination.prefix),\n ]);\n return `s3:${sha256(Buffer.from(destination))}`;\n}\n\nfunction s3Destination(config: ResolvedS3Backend) {\n let host = secretFreeEndpoint(config.profile.endpoint);\n try {\n host = new URL(host).hostname;\n } catch {\n host = \"invalid S3 endpoint\";\n }\n return `${host} \u00B7 ${config.destination.bucket}/${storageRoot(config)}`;\n}\n\nfunction secretFreeEndpoint(value: string) {\n const normalized = value.trim();\n try {\n const url = new URL(normalized);\n url.username = \"\";\n url.password = \"\";\n return url.toString();\n } catch {\n return normalized.replace(/\\/\\/[^/@\\s]+@/u, \"//\");\n }\n}\n\nfunction trimSlashes(value: string) {\n return value.replace(/^\\/+|\\/+$/g, \"\");\n}\n\nfunction remoteHistoryEntry(pointer: LatestPointer): RemoteHistoryEntry {\n return {\n snapshotRef: pointer.snapshot,\n snapshotId: pointer.snapshot,\n createdAt: pointer.createdAt,\n machine: pointer.machine,\n syncSessions: pointer.syncSessions === true,\n };\n}\n\nfunction remoteHead(pointer: LatestPointer, identity: string, etag?: string): RemoteHead {\n return {\n snapshotRef: pointer.snapshot,\n snapshotId: pointer.snapshot,\n revision: `s3:${sha256(Buffer.from(canonicalJson([identity, etag ?? null, pointer])))}`,\n createdAt: pointer.createdAt,\n machine: pointer.machine,\n syncSessions: pointer.syncSessions === true,\n ...(pointer.selection === undefined ? {} : { selection: pointer.selection }),\n };\n}\n\nfunction samePointer(left: LatestPointer, right: LatestPointer) {\n return canonicalJson(left) === canonicalJson(right);\n}\n\nfunction canonicalJson(value: unknown) {\n return JSON.stringify(canonicalValue(value));\n}\n\nfunction canonicalValue(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(canonicalValue);\n if (!value || typeof value !== \"object\") return value;\n return Object.fromEntries(\n Object.keys(value)\n .sort()\n .map((key) => [key, canonicalValue((value as Record<string, unknown>)[key])]),\n );\n}\n\nfunction matchesExpected(head: RemoteHead | undefined, expected: ExpectedRemoteHead) {\n if (expected.kind === \"missing\") return head === undefined;\n return head?.revision === expected.revision;\n}\n\nfunction requirePointer(value: LatestPointer | undefined, message: string, expectedProfile: string) {\n if (\n !value ||\n value.version !== VERSION ||\n value.profile !== expectedProfile ||\n typeof value.snapshot !== \"string\" ||\n !isSafeSnapshotReference(value.snapshot) ||\n typeof value.sha256 !== \"string\" ||\n !/^[0-9a-f]{64}$/.test(value.sha256) ||\n typeof value.createdAt !== \"string\" ||\n !isSafeMetadata(value.createdAt, 64) ||\n typeof value.machine !== \"string\" ||\n !isSafeMetadata(value.machine, 256) ||\n (value.syncSessions !== undefined && typeof value.syncSessions !== \"boolean\")\n ) {\n throw new Error(message);\n }\n if (value.selection !== undefined) portableSnapshotSelection(value.selection);\n return value;\n}\n\nfunction requireHistory(value: { version: number; snapshots: LatestPointer[] } | undefined, expectedProfile: string) {\n if (!value || value.version !== VERSION || !Array.isArray(value.snapshots)) {\n throw new Error(\"Remote history is malformed.\");\n }\n const pointers = value.snapshots.map((pointer) =>\n requirePointer(pointer, \"Remote history entry is malformed.\", expectedProfile),\n );\n const references = new Set<string>();\n for (const pointer of pointers) {\n if (references.has(pointer.snapshot)) {\n throw new Error(\"Remote history contains duplicate snapshot references.\");\n }\n references.add(pointer.snapshot);\n }\n return pointers;\n}\n\nfunction assertSnapshotIdentity(snapshot: Snapshot, expectedProfile: string) {\n validatePortableSnapshot(snapshot);\n if (\n snapshot.profile !== expectedProfile ||\n !isSafeSnapshotReference(snapshot.id) ||\n !isSafeMetadata(snapshot.createdAt, 64) ||\n !isSafeMetadata(snapshot.machine, 256) ||\n !Array.isArray(snapshot.files)\n ) {\n throw new Error(\"Invalid snapshot identity for S3 publication.\");\n }\n}\n\nfunction validateSnapshotBundle(snapshot: Snapshot) {\n const paths = new Set<string>();\n for (const file of snapshot.files) {\n if (\n !file ||\n typeof file.path !== \"string\" ||\n typeof file.contentBase64 !== \"string\" ||\n typeof file.sha256 !== \"string\" ||\n !/^[0-9a-f]{64}$/.test(file.sha256) ||\n paths.has(file.path)\n ) {\n throw new Error(\"Remote snapshot bundle is malformed.\");\n }\n const content = Buffer.from(file.contentBase64, \"base64\");\n if (content.toString(\"base64\") !== file.contentBase64 || sha256(content) !== file.sha256) {\n throw new Error(\"Remote snapshot file checksum mismatch.\");\n }\n paths.add(file.path);\n }\n}\n\nfunction assertSafeDestination(config: ResolvedS3Backend) {\n for (const [label, value, allowEmpty] of [\n [\"bucket\", config.destination.bucket, false],\n [\"prefix\", config.destination.prefix, true],\n [\"namespace\", config.destination.namespace, false],\n ] as const) {\n if (label === \"prefix\" && value === \"./\") continue;\n if (\n (!allowEmpty && value.length === 0) ||\n value.includes(\"\\\\\") ||\n hasControlCharacter(value) ||\n value.split(\"/\").some((segment) => segment === \".\" || segment === \"..\")\n ) {\n throw new Error(`Invalid S3 storage location ${label}.`);\n }\n }\n}\n\nfunction requireSnapshotReference(reference: string) {\n if (!isSafeSnapshotReference(reference)) {\n throw new Error(\"Invalid S3 snapshot reference.\");\n }\n}\n\nfunction isSafeSnapshotReference(reference: string) {\n return (\n reference.length > 0 &&\n reference.length <= 512 &&\n reference !== \".\" &&\n reference !== \"..\" &&\n !reference.includes(\"/\") &&\n !reference.includes(\"\\\\\") &&\n !hasControlCharacter(reference)\n );\n}\n\nfunction isSafeMetadata(value: string, maxLength: number) {\n return value.length > 0 && value.length <= maxLength && !hasControlCharacter(value);\n}\n\nfunction hasControlCharacter(value: string) {\n return [...value].some((character) => {\n const code = character.codePointAt(0) ?? 0;\n return code < 0x20 || code === 0x7f;\n });\n}\n\nfunction throwIfAborted(signal?: AbortSignal) {\n if (!signal?.aborted) return;\n throw signal.reason instanceof Error ? signal.reason : new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n\nfunction sha256(value: Buffer) {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport { encodeKey };\n", "import { createHash, createHmac } from \"node:crypto\";\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport { encodeKey, posixJoin } from \"../../paths.js\";\nimport type { RemoteObject, ResolvedS3Backend } from \"../backend-types.js\";\n\nconst MAX_JSON_RESPONSE_BYTES = 1024 * 1024;\nconst MAX_SNAPSHOT_RESPONSE_BYTES = 256 * 1024 * 1024;\nconst MAX_ERROR_RESPONSE_BYTES = 64 * 1024;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 30_000;\n\nfunction iso8601Basic(date: Date) {\n return date.toISOString().replace(/[:-]|\\.\\d{3}/g, \"\");\n}\n\nfunction isCloudflareR2Endpoint(endpoint: string | undefined) {\n const value = endpoint?.trim();\n if (!value) return false;\n try {\n const hostname = new URL(value).hostname.toLowerCase();\n return hostname === \"r2.cloudflarestorage.com\" || hostname.endsWith(\".r2.cloudflarestorage.com\");\n } catch {\n return false;\n }\n}\n\nexport class S3ObjectAlreadyExistsError extends Error {\n constructor(readonly key: string) {\n super(`S3 object already exists: ${key}`);\n this.name = \"S3ObjectAlreadyExistsError\";\n }\n}\n\nexport class S3HttpError extends Error {\n constructor(\n message: string,\n readonly status: number,\n ) {\n super(message);\n this.name = \"S3HttpError\";\n }\n}\n\nexport class S3Client {\n private config: ResolvedS3Backend;\n private endpoint: URL;\n private signal?: AbortSignal;\n private requestTimeoutMs: number;\n private omitSessionTokenAfterRejection = false;\n\n constructor(config: ResolvedS3Backend, signal?: AbortSignal, requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS) {\n this.config = config;\n this.endpoint = new URL(config.profile.endpoint);\n this.signal = signal;\n this.requestTimeoutMs = requestTimeoutMs;\n }\n\n /** Read-only access probe. A bare 404 cannot distinguish a missing key from a missing bucket. */\n async diagnoseRead(key: string): Promise<\"readable\" | \"missing-key\" | \"missing-bucket\" | \"unknown-404\"> {\n this.signal?.throwIfAborted();\n const response = await this.request(\"GET\", key);\n if (response.ok) {\n await response.body?.cancel();\n this.signal?.throwIfAborted();\n return \"readable\";\n }\n const detail = await this.readErrorText(response);\n this.signal?.throwIfAborted();\n if (response.status === 404) {\n const code = /<Code>\\s*([A-Za-z]+)\\s*<\\/Code>/u.exec(detail)?.[1];\n if (code === \"NoSuchBucket\") return \"missing-bucket\";\n if (code === \"NoSuchKey\") return \"missing-key\";\n return \"unknown-404\";\n }\n throw new S3HttpError(`S3 remote read failed (HTTP ${response.status}).`, response.status);\n }\n\n async getJson<T>(key: string): Promise<RemoteObject<T>> {\n const maxAttempts = 3;\n let lastError: unknown;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const object = await this.request(\"GET\", key);\n if (object.status === 404) return { missing: true };\n if (!object.ok) {\n throw new S3HttpError(`S3 GET failed (${object.status}): ${await this.readErrorText(object)}`, object.status);\n }\n const body = await readBoundedText(object, MAX_JSON_RESPONSE_BYTES, \"S3 JSON response\");\n // R2 can intermittently return an empty 200 body (read-after-write\n // inconsistency on a long-lived keep-alive connection), which makes\n // response.json() throw \"JSON Parse error: Unexpected EOF\" under Bun.\n // Retry so the transient blip is absorbed instead of surfacing as a\n // \"pi-sync auto sync skipped\" warning on every session start.\n if (body.length > 0) {\n return {\n value: JSON.parse(body) as T,\n etag: normalizeEtag(object.headers.get(\"etag\")),\n missing: false,\n };\n }\n lastError = new Error(`S3 GET returned an empty body for ${key}`);\n if (attempt < maxAttempts) {\n await sleep(250 * attempt, undefined, { signal: this.signal });\n }\n }\n throw lastError;\n }\n\n async getBuffer(key: string): Promise<RemoteObject<Buffer>> {\n const maxAttempts = 3;\n let lastError: unknown;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const object = await this.request(\"GET\", key);\n if (object.status === 404) return { missing: true };\n if (!object.ok) {\n throw new S3HttpError(`S3 GET failed (${object.status}): ${await this.readErrorText(object)}`, object.status);\n }\n const buffer = await readBoundedBuffer(object, MAX_SNAPSHOT_RESPONSE_BYTES, \"S3 snapshot response\");\n // R2 can intermittently return an empty 200 body on a long-lived\n // keep-alive connection (same root cause as the getJson retry\n // above). getBuffer is only used for snapshot .json.gz payloads,\n // which are always non-empty, so an empty body is a transient\n // blip, not a legitimate response. Retry so the checksum guard\n // downstream doesn't surface it as \"Remote snapshot checksum\n // mismatch\".\n if (buffer.length > 0) {\n return { value: buffer, etag: normalizeEtag(object.headers.get(\"etag\")), missing: false };\n }\n lastError = new Error(`S3 GET returned an empty body for ${key}`);\n if (attempt < maxAttempts) {\n await sleep(250 * attempt, undefined, { signal: this.signal });\n }\n }\n throw lastError;\n }\n\n async putJson(key: string, value: unknown, options: { ifAbsent?: boolean; ifMatch?: string } = {}) {\n const body = Buffer.from(JSON.stringify(value, null, \"\\t\"), \"utf8\");\n await this.putBuffer(key, body, \"application/json\", options);\n }\n\n async putBuffer(\n key: string,\n body: Buffer,\n contentType: string,\n options: { ifAbsent?: boolean; ifMatch?: string } = {},\n ) {\n const headers: Record<string, string> = { \"content-type\": contentType };\n if (options.ifAbsent) headers[\"if-none-match\"] = \"*\";\n if (options.ifMatch) headers[\"if-match\"] = options.ifMatch;\n const response = await this.request(\"PUT\", key, body, headers);\n if ((options.ifAbsent || options.ifMatch) && (response.status === 412 || response.status === 409)) {\n await response.body?.cancel();\n if (options.ifAbsent && response.status === 412) throw new S3ObjectAlreadyExistsError(key);\n if (options.ifAbsent || options.ifMatch) {\n throw new S3HttpError(`S3 conditional PUT rejected (${response.status}).`, response.status);\n }\n }\n if (!response.ok) {\n throw new S3HttpError(\n `S3 PUT failed (${response.status}): ${await this.readErrorText(response)}`,\n response.status,\n );\n }\n await response.body?.cancel();\n }\n\n async delete(key: string) {\n const response = await this.request(\"DELETE\", key);\n if (!response.ok && response.status !== 404) {\n throw new S3HttpError(\n `S3 DELETE failed (${response.status}): ${await this.readErrorText(response)}`,\n response.status,\n );\n }\n await response.body?.cancel();\n }\n\n private async request(\n method: \"GET\" | \"PUT\" | \"DELETE\",\n key: string,\n body?: Buffer,\n extraHeaders: Record<string, string> = {},\n ) {\n const url = new URL(this.endpoint.toString());\n url.pathname = posixJoin(url.pathname, this.config.destination.bucket, encodeKey(key));\n const send = async (sessionToken: string | undefined) => {\n const transportSignal = this.transportSignal();\n const headers = await signedHeaders({\n method,\n url,\n body,\n // Transfer compression can weaken an object's ETag (R2 JSON responses).\n // Read the original representation for exact checksums and strong If-Match tokens.\n extraHeaders: method === \"GET\" ? { ...extraHeaders, \"accept-encoding\": \"identity\" } : extraHeaders,\n accessKeyId: this.config.profile.accessKeyId,\n secretAccessKey: this.config.profile.secretAccessKey,\n sessionToken,\n region: this.config.profile.region,\n });\n try {\n return await fetch(url, {\n method,\n headers,\n body: body ? new Uint8Array(body) : undefined,\n signal: transportSignal,\n });\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") throw error;\n if (error instanceof Error && error.name === \"TimeoutError\") {\n throw new Error(\"S3 request timed out.\", { cause: error });\n }\n throw new Error(`S3 request failed: ${this.redact(errorMessage(error))}`, { cause: error });\n }\n };\n const sessionToken = this.omitSessionTokenAfterRejection ? undefined : this.config.profile.sessionToken;\n const response = await send(sessionToken);\n try {\n if (!(await this.shouldRetryWithoutSessionToken(response, sessionToken))) return response;\n } catch (error) {\n await response.body?.cancel().catch(() => undefined);\n throw error;\n }\n await response.body?.cancel();\n const retry = await send(undefined);\n if (retry.ok || retry.status === 404) this.omitSessionTokenAfterRejection = true;\n return retry;\n }\n\n private transportSignal() {\n const timeout = AbortSignal.timeout(this.requestTimeoutMs);\n return this.signal ? AbortSignal.any([this.signal, timeout]) : timeout;\n }\n\n private async shouldRetryWithoutSessionToken(response: Response, sessionToken: string | undefined) {\n if (\n !sessionToken ||\n !isCloudflareR2Endpoint(this.config.profile.endpoint) ||\n response.ok ||\n response.status !== 400\n ) {\n return false;\n }\n return isSecurityTokenInvalidArgument(\n await readBoundedText(response.clone(), MAX_ERROR_RESPONSE_BYTES, \"S3 error response\"),\n );\n }\n\n private async readErrorText(response: Response) {\n try {\n return this.redact(await readBoundedText(response, MAX_ERROR_RESPONSE_BYTES, \"S3 error response\"));\n } catch (error) {\n return this.redact(errorMessage(error));\n }\n }\n\n private redact(value: string) {\n let redacted = value;\n let endpointUsername: string | undefined;\n let endpointPassword: string | undefined;\n let endpointQueryValues: string[] = [];\n try {\n const endpoint = new URL(this.config.profile.endpoint);\n endpointUsername = endpoint.username;\n endpointPassword = endpoint.password;\n endpointQueryValues = [...endpoint.searchParams.values()];\n } catch {\n // The constructor already validates normal runtime endpoints.\n }\n for (const secret of [\n this.config.profile.accessKeyId,\n this.config.profile.secretAccessKey,\n this.config.profile.sessionToken,\n endpointUsername,\n endpointPassword,\n ...endpointQueryValues,\n ]) {\n if (secret) redacted = redacted.replaceAll(secret, \"[REDACTED]\");\n }\n return redacted;\n }\n}\n\nasync function readBoundedText(response: Response, limit: number, label: string) {\n return (await readBoundedBuffer(response, limit, label)).toString(\"utf8\");\n}\n\nasync function readBoundedBuffer(response: Response, limit: number, label: string) {\n const contentLength = Number(response.headers.get(\"content-length\"));\n if (Number.isFinite(contentLength) && contentLength > limit) {\n // Do not await cancellation of a cloned stream before its sibling can be released.\n void response.body?.cancel().catch(() => undefined);\n throw new Error(`${label} exceeds the ${limit}-byte limit.`);\n }\n if (!response.body) return Buffer.alloc(0);\n const reader = response.body.getReader();\n const chunks: Buffer[] = [];\n let total = 0;\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > limit) {\n void reader.cancel().catch(() => undefined);\n throw new Error(`${label} exceeds the ${limit}-byte limit.`);\n }\n chunks.push(Buffer.from(value));\n }\n } finally {\n reader.releaseLock();\n }\n return Buffer.concat(chunks, total);\n}\n\nfunction errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error);\n}\n\nasync function signedHeaders(input: {\n method: string;\n url: URL;\n body?: Buffer;\n extraHeaders: Record<string, string>;\n accessKeyId: string;\n secretAccessKey: string;\n sessionToken?: string;\n region: string;\n}) {\n const now = new Date();\n const amzDate = iso8601Basic(now);\n const dateStamp = amzDate.slice(0, 8);\n const payloadHash = sha256(input.body ?? Buffer.alloc(0));\n const headers: Record<string, string> = {\n ...lowercaseKeys(input.extraHeaders),\n host: input.url.host,\n \"x-amz-content-sha256\": payloadHash,\n \"x-amz-date\": amzDate,\n };\n if (input.sessionToken) headers[\"x-amz-security-token\"] = input.sessionToken;\n const signedHeaderNames = Object.keys(headers).sort();\n const canonicalHeaders = signedHeaderNames.map((name) => `${name}:${headers[name]?.trim()}\\n`).join(\"\");\n const canonicalRequest = [\n input.method,\n input.url.pathname,\n input.url.searchParams.toString(),\n canonicalHeaders,\n signedHeaderNames.join(\";\"),\n payloadHash,\n ].join(\"\\n\");\n const scope = `${dateStamp}/${input.region}/s3/aws4_request`;\n const stringToSign = [\"AWS4-HMAC-SHA256\", amzDate, scope, sha256(Buffer.from(canonicalRequest))].join(\"\\n\");\n const signingKey = hmac(\n hmac(hmac(hmac(Buffer.from(`AWS4${input.secretAccessKey}`), dateStamp), input.region), \"s3\"),\n \"aws4_request\",\n );\n const signature = createHmac(\"sha256\", signingKey).update(stringToSign).digest(\"hex\");\n return {\n ...headers,\n authorization: `AWS4-HMAC-SHA256 Credential=${input.accessKeyId}/${scope}, SignedHeaders=${signedHeaderNames.join(\";\")}, Signature=${signature}`,\n };\n}\n\nfunction hmac(key: Buffer, value: string) {\n return createHmac(\"sha256\", key).update(value).digest();\n}\n\nfunction sha256(value: Buffer) {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction lowercaseKeys(value: Record<string, string>) {\n return Object.fromEntries(Object.entries(value).map(([key, item]) => [key.toLowerCase(), item]));\n}\n\nfunction normalizeEtag(value: string | null) {\n return value ?? undefined;\n}\n\nfunction isSecurityTokenInvalidArgument(text: string) {\n return text.includes(\"<Code>InvalidArgument</Code>\") && text.includes(\"<Message>X-Amz-Security-Token</Message>\");\n}\n", "import { randomUUID } from \"node:crypto\";\nimport { posixJoin } from \"../../paths.js\";\nimport type { ResolvedS3Backend } from \"../backend-types.js\";\nimport { S3Client, S3HttpError, S3ObjectAlreadyExistsError } from \"./s3-client.js\";\n\nexport function requireS3Etag(value: string | undefined) {\n if (!value || !/^\"[^\"\\r\\n]+\"$/u.test(value)) throw new Error(\"S3 conditional publication requires a strong ETag.\");\n return value;\n}\n\n/** Never probe the active pointer or immutable snapshots; ignored conditions must not corrupt either. */\nexport async function verifyS3Conditions(config: ResolvedS3Backend, signal?: AbortSignal) {\n const key = posixJoin(\n config.destination.prefix === \"./\" ? \"\" : config.destination.prefix,\n \".pi-sync-probes\",\n randomUUID(),\n );\n const client = new S3Client(config, signal);\n let failure: unknown;\n let attempted = false;\n try {\n signal?.throwIfAborted();\n attempted = true;\n await client.putBuffer(key, Buffer.from(\"first\"), \"text/plain\", { ifAbsent: true });\n const first = await client.getBuffer(key);\n const etag = requireS3Etag(first.etag);\n if (!first.value?.equals(Buffer.from(\"first\"))) throw new Error(\"S3 conditional probe read did not match.\");\n await expectRejected(client.putBuffer(key, Buffer.from(\"ignored\"), \"text/plain\", { ifAbsent: true }));\n await expectRejected(client.putBuffer(key, Buffer.from(\"ignored\"), \"text/plain\", { ifMatch: '\"pi-sync-stale\"' }));\n const unchanged = await client.getBuffer(key);\n if (!unchanged.value?.equals(first.value) || unchanged.etag !== etag)\n throw new Error(\"S3 failed precondition changed the probe.\");\n await client.putBuffer(key, Buffer.from(\"second\"), \"text/plain\", { ifMatch: etag });\n const second = await client.getBuffer(key);\n if (!second.value?.equals(Buffer.from(\"second\")) || requireS3Etag(second.etag) === etag) {\n throw new Error(\"S3 conditional write did not rotate the probe ETag.\");\n }\n await expectRejected(client.putBuffer(key, Buffer.from(\"ignored\"), \"text/plain\", { ifMatch: etag }));\n const final = await client.getBuffer(key);\n if (!final.value?.equals(second.value) || final.etag !== second.etag)\n throw new Error(\"S3 stale ETag changed the probe.\");\n signal?.throwIfAborted();\n } catch (error) {\n failure = error;\n }\n // Cleanup has its own bounded deadline even when the owning session was cancelled.\n if (attempted) {\n try {\n await new S3Client(config, AbortSignal.timeout(10_000)).delete(key);\n } catch (error) {\n throw new Error(`S3 probe cleanup failed; remove ${key}.`, { cause: failure ?? error });\n }\n }\n if (failure) throw failure;\n signal?.throwIfAborted();\n}\n\nasync function expectRejected(operation: Promise<void>) {\n try {\n await operation;\n } catch (error) {\n // 409 is retryable contention, not proof that a failed condition was enforced.\n if (error instanceof S3ObjectAlreadyExistsError || (error instanceof S3HttpError && error.status === 412)) return;\n throw error;\n }\n throw new Error(\"S3 server ignored a write precondition; publication stopped for safety.\");\n}\n"],
5
- "mappings": "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",
6
- "names": ["createHash", "sessionToken", "sha256", "errorMessage", "createHash"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/ui/setup/setup-name-ui.ts", "../../src/ui/setup/setup-wizard.ts"],
4
- "sourcesContent": ["import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { validateConfigName } from \"../../settings/settings-validation.js\";\nimport { errorMessage } from \"../../sync/sync-errors.js\";\nimport { safeTerminalText } from \"../terminal-text.js\";\n\nexport async function promptInitialSetupName(ctx: ExtensionCommandContext, signal?: AbortSignal) {\n while (!signal?.aborted) {\n const hint = \"For example: home or work. Leave blank for default.\";\n // Pi styles the whole input title as accent; give only the guidance a muted role.\n const guidance = ctx.mode === \"tui\" ? ctx.ui.theme.fg(\"muted\", hint) : hint;\n // This compact prompt owns its default hint; the general helper would repeat it.\n const value = await ctx.ui.input(`Sync setup name\\n${guidance}`, undefined, { signal });\n if (signal?.aborted) {\n throw signal.reason instanceof Error\n ? signal.reason\n : new DOMException(\"The operation was aborted\", \"AbortError\");\n }\n if (value === undefined) return undefined;\n const name = value.trim() || \"default\";\n try {\n if (name.includes(\"<\") || name.includes(\">\")) {\n throw new Error(\"Replace example placeholders with your own name.\");\n }\n validateConfigName(name, \"sync setup\");\n return name;\n } catch (error) {\n ctx.ui.notify(\n `This name cannot be used for the sync setup. ${safeTerminalText(errorMessage(error))} Enter another name (for example, default).`,\n \"warning\",\n );\n }\n }\n return undefined;\n}\n", "import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { refreshTargetCompletions } from \"../../commands/setup-completions.js\";\nimport { localConfigPath } from \"../../settings/config-file.js\";\nimport { safeTerminalText } from \"../terminal-text.js\";\nimport { showGitSetup } from \"./git-ui.js\";\nimport { showS3Setup } from \"./s3-ui.js\";\nimport { promptInitialSetupName } from \"./setup-name-ui.js\";\nimport { showWebDavSetup } from \"./webdav-ui.js\";\n\nexport async function showSetupWizard(ctx: ExtensionCommandContext, signal?: AbortSignal) {\n if (ctx.mode !== \"tui\") {\n ctx.ui.notify(\n `Guided sync setup requires TUI mode for masked credential input. Create version 3 settings in ${safeTerminalText(localConfigPath())}.`,\n \"warning\",\n );\n return false;\n }\n const preset = await ctx.ui.select(\n \"Set up sync\\n\\nWhere will Pi settings be stored?\",\n [\"Cloudflare R2\", \"Other S3-compatible storage\", \"WebDAV\", \"Git\", \"Cancel\"],\n { signal },\n );\n if (signal?.aborted || !preset || preset === \"Cancel\") return false;\n const targetName = await promptInitialSetupName(ctx, signal);\n if (!targetName) return false;\n if (preset === \"WebDAV\") {\n const saved = await showWebDavSetup(ctx, targetName, signal);\n if (signal?.aborted) return false;\n if (saved) await refreshTargetCompletions();\n return saved;\n }\n if (preset === \"Git\") {\n const saved = await showGitSetup(ctx, targetName, signal);\n if (signal?.aborted) return false;\n if (saved) await refreshTargetCompletions();\n return saved;\n }\n return showS3Setup(ctx, preset, targetName, signal);\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,eAAsB,uBAAuB,KAA8B,QAAsB;AAC/F,SAAO,CAAC,QAAQ,SAAS;AACvB,UAAM,OAAO;AAEb,UAAM,WAAW,IAAI,SAAS,QAAQ,IAAI,GAAG,MAAM,GAAG,SAAS,IAAI,IAAI;AAEvE,UAAM,QAAQ,MAAM,IAAI,GAAG,MAAM;AAAA,EAAoB,QAAQ,IAAI,QAAW,EAAE,OAAO,CAAC;AACtF,QAAI,QAAQ,SAAS;AACnB,YAAM,OAAO,kBAAkB,QAC3B,OAAO,SACP,IAAI,aAAa,6BAA6B,YAAY;AAAA,IAChE;AACA,QAAI,UAAU,OAAW,QAAO;AAChC,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI;AACF,UAAI,KAAK,SAAS,GAAG,KAAK,KAAK,SAAS,GAAG,GAAG;AAC5C,cAAM,IAAI,MAAM,kDAAkD;AAAA,MACpE;AACA,yBAAmB,MAAM,YAAY;AACrC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,GAAG;AAAA,QACL,gDAAgD,iBAAiB,aAAa,KAAK,CAAC,CAAC;AAAA,QACrF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;;;ACxBA,eAAsB,gBAAgB,KAA8B,QAAsB;AACxF,MAAI,IAAI,SAAS,OAAO;AACtB,QAAI,GAAG;AAAA,MACL,iGAAiG,iBAAiB,gBAAgB,CAAC,CAAC;AAAA,MACpI;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,QAAM,SAAS,MAAM,IAAI,GAAG;AAAA,IAC1B;AAAA,IACA,CAAC,iBAAiB,+BAA+B,UAAU,OAAO,QAAQ;AAAA,IAC1E,EAAE,OAAO;AAAA,EACX;AACA,MAAI,QAAQ,WAAW,CAAC,UAAU,WAAW,SAAU,QAAO;AAC9D,QAAM,aAAa,MAAM,uBAAuB,KAAK,MAAM;AAC3D,MAAI,CAAC,WAAY,QAAO;AACxB,MAAI,WAAW,UAAU;AACvB,UAAM,QAAQ,MAAM,gBAAgB,KAAK,YAAY,MAAM;AAC3D,QAAI,QAAQ,QAAS,QAAO;AAC5B,QAAI,MAAO,OAAM,yBAAyB;AAC1C,WAAO;AAAA,EACT;AACA,MAAI,WAAW,OAAO;AACpB,UAAM,QAAQ,MAAM,aAAa,KAAK,YAAY,MAAM;AACxD,QAAI,QAAQ,QAAS,QAAO;AAC5B,QAAI,MAAO,OAAM,yBAAyB;AAC1C,WAAO;AAAA,EACT;AACA,SAAO,YAAY,KAAK,QAAQ,YAAY,MAAM;AACpD;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/sync/field-migration.ts", "../../src/sync/sync-mutations.ts", "../../src/sync/sync-queries.ts"],
4
- "sourcesContent": ["import type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport type { Snapshot } from \"../snapshot/snapshot-types.js\";\nimport type { SyncState } from \"../state/state-types.js\";\nimport { safeTerminalText } from \"../ui/terminal-text.js\";\nimport { sameLocalFields } from \"./local-fields.js\";\nimport { captureMutationOwner } from \"./sync-local.js\";\n\nexport async function confirmFieldMigration(\n ctx: ExtensionContext,\n config: AnySyncConfig,\n state: SyncState,\n remote: Snapshot | undefined,\n force: boolean,\n signal?: AbortSignal,\n) {\n if (remote?.localFields !== undefined && config.localFields === undefined)\n throw new Error(\n \"Portable snapshots require settings version 4 and explicit localFields rules on this machine; older policy must not replace local-only values.\",\n );\n const changed =\n (Boolean(state.lastAppliedSnapshot) && !sameLocalFields(state.localFields, config.localFields)) ||\n (remote !== undefined && !sameLocalFields(remote.localFields, config.localFields));\n if (!changed) return true;\n if (!force)\n throw new Error(\n \"Local-field policy changed; review an explicit push --force or pull --force migration. Old remote history is not erased.\",\n );\n const validate = captureMutationOwner(ctx, signal);\n if (!ctx.hasUI) throw new Error(\"Local-field migration requires observable TUI/RPC confirmation.\");\n validate();\n const confirmed = await ctx.ui.confirm(\n \"Migrate portable settings policy?\",\n `New machine-local fields: ${(config.localFields ?? []).map(safeTerminalText).join(\", \") || \"none\"}. Additions remove fields from future snapshots, not old history. Removals make local-only values portable again and a pull may replace them. The selected direction is authoritative; inspect /sync diff first. This confirmation is required even with --yes.`,\n { signal },\n );\n validate();\n return confirmed;\n}\n", "import type { ExtensionCommandContext, ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { createSyncBackend, type SyncBackendFactory } from \"../backends/backend-factory.js\";\nimport {\n expectedRemoteHead,\n type PublishSnapshotResult,\n type RemoteHead,\n type SyncBackend,\n} from \"../backends/sync-backend.js\";\nimport type { CommandOptions } from \"../commands/command-types.js\";\nimport { loadConfig, syncCheckConfigFingerprint } from \"../settings/config.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport { sessionDirForApply, snapshotOptionsForContext } from \"../snapshot/session-paths.js\";\nimport {\n createSnapshot,\n filterSnapshotForConfigPolicy,\n mergeRemotePreservedFiles,\n regenerateSnapshotIdentity,\n scanSnapshot,\n snapshotIncludesSessions,\n snapshotWithoutSessions,\n} from \"../snapshot/snapshot.js\";\nimport { applySnapshot } from \"../snapshot/snapshot-apply.js\";\nimport type { Snapshot } from \"../snapshot/snapshot-types.js\";\nimport { pruneMergeBaselines } from \"../state/merge-baseline-store.js\";\nimport type { SyncState } from \"../state/state-types.js\";\nimport { readStateForConfig, writeStateForConfig } from \"../state/sync-state-store.js\";\nimport {\n countPreservedRemoteFiles,\n formatPullSummary,\n formatPushSummary,\n formatRollbackSummary,\n} from \"../ui/sync-format.js\";\nimport { setSyncStatus } from \"../ui/sync-status.js\";\nimport { confirmFieldMigration } from \"./field-migration.js\";\nimport { overlayLocalFields, portableSnapshot, sameLocalFields, validatePortableSnapshot } from \"./local-fields.js\";\nimport { readMergeJournal, requireNoMergeJournal, retireMergeJournal } from \"./merge-journal.js\";\nimport { mergeSync } from \"./merged-sync.js\";\nimport { readRemoteSnapshot, readSnapshotForHead, requireCompatibleRemoteSelection } from \"./remote-snapshot.js\";\nimport { throwIfAborted } from \"./signals.js\";\nimport { createSyncDecision } from \"./sync-decision.js\";\nimport { errorMessage } from \"./sync-errors.js\";\n\nimport { backupLocal, captureMutationOwner, protectedSessionPaths } from \"./sync-local.js\";\nimport { inspectRemoteSelection } from \"./sync-policy.js\";\nimport {\n canPullRemoteSessionsOnFirstSync,\n canPullRemoteSettingsOnFirstSync,\n fileHashMap,\n hasLocalChanges,\n hasRemoteChanges,\n remoteChangedSinceState,\n sameHashes,\n shouldRefreshSyncedState,\n snapshotHashesMatchState,\n snapshotsMatch,\n syncPolicyChanged,\n} from \"./sync-state.js\";\n\nconst VERSION = 1;\nconst POST_LOCAL_COMMIT_TIMEOUT_MS = 30_000;\n\n/** Whole-direction acceptance must never forget withheld state without an explicit recovery choice. */\nfunction requireResolvedDirectionalProgress(state: SyncState, options: CommandOptions, allowForce = true) {\n if (state.unresolved?.length && (options.auto || !options.force || !allowForce))\n throw new Error(\n \"Unresolved partial conflicts remain. Review /sync conflicts or explicitly choose push --force or pull --force; automatic transfer and rollback cannot accept unresolved groups.\",\n );\n}\n\nexport class PublicationStatePersistenceError extends Error {\n readonly head: RemoteHead;\n readonly backupPath?: string;\n\n constructor(head: RemoteHead, cause: unknown, backupPath?: string) {\n super(\n `Remote publication ${head.snapshotId} is active, but local sync state could not be saved${backupPath ? `; local backup: ${backupPath}` : \"\"}: ${errorMessage(cause)}`,\n { cause },\n );\n this.name = \"PublicationStatePersistenceError\";\n this.head = head;\n this.backupPath = backupPath;\n }\n}\n\nexport class RollbackPublicationError extends Error {\n readonly backupPath: string;\n\n constructor(backupPath: string, cause: unknown) {\n super(`Rollback applied locally with backup ${backupPath}, but remote publication failed: ${errorMessage(cause)}`, {\n cause,\n });\n this.name = \"RollbackPublicationError\";\n this.backupPath = backupPath;\n }\n}\n\ninterface PushInput {\n config: AnySyncConfig;\n state: SyncState;\n local: Snapshot;\n backend?: SyncBackend;\n}\n\nexport async function push(\n ctx: ExtensionCommandContext | ExtensionContext,\n options: CommandOptions,\n input?: PushInput,\n factory: SyncBackendFactory = createSyncBackend,\n) {\n const validateMutation = captureMutationOwner(ctx, options.signal);\n const validateCommittedOwner = captureMutationOwner(ctx);\n const config = input?.config ?? (await loadConfig(options.setup));\n throwIfAborted(options.signal);\n await requireNoMergeJournal(config, options);\n const state = input?.state ?? (await readStateForConfig(config));\n validateMutation();\n requireResolvedDirectionalProgress(state, options);\n setSyncStatus(ctx, `pushing ${config.setupName}`);\n const backend = input?.backend ?? (await factory(config));\n throwIfAborted(options.signal);\n const localRaw =\n input?.local ?? (await createSnapshot(config.snapshotIdentity, snapshotOptionsForContext(ctx, config)));\n const local = portableSnapshot(localRaw, config.localFields);\n throwIfAborted(options.signal);\n\n let head = await backend.readHead(options.signal);\n let remoteForUpload = await readRemoteSnapshotForUpload(backend, config, head, state, options.signal);\n if (\n !options.force &&\n !remoteForUpload &&\n head?.selection &&\n inspectRemoteSelection(config.include, { selection: head.selection, files: [] }).kind === \"different\"\n ) {\n remoteForUpload = await readSnapshotForHead(backend, head, options.signal);\n }\n if (remoteForUpload && !options.force) {\n requireCompatibleRemoteSelection(config, remoteForUpload);\n }\n if (\n remoteChangedSinceState(head, state, config, (left, right) => backend.sameRevision(left, right)) &&\n !options.force\n ) {\n const remoteForConflict = remoteForUpload ? filterSnapshotForConfigPolicy(remoteForUpload, config) : undefined;\n if (!remoteForConflict || !snapshotHashesMatchState(remoteForConflict, state, config)) {\n throw createSyncDecision({\n kind: head ? \"remote-or-policy-changed\" : \"remote-empty\",\n config,\n state,\n local,\n remote: remoteForConflict,\n localChanged: hasLocalChanges(local, state, config),\n remoteChanged: true,\n directMessage: \"Remote or sync policy changed since last sync. Run /sync pull first or /sync push --force.\",\n });\n }\n }\n\n if (!remoteForUpload && head && config.localFields !== undefined)\n remoteForUpload = await readSnapshotForHead(backend, head, options.signal);\n if (!(await confirmFieldMigration(ctx, config, state, remoteForUpload, options.force, options.signal))) {\n setSyncStatus(ctx, undefined);\n return \"cancelled\" as const;\n }\n const configIdentity = syncCheckConfigFingerprint(config);\n let upload = await snapshotForUpload(backend, config, local, head, remoteForUpload, options.signal);\n if (!config.skipSecretScan) {\n const secrets = scanSnapshot(local);\n if (secrets.length > 0) {\n throw new Error(`Refusing to push possible secrets:\\n${secrets.map((s) => `- ${s}`).join(\"\\n\")}`);\n }\n }\n\n if (!(await confirmPush(ctx, options, config, backend, local, upload, head, remoteForUpload))) {\n return \"cancelled\" as const;\n }\n\n if (options.force) {\n const refreshedHead = await backend.readHead(options.signal);\n if (!sameRemoteHead(backend, head, refreshedHead)) {\n head = refreshedHead;\n remoteForUpload = head ? await readSnapshotForHead(backend, head, options.signal) : undefined;\n validateMutation();\n if (!(await confirmFieldMigration(ctx, config, state, remoteForUpload, options.force, options.signal))) {\n setSyncStatus(ctx, undefined);\n return \"cancelled\" as const;\n }\n validateMutation();\n upload = await snapshotForUpload(backend, config, local, head, remoteForUpload, options.signal);\n if (\n !(await confirmPush(\n ctx,\n options,\n config,\n backend,\n local,\n upload,\n head,\n remoteForUpload,\n \"Remote changed during review. Push the refreshed plan?\",\n ))\n ) {\n return \"cancelled\" as const;\n }\n }\n }\n\n validateMutation();\n if (configIdentity !== syncCheckConfigFingerprint(await loadConfig(options.setup)))\n throw new Error(\"Settings changed during push review.\");\n validateMutation();\n if (config.localFields !== undefined || (await readMergeJournal(config))) {\n const current = await createSnapshot(config.snapshotIdentity, snapshotOptionsForContext(ctx, config));\n if (!sameHashes(fileHashMap(current), fileHashMap(localRaw)))\n throw new Error(\"Local content changed during recovery review; retry from current bytes.\");\n }\n requireResolvedDirectionalProgress(await readStateForConfig(config), options);\n validateMutation();\n const result = await backend.publishSnapshot(upload, expectedRemoteHead(head), {\n signal: options.signal,\n onCommit: options.onCommit,\n });\n try {\n await writeStateForConfig(\n config,\n {\n version: VERSION,\n profile: config.snapshotIdentity,\n lastAppliedSnapshot: result.head.snapshotId,\n lastRemoteRevision: result.head.revision,\n lastFileHashes: fileHashMap(local),\n include: [...config.include],\n ...(config.localFields !== undefined ? { localFields: config.localFields } : {}),\n },\n local,\n validateCommittedOwner,\n );\n } catch (error) {\n throw new PublicationStatePersistenceError(result.head, error);\n }\n await retireMergeJournal(config);\n await pruneMergeBaselines(config, await readStateForConfig(config), validateCommittedOwner);\n validateCommittedOwner();\n if (options.signal?.aborted) return;\n setSyncStatus(ctx, undefined);\n if (!options.silent) {\n ctx.ui.notify(\n [\n `Pushed ${upload.files.length} files from sync setup \u201C${config.setupName}\u201D as ${result.head.snapshotId}.`,\n ...result.warnings,\n ]\n .filter(Boolean)\n .join(\"\\n\"),\n result.warnings.length > 0 ? \"warning\" : \"info\",\n );\n }\n return \"applied\" as const;\n}\n\nexport async function pull(\n ctx: ExtensionCommandContext | ExtensionContext,\n options: CommandOptions,\n factory: SyncBackendFactory = createSyncBackend,\n) {\n const validateMutation = captureMutationOwner(ctx, options.signal);\n const validateCommittedOwner = captureMutationOwner(ctx);\n const config = await loadConfig(options.setup);\n throwIfAborted(options.signal);\n await requireNoMergeJournal(config, options);\n setSyncStatus(ctx, `pulling ${config.setupName}`);\n const backend = await factory(config);\n const state = await readStateForConfig(config);\n validateMutation();\n requireResolvedDirectionalProgress(state, options);\n const local = await createSnapshot(config.snapshotIdentity, snapshotOptionsForContext(ctx, config));\n throwIfAborted(options.signal);\n const { head, snapshot: remote } = await readRemoteSnapshot(backend, config, options.signal);\n throwIfAborted(options.signal);\n const localChanged = hasLocalChanges(local, state, config);\n if (!remote) {\n throw createSyncDecision({\n kind: \"remote-empty\",\n config,\n state,\n local,\n localChanged,\n remoteChanged: false,\n directMessage: \"Remote is empty. Run /sync push from a configured machine first.\",\n });\n }\n\n if (!sameLocalFields(config.localFields, remote.localFields)) {\n setSyncStatus(ctx, undefined);\n throw new Error(\n \"Pull requires the configured local-field policy to match the remote. To change the remote policy, review push --force from the authoritative machine first, then pull using matching rules; old history is not erased.\",\n );\n }\n if (!(await confirmFieldMigration(ctx, config, state, remote, options.force, options.signal))) {\n setSyncStatus(ctx, undefined);\n return \"cancelled\" as const;\n }\n const configIdentity = syncCheckConfigFingerprint(config);\n const logical = portableSnapshot(remote, config.localFields);\n const physical = overlayLocalFields(logical, local, config.localFields);\n const remoteChanged = hasRemoteChanges(remote, state, config, protectedSessionPaths(ctx));\n if (localChanged && remoteChanged && state.lastAppliedSnapshot && !options.force) {\n throw createSyncDecision({\n kind: \"both-changed\",\n config,\n state,\n local,\n remote,\n localChanged,\n remoteChanged,\n directMessage:\n \"Both local and remote changed since last sync. Run /sync diff, then choose /sync pull --force or /sync push --force.\",\n });\n }\n\n if (\n !options.yes &&\n !(await ctx.ui.confirm(\n snapshotIncludesSessions(remote) ? \"Pull pi settings and sessions?\" : \"Pull pi settings?\",\n formatPullSummary(config, backend.destination, local, physical, protectedSessionPaths(ctx).size),\n ))\n ) {\n setSyncStatus(ctx, undefined);\n ctx.ui.notify(\"Pull cancelled.\", \"info\");\n return \"cancelled\" as const;\n }\n\n throwIfAborted(options.signal);\n const recoveringMerge = Boolean(await readMergeJournal(config));\n const requireFreshRecovery = async () => {\n validateMutation();\n const currentHead = await backend.readHead(options.signal);\n validateMutation();\n const current = await createSnapshot(config.snapshotIdentity, snapshotOptionsForContext(ctx, config));\n validateMutation();\n if (!sameHashes(fileHashMap(current), fileHashMap(local)) || !sameRemoteHead(backend, head, currentHead)) {\n throw new Error(\"Local or remote content changed during recovery review; retry from a fresh diff.\");\n }\n };\n if (recoveringMerge) await requireFreshRecovery();\n if (configIdentity !== syncCheckConfigFingerprint(await loadConfig(options.setup)))\n throw new Error(\"Settings changed during pull review.\");\n validateMutation();\n const refreshed = await createSnapshot(config.snapshotIdentity, snapshotOptionsForContext(ctx, config));\n if (!sameHashes(fileHashMap(local), fileHashMap(refreshed)))\n throw new Error(\"Local bytes changed during pull review.\");\n if (!sameRemoteHead(backend, head, await backend.readHead(options.signal)))\n throw new Error(\"Remote changed during pull review.\");\n validateMutation();\n const backup = await backupLocal(config.snapshotIdentity, snapshotOptionsForContext(ctx, config), options.signal);\n const applySessionDir = await sessionDirForApply(ctx, physical);\n if (recoveringMerge) await requireFreshRecovery();\n requireResolvedDirectionalProgress(await readStateForConfig(config), options);\n validateMutation();\n options.onCommit?.();\n const lastFileHashes = await applySnapshot(physical, protectedSessionPaths(ctx), {\n include: config.include,\n sessionDir: applySessionDir,\n signal: options.signal,\n validateMutation,\n expectedFileHashes: config.localFields?.length\n ? { \"settings.json\": fileHashMap(local)[\"settings.json\"] ?? null }\n : undefined,\n });\n // Local installation is complete; user cancellation must not leave the baseline stale.\n validateCommittedOwner();\n await writeStateForConfig(\n config,\n {\n version: VERSION,\n profile: config.snapshotIdentity,\n lastAppliedSnapshot: remote.id,\n lastRemoteRevision: head?.revision,\n lastFileHashes: config.localFields?.length\n ? { ...lastFileHashes, \"settings.json\": fileHashMap(logical)[\"settings.json\"] }\n : lastFileHashes,\n include: [...config.include],\n ...(config.localFields !== undefined ? { localFields: config.localFields } : {}),\n },\n logical,\n validateCommittedOwner,\n );\n await retireMergeJournal(config);\n await pruneMergeBaselines(config, await readStateForConfig(config), validateCommittedOwner);\n validateCommittedOwner();\n if (options.signal?.aborted) return \"applied\" as const;\n setSyncStatus(ctx, undefined);\n if (!options.silent) {\n ctx.ui.notify(`Pulled ${remote.files.length} files from ${remote.id}. Backup: ${backup}`, \"info\");\n } else if (options.auto && config.include.includes(\"sessions\") && snapshotIncludesSessions(remote)) {\n ctx.ui.notify(\n \"Pulled Pi sessions after startup selected the current session. Restart Pi or resume a pulled session to use newly synced conversations.\",\n \"warning\",\n );\n }\n if (options.reload) await maybeReload(ctx, options.signal, validateMutation);\n return \"applied\" as const;\n}\n\nexport async function syncBoth(\n ctx: ExtensionCommandContext | ExtensionContext,\n options: CommandOptions,\n factory: SyncBackendFactory = createSyncBackend,\n) {\n const validateMutation = captureMutationOwner(ctx, options.signal);\n const config = await loadConfig(options.setup);\n throwIfAborted(options.signal);\n if (config.include.length > 0 && options.auto && config.automaticTransfer) return mergeSync(ctx, options, factory);\n if (!options.auto && config.include.length > 0 && (await readMergeJournal(config)))\n return mergeSync(ctx, options, factory);\n const state = await readStateForConfig(config);\n throwIfAborted(options.signal);\n if (!options.auto && config.include.length > 0 && state.lastAppliedSnapshot) return mergeSync(ctx, options, factory);\n const backend = await factory(config);\n const local = await createSnapshot(config.snapshotIdentity, snapshotOptionsForContext(ctx, config));\n throwIfAborted(options.signal);\n if (config.include.length === 0) {\n if (!options.silent) {\n ctx.ui.notify(\n `Sync setup \u201C${config.setupName}\u201D includes no files. Choose included content in /sync Settings before syncing.`,\n \"warning\",\n );\n }\n return;\n }\n const { head, snapshot: remote } = await readRemoteSnapshot(backend, config, options.signal);\n throwIfAborted(options.signal);\n const localChanged = hasLocalChanges(local, state, config);\n const remoteChanged = remote ? hasRemoteChanges(remote, state, config, protectedSessionPaths(ctx)) : false;\n const firstSync = !state.lastAppliedSnapshot;\n if (options.auto) throw new Error(\"Automatic transfer is not authorized by the current settings.\");\n\n const portableLocal = portableSnapshot(local, config.localFields);\n const acceptMatchingState = async (snapshot: Snapshot) => {\n requireCompatibleRemoteSelection(config, snapshot);\n const accepted = portableSnapshot(snapshot, config.localFields);\n if (state.lastAppliedSnapshot && !sameLocalFields(state.localFields, config.localFields))\n throw new Error(\"Local-field rules changed; review and confirm a directional migration first.\");\n await writeStateForConfig(\n config,\n {\n version: VERSION,\n profile: config.snapshotIdentity,\n lastAppliedSnapshot: snapshot.id,\n lastRemoteRevision: head?.revision,\n lastFileHashes: fileHashMap(accepted),\n include: [...config.include],\n ...(config.localFields !== undefined ? { localFields: config.localFields } : {}),\n },\n accepted,\n validateMutation,\n );\n await pruneMergeBaselines(config, await readStateForConfig(config), validateMutation);\n validateMutation();\n };\n if (firstSync && remote && remote.files.length > 0 && local.files.length > 0) {\n requireCompatibleRemoteSelection(config, remote);\n const portableRemote = portableSnapshot(remote, config.localFields);\n if (!canPullRemoteSettingsOnFirstSync(portableLocal, portableRemote)) {\n throw createSyncDecision({\n kind: \"first-sync-settings-diverged\",\n config,\n state,\n local,\n remote,\n localChanged: true,\n remoteChanged: true,\n directMessage:\n \"Remote settings exist and this machine has different local Pi settings. Run /sync diff, then manually choose /sync pull or /sync push.\",\n });\n }\n if (!sameHashes(fileHashMap(portableLocal), fileHashMap(portableRemote))) {\n if (!canPullRemoteSessionsOnFirstSync(portableLocal, portableRemote)) {\n throw createSyncDecision({\n kind: \"first-sync-sessions-diverged\",\n config,\n state,\n local,\n remote,\n localChanged: true,\n remoteChanged: true,\n directMessage:\n \"Remote settings match, but local and remote Pi sessions differ. Run /sync diff, then manually choose /sync pull or /sync push.\",\n });\n }\n await pull(ctx, options, factory);\n return;\n }\n await acceptMatchingState(remote);\n if (!options.silent) ctx.ui.notify(\"pi-sync state initialized; local settings already match remote.\", \"info\");\n return;\n }\n if (\n localChanged &&\n remoteChanged &&\n remote &&\n snapshotsMatch(portableLocal, portableSnapshot(remote, remote.localFields))\n ) {\n requireCompatibleRemoteSelection(config, remote);\n await acceptMatchingState(remote);\n if (!options.silent) ctx.ui.notify(\"pi-sync is already up to date.\", \"info\");\n return;\n }\n if (localChanged && remoteChanged && state.lastAppliedSnapshot) {\n throw createSyncDecision({\n kind: \"both-changed\",\n config,\n state,\n local,\n remote,\n localChanged,\n remoteChanged,\n directMessage: \"Both local and remote changed. Run /sync diff and resolve with push --force or pull --force.\",\n });\n }\n if (remoteChanged) {\n await pull(ctx, options, factory);\n return;\n }\n if (localChanged || !remote) {\n await push(ctx, options, undefined, factory);\n return;\n }\n if (shouldRefreshSyncedState(remote, head, state, config, (left, right) => backend.sameRevision(left, right))) {\n await acceptMatchingState(remote);\n }\n if (!options.silent) ctx.ui.notify(\"pi-sync is already up to date.\", \"info\");\n}\n\nexport async function rollback(\n ctx: ExtensionCommandContext,\n options: CommandOptions,\n factory: SyncBackendFactory = createSyncBackend,\n expectedSelection?: { backendIdentity: string; setup?: string },\n) {\n const validateMutation = captureMutationOwner(ctx, options.signal);\n const validateCommittedOwner = captureMutationOwner(ctx);\n const target = options.args[0];\n if (!target) throw new Error(\"Usage: /sync rollback <snapshot-id> [--yes]\");\n\n const config = await loadConfig(options.setup);\n throwIfAborted(options.signal);\n const backend = await factory(config);\n if (\n expectedSelection &&\n (backend.identity !== expectedSelection.backendIdentity || config.setupName !== expectedSelection.setup)\n ) {\n throw new Error(\"Sync setup or storage location changed while history was open; reopen history and retry.\");\n }\n // --force is only a rollback compatibility flag, not a reviewed merge-recovery direction.\n await requireNoMergeJournal(config);\n const state = await readStateForConfig(config);\n validateMutation();\n requireResolvedDirectionalProgress(state, options, false);\n const decoded = await backend.readSnapshot(target, options.signal);\n validatePortableSnapshot(decoded);\n if (!sameLocalFields(decoded.localFields, config.localFields))\n throw new Error(\n \"Rollback requires the historical snapshot local-field policy to match the configured rules. Review push --force from current local bytes to migrate policy first; choose matching history afterward.\",\n );\n const selected = filterSnapshotForConfigPolicy(\n config.include.includes(\"sessions\") ? decoded : snapshotWithoutSessions(decoded),\n config,\n );\n const remote = portableSnapshot(regenerateSnapshotIdentity(selected), config.localFields);\n const local = await createSnapshot(config.snapshotIdentity, snapshotOptionsForContext(ctx, config));\n const expectedHead = await backend.readHead(options.signal);\n const currentRemote = expectedHead ? await readSnapshotForHead(backend, expectedHead, options.signal) : undefined;\n validateMutation();\n if (!(await confirmFieldMigration(ctx, config, state, currentRemote, true, options.signal))) return;\n validateMutation();\n const physical = overlayLocalFields(remote, local, config.localFields);\n\n if (!options.yes) {\n const confirmed = await ctx.ui.confirm(\n snapshotIncludesSessions(remote) ? \"Rollback pi settings and sessions?\" : \"Rollback pi settings?\",\n formatRollbackSummary(config, backend.destination, local, physical, target, protectedSessionPaths(ctx).size),\n { signal: options.signal },\n );\n validateMutation();\n if (!confirmed) {\n ctx.ui.notify(\"Rollback cancelled.\", \"info\");\n return;\n }\n }\n\n validateMutation();\n const currentLocal = await createSnapshot(config.snapshotIdentity, snapshotOptionsForContext(ctx, config));\n if (!sameHashes(fileHashMap(currentLocal), fileHashMap(local)))\n throw new Error(\"Local bytes changed during rollback review.\");\n if (syncCheckConfigFingerprint(config) !== syncCheckConfigFingerprint(await loadConfig(options.setup)))\n throw new Error(\"Settings changed during rollback review.\");\n if (!sameRemoteHead(backend, expectedHead, await backend.readHead(options.signal)))\n throw new Error(\"Remote changed during rollback review.\");\n validateMutation();\n throwIfAborted(options.signal);\n const backup = await backupLocal(config.snapshotIdentity, snapshotOptionsForContext(ctx, config), options.signal);\n const applySessionDir = await sessionDirForApply(ctx, remote);\n requireResolvedDirectionalProgress(await readStateForConfig(config), options, false);\n validateMutation();\n options.onCommit?.();\n const lastFileHashes = await applySnapshot(physical, protectedSessionPaths(ctx), {\n include: config.include,\n sessionDir: applySessionDir,\n signal: options.signal,\n validateMutation,\n expectedFileHashes: config.localFields?.length\n ? { \"settings.json\": fileHashMap(local)[\"settings.json\"] ?? null }\n : undefined,\n });\n // The local transaction is retired; finish publication despite caller cancellation.\n validateCommittedOwner();\n let result: PublishSnapshotResult;\n try {\n const completionSignal = AbortSignal.timeout(POST_LOCAL_COMMIT_TIMEOUT_MS);\n const upload = await snapshotForUpload(backend, config, remote, expectedHead, currentRemote, completionSignal);\n validateCommittedOwner();\n result = await backend.publishSnapshot(upload, expectedRemoteHead(expectedHead), {\n signal: completionSignal,\n });\n } catch (error) {\n throw new RollbackPublicationError(backup, error);\n }\n try {\n await writeStateForConfig(\n config,\n {\n version: VERSION,\n profile: config.snapshotIdentity,\n lastAppliedSnapshot: result.head.snapshotId,\n lastRemoteRevision: result.head.revision,\n lastFileHashes: config.localFields?.length\n ? { ...lastFileHashes, \"settings.json\": fileHashMap(remote)[\"settings.json\"] }\n : lastFileHashes,\n include: [...config.include],\n ...(config.localFields !== undefined ? { localFields: config.localFields } : {}),\n },\n remote,\n validateCommittedOwner,\n );\n } catch (error) {\n throw new PublicationStatePersistenceError(result.head, error, backup);\n }\n await retireMergeJournal(config);\n await pruneMergeBaselines(config, await readStateForConfig(config), validateCommittedOwner);\n validateCommittedOwner();\n if (options.signal?.aborted) return;\n ctx.ui.notify(\n [\n `Rolled back sync setup \u201C${config.setupName}\u201D to ${target}; latest: ${result.head.snapshotId}. Backup: ${backup}`,\n ...result.warnings,\n ]\n .filter(Boolean)\n .join(\"\\n\"),\n result.warnings.length > 0 ? \"warning\" : \"info\",\n );\n await maybeReload(ctx, options.signal, validateMutation);\n}\n\nasync function maybeReload(\n ctx: ExtensionCommandContext | ExtensionContext,\n signal?: AbortSignal,\n validateMutation = captureMutationOwner(ctx, signal),\n) {\n if (signal?.aborted || !(\"reload\" in ctx)) return;\n validateMutation();\n if (\n ctx.hasUI &&\n (await ctx.ui.confirm(\n \"Reload Pi resources now?\",\n \"This reloads extensions, skills, prompts, themes, and context files.\",\n ))\n ) {\n if (signal?.aborted) return;\n validateMutation();\n await ctx.reload();\n }\n}\n\nasync function readRemoteSnapshotForUpload(\n backend: SyncBackend,\n config: AnySyncConfig,\n head: RemoteHead | undefined,\n state: SyncState,\n signal?: AbortSignal,\n) {\n if (\n !head ||\n (head.snapshotId === state.lastAppliedSnapshot &&\n !syncPolicyChanged(state, config) &&\n (!state.lastRemoteRevision || backend.sameRevision(head.revision, state.lastRemoteRevision)))\n ) {\n return undefined;\n }\n return readSnapshotForHead(backend, head, signal);\n}\n\nasync function snapshotForUpload(\n backend: SyncBackend,\n config: AnySyncConfig,\n local: Snapshot,\n head: RemoteHead | undefined,\n remote?: Snapshot,\n signal?: AbortSignal,\n) {\n if (!head) return local;\n const snapshot = remote ?? (await readSnapshotForHead(backend, head, signal));\n return mergeRemotePreservedFiles(local, snapshot, config);\n}\n\nasync function confirmPush(\n ctx: ExtensionCommandContext | ExtensionContext,\n options: CommandOptions,\n config: AnySyncConfig,\n backend: SyncBackend,\n local: Snapshot,\n upload: Snapshot,\n head: RemoteHead | undefined,\n remote: Snapshot | undefined,\n title = snapshotIncludesSessions(upload) ? \"Push pi settings and sessions?\" : \"Push pi settings?\",\n) {\n throwIfAborted(options.signal);\n if (options.yes) return true;\n const confirmed = await ctx.ui.confirm(\n title,\n formatPushSummary(config, backend.destination, upload, head, countPreservedRemoteFiles(local, upload), remote),\n );\n throwIfAborted(options.signal);\n if (confirmed) return true;\n setSyncStatus(ctx, undefined);\n ctx.ui.notify(\"Push cancelled.\", \"info\");\n return false;\n}\n\nfunction sameRemoteHead(backend: SyncBackend, left: RemoteHead | undefined, right: RemoteHead | undefined) {\n if (!left || !right) return left === right;\n return backend.sameRevision(left.revision, right.revision);\n}\n\nexport { backupLocal } from \"./sync-local.js\";\n", "import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { createSyncBackend, type SyncBackendFactory } from \"../backends/backend-factory.js\";\nimport type { SyncBackend } from \"../backends/sync-backend.js\";\nimport type { CommandOptions } from \"../commands/command-types.js\";\nimport { loadConfig, syncSessionsWarnings } from \"../settings/config.js\";\nimport { snapshotOptionsForContext } from \"../snapshot/session-paths.js\";\nimport { createSnapshot, scanSnapshot } from \"../snapshot/snapshot.js\";\nimport type { SnapshotOptions } from \"../snapshot/snapshot-types.js\";\nimport { inspectLock, isLockGuardHeld, isStaleLock, withLock } from \"../state/lock.js\";\nimport { formatDiff, formatSnapshotOnlyDiff, publicationCapabilityDescription } from \"../ui/sync-format.js\";\nimport { setSyncStatus } from \"../ui/sync-status.js\";\nimport { safeTerminalText } from \"../ui/terminal-text.js\";\nimport { portableSnapshot } from \"./local-fields.js\";\nimport { formatRemoteSelectionStatus, readRemoteSnapshot } from \"./remote-snapshot.js\";\nimport { throwIfAborted } from \"./signals.js\";\nimport { errorMessage } from \"./sync-errors.js\";\nimport { inspectSync } from \"./sync-inspection.js\";\nimport { rollback } from \"./sync-mutations.js\";\n\nconst DEFAULT_PROFILE = \"default\";\n\nexport async function status(\n ctx: ExtensionCommandContext,\n options: CommandOptions,\n factory: SyncBackendFactory = createSyncBackend,\n) {\n const config = await loadConfig(options.setup);\n throwIfAborted(options.signal);\n setSyncStatus(ctx, `checking ${config.setupName}`);\n const { head, selectionState, localChanged, remoteChanged, localFiles, destination, capability } = await inspectSync(\n config,\n snapshotOptionsForContext(ctx, config),\n options.signal,\n factory,\n );\n throwIfAborted(options.signal);\n\n const remoteText = head ? `remote: ${head.snapshotId} from ${head.machine} at ${head.createdAt}` : \"remote: empty\";\n const warnings = syncSessionsWarnings(config);\n setSyncStatus(ctx, undefined);\n ctx.ui.notify(\n [\n `sync setup: ${config.setupName}`,\n `storage connection: ${config.connectionName}`,\n `storage location: ${safeTerminalText(destination)}`,\n `publication safety: ${publicationCapabilityDescription(capability)}`,\n `included content: ${config.include.join(\", \") || \"none\"}`,\n `sessions: ${config.include.includes(\"sessions\") ? \"included\" : \"excluded\"}`,\n remoteText,\n formatRemoteSelectionStatus(selectionState),\n `local files: ${localFiles}`,\n `local changed since last sync: ${localChanged ? \"yes\" : \"no\"}`,\n `remote changed since last sync: ${remoteChanged ? \"yes\" : \"no\"}`,\n ...warnings,\n ].join(\"\\n\"),\n localChanged || remoteChanged || selectionState?.kind === \"different\" || warnings.length > 0 ? \"warning\" : \"info\",\n );\n}\n\nexport async function diff(\n ctx: ExtensionCommandContext,\n options: CommandOptions,\n factory: SyncBackendFactory = createSyncBackend,\n) {\n const config = await loadConfig(options.setup);\n throwIfAborted(options.signal);\n setSyncStatus(ctx, `checking ${config.setupName}`);\n const backend = await factory(config);\n const local = portableSnapshot(\n await createSnapshot(config.snapshotIdentity, snapshotOptionsForContext(ctx, config)),\n config.localFields,\n );\n throwIfAborted(options.signal);\n const { snapshot: remote, selectionState } = await readRemoteSnapshot(backend, config, options.signal, {\n allowSelectionDifference: true,\n });\n throwIfAborted(options.signal);\n setSyncStatus(ctx, undefined);\n\n const warnings = syncSessionsWarnings(config);\n const header = [\n `sync setup: ${config.setupName}`,\n `storage connection: ${config.connectionName}`,\n `storage location: ${safeTerminalText(backend.destination)}`,\n `included content: ${config.include.join(\", \") || \"none\"}`,\n `sessions: ${config.include.includes(\"sessions\") ? \"included\" : \"excluded\"}`,\n formatRemoteSelectionStatus(selectionState),\n ...warnings,\n ].join(\"\\n\");\n const level = warnings.length > 0 || selectionState?.kind === \"different\" ? \"warning\" : \"info\";\n if (!remote) {\n ctx.ui.notify(`${header}\\n\\n${formatSnapshotOnlyDiff(\"Remote is empty. Local push would upload\", local)}`, level);\n return;\n }\n\n ctx.ui.notify(`${header}\\n\\n${formatDiff(local, portableSnapshot(remote, remote.localFields))}`, level);\n}\n\nexport async function doctor(\n ctx: ExtensionCommandContext,\n options: CommandOptions,\n factory: SyncBackendFactory = createSyncBackend,\n) {\n const messages: string[] = [];\n let level: \"info\" | \"warning\" = \"info\";\n let snapshotOptions: SnapshotOptions = {};\n let profile = DEFAULT_PROFILE;\n let backend: SyncBackend | undefined;\n let backendSummary: string[] = [];\n\n try {\n const config = await loadConfig(options.setup);\n throwIfAborted(options.signal);\n backend = await factory(config);\n profile = config.snapshotIdentity;\n snapshotOptions = snapshotOptionsForContext(ctx, config);\n messages.push(\n `config: ok (sync setup ${config.setupName})`,\n `included content: ${config.include.join(\", \") || \"none\"}`,\n `sessions: ${config.include.includes(\"sessions\") ? \"included\" : \"excluded\"}`,\n );\n backendSummary = [\n `storage location: ${safeTerminalText(backend.destination)}`,\n `publication safety: ${publicationCapabilityDescription(backend.capability)}`,\n ];\n const warnings = syncSessionsWarnings(config);\n if (warnings.length > 0) {\n level = \"warning\";\n messages.push(...warnings);\n }\n } catch (error) {\n throwIfAborted(options.signal);\n level = \"warning\";\n messages.push(`config: ${errorMessage(error)}`);\n }\n\n const local = await createSnapshot(profile, snapshotOptions);\n throwIfAborted(options.signal);\n const secrets = scanSnapshot(local);\n if (secrets.length > 0) {\n level = \"warning\";\n messages.push(\"secret scan: possible secrets found:\");\n messages.push(...secrets.map((secret) => `- ${secret}`));\n } else {\n messages.push(`secret scan: ok (${local.files.length} files checked)`);\n }\n\n const lock = await inspectLock();\n throwIfAborted(options.signal);\n if (lock.status === \"valid\" && isStaleLock(lock.lock)) {\n level = \"warning\";\n messages.push(`lock: stale (pid ${lock.lock.pid}); run /sync unlock --stale after verifying no sync is running`);\n } else if (lock.status === \"valid\") {\n messages.push(`lock: held by pid ${lock.lock.pid} since ${lock.lock.startedAt}`);\n } else if (lock.status === \"unreadable\") {\n level = \"warning\";\n messages.push(\"lock: unreadable; use /sync unlock --stale only after verifying no sync is running\");\n } else if (await isLockGuardHeld()) {\n throwIfAborted(options.signal);\n level = \"warning\";\n messages.push(\"lock: guard active while metadata is missing or still being initialized\");\n } else {\n messages.push(\"lock: free\");\n }\n\n if (backend) {\n messages.push(...backendSummary);\n const diagnostics = await backend.diagnose(options.signal);\n throwIfAborted(options.signal);\n for (const diagnostic of diagnostics) {\n messages.push(diagnostic.message);\n if (diagnostic.level !== \"info\") level = \"warning\";\n }\n }\n ctx.ui.notify(messages.join(\"\\n\"), level);\n}\n\nexport async function history(\n ctx: ExtensionCommandContext,\n options: CommandOptions,\n factory: SyncBackendFactory = createSyncBackend,\n) {\n const config = await loadConfig(options.setup);\n throwIfAborted(options.signal);\n const backend = await factory(config);\n const snapshots = (await backend.listHistory(options.signal)).slice(-20).reverse();\n throwIfAborted(options.signal);\n if (snapshots.length === 0) {\n ctx.ui.notify(\"No remote pi-sync history found.\", \"info\");\n return;\n }\n\n const currentSnapshot = snapshots[0]?.snapshotId;\n if (ctx.mode === \"tui\") {\n const labels = snapshots.map(\n (item, index) =>\n `${index + 1}. ${item.createdAt} \u00B7 ${safeTerminalText(item.machine)} \u00B7 ${item.snapshotId}${item.snapshotId === currentSnapshot ? \" (current)\" : \"\"}${item.syncSessions ? \" \u00B7 sessions\" : \"\"}`,\n );\n const selected = await ctx.ui.select(\n `History for sync setup \u201C${safeTerminalText(config.setupName)}\u201D\\n\\nChoose a snapshot to preview rollback.`,\n [...labels, \"Back\"],\n { signal: options.signal },\n );\n if (!selected || selected === \"Back\") return;\n throwIfAborted(options.signal);\n const index = labels.indexOf(selected);\n const snapshot = snapshots[index];\n if (!snapshot) return;\n await withLock(\"rollback\", () =>\n rollback(ctx, { ...options, args: [snapshot.snapshotRef], yes: false }, factory, {\n backendIdentity: backend.identity,\n setup: config.setupName,\n }),\n );\n return;\n }\n ctx.ui.notify(\n snapshots.map((item) => `${item.snapshotRef} ${item.createdAt} ${safeTerminalText(item.machine)}`).join(\"\\n\"),\n \"info\",\n );\n}\n"],
5
- "mappings": "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",
6
- "names": ["index"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/backends/webdav/webdav-backend.ts", "../../src/backends/webdav/webdav-client.ts"],
4
- "sourcesContent": ["import { createHash, randomUUID } from \"node:crypto\";\nimport { decodeSnapshot, encodeSnapshot } from \"../../snapshot/snapshot-codec.js\";\nimport type { Snapshot } from \"../../snapshot/snapshot-types.js\";\nimport { validatePortableSnapshot } from \"../../sync/local-fields.js\";\nimport { syncErrorGuidance } from \"../../sync/sync-error-guidance.js\";\nimport { portableSnapshotSelection } from \"../../sync/sync-policy.js\";\nimport type { LatestPointer, RemoteObject, ResolvedWebDavBackend } from \"../backend-types.js\";\nimport {\n type BackendDiagnostic,\n type ExpectedRemoteHead,\n type PublishSnapshotOptions,\n type PublishSnapshotResult,\n type RemoteHead,\n type RemoteHistoryEntry,\n type SyncBackend,\n SyncBackendConflictError,\n SyncBackendPublicationOutcomeUnknownError,\n} from \"../sync-backend.js\";\nimport { WebDavClient, WebDavHttpError, WebDavPreconditionError } from \"./webdav-client.js\";\n\nconst VERSION = 1;\nconst POST_COMMIT_TIMEOUT_MS = 30_000;\n\nexport class WebDavSyncBackend implements SyncBackend {\n readonly identity: string;\n readonly destination: string;\n private conditionalVerified = false;\n private readonly checksums = new Map<string, string>();\n private capabilityCheck?: Promise<void>;\n\n constructor(\n private readonly config: ResolvedWebDavBackend,\n private readonly postCommitTimeoutMs = POST_COMMIT_TIMEOUT_MS,\n ) {\n assertSafeDestination(config);\n this.identity = webDavBackendIdentity(config);\n this.destination = webDavStorageLocation(config);\n }\n\n get capability() {\n return this.conditionalVerified ? (\"atomic-conditional\" as const) : (\"conditional-required\" as const);\n }\n\n sameRevision(left: string, right: string) {\n return left === right;\n }\n\n async readHead(signal?: AbortSignal): Promise<RemoteHead | undefined> {\n const object = await new WebDavClient(this.config, signal).getJson<LatestPointer>(latestPath(this.config));\n throwIfAborted(signal);\n if (object.missing) return undefined;\n const pointer = requirePointer(object.value, this.config.destination.namespace);\n this.registerChecksum(pointer.snapshot, pointer.sha256);\n return remoteHead(pointer, this.identity, object.etag);\n }\n\n async readSnapshot(reference: string, signal?: AbortSignal): Promise<Snapshot> {\n requireSnapshotReference(reference);\n const expectedChecksum = this.checksums.get(reference) ?? (await this.resolveChecksum(reference, signal));\n const object = await new WebDavClient(this.config, signal).getBuffer(snapshotPath(this.config, reference));\n throwIfAborted(signal);\n if (!object.value) throw new Error(`Snapshot not found: ${reference}`);\n if (!expectedChecksum || sha256(object.value) !== expectedChecksum) {\n throw new Error(\"Remote snapshot checksum mismatch.\");\n }\n const snapshot = await decodeSnapshot(object.value, { signal });\n if (snapshot.id !== reference || snapshot.profile !== this.config.destination.namespace) {\n throw new Error(\"Remote snapshot identity mismatch.\");\n }\n validateSnapshotBundle(snapshot);\n return snapshot;\n }\n\n async publishSnapshot(\n snapshot: Snapshot,\n expected: ExpectedRemoteHead,\n options: PublishSnapshotOptions = {},\n ): Promise<PublishSnapshotResult> {\n throwIfAborted(options.signal);\n assertSnapshotIdentity(snapshot, this.config.destination.namespace);\n await this.ensureAtomicConditions(options.signal);\n throwIfAborted(options.signal);\n const client = new WebDavClient(this.config, options.signal);\n await client.ensureCollection(snapshotsPath(this.config));\n const encoded = await encodeSnapshot(snapshot);\n throwIfAborted(options.signal);\n const pointer = pointerFor(this.config, snapshot, sha256(encoded));\n const stagedPath = snapshotPath(this.config, snapshot.id);\n try {\n await client.putBuffer(stagedPath, encoded, \"application/gzip\", { ifAbsent: true });\n } catch (error) {\n if (!(error instanceof WebDavPreconditionError)) throw error;\n const existing = await client.getBuffer(stagedPath);\n if (!existing.value || sha256(existing.value) !== pointer.sha256) {\n throw new SyncBackendConflictError(\n `Immutable snapshot id already exists with different content: ${snapshot.id}`,\n );\n }\n }\n const currentObject = await client.getJson<LatestPointer>(latestPath(this.config));\n throwIfAborted(options.signal);\n const current = currentObject.missing\n ? undefined\n : remoteHead(\n requirePointer(currentObject.value, this.config.destination.namespace),\n this.identity,\n currentObject.etag,\n );\n if (!matchesExpected(current, expected)) {\n throw new SyncBackendConflictError(\"Remote changed while pushing. Run /sync pull first, then retry.\", {\n currentHead: current,\n });\n }\n const condition = publicationCondition(currentObject, expected, this.identity);\n throwIfAborted(options.signal);\n options.onCommit?.();\n const commitClient = new WebDavClient(\n this.config,\n AbortSignal.timeout(this.postCommitTimeoutMs),\n this.postCommitTimeoutMs,\n );\n try {\n await commitClient.putJson(latestPath(this.config), pointer, condition);\n } catch (error) {\n if (error instanceof WebDavPreconditionError) {\n const latest = await this.readHeadAfterCommit(commitClient).catch(() => undefined);\n throw new SyncBackendConflictError(\"Remote changed while publishing the WebDAV pointer.\", {\n currentHead: latest,\n });\n }\n throw new SyncBackendPublicationOutcomeUnknownError(\n `Remote publication outcome is unknown: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n let verifiedObject: RemoteObject<LatestPointer>;\n try {\n verifiedObject = await commitClient.getJson<LatestPointer>(latestPath(this.config));\n } catch (error) {\n throw new SyncBackendPublicationOutcomeUnknownError(\n `Remote snapshot may be active, but publication could not be verified: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n let verified: LatestPointer;\n try {\n verified = requirePointer(verifiedObject.value, this.config.destination.namespace);\n } catch (error) {\n throw new SyncBackendPublicationOutcomeUnknownError(\n `Remote snapshot may be active, but publication verification was malformed: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n if (!samePointer(pointer, verified)) {\n throw new SyncBackendConflictError(\n \"Remote latest changed immediately after push. Run /sync status before continuing.\",\n {\n phase: \"after-commit\",\n currentHead: remoteHead(verified, this.identity, verifiedObject.etag),\n candidateMayHaveBeenActive: true,\n },\n );\n }\n if (!strongEtag(verifiedObject.etag)) {\n throw new SyncBackendPublicationOutcomeUnknownError(\n \"Remote snapshot is active, but the WebDAV server returned no strong ETag.\",\n );\n }\n this.registerChecksum(verified.snapshot, verified.sha256);\n const head = remoteHead(verified, this.identity, verifiedObject.etag);\n const warning = await this.updateHistorySafely(commitClient, pointer);\n return { head, warnings: warning ? [warning] : [] };\n }\n\n async listHistory(signal?: AbortSignal): Promise<RemoteHistoryEntry[]> {\n const object = await new WebDavClient(this.config, signal).getJson<{\n version: number;\n snapshots: LatestPointer[];\n }>(historyPath(this.config));\n throwIfAborted(signal);\n if (object.missing) return [];\n const pointers = requireHistory(object.value, this.config.destination.namespace);\n for (const pointer of pointers) this.registerChecksum(pointer.snapshot, pointer.sha256);\n return pointers.map(remoteHistoryEntry);\n }\n\n async diagnose(signal?: AbortSignal): Promise<BackendDiagnostic[]> {\n const diagnostics: BackendDiagnostic[] = [\n {\n key: \"webdav-url\",\n level: \"info\",\n message: `webdav URL/TLS/auth: configured (${webDavStorageLocation(this.config)})`,\n },\n {\n key: \"webdav-scope\",\n level: \"info\",\n message:\n \"webdav check scope: temporary write/delete probe; repair the active snapshot's history entry if missing. No local content is applied.\",\n },\n ];\n try {\n await this.runCapabilityProbe(signal);\n diagnostics.push(\n { key: \"webdav-collection\", level: \"info\", message: \"webdav collection read/write: ok\" },\n {\n key: \"webdav-conditional\",\n level: \"info\",\n message: \"webdav conditional publication: atomic-conditional (verified)\",\n },\n { key: \"webdav-cleanup\", level: \"info\", message: \"webdav probe cleanup: ok\" },\n );\n } catch (error) {\n this.capabilityCheck = undefined;\n this.conditionalVerified = false;\n if (error instanceof Error && error.name === \"AbortError\") throw error;\n diagnostics.push({\n key: \"webdav-probe\",\n level: \"error\",\n message: `webdav publication is read-only until diagnostics pass: ${syncErrorGuidance(error)}`,\n });\n return diagnostics;\n }\n try {\n diagnostics.push({\n key: \"webdav-history\",\n level: \"info\",\n message: await this.reconcileActiveHistory(signal),\n });\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") throw error;\n diagnostics.push({\n key: \"webdav-history\",\n level: \"error\",\n message: `webdav history repair failed: ${syncErrorGuidance(error)}`,\n });\n }\n return diagnostics;\n }\n\n private ensureAtomicConditions(signal?: AbortSignal) {\n if (this.capabilityCheck) return this.capabilityCheck;\n this.conditionalVerified = false;\n const check = this.runCapabilityProbe(signal).finally(() => {\n if (this.capabilityCheck === check) this.capabilityCheck = undefined;\n });\n this.capabilityCheck = check;\n return check;\n }\n\n private async runCapabilityProbe(signal?: AbortSignal) {\n throwIfAborted(signal);\n const probeCollection = joinRemote(rootPath(this.config), \".pi-sync-probes\", randomUUID());\n const probe = `${probeCollection}/conditional.txt`;\n const client = new WebDavClient(this.config, signal);\n let created = false;\n let operationError: unknown;\n try {\n created = true;\n await client.ensureCollection(probeCollection);\n await client.listCollection(probeCollection);\n await client.putBuffer(probe, Buffer.from(\"first\"), \"text/plain\", { ifAbsent: true });\n const read = await client.getBuffer(probe);\n const etag = strongEtag(read.etag);\n if (!read.value || !etag) {\n throw new Error(\"WebDAV server did not return a strong ETag for the capability probe.\");\n }\n await expectPrecondition(\n client.putBuffer(probe, Buffer.from(\"replace\"), \"text/plain\", { ifAbsent: true }),\n \"If-None-Match\",\n );\n await expectPrecondition(\n client.putBuffer(probe, Buffer.from(\"replace\"), \"text/plain\", {\n ifMatch: '\"pi-sync-deliberately-stale\"',\n }),\n \"If-Match\",\n );\n const unchanged = await client.getBuffer(probe);\n if (!unchanged.value?.equals(Buffer.from(\"first\"))) {\n throw new Error(\"WebDAV server changed a probe despite a failed precondition.\");\n }\n await client.putBuffer(probe, Buffer.from(\"second\"), \"text/plain\", { ifMatch: etag });\n const changed = await client.getBuffer(probe);\n const changedEtag = strongEtag(changed.etag);\n if (!changed.value?.equals(Buffer.from(\"second\")) || !changedEtag || changedEtag === etag) {\n throw new Error(\"WebDAV server did not rotate its strong ETag after changing the capability probe.\");\n }\n } catch (error) {\n operationError = error;\n }\n if (created) {\n try {\n await new WebDavClient(this.config, undefined).delete(probeCollection);\n } catch (cleanupError) {\n const operationDetail = operationError ? `WebDAV probe failed: ${errorMessage(operationError)}; ` : \"\";\n throw new Error(\n `${operationDetail}probe cleanup also failed; remove ${probeCollection}: ${errorMessage(cleanupError)}`,\n { cause: operationError ?? cleanupError },\n );\n }\n }\n if (operationError) throw operationError;\n this.conditionalVerified = true;\n }\n\n private async resolveChecksum(reference: string, signal?: AbortSignal) {\n await this.readHead(signal);\n if (this.checksums.has(reference)) return this.checksums.get(reference);\n await this.listHistory(signal);\n return this.checksums.get(reference);\n }\n\n private registerChecksum(reference: string, checksum: string) {\n const known = this.checksums.get(reference);\n if (known && known !== checksum) {\n throw new Error(\"Remote snapshot reference was rebound to a different checksum.\");\n }\n this.checksums.set(reference, checksum);\n }\n\n private async readHeadAfterCommit(client: WebDavClient) {\n const object = await client.getJson<LatestPointer>(latestPath(this.config));\n if (object.missing) return undefined;\n return remoteHead(requirePointer(object.value, this.config.destination.namespace), this.identity, object.etag);\n }\n\n private async reconcileActiveHistory(signal?: AbortSignal) {\n const client = new WebDavClient(this.config, signal);\n const object = await client.getJson<LatestPointer>(latestPath(this.config));\n throwIfAborted(signal);\n if (object.missing) return \"webdav history: no active snapshot\";\n const pointer = requirePointer(object.value, this.config.destination.namespace);\n this.registerChecksum(pointer.snapshot, pointer.sha256);\n const repaired = await this.ensureHistoryPointer(client, pointer);\n return repaired\n ? \"webdav history: repaired active snapshot entry\"\n : \"webdav history: active snapshot entry present\";\n }\n\n private async ensureHistoryPointer(client: WebDavClient, pointer: LatestPointer) {\n const object = await client.getJson<{ version: number; snapshots: LatestPointer[] }>(historyPath(this.config));\n const snapshots = object.missing ? [] : requireHistory(object.value, this.config.destination.namespace);\n const existing = snapshots.find((entry) => entry.snapshot === pointer.snapshot);\n if (existing) {\n if (!samePointer(existing, pointer)) {\n throw new Error(\"Remote history rebound an immutable snapshot reference.\");\n }\n return false;\n }\n const next = [...snapshots, pointer].slice(-100);\n const condition = object.missing ? { ifAbsent: true } : { ifMatch: requireStrongEtag(object.etag, \"history\") };\n await client.putJson(historyPath(this.config), { version: VERSION, snapshots: next }, condition);\n return true;\n }\n\n private async updateHistorySafely(client: WebDavClient, pointer: LatestPointer) {\n try {\n await this.ensureHistoryPointer(client, pointer);\n return undefined;\n } catch (error) {\n return `Remote snapshot is active, but history could not be updated: ${errorMessage(error)}. Run /sync doctor before relying on history.`;\n }\n }\n}\n\nexport function rootPath(config: ResolvedWebDavBackend) {\n return config.destination.path === \"./\" ? \"\" : config.destination.path;\n}\n\nexport function latestPath(config: ResolvedWebDavBackend) {\n return joinRemote(rootPath(config), \"latest.json\");\n}\n\nexport function historyPath(config: ResolvedWebDavBackend) {\n return joinRemote(rootPath(config), \"history.json\");\n}\n\nexport function snapshotsPath(config: ResolvedWebDavBackend) {\n return joinRemote(rootPath(config), \"snapshots\");\n}\n\nexport function snapshotPath(config: ResolvedWebDavBackend, reference: string) {\n requireSnapshotReference(reference);\n return joinRemote(snapshotsPath(config), `${reference}.json.gz`);\n}\n\nexport function webDavBackendIdentity(config: ResolvedWebDavBackend) {\n return `webdav:${sha256(Buffer.from(JSON.stringify([secretFreeUrl(config.profile.url), config.destination.path])))}`;\n}\n\nfunction webDavStorageLocation(config: ResolvedWebDavBackend) {\n const url = new URL(secretFreeUrl(config.profile.url));\n return `${url.host} \u00B7 ${config.destination.path}`;\n}\n\nfunction pointerFor(config: ResolvedWebDavBackend, snapshot: Snapshot, checksum: string): LatestPointer {\n return {\n version: VERSION,\n profile: config.destination.namespace,\n snapshot: snapshot.id,\n sha256: checksum,\n createdAt: snapshot.createdAt,\n machine: snapshot.machine,\n syncSessions: snapshot.syncSessions === true || snapshot.files.some((file) => file.path.startsWith(\"sessions/\")),\n ...(snapshot.selection === undefined ? {} : { selection: snapshot.selection }),\n };\n}\n\nfunction remoteHead(pointer: LatestPointer, identity: string, etag?: string): RemoteHead {\n return {\n snapshotRef: pointer.snapshot,\n snapshotId: pointer.snapshot,\n revision: encodeRevision(identity, etag, pointer),\n createdAt: pointer.createdAt,\n machine: pointer.machine,\n syncSessions: pointer.syncSessions === true,\n ...(pointer.selection === undefined ? {} : { selection: pointer.selection }),\n };\n}\n\nfunction encodeRevision(identity: string, etag: string | undefined, pointer: LatestPointer) {\n return `webdav-v1:${Buffer.from(JSON.stringify({ identity, etag: etag ?? null, pointer: sha256(Buffer.from(canonicalJson(pointer))) })).toString(\"base64url\")}`;\n}\n\nfunction decodeRevision(value: string, identity: string) {\n try {\n if (!value.startsWith(\"webdav-v1:\")) return undefined;\n const parsed = JSON.parse(Buffer.from(value.slice(10), \"base64url\").toString(\"utf8\")) as {\n identity?: unknown;\n etag?: unknown;\n };\n if (parsed.identity !== identity || typeof parsed.etag !== \"string\") return undefined;\n return strongEtag(parsed.etag);\n } catch {\n return undefined;\n }\n}\n\nfunction publicationCondition(current: RemoteObject<LatestPointer>, expected: ExpectedRemoteHead, identity: string) {\n if (expected.kind === \"missing\") return { ifAbsent: true };\n const etag = decodeRevision(expected.revision, identity) ?? strongEtag(current.etag);\n if (!etag) throw new SyncBackendConflictError(\"WebDAV head has no usable strong ETag.\");\n return { ifMatch: etag };\n}\n\nasync function expectPrecondition(operation: Promise<unknown>, header: string) {\n try {\n await operation;\n } catch (error) {\n if (error instanceof WebDavPreconditionError) return;\n throw error;\n }\n throw new Error(`WebDAV server ignored ${header}; publication is read-only for safety.`);\n}\n\nfunction requireStrongEtag(value: string | undefined, resource: string) {\n const etag = strongEtag(value);\n if (!etag) throw new Error(`WebDAV ${resource} has no strong ETag.`);\n return etag;\n}\n\nfunction strongEtag(value: string | undefined) {\n return value && !value.startsWith(\"W/\") && /^\"[^\"\\r\\n]+\"$/u.test(value) ? value : undefined;\n}\n\nfunction requirePointer(value: LatestPointer | undefined, expectedProfile: string) {\n if (\n !value ||\n value.version !== VERSION ||\n value.profile !== expectedProfile ||\n !isSafeReference(value.snapshot) ||\n !/^[0-9a-f]{64}$/u.test(value.sha256) ||\n !isSafeMetadata(value.createdAt, 64) ||\n !isSafeMetadata(value.machine, 256) ||\n (value.syncSessions !== undefined && typeof value.syncSessions !== \"boolean\")\n ) {\n throw new Error(\"Remote latest pointer is malformed.\");\n }\n if (value.selection !== undefined) portableSnapshotSelection(value.selection);\n return value;\n}\n\nfunction requireHistory(value: { version: number; snapshots: LatestPointer[] } | undefined, expectedProfile: string) {\n if (!value || value.version !== VERSION || !Array.isArray(value.snapshots)) {\n throw new Error(\"Remote history is malformed.\");\n }\n const pointers = value.snapshots.map((item) => requirePointer(item, expectedProfile));\n if (new Set(pointers.map((item) => item.snapshot)).size !== pointers.length) {\n throw new Error(\"Remote history contains duplicate snapshot references.\");\n }\n return pointers;\n}\n\nfunction remoteHistoryEntry(pointer: LatestPointer): RemoteHistoryEntry {\n return {\n snapshotRef: pointer.snapshot,\n snapshotId: pointer.snapshot,\n createdAt: pointer.createdAt,\n machine: pointer.machine,\n syncSessions: pointer.syncSessions === true,\n };\n}\n\nfunction assertSnapshotIdentity(snapshot: Snapshot, namespace: string) {\n validatePortableSnapshot(snapshot);\n if (\n snapshot.profile !== namespace ||\n !isSafeReference(snapshot.id) ||\n !isSafeMetadata(snapshot.createdAt, 64) ||\n !isSafeMetadata(snapshot.machine, 256) ||\n !Array.isArray(snapshot.files)\n ) {\n throw new Error(\"Invalid snapshot identity for WebDAV publication.\");\n }\n}\n\nfunction validateSnapshotBundle(snapshot: Snapshot) {\n const paths = new Set<string>();\n for (const file of snapshot.files) {\n if (\n !file ||\n !isSafeSnapshotPath(file.path) ||\n paths.has(file.path) ||\n typeof file.contentBase64 !== \"string\" ||\n typeof file.sha256 !== \"string\"\n ) {\n throw new Error(\"Remote snapshot bundle is malformed.\");\n }\n const content = Buffer.from(file.contentBase64, \"base64\");\n if (content.toString(\"base64\") !== file.contentBase64 || sha256(content) !== file.sha256) {\n throw new Error(\"Remote snapshot bundle is malformed.\");\n }\n paths.add(file.path);\n }\n}\n\nfunction isSafeSnapshotPath(value: unknown): value is string {\n if (typeof value !== \"string\" || !value || value.length > 4096 || value.includes(\"\\\\\")) {\n return false;\n }\n if (\n [...value].some((character) => {\n const code = character.codePointAt(0) ?? 0;\n return code < 0x20 || (code >= 0x7f && code <= 0x9f);\n })\n ) {\n return false;\n }\n return value.split(\"/\").every((segment) => segment && segment !== \".\" && segment !== \"..\");\n}\n\nfunction assertSafeDestination(config: ResolvedWebDavBackend) {\n const url = new URL(config.profile.url);\n if (url.username || url.password || url.search || url.hash) throw new Error(\"Invalid WebDAV URL.\");\n for (const [label, value] of [\n [\"path\", config.destination.path],\n [\"namespace\", config.destination.namespace],\n ]) {\n if (label === \"path\" && value === \"./\") continue;\n if (\n !value ||\n value.includes(\"\\\\\") ||\n [...value].some((character) => {\n const code = character.codePointAt(0) ?? 0;\n return code < 0x20 || (code >= 0x7f && code <= 0x9f);\n }) ||\n value.split(\"/\").some((part) => part === \".\" || part === \"..\")\n ) {\n throw new Error(\"Invalid WebDAV storage location.\");\n }\n }\n}\n\nfunction isSafeMetadata(value: unknown, maxLength: number): value is string {\n return (\n typeof value === \"string\" &&\n value.length > 0 &&\n value.length <= maxLength &&\n ![...value].some((character) => {\n const code = character.codePointAt(0) ?? 0;\n return code < 0x20 || (code >= 0x7f && code <= 0x9f);\n })\n );\n}\n\nfunction requireSnapshotReference(reference: string) {\n if (!isSafeReference(reference)) throw new Error(\"Invalid WebDAV snapshot reference.\");\n}\n\nfunction isSafeReference(value: string) {\n return (\n !!value &&\n value.length <= 512 &&\n // biome-ignore lint/suspicious/noControlCharactersInRegex: Remote references cannot contain terminal controls.\n !/[\\\\/\\u0000-\\u001f\\u007f-\\u009f]/u.test(value) &&\n value !== \".\" &&\n value !== \"..\"\n );\n}\n\nfunction matchesExpected(head: RemoteHead | undefined, expected: ExpectedRemoteHead) {\n return expected.kind === \"missing\" ? head === undefined : head?.revision === expected.revision;\n}\n\nfunction samePointer(left: LatestPointer, right: LatestPointer) {\n return canonicalJson(left) === canonicalJson(right);\n}\n\nfunction canonicalJson(value: unknown): string {\n if (Array.isArray(value)) return JSON.stringify(value.map((item) => JSON.parse(canonicalJson(item))));\n if (!value || typeof value !== \"object\") return JSON.stringify(value);\n return JSON.stringify(\n Object.fromEntries(\n Object.keys(value)\n .sort()\n .map((key) => [key, JSON.parse(canonicalJson((value as Record<string, unknown>)[key]))]),\n ),\n );\n}\n\nfunction joinRemote(...parts: string[]) {\n return parts\n .flatMap((part) => part.split(\"/\"))\n .filter(Boolean)\n .join(\"/\");\n}\n\nfunction secretFreeUrl(value: string) {\n const url = new URL(value);\n url.username = \"\";\n url.password = \"\";\n url.search = \"\";\n url.hash = \"\";\n return url.toString();\n}\n\nfunction sha256(value: Buffer) {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction throwIfAborted(signal?: AbortSignal) {\n if (!signal?.aborted) return;\n throw signal.reason instanceof Error ? signal.reason : new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n\nfunction errorMessage(error: unknown) {\n if (error instanceof WebDavHttpError) return error.message;\n return error instanceof Error ? error.message : String(error);\n}\n", "import { XMLParser } from \"fast-xml-parser\";\nimport type { RemoteObject, ResolvedWebDavBackend } from \"../backend-types.js\";\n\nconst JSON_LIMIT = 1024 * 1024;\nconst ERROR_LIMIT = 64 * 1024;\nconst SNAPSHOT_LIMIT = 256 * 1024 * 1024;\nconst XML_LIMIT = 1024 * 1024;\nconst REQUEST_TIMEOUT_MS = 30_000;\nconst MAX_REDIRECTS = 3;\n\nexport interface WebDavPutOptions {\n ifAbsent?: boolean;\n ifMatch?: string;\n}\n\nexport interface WebDavEntry {\n href: string;\n etag?: string;\n collection: boolean;\n}\n\nexport class WebDavHttpError extends Error {\n constructor(\n message: string,\n readonly status: number,\n options?: ErrorOptions,\n ) {\n super(message, options);\n this.name = \"WebDavHttpError\";\n }\n}\n\nexport class WebDavPreconditionError extends WebDavHttpError {\n constructor(message = \"WebDAV precondition failed.\") {\n super(message, 412);\n this.name = \"WebDavPreconditionError\";\n }\n}\n\nexport class WebDavClient {\n private readonly baseUrl: URL;\n private readonly authorization: string;\n\n constructor(\n private readonly config: ResolvedWebDavBackend,\n private readonly signal?: AbortSignal,\n private readonly timeoutMs = REQUEST_TIMEOUT_MS,\n ) {\n this.baseUrl = new URL(config.profile.url);\n assertSafeAuthenticatedUrl(this.baseUrl);\n if (\n !config.profile.username ||\n !config.profile.password ||\n config.profile.username.includes(\":\") ||\n hasControlCharacter(config.profile.username) ||\n hasControlCharacter(config.profile.password)\n ) {\n throw new Error(\"Invalid WebDAV credentials.\");\n }\n this.authorization = `Basic ${Buffer.from(`${config.profile.username}:${config.profile.password}`).toString(\"base64\")}`;\n }\n\n async getBuffer(remotePath: string): Promise<RemoteObject<Buffer>> {\n const response = await this.request(remotePath, { method: \"GET\" });\n if (response.status === 404) {\n await response.body?.cancel();\n return { missing: true };\n }\n await this.requireOk(response, \"read\");\n return {\n value: await readBounded(response, SNAPSHOT_LIMIT, \"WebDAV response is too large\"),\n etag: response.headers.get(\"etag\") ?? undefined,\n missing: false,\n };\n }\n\n async getJson<T>(remotePath: string): Promise<RemoteObject<T>> {\n const response = await this.request(remotePath, { method: \"GET\" });\n if (response.status === 404) {\n await response.body?.cancel();\n return { missing: true };\n }\n await this.requireOk(response, \"read\");\n const bytes = await readBounded(response, JSON_LIMIT, \"WebDAV JSON response is too large\");\n try {\n return {\n value: JSON.parse(bytes.toString(\"utf8\")) as T,\n etag: response.headers.get(\"etag\") ?? undefined,\n missing: false,\n };\n } catch (error) {\n throw new Error(\"WebDAV JSON response is malformed.\", { cause: error });\n }\n }\n\n async putBuffer(remotePath: string, body: Buffer, contentType: string, options: WebDavPutOptions = {}) {\n const headers: Record<string, string> = { \"content-type\": contentType };\n if (options.ifAbsent) headers[\"if-none-match\"] = \"*\";\n if (options.ifMatch) headers[\"if-match\"] = options.ifMatch;\n const response = await this.request(remotePath, {\n method: \"PUT\",\n headers,\n body: body as unknown as BodyInit,\n });\n if (response.status === 412) {\n await response.body?.cancel();\n throw new WebDavPreconditionError();\n }\n await this.requireOk(response, \"write\");\n await response.body?.cancel();\n return response.headers.get(\"etag\") ?? undefined;\n }\n\n async putJson(remotePath: string, value: unknown, options: WebDavPutOptions = {}) {\n return this.putBuffer(remotePath, Buffer.from(JSON.stringify(value)), \"application/json\", options);\n }\n\n async makeCollection(remotePath: string) {\n const response = await this.request(remotePath, { method: \"MKCOL\" });\n if (response.status === 405) {\n await response.body?.cancel();\n return false;\n }\n await this.requireOk(response, \"create collection\");\n await response.body?.cancel();\n return true;\n }\n\n async ensureCollection(remotePath: string) {\n const segments = safeSegments(remotePath);\n for (let index = 1; index <= segments.length; index += 1) {\n await this.makeCollection(segments.slice(0, index).join(\"/\"));\n }\n }\n\n async listCollection(remotePath: string): Promise<WebDavEntry[]> {\n const response = await this.request(remotePath, {\n method: \"PROPFIND\",\n headers: { depth: \"1\", \"content-type\": \"application/xml; charset=utf-8\" },\n body: '<?xml version=\"1.0\"?><d:propfind xmlns:d=\"DAV:\"><d:prop><d:getetag/><d:resourcetype/></d:prop></d:propfind>',\n });\n if (response.status === 404) {\n await response.body?.cancel();\n throw new WebDavHttpError(\"WebDAV collection is missing.\", 404);\n }\n if (response.status !== 207) await this.requireOk(response, \"list collection\");\n const xml = (await readBounded(response, XML_LIMIT, \"WebDAV directory response is too large\")).toString(\"utf8\");\n try {\n const parsed = new XMLParser({\n removeNSPrefix: true,\n ignoreAttributes: false,\n processEntities: false,\n }).parse(xml) as {\n multistatus?: { response?: unknown };\n };\n if (!parsed.multistatus || parsed.multistatus.response === undefined) {\n throw new Error(\"Missing DAV multistatus response.\");\n }\n const responses = asArray(parsed.multistatus.response);\n return responses.map(parseEntry);\n } catch (error) {\n throw new Error(\"WebDAV directory response is malformed.\", { cause: error });\n }\n }\n\n async delete(remotePath: string) {\n const response = await this.request(remotePath, { method: \"DELETE\" });\n if (response.status === 404) {\n await response.body?.cancel();\n return;\n }\n if (response.status === 207) {\n await response.body?.cancel();\n throw new WebDavHttpError(\"WebDAV probe cleanup returned a partial response.\", 207);\n }\n await this.requireOk(response, \"delete probe resource\");\n await response.body?.cancel();\n }\n\n private async request(remotePath: string, init: RequestInit) {\n throwIfAborted(this.signal);\n let url = appendRemotePath(this.baseUrl, remotePath);\n for (let redirects = 0; ; redirects += 1) {\n const timeout = AbortSignal.timeout(this.timeoutMs);\n const signal = this.signal ? AbortSignal.any([this.signal, timeout]) : timeout;\n let response: Response;\n try {\n response = await fetch(url, {\n ...init,\n headers: {\n accept: \"*/*\",\n authorization: this.authorization,\n ...headersObject(init.headers),\n },\n redirect: \"manual\",\n signal,\n });\n } catch (error) {\n throwIfAborted(this.signal);\n throw new Error(\n `WebDAV ${String(init.method ?? \"GET\")} request failed for ${redactText(safeUrl(url), this.config)}.`,\n {\n cause: redactError(error, this.config),\n },\n );\n }\n if (![301, 302, 303, 307, 308].includes(response.status)) return response;\n await response.body?.cancel();\n const method = String(init.method ?? \"GET\").toUpperCase();\n if ([301, 302, 303].includes(response.status) && method !== \"GET\" && method !== \"HEAD\") {\n throw new Error(\n `WebDAV refused an ambiguous HTTP ${response.status} redirect for ${method}; configure the canonical collection URL or require HTTP 307/308.`,\n );\n }\n if (redirects >= MAX_REDIRECTS) throw new Error(\"WebDAV redirect limit exceeded.\");\n const location = response.headers.get(\"location\");\n if (!location) throw new Error(\"WebDAV redirect is missing Location.\");\n const next = new URL(location, url);\n if (next.origin !== this.baseUrl.origin) {\n throw new Error(\"WebDAV refused a cross-origin authenticated redirect.\");\n }\n url = next;\n }\n }\n\n private async requireOk(response: Response, action: string) {\n if (response.ok) return;\n const body = (await readBounded(response, ERROR_LIMIT, \"WebDAV error body is too large\"))\n .toString(\"utf8\")\n // biome-ignore lint/suspicious/noControlCharactersInRegex: Remote error text is untrusted terminal input.\n .replace(/[\\u0000-\\u001f\\u007f-\\u009f]/gu, \" \")\n .trim();\n const detail = body ? `: ${redactText(body, this.config)}` : \"\";\n throw new WebDavHttpError(`WebDAV ${action} failed with HTTP ${response.status}${detail}`, response.status);\n }\n}\n\nfunction assertSafeAuthenticatedUrl(url: URL) {\n const loopback =\n url.hostname === \"127.0.0.1\" || url.hostname === \"localhost\" || url.hostname === \"[::1]\" || url.hostname === \"::1\";\n if (\n url.username ||\n url.password ||\n url.search ||\n url.hash ||\n (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && loopback))\n ) {\n throw new Error(\n \"Invalid WebDAV URL: HTTPS is required and embedded credentials, query, or fragment are not allowed.\",\n );\n }\n}\n\nfunction hasControlCharacter(value: string) {\n return [...value].some((character) => {\n const code = character.codePointAt(0) ?? 0;\n return code < 0x20 || (code >= 0x7f && code <= 0x9f);\n });\n}\n\nfunction appendRemotePath(base: URL, remotePath: string) {\n const url = new URL(base);\n const suffix = safeSegments(remotePath).map(encodeURIComponent).join(\"/\");\n url.pathname = `${base.pathname.replace(/\\/+$/u, \"\")}/${suffix}`;\n return url;\n}\n\nfunction safeSegments(value: string) {\n const segments = value\n .replace(/^\\/+|\\/+$/gu, \"\")\n .split(\"/\")\n .filter(Boolean);\n if (\n segments.some(\n (segment) =>\n segment === \".\" ||\n segment === \"..\" ||\n // biome-ignore lint/suspicious/noControlCharactersInRegex: Remote path segments cannot contain controls.\n /[\\u0000-\\u001f]/u.test(segment),\n )\n ) {\n throw new Error(\"Invalid WebDAV remote path.\");\n }\n return segments;\n}\n\nasync function readBounded(response: Response, limit: number, message: string) {\n const length = Number(response.headers.get(\"content-length\"));\n if (Number.isFinite(length) && length > limit) {\n await response.body?.cancel();\n throw new Error(message);\n }\n if (!response.body) return Buffer.alloc(0);\n const reader = response.body.getReader();\n const chunks: Buffer[] = [];\n let total = 0;\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > limit) throw new Error(message);\n chunks.push(Buffer.from(value));\n }\n } catch (error) {\n await reader.cancel().catch(() => undefined);\n throw error;\n }\n return Buffer.concat(chunks, total);\n}\n\nfunction parseEntry(value: unknown): WebDavEntry {\n if (!value || typeof value !== \"object\") throw new Error(\"Invalid WebDAV response entry.\");\n const record = value as Record<string, unknown>;\n const href = typeof record.href === \"string\" ? record.href : undefined;\n if (!href) throw new Error(\"Invalid WebDAV response href.\");\n const propstat = asArray(record.propstat).find((item) => {\n if (!item || typeof item !== \"object\") return false;\n return String((item as Record<string, unknown>).status ?? \"\").includes(\" 200 \");\n }) as Record<string, unknown> | undefined;\n const prop = propstat?.prop as Record<string, unknown> | undefined;\n return {\n href,\n etag: typeof prop?.getetag === \"string\" ? prop.getetag : undefined,\n collection:\n !!prop?.resourcetype && typeof prop.resourcetype === \"object\" && Object.hasOwn(prop.resourcetype, \"collection\"),\n };\n}\n\nfunction asArray(value: unknown): unknown[] {\n if (value === undefined) return [];\n return Array.isArray(value) ? value : [value];\n}\n\nfunction headersObject(headers: HeadersInit | undefined) {\n return Object.fromEntries(new Headers(headers).entries());\n}\n\nfunction safeUrl(url: URL) {\n return `${url.protocol}//${url.host}${url.pathname}`;\n}\n\nfunction redactError(error: unknown, config: ResolvedWebDavBackend) {\n const message = error instanceof Error ? error.message : String(error);\n return new Error(redactText(message, config));\n}\n\nfunction redactText(value: string, config: ResolvedWebDavBackend) {\n let result = value;\n for (const secret of [config.profile.username, config.profile.password, config.profile.url]) {\n if (!secret) continue;\n for (const variant of new Set([secret, encodeURIComponent(secret)])) {\n result = result.replace(new RegExp(escapeRegExp(variant), \"giu\"), \"[redacted]\");\n }\n }\n return result.replace(/basic\\s+[a-z0-9+/=]+/giu, \"Basic [redacted]\").replace(/\\?[^\\s]*/gu, \"?[redacted]\");\n}\n\nfunction escapeRegExp(value: string) {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/gu, \"\\\\$&\");\n}\n\nfunction throwIfAborted(signal?: AbortSignal) {\n if (!signal?.aborted) return;\n throw signal.reason instanceof Error ? signal.reason : new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n"],
5
- "mappings": "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",
6
- "names": ["throwIfAborted"]
7
- }