@narumitw/pi-sync 0.49.14 → 0.50.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.
- package/README.md +134 -241
- package/dist/chunks/chunk-2B2ELUF5.ts +29 -0
- package/dist/chunks/chunk-2B2ELUF5.ts.map +7 -0
- package/dist/chunks/chunk-6LP3MCR2.ts +115 -0
- package/dist/chunks/chunk-6LP3MCR2.ts.map +7 -0
- package/dist/chunks/chunk-6UHKGALE.ts +134 -0
- package/dist/chunks/chunk-6UHKGALE.ts.map +7 -0
- package/dist/chunks/{chunk-RGJ6SOYR.ts → chunk-AUSDLD6F.ts} +4 -4
- package/dist/chunks/chunk-AUSDLD6F.ts.map +7 -0
- package/dist/chunks/{chunk-3NDD5QPM.ts → chunk-AXXS2BPA.ts} +9 -9
- package/dist/chunks/chunk-AXXS2BPA.ts.map +7 -0
- package/dist/chunks/{chunk-APZVBSM6.ts → chunk-C7XY5NF5.ts} +214 -365
- package/dist/chunks/chunk-C7XY5NF5.ts.map +7 -0
- package/dist/chunks/{chunk-4U6AFLJB.ts → chunk-CHH26D4F.ts} +3 -2
- package/dist/chunks/chunk-CHH26D4F.ts.map +7 -0
- package/dist/chunks/chunk-CPEHGXJV.ts +50 -0
- package/dist/chunks/chunk-CPEHGXJV.ts.map +7 -0
- package/dist/chunks/{chunk-5MQ76BK5.ts → chunk-D5X27LCA.ts} +2 -2
- package/dist/chunks/chunk-D5X27LCA.ts.map +7 -0
- package/dist/chunks/{chunk-LJDSHNS3.ts → chunk-GWMHAQG4.ts} +4 -4
- package/dist/chunks/chunk-GWMHAQG4.ts.map +7 -0
- package/dist/chunks/{chunk-FR6CVXAL.ts → chunk-HUDQATCL.ts} +25 -25
- package/dist/chunks/chunk-HUDQATCL.ts.map +7 -0
- package/dist/chunks/{chunk-YQ6UW7IF.ts → chunk-JAAKLL6M.ts} +2 -2
- package/dist/chunks/chunk-JAAKLL6M.ts.map +7 -0
- package/dist/chunks/chunk-JSYMGJQQ.ts +51 -0
- package/dist/chunks/chunk-JSYMGJQQ.ts.map +7 -0
- package/dist/chunks/chunk-L7TBO32M.ts +25 -0
- package/dist/chunks/chunk-L7TBO32M.ts.map +7 -0
- package/dist/chunks/{chunk-4F3W4CSC.ts → chunk-LCRI3ABW.ts} +22 -8
- package/dist/chunks/chunk-LCRI3ABW.ts.map +7 -0
- package/dist/chunks/chunk-LTBWGSBV.ts +12 -0
- package/dist/chunks/chunk-LTBWGSBV.ts.map +7 -0
- package/dist/chunks/chunk-NJFUIVYL.ts +17 -0
- package/dist/chunks/chunk-NJFUIVYL.ts.map +7 -0
- package/dist/chunks/{chunk-EWX3TPLQ.ts → chunk-OEX4ABY6.ts} +39 -37
- package/dist/chunks/chunk-OEX4ABY6.ts.map +7 -0
- package/dist/chunks/chunk-OUHGBFYF.ts +1255 -0
- package/dist/chunks/chunk-OUHGBFYF.ts.map +7 -0
- package/dist/chunks/{chunk-HGV24P4T.ts → chunk-Q2TUM5X6.ts} +3 -3
- package/dist/chunks/chunk-Q2TUM5X6.ts.map +7 -0
- package/dist/chunks/{chunk-BHJUISB4.ts → chunk-SL64RLXR.ts} +8 -6
- package/dist/chunks/chunk-SL64RLXR.ts.map +7 -0
- package/dist/chunks/chunk-T3HH3UEJ.ts +96 -0
- package/dist/chunks/chunk-T3HH3UEJ.ts.map +7 -0
- package/dist/chunks/chunk-TEN2ZBJV.ts +101 -0
- package/dist/chunks/chunk-TEN2ZBJV.ts.map +7 -0
- package/dist/chunks/chunk-THMF4BVL.ts +18 -0
- package/dist/chunks/chunk-THMF4BVL.ts.map +7 -0
- package/dist/chunks/{chunk-LONPFFNP.ts → chunk-X5OM6GXT.ts} +9 -7
- package/dist/chunks/chunk-X5OM6GXT.ts.map +7 -0
- package/dist/chunks/chunk-XBX4HBLG.ts +57 -0
- package/dist/chunks/chunk-XBX4HBLG.ts.map +7 -0
- package/dist/chunks/{chunk-5WJNWFTG.ts → chunk-YKJHPTGO.ts} +23 -55
- package/dist/chunks/chunk-YKJHPTGO.ts.map +7 -0
- package/dist/chunks/chunk-Z4DQF6L3.ts +12 -0
- package/dist/chunks/chunk-Z4DQF6L3.ts.map +7 -0
- package/dist/chunks/{chunk-F5QL2GPY.ts → chunk-ZI5MXMEX.ts} +5 -99
- package/dist/chunks/chunk-ZI5MXMEX.ts.map +7 -0
- package/dist/chunks/{file-selection-4UABOP44.ts → file-selection-FTTKAOYX.ts} +10 -7
- package/dist/chunks/file-selection-FTTKAOYX.ts.map +7 -0
- package/dist/chunks/{git-backend-E3UOUUOM.ts → git-backend-OQW46G2X.ts} +42 -17
- package/dist/chunks/git-backend-OQW46G2X.ts.map +7 -0
- package/dist/chunks/manager-result-dispatcher-U23ODD32.ts +22 -0
- package/dist/chunks/manager-ui-ABATHC36.ts +1680 -0
- package/dist/chunks/manager-ui-ABATHC36.ts.map +7 -0
- package/dist/chunks/remote-selection-ui-ZE3TY67S.ts +21 -0
- package/dist/chunks/{s3-backend-3QZGO2EF.ts → s3-backend-3P33LQHU.ts} +96 -18
- package/dist/chunks/s3-backend-3P33LQHU.ts.map +7 -0
- package/dist/chunks/{setup-switch-X3W3FALZ.ts → setup-switch-IS2PEZ3J.ts} +9 -9
- package/dist/chunks/setup-wizard-VB3VDOV5.ts +89 -0
- package/dist/chunks/setup-wizard-VB3VDOV5.ts.map +7 -0
- package/dist/chunks/{snapshot-WBSV4MQG.ts → snapshot-HKEWCVK6.ts} +7 -6
- package/dist/chunks/sync-inspection-FEP4L5TR.ts +20 -0
- package/dist/chunks/{sync-operations-MPAFVVHA.ts → sync-operations-ONJ27QRL.ts} +381 -299
- package/dist/chunks/sync-operations-ONJ27QRL.ts.map +7 -0
- package/dist/chunks/{sync-state-36H7ULG2.ts → sync-state-Q2FTXTW6.ts} +6 -6
- package/dist/chunks/sync-state-Q2FTXTW6.ts.map +7 -0
- package/dist/chunks/{webdav-backend-ZD5RHRIU.ts → webdav-backend-ECIKD7SO.ts} +26 -13
- package/dist/chunks/webdav-backend-ECIKD7SO.ts.map +7 -0
- package/dist/index.ts +477 -342
- package/dist/index.ts.map +4 -4
- package/docs/settings.md +211 -0
- package/package.json +6 -8
- package/src/{backend-factory.ts → backends/backend-factory.ts} +4 -4
- package/src/backends/backend-identity.ts +40 -0
- package/src/backends/backend-types.ts +81 -0
- package/src/{git-backend.ts → backends/git/git-backend.ts} +43 -19
- package/src/{git-config.ts → backends/git/git-config.ts} +1 -0
- package/src/{git-storage.ts → backends/git/git-storage.ts} +2 -2
- package/src/{s3-backend.ts → backends/s3/s3-backend.ts} +45 -9
- package/src/{s3-client.ts → backends/s3/s3-client.ts} +56 -8
- package/src/{sync-backend.ts → backends/sync-backend.ts} +1 -1
- package/src/{webdav-backend.ts → backends/webdav/webdav-backend.ts} +22 -10
- package/src/{webdav-client.ts → backends/webdav/webdav-client.ts} +1 -1
- package/src/{webdav-config.ts → backends/webdav/webdav-config.ts} +1 -0
- package/src/commands/command-execution.ts +330 -0
- package/src/commands/command-handler.ts +201 -0
- package/src/commands/command-types.ts +18 -0
- package/src/{command.ts → commands/command.ts} +2 -1
- package/src/commands/setup-completions.ts +6 -0
- package/src/settings/config.ts +238 -0
- package/src/{settings-management.ts → settings/settings-management.ts} +40 -14
- package/src/settings/settings-store.ts +109 -0
- package/src/settings/settings-types.ts +128 -0
- package/src/settings/settings-validation.ts +443 -0
- package/src/snapshot/session-paths.ts +84 -0
- package/src/{snapshot-apply.ts → snapshot/snapshot-apply.ts} +3 -3
- package/src/{snapshot-codec.ts → snapshot/snapshot-codec.ts} +2 -2
- package/src/{snapshot-transaction.ts → snapshot/snapshot-transaction.ts} +5 -4
- package/src/snapshot/snapshot-types.ts +38 -0
- package/src/{snapshot.ts → snapshot/snapshot.ts} +39 -20
- package/src/state/json-file.ts +20 -0
- package/src/{lock.ts → state/lock.ts} +3 -2
- package/src/{operation-availability.ts → state/operation-availability.ts} +2 -2
- package/src/state/state-types.ts +20 -0
- package/src/state/sync-state-store.ts +62 -0
- package/src/sync/automatic-sync.ts +103 -0
- package/src/{remote-snapshot.ts → sync/remote-snapshot.ts} +27 -4
- package/src/{setup-switch.ts → sync/setup-switch.ts} +6 -7
- package/src/sync/signals.ts +10 -0
- package/src/sync/startup-check.ts +128 -0
- package/src/{sync-decision.ts → sync/sync-decision.ts} +6 -3
- package/src/sync/sync-error-guidance.ts +53 -0
- package/src/sync/sync-inspection.ts +51 -0
- package/src/sync/sync-loaders.ts +54 -0
- package/src/{sync-operations.ts → sync/sync-mutations.ts} +41 -330
- package/src/sync/sync-operations.ts +12 -0
- package/src/{sync-policy.ts → sync/sync-policy.ts} +2 -2
- package/src/sync/sync-queries.ts +235 -0
- package/src/{sync-state.ts → sync/sync-state.ts} +5 -4
- package/src/sync-extension.ts +64 -708
- package/src/sync.ts +8 -8
- package/src/types.ts +47 -284
- package/src/ui/automatic-sync-summary.ts +6 -0
- package/src/{cancellable-operation.ts → ui/cancellable-operation.ts} +4 -4
- package/src/{file-selection.ts → ui/file-selection.ts} +5 -3
- package/src/{manager-attention.ts → ui/manager-attention.ts} +5 -1
- package/src/{manager-recovery.ts → ui/manager-recovery.ts} +6 -2
- package/src/{manager-state.ts → ui/manager-state.ts} +35 -14
- package/src/ui/manager-ui.ts +386 -0
- package/src/{remote-selection-ui.ts → ui/remote-selection-ui.ts} +21 -13
- package/src/{secret-input.ts → ui/secret-input.ts} +22 -4
- package/src/{settings-ui.ts → ui/settings-ui.ts} +42 -11
- package/src/ui/setup/git-ui.ts +293 -0
- package/src/{s3-credentials-ui.ts → ui/setup/s3-credentials-ui.ts} +13 -21
- package/src/ui/setup/s3-ui.ts +217 -0
- package/src/ui/setup/setup-actions.ts +127 -0
- package/src/ui/setup/setup-location-ui.ts +167 -0
- package/src/ui/setup/setup-name-ui.ts +34 -0
- package/src/ui/setup/setup-prompts.ts +92 -0
- package/src/ui/setup/setup-review.ts +70 -0
- package/src/ui/setup/setup-switcher.ts +181 -0
- package/src/ui/setup/setup-wizard.ts +39 -0
- package/src/ui/setup/text-input.ts +78 -0
- package/src/ui/setup/webdav-ui.ts +330 -0
- package/src/{storage-connections-ui.ts → ui/storage-connections-ui.ts} +99 -69
- package/src/{sync-attention.ts → ui/sync-attention.ts} +75 -6
- package/src/{sync-format.ts → ui/sync-format.ts} +7 -13
- package/src/{sync-resolution-ui.ts → ui/sync-resolution-ui.ts} +4 -3
- package/src/{sync-setups-ui.ts → ui/sync-setups-ui.ts} +23 -10
- package/src/ui/terminal-text.ts +4 -0
- package/dist/chunks/chunk-3NDD5QPM.ts.map +0 -7
- package/dist/chunks/chunk-4F3W4CSC.ts.map +0 -7
- package/dist/chunks/chunk-4U6AFLJB.ts.map +0 -7
- package/dist/chunks/chunk-5MQ76BK5.ts.map +0 -7
- package/dist/chunks/chunk-5WJNWFTG.ts.map +0 -7
- package/dist/chunks/chunk-APZVBSM6.ts.map +0 -7
- package/dist/chunks/chunk-BHJUISB4.ts.map +0 -7
- package/dist/chunks/chunk-EWX3TPLQ.ts.map +0 -7
- package/dist/chunks/chunk-F5QL2GPY.ts.map +0 -7
- package/dist/chunks/chunk-FR6CVXAL.ts.map +0 -7
- package/dist/chunks/chunk-HGV24P4T.ts.map +0 -7
- package/dist/chunks/chunk-JNOOSPEW.ts +0 -82
- package/dist/chunks/chunk-JNOOSPEW.ts.map +0 -7
- package/dist/chunks/chunk-LJDSHNS3.ts.map +0 -7
- package/dist/chunks/chunk-LONPFFNP.ts.map +0 -7
- package/dist/chunks/chunk-RGJ6SOYR.ts.map +0 -7
- package/dist/chunks/chunk-W64NEHXT.ts +0 -167
- package/dist/chunks/chunk-W64NEHXT.ts.map +0 -7
- package/dist/chunks/chunk-YQ6UW7IF.ts.map +0 -7
- package/dist/chunks/file-selection-4UABOP44.ts.map +0 -7
- package/dist/chunks/git-backend-E3UOUUOM.ts.map +0 -7
- package/dist/chunks/manager-result-dispatcher-RNRQA3PW.ts +0 -18
- package/dist/chunks/manager-ui-QO2P4V3Z.ts +0 -2757
- package/dist/chunks/manager-ui-QO2P4V3Z.ts.map +0 -7
- package/dist/chunks/remote-selection-ui-LHSAGKGA.ts +0 -17
- package/dist/chunks/s3-backend-3QZGO2EF.ts.map +0 -7
- package/dist/chunks/sync-operations-MPAFVVHA.ts.map +0 -7
- package/dist/chunks/webdav-backend-ZD5RHRIU.ts.map +0 -7
- package/src/config.ts +0 -910
- package/src/git-ui.ts +0 -307
- package/src/manager-helpers.ts +0 -64
- package/src/manager-ui.ts +0 -997
- package/src/webdav-ui.ts +0 -421
- /package/dist/chunks/{manager-result-dispatcher-RNRQA3PW.ts.map → manager-result-dispatcher-U23ODD32.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-LHSAGKGA.ts.map → remote-selection-ui-ZE3TY67S.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-X3W3FALZ.ts.map → setup-switch-IS2PEZ3J.ts.map} +0 -0
- /package/dist/chunks/{snapshot-WBSV4MQG.ts.map → snapshot-HKEWCVK6.ts.map} +0 -0
- /package/dist/chunks/{sync-state-36H7ULG2.ts.map → sync-inspection-FEP4L5TR.ts.map} +0 -0
- /package/src/{git-runner.ts → backends/git/git-runner.ts} +0 -0
- /package/src/{config-errors.ts → settings/config-errors.ts} +0 -0
- /package/src/{config-file.ts → settings/config-file.ts} +0 -0
- /package/src/{snapshot-paths.ts → snapshot/snapshot-paths.ts} +0 -0
- /package/src/{lock-policy.ts → state/lock-policy.ts} +0 -0
- /package/src/{lockfile-fs.ts → state/lockfile-fs.ts} +0 -0
- /package/src/{state-directory.ts → state/state-directory.ts} +0 -0
- /package/src/{sync-errors.ts → sync/sync-errors.ts} +0 -0
- /package/src/{manager-result-dispatcher.ts → ui/manager-result-dispatcher.ts} +0 -0
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/s3-backend.ts", "../../src/s3-client.ts"],
|
|
4
|
-
"sourcesContent": ["import { createHash } from \"node:crypto\";\nimport { sessionTokenWarnings } from \"./config.js\";\nimport { encodeKey, posixJoin } from \"./paths.js\";\nimport { S3Client, S3ObjectAlreadyExistsError } from \"./s3-client.js\";\nimport { decodeSnapshot, encodeSnapshot } from \"./snapshot-codec.js\";\nimport {\n\ttype BackendDiagnostic,\n\ttype ExpectedRemoteHead,\n\ttype PublishSnapshotOptions,\n\ttype PublishSnapshotResult,\n\ttype RemoteHead,\n\ttype RemoteHistoryEntry,\n\ttype SyncBackend,\n\tSyncBackendConflictError,\n\tSyncBackendPublicationOutcomeUnknownError,\n} from \"./sync-backend.js\";\nimport { portableSnapshotSelection } from \"./sync-policy.js\";\nimport type { LatestPointer, RemoteObject, ResolvedS3Backend, Snapshot } from \"./types.js\";\n\nconst VERSION = 1;\nconst POST_COMMIT_TIMEOUT_MS = 30_000;\n\nexport class S3SyncBackend implements SyncBackend {\n\treadonly identity: string;\n\treadonly destination: string;\n\treadonly capability = \"read-check-write-verify\" as const;\n\tprivate readonly checksums = new Map<string, string>();\n\n\tconstructor(\n\t\tprivate readonly config: ResolvedS3Backend,\n\t\tprivate readonly postCommitTimeoutMs = POST_COMMIT_TIMEOUT_MS,\n\t) {\n\t\tassertSafeDestination(config);\n\t\tthis.identity = s3BackendIdentity(config);\n\t\tthis.destination = s3Destination(config);\n\t}\n\n\tsameRevision(left: string, right: string) {\n\t\treturn left === right;\n\t}\n\n\tasync readHead(signal?: AbortSignal): Promise<RemoteHead | undefined> {\n\t\tconst object = await new S3Client(this.config, signal).getJson<LatestPointer>(\n\t\t\tlatestKey(this.config),\n\t\t);\n\t\tthrowIfAborted(signal);\n\t\tif (object.missing) return undefined;\n\t\tconst pointer = requirePointer(\n\t\t\tobject.value,\n\t\t\t\"Remote latest pointer is malformed.\",\n\t\t\tthis.config.destination.namespace,\n\t\t);\n\t\tthis.registerChecksum(pointer.snapshot, pointer.sha256);\n\t\treturn remoteHead(pointer, this.identity, object.etag);\n\t}\n\n\tasync readSnapshot(reference: string, signal?: AbortSignal): Promise<Snapshot> {\n\t\tconst expectedChecksum =\n\t\t\tthis.checksums.get(reference) ?? (await this.resolveChecksum(reference, signal));\n\t\tconst object = await new S3Client(this.config, signal).getBuffer(\n\t\t\tsnapshotKey(this.config, reference),\n\t\t);\n\t\tthrowIfAborted(signal);\n\t\tif (!object.value) throw new Error(`Snapshot not found: ${reference}`);\n\t\tif (expectedChecksum && sha256(object.value) !== expectedChecksum) {\n\t\t\tthrow new Error(\"Remote snapshot checksum mismatch.\");\n\t\t}\n\t\tconst snapshot = await decodeSnapshot(object.value, { signal });\n\t\tif (snapshot.id !== reference || snapshot.profile !== this.config.destination.namespace) {\n\t\t\tthrow new Error(\"Remote snapshot identity mismatch.\");\n\t\t}\n\t\tvalidateSnapshotBundle(snapshot);\n\t\treturn snapshot;\n\t}\n\n\tasync publishSnapshot(\n\t\tsnapshot: Snapshot,\n\t\texpected: ExpectedRemoteHead,\n\t\toptions: PublishSnapshotOptions = {},\n\t): Promise<PublishSnapshotResult> {\n\t\tthrowIfAborted(options.signal);\n\t\tassertSnapshotIdentity(snapshot, this.config.destination.namespace);\n\t\tconst stagedKey = snapshotKey(this.config, snapshot.id);\n\t\tconst encoded = await encodeSnapshot(snapshot);\n\t\tthrowIfAborted(options.signal);\n\t\tconst pointer = pointerFor(this.config, snapshot, sha256(encoded));\n\t\tconst cancellableClient = new S3Client(this.config, options.signal);\n\t\ttry {\n\t\t\tawait cancellableClient.putBuffer(stagedKey, encoded, \"application/gzip\", {\n\t\t\t\tifAbsent: true,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof S3ObjectAlreadyExistsError)) throw error;\n\t\t\tconst existing = await cancellableClient.getBuffer(stagedKey);\n\t\t\tif (!existing.value || sha256(existing.value) !== pointer.sha256) {\n\t\t\t\tthrow new SyncBackendConflictError(\n\t\t\t\t\t`Immutable snapshot id already exists with different content: ${snapshot.id}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tconst currentObject = await cancellableClient.getJson<LatestPointer>(latestKey(this.config));\n\t\tthrowIfAborted(options.signal);\n\t\tlet current: RemoteHead | undefined;\n\t\tif (!currentObject.missing) {\n\t\t\tconst currentPointer = requirePointer(\n\t\t\t\tcurrentObject.value,\n\t\t\t\t\"Remote latest pointer is malformed.\",\n\t\t\t\tthis.config.destination.namespace,\n\t\t\t);\n\t\t\tthis.registerChecksum(currentPointer.snapshot, currentPointer.sha256);\n\t\t\tcurrent = remoteHead(currentPointer, this.identity, currentObject.etag);\n\t\t}\n\t\tif (!matchesExpected(current, expected)) {\n\t\t\tthrow new SyncBackendConflictError(\n\t\t\t\t\"Remote changed while pushing. Run /sync pull first, then retry.\",\n\t\t\t\t{ currentHead: current },\n\t\t\t);\n\t\t}\n\t\tthrowIfAborted(options.signal);\n\t\toptions.onCommit?.();\n\n\t\t// The active-head PUT is the publication boundary. Do not bind it or its\n\t\t// verification to a user-cancellation signal after the boundary begins.\n\t\tconst commitClient = new S3Client(this.config, AbortSignal.timeout(this.postCommitTimeoutMs));\n\t\ttry {\n\t\t\tawait commitClient.putJson(latestKey(this.config), pointer);\n\t\t} catch (error) {\n\t\t\tthrow new SyncBackendPublicationOutcomeUnknownError(\n\t\t\t\t`Remote publication outcome is unknown: ${errorMessage(error)}`,\n\t\t\t\t{ cause: error },\n\t\t\t);\n\t\t}\n\n\t\tlet verifiedObject: RemoteObject<LatestPointer>;\n\t\ttry {\n\t\t\tverifiedObject = await commitClient.getJson<LatestPointer>(latestKey(this.config));\n\t\t} catch (error) {\n\t\t\tthrow new SyncBackendPublicationOutcomeUnknownError(\n\t\t\t\t`Remote snapshot may be active, but publication could not be verified: ${errorMessage(error)}`,\n\t\t\t\t{ cause: error },\n\t\t\t);\n\t\t}\n\t\tlet verifiedPointer: LatestPointer;\n\t\ttry {\n\t\t\tverifiedPointer = requirePointer(\n\t\t\t\tverifiedObject.value,\n\t\t\t\t\"Remote latest pointer is malformed after publication.\",\n\t\t\t\tthis.config.destination.namespace,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthrow new SyncBackendPublicationOutcomeUnknownError(\n\t\t\t\t`Remote snapshot may be active, but publication verification was malformed: ${errorMessage(error)}`,\n\t\t\t\t{ cause: error },\n\t\t\t);\n\t\t}\n\t\tif (!samePointer(verifiedPointer, pointer)) {\n\t\t\tthrow new SyncBackendConflictError(\n\t\t\t\t\"Remote latest changed immediately after push. Run /sync status before continuing.\",\n\t\t\t\t{\n\t\t\t\t\tphase: \"after-commit\",\n\t\t\t\t\tcurrentHead: remoteHead(verifiedPointer, this.identity, verifiedObject.etag),\n\t\t\t\t\tcandidateMayHaveBeenActive: true,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\tthis.registerChecksum(verifiedPointer.snapshot, verifiedPointer.sha256);\n\t\tconst head = remoteHead(verifiedPointer, this.identity, verifiedObject.etag);\n\t\tconst warning = await this.updateHistorySafely(commitClient, pointer);\n\t\treturn { head, warnings: warning ? [warning] : [] };\n\t}\n\n\tasync listHistory(signal?: AbortSignal): Promise<RemoteHistoryEntry[]> {\n\t\tconst object = await new S3Client(this.config, signal).getJson<{\n\t\t\tversion: number;\n\t\t\tsnapshots: LatestPointer[];\n\t\t}>(historyKey(this.config));\n\t\tthrowIfAborted(signal);\n\t\tif (object.missing) return [];\n\t\tconst pointers = requireHistory(object.value, this.config.destination.namespace);\n\t\tfor (const pointer of pointers) {\n\t\t\tconst known = this.checksums.get(pointer.snapshot);\n\t\t\tif (known && known !== pointer.sha256) {\n\t\t\t\tthrow new Error(\"Remote history conflicts with an already observed snapshot checksum.\");\n\t\t\t}\n\t\t}\n\t\tfor (const pointer of pointers) this.registerChecksum(pointer.snapshot, pointer.sha256);\n\t\treturn pointers.map(remoteHistoryEntry);\n\t}\n\n\tasync diagnose(signal?: AbortSignal): Promise<BackendDiagnostic[]> {\n\t\tthrowIfAborted(signal);\n\t\treturn [\n\t\t\t{\n\t\t\t\tkey: \"s3-config\",\n\t\t\t\tlevel: \"info\",\n\t\t\t\tmessage: `s3 config: ok (${this.config.destination.bucket}/${storageRoot(this.config)})`,\n\t\t\t},\n\t\t\t...sessionTokenWarnings(this.config.profile).map((message) => ({\n\t\t\t\tkey: \"s3-session-token\",\n\t\t\t\tlevel: \"warning\" as const,\n\t\t\t\tmessage,\n\t\t\t})),\n\t\t];\n\t}\n\n\tprivate async resolveChecksum(reference: string, signal?: AbortSignal) {\n\t\tawait this.readHead(signal);\n\t\tconst headChecksum = this.checksums.get(reference);\n\t\tif (headChecksum) return headChecksum;\n\t\tawait this.listHistory(signal);\n\t\treturn this.checksums.get(reference);\n\t}\n\n\tprivate registerChecksum(reference: string, checksum: string) {\n\t\tconst known = this.checksums.get(reference);\n\t\tif (known && known !== checksum) {\n\t\t\tthrow new Error(\"Remote snapshot reference was rebound to a different checksum.\");\n\t\t}\n\t\tthis.checksums.set(reference, checksum);\n\t}\n\n\tprivate async updateHistorySafely(client: S3Client, pointer: LatestPointer) {\n\t\ttry {\n\t\t\tawait this.updateHistory(client, pointer);\n\t\t\treturn undefined;\n\t\t} catch (error) {\n\t\t\treturn `Remote snapshot is active, but history could not be updated: ${errorMessage(error)}. Run /sync doctor before relying on history.`;\n\t\t}\n\t}\n\n\tprivate async updateHistory(client: S3Client, pointer: LatestPointer) {\n\t\tconst object = await client.getJson<{ version: number; snapshots: LatestPointer[] }>(\n\t\t\thistoryKey(this.config),\n\t\t);\n\t\tconst snapshots = object.missing\n\t\t\t? []\n\t\t\t: requireHistory(object.value, this.config.destination.namespace);\n\t\tconst next = [\n\t\t\t...snapshots.filter((snapshot) => snapshot.snapshot !== pointer.snapshot),\n\t\t\tpointer,\n\t\t].slice(-100);\n\t\tawait client.putJson(historyKey(this.config), { version: VERSION, snapshots: next });\n\t}\n}\n\nexport function latestKey(config: ResolvedS3Backend) {\n\treturn posixJoin(storageRoot(config), \"latest.json\");\n}\n\nexport function historyKey(config: ResolvedS3Backend) {\n\treturn posixJoin(storageRoot(config), \"history.json\");\n}\n\nexport function snapshotKey(config: ResolvedS3Backend, id: string) {\n\trequireSnapshotReference(id);\n\treturn posixJoin(storageRoot(config), \"snapshots\", `${id}.json.gz`);\n}\n\nexport function storageRoot(config: ResolvedS3Backend) {\n\treturn config.destination.prefix;\n}\n\nexport function pointerFor(\n\tconfig: ResolvedS3Backend,\n\tsnapshot: Snapshot,\n\tchecksum: string,\n): LatestPointer {\n\treturn {\n\t\tversion: VERSION,\n\t\tprofile: config.destination.namespace,\n\t\tsnapshot: snapshot.id,\n\t\tsha256: checksum,\n\t\tcreatedAt: snapshot.createdAt,\n\t\tmachine: snapshot.machine,\n\t\tsyncSessions:\n\t\t\tsnapshot.syncSessions === true ||\n\t\t\tsnapshot.files.some((file) => file.path.startsWith(\"sessions/\")),\n\t\t...(snapshot.selection === undefined ? {} : { selection: snapshot.selection }),\n\t};\n}\n\nexport function s3BackendIdentity(config: ResolvedS3Backend) {\n\tconst destination = JSON.stringify([\n\t\tsecretFreeEndpoint(config.profile.endpoint),\n\t\ttrimSlashes(config.destination.bucket),\n\t\ttrimSlashes(config.destination.prefix),\n\t]);\n\treturn `s3:${sha256(Buffer.from(destination))}`;\n}\n\nfunction s3Destination(config: ResolvedS3Backend) {\n\tlet host = secretFreeEndpoint(config.profile.endpoint);\n\ttry {\n\t\thost = new URL(host).hostname;\n\t} catch {\n\t\thost = \"invalid S3 endpoint\";\n\t}\n\treturn `${host} \u00B7 ${config.destination.bucket}/${storageRoot(config)}`;\n}\n\nfunction secretFreeEndpoint(value: string) {\n\tconst normalized = value.trim();\n\ttry {\n\t\tconst url = new URL(normalized);\n\t\turl.username = \"\";\n\t\turl.password = \"\";\n\t\treturn url.toString();\n\t} catch {\n\t\treturn normalized.replace(/\\/\\/[^/@\\s]+@/u, \"//\");\n\t}\n}\n\nfunction trimSlashes(value: string) {\n\treturn value.replace(/^\\/+|\\/+$/g, \"\");\n}\n\nfunction remoteHistoryEntry(pointer: LatestPointer): RemoteHistoryEntry {\n\treturn {\n\t\tsnapshotRef: pointer.snapshot,\n\t\tsnapshotId: pointer.snapshot,\n\t\tcreatedAt: pointer.createdAt,\n\t\tmachine: pointer.machine,\n\t\tsyncSessions: pointer.syncSessions === true,\n\t};\n}\n\nfunction remoteHead(pointer: LatestPointer, identity: string, etag?: string): RemoteHead {\n\treturn {\n\t\tsnapshotRef: pointer.snapshot,\n\t\tsnapshotId: pointer.snapshot,\n\t\trevision: `s3:${sha256(Buffer.from(canonicalJson([identity, etag ?? null, pointer])))}`,\n\t\tcreatedAt: pointer.createdAt,\n\t\tmachine: pointer.machine,\n\t\tsyncSessions: pointer.syncSessions === true,\n\t\t...(pointer.selection === undefined ? {} : { selection: pointer.selection }),\n\t};\n}\n\nfunction samePointer(left: LatestPointer, right: LatestPointer) {\n\treturn canonicalJson(left) === canonicalJson(right);\n}\n\nfunction canonicalJson(value: unknown) {\n\treturn JSON.stringify(canonicalValue(value));\n}\n\nfunction canonicalValue(value: unknown): unknown {\n\tif (Array.isArray(value)) return value.map(canonicalValue);\n\tif (!value || typeof value !== \"object\") return value;\n\treturn Object.fromEntries(\n\t\tObject.keys(value)\n\t\t\t.sort()\n\t\t\t.map((key) => [key, canonicalValue((value as Record<string, unknown>)[key])]),\n\t);\n}\n\nfunction matchesExpected(head: RemoteHead | undefined, expected: ExpectedRemoteHead) {\n\tif (expected.kind === \"missing\") return head === undefined;\n\treturn head?.revision === expected.revision;\n}\n\nfunction requirePointer(\n\tvalue: LatestPointer | undefined,\n\tmessage: string,\n\texpectedProfile: string,\n) {\n\tif (\n\t\t!value ||\n\t\tvalue.version !== VERSION ||\n\t\tvalue.profile !== expectedProfile ||\n\t\ttypeof value.snapshot !== \"string\" ||\n\t\t!isSafeSnapshotReference(value.snapshot) ||\n\t\ttypeof value.sha256 !== \"string\" ||\n\t\t!/^[0-9a-f]{64}$/.test(value.sha256) ||\n\t\ttypeof value.createdAt !== \"string\" ||\n\t\t!isSafeMetadata(value.createdAt, 64) ||\n\t\ttypeof value.machine !== \"string\" ||\n\t\t!isSafeMetadata(value.machine, 256) ||\n\t\t(value.syncSessions !== undefined && typeof value.syncSessions !== \"boolean\")\n\t) {\n\t\tthrow new Error(message);\n\t}\n\tif (value.selection !== undefined) portableSnapshotSelection(value.selection);\n\treturn value;\n}\n\nfunction requireHistory(\n\tvalue: { version: number; snapshots: LatestPointer[] } | undefined,\n\texpectedProfile: string,\n) {\n\tif (!value || value.version !== VERSION || !Array.isArray(value.snapshots)) {\n\t\tthrow new Error(\"Remote history is malformed.\");\n\t}\n\tconst pointers = value.snapshots.map((pointer) =>\n\t\trequirePointer(pointer, \"Remote history entry is malformed.\", expectedProfile),\n\t);\n\tconst references = new Set<string>();\n\tfor (const pointer of pointers) {\n\t\tif (references.has(pointer.snapshot)) {\n\t\t\tthrow new Error(\"Remote history contains duplicate snapshot references.\");\n\t\t}\n\t\treferences.add(pointer.snapshot);\n\t}\n\treturn pointers;\n}\n\nfunction assertSnapshotIdentity(snapshot: Snapshot, expectedProfile: string) {\n\tif (\n\t\tsnapshot.version !== VERSION ||\n\t\tsnapshot.profile !== expectedProfile ||\n\t\t!isSafeSnapshotReference(snapshot.id) ||\n\t\t!isSafeMetadata(snapshot.createdAt, 64) ||\n\t\t!isSafeMetadata(snapshot.machine, 256) ||\n\t\t!Array.isArray(snapshot.files)\n\t) {\n\t\tthrow new Error(\"Invalid snapshot identity for S3 publication.\");\n\t}\n}\n\nfunction validateSnapshotBundle(snapshot: Snapshot) {\n\tconst paths = new Set<string>();\n\tfor (const file of snapshot.files) {\n\t\tif (\n\t\t\t!file ||\n\t\t\ttypeof file.path !== \"string\" ||\n\t\t\ttypeof file.contentBase64 !== \"string\" ||\n\t\t\ttypeof file.sha256 !== \"string\" ||\n\t\t\t!/^[0-9a-f]{64}$/.test(file.sha256) ||\n\t\t\tpaths.has(file.path)\n\t\t) {\n\t\t\tthrow new Error(\"Remote snapshot bundle is malformed.\");\n\t\t}\n\t\tconst content = Buffer.from(file.contentBase64, \"base64\");\n\t\tif (content.toString(\"base64\") !== file.contentBase64 || sha256(content) !== file.sha256) {\n\t\t\tthrow new Error(\"Remote snapshot file checksum mismatch.\");\n\t\t}\n\t\tpaths.add(file.path);\n\t}\n}\n\nfunction assertSafeDestination(config: ResolvedS3Backend) {\n\tfor (const [label, value, allowEmpty] of [\n\t\t[\"bucket\", config.destination.bucket, false],\n\t\t[\"prefix\", config.destination.prefix, true],\n\t\t[\"namespace\", config.destination.namespace, false],\n\t] as const) {\n\t\tif (\n\t\t\t(!allowEmpty && value.length === 0) ||\n\t\t\tvalue.includes(\"\\\\\") ||\n\t\t\thasControlCharacter(value) ||\n\t\t\tvalue.split(\"/\").some((segment) => segment === \".\" || segment === \"..\")\n\t\t) {\n\t\t\tthrow new Error(`Invalid S3 storage location ${label}.`);\n\t\t}\n\t}\n}\n\nfunction requireSnapshotReference(reference: string) {\n\tif (!isSafeSnapshotReference(reference)) {\n\t\tthrow new Error(\"Invalid S3 snapshot reference.\");\n\t}\n}\n\nfunction isSafeSnapshotReference(reference: string) {\n\treturn (\n\t\treference.length > 0 &&\n\t\treference.length <= 512 &&\n\t\treference !== \".\" &&\n\t\treference !== \"..\" &&\n\t\t!reference.includes(\"/\") &&\n\t\t!reference.includes(\"\\\\\") &&\n\t\t!hasControlCharacter(reference)\n\t);\n}\n\nfunction isSafeMetadata(value: string, maxLength: number) {\n\treturn value.length > 0 && value.length <= maxLength && !hasControlCharacter(value);\n}\n\nfunction hasControlCharacter(value: string) {\n\treturn [...value].some((character) => {\n\t\tconst code = character.codePointAt(0) ?? 0;\n\t\treturn code < 0x20 || code === 0x7f;\n\t});\n}\n\nfunction throwIfAborted(signal?: AbortSignal) {\n\tif (!signal?.aborted) return;\n\tthrow signal.reason instanceof Error\n\t\t? signal.reason\n\t\t: new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n\nfunction sha256(value: Buffer) {\n\treturn createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction errorMessage(error: unknown) {\n\treturn 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 \"./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\treturn date.toISOString().replace(/[:-]|\\.\\d{3}/g, \"\");\n}\n\nfunction isCloudflareR2Endpoint(endpoint: string | undefined) {\n\tconst value = endpoint?.trim();\n\tif (!value) return false;\n\ttry {\n\t\tconst hostname = new URL(value).hostname.toLowerCase();\n\t\treturn (\n\t\t\thostname === \"r2.cloudflarestorage.com\" || hostname.endsWith(\".r2.cloudflarestorage.com\")\n\t\t);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport class S3ObjectAlreadyExistsError extends Error {\n\tconstructor(readonly key: string) {\n\t\tsuper(`S3 object already exists: ${key}`);\n\t\tthis.name = \"S3ObjectAlreadyExistsError\";\n\t}\n}\n\nexport class S3Client {\n\tprivate config: ResolvedS3Backend;\n\tprivate endpoint: URL;\n\tprivate signal?: AbortSignal;\n\tprivate requestTimeoutMs: number;\n\tprivate omitSessionTokenAfterRejection = false;\n\n\tconstructor(\n\t\tconfig: ResolvedS3Backend,\n\t\tsignal?: AbortSignal,\n\t\trequestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS,\n\t) {\n\t\tthis.config = config;\n\t\tthis.endpoint = new URL(config.profile.endpoint);\n\t\tthis.signal = signal;\n\t\tthis.requestTimeoutMs = requestTimeoutMs;\n\t}\n\n\tasync getJson<T>(key: string): Promise<RemoteObject<T>> {\n\t\tconst maxAttempts = 3;\n\t\tlet lastError: unknown;\n\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\tconst object = await this.request(\"GET\", key);\n\t\t\tif (object.status === 404) return { missing: true };\n\t\t\tif (!object.ok) {\n\t\t\t\tthrow new Error(`S3 GET failed (${object.status}): ${await this.readErrorText(object)}`);\n\t\t\t}\n\t\t\tconst body = await readBoundedText(object, MAX_JSON_RESPONSE_BYTES, \"S3 JSON response\");\n\t\t\t// R2 can intermittently return an empty 200 body (read-after-write\n\t\t\t// inconsistency on a long-lived keep-alive connection), which makes\n\t\t\t// response.json() throw \"JSON Parse error: Unexpected EOF\" under Bun.\n\t\t\t// Retry so the transient blip is absorbed instead of surfacing as a\n\t\t\t// \"pi-sync auto sync skipped\" warning on every session start.\n\t\t\tif (body.length > 0) {\n\t\t\t\treturn {\n\t\t\t\t\tvalue: JSON.parse(body) as T,\n\t\t\t\t\tetag: normalizeEtag(object.headers.get(\"etag\")),\n\t\t\t\t\tmissing: false,\n\t\t\t\t};\n\t\t\t}\n\t\t\tlastError = new Error(`S3 GET returned an empty body for ${key}`);\n\t\t\tif (attempt < maxAttempts) {\n\t\t\t\tawait sleep(250 * attempt, undefined, { signal: this.signal });\n\t\t\t}\n\t\t}\n\t\tthrow lastError;\n\t}\n\n\tasync getBuffer(key: string): Promise<RemoteObject<Buffer>> {\n\t\tconst maxAttempts = 3;\n\t\tlet lastError: unknown;\n\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\tconst object = await this.request(\"GET\", key);\n\t\t\tif (object.status === 404) return { missing: true };\n\t\t\tif (!object.ok) {\n\t\t\t\tthrow new Error(`S3 GET failed (${object.status}): ${await this.readErrorText(object)}`);\n\t\t\t}\n\t\t\tconst buffer = await readBoundedBuffer(\n\t\t\t\tobject,\n\t\t\t\tMAX_SNAPSHOT_RESPONSE_BYTES,\n\t\t\t\t\"S3 snapshot response\",\n\t\t\t);\n\t\t\t// R2 can intermittently return an empty 200 body on a long-lived\n\t\t\t// keep-alive connection (same root cause as the getJson retry\n\t\t\t// above). getBuffer is only used for snapshot .json.gz payloads,\n\t\t\t// which are always non-empty, so an empty body is a transient\n\t\t\t// blip, not a legitimate response. Retry so the checksum guard\n\t\t\t// downstream doesn't surface it as \"Remote snapshot checksum\n\t\t\t// mismatch\".\n\t\t\tif (buffer.length > 0) {\n\t\t\t\treturn { value: buffer, etag: normalizeEtag(object.headers.get(\"etag\")), missing: false };\n\t\t\t}\n\t\t\tlastError = new Error(`S3 GET returned an empty body for ${key}`);\n\t\t\tif (attempt < maxAttempts) {\n\t\t\t\tawait sleep(250 * attempt, undefined, { signal: this.signal });\n\t\t\t}\n\t\t}\n\t\tthrow lastError;\n\t}\n\n\tasync putJson(key: string, value: unknown) {\n\t\tconst body = Buffer.from(JSON.stringify(value, null, \"\\t\"), \"utf8\");\n\t\tawait this.putBuffer(key, body, \"application/json\");\n\t}\n\n\tasync putBuffer(\n\t\tkey: string,\n\t\tbody: Buffer,\n\t\tcontentType: string,\n\t\toptions: { ifAbsent?: boolean } = {},\n\t) {\n\t\tconst headers: Record<string, string> = { \"content-type\": contentType };\n\t\tif (options.ifAbsent) headers[\"if-none-match\"] = \"*\";\n\t\tconst response = await this.request(\"PUT\", key, body, headers);\n\t\tif (options.ifAbsent && response.status === 412) {\n\t\t\tthrow new S3ObjectAlreadyExistsError(key);\n\t\t}\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`S3 PUT failed (${response.status}): ${await this.readErrorText(response)}`);\n\t\t}\n\t}\n\n\tprivate async request(\n\t\tmethod: \"GET\" | \"PUT\",\n\t\tkey: string,\n\t\tbody?: Buffer,\n\t\textraHeaders: Record<string, string> = {},\n\t) {\n\t\tconst url = new URL(this.endpoint.toString());\n\t\turl.pathname = posixJoin(url.pathname, this.config.destination.bucket, encodeKey(key));\n\t\tconst send = async (sessionToken: string | undefined) => {\n\t\t\tconst transportSignal = this.transportSignal();\n\t\t\tconst headers = await signedHeaders({\n\t\t\t\tmethod,\n\t\t\t\turl,\n\t\t\t\tbody,\n\t\t\t\textraHeaders,\n\t\t\t\taccessKeyId: this.config.profile.accessKeyId,\n\t\t\t\tsecretAccessKey: this.config.profile.secretAccessKey,\n\t\t\t\tsessionToken,\n\t\t\t\tregion: this.config.profile.region,\n\t\t\t});\n\t\t\ttry {\n\t\t\t\treturn await fetch(url, {\n\t\t\t\t\tmethod,\n\t\t\t\t\theaders,\n\t\t\t\t\tbody: body ? new Uint8Array(body) : undefined,\n\t\t\t\t\tsignal: transportSignal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof Error && error.name === \"AbortError\") throw error;\n\t\t\t\tif (error instanceof Error && error.name === \"TimeoutError\") {\n\t\t\t\t\tthrow new Error(\"S3 request timed out.\", { cause: error });\n\t\t\t\t}\n\t\t\t\tthrow new Error(`S3 request failed: ${this.redact(errorMessage(error))}`, { cause: error });\n\t\t\t}\n\t\t};\n\t\tconst sessionToken = this.omitSessionTokenAfterRejection\n\t\t\t? undefined\n\t\t\t: this.config.profile.sessionToken;\n\t\tconst response = await send(sessionToken);\n\t\tif (!(await this.shouldRetryWithoutSessionToken(response, sessionToken))) return response;\n\n\t\tconst retry = await send(undefined);\n\t\tif (retry.ok || retry.status === 404) this.omitSessionTokenAfterRejection = true;\n\t\treturn retry;\n\t}\n\n\tprivate transportSignal() {\n\t\tconst timeout = AbortSignal.timeout(this.requestTimeoutMs);\n\t\treturn this.signal ? AbortSignal.any([this.signal, timeout]) : timeout;\n\t}\n\n\tprivate async shouldRetryWithoutSessionToken(\n\t\tresponse: Response,\n\t\tsessionToken: string | undefined,\n\t) {\n\t\tif (\n\t\t\t!sessionToken ||\n\t\t\t!isCloudflareR2Endpoint(this.config.profile.endpoint) ||\n\t\t\tresponse.ok ||\n\t\t\tresponse.status !== 400\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\treturn isSecurityTokenInvalidArgument(\n\t\t\tawait readBoundedText(response.clone(), MAX_ERROR_RESPONSE_BYTES, \"S3 error response\"),\n\t\t);\n\t}\n\n\tprivate async readErrorText(response: Response) {\n\t\ttry {\n\t\t\treturn this.redact(\n\t\t\t\tawait readBoundedText(response, MAX_ERROR_RESPONSE_BYTES, \"S3 error response\"),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\treturn this.redact(errorMessage(error));\n\t\t}\n\t}\n\n\tprivate redact(value: string) {\n\t\tlet redacted = value;\n\t\tlet endpointUsername: string | undefined;\n\t\tlet endpointPassword: string | undefined;\n\t\tlet endpointQueryValues: string[] = [];\n\t\ttry {\n\t\t\tconst endpoint = new URL(this.config.profile.endpoint);\n\t\t\tendpointUsername = endpoint.username;\n\t\t\tendpointPassword = endpoint.password;\n\t\t\tendpointQueryValues = [...endpoint.searchParams.values()];\n\t\t} catch {\n\t\t\t// The constructor already validates normal runtime endpoints.\n\t\t}\n\t\tfor (const secret of [\n\t\t\tthis.config.profile.accessKeyId,\n\t\t\tthis.config.profile.secretAccessKey,\n\t\t\tthis.config.profile.sessionToken,\n\t\t\tendpointUsername,\n\t\t\tendpointPassword,\n\t\t\t...endpointQueryValues,\n\t\t]) {\n\t\t\tif (secret) redacted = redacted.replaceAll(secret, \"[REDACTED]\");\n\t\t}\n\t\treturn redacted;\n\t}\n}\n\nasync function readBoundedText(response: Response, limit: number, label: string) {\n\treturn (await readBoundedBuffer(response, limit, label)).toString(\"utf8\");\n}\n\nasync function readBoundedBuffer(response: Response, limit: number, label: string) {\n\tconst contentLength = Number(response.headers.get(\"content-length\"));\n\tif (Number.isFinite(contentLength) && contentLength > limit) {\n\t\tthrow new Error(`${label} exceeds the ${limit}-byte limit.`);\n\t}\n\tif (!response.body) return Buffer.alloc(0);\n\tconst reader = response.body.getReader();\n\tconst chunks: Buffer[] = [];\n\tlet total = 0;\n\ttry {\n\t\twhile (true) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) break;\n\t\t\ttotal += value.byteLength;\n\t\t\tif (total > limit) {\n\t\t\t\tawait reader.cancel().catch(() => undefined);\n\t\t\t\tthrow new Error(`${label} exceeds the ${limit}-byte limit.`);\n\t\t\t}\n\t\t\tchunks.push(Buffer.from(value));\n\t\t}\n\t} finally {\n\t\treader.releaseLock();\n\t}\n\treturn Buffer.concat(chunks, total);\n}\n\nfunction errorMessage(error: unknown) {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nasync function signedHeaders(input: {\n\tmethod: string;\n\turl: URL;\n\tbody?: Buffer;\n\textraHeaders: Record<string, string>;\n\taccessKeyId: string;\n\tsecretAccessKey: string;\n\tsessionToken?: string;\n\tregion: string;\n}) {\n\tconst now = new Date();\n\tconst amzDate = iso8601Basic(now);\n\tconst dateStamp = amzDate.slice(0, 8);\n\tconst payloadHash = sha256(input.body ?? Buffer.alloc(0));\n\tconst headers: Record<string, string> = {\n\t\t...lowercaseKeys(input.extraHeaders),\n\t\thost: input.url.host,\n\t\t\"x-amz-content-sha256\": payloadHash,\n\t\t\"x-amz-date\": amzDate,\n\t};\n\tif (input.sessionToken) headers[\"x-amz-security-token\"] = input.sessionToken;\n\tconst signedHeaderNames = Object.keys(headers).sort();\n\tconst canonicalHeaders = signedHeaderNames\n\t\t.map((name) => `${name}:${headers[name]?.trim()}\\n`)\n\t\t.join(\"\");\n\tconst canonicalRequest = [\n\t\tinput.method,\n\t\tinput.url.pathname,\n\t\tinput.url.searchParams.toString(),\n\t\tcanonicalHeaders,\n\t\tsignedHeaderNames.join(\";\"),\n\t\tpayloadHash,\n\t].join(\"\\n\");\n\tconst scope = `${dateStamp}/${input.region}/s3/aws4_request`;\n\tconst stringToSign = [\n\t\t\"AWS4-HMAC-SHA256\",\n\t\tamzDate,\n\t\tscope,\n\t\tsha256(Buffer.from(canonicalRequest)),\n\t].join(\"\\n\");\n\tconst signingKey = hmac(\n\t\thmac(hmac(hmac(Buffer.from(`AWS4${input.secretAccessKey}`), dateStamp), input.region), \"s3\"),\n\t\t\"aws4_request\",\n\t);\n\tconst signature = createHmac(\"sha256\", signingKey).update(stringToSign).digest(\"hex\");\n\treturn {\n\t\t...headers,\n\t\tauthorization: `AWS4-HMAC-SHA256 Credential=${input.accessKeyId}/${scope}, SignedHeaders=${signedHeaderNames.join(\";\")}, Signature=${signature}`,\n\t};\n}\n\nfunction hmac(key: Buffer, value: string) {\n\treturn createHmac(\"sha256\", key).update(value).digest();\n}\n\nfunction sha256(value: Buffer) {\n\treturn createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction lowercaseKeys(value: Record<string, string>) {\n\treturn Object.fromEntries(Object.entries(value).map(([key, item]) => [key.toLowerCase(), item]));\n}\n\nfunction normalizeEtag(value: string | null) {\n\treturn value ?? undefined;\n}\n\nfunction isSecurityTokenInvalidArgument(text: string) {\n\treturn (\n\t\ttext.includes(\"<Code>InvalidArgument</Code>\") &&\n\t\ttext.includes(\"<Message>X-Amz-Security-Token</Message>\")\n\t);\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/sync-operations.ts", "../../src/snapshot-apply.ts", "../../src/sync-decision.ts"],
|
|
4
|
-
"sourcesContent": ["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { ExtensionCommandContext, ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { createSyncBackend, type SyncBackendFactory } from \"./backend-factory.js\";\nimport {\n\tloadConfig,\n\treadStateForConfig,\n\tsessionDirForApply,\n\tstateDir,\n\tsyncConfigReviewFingerprint,\n\tsyncSessionsWarnings,\n\twriteStateForConfig,\n} from \"./config.js\";\nimport { inspectLock, isLockGuardHeld, isStaleLock, withLock } from \"./lock.js\";\nimport {\n\tformatRemoteSelectionStatus,\n\treadSnapshotForHead,\n\trequireCompatibleRemoteSelection,\n} from \"./remote-snapshot.js\";\nimport {\n\tcreateSnapshot,\n\tfilterSnapshotForConfigPolicy,\n\tmergeRemotePreservedFiles,\n\tregenerateSnapshotIdentity,\n\tscanSnapshot,\n\tsessionSnapshotPathFromAbsolute,\n\tsnapshotIncludesSessions,\n\tsnapshotWithoutSessions,\n} from \"./snapshot.js\";\nimport { applySnapshot } from \"./snapshot-apply.js\";\nimport { encodeSnapshot } from \"./snapshot-codec.js\";\nimport {\n\texpectedRemoteHead,\n\ttype PublishSnapshotResult,\n\ttype RemoteHead,\n\ttype SyncBackend,\n} from \"./sync-backend.js\";\nimport { createSyncDecision } from \"./sync-decision.js\";\nimport {\n\tcountPreservedRemoteFiles,\n\terrorMessage,\n\tformatDiff,\n\tformatPullSummary,\n\tformatPushSummary,\n\tformatRollbackSummary,\n\tformatSnapshotOnlyDiff,\n\tpublicationCapabilityDescription,\n\tsafeTerminalText,\n} from \"./sync-format.js\";\nimport { inspectRemoteSelection, remoteSelectionMismatch } from \"./sync-policy.js\";\nimport {\n\tcanPullRemoteSessionsOnFirstSync,\n\tcanPullRemoteSettingsOnFirstSync,\n\tfileHashMap,\n\thasLocalChanges,\n\thasRemoteChanges,\n\tremoteChangedSinceState,\n\tsameHashes,\n\tshouldRefreshSyncedState,\n\tsnapshotHashesMatchState,\n\tsnapshotsMatch,\n\tsyncPolicyChanged,\n} from \"./sync-state.js\";\nimport type {\n\tAnySyncConfig,\n\tCommandOptions,\n\tSnapshot,\n\tSnapshotOptions,\n\tSyncState,\n} from \"./types.js\";\n\nconst STATUS_KEY = \"sync\";\nconst VERSION = 1;\nconst DEFAULT_PROFILE = \"default\";\nconst POST_LOCAL_COMMIT_TIMEOUT_MS = 30_000;\n\nexport class PublicationStatePersistenceError extends Error {\n\treadonly head: RemoteHead;\n\treadonly backupPath?: string;\n\n\tconstructor(head: RemoteHead, cause: unknown, backupPath?: string) {\n\t\tsuper(\n\t\t\t`Remote publication ${head.snapshotId} is active, but local sync state could not be saved${backupPath ? `; local backup: ${backupPath}` : \"\"}: ${errorMessage(cause)}`,\n\t\t\t{ cause },\n\t\t);\n\t\tthis.name = \"PublicationStatePersistenceError\";\n\t\tthis.head = head;\n\t\tthis.backupPath = backupPath;\n\t}\n}\n\nexport class RollbackPublicationError extends Error {\n\treadonly backupPath: string;\n\n\tconstructor(backupPath: string, cause: unknown) {\n\t\tsuper(\n\t\t\t`Rollback applied locally with backup ${backupPath}, but remote publication failed: ${errorMessage(cause)}`,\n\t\t\t{ cause },\n\t\t);\n\t\tthis.name = \"RollbackPublicationError\";\n\t\tthis.backupPath = backupPath;\n\t}\n}\n\ninterface PushInput {\n\tconfig: AnySyncConfig;\n\tstate: SyncState;\n\tlocal: Snapshot;\n\tbackend?: SyncBackend;\n}\n\nfunction backendFor(config: AnySyncConfig, factory: SyncBackendFactory) {\n\treturn factory(config);\n}\n\nexport async function status(\n\tctx: ExtensionCommandContext,\n\toptions: CommandOptions,\n\tfactory: SyncBackendFactory = createSyncBackend,\n) {\n\tconst config = await loadConfig(options.setup);\n\tthrowIfAborted(options.signal);\n\tctx.ui.setStatus(STATUS_KEY, `checking ${config.setupName}`);\n\tconst backend = await backendFor(config, factory);\n\tconst local = await createSnapshot(\n\t\tconfig.snapshotIdentity,\n\t\tsnapshotOptionsForContext(ctx, config),\n\t);\n\tthrowIfAborted(options.signal);\n\tconst state = await readStateForConfig(config);\n\tthrowIfAborted(options.signal);\n\tconst head = await backend.readHead(options.signal);\n\tthrowIfAborted(options.signal);\n\tconst selectionState = head\n\t\t? inspectRemoteSelection(config.include, { selection: head.selection, files: [] })\n\t\t: undefined;\n\tconst localChanged = hasLocalChanges(local, state, config);\n\n\tconst remoteText = head\n\t\t? `remote: ${head.snapshotId} from ${head.machine} at ${head.createdAt}`\n\t\t: \"remote: empty\";\n\tconst remoteChanged = remoteChangedSinceState(head, state, config, (left, right) =>\n\t\tbackend.sameRevision(left, right),\n\t);\n\tconst warnings = syncSessionsWarnings(config);\n\tctx.ui.setStatus(STATUS_KEY, undefined);\n\tctx.ui.notify(\n\t\t[\n\t\t\t`sync setup: ${config.setupName}`,\n\t\t\t`storage connection: ${config.connectionName}`,\n\t\t\t`storage location: ${safeTerminalText(backend.destination)}`,\n\t\t\t`publication safety: ${publicationCapabilityDescription(backend.capability)}`,\n\t\t\t`included content: ${config.include.join(\", \") || \"none\"}`,\n\t\t\t`sessions: ${config.include.includes(\"sessions\") ? \"included\" : \"excluded\"}`,\n\t\t\tremoteText,\n\t\t\tformatRemoteSelectionStatus(selectionState),\n\t\t\t`local files: ${local.files.length}`,\n\t\t\t`local changed since last sync: ${localChanged ? \"yes\" : \"no\"}`,\n\t\t\t`remote changed since last sync: ${remoteChanged ? \"yes\" : \"no\"}`,\n\t\t\t...warnings,\n\t\t].join(\"\\n\"),\n\t\tlocalChanged || remoteChanged || selectionState?.kind === \"different\" || warnings.length > 0\n\t\t\t? \"warning\"\n\t\t\t: \"info\",\n\t);\n}\n\nexport async function diff(\n\tctx: ExtensionCommandContext,\n\toptions: CommandOptions,\n\tfactory: SyncBackendFactory = createSyncBackend,\n) {\n\tconst config = await loadConfig(options.setup);\n\tthrowIfAborted(options.signal);\n\tctx.ui.setStatus(STATUS_KEY, `checking ${config.setupName}`);\n\tconst backend = await backendFor(config, factory);\n\tconst local = await createSnapshot(\n\t\tconfig.snapshotIdentity,\n\t\tsnapshotOptionsForContext(ctx, config),\n\t);\n\tthrowIfAborted(options.signal);\n\tconst { snapshot: remote, selectionState } = await readRemoteSnapshot(\n\t\tbackend,\n\t\tconfig,\n\t\toptions.signal,\n\t\t{ allowSelectionDifference: true },\n\t);\n\tthrowIfAborted(options.signal);\n\tctx.ui.setStatus(STATUS_KEY, undefined);\n\n\tconst warnings = syncSessionsWarnings(config);\n\tconst header = [\n\t\t`sync setup: ${config.setupName}`,\n\t\t`storage connection: ${config.connectionName}`,\n\t\t`storage location: ${safeTerminalText(backend.destination)}`,\n\t\t`included content: ${config.include.join(\", \") || \"none\"}`,\n\t\t`sessions: ${config.include.includes(\"sessions\") ? \"included\" : \"excluded\"}`,\n\t\tformatRemoteSelectionStatus(selectionState),\n\t\t...warnings,\n\t].join(\"\\n\");\n\tconst level = warnings.length > 0 || selectionState?.kind === \"different\" ? \"warning\" : \"info\";\n\tif (!remote) {\n\t\tctx.ui.notify(\n\t\t\t`${header}\\n\\n${formatSnapshotOnlyDiff(\"Remote is empty. Local push would upload\", local)}`,\n\t\t\tlevel,\n\t\t);\n\t\treturn;\n\t}\n\n\tctx.ui.notify(`${header}\\n\\n${formatDiff(local, remote)}`, level);\n}\n\nexport async function doctor(\n\tctx: ExtensionCommandContext,\n\toptions: CommandOptions,\n\tfactory: SyncBackendFactory = createSyncBackend,\n) {\n\tconst messages: string[] = [];\n\tlet level: \"info\" | \"warning\" = \"info\";\n\tlet snapshotOptions: SnapshotOptions = {};\n\tlet profile = DEFAULT_PROFILE;\n\tlet backend: SyncBackend | undefined;\n\tlet backendSummary: string[] = [];\n\n\ttry {\n\t\tconst config = await loadConfig(options.setup);\n\t\tthrowIfAborted(options.signal);\n\t\tbackend = await backendFor(config, factory);\n\t\tprofile = config.snapshotIdentity;\n\t\tsnapshotOptions = snapshotOptionsForContext(ctx, config);\n\t\tmessages.push(\n\t\t\t`config: ok (sync setup ${config.setupName})`,\n\t\t\t`included content: ${config.include.join(\", \") || \"none\"}`,\n\t\t\t`sessions: ${config.include.includes(\"sessions\") ? \"included\" : \"excluded\"}`,\n\t\t);\n\t\tbackendSummary = [\n\t\t\t`storage location: ${safeTerminalText(backend.destination)}`,\n\t\t\t`publication safety: ${publicationCapabilityDescription(backend.capability)}`,\n\t\t];\n\t\tconst warnings = syncSessionsWarnings(config);\n\t\tif (warnings.length > 0) {\n\t\t\tlevel = \"warning\";\n\t\t\tmessages.push(...warnings);\n\t\t}\n\t} catch (error) {\n\t\tthrowIfAborted(options.signal);\n\t\tlevel = \"warning\";\n\t\tmessages.push(`config: ${errorMessage(error)}`);\n\t}\n\n\tconst local = await createSnapshot(profile, snapshotOptions);\n\tthrowIfAborted(options.signal);\n\tconst secrets = scanSnapshot(local);\n\tif (secrets.length > 0) {\n\t\tlevel = \"warning\";\n\t\tmessages.push(\"secret scan: possible secrets found:\");\n\t\tmessages.push(...secrets.map((secret) => `- ${secret}`));\n\t} else {\n\t\tmessages.push(`secret scan: ok (${local.files.length} files checked)`);\n\t}\n\n\tconst lock = await inspectLock();\n\tthrowIfAborted(options.signal);\n\tif (lock.status === \"valid\" && isStaleLock(lock.lock)) {\n\t\tlevel = \"warning\";\n\t\tmessages.push(\n\t\t\t`lock: stale (pid ${lock.lock.pid}); run /sync unlock after verifying no sync is running`,\n\t\t);\n\t} else if (lock.status === \"valid\") {\n\t\tmessages.push(`lock: held by pid ${lock.lock.pid} since ${lock.lock.startedAt}`);\n\t} else if (lock.status === \"unreadable\") {\n\t\tlevel = \"warning\";\n\t\tmessages.push(\n\t\t\t\"lock: unreadable; use /sync unlock --stale only after verifying no sync is running\",\n\t\t);\n\t} else if (await isLockGuardHeld()) {\n\t\tthrowIfAborted(options.signal);\n\t\tlevel = \"warning\";\n\t\tmessages.push(\"lock: guard active while metadata is missing or still being initialized\");\n\t} else {\n\t\tmessages.push(\"lock: free\");\n\t}\n\n\tif (backend) {\n\t\tmessages.push(...backendSummary);\n\t\tconst diagnostics = await backend.diagnose(options.signal);\n\t\tthrowIfAborted(options.signal);\n\t\tfor (const diagnostic of diagnostics) {\n\t\t\tmessages.push(diagnostic.message);\n\t\t\tif (diagnostic.level !== \"info\") level = \"warning\";\n\t\t}\n\t}\n\tctx.ui.notify(messages.join(\"\\n\"), level);\n}\n\nexport async function push(\n\tctx: ExtensionCommandContext | ExtensionContext,\n\toptions: CommandOptions,\n\tinput?: PushInput,\n\tfactory: SyncBackendFactory = createSyncBackend,\n) {\n\tconst config = input?.config ?? (await loadConfig(options.setup));\n\tthrowIfAborted(options.signal);\n\tctx.ui.setStatus(STATUS_KEY, `pushing ${config.setupName}`);\n\tconst backend = input?.backend ?? (await backendFor(config, factory));\n\tconst state = input?.state ?? (await readStateForConfig(config));\n\tthrowIfAborted(options.signal);\n\tconst local =\n\t\tinput?.local ??\n\t\t(await createSnapshot(config.snapshotIdentity, snapshotOptionsForContext(ctx, config)));\n\tthrowIfAborted(options.signal);\n\n\tlet head = await backend.readHead(options.signal);\n\tlet remoteForUpload = await readRemoteSnapshotForUpload(\n\t\tbackend,\n\t\tconfig,\n\t\thead,\n\t\tstate,\n\t\toptions.signal,\n\t);\n\tif (\n\t\t!options.force &&\n\t\t!remoteForUpload &&\n\t\thead?.selection &&\n\t\tinspectRemoteSelection(config.include, { selection: head.selection, files: [] }).kind ===\n\t\t\t\"different\"\n\t) {\n\t\tremoteForUpload = await readSnapshotForHead(backend, head, options.signal);\n\t}\n\tif (remoteForUpload && !options.force) {\n\t\trequireCompatibleRemoteSelection(config, remoteForUpload);\n\t}\n\tif (\n\t\tremoteChangedSinceState(head, state, config, (left, right) =>\n\t\t\tbackend.sameRevision(left, right),\n\t\t) &&\n\t\t!options.force\n\t) {\n\t\tconst remoteForConflict = remoteForUpload\n\t\t\t? filterSnapshotForConfigPolicy(remoteForUpload, config)\n\t\t\t: undefined;\n\t\tif (!remoteForConflict || !snapshotHashesMatchState(remoteForConflict, state, config)) {\n\t\t\tthrow createSyncDecision({\n\t\t\t\tkind: head ? \"remote-or-policy-changed\" : \"remote-empty\",\n\t\t\t\tconfig,\n\t\t\t\tstate,\n\t\t\t\tlocal,\n\t\t\t\tremote: remoteForConflict,\n\t\t\t\tlocalChanged: hasLocalChanges(local, state, config),\n\t\t\t\tremoteChanged: true,\n\t\t\t\tdirectMessage:\n\t\t\t\t\t\"Remote or sync policy changed since last sync. Run /sync pull first or /sync push --force.\",\n\t\t\t});\n\t\t}\n\t}\n\n\tlet upload = await snapshotForUpload(\n\t\tbackend,\n\t\tconfig,\n\t\tlocal,\n\t\thead,\n\t\tremoteForUpload,\n\t\toptions.signal,\n\t);\n\tconst secrets = scanSnapshot(local);\n\tif (secrets.length > 0) {\n\t\tthrow new Error(\n\t\t\t`Refusing to push possible secrets:\\n${secrets.map((s) => `- ${s}`).join(\"\\n\")}`,\n\t\t);\n\t}\n\n\tif (!(await confirmPush(ctx, options, config, backend, local, upload, head, remoteForUpload))) {\n\t\treturn \"cancelled\" as const;\n\t}\n\n\tif (options.force) {\n\t\tconst refreshedHead = await backend.readHead(options.signal);\n\t\tif (!sameRemoteHead(backend, head, refreshedHead)) {\n\t\t\thead = refreshedHead;\n\t\t\tremoteForUpload = head\n\t\t\t\t? await backend.readSnapshot(head.snapshotRef, options.signal)\n\t\t\t\t: undefined;\n\t\t\tupload = await snapshotForUpload(\n\t\t\t\tbackend,\n\t\t\t\tconfig,\n\t\t\t\tlocal,\n\t\t\t\thead,\n\t\t\t\tremoteForUpload,\n\t\t\t\toptions.signal,\n\t\t\t);\n\t\t\tif (\n\t\t\t\t!(await confirmPush(\n\t\t\t\t\tctx,\n\t\t\t\t\toptions,\n\t\t\t\t\tconfig,\n\t\t\t\t\tbackend,\n\t\t\t\t\tlocal,\n\t\t\t\t\tupload,\n\t\t\t\t\thead,\n\t\t\t\t\tremoteForUpload,\n\t\t\t\t\t\"Remote changed during review. Push the refreshed plan?\",\n\t\t\t\t))\n\t\t\t) {\n\t\t\t\treturn \"cancelled\" as const;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst result = await backend.publishSnapshot(upload, expectedRemoteHead(head), {\n\t\tsignal: options.signal,\n\t\tonCommit: options.onCommit,\n\t});\n\ttry {\n\t\tawait writeStateForConfig(config, {\n\t\t\tversion: VERSION,\n\t\t\tprofile: config.snapshotIdentity,\n\t\t\tlastAppliedSnapshot: result.head.snapshotId,\n\t\t\tlastRemoteRevision: result.head.revision,\n\t\t\tlastFileHashes: fileHashMap(local),\n\t\t\tinclude: [...config.include],\n\t\t});\n\t} catch (error) {\n\t\tthrow new PublicationStatePersistenceError(result.head, error);\n\t}\n\tif (options.signal?.aborted) return;\n\tctx.ui.setStatus(STATUS_KEY, undefined);\n\tif (!options.silent) {\n\t\tctx.ui.notify(\n\t\t\t[\n\t\t\t\t`Pushed ${upload.files.length} files from sync setup \u201C${config.setupName}\u201D as ${result.head.snapshotId}.`,\n\t\t\t\t...result.warnings,\n\t\t\t]\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.join(\"\\n\"),\n\t\t\tresult.warnings.length > 0 ? \"warning\" : \"info\",\n\t\t);\n\t}\n\treturn \"applied\" as const;\n}\n\nexport async function pull(\n\tctx: ExtensionCommandContext | ExtensionContext,\n\toptions: CommandOptions,\n\tfactory: SyncBackendFactory = createSyncBackend,\n) {\n\tconst config = await loadConfig(options.setup);\n\tthrowIfAborted(options.signal);\n\tctx.ui.setStatus(STATUS_KEY, `pulling ${config.setupName}`);\n\tconst backend = await backendFor(config, factory);\n\tconst state = await readStateForConfig(config);\n\tthrowIfAborted(options.signal);\n\tconst local = await createSnapshot(\n\t\tconfig.snapshotIdentity,\n\t\tsnapshotOptionsForContext(ctx, config),\n\t);\n\tthrowIfAborted(options.signal);\n\tconst { head, snapshot: remote } = await readRemoteSnapshot(backend, config, options.signal);\n\tthrowIfAborted(options.signal);\n\tconst localChanged = hasLocalChanges(local, state, config);\n\tif (!remote) {\n\t\tthrow createSyncDecision({\n\t\t\tkind: \"remote-empty\",\n\t\t\tconfig,\n\t\t\tstate,\n\t\t\tlocal,\n\t\t\tlocalChanged,\n\t\t\tremoteChanged: false,\n\t\t\tdirectMessage: \"Remote is empty. Run /sync push from a configured machine first.\",\n\t\t});\n\t}\n\n\tconst remoteChanged = hasRemoteChanges(remote, state, config, protectedSessionPaths(ctx));\n\tif (localChanged && remoteChanged && state.lastAppliedSnapshot && !options.force) {\n\t\tthrow createSyncDecision({\n\t\t\tkind: \"both-changed\",\n\t\t\tconfig,\n\t\t\tstate,\n\t\t\tlocal,\n\t\t\tremote,\n\t\t\tlocalChanged,\n\t\t\tremoteChanged,\n\t\t\tdirectMessage:\n\t\t\t\t\"Both local and remote changed since last sync. Run /sync diff, then choose /sync pull --force or /sync push --force.\",\n\t\t});\n\t}\n\n\tif (\n\t\t!options.yes &&\n\t\t!(await ctx.ui.confirm(\n\t\t\tsnapshotIncludesSessions(remote) ? \"Pull pi settings and sessions?\" : \"Pull pi settings?\",\n\t\t\tformatPullSummary(\n\t\t\t\tconfig,\n\t\t\t\tbackend.destination,\n\t\t\t\tlocal,\n\t\t\t\tremote,\n\t\t\t\tprotectedSessionPaths(ctx).size,\n\t\t\t),\n\t\t))\n\t) {\n\t\tctx.ui.setStatus(STATUS_KEY, undefined);\n\t\tctx.ui.notify(\"Pull cancelled.\", \"info\");\n\t\treturn \"cancelled\" as const;\n\t}\n\n\tthrowIfAborted(options.signal);\n\tconst backup = await backupLocal(\n\t\tconfig.snapshotIdentity,\n\t\tsnapshotOptionsForContext(ctx, config),\n\t\toptions.signal,\n\t);\n\tconst applySessionDir = await sessionDirForApply(ctx, remote);\n\tthrowIfAborted(options.signal);\n\toptions.onCommit?.();\n\tconst lastFileHashes = await applySnapshot(remote, protectedSessionPaths(ctx), {\n\t\tinclude: config.include,\n\t\tsessionDir: applySessionDir,\n\t});\n\tawait writeStateForConfig(config, {\n\t\tversion: VERSION,\n\t\tprofile: config.snapshotIdentity,\n\t\tlastAppliedSnapshot: remote.id,\n\t\tlastRemoteRevision: head?.revision,\n\t\tlastFileHashes,\n\t\tinclude: [...config.include],\n\t});\n\tif (options.signal?.aborted) return \"applied\" as const;\n\tctx.ui.setStatus(STATUS_KEY, undefined);\n\tif (!options.silent) {\n\t\tctx.ui.notify(\n\t\t\t`Pulled ${remote.files.length} files from ${remote.id}. Backup: ${backup}`,\n\t\t\t\"info\",\n\t\t);\n\t} else if (\n\t\toptions.auto &&\n\t\tconfig.include.includes(\"sessions\") &&\n\t\tsnapshotIncludesSessions(remote)\n\t) {\n\t\tctx.ui.notify(\n\t\t\t\"Pulled Pi sessions after startup selected the current session. Restart Pi or resume a pulled session to use newly synced conversations.\",\n\t\t\t\"warning\",\n\t\t);\n\t}\n\tif (options.reload) await maybeReload(ctx, options.signal);\n\treturn \"applied\" as const;\n}\n\nexport async function syncBoth(\n\tctx: ExtensionCommandContext | ExtensionContext,\n\toptions: CommandOptions,\n\tfactory: SyncBackendFactory = createSyncBackend,\n) {\n\tconst config = await loadConfig(options.setup);\n\tthrowIfAborted(options.signal);\n\tconst backend = await backendFor(config, factory);\n\tconst state = await readStateForConfig(config);\n\tthrowIfAborted(options.signal);\n\tconst local = await createSnapshot(\n\t\tconfig.snapshotIdentity,\n\t\tsnapshotOptionsForContext(ctx, config),\n\t);\n\tthrowIfAborted(options.signal);\n\tif (config.include.length === 0) {\n\t\tif (!options.silent) {\n\t\t\tctx.ui.notify(\n\t\t\t\t`Sync setup \u201C${config.setupName}\u201D includes no files. Choose included content in /sync Settings before syncing.`,\n\t\t\t\t\"warning\",\n\t\t\t);\n\t\t}\n\t\treturn;\n\t}\n\tconst { head, snapshot: remote } = await readRemoteSnapshot(backend, config, options.signal);\n\tthrowIfAborted(options.signal);\n\tconst localChanged = hasLocalChanges(local, state, config);\n\tconst remoteChanged = remote\n\t\t? hasRemoteChanges(remote, state, config, protectedSessionPaths(ctx))\n\t\t: false;\n\tconst firstSync = !state.lastAppliedSnapshot;\n\n\tif (firstSync && remote && remote.files.length > 0 && local.files.length > 0) {\n\t\tif (!canPullRemoteSettingsOnFirstSync(local, remote)) {\n\t\t\tthrow createSyncDecision({\n\t\t\t\tkind: \"first-sync-settings-diverged\",\n\t\t\t\tconfig,\n\t\t\t\tstate,\n\t\t\t\tlocal,\n\t\t\t\tremote,\n\t\t\t\tlocalChanged: true,\n\t\t\t\tremoteChanged: true,\n\t\t\t\tdirectMessage:\n\t\t\t\t\t\"Remote settings exist and this machine has different local Pi settings. Run /sync diff, then manually choose /sync pull or /sync push.\",\n\t\t\t});\n\t\t}\n\t\tif (!sameHashes(fileHashMap(local), fileHashMap(remote))) {\n\t\t\tif (!canPullRemoteSessionsOnFirstSync(local, remote)) {\n\t\t\t\tthrow createSyncDecision({\n\t\t\t\t\tkind: \"first-sync-sessions-diverged\",\n\t\t\t\t\tconfig,\n\t\t\t\t\tstate,\n\t\t\t\t\tlocal,\n\t\t\t\t\tremote,\n\t\t\t\t\tlocalChanged: true,\n\t\t\t\t\tremoteChanged: true,\n\t\t\t\t\tdirectMessage:\n\t\t\t\t\t\t\"Remote settings match, but local and remote Pi sessions differ. Run /sync diff, then manually choose /sync pull or /sync push.\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tawait pull(ctx, options, factory);\n\t\t\treturn;\n\t\t}\n\t\tawait writeStateForConfig(config, {\n\t\t\tversion: VERSION,\n\t\t\tprofile: config.snapshotIdentity,\n\t\t\tlastAppliedSnapshot: remote.id,\n\t\t\tlastRemoteRevision: head?.revision,\n\t\t\tlastFileHashes: fileHashMap(remote),\n\t\t\tinclude: [...config.include],\n\t\t});\n\t\tif (!options.silent)\n\t\t\tctx.ui.notify(\"pi-sync state initialized; local settings already match remote.\", \"info\");\n\t\treturn;\n\t}\n\tif (localChanged && remoteChanged && remote && snapshotsMatch(local, remote)) {\n\t\tawait writeStateForConfig(config, {\n\t\t\tversion: VERSION,\n\t\t\tprofile: config.snapshotIdentity,\n\t\t\tlastAppliedSnapshot: remote.id,\n\t\t\tlastRemoteRevision: head?.revision,\n\t\t\tlastFileHashes: fileHashMap(remote),\n\t\t\tinclude: [...config.include],\n\t\t});\n\t\tif (!options.silent) ctx.ui.notify(\"pi-sync is already up to date.\", \"info\");\n\t\treturn;\n\t}\n\tif (localChanged && remoteChanged && state.lastAppliedSnapshot) {\n\t\tthrow createSyncDecision({\n\t\t\tkind: \"both-changed\",\n\t\t\tconfig,\n\t\t\tstate,\n\t\t\tlocal,\n\t\t\tremote,\n\t\t\tlocalChanged,\n\t\t\tremoteChanged,\n\t\t\tdirectMessage:\n\t\t\t\t\"Both local and remote changed. Run /sync diff and resolve with push --force or pull --force.\",\n\t\t});\n\t}\n\tif (remoteChanged) {\n\t\tawait pull(ctx, options, factory);\n\t\treturn;\n\t}\n\tif (localChanged || !remote) {\n\t\tawait push(ctx, options, undefined, factory);\n\t\treturn;\n\t}\n\tif (\n\t\tshouldRefreshSyncedState(remote, head, state, config, (left, right) =>\n\t\t\tbackend.sameRevision(left, right),\n\t\t)\n\t) {\n\t\tawait writeStateForConfig(config, {\n\t\t\tversion: VERSION,\n\t\t\tprofile: config.snapshotIdentity,\n\t\t\tlastAppliedSnapshot: remote.id,\n\t\t\tlastRemoteRevision: head?.revision,\n\t\t\tlastFileHashes: fileHashMap(remote),\n\t\t\tinclude: [...config.include],\n\t\t});\n\t}\n\tif (!options.silent) ctx.ui.notify(\"pi-sync is already up to date.\", \"info\");\n}\n\nexport async function history(\n\tctx: ExtensionCommandContext,\n\toptions: CommandOptions,\n\tfactory: SyncBackendFactory = createSyncBackend,\n) {\n\tconst config = await loadConfig(options.setup);\n\tthrowIfAborted(options.signal);\n\tconst backend = await backendFor(config, factory);\n\tconst snapshots = (await backend.listHistory(options.signal)).slice(-20).reverse();\n\tthrowIfAborted(options.signal);\n\tif (snapshots.length === 0) {\n\t\tctx.ui.notify(\"No remote pi-sync history found.\", \"info\");\n\t\treturn;\n\t}\n\n\tconst currentSnapshot = snapshots[0]?.snapshotId;\n\tif (ctx.mode === \"tui\") {\n\t\tconst labels = snapshots.map(\n\t\t\t(item, index) =>\n\t\t\t\t`${index + 1}. ${item.createdAt} \u00B7 ${safeTerminalText(item.machine)} \u00B7 ${item.snapshotId}${item.snapshotId === currentSnapshot ? \" (current)\" : \"\"}${item.syncSessions ? \" \u00B7 sessions\" : \"\"}`,\n\t\t);\n\t\tconst selected = await ctx.ui.select(\n\t\t\t`History for sync setup \u201C${safeTerminalText(config.setupName)}\u201D\\n\\nChoose a snapshot to preview rollback.`,\n\t\t\t[...labels, \"Back\"],\n\t\t);\n\t\tif (!selected || selected === \"Back\") return;\n\t\tthrowIfAborted(options.signal);\n\t\tconst index = labels.indexOf(selected);\n\t\tconst snapshot = snapshots[index];\n\t\tif (!snapshot) return;\n\t\tawait withLock(\"rollback\", () =>\n\t\t\trollback(ctx, { ...options, args: [snapshot.snapshotRef], yes: false }, factory, {\n\t\t\t\tbackendIdentity: backend.identity,\n\t\t\t\tsetup: config.setupName,\n\t\t\t}),\n\t\t);\n\t\treturn;\n\t}\n\tctx.ui.notify(\n\t\tsnapshots\n\t\t\t.map((item) => `${item.snapshotRef} ${item.createdAt} ${safeTerminalText(item.machine)}`)\n\t\t\t.join(\"\\n\"),\n\t\t\"info\",\n\t);\n}\n\nexport async function rollback(\n\tctx: ExtensionCommandContext,\n\toptions: CommandOptions,\n\tfactory: SyncBackendFactory = createSyncBackend,\n\texpectedSelection?: { backendIdentity: string; setup?: string },\n) {\n\tconst target = options.args[0];\n\tif (!target) throw new Error(\"Usage: /sync rollback <snapshot-id> [--yes]\");\n\n\tconst config = await loadConfig(options.setup);\n\tthrowIfAborted(options.signal);\n\tconst backend = await backendFor(config, factory);\n\tif (\n\t\texpectedSelection &&\n\t\t(backend.identity !== expectedSelection.backendIdentity ||\n\t\t\tconfig.setupName !== expectedSelection.setup)\n\t) {\n\t\tthrow new Error(\n\t\t\t\"Sync setup or storage location changed while history was open; reopen history and retry.\",\n\t\t);\n\t}\n\tconst decoded = await backend.readSnapshot(target, options.signal);\n\tconst selected = filterSnapshotForConfigPolicy(\n\t\tconfig.include.includes(\"sessions\") ? decoded : snapshotWithoutSessions(decoded),\n\t\tconfig,\n\t);\n\tconst remote = regenerateSnapshotIdentity(selected);\n\tconst local = await createSnapshot(\n\t\tconfig.snapshotIdentity,\n\t\tsnapshotOptionsForContext(ctx, config),\n\t);\n\tconst expectedHead = await backend.readHead(options.signal);\n\tthrowIfAborted(options.signal);\n\n\tif (\n\t\t!options.yes &&\n\t\t!(await ctx.ui.confirm(\n\t\t\tsnapshotIncludesSessions(remote)\n\t\t\t\t? \"Rollback pi settings and sessions?\"\n\t\t\t\t: \"Rollback pi settings?\",\n\t\t\tformatRollbackSummary(\n\t\t\t\tconfig,\n\t\t\t\tbackend.destination,\n\t\t\t\tlocal,\n\t\t\t\tremote,\n\t\t\t\ttarget,\n\t\t\t\tprotectedSessionPaths(ctx).size,\n\t\t\t),\n\t\t))\n\t) {\n\t\tctx.ui.notify(\"Rollback cancelled.\", \"info\");\n\t\treturn;\n\t}\n\n\tthrowIfAborted(options.signal);\n\tconst backup = await backupLocal(\n\t\tconfig.snapshotIdentity,\n\t\tsnapshotOptionsForContext(ctx, config),\n\t\toptions.signal,\n\t);\n\tconst applySessionDir = await sessionDirForApply(ctx, remote);\n\tthrowIfAborted(options.signal);\n\toptions.onCommit?.();\n\tconst lastFileHashes = await applySnapshot(remote, protectedSessionPaths(ctx), {\n\t\tinclude: config.include,\n\t\tsessionDir: applySessionDir,\n\t});\n\tlet result: PublishSnapshotResult;\n\ttry {\n\t\tconst completionSignal = AbortSignal.timeout(POST_LOCAL_COMMIT_TIMEOUT_MS);\n\t\tconst upload = await snapshotForUpload(\n\t\t\tbackend,\n\t\t\tconfig,\n\t\t\tremote,\n\t\t\texpectedHead,\n\t\t\tundefined,\n\t\t\tcompletionSignal,\n\t\t\t{ ignoreUnreadableRemote: true },\n\t\t);\n\t\tresult = await backend.publishSnapshot(upload, expectedRemoteHead(expectedHead), {\n\t\t\tsignal: completionSignal,\n\t\t});\n\t} catch (error) {\n\t\tthrow new RollbackPublicationError(backup, error);\n\t}\n\ttry {\n\t\tawait writeStateForConfig(config, {\n\t\t\tversion: VERSION,\n\t\t\tprofile: config.snapshotIdentity,\n\t\t\tlastAppliedSnapshot: result.head.snapshotId,\n\t\t\tlastRemoteRevision: result.head.revision,\n\t\t\tlastFileHashes,\n\t\t\tinclude: [...config.include],\n\t\t});\n\t} catch (error) {\n\t\tthrow new PublicationStatePersistenceError(result.head, error, backup);\n\t}\n\tif (options.signal?.aborted) return;\n\tctx.ui.notify(\n\t\t[\n\t\t\t`Rolled back sync setup \u201C${config.setupName}\u201D to ${target}; latest: ${result.head.snapshotId}. Backup: ${backup}`,\n\t\t\t...result.warnings,\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\"\\n\"),\n\t\tresult.warnings.length > 0 ? \"warning\" : \"info\",\n\t);\n\tawait maybeReload(ctx, options.signal);\n}\n\nfunction protectedSessionPaths(ctx: ExtensionCommandContext | ExtensionContext) {\n\tconst getSessionFile = ctx.sessionManager.getSessionFile;\n\tif (typeof getSessionFile !== \"function\") return new Set<string>();\n\tconst sessionFile = getSessionFile.call(ctx.sessionManager) as string | undefined;\n\tconst snapshotPath = sessionFile\n\t\t? sessionSnapshotPathFromAbsolute(sessionFile, sessionDirFromContext(ctx))\n\t\t: undefined;\n\treturn snapshotPath ? new Set([snapshotPath]) : new Set<string>();\n}\n\nfunction snapshotOptionsForContext(\n\tctx: ExtensionCommandContext | ExtensionContext,\n\tconfig: AnySyncConfig,\n): SnapshotOptions {\n\treturn {\n\t\tinclude: config.include,\n\t\tsessionDir: sessionDirFromContext(ctx),\n\t};\n}\n\nfunction sessionDirFromContext(ctx: ExtensionCommandContext | ExtensionContext) {\n\tconst manager = ctx.sessionManager as typeof ctx.sessionManager & {\n\t\tusesDefaultSessionDir?: () => boolean;\n\t};\n\tconst usesDefaultSessionDir = manager.usesDefaultSessionDir;\n\tif (typeof usesDefaultSessionDir === \"function\" && usesDefaultSessionDir.call(manager)) {\n\t\treturn undefined;\n\t}\n\tconst getSessionDir = manager.getSessionDir;\n\treturn typeof getSessionDir === \"function\"\n\t\t? (getSessionDir.call(manager) as string | undefined)\n\t\t: undefined;\n}\n\nasync function maybeReload(ctx: ExtensionCommandContext | ExtensionContext, signal?: AbortSignal) {\n\tif (signal?.aborted || !(\"reload\" in ctx)) return;\n\tif (\n\t\tctx.hasUI &&\n\t\t(await ctx.ui.confirm(\n\t\t\t\"Reload Pi resources now?\",\n\t\t\t\"This reloads extensions, skills, prompts, themes, and context files.\",\n\t\t))\n\t) {\n\t\tif (signal?.aborted) return;\n\t\tawait ctx.reload();\n\t}\n}\n\nasync function readRemoteSnapshotForUpload(\n\tbackend: SyncBackend,\n\tconfig: AnySyncConfig,\n\thead: RemoteHead | undefined,\n\tstate: SyncState,\n\tsignal?: AbortSignal,\n) {\n\tif (\n\t\t!head ||\n\t\t(head.snapshotId === state.lastAppliedSnapshot &&\n\t\t\t!syncPolicyChanged(state, config) &&\n\t\t\t(!state.lastRemoteRevision || backend.sameRevision(head.revision, state.lastRemoteRevision)))\n\t) {\n\t\treturn undefined;\n\t}\n\treturn backend.readSnapshot(head.snapshotRef, signal);\n}\n\nasync function snapshotForUpload(\n\tbackend: SyncBackend,\n\tconfig: AnySyncConfig,\n\tlocal: Snapshot,\n\thead: RemoteHead | undefined,\n\tremote?: Snapshot,\n\tsignal?: AbortSignal,\n\toptions: { ignoreUnreadableRemote?: boolean } = {},\n) {\n\tif (!head) return local;\n\tlet snapshot = remote;\n\tif (!snapshot) {\n\t\ttry {\n\t\t\tsnapshot = await backend.readSnapshot(head.snapshotRef, signal);\n\t\t} catch (error) {\n\t\t\tif (options.ignoreUnreadableRemote) return local;\n\t\t\tthrow error;\n\t\t}\n\t}\n\treturn mergeRemotePreservedFiles(local, snapshot, config);\n}\n\nasync function readRemoteSnapshot(\n\tbackend: SyncBackend,\n\tconfig: AnySyncConfig,\n\tsignal?: AbortSignal,\n\toptions: { allowSelectionDifference?: boolean } = {},\n) {\n\tconst head = await backend.readHead(signal);\n\tif (!head) return { head: undefined, snapshot: undefined, selectionState: undefined };\n\tconst snapshot = await readSnapshotForHead(backend, head, signal);\n\tconst selectionState = inspectRemoteSelection(config.include, snapshot);\n\tif (!options.allowSelectionDifference && selectionState.kind === \"different\") {\n\t\tconst configIdentity = syncConfigReviewFingerprint(config);\n\t\tthrow remoteSelectionMismatch(config, selectionState.include, configIdentity);\n\t}\n\treturn {\n\t\thead,\n\t\tsnapshot: filterSnapshotForConfigPolicy(snapshot, config),\n\t\tselectionState,\n\t};\n}\n\nasync function confirmPush(\n\tctx: ExtensionCommandContext | ExtensionContext,\n\toptions: CommandOptions,\n\tconfig: AnySyncConfig,\n\tbackend: SyncBackend,\n\tlocal: Snapshot,\n\tupload: Snapshot,\n\thead: RemoteHead | undefined,\n\tremote: Snapshot | undefined,\n\ttitle = snapshotIncludesSessions(upload) ? \"Push pi settings and sessions?\" : \"Push pi settings?\",\n) {\n\tthrowIfAborted(options.signal);\n\tif (options.yes) return true;\n\tconst confirmed = await ctx.ui.confirm(\n\t\ttitle,\n\t\tformatPushSummary(\n\t\t\tconfig,\n\t\t\tbackend.destination,\n\t\t\tupload,\n\t\t\thead,\n\t\t\tcountPreservedRemoteFiles(local, upload),\n\t\t\tremote,\n\t\t),\n\t);\n\tthrowIfAborted(options.signal);\n\tif (confirmed) return true;\n\tctx.ui.setStatus(STATUS_KEY, undefined);\n\tctx.ui.notify(\"Push cancelled.\", \"info\");\n\treturn false;\n}\n\nfunction throwIfAborted(signal?: AbortSignal) {\n\tif (!signal?.aborted) return;\n\tthrow signal.reason instanceof Error\n\t\t? signal.reason\n\t\t: new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n\nfunction sameRemoteHead(\n\tbackend: SyncBackend,\n\tleft: RemoteHead | undefined,\n\tright: RemoteHead | undefined,\n) {\n\tif (!left || !right) return left === right;\n\treturn backend.sameRevision(left.revision, right.revision);\n}\n\nexport async function backupLocal(\n\tprofile: string,\n\toptions: SnapshotOptions = {},\n\tsignal?: AbortSignal,\n) {\n\tthrowIfAborted(signal);\n\tconst snapshot = await createSnapshot(profile, options);\n\tthrowIfAborted(signal);\n\tconst backupDirectory = path.join(stateDir(), \"backups\");\n\tawait fs.mkdir(backupDirectory, { recursive: true });\n\tthrowIfAborted(signal);\n\tconst backupPath = path.join(backupDirectory, `${snapshot.id}.json.gz`);\n\tconst encoded = await encodeSnapshot(snapshot);\n\tthrowIfAborted(signal);\n\tawait fs.writeFile(backupPath, encoded, { signal });\n\treturn backupPath;\n}\n", "import { createHash } from \"node:crypto\";\nimport type { Dirent } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { agentDir } from \"./config.js\";\nimport {\n\tassertWithinRoot,\n\tisDeniedPath,\n\tisPathInside,\n\tparentPaths,\n\tsafeJoin,\n\ttoPosix,\n} from \"./paths.js\";\nimport {\n\tcreateSnapshot,\n\tisSessionFilePath,\n\tisSessionPath,\n\tsessionStorageRoot,\n\tsnapshotIncludesSessions,\n\tsnapshotTarget,\n} from \"./snapshot.js\";\nimport {\n\tapplySnapshotTransaction,\n\trecoverPendingSnapshotTransactions,\n} from \"./snapshot-transaction.js\";\nimport type { Snapshot, SnapshotApplyPlan, SnapshotOptions } from \"./types.js\";\n\nfunction sha256(value: Buffer) {\n\treturn createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction fileHashMap(snapshot: Snapshot) {\n\treturn Object.fromEntries(snapshot.files.map((file) => [file.path, file.sha256]));\n}\n\nexport async function applySnapshot(\n\tsnapshot: Snapshot,\n\tprotectedRelativePaths = new Set<string>(),\n\toptions: Pick<\n\t\tSnapshotOptions,\n\t\t\"include\" | \"sessionDir\" | \"syncFiles\" | \"syncSessions\" | \"extraFiles\"\n\t> = {},\n) {\n\tconst root = agentDir();\n\tconst { sessionDir } = options;\n\tawait recoverPendingSnapshotTransactions();\n\tconst current = await createSnapshot(snapshot.profile, {\n\t\t...options,\n\t\t...(options.include === undefined ? { syncSessions: snapshotIncludesSessions(snapshot) } : {}),\n\t\tsessionDir,\n\t});\n\tconst plan = await addTopLevelCaseVariantDeletes(\n\t\troot,\n\t\tprotectSnapshotApplyPlan(\n\t\t\troot,\n\t\t\tpreflightSnapshotApply(root, snapshot, current, { sessionDir }),\n\t\t\tprotectedRelativePaths,\n\t\t\tsessionDir,\n\t\t),\n\t\tsnapshot,\n\t);\n\tawait preflightSnapshotMutations(root, plan, sessionDir);\n\tawait applySnapshotTransaction(plan, { sessionDir });\n\treturn appliedFileHashMap(snapshot, current, protectedRelativePaths);\n}\n\nexport function preflightSnapshotApply(\n\troot: string,\n\tsnapshot: Snapshot,\n\tcurrent: Snapshot,\n\toptions: { sessionDir?: string } = {},\n): SnapshotApplyPlan {\n\tconst seenPaths = new Set<string>();\n\tconst remotePaths = new Set<string>();\n\tconst writes: Array<{ target: string; content: Buffer }> = [];\n\tconst deletes: string[] = [];\n\n\tfor (const file of snapshot.files) {\n\t\tconst normalized = toPosix(file.path);\n\t\tif (!isSafeSnapshotPath(file.path)) {\n\t\t\tthrow new Error(`Unsafe path in snapshot: ${file.path}`);\n\t\t}\n\t\tif (isSessionPath(normalized) && !isSessionFilePath(normalized)) {\n\t\t\tthrow new Error(`Unsafe session path in snapshot: ${file.path}`);\n\t\t}\n\t\tif (seenPaths.has(normalized)) throw new Error(`Duplicate path in snapshot: ${normalized}`);\n\t\tseenPaths.add(normalized);\n\t\tremotePaths.add(normalized);\n\n\t\tconst target = snapshotTarget(root, normalized, options.sessionDir);\n\t\tconst content = decodeBase64Strict(file.contentBase64, normalized);\n\t\tif (sha256(content) !== file.sha256)\n\t\t\tthrow new Error(`Checksum mismatch in snapshot file: ${normalized}`);\n\t\twrites.push({ target, content });\n\t}\n\n\tconst deletePaths = new Set<string>();\n\tfor (const file of current.files) {\n\t\tconst normalized = toPosix(file.path);\n\t\tif (!remotePaths.has(normalized)) {\n\t\t\tdeletePaths.add(snapshotTarget(root, normalized, options.sessionDir));\n\t\t}\n\t\tfor (const remotePath of parentPaths(normalized)) {\n\t\t\tif (remotePaths.has(remotePath)) {\n\t\t\t\tdeletePaths.add(snapshotTarget(root, remotePath, options.sessionDir));\n\t\t\t}\n\t\t}\n\t}\n\tdeletes.push(...deletePaths);\n\n\treturn { writes, deletes };\n}\n\nexport function protectSnapshotApplyPlan(\n\troot: string,\n\tplan: SnapshotApplyPlan,\n\tprotectedRelativePaths: Set<string>,\n\tsessionDir?: string,\n): SnapshotApplyPlan {\n\tif (protectedRelativePaths.size === 0) return plan;\n\tconst protectedTargets = new Set(\n\t\t[...protectedRelativePaths].map((relativePath) =>\n\t\t\tsnapshotTarget(root, relativePath, sessionDir),\n\t\t),\n\t);\n\treturn {\n\t\twrites: plan.writes.filter((item) => !protectedTargets.has(item.target)),\n\t\tdeletes: plan.deletes.filter((target) => !protectedTargets.has(target)),\n\t};\n}\n\nexport async function addTopLevelCaseVariantDeletes(\n\troot: string,\n\tplan: SnapshotApplyPlan,\n\tsnapshot: Pick<Snapshot, \"files\">,\n): Promise<SnapshotApplyPlan> {\n\tconst topLevelPaths = new Map<string, string>();\n\tfor (const file of snapshot.files) {\n\t\tconst normalized = toPosix(file.path);\n\t\tif (!normalized.includes(\"/\") && isSafeSnapshotPath(file.path)) {\n\t\t\ttopLevelPaths.set(normalized.toLowerCase(), normalized);\n\t\t}\n\t}\n\tif (topLevelPaths.size === 0) return plan;\n\n\tlet entries: Dirent[];\n\ttry {\n\t\tentries = await fs.readdir(root, { withFileTypes: true });\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return plan;\n\t\tthrow error;\n\t}\n\n\tconst deletes = new Set(plan.deletes);\n\tfor (const entry of entries) {\n\t\tconst canonicalPath = topLevelPaths.get(entry.name.toLowerCase());\n\t\tif (\n\t\t\tcanonicalPath &&\n\t\t\tentry.name !== canonicalPath &&\n\t\t\t(entry.isFile() || entry.isSymbolicLink())\n\t\t) {\n\t\t\tdeletes.add(safeJoin(root, entry.name));\n\t\t}\n\t}\n\treturn { ...plan, deletes: [...deletes] };\n}\n\nexport function appliedFileHashMap(\n\tsnapshot: Snapshot,\n\tcurrent: Snapshot,\n\tprotectedRelativePaths: Set<string>,\n) {\n\tconst hashes = fileHashMap(snapshot);\n\tif (protectedRelativePaths.size === 0) return hashes;\n\tconst currentHashes = fileHashMap(current);\n\tfor (const relativePath of protectedRelativePaths) {\n\t\tconst normalized = toPosix(relativePath);\n\t\tif (currentHashes[normalized]) {\n\t\t\thashes[normalized] = currentHashes[normalized];\n\t\t} else {\n\t\t\tdelete hashes[normalized];\n\t\t}\n\t}\n\treturn hashes;\n}\n\nfunction isSafeSnapshotPath(relativePath: string) {\n\tif (relativePath.includes(\"\\\\\")) return false;\n\tconst normalized = toPosix(relativePath);\n\treturn (\n\t\tBoolean(normalized) &&\n\t\tnormalized !== \".\" &&\n\t\tnormalized !== \"..\" &&\n\t\t!normalized.startsWith(\"../\") &&\n\t\t!path.posix.isAbsolute(normalized) &&\n\t\tpath.posix.normalize(normalized) === normalized &&\n\t\t!isDeniedPath(normalized)\n\t);\n}\n\nfunction decodeBase64Strict(value: string, filePath: string) {\n\tif (!/^[A-Za-z0-9+/]*={0,2}$/.test(value) || value.length % 4 !== 0) {\n\t\tthrow new Error(`Invalid base64 content in snapshot file: ${filePath}`);\n\t}\n\treturn Buffer.from(value, \"base64\");\n}\n\nasync function preflightSnapshotMutations(\n\troot: string,\n\tplan: { deletes: string[]; writes: Array<{ target: string; content: Buffer }> },\n\tsessionDir?: string,\n) {\n\tconst deletePaths = new Set(plan.deletes);\n\tfor (const target of plan.deletes) {\n\t\tawait assertNoSymlinkParents(rootForTarget(root, target, sessionDir), target);\n\t}\n\tfor (const item of plan.writes) {\n\t\tawait prepareSnapshotWrite(\n\t\t\trootForTarget(root, item.target, sessionDir),\n\t\t\titem.target,\n\t\t\tdeletePaths,\n\t\t);\n\t}\n}\n\nfunction rootForTarget(root: string, target: string, sessionDir?: string) {\n\tconst sessionRoot = sessionDir ? sessionStorageRoot(root, sessionDir) : undefined;\n\tif (sessionRoot && isPathInside(sessionRoot, target)) return sessionRoot;\n\treturn root;\n}\n\nasync function prepareSnapshotWrite(root: string, target: string, deletePaths: Set<string>) {\n\tconst parentWillBeReplaced = await ensureSafeDirectory(root, path.dirname(target), deletePaths);\n\tif (parentWillBeReplaced) return;\n\ttry {\n\t\tconst stat = await fs.lstat(target);\n\t\tif (stat.isSymbolicLink())\n\t\t\tthrow new Error(`Refusing to overwrite symlink during snapshot apply: ${target}`);\n\t\tif (stat.isDirectory() && !deletePaths.has(target)) {\n\t\t\tthrow new Error(`Refusing to overwrite directory during snapshot apply: ${target}`);\n\t\t}\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t}\n}\n\nasync function ensureSafeDirectory(root: string, directory: string, deletePaths: Set<string>) {\n\tassertWithinRoot(root, directory);\n\tconst rootPath = path.resolve(root);\n\tconst relative = path.relative(rootPath, path.resolve(directory));\n\tlet current = rootPath;\n\tfor (const part of relative.split(path.sep).filter(Boolean)) {\n\t\tcurrent = path.join(current, part);\n\t\ttry {\n\t\t\tconst stat = await fs.lstat(current);\n\t\t\tif (stat.isSymbolicLink())\n\t\t\t\tthrow new Error(`Refusing to follow symlink during snapshot apply: ${current}`);\n\t\t\tif (!stat.isDirectory()) {\n\t\t\t\tif (deletePaths.has(current)) return true;\n\t\t\t\tthrow new Error(`Snapshot path parent is not a directory: ${current}`);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t\t\tawait fs.mkdir(current);\n\t\t}\n\t}\n\treturn false;\n}\n\nasync function assertNoSymlinkParents(root: string, target: string) {\n\tassertWithinRoot(root, target);\n\tconst rootPath = path.resolve(root);\n\tconst relative = path.relative(rootPath, path.resolve(target));\n\tlet current = rootPath;\n\tconst parts = relative.split(path.sep).filter(Boolean);\n\tfor (const part of parts.slice(0, -1)) {\n\t\tcurrent = path.join(current, part);\n\t\ttry {\n\t\t\tconst stat = await fs.lstat(current);\n\t\t\tif (stat.isSymbolicLink())\n\t\t\t\tthrow new Error(`Refusing to follow symlink during snapshot apply: ${current}`);\n\t\t\tif (!stat.isDirectory())\n\t\t\t\tthrow new Error(`Snapshot path parent is not a directory: ${current}`);\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n", "import { syncConfigReviewIdentity } from \"./config.js\";\nimport { SyncDecisionRequiredError } from \"./sync-errors.js\";\nimport { formatDiff, formatSnapshotOnlyDiff, safeTerminalText } from \"./sync-format.js\";\nimport { includeFromSelectionConfig } from \"./sync-policy.js\";\nimport { syncPolicyChanged } from \"./sync-state.js\";\nimport type { AnySyncConfig, Snapshot, SyncState } from \"./types.js\";\n\nexport type SyncDecisionKind =\n\t| \"remote-or-policy-changed\"\n\t| \"both-changed\"\n\t| \"first-sync-settings-diverged\"\n\t| \"first-sync-sessions-diverged\"\n\t| \"remote-empty\";\n\nexport type SyncResolutionDirection = \"push\" | \"pull\";\n\nexport interface SyncDecision {\n\tkind: SyncDecisionKind;\n\tsetupName: string;\n\tconfigIdentity: string;\n\tcauses: {\n\t\tlocalChanged: boolean;\n\t\tremoteChanged: boolean;\n\t\tpolicyChanged: boolean;\n\t};\n\tpreviousInclude?: readonly string[];\n\tcurrentInclude: readonly string[];\n\treview: string;\n\tdirections: readonly SyncResolutionDirection[];\n\tdirectMessage: string;\n}\n\nexport {\n\tisSyncDecisionRequiredError,\n\tSyncDecisionRequiredError,\n} from \"./sync-errors.js\";\n\ninterface CreateSyncDecisionOptions {\n\tkind: SyncDecisionKind;\n\tconfig: AnySyncConfig;\n\tstate: SyncState;\n\tlocal: Snapshot;\n\tremote?: Snapshot;\n\tlocalChanged: boolean;\n\tremoteChanged: boolean;\n\tdirectMessage: string;\n}\n\nexport function createSyncDecision(options: CreateSyncDecisionOptions) {\n\tconst { config, state, local, remote, kind } = options;\n\tconst policyChanged = Boolean(state.lastAppliedSnapshot) && syncPolicyChanged(state, config);\n\tconst previousInclude = includeFromSelectionConfig(state);\n\tconst currentInclude = [...config.include];\n\tconst causes = {\n\t\tlocalChanged: options.localChanged,\n\t\tremoteChanged: options.remoteChanged,\n\t\tpolicyChanged,\n\t};\n\tconst causeLines =\n\t\tkind === \"first-sync-settings-diverged\"\n\t\t\t? [\"This machine and the remote have different Pi settings on first sync.\"]\n\t\t\t: kind === \"first-sync-sessions-diverged\"\n\t\t\t\t? [\"Pi settings match, but local and remote sessions differ on first sync.\"]\n\t\t\t\t: kind === \"remote-empty\"\n\t\t\t\t\t? [\"The remote storage location is empty.\"]\n\t\t\t\t\t: [\n\t\t\t\t\t\t\t...(causes.localChanged ? [\"Local content changed since the last sync.\"] : []),\n\t\t\t\t\t\t\t...(causes.remoteChanged ? [\"Remote content changed since the last sync.\"] : []),\n\t\t\t\t\t\t\t...(causes.policyChanged ? [\"Included content changed since the last sync.\"] : []),\n\t\t\t\t\t\t];\n\tconst comparison = remote\n\t\t? formatDiff(local, remote)\n\t\t: formatSnapshotOnlyDiff(\"Remote is empty. Local push would upload\", local);\n\tconst review = [\n\t\t`Sync setup: ${safeTerminalText(config.setupName)}`,\n\t\t\"\",\n\t\t\"Why a decision is required:\",\n\t\t...causeLines,\n\t\t...(policyChanged\n\t\t\t? [\n\t\t\t\t\t\"\",\n\t\t\t\t\t`Previously included: ${safeList(previousInclude)}`,\n\t\t\t\t\t`Currently included: ${safeList(currentInclude)}`,\n\t\t\t\t]\n\t\t\t: []),\n\t\t\"\",\n\t\t\"Observed differences:\",\n\t\t...comparison.split(\"\\n\").map(safeTerminalText),\n\t].join(\"\\n\");\n\treturn new SyncDecisionRequiredError({\n\t\tkind,\n\t\tsetupName: config.setupName,\n\t\tconfigIdentity: syncConfigReviewIdentity(config),\n\t\tcauses,\n\t\t...(policyChanged ? { previousInclude: [...previousInclude] } : {}),\n\t\tcurrentInclude,\n\t\treview,\n\t\tdirections: kind === \"remote-empty\" ? [\"push\"] : [\"push\", \"pull\"],\n\t\tdirectMessage: options.directMessage,\n\t});\n}\n\nfunction safeList(values: readonly string[]) {\n\treturn values.length > 0 ? values.map(safeTerminalText).join(\", \") : \"none\";\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["fs", "path", "fileHashMap", "index", "path", "fs"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/webdav-backend.ts", "../../src/webdav-client.ts"],
|
|
4
|
-
"sourcesContent": ["import { createHash, randomUUID } from \"node:crypto\";\nimport { decodeSnapshot, encodeSnapshot } from \"./snapshot-codec.js\";\nimport {\n\ttype BackendDiagnostic,\n\ttype ExpectedRemoteHead,\n\ttype PublishSnapshotOptions,\n\ttype PublishSnapshotResult,\n\ttype RemoteHead,\n\ttype RemoteHistoryEntry,\n\ttype SyncBackend,\n\tSyncBackendConflictError,\n\tSyncBackendPublicationOutcomeUnknownError,\n} from \"./sync-backend.js\";\nimport { portableSnapshotSelection } from \"./sync-policy.js\";\nimport type { LatestPointer, RemoteObject, ResolvedWebDavBackend, Snapshot } from \"./types.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\treadonly identity: string;\n\treadonly destination: string;\n\tprivate conditionalVerified = false;\n\tprivate readonly checksums = new Map<string, string>();\n\tprivate capabilityCheck?: Promise<void>;\n\n\tconstructor(\n\t\tprivate readonly config: ResolvedWebDavBackend,\n\t\tprivate readonly postCommitTimeoutMs = POST_COMMIT_TIMEOUT_MS,\n\t) {\n\t\tassertSafeDestination(config);\n\t\tthis.identity = webDavBackendIdentity(config);\n\t\tthis.destination = webDavStorageLocation(config);\n\t}\n\n\tget capability() {\n\t\treturn this.conditionalVerified\n\t\t\t? (\"atomic-conditional\" as const)\n\t\t\t: (\"conditional-required\" as const);\n\t}\n\n\tsameRevision(left: string, right: string) {\n\t\treturn left === right;\n\t}\n\n\tasync readHead(signal?: AbortSignal): Promise<RemoteHead | undefined> {\n\t\tconst object = await new WebDavClient(this.config, signal).getJson<LatestPointer>(\n\t\t\tlatestPath(this.config),\n\t\t);\n\t\tthrowIfAborted(signal);\n\t\tif (object.missing) return undefined;\n\t\tconst pointer = requirePointer(object.value, this.config.destination.namespace);\n\t\tthis.registerChecksum(pointer.snapshot, pointer.sha256);\n\t\treturn remoteHead(pointer, this.identity, object.etag);\n\t}\n\n\tasync readSnapshot(reference: string, signal?: AbortSignal): Promise<Snapshot> {\n\t\trequireSnapshotReference(reference);\n\t\tconst expectedChecksum =\n\t\t\tthis.checksums.get(reference) ?? (await this.resolveChecksum(reference, signal));\n\t\tconst object = await new WebDavClient(this.config, signal).getBuffer(\n\t\t\tsnapshotPath(this.config, reference),\n\t\t);\n\t\tthrowIfAborted(signal);\n\t\tif (!object.value) throw new Error(`Snapshot not found: ${reference}`);\n\t\tif (!expectedChecksum || sha256(object.value) !== expectedChecksum) {\n\t\t\tthrow new Error(\"Remote snapshot checksum mismatch.\");\n\t\t}\n\t\tconst snapshot = await decodeSnapshot(object.value, { signal });\n\t\tif (snapshot.id !== reference || snapshot.profile !== this.config.destination.namespace) {\n\t\t\tthrow new Error(\"Remote snapshot identity mismatch.\");\n\t\t}\n\t\tvalidateSnapshotBundle(snapshot);\n\t\treturn snapshot;\n\t}\n\n\tasync publishSnapshot(\n\t\tsnapshot: Snapshot,\n\t\texpected: ExpectedRemoteHead,\n\t\toptions: PublishSnapshotOptions = {},\n\t): Promise<PublishSnapshotResult> {\n\t\tthrowIfAborted(options.signal);\n\t\tassertSnapshotIdentity(snapshot, this.config.destination.namespace);\n\t\tawait this.ensureAtomicConditions(options.signal);\n\t\tthrowIfAborted(options.signal);\n\t\tconst client = new WebDavClient(this.config, options.signal);\n\t\tawait client.ensureCollection(snapshotsPath(this.config));\n\t\tconst encoded = await encodeSnapshot(snapshot);\n\t\tthrowIfAborted(options.signal);\n\t\tconst pointer = pointerFor(this.config, snapshot, sha256(encoded));\n\t\tconst stagedPath = snapshotPath(this.config, snapshot.id);\n\t\ttry {\n\t\t\tawait client.putBuffer(stagedPath, encoded, \"application/gzip\", { ifAbsent: true });\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof WebDavPreconditionError)) throw error;\n\t\t\tconst existing = await client.getBuffer(stagedPath);\n\t\t\tif (!existing.value || sha256(existing.value) !== pointer.sha256) {\n\t\t\t\tthrow new SyncBackendConflictError(\n\t\t\t\t\t`Immutable snapshot id already exists with different content: ${snapshot.id}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tconst currentObject = await client.getJson<LatestPointer>(latestPath(this.config));\n\t\tthrowIfAborted(options.signal);\n\t\tconst current = currentObject.missing\n\t\t\t? undefined\n\t\t\t: remoteHead(\n\t\t\t\t\trequirePointer(currentObject.value, this.config.destination.namespace),\n\t\t\t\t\tthis.identity,\n\t\t\t\t\tcurrentObject.etag,\n\t\t\t\t);\n\t\tif (!matchesExpected(current, expected)) {\n\t\t\tthrow new SyncBackendConflictError(\n\t\t\t\t\"Remote changed while pushing. Run /sync pull first, then retry.\",\n\t\t\t\t{\n\t\t\t\t\tcurrentHead: current,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\tconst condition = publicationCondition(currentObject, expected, this.identity);\n\t\tthrowIfAborted(options.signal);\n\t\toptions.onCommit?.();\n\t\tconst commitClient = new WebDavClient(\n\t\t\tthis.config,\n\t\t\tAbortSignal.timeout(this.postCommitTimeoutMs),\n\t\t\tthis.postCommitTimeoutMs,\n\t\t);\n\t\ttry {\n\t\t\tawait commitClient.putJson(latestPath(this.config), pointer, condition);\n\t\t} catch (error) {\n\t\t\tif (error instanceof WebDavPreconditionError) {\n\t\t\t\tconst latest = await this.readHeadAfterCommit(commitClient).catch(() => undefined);\n\t\t\t\tthrow new SyncBackendConflictError(\"Remote changed while publishing the WebDAV pointer.\", {\n\t\t\t\t\tcurrentHead: latest,\n\t\t\t\t});\n\t\t\t}\n\t\t\tthrow new SyncBackendPublicationOutcomeUnknownError(\n\t\t\t\t`Remote publication outcome is unknown: ${errorMessage(error)}`,\n\t\t\t\t{ cause: error },\n\t\t\t);\n\t\t}\n\t\tlet verifiedObject: RemoteObject<LatestPointer>;\n\t\ttry {\n\t\t\tverifiedObject = await commitClient.getJson<LatestPointer>(latestPath(this.config));\n\t\t} catch (error) {\n\t\t\tthrow new SyncBackendPublicationOutcomeUnknownError(\n\t\t\t\t`Remote snapshot may be active, but publication could not be verified: ${errorMessage(error)}`,\n\t\t\t\t{ cause: error },\n\t\t\t);\n\t\t}\n\t\tlet verified: LatestPointer;\n\t\ttry {\n\t\t\tverified = requirePointer(verifiedObject.value, this.config.destination.namespace);\n\t\t} catch (error) {\n\t\t\tthrow new SyncBackendPublicationOutcomeUnknownError(\n\t\t\t\t`Remote snapshot may be active, but publication verification was malformed: ${errorMessage(error)}`,\n\t\t\t\t{ cause: error },\n\t\t\t);\n\t\t}\n\t\tif (!samePointer(pointer, verified)) {\n\t\t\tthrow new SyncBackendConflictError(\n\t\t\t\t\"Remote latest changed immediately after push. Run /sync status before continuing.\",\n\t\t\t\t{\n\t\t\t\t\tphase: \"after-commit\",\n\t\t\t\t\tcurrentHead: remoteHead(verified, this.identity, verifiedObject.etag),\n\t\t\t\t\tcandidateMayHaveBeenActive: true,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\tif (!strongEtag(verifiedObject.etag)) {\n\t\t\tthrow new SyncBackendPublicationOutcomeUnknownError(\n\t\t\t\t\"Remote snapshot is active, but the WebDAV server returned no strong ETag.\",\n\t\t\t);\n\t\t}\n\t\tthis.registerChecksum(verified.snapshot, verified.sha256);\n\t\tconst head = remoteHead(verified, this.identity, verifiedObject.etag);\n\t\tconst warning = await this.updateHistorySafely(commitClient, pointer);\n\t\treturn { head, warnings: warning ? [warning] : [] };\n\t}\n\n\tasync listHistory(signal?: AbortSignal): Promise<RemoteHistoryEntry[]> {\n\t\tconst object = await new WebDavClient(this.config, signal).getJson<{\n\t\t\tversion: number;\n\t\t\tsnapshots: LatestPointer[];\n\t\t}>(historyPath(this.config));\n\t\tthrowIfAborted(signal);\n\t\tif (object.missing) return [];\n\t\tconst pointers = requireHistory(object.value, this.config.destination.namespace);\n\t\tfor (const pointer of pointers) this.registerChecksum(pointer.snapshot, pointer.sha256);\n\t\treturn pointers.map(remoteHistoryEntry);\n\t}\n\n\tasync diagnose(signal?: AbortSignal): Promise<BackendDiagnostic[]> {\n\t\tconst diagnostics: BackendDiagnostic[] = [\n\t\t\t{\n\t\t\t\tkey: \"webdav-url\",\n\t\t\t\tlevel: \"info\",\n\t\t\t\tmessage: `webdav URL/TLS/auth: configured (${webDavStorageLocation(this.config)})`,\n\t\t\t},\n\t\t];\n\t\ttry {\n\t\t\tawait this.runCapabilityProbe(signal);\n\t\t\tdiagnostics.push(\n\t\t\t\t{ key: \"webdav-collection\", level: \"info\", message: \"webdav collection read/write: ok\" },\n\t\t\t\t{\n\t\t\t\t\tkey: \"webdav-conditional\",\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tmessage: \"webdav conditional publication: atomic-conditional (verified)\",\n\t\t\t\t},\n\t\t\t\t{ key: \"webdav-cleanup\", level: \"info\", message: \"webdav probe cleanup: ok\" },\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthis.capabilityCheck = undefined;\n\t\t\tthis.conditionalVerified = false;\n\t\t\tif (error instanceof Error && error.name === \"AbortError\") throw error;\n\t\t\tdiagnostics.push({\n\t\t\t\tkey: \"webdav-probe\",\n\t\t\t\tlevel: \"error\",\n\t\t\t\tmessage: `webdav publication is read-only until diagnostics pass: ${errorMessage(error)}`,\n\t\t\t});\n\t\t\treturn diagnostics;\n\t\t}\n\t\ttry {\n\t\t\tdiagnostics.push({\n\t\t\t\tkey: \"webdav-history\",\n\t\t\t\tlevel: \"info\",\n\t\t\t\tmessage: await this.reconcileActiveHistory(signal),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.name === \"AbortError\") throw error;\n\t\t\tdiagnostics.push({\n\t\t\t\tkey: \"webdav-history\",\n\t\t\t\tlevel: \"error\",\n\t\t\t\tmessage: `webdav history repair failed: ${errorMessage(error)}`,\n\t\t\t});\n\t\t}\n\t\treturn diagnostics;\n\t}\n\n\tprivate ensureAtomicConditions(signal?: AbortSignal) {\n\t\tif (this.capabilityCheck) return this.capabilityCheck;\n\t\tthis.conditionalVerified = false;\n\t\tconst check = this.runCapabilityProbe(signal).finally(() => {\n\t\t\tif (this.capabilityCheck === check) this.capabilityCheck = undefined;\n\t\t});\n\t\tthis.capabilityCheck = check;\n\t\treturn check;\n\t}\n\n\tprivate async runCapabilityProbe(signal?: AbortSignal) {\n\t\tthrowIfAborted(signal);\n\t\tconst probeCollection = `${rootPath(this.config)}/.pi-sync-probes/${randomUUID()}`;\n\t\tconst probe = `${probeCollection}/conditional.txt`;\n\t\tconst client = new WebDavClient(this.config, signal);\n\t\tlet created = false;\n\t\tlet operationError: unknown;\n\t\ttry {\n\t\t\tcreated = true;\n\t\t\tawait client.ensureCollection(probeCollection);\n\t\t\tawait client.listCollection(probeCollection);\n\t\t\tawait client.putBuffer(probe, Buffer.from(\"first\"), \"text/plain\", { ifAbsent: true });\n\t\t\tconst read = await client.getBuffer(probe);\n\t\t\tconst etag = strongEtag(read.etag);\n\t\t\tif (!read.value || !etag) {\n\t\t\t\tthrow new Error(\"WebDAV server did not return a strong ETag for the capability probe.\");\n\t\t\t}\n\t\t\tawait expectPrecondition(\n\t\t\t\tclient.putBuffer(probe, Buffer.from(\"replace\"), \"text/plain\", { ifAbsent: true }),\n\t\t\t\t\"If-None-Match\",\n\t\t\t);\n\t\t\tawait expectPrecondition(\n\t\t\t\tclient.putBuffer(probe, Buffer.from(\"replace\"), \"text/plain\", {\n\t\t\t\t\tifMatch: '\"pi-sync-deliberately-stale\"',\n\t\t\t\t}),\n\t\t\t\t\"If-Match\",\n\t\t\t);\n\t\t\tconst unchanged = await client.getBuffer(probe);\n\t\t\tif (!unchanged.value?.equals(Buffer.from(\"first\"))) {\n\t\t\t\tthrow new Error(\"WebDAV server changed a probe despite a failed precondition.\");\n\t\t\t}\n\t\t\tawait client.putBuffer(probe, Buffer.from(\"second\"), \"text/plain\", { ifMatch: etag });\n\t\t\tconst changed = await client.getBuffer(probe);\n\t\t\tconst changedEtag = strongEtag(changed.etag);\n\t\t\tif (!changed.value?.equals(Buffer.from(\"second\")) || !changedEtag || changedEtag === etag) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"WebDAV server did not rotate its strong ETag after changing the capability probe.\",\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\toperationError = error;\n\t\t}\n\t\tif (created) {\n\t\t\ttry {\n\t\t\t\tawait new WebDavClient(this.config, undefined).delete(probeCollection);\n\t\t\t} catch (cleanupError) {\n\t\t\t\tconst operationDetail = operationError\n\t\t\t\t\t? `WebDAV probe failed: ${errorMessage(operationError)}; `\n\t\t\t\t\t: \"\";\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${operationDetail}probe cleanup also failed; remove ${probeCollection}: ${errorMessage(cleanupError)}`,\n\t\t\t\t\t{ cause: operationError ?? cleanupError },\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (operationError) throw operationError;\n\t\tthis.conditionalVerified = true;\n\t}\n\n\tprivate async resolveChecksum(reference: string, signal?: AbortSignal) {\n\t\tawait this.readHead(signal);\n\t\tif (this.checksums.has(reference)) return this.checksums.get(reference);\n\t\tawait this.listHistory(signal);\n\t\treturn this.checksums.get(reference);\n\t}\n\n\tprivate registerChecksum(reference: string, checksum: string) {\n\t\tconst known = this.checksums.get(reference);\n\t\tif (known && known !== checksum) {\n\t\t\tthrow new Error(\"Remote snapshot reference was rebound to a different checksum.\");\n\t\t}\n\t\tthis.checksums.set(reference, checksum);\n\t}\n\n\tprivate async readHeadAfterCommit(client: WebDavClient) {\n\t\tconst object = await client.getJson<LatestPointer>(latestPath(this.config));\n\t\tif (object.missing) return undefined;\n\t\treturn remoteHead(\n\t\t\trequirePointer(object.value, this.config.destination.namespace),\n\t\t\tthis.identity,\n\t\t\tobject.etag,\n\t\t);\n\t}\n\n\tprivate async reconcileActiveHistory(signal?: AbortSignal) {\n\t\tconst client = new WebDavClient(this.config, signal);\n\t\tconst object = await client.getJson<LatestPointer>(latestPath(this.config));\n\t\tthrowIfAborted(signal);\n\t\tif (object.missing) return \"webdav history: no active snapshot\";\n\t\tconst pointer = requirePointer(object.value, this.config.destination.namespace);\n\t\tthis.registerChecksum(pointer.snapshot, pointer.sha256);\n\t\tconst repaired = await this.ensureHistoryPointer(client, pointer);\n\t\treturn repaired\n\t\t\t? \"webdav history: repaired active snapshot entry\"\n\t\t\t: \"webdav history: active snapshot entry present\";\n\t}\n\n\tprivate async ensureHistoryPointer(client: WebDavClient, pointer: LatestPointer) {\n\t\tconst object = await client.getJson<{ version: number; snapshots: LatestPointer[] }>(\n\t\t\thistoryPath(this.config),\n\t\t);\n\t\tconst snapshots = object.missing\n\t\t\t? []\n\t\t\t: requireHistory(object.value, this.config.destination.namespace);\n\t\tconst existing = snapshots.find((entry) => entry.snapshot === pointer.snapshot);\n\t\tif (existing) {\n\t\t\tif (!samePointer(existing, pointer)) {\n\t\t\t\tthrow new Error(\"Remote history rebound an immutable snapshot reference.\");\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\tconst next = [...snapshots, pointer].slice(-100);\n\t\tconst condition = object.missing\n\t\t\t? { ifAbsent: true }\n\t\t\t: { ifMatch: requireStrongEtag(object.etag, \"history\") };\n\t\tawait client.putJson(\n\t\t\thistoryPath(this.config),\n\t\t\t{ version: VERSION, snapshots: next },\n\t\t\tcondition,\n\t\t);\n\t\treturn true;\n\t}\n\n\tprivate async updateHistorySafely(client: WebDavClient, pointer: LatestPointer) {\n\t\ttry {\n\t\t\tawait this.ensureHistoryPointer(client, pointer);\n\t\t\treturn undefined;\n\t\t} catch (error) {\n\t\t\treturn `Remote snapshot is active, but history could not be updated: ${errorMessage(error)}. Run /sync doctor before relying on history.`;\n\t\t}\n\t}\n}\n\nexport function rootPath(config: ResolvedWebDavBackend) {\n\treturn config.destination.path;\n}\n\nexport function latestPath(config: ResolvedWebDavBackend) {\n\treturn joinRemote(rootPath(config), \"latest.json\");\n}\n\nexport function historyPath(config: ResolvedWebDavBackend) {\n\treturn joinRemote(rootPath(config), \"history.json\");\n}\n\nexport function snapshotsPath(config: ResolvedWebDavBackend) {\n\treturn joinRemote(rootPath(config), \"snapshots\");\n}\n\nexport function snapshotPath(config: ResolvedWebDavBackend, reference: string) {\n\trequireSnapshotReference(reference);\n\treturn joinRemote(snapshotsPath(config), `${reference}.json.gz`);\n}\n\nexport function webDavBackendIdentity(config: ResolvedWebDavBackend) {\n\treturn `webdav:${sha256(\n\t\tBuffer.from(JSON.stringify([secretFreeUrl(config.profile.url), config.destination.path])),\n\t)}`;\n}\n\nfunction webDavStorageLocation(config: ResolvedWebDavBackend) {\n\tconst url = new URL(secretFreeUrl(config.profile.url));\n\treturn `${url.host} \u00B7 ${rootPath(config)}`;\n}\n\nfunction pointerFor(\n\tconfig: ResolvedWebDavBackend,\n\tsnapshot: Snapshot,\n\tchecksum: string,\n): LatestPointer {\n\treturn {\n\t\tversion: VERSION,\n\t\tprofile: config.destination.namespace,\n\t\tsnapshot: snapshot.id,\n\t\tsha256: checksum,\n\t\tcreatedAt: snapshot.createdAt,\n\t\tmachine: snapshot.machine,\n\t\tsyncSessions:\n\t\t\tsnapshot.syncSessions === true ||\n\t\t\tsnapshot.files.some((file) => file.path.startsWith(\"sessions/\")),\n\t\t...(snapshot.selection === undefined ? {} : { selection: snapshot.selection }),\n\t};\n}\n\nfunction remoteHead(pointer: LatestPointer, identity: string, etag?: string): RemoteHead {\n\treturn {\n\t\tsnapshotRef: pointer.snapshot,\n\t\tsnapshotId: pointer.snapshot,\n\t\trevision: encodeRevision(identity, etag, pointer),\n\t\tcreatedAt: pointer.createdAt,\n\t\tmachine: pointer.machine,\n\t\tsyncSessions: pointer.syncSessions === true,\n\t\t...(pointer.selection === undefined ? {} : { selection: pointer.selection }),\n\t};\n}\n\nfunction encodeRevision(identity: string, etag: string | undefined, pointer: LatestPointer) {\n\treturn `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\ttry {\n\t\tif (!value.startsWith(\"webdav-v1:\")) return undefined;\n\t\tconst parsed = JSON.parse(Buffer.from(value.slice(10), \"base64url\").toString(\"utf8\")) as {\n\t\t\tidentity?: unknown;\n\t\t\tetag?: unknown;\n\t\t};\n\t\tif (parsed.identity !== identity || typeof parsed.etag !== \"string\") return undefined;\n\t\treturn strongEtag(parsed.etag);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction publicationCondition(\n\tcurrent: RemoteObject<LatestPointer>,\n\texpected: ExpectedRemoteHead,\n\tidentity: string,\n) {\n\tif (expected.kind === \"missing\") return { ifAbsent: true };\n\tconst etag = decodeRevision(expected.revision, identity) ?? strongEtag(current.etag);\n\tif (!etag) throw new SyncBackendConflictError(\"WebDAV head has no usable strong ETag.\");\n\treturn { ifMatch: etag };\n}\n\nasync function expectPrecondition(operation: Promise<unknown>, header: string) {\n\ttry {\n\t\tawait operation;\n\t} catch (error) {\n\t\tif (error instanceof WebDavPreconditionError) return;\n\t\tthrow error;\n\t}\n\tthrow new Error(`WebDAV server ignored ${header}; publication is read-only for safety.`);\n}\n\nfunction requireStrongEtag(value: string | undefined, resource: string) {\n\tconst etag = strongEtag(value);\n\tif (!etag) throw new Error(`WebDAV ${resource} has no strong ETag.`);\n\treturn etag;\n}\n\nfunction strongEtag(value: string | undefined) {\n\treturn value && !value.startsWith(\"W/\") && /^\"[^\"\\r\\n]+\"$/u.test(value) ? value : undefined;\n}\n\nfunction requirePointer(value: LatestPointer | undefined, expectedProfile: string) {\n\tif (\n\t\t!value ||\n\t\tvalue.version !== VERSION ||\n\t\tvalue.profile !== expectedProfile ||\n\t\t!isSafeReference(value.snapshot) ||\n\t\t!/^[0-9a-f]{64}$/u.test(value.sha256) ||\n\t\t!isSafeMetadata(value.createdAt, 64) ||\n\t\t!isSafeMetadata(value.machine, 256) ||\n\t\t(value.syncSessions !== undefined && typeof value.syncSessions !== \"boolean\")\n\t) {\n\t\tthrow new Error(\"Remote latest pointer is malformed.\");\n\t}\n\tif (value.selection !== undefined) portableSnapshotSelection(value.selection);\n\treturn value;\n}\n\nfunction requireHistory(\n\tvalue: { version: number; snapshots: LatestPointer[] } | undefined,\n\texpectedProfile: string,\n) {\n\tif (!value || value.version !== VERSION || !Array.isArray(value.snapshots)) {\n\t\tthrow new Error(\"Remote history is malformed.\");\n\t}\n\tconst pointers = value.snapshots.map((item) => requirePointer(item, expectedProfile));\n\tif (new Set(pointers.map((item) => item.snapshot)).size !== pointers.length) {\n\t\tthrow new Error(\"Remote history contains duplicate snapshot references.\");\n\t}\n\treturn pointers;\n}\n\nfunction remoteHistoryEntry(pointer: LatestPointer): RemoteHistoryEntry {\n\treturn {\n\t\tsnapshotRef: pointer.snapshot,\n\t\tsnapshotId: pointer.snapshot,\n\t\tcreatedAt: pointer.createdAt,\n\t\tmachine: pointer.machine,\n\t\tsyncSessions: pointer.syncSessions === true,\n\t};\n}\n\nfunction assertSnapshotIdentity(snapshot: Snapshot, namespace: string) {\n\tif (\n\t\tsnapshot.version !== VERSION ||\n\t\tsnapshot.profile !== namespace ||\n\t\t!isSafeReference(snapshot.id) ||\n\t\t!isSafeMetadata(snapshot.createdAt, 64) ||\n\t\t!isSafeMetadata(snapshot.machine, 256) ||\n\t\t!Array.isArray(snapshot.files)\n\t) {\n\t\tthrow new Error(\"Invalid snapshot identity for WebDAV publication.\");\n\t}\n}\n\nfunction validateSnapshotBundle(snapshot: Snapshot) {\n\tconst paths = new Set<string>();\n\tfor (const file of snapshot.files) {\n\t\tif (\n\t\t\t!file ||\n\t\t\t!isSafeSnapshotPath(file.path) ||\n\t\t\tpaths.has(file.path) ||\n\t\t\ttypeof file.contentBase64 !== \"string\" ||\n\t\t\ttypeof file.sha256 !== \"string\"\n\t\t) {\n\t\t\tthrow new Error(\"Remote snapshot bundle is malformed.\");\n\t\t}\n\t\tconst content = Buffer.from(file.contentBase64, \"base64\");\n\t\tif (content.toString(\"base64\") !== file.contentBase64 || sha256(content) !== file.sha256) {\n\t\t\tthrow new Error(\"Remote snapshot bundle is malformed.\");\n\t\t}\n\t\tpaths.add(file.path);\n\t}\n}\n\nfunction isSafeSnapshotPath(value: unknown): value is string {\n\tif (typeof value !== \"string\" || !value || value.length > 4096 || value.includes(\"\\\\\")) {\n\t\treturn false;\n\t}\n\tif (\n\t\t[...value].some((character) => {\n\t\t\tconst code = character.codePointAt(0) ?? 0;\n\t\t\treturn code < 0x20 || (code >= 0x7f && code <= 0x9f);\n\t\t})\n\t) {\n\t\treturn false;\n\t}\n\treturn value.split(\"/\").every((segment) => segment && segment !== \".\" && segment !== \"..\");\n}\n\nfunction assertSafeDestination(config: ResolvedWebDavBackend) {\n\tconst url = new URL(config.profile.url);\n\tif (url.username || url.password || url.search || url.hash)\n\t\tthrow new Error(\"Invalid WebDAV URL.\");\n\tfor (const value of [config.destination.path, config.destination.namespace]) {\n\t\tif (\n\t\t\t!value ||\n\t\t\tvalue.includes(\"\\\\\") ||\n\t\t\t[...value].some((character) => {\n\t\t\t\tconst code = character.codePointAt(0) ?? 0;\n\t\t\t\treturn code < 0x20 || (code >= 0x7f && code <= 0x9f);\n\t\t\t}) ||\n\t\t\tvalue.split(\"/\").some((part) => part === \".\" || part === \"..\")\n\t\t) {\n\t\t\tthrow new Error(\"Invalid WebDAV storage location.\");\n\t\t}\n\t}\n}\n\nfunction isSafeMetadata(value: unknown, maxLength: number): value is string {\n\treturn (\n\t\ttypeof value === \"string\" &&\n\t\tvalue.length > 0 &&\n\t\tvalue.length <= maxLength &&\n\t\t![...value].some((character) => {\n\t\t\tconst code = character.codePointAt(0) ?? 0;\n\t\t\treturn code < 0x20 || (code >= 0x7f && code <= 0x9f);\n\t\t})\n\t);\n}\n\nfunction requireSnapshotReference(reference: string) {\n\tif (!isSafeReference(reference)) throw new Error(\"Invalid WebDAV snapshot reference.\");\n}\n\nfunction isSafeReference(value: string) {\n\treturn (\n\t\t!!value &&\n\t\tvalue.length <= 512 &&\n\t\t// biome-ignore lint/suspicious/noControlCharactersInRegex: Remote references cannot contain terminal controls.\n\t\t!/[\\\\/\\u0000-\\u001f\\u007f-\\u009f]/u.test(value) &&\n\t\tvalue !== \".\" &&\n\t\tvalue !== \"..\"\n\t);\n}\n\nfunction matchesExpected(head: RemoteHead | undefined, expected: ExpectedRemoteHead) {\n\treturn expected.kind === \"missing\" ? head === undefined : head?.revision === expected.revision;\n}\n\nfunction samePointer(left: LatestPointer, right: LatestPointer) {\n\treturn canonicalJson(left) === canonicalJson(right);\n}\n\nfunction canonicalJson(value: unknown): string {\n\tif (Array.isArray(value))\n\t\treturn JSON.stringify(value.map((item) => JSON.parse(canonicalJson(item))));\n\tif (!value || typeof value !== \"object\") return JSON.stringify(value);\n\treturn JSON.stringify(\n\t\tObject.fromEntries(\n\t\t\tObject.keys(value)\n\t\t\t\t.sort()\n\t\t\t\t.map((key) => [key, JSON.parse(canonicalJson((value as Record<string, unknown>)[key]))]),\n\t\t),\n\t);\n}\n\nfunction joinRemote(...parts: string[]) {\n\treturn parts\n\t\t.flatMap((part) => part.split(\"/\"))\n\t\t.filter(Boolean)\n\t\t.join(\"/\");\n}\n\nfunction secretFreeUrl(value: string) {\n\tconst url = new URL(value);\n\turl.username = \"\";\n\turl.password = \"\";\n\turl.search = \"\";\n\turl.hash = \"\";\n\treturn url.toString();\n}\n\nfunction sha256(value: Buffer) {\n\treturn createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction throwIfAborted(signal?: AbortSignal) {\n\tif (!signal?.aborted) return;\n\tthrow signal.reason instanceof Error\n\t\t? signal.reason\n\t\t: new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n\nfunction errorMessage(error: unknown) {\n\tif (error instanceof WebDavHttpError) return error.message;\n\treturn error instanceof Error ? error.message : String(error);\n}\n", "import { XMLParser } from \"fast-xml-parser\";\nimport type { RemoteObject, ResolvedWebDavBackend } from \"./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\tifAbsent?: boolean;\n\tifMatch?: string;\n}\n\nexport interface WebDavEntry {\n\thref: string;\n\tetag?: string;\n\tcollection: boolean;\n}\n\nexport class WebDavHttpError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\treadonly status: number,\n\t\toptions?: ErrorOptions,\n\t) {\n\t\tsuper(message, options);\n\t\tthis.name = \"WebDavHttpError\";\n\t}\n}\n\nexport class WebDavPreconditionError extends WebDavHttpError {\n\tconstructor(message = \"WebDAV precondition failed.\") {\n\t\tsuper(message, 412);\n\t\tthis.name = \"WebDavPreconditionError\";\n\t}\n}\n\nexport class WebDavClient {\n\tprivate readonly baseUrl: URL;\n\tprivate readonly authorization: string;\n\n\tconstructor(\n\t\tprivate readonly config: ResolvedWebDavBackend,\n\t\tprivate readonly signal?: AbortSignal,\n\t\tprivate readonly timeoutMs = REQUEST_TIMEOUT_MS,\n\t) {\n\t\tthis.baseUrl = new URL(config.profile.url);\n\t\tassertSafeAuthenticatedUrl(this.baseUrl);\n\t\tif (\n\t\t\t!config.profile.username ||\n\t\t\t!config.profile.password ||\n\t\t\tconfig.profile.username.includes(\":\") ||\n\t\t\thasControlCharacter(config.profile.username) ||\n\t\t\thasControlCharacter(config.profile.password)\n\t\t) {\n\t\t\tthrow new Error(\"Invalid WebDAV credentials.\");\n\t\t}\n\t\tthis.authorization = `Basic ${Buffer.from(`${config.profile.username}:${config.profile.password}`).toString(\"base64\")}`;\n\t}\n\n\tasync getBuffer(remotePath: string): Promise<RemoteObject<Buffer>> {\n\t\tconst response = await this.request(remotePath, { method: \"GET\" });\n\t\tif (response.status === 404) {\n\t\t\tawait response.body?.cancel();\n\t\t\treturn { missing: true };\n\t\t}\n\t\tawait this.requireOk(response, \"read\");\n\t\treturn {\n\t\t\tvalue: await readBounded(response, SNAPSHOT_LIMIT, \"WebDAV response is too large\"),\n\t\t\tetag: response.headers.get(\"etag\") ?? undefined,\n\t\t\tmissing: false,\n\t\t};\n\t}\n\n\tasync getJson<T>(remotePath: string): Promise<RemoteObject<T>> {\n\t\tconst response = await this.request(remotePath, { method: \"GET\" });\n\t\tif (response.status === 404) {\n\t\t\tawait response.body?.cancel();\n\t\t\treturn { missing: true };\n\t\t}\n\t\tawait this.requireOk(response, \"read\");\n\t\tconst bytes = await readBounded(response, JSON_LIMIT, \"WebDAV JSON response is too large\");\n\t\ttry {\n\t\t\treturn {\n\t\t\t\tvalue: JSON.parse(bytes.toString(\"utf8\")) as T,\n\t\t\t\tetag: response.headers.get(\"etag\") ?? undefined,\n\t\t\t\tmissing: false,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new Error(\"WebDAV JSON response is malformed.\", { cause: error });\n\t\t}\n\t}\n\n\tasync putBuffer(\n\t\tremotePath: string,\n\t\tbody: Buffer,\n\t\tcontentType: string,\n\t\toptions: WebDavPutOptions = {},\n\t) {\n\t\tconst headers: Record<string, string> = { \"content-type\": contentType };\n\t\tif (options.ifAbsent) headers[\"if-none-match\"] = \"*\";\n\t\tif (options.ifMatch) headers[\"if-match\"] = options.ifMatch;\n\t\tconst response = await this.request(remotePath, {\n\t\t\tmethod: \"PUT\",\n\t\t\theaders,\n\t\t\tbody: body as unknown as BodyInit,\n\t\t});\n\t\tif (response.status === 412) {\n\t\t\tawait response.body?.cancel();\n\t\t\tthrow new WebDavPreconditionError();\n\t\t}\n\t\tawait this.requireOk(response, \"write\");\n\t\tawait response.body?.cancel();\n\t\treturn response.headers.get(\"etag\") ?? undefined;\n\t}\n\n\tasync putJson(remotePath: string, value: unknown, options: WebDavPutOptions = {}) {\n\t\treturn this.putBuffer(\n\t\t\tremotePath,\n\t\t\tBuffer.from(JSON.stringify(value)),\n\t\t\t\"application/json\",\n\t\t\toptions,\n\t\t);\n\t}\n\n\tasync makeCollection(remotePath: string) {\n\t\tconst response = await this.request(remotePath, { method: \"MKCOL\" });\n\t\tif (response.status === 405) {\n\t\t\tawait response.body?.cancel();\n\t\t\treturn false;\n\t\t}\n\t\tawait this.requireOk(response, \"create collection\");\n\t\tawait response.body?.cancel();\n\t\treturn true;\n\t}\n\n\tasync ensureCollection(remotePath: string) {\n\t\tconst segments = safeSegments(remotePath);\n\t\tfor (let index = 1; index <= segments.length; index += 1) {\n\t\t\tawait this.makeCollection(segments.slice(0, index).join(\"/\"));\n\t\t}\n\t}\n\n\tasync listCollection(remotePath: string): Promise<WebDavEntry[]> {\n\t\tconst response = await this.request(remotePath, {\n\t\t\tmethod: \"PROPFIND\",\n\t\t\theaders: { depth: \"1\", \"content-type\": \"application/xml; charset=utf-8\" },\n\t\t\tbody: '<?xml version=\"1.0\"?><d:propfind xmlns:d=\"DAV:\"><d:prop><d:getetag/><d:resourcetype/></d:prop></d:propfind>',\n\t\t});\n\t\tif (response.status === 404) {\n\t\t\tawait response.body?.cancel();\n\t\t\tthrow new WebDavHttpError(\"WebDAV collection is missing.\", 404);\n\t\t}\n\t\tif (response.status !== 207) await this.requireOk(response, \"list collection\");\n\t\tconst xml = (\n\t\t\tawait readBounded(response, XML_LIMIT, \"WebDAV directory response is too large\")\n\t\t).toString(\"utf8\");\n\t\ttry {\n\t\t\tconst parsed = new XMLParser({\n\t\t\t\tremoveNSPrefix: true,\n\t\t\t\tignoreAttributes: false,\n\t\t\t\tprocessEntities: false,\n\t\t\t}).parse(xml) as {\n\t\t\t\tmultistatus?: { response?: unknown };\n\t\t\t};\n\t\t\tif (!parsed.multistatus || parsed.multistatus.response === undefined) {\n\t\t\t\tthrow new Error(\"Missing DAV multistatus response.\");\n\t\t\t}\n\t\t\tconst responses = asArray(parsed.multistatus.response);\n\t\t\treturn responses.map(parseEntry);\n\t\t} catch (error) {\n\t\t\tthrow new Error(\"WebDAV directory response is malformed.\", { cause: error });\n\t\t}\n\t}\n\n\tasync delete(remotePath: string) {\n\t\tconst response = await this.request(remotePath, { method: \"DELETE\" });\n\t\tif (response.status === 404) {\n\t\t\tawait response.body?.cancel();\n\t\t\treturn;\n\t\t}\n\t\tif (response.status === 207) {\n\t\t\tawait response.body?.cancel();\n\t\t\tthrow new WebDavHttpError(\"WebDAV probe cleanup returned a partial response.\", 207);\n\t\t}\n\t\tawait this.requireOk(response, \"delete probe resource\");\n\t\tawait response.body?.cancel();\n\t}\n\n\tprivate async request(remotePath: string, init: RequestInit) {\n\t\tthrowIfAborted(this.signal);\n\t\tlet url = appendRemotePath(this.baseUrl, remotePath);\n\t\tfor (let redirects = 0; ; redirects += 1) {\n\t\t\tconst timeout = AbortSignal.timeout(this.timeoutMs);\n\t\t\tconst signal = this.signal ? AbortSignal.any([this.signal, timeout]) : timeout;\n\t\t\tlet response: Response;\n\t\t\ttry {\n\t\t\t\tresponse = await fetch(url, {\n\t\t\t\t\t...init,\n\t\t\t\t\theaders: {\n\t\t\t\t\t\taccept: \"*/*\",\n\t\t\t\t\t\tauthorization: this.authorization,\n\t\t\t\t\t\t...headersObject(init.headers),\n\t\t\t\t\t},\n\t\t\t\t\tredirect: \"manual\",\n\t\t\t\t\tsignal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tthrowIfAborted(this.signal);\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`WebDAV ${String(init.method ?? \"GET\")} request failed for ${redactText(safeUrl(url), this.config)}.`,\n\t\t\t\t\t{\n\t\t\t\t\t\tcause: redactError(error, this.config),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (![301, 302, 303, 307, 308].includes(response.status)) return response;\n\t\t\tawait response.body?.cancel();\n\t\t\tconst method = String(init.method ?? \"GET\").toUpperCase();\n\t\t\tif ([301, 302, 303].includes(response.status) && method !== \"GET\" && method !== \"HEAD\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`WebDAV refused an ambiguous HTTP ${response.status} redirect for ${method}; configure the canonical collection URL or require HTTP 307/308.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (redirects >= MAX_REDIRECTS) throw new Error(\"WebDAV redirect limit exceeded.\");\n\t\t\tconst location = response.headers.get(\"location\");\n\t\t\tif (!location) throw new Error(\"WebDAV redirect is missing Location.\");\n\t\t\tconst next = new URL(location, url);\n\t\t\tif (next.origin !== this.baseUrl.origin) {\n\t\t\t\tthrow new Error(\"WebDAV refused a cross-origin authenticated redirect.\");\n\t\t\t}\n\t\t\turl = next;\n\t\t}\n\t}\n\n\tprivate async requireOk(response: Response, action: string) {\n\t\tif (response.ok) return;\n\t\tconst body = (await readBounded(response, ERROR_LIMIT, \"WebDAV error body is too large\"))\n\t\t\t.toString(\"utf8\")\n\t\t\t// biome-ignore lint/suspicious/noControlCharactersInRegex: Remote error text is untrusted terminal input.\n\t\t\t.replace(/[\\u0000-\\u001f\\u007f-\\u009f]/gu, \" \")\n\t\t\t.trim();\n\t\tconst detail = body ? `: ${redactText(body, this.config)}` : \"\";\n\t\tthrow new WebDavHttpError(\n\t\t\t`WebDAV ${action} failed with HTTP ${response.status}${detail}`,\n\t\t\tresponse.status,\n\t\t);\n\t}\n}\n\nfunction assertSafeAuthenticatedUrl(url: URL) {\n\tconst loopback =\n\t\turl.hostname === \"127.0.0.1\" ||\n\t\turl.hostname === \"localhost\" ||\n\t\turl.hostname === \"[::1]\" ||\n\t\turl.hostname === \"::1\";\n\tif (\n\t\turl.username ||\n\t\turl.password ||\n\t\turl.search ||\n\t\turl.hash ||\n\t\t(url.protocol !== \"https:\" && !(url.protocol === \"http:\" && loopback))\n\t) {\n\t\tthrow new Error(\n\t\t\t\"Invalid WebDAV URL: HTTPS is required and embedded credentials, query, or fragment are not allowed.\",\n\t\t);\n\t}\n}\n\nfunction hasControlCharacter(value: string) {\n\treturn [...value].some((character) => {\n\t\tconst code = character.codePointAt(0) ?? 0;\n\t\treturn code < 0x20 || (code >= 0x7f && code <= 0x9f);\n\t});\n}\n\nfunction appendRemotePath(base: URL, remotePath: string) {\n\tconst url = new URL(base);\n\tconst suffix = safeSegments(remotePath).map(encodeURIComponent).join(\"/\");\n\turl.pathname = `${base.pathname.replace(/\\/+$/u, \"\")}/${suffix}`;\n\treturn url;\n}\n\nfunction safeSegments(value: string) {\n\tconst segments = value\n\t\t.replace(/^\\/+|\\/+$/gu, \"\")\n\t\t.split(\"/\")\n\t\t.filter(Boolean);\n\tif (\n\t\tsegments.some(\n\t\t\t(segment) =>\n\t\t\t\tsegment === \".\" ||\n\t\t\t\tsegment === \"..\" ||\n\t\t\t\t// biome-ignore lint/suspicious/noControlCharactersInRegex: Remote path segments cannot contain controls.\n\t\t\t\t/[\\u0000-\\u001f]/u.test(segment),\n\t\t)\n\t) {\n\t\tthrow new Error(\"Invalid WebDAV remote path.\");\n\t}\n\treturn segments;\n}\n\nasync function readBounded(response: Response, limit: number, message: string) {\n\tconst length = Number(response.headers.get(\"content-length\"));\n\tif (Number.isFinite(length) && length > limit) {\n\t\tawait response.body?.cancel();\n\t\tthrow new Error(message);\n\t}\n\tif (!response.body) return Buffer.alloc(0);\n\tconst reader = response.body.getReader();\n\tconst chunks: Buffer[] = [];\n\tlet total = 0;\n\ttry {\n\t\twhile (true) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) break;\n\t\t\ttotal += value.byteLength;\n\t\t\tif (total > limit) throw new Error(message);\n\t\t\tchunks.push(Buffer.from(value));\n\t\t}\n\t} catch (error) {\n\t\tawait reader.cancel().catch(() => undefined);\n\t\tthrow error;\n\t}\n\treturn Buffer.concat(chunks, total);\n}\n\nfunction parseEntry(value: unknown): WebDavEntry {\n\tif (!value || typeof value !== \"object\") throw new Error(\"Invalid WebDAV response entry.\");\n\tconst record = value as Record<string, unknown>;\n\tconst href = typeof record.href === \"string\" ? record.href : undefined;\n\tif (!href) throw new Error(\"Invalid WebDAV response href.\");\n\tconst propstat = asArray(record.propstat).find((item) => {\n\t\tif (!item || typeof item !== \"object\") return false;\n\t\treturn String((item as Record<string, unknown>).status ?? \"\").includes(\" 200 \");\n\t}) as Record<string, unknown> | undefined;\n\tconst prop = propstat?.prop as Record<string, unknown> | undefined;\n\treturn {\n\t\thref,\n\t\tetag: typeof prop?.getetag === \"string\" ? prop.getetag : undefined,\n\t\tcollection:\n\t\t\t!!prop?.resourcetype &&\n\t\t\ttypeof prop.resourcetype === \"object\" &&\n\t\t\tObject.hasOwn(prop.resourcetype, \"collection\"),\n\t};\n}\n\nfunction asArray(value: unknown): unknown[] {\n\tif (value === undefined) return [];\n\treturn Array.isArray(value) ? value : [value];\n}\n\nfunction headersObject(headers: HeadersInit | undefined) {\n\treturn Object.fromEntries(new Headers(headers).entries());\n}\n\nfunction safeUrl(url: URL) {\n\treturn `${url.protocol}//${url.host}${url.pathname}`;\n}\n\nfunction redactError(error: unknown, config: ResolvedWebDavBackend) {\n\tconst message = error instanceof Error ? error.message : String(error);\n\treturn new Error(redactText(message, config));\n}\n\nfunction redactText(value: string, config: ResolvedWebDavBackend) {\n\tlet result = value;\n\tfor (const secret of [config.profile.username, config.profile.password, config.profile.url]) {\n\t\tif (!secret) continue;\n\t\tfor (const variant of new Set([secret, encodeURIComponent(secret)])) {\n\t\t\tresult = result.replace(new RegExp(escapeRegExp(variant), \"giu\"), \"[redacted]\");\n\t\t}\n\t}\n\treturn result\n\t\t.replace(/basic\\s+[a-z0-9+/=]+/giu, \"Basic [redacted]\")\n\t\t.replace(/\\?[^\\s]*/gu, \"?[redacted]\");\n}\n\nfunction escapeRegExp(value: string) {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/gu, \"\\\\$&\");\n}\n\nfunction throwIfAborted(signal?: AbortSignal) {\n\tif (!signal?.aborted) return;\n\tthrow signal.reason instanceof Error\n\t\t? signal.reason\n\t\t: new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["throwIfAborted"]
|
|
7
|
-
}
|