@narumitw/pi-sync 0.49.15 → 0.50.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -16
- package/dist/chunks/attention-widget-Z7G3SYYJ.ts +9 -0
- package/dist/chunks/attention-widget-Z7G3SYYJ.ts.map +7 -0
- package/dist/chunks/chunk-2B2ELUF5.ts +29 -0
- package/dist/chunks/chunk-2B2ELUF5.ts.map +7 -0
- package/dist/chunks/{chunk-ARN2672F.ts → chunk-4CHTZMEO.ts} +23 -55
- package/dist/chunks/chunk-4CHTZMEO.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-JF6MZCT4.ts → chunk-AUSDLD6F.ts} +4 -4
- package/dist/chunks/chunk-AUSDLD6F.ts.map +7 -0
- package/dist/chunks/{chunk-5T442OP3.ts → chunk-C7XY5NF5.ts} +210 -373
- package/dist/chunks/chunk-C7XY5NF5.ts.map +7 -0
- package/dist/chunks/chunk-CCSN3F47.ts +51 -0
- package/dist/chunks/chunk-CCSN3F47.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-WSOBYHIZ.ts → chunk-ETTRJDNP.ts} +4 -4
- package/dist/chunks/chunk-ETTRJDNP.ts.map +7 -0
- package/dist/chunks/{chunk-44LPGQTI.ts → chunk-G4RNQQZS.ts} +9 -7
- package/dist/chunks/chunk-G4RNQQZS.ts.map +7 -0
- package/dist/chunks/{chunk-5LZALPCD.ts → chunk-HUDQATCL.ts} +25 -25
- package/dist/chunks/chunk-HUDQATCL.ts.map +7 -0
- package/dist/chunks/{chunk-X7SQ2EQM.ts → chunk-IJ6FJFA5.ts} +9 -9
- package/dist/chunks/chunk-IJ6FJFA5.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-KW7YQEZN.ts +1255 -0
- package/dist/chunks/chunk-KW7YQEZN.ts.map +7 -0
- package/dist/chunks/{chunk-DFXBKHGN.ts → chunk-LCRI3ABW.ts} +21 -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-HVUSHMVL.ts → chunk-OEX4ABY6.ts} +39 -37
- package/dist/chunks/chunk-OEX4ABY6.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-S7YBZR42.ts +146 -0
- package/dist/chunks/chunk-S7YBZR42.ts.map +7 -0
- package/dist/chunks/{chunk-GLQLN5GV.ts → chunk-SL64RLXR.ts} +8 -6
- package/dist/chunks/chunk-SL64RLXR.ts.map +7 -0
- package/dist/chunks/chunk-SZWBGPID.ts +57 -0
- package/dist/chunks/chunk-SZWBGPID.ts.map +7 -0
- package/dist/chunks/chunk-T2B5IU74.ts +25 -0
- package/dist/chunks/chunk-T2B5IU74.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-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-RKEHALNQ.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-GMVS4PD4.ts} +39 -14
- package/dist/chunks/git-backend-GMVS4PD4.ts.map +7 -0
- package/dist/chunks/manager-result-dispatcher-FKIBM3GO.ts +22 -0
- package/dist/chunks/manager-ui-R3XPUFFS.ts +1680 -0
- package/dist/chunks/manager-ui-R3XPUFFS.ts.map +7 -0
- package/dist/chunks/remote-selection-ui-D7RBRJNL.ts +21 -0
- package/dist/chunks/{s3-backend-552LXHE4.ts → s3-backend-66O4FGBH.ts} +94 -16
- package/dist/chunks/s3-backend-66O4FGBH.ts.map +7 -0
- package/dist/chunks/{setup-switch-5YDG5YGJ.ts → setup-switch-IS2PEZ3J.ts} +9 -9
- package/dist/chunks/setup-wizard-IUB6ESEU.ts +89 -0
- package/dist/chunks/setup-wizard-IUB6ESEU.ts.map +7 -0
- package/dist/chunks/{snapshot-2RYBUDRA.ts → snapshot-HKEWCVK6.ts} +7 -6
- package/dist/chunks/sync-inspection-CST2KL65.ts +20 -0
- package/dist/chunks/{sync-operations-3LLIHWZO.ts → sync-operations-LBX3GKCM.ts} +369 -289
- package/dist/chunks/sync-operations-LBX3GKCM.ts.map +7 -0
- package/dist/chunks/{sync-state-SRN6YRBK.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 +476 -341
- package/dist/index.ts.map +4 -4
- package/docs/settings.md +30 -6
- package/package.json +1 -1
- 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} +39 -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} +34 -325
- 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 -286
- package/src/ui/attention-widget.ts +1 -0
- 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} +17 -13
- 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/ui/sync-attention.ts +187 -0
- 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-44LPGQTI.ts.map +0 -7
- package/dist/chunks/chunk-4U6AFLJB.ts.map +0 -7
- package/dist/chunks/chunk-5LZALPCD.ts.map +0 -7
- package/dist/chunks/chunk-5MQ76BK5.ts.map +0 -7
- package/dist/chunks/chunk-5T442OP3.ts.map +0 -7
- package/dist/chunks/chunk-ARN2672F.ts.map +0 -7
- package/dist/chunks/chunk-C7LXZ3UH.ts +0 -167
- package/dist/chunks/chunk-C7LXZ3UH.ts.map +0 -7
- package/dist/chunks/chunk-DFXBKHGN.ts.map +0 -7
- package/dist/chunks/chunk-E4COSV32.ts +0 -82
- package/dist/chunks/chunk-E4COSV32.ts.map +0 -7
- package/dist/chunks/chunk-F5QL2GPY.ts.map +0 -7
- package/dist/chunks/chunk-GLQLN5GV.ts.map +0 -7
- package/dist/chunks/chunk-HGV24P4T.ts.map +0 -7
- package/dist/chunks/chunk-HVUSHMVL.ts.map +0 -7
- package/dist/chunks/chunk-JF6MZCT4.ts.map +0 -7
- package/dist/chunks/chunk-WSOBYHIZ.ts.map +0 -7
- package/dist/chunks/chunk-X7SQ2EQM.ts.map +0 -7
- package/dist/chunks/chunk-YQ6UW7IF.ts.map +0 -7
- package/dist/chunks/file-selection-RKEHALNQ.ts.map +0 -7
- package/dist/chunks/git-backend-E3UOUUOM.ts.map +0 -7
- package/dist/chunks/manager-result-dispatcher-LWPYJAD5.ts +0 -18
- package/dist/chunks/manager-ui-NF4RUHBY.ts +0 -2785
- package/dist/chunks/manager-ui-NF4RUHBY.ts.map +0 -7
- package/dist/chunks/remote-selection-ui-NUF5P4ZJ.ts +0 -17
- package/dist/chunks/s3-backend-552LXHE4.ts.map +0 -7
- package/dist/chunks/sync-operations-3LLIHWZO.ts.map +0 -7
- package/dist/chunks/webdav-backend-ZD5RHRIU.ts.map +0 -7
- package/src/config.ts +0 -923
- package/src/git-ui.ts +0 -307
- package/src/manager-helpers.ts +0 -64
- package/src/manager-ui.ts +0 -997
- package/src/sync-attention.ts +0 -100
- package/src/webdav-ui.ts +0 -421
- /package/dist/chunks/{manager-result-dispatcher-LWPYJAD5.ts.map → manager-result-dispatcher-FKIBM3GO.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-NUF5P4ZJ.ts.map → remote-selection-ui-D7RBRJNL.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-5YDG5YGJ.ts.map → setup-switch-IS2PEZ3J.ts.map} +0 -0
- /package/dist/chunks/{snapshot-2RYBUDRA.ts.map → snapshot-HKEWCVK6.ts.map} +0 -0
- /package/dist/chunks/{sync-state-SRN6YRBK.ts.map → sync-inspection-CST2KL65.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
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/backends/s3/s3-backend.ts", "../../src/backends/s3/s3-client.ts"],
|
|
4
|
+
"sourcesContent": ["import { createHash } from \"node:crypto\";\nimport { encodeKey, posixJoin } from \"../../paths.js\";\nimport { sessionTokenWarnings } from \"../../settings/config.js\";\nimport { decodeSnapshot, encodeSnapshot } from \"../../snapshot/snapshot-codec.js\";\nimport type { Snapshot } from \"../../snapshot/snapshot-types.js\";\nimport { syncErrorGuidance } from \"../../sync/sync-error-guidance.js\";\nimport { portableSnapshotSelection } from \"../../sync/sync-policy.js\";\nimport type { LatestPointer, RemoteObject, ResolvedS3Backend } from \"../backend-types.js\";\nimport {\n\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 { S3Client, S3ObjectAlreadyExistsError } from \"./s3-client.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\tconst diagnostics: BackendDiagnostic[] = [\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\tconst deadline = AbortSignal.timeout(10_000);\n\t\tconst probeSignal = signal ? AbortSignal.any([signal, deadline]) : deadline;\n\t\ttry {\n\t\t\tconst result = await new S3Client(this.config, probeSignal).diagnoseRead(\n\t\t\t\tlatestKey(this.config),\n\t\t\t);\n\t\t\tthrowIfAborted(probeSignal);\n\t\t\tconst messages = {\n\t\t\t\treadable:\n\t\t\t\t\t\"s3 remote read: HTTP success. Snapshot contents and write access are not tested.\",\n\t\t\t\t\"missing-key\":\n\t\t\t\t\t\"s3 remote read: no snapshot at this path (NoSuchKey). Write access is not tested; verify the bucket and path before first sync.\",\n\t\t\t\t\"missing-bucket\":\n\t\t\t\t\t\"s3 remote read: bucket not found (NoSuchBucket). Create the bucket with your provider or edit the setup's bucket name.\",\n\t\t\t\t\"unknown-404\":\n\t\t\t\t\t\"s3 remote read: HTTP 404; cannot confirm whether the bucket or snapshot is missing. Verify the endpoint, bucket, and path with your provider. Write access is not tested.\",\n\t\t\t};\n\t\t\tdiagnostics.push({\n\t\t\t\tkey: \"s3-read\",\n\t\t\t\tlevel: result === \"readable\" ? \"info\" : \"warning\",\n\t\t\t\tmessage: messages[result],\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthrowIfAborted(signal);\n\t\t\tdiagnostics.push({\n\t\t\t\tkey: \"s3-read\",\n\t\t\t\tlevel: \"warning\",\n\t\t\t\tmessage: syncErrorGuidance(\n\t\t\t\t\tdeadline.aborted ? new Error(\"S3 diagnostic request timed out.\") : error,\n\t\t\t\t),\n\t\t\t});\n\t\t}\n\t\treturn diagnostics;\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 === \"./\" ? \"\" : 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 (label === \"prefix\" && value === \"./\") continue;\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 \"../backend-types.js\";\n\nconst MAX_JSON_RESPONSE_BYTES = 1024 * 1024;\nconst MAX_SNAPSHOT_RESPONSE_BYTES = 256 * 1024 * 1024;\nconst MAX_ERROR_RESPONSE_BYTES = 64 * 1024;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 30_000;\n\nfunction iso8601Basic(date: Date) {\n\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 S3HttpError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\treadonly status: number,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"S3HttpError\";\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\t/** Read-only access probe. A bare 404 cannot distinguish a missing key from a missing bucket. */\n\tasync diagnoseRead(\n\t\tkey: string,\n\t): Promise<\"readable\" | \"missing-key\" | \"missing-bucket\" | \"unknown-404\"> {\n\t\tthis.signal?.throwIfAborted();\n\t\tconst response = await this.request(\"GET\", key);\n\t\tif (response.ok) {\n\t\t\tawait response.body?.cancel();\n\t\t\tthis.signal?.throwIfAborted();\n\t\t\treturn \"readable\";\n\t\t}\n\t\tconst detail = await this.readErrorText(response);\n\t\tthis.signal?.throwIfAborted();\n\t\tif (response.status === 404) {\n\t\t\tconst code = /<Code>\\s*([A-Za-z]+)\\s*<\\/Code>/u.exec(detail)?.[1];\n\t\t\tif (code === \"NoSuchBucket\") return \"missing-bucket\";\n\t\t\tif (code === \"NoSuchKey\") return \"missing-key\";\n\t\t\treturn \"unknown-404\";\n\t\t}\n\t\tthrow new S3HttpError(`S3 remote read failed (HTTP ${response.status}).`, response.status);\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 S3HttpError(\n\t\t\t\t\t`S3 GET failed (${object.status}): ${await this.readErrorText(object)}`,\n\t\t\t\t\tobject.status,\n\t\t\t\t);\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 S3HttpError(\n\t\t\t\t\t`S3 GET failed (${object.status}): ${await this.readErrorText(object)}`,\n\t\t\t\t\tobject.status,\n\t\t\t\t);\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 S3HttpError(\n\t\t\t\t`S3 PUT failed (${response.status}): ${await this.readErrorText(response)}`,\n\t\t\t\tresponse.status,\n\t\t\t);\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\ttry {\n\t\t\tif (!(await this.shouldRetryWithoutSessionToken(response, sessionToken))) return response;\n\t\t} catch (error) {\n\t\t\tawait response.body?.cancel().catch(() => undefined);\n\t\t\tthrow error;\n\t\t}\n\t\tawait response.body?.cancel();\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\t// Do not await cancellation of a cloned stream before its sibling can be released.\n\t\tvoid response.body?.cancel().catch(() => undefined);\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\tvoid 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": ";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,cAAAA,mBAAkB;;;ACA3B,SAAS,YAAY,kBAAkB;AACvC,SAAS,cAAc,aAAa;AAIpC,IAAM,0BAA0B,OAAO;AACvC,IAAM,8BAA8B,MAAM,OAAO;AACjD,IAAM,2BAA2B,KAAK;AACtC,IAAM,6BAA6B;AAEnC,SAAS,aAAa,MAAY;AACjC,SAAO,KAAK,YAAY,EAAE,QAAQ,iBAAiB,EAAE;AACtD;AAEA,SAAS,uBAAuB,UAA8B;AAC7D,QAAM,QAAQ,UAAU,KAAK;AAC7B,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI;AACH,UAAM,WAAW,IAAI,IAAI,KAAK,EAAE,SAAS,YAAY;AACrD,WACC,aAAa,8BAA8B,SAAS,SAAS,2BAA2B;AAAA,EAE1F,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEO,IAAM,6BAAN,cAAyC,MAAM;AAAA,EACrD,YAAqB,KAAa;AACjC,UAAM,6BAA6B,GAAG,EAAE;AADpB;AAEpB,SAAK,OAAO;AAAA,EACb;AAAA,EAHqB;AAItB;AAEO,IAAM,cAAN,cAA0B,MAAM;AAAA,EACtC,YACC,SACS,QACR;AACD,UAAM,OAAO;AAFJ;AAGT,SAAK,OAAO;AAAA,EACb;AAAA,EAJU;AAKX;AAEO,IAAM,WAAN,MAAe;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,iCAAiC;AAAA,EAEzC,YACC,QACA,QACA,mBAAmB,4BAClB;AACD,SAAK,SAAS;AACd,SAAK,WAAW,IAAI,IAAI,OAAO,QAAQ,QAAQ;AAC/C,SAAK,SAAS;AACd,SAAK,mBAAmB;AAAA,EACzB;AAAA;AAAA,EAGA,MAAM,aACL,KACyE;AACzE,SAAK,QAAQ,eAAe;AAC5B,UAAM,WAAW,MAAM,KAAK,QAAQ,OAAO,GAAG;AAC9C,QAAI,SAAS,IAAI;AAChB,YAAM,SAAS,MAAM,OAAO;AAC5B,WAAK,QAAQ,eAAe;AAC5B,aAAO;AAAA,IACR;AACA,UAAM,SAAS,MAAM,KAAK,cAAc,QAAQ;AAChD,SAAK,QAAQ,eAAe;AAC5B,QAAI,SAAS,WAAW,KAAK;AAC5B,YAAM,OAAO,mCAAmC,KAAK,MAAM,IAAI,CAAC;AAChE,UAAI,SAAS,eAAgB,QAAO;AACpC,UAAI,SAAS,YAAa,QAAO;AACjC,aAAO;AAAA,IACR;AACA,UAAM,IAAI,YAAY,+BAA+B,SAAS,MAAM,MAAM,SAAS,MAAM;AAAA,EAC1F;AAAA,EAEA,MAAM,QAAW,KAAuC;AACvD,UAAM,cAAc;AACpB,QAAI;AACJ,aAAS,UAAU,GAAG,WAAW,aAAa,WAAW;AACxD,YAAM,SAAS,MAAM,KAAK,QAAQ,OAAO,GAAG;AAC5C,UAAI,OAAO,WAAW,IAAK,QAAO,EAAE,SAAS,KAAK;AAClD,UAAI,CAAC,OAAO,IAAI;AACf,cAAM,IAAI;AAAA,UACT,kBAAkB,OAAO,MAAM,MAAM,MAAM,KAAK,cAAc,MAAM,CAAC;AAAA,UACrE,OAAO;AAAA,QACR;AAAA,MACD;AACA,YAAM,OAAO,MAAM,gBAAgB,QAAQ,yBAAyB,kBAAkB;AAMtF,UAAI,KAAK,SAAS,GAAG;AACpB,eAAO;AAAA,UACN,OAAO,KAAK,MAAM,IAAI;AAAA,UACtB,MAAM,cAAc,OAAO,QAAQ,IAAI,MAAM,CAAC;AAAA,UAC9C,SAAS;AAAA,QACV;AAAA,MACD;AACA,kBAAY,IAAI,MAAM,qCAAqC,GAAG,EAAE;AAChE,UAAI,UAAU,aAAa;AAC1B,cAAM,MAAM,MAAM,SAAS,QAAW,EAAE,QAAQ,KAAK,OAAO,CAAC;AAAA,MAC9D;AAAA,IACD;AACA,UAAM;AAAA,EACP;AAAA,EAEA,MAAM,UAAU,KAA4C;AAC3D,UAAM,cAAc;AACpB,QAAI;AACJ,aAAS,UAAU,GAAG,WAAW,aAAa,WAAW;AACxD,YAAM,SAAS,MAAM,KAAK,QAAQ,OAAO,GAAG;AAC5C,UAAI,OAAO,WAAW,IAAK,QAAO,EAAE,SAAS,KAAK;AAClD,UAAI,CAAC,OAAO,IAAI;AACf,cAAM,IAAI;AAAA,UACT,kBAAkB,OAAO,MAAM,MAAM,MAAM,KAAK,cAAc,MAAM,CAAC;AAAA,UACrE,OAAO;AAAA,QACR;AAAA,MACD;AACA,YAAM,SAAS,MAAM;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAQA,UAAI,OAAO,SAAS,GAAG;AACtB,eAAO,EAAE,OAAO,QAAQ,MAAM,cAAc,OAAO,QAAQ,IAAI,MAAM,CAAC,GAAG,SAAS,MAAM;AAAA,MACzF;AACA,kBAAY,IAAI,MAAM,qCAAqC,GAAG,EAAE;AAChE,UAAI,UAAU,aAAa;AAC1B,cAAM,MAAM,MAAM,SAAS,QAAW,EAAE,QAAQ,KAAK,OAAO,CAAC;AAAA,MAC9D;AAAA,IACD;AACA,UAAM;AAAA,EACP;AAAA,EAEA,MAAM,QAAQ,KAAa,OAAgB;AAC1C,UAAM,OAAO,OAAO,KAAK,KAAK,UAAU,OAAO,MAAM,GAAI,GAAG,MAAM;AAClE,UAAM,KAAK,UAAU,KAAK,MAAM,kBAAkB;AAAA,EACnD;AAAA,EAEA,MAAM,UACL,KACA,MACA,aACA,UAAkC,CAAC,GAClC;AACD,UAAM,UAAkC,EAAE,gBAAgB,YAAY;AACtE,QAAI,QAAQ,SAAU,SAAQ,eAAe,IAAI;AACjD,UAAM,WAAW,MAAM,KAAK,QAAQ,OAAO,KAAK,MAAM,OAAO;AAC7D,QAAI,QAAQ,YAAY,SAAS,WAAW,KAAK;AAChD,YAAM,IAAI,2BAA2B,GAAG;AAAA,IACzC;AACA,QAAI,CAAC,SAAS,IAAI;AACjB,YAAM,IAAI;AAAA,QACT,kBAAkB,SAAS,MAAM,MAAM,MAAM,KAAK,cAAc,QAAQ,CAAC;AAAA,QACzE,SAAS;AAAA,MACV;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAc,QACb,QACA,KACA,MACA,eAAuC,CAAC,GACvC;AACD,UAAM,MAAM,IAAI,IAAI,KAAK,SAAS,SAAS,CAAC;AAC5C,QAAI,WAAW,UAAU,IAAI,UAAU,KAAK,OAAO,YAAY,QAAQ,UAAU,GAAG,CAAC;AACrF,UAAM,OAAO,OAAOC,kBAAqC;AACxD,YAAM,kBAAkB,KAAK,gBAAgB;AAC7C,YAAM,UAAU,MAAM,cAAc;AAAA,QACnC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa,KAAK,OAAO,QAAQ;AAAA,QACjC,iBAAiB,KAAK,OAAO,QAAQ;AAAA,QACrC,cAAAA;AAAA,QACA,QAAQ,KAAK,OAAO,QAAQ;AAAA,MAC7B,CAAC;AACD,UAAI;AACH,eAAO,MAAM,MAAM,KAAK;AAAA,UACvB;AAAA,UACA;AAAA,UACA,MAAM,OAAO,IAAI,WAAW,IAAI,IAAI;AAAA,UACpC,QAAQ;AAAA,QACT,CAAC;AAAA,MACF,SAAS,OAAO;AACf,YAAI,iBAAiB,SAAS,MAAM,SAAS,aAAc,OAAM;AACjE,YAAI,iBAAiB,SAAS,MAAM,SAAS,gBAAgB;AAC5D,gBAAM,IAAI,MAAM,yBAAyB,EAAE,OAAO,MAAM,CAAC;AAAA,QAC1D;AACA,cAAM,IAAI,MAAM,sBAAsB,KAAK,OAAO,aAAa,KAAK,CAAC,CAAC,IAAI,EAAE,OAAO,MAAM,CAAC;AAAA,MAC3F;AAAA,IACD;AACA,UAAM,eAAe,KAAK,iCACvB,SACA,KAAK,OAAO,QAAQ;AACvB,UAAM,WAAW,MAAM,KAAK,YAAY;AACxC,QAAI;AACH,UAAI,CAAE,MAAM,KAAK,+BAA+B,UAAU,YAAY,EAAI,QAAO;AAAA,IAClF,SAAS,OAAO;AACf,YAAM,SAAS,MAAM,OAAO,EAAE,MAAM,MAAM,MAAS;AACnD,YAAM;AAAA,IACP;AACA,UAAM,SAAS,MAAM,OAAO;AAC5B,UAAM,QAAQ,MAAM,KAAK,MAAS;AAClC,QAAI,MAAM,MAAM,MAAM,WAAW,IAAK,MAAK,iCAAiC;AAC5E,WAAO;AAAA,EACR;AAAA,EAEQ,kBAAkB;AACzB,UAAM,UAAU,YAAY,QAAQ,KAAK,gBAAgB;AACzD,WAAO,KAAK,SAAS,YAAY,IAAI,CAAC,KAAK,QAAQ,OAAO,CAAC,IAAI;AAAA,EAChE;AAAA,EAEA,MAAc,+BACb,UACA,cACC;AACD,QACC,CAAC,gBACD,CAAC,uBAAuB,KAAK,OAAO,QAAQ,QAAQ,KACpD,SAAS,MACT,SAAS,WAAW,KACnB;AACD,aAAO;AAAA,IACR;AACA,WAAO;AAAA,MACN,MAAM,gBAAgB,SAAS,MAAM,GAAG,0BAA0B,mBAAmB;AAAA,IACtF;AAAA,EACD;AAAA,EAEA,MAAc,cAAc,UAAoB;AAC/C,QAAI;AACH,aAAO,KAAK;AAAA,QACX,MAAM,gBAAgB,UAAU,0BAA0B,mBAAmB;AAAA,MAC9E;AAAA,IACD,SAAS,OAAO;AACf,aAAO,KAAK,OAAO,aAAa,KAAK,CAAC;AAAA,IACvC;AAAA,EACD;AAAA,EAEQ,OAAO,OAAe;AAC7B,QAAI,WAAW;AACf,QAAI;AACJ,QAAI;AACJ,QAAI,sBAAgC,CAAC;AACrC,QAAI;AACH,YAAM,WAAW,IAAI,IAAI,KAAK,OAAO,QAAQ,QAAQ;AACrD,yBAAmB,SAAS;AAC5B,yBAAmB,SAAS;AAC5B,4BAAsB,CAAC,GAAG,SAAS,aAAa,OAAO,CAAC;AAAA,IACzD,QAAQ;AAAA,IAER;AACA,eAAW,UAAU;AAAA,MACpB,KAAK,OAAO,QAAQ;AAAA,MACpB,KAAK,OAAO,QAAQ;AAAA,MACpB,KAAK,OAAO,QAAQ;AAAA,MACpB;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACJ,GAAG;AACF,UAAI,OAAQ,YAAW,SAAS,WAAW,QAAQ,YAAY;AAAA,IAChE;AACA,WAAO;AAAA,EACR;AACD;AAEA,eAAe,gBAAgB,UAAoB,OAAe,OAAe;AAChF,UAAQ,MAAM,kBAAkB,UAAU,OAAO,KAAK,GAAG,SAAS,MAAM;AACzE;AAEA,eAAe,kBAAkB,UAAoB,OAAe,OAAe;AAClF,QAAM,gBAAgB,OAAO,SAAS,QAAQ,IAAI,gBAAgB,CAAC;AACnE,MAAI,OAAO,SAAS,aAAa,KAAK,gBAAgB,OAAO;AAE5D,SAAK,SAAS,MAAM,OAAO,EAAE,MAAM,MAAM,MAAS;AAClD,UAAM,IAAI,MAAM,GAAG,KAAK,gBAAgB,KAAK,cAAc;AAAA,EAC5D;AACA,MAAI,CAAC,SAAS,KAAM,QAAO,OAAO,MAAM,CAAC;AACzC,QAAM,SAAS,SAAS,KAAK,UAAU;AACvC,QAAM,SAAmB,CAAC;AAC1B,MAAI,QAAQ;AACZ,MAAI;AACH,WAAO,MAAM;AACZ,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,KAAM;AACV,eAAS,MAAM;AACf,UAAI,QAAQ,OAAO;AAClB,aAAK,OAAO,OAAO,EAAE,MAAM,MAAM,MAAS;AAC1C,cAAM,IAAI,MAAM,GAAG,KAAK,gBAAgB,KAAK,cAAc;AAAA,MAC5D;AACA,aAAO,KAAK,OAAO,KAAK,KAAK,CAAC;AAAA,IAC/B;AAAA,EACD,UAAE;AACD,WAAO,YAAY;AAAA,EACpB;AACA,SAAO,OAAO,OAAO,QAAQ,KAAK;AACnC;AAEA,SAAS,aAAa,OAAgB;AACrC,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC7D;AAEA,eAAe,cAAc,OAS1B;AACF,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,UAAU,aAAa,GAAG;AAChC,QAAM,YAAY,QAAQ,MAAM,GAAG,CAAC;AACpC,QAAM,cAAc,OAAO,MAAM,QAAQ,OAAO,MAAM,CAAC,CAAC;AACxD,QAAM,UAAkC;AAAA,IACvC,GAAG,cAAc,MAAM,YAAY;AAAA,IACnC,MAAM,MAAM,IAAI;AAAA,IAChB,wBAAwB;AAAA,IACxB,cAAc;AAAA,EACf;AACA,MAAI,MAAM,aAAc,SAAQ,sBAAsB,IAAI,MAAM;AAChE,QAAM,oBAAoB,OAAO,KAAK,OAAO,EAAE,KAAK;AACpD,QAAM,mBAAmB,kBACvB,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,QAAQ,IAAI,GAAG,KAAK,CAAC;AAAA,CAAI,EAClD,KAAK,EAAE;AACT,QAAM,mBAAmB;AAAA,IACxB,MAAM;AAAA,IACN,MAAM,IAAI;AAAA,IACV,MAAM,IAAI,aAAa,SAAS;AAAA,IAChC;AAAA,IACA,kBAAkB,KAAK,GAAG;AAAA,IAC1B;AAAA,EACD,EAAE,KAAK,IAAI;AACX,QAAM,QAAQ,GAAG,SAAS,IAAI,MAAM,MAAM;AAC1C,QAAM,eAAe;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,OAAO,KAAK,gBAAgB,CAAC;AAAA,EACrC,EAAE,KAAK,IAAI;AACX,QAAM,aAAa;AAAA,IAClB,KAAK,KAAK,KAAK,OAAO,KAAK,OAAO,MAAM,eAAe,EAAE,GAAG,SAAS,GAAG,MAAM,MAAM,GAAG,IAAI;AAAA,IAC3F;AAAA,EACD;AACA,QAAM,YAAY,WAAW,UAAU,UAAU,EAAE,OAAO,YAAY,EAAE,OAAO,KAAK;AACpF,SAAO;AAAA,IACN,GAAG;AAAA,IACH,eAAe,+BAA+B,MAAM,WAAW,IAAI,KAAK,mBAAmB,kBAAkB,KAAK,GAAG,CAAC,eAAe,SAAS;AAAA,EAC/I;AACD;AAEA,SAAS,KAAK,KAAa,OAAe;AACzC,SAAO,WAAW,UAAU,GAAG,EAAE,OAAO,KAAK,EAAE,OAAO;AACvD;AAEA,SAAS,OAAO,OAAe;AAC9B,SAAO,WAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AACvD;AAEA,SAAS,cAAc,OAA+B;AACrD,SAAO,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,YAAY,GAAG,IAAI,CAAC,CAAC;AAChG;AAEA,SAAS,cAAc,OAAsB;AAC5C,SAAO,SAAS;AACjB;AAEA,SAAS,+BAA+B,MAAc;AACrD,SACC,KAAK,SAAS,8BAA8B,KAC5C,KAAK,SAAS,yCAAyC;AAEzD;;;ADtXA,IAAM,UAAU;AAChB,IAAM,yBAAyB;AAExB,IAAM,gBAAN,MAA2C;AAAA,EAMjD,YACkB,QACA,sBAAsB,wBACtC;AAFgB;AACA;AAEjB,0BAAsB,MAAM;AAC5B,SAAK,WAAW,kBAAkB,MAAM;AACxC,SAAK,cAAc,cAAc,MAAM;AAAA,EACxC;AAAA,EANkB;AAAA,EACA;AAAA,EAPT;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACL,YAAY,oBAAI,IAAoB;AAAA,EAWrD,aAAa,MAAc,OAAe;AACzC,WAAO,SAAS;AAAA,EACjB;AAAA,EAEA,MAAM,SAAS,QAAuD;AACrE,UAAM,SAAS,MAAM,IAAI,SAAS,KAAK,QAAQ,MAAM,EAAE;AAAA,MACtD,UAAU,KAAK,MAAM;AAAA,IACtB;AACA,mBAAe,MAAM;AACrB,QAAI,OAAO,QAAS,QAAO;AAC3B,UAAM,UAAU;AAAA,MACf,OAAO;AAAA,MACP;AAAA,MACA,KAAK,OAAO,YAAY;AAAA,IACzB;AACA,SAAK,iBAAiB,QAAQ,UAAU,QAAQ,MAAM;AACtD,WAAO,WAAW,SAAS,KAAK,UAAU,OAAO,IAAI;AAAA,EACtD;AAAA,EAEA,MAAM,aAAa,WAAmB,QAAyC;AAC9E,UAAM,mBACL,KAAK,UAAU,IAAI,SAAS,KAAM,MAAM,KAAK,gBAAgB,WAAW,MAAM;AAC/E,UAAM,SAAS,MAAM,IAAI,SAAS,KAAK,QAAQ,MAAM,EAAE;AAAA,MACtD,YAAY,KAAK,QAAQ,SAAS;AAAA,IACnC;AACA,mBAAe,MAAM;AACrB,QAAI,CAAC,OAAO,MAAO,OAAM,IAAI,MAAM,uBAAuB,SAAS,EAAE;AACrE,QAAI,oBAAoBC,QAAO,OAAO,KAAK,MAAM,kBAAkB;AAClE,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACrD;AACA,UAAM,WAAW,MAAM,eAAe,OAAO,OAAO,EAAE,OAAO,CAAC;AAC9D,QAAI,SAAS,OAAO,aAAa,SAAS,YAAY,KAAK,OAAO,YAAY,WAAW;AACxF,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACrD;AACA,2BAAuB,QAAQ;AAC/B,WAAO;AAAA,EACR;AAAA,EAEA,MAAM,gBACL,UACA,UACA,UAAkC,CAAC,GACF;AACjC,mBAAe,QAAQ,MAAM;AAC7B,2BAAuB,UAAU,KAAK,OAAO,YAAY,SAAS;AAClE,UAAM,YAAY,YAAY,KAAK,QAAQ,SAAS,EAAE;AACtD,UAAM,UAAU,MAAM,eAAe,QAAQ;AAC7C,mBAAe,QAAQ,MAAM;AAC7B,UAAM,UAAU,WAAW,KAAK,QAAQ,UAAUA,QAAO,OAAO,CAAC;AACjE,UAAM,oBAAoB,IAAI,SAAS,KAAK,QAAQ,QAAQ,MAAM;AAClE,QAAI;AACH,YAAM,kBAAkB,UAAU,WAAW,SAAS,oBAAoB;AAAA,QACzE,UAAU;AAAA,MACX,CAAC;AAAA,IACF,SAAS,OAAO;AACf,UAAI,EAAE,iBAAiB,4BAA6B,OAAM;AAC1D,YAAM,WAAW,MAAM,kBAAkB,UAAU,SAAS;AAC5D,UAAI,CAAC,SAAS,SAASA,QAAO,SAAS,KAAK,MAAM,QAAQ,QAAQ;AACjE,cAAM,IAAI;AAAA,UACT,gEAAgE,SAAS,EAAE;AAAA,QAC5E;AAAA,MACD;AAAA,IACD;AACA,UAAM,gBAAgB,MAAM,kBAAkB,QAAuB,UAAU,KAAK,MAAM,CAAC;AAC3F,mBAAe,QAAQ,MAAM;AAC7B,QAAI;AACJ,QAAI,CAAC,cAAc,SAAS;AAC3B,YAAM,iBAAiB;AAAA,QACtB,cAAc;AAAA,QACd;AAAA,QACA,KAAK,OAAO,YAAY;AAAA,MACzB;AACA,WAAK,iBAAiB,eAAe,UAAU,eAAe,MAAM;AACpE,gBAAU,WAAW,gBAAgB,KAAK,UAAU,cAAc,IAAI;AAAA,IACvE;AACA,QAAI,CAAC,gBAAgB,SAAS,QAAQ,GAAG;AACxC,YAAM,IAAI;AAAA,QACT;AAAA,QACA,EAAE,aAAa,QAAQ;AAAA,MACxB;AAAA,IACD;AACA,mBAAe,QAAQ,MAAM;AAC7B,YAAQ,WAAW;AAInB,UAAM,eAAe,IAAI,SAAS,KAAK,QAAQ,YAAY,QAAQ,KAAK,mBAAmB,CAAC;AAC5F,QAAI;AACH,YAAM,aAAa,QAAQ,UAAU,KAAK,MAAM,GAAG,OAAO;AAAA,IAC3D,SAAS,OAAO;AACf,YAAM,IAAI;AAAA,QACT,0CAA0CC,cAAa,KAAK,CAAC;AAAA,QAC7D,EAAE,OAAO,MAAM;AAAA,MAChB;AAAA,IACD;AAEA,QAAI;AACJ,QAAI;AACH,uBAAiB,MAAM,aAAa,QAAuB,UAAU,KAAK,MAAM,CAAC;AAAA,IAClF,SAAS,OAAO;AACf,YAAM,IAAI;AAAA,QACT,yEAAyEA,cAAa,KAAK,CAAC;AAAA,QAC5F,EAAE,OAAO,MAAM;AAAA,MAChB;AAAA,IACD;AACA,QAAI;AACJ,QAAI;AACH,wBAAkB;AAAA,QACjB,eAAe;AAAA,QACf;AAAA,QACA,KAAK,OAAO,YAAY;AAAA,MACzB;AAAA,IACD,SAAS,OAAO;AACf,YAAM,IAAI;AAAA,QACT,8EAA8EA,cAAa,KAAK,CAAC;AAAA,QACjG,EAAE,OAAO,MAAM;AAAA,MAChB;AAAA,IACD;AACA,QAAI,CAAC,YAAY,iBAAiB,OAAO,GAAG;AAC3C,YAAM,IAAI;AAAA,QACT;AAAA,QACA;AAAA,UACC,OAAO;AAAA,UACP,aAAa,WAAW,iBAAiB,KAAK,UAAU,eAAe,IAAI;AAAA,UAC3E,4BAA4B;AAAA,QAC7B;AAAA,MACD;AAAA,IACD;AACA,SAAK,iBAAiB,gBAAgB,UAAU,gBAAgB,MAAM;AACtE,UAAM,OAAO,WAAW,iBAAiB,KAAK,UAAU,eAAe,IAAI;AAC3E,UAAM,UAAU,MAAM,KAAK,oBAAoB,cAAc,OAAO;AACpE,WAAO,EAAE,MAAM,UAAU,UAAU,CAAC,OAAO,IAAI,CAAC,EAAE;AAAA,EACnD;AAAA,EAEA,MAAM,YAAY,QAAqD;AACtE,UAAM,SAAS,MAAM,IAAI,SAAS,KAAK,QAAQ,MAAM,EAAE,QAGpD,WAAW,KAAK,MAAM,CAAC;AAC1B,mBAAe,MAAM;AACrB,QAAI,OAAO,QAAS,QAAO,CAAC;AAC5B,UAAM,WAAW,eAAe,OAAO,OAAO,KAAK,OAAO,YAAY,SAAS;AAC/E,eAAW,WAAW,UAAU;AAC/B,YAAM,QAAQ,KAAK,UAAU,IAAI,QAAQ,QAAQ;AACjD,UAAI,SAAS,UAAU,QAAQ,QAAQ;AACtC,cAAM,IAAI,MAAM,sEAAsE;AAAA,MACvF;AAAA,IACD;AACA,eAAW,WAAW,SAAU,MAAK,iBAAiB,QAAQ,UAAU,QAAQ,MAAM;AACtF,WAAO,SAAS,IAAI,kBAAkB;AAAA,EACvC;AAAA,EAEA,MAAM,SAAS,QAAoD;AAClE,mBAAe,MAAM;AACrB,UAAM,cAAmC;AAAA,MACxC;AAAA,QACC,KAAK;AAAA,QACL,OAAO;AAAA,QACP,SAAS,kBAAkB,KAAK,OAAO,YAAY,MAAM,IAAI,YAAY,KAAK,MAAM,CAAC;AAAA,MACtF;AAAA,MACA,GAAG,qBAAqB,KAAK,OAAO,OAAO,EAAE,IAAI,CAAC,aAAa;AAAA,QAC9D,KAAK;AAAA,QACL,OAAO;AAAA,QACP;AAAA,MACD,EAAE;AAAA,IACH;AACA,UAAM,WAAW,YAAY,QAAQ,GAAM;AAC3C,UAAM,cAAc,SAAS,YAAY,IAAI,CAAC,QAAQ,QAAQ,CAAC,IAAI;AACnE,QAAI;AACH,YAAM,SAAS,MAAM,IAAI,SAAS,KAAK,QAAQ,WAAW,EAAE;AAAA,QAC3D,UAAU,KAAK,MAAM;AAAA,MACtB;AACA,qBAAe,WAAW;AAC1B,YAAM,WAAW;AAAA,QAChB,UACC;AAAA,QACD,eACC;AAAA,QACD,kBACC;AAAA,QACD,eACC;AAAA,MACF;AACA,kBAAY,KAAK;AAAA,QAChB,KAAK;AAAA,QACL,OAAO,WAAW,aAAa,SAAS;AAAA,QACxC,SAAS,SAAS,MAAM;AAAA,MACzB,CAAC;AAAA,IACF,SAAS,OAAO;AACf,qBAAe,MAAM;AACrB,kBAAY,KAAK;AAAA,QAChB,KAAK;AAAA,QACL,OAAO;AAAA,QACP,SAAS;AAAA,UACR,SAAS,UAAU,IAAI,MAAM,kCAAkC,IAAI;AAAA,QACpE;AAAA,MACD,CAAC;AAAA,IACF;AACA,WAAO;AAAA,EACR;AAAA,EAEA,MAAc,gBAAgB,WAAmB,QAAsB;AACtE,UAAM,KAAK,SAAS,MAAM;AAC1B,UAAM,eAAe,KAAK,UAAU,IAAI,SAAS;AACjD,QAAI,aAAc,QAAO;AACzB,UAAM,KAAK,YAAY,MAAM;AAC7B,WAAO,KAAK,UAAU,IAAI,SAAS;AAAA,EACpC;AAAA,EAEQ,iBAAiB,WAAmB,UAAkB;AAC7D,UAAM,QAAQ,KAAK,UAAU,IAAI,SAAS;AAC1C,QAAI,SAAS,UAAU,UAAU;AAChC,YAAM,IAAI,MAAM,gEAAgE;AAAA,IACjF;AACA,SAAK,UAAU,IAAI,WAAW,QAAQ;AAAA,EACvC;AAAA,EAEA,MAAc,oBAAoB,QAAkB,SAAwB;AAC3E,QAAI;AACH,YAAM,KAAK,cAAc,QAAQ,OAAO;AACxC,aAAO;AAAA,IACR,SAAS,OAAO;AACf,aAAO,gEAAgEA,cAAa,KAAK,CAAC;AAAA,IAC3F;AAAA,EACD;AAAA,EAEA,MAAc,cAAc,QAAkB,SAAwB;AACrE,UAAM,SAAS,MAAM,OAAO;AAAA,MAC3B,WAAW,KAAK,MAAM;AAAA,IACvB;AACA,UAAM,YAAY,OAAO,UACtB,CAAC,IACD,eAAe,OAAO,OAAO,KAAK,OAAO,YAAY,SAAS;AACjE,UAAM,OAAO;AAAA,MACZ,GAAG,UAAU,OAAO,CAAC,aAAa,SAAS,aAAa,QAAQ,QAAQ;AAAA,MACxE;AAAA,IACD,EAAE,MAAM,IAAI;AACZ,UAAM,OAAO,QAAQ,WAAW,KAAK,MAAM,GAAG,EAAE,SAAS,SAAS,WAAW,KAAK,CAAC;AAAA,EACpF;AACD;AAEO,SAAS,UAAU,QAA2B;AACpD,SAAO,UAAU,YAAY,MAAM,GAAG,aAAa;AACpD;AAEO,SAAS,WAAW,QAA2B;AACrD,SAAO,UAAU,YAAY,MAAM,GAAG,cAAc;AACrD;AAEO,SAAS,YAAY,QAA2B,IAAY;AAClE,2BAAyB,EAAE;AAC3B,SAAO,UAAU,YAAY,MAAM,GAAG,aAAa,GAAG,EAAE,UAAU;AACnE;AAEO,SAAS,YAAY,QAA2B;AACtD,SAAO,OAAO,YAAY,WAAW,OAAO,KAAK,OAAO,YAAY;AACrE;AAEO,SAAS,WACf,QACA,UACA,UACgB;AAChB,SAAO;AAAA,IACN,SAAS;AAAA,IACT,SAAS,OAAO,YAAY;AAAA,IAC5B,UAAU,SAAS;AAAA,IACnB,QAAQ;AAAA,IACR,WAAW,SAAS;AAAA,IACpB,SAAS,SAAS;AAAA,IAClB,cACC,SAAS,iBAAiB,QAC1B,SAAS,MAAM,KAAK,CAAC,SAAS,KAAK,KAAK,WAAW,WAAW,CAAC;AAAA,IAChE,GAAI,SAAS,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,SAAS,UAAU;AAAA,EAC7E;AACD;AAEO,SAAS,kBAAkB,QAA2B;AAC5D,QAAM,cAAc,KAAK,UAAU;AAAA,IAClC,mBAAmB,OAAO,QAAQ,QAAQ;AAAA,IAC1C,YAAY,OAAO,YAAY,MAAM;AAAA,IACrC,YAAY,OAAO,YAAY,MAAM;AAAA,EACtC,CAAC;AACD,SAAO,MAAMD,QAAO,OAAO,KAAK,WAAW,CAAC,CAAC;AAC9C;AAEA,SAAS,cAAc,QAA2B;AACjD,MAAI,OAAO,mBAAmB,OAAO,QAAQ,QAAQ;AACrD,MAAI;AACH,WAAO,IAAI,IAAI,IAAI,EAAE;AAAA,EACtB,QAAQ;AACP,WAAO;AAAA,EACR;AACA,SAAO,GAAG,IAAI,SAAM,OAAO,YAAY,MAAM,IAAI,YAAY,MAAM,CAAC;AACrE;AAEA,SAAS,mBAAmB,OAAe;AAC1C,QAAM,aAAa,MAAM,KAAK;AAC9B,MAAI;AACH,UAAM,MAAM,IAAI,IAAI,UAAU;AAC9B,QAAI,WAAW;AACf,QAAI,WAAW;AACf,WAAO,IAAI,SAAS;AAAA,EACrB,QAAQ;AACP,WAAO,WAAW,QAAQ,kBAAkB,IAAI;AAAA,EACjD;AACD;AAEA,SAAS,YAAY,OAAe;AACnC,SAAO,MAAM,QAAQ,cAAc,EAAE;AACtC;AAEA,SAAS,mBAAmB,SAA4C;AACvE,SAAO;AAAA,IACN,aAAa,QAAQ;AAAA,IACrB,YAAY,QAAQ;AAAA,IACpB,WAAW,QAAQ;AAAA,IACnB,SAAS,QAAQ;AAAA,IACjB,cAAc,QAAQ,iBAAiB;AAAA,EACxC;AACD;AAEA,SAAS,WAAW,SAAwB,UAAkB,MAA2B;AACxF,SAAO;AAAA,IACN,aAAa,QAAQ;AAAA,IACrB,YAAY,QAAQ;AAAA,IACpB,UAAU,MAAMA,QAAO,OAAO,KAAK,cAAc,CAAC,UAAU,QAAQ,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;AAAA,IACrF,WAAW,QAAQ;AAAA,IACnB,SAAS,QAAQ;AAAA,IACjB,cAAc,QAAQ,iBAAiB;AAAA,IACvC,GAAI,QAAQ,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,QAAQ,UAAU;AAAA,EAC3E;AACD;AAEA,SAAS,YAAY,MAAqB,OAAsB;AAC/D,SAAO,cAAc,IAAI,MAAM,cAAc,KAAK;AACnD;AAEA,SAAS,cAAc,OAAgB;AACtC,SAAO,KAAK,UAAU,eAAe,KAAK,CAAC;AAC5C;AAEA,SAAS,eAAe,OAAyB;AAChD,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,cAAc;AACzD,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,SAAO,OAAO;AAAA,IACb,OAAO,KAAK,KAAK,EACf,KAAK,EACL,IAAI,CAAC,QAAQ,CAAC,KAAK,eAAgB,MAAkC,GAAG,CAAC,CAAC,CAAC;AAAA,EAC9E;AACD;AAEA,SAAS,gBAAgB,MAA8B,UAA8B;AACpF,MAAI,SAAS,SAAS,UAAW,QAAO,SAAS;AACjD,SAAO,MAAM,aAAa,SAAS;AACpC;AAEA,SAAS,eACR,OACA,SACA,iBACC;AACD,MACC,CAAC,SACD,MAAM,YAAY,WAClB,MAAM,YAAY,mBAClB,OAAO,MAAM,aAAa,YAC1B,CAAC,wBAAwB,MAAM,QAAQ,KACvC,OAAO,MAAM,WAAW,YACxB,CAAC,iBAAiB,KAAK,MAAM,MAAM,KACnC,OAAO,MAAM,cAAc,YAC3B,CAAC,eAAe,MAAM,WAAW,EAAE,KACnC,OAAO,MAAM,YAAY,YACzB,CAAC,eAAe,MAAM,SAAS,GAAG,KACjC,MAAM,iBAAiB,UAAa,OAAO,MAAM,iBAAiB,WAClE;AACD,UAAM,IAAI,MAAM,OAAO;AAAA,EACxB;AACA,MAAI,MAAM,cAAc,OAAW,2BAA0B,MAAM,SAAS;AAC5E,SAAO;AACR;AAEA,SAAS,eACR,OACA,iBACC;AACD,MAAI,CAAC,SAAS,MAAM,YAAY,WAAW,CAAC,MAAM,QAAQ,MAAM,SAAS,GAAG;AAC3E,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAC/C;AACA,QAAM,WAAW,MAAM,UAAU;AAAA,IAAI,CAAC,YACrC,eAAe,SAAS,sCAAsC,eAAe;AAAA,EAC9E;AACA,QAAM,aAAa,oBAAI,IAAY;AACnC,aAAW,WAAW,UAAU;AAC/B,QAAI,WAAW,IAAI,QAAQ,QAAQ,GAAG;AACrC,YAAM,IAAI,MAAM,wDAAwD;AAAA,IACzE;AACA,eAAW,IAAI,QAAQ,QAAQ;AAAA,EAChC;AACA,SAAO;AACR;AAEA,SAAS,uBAAuB,UAAoB,iBAAyB;AAC5E,MACC,SAAS,YAAY,WACrB,SAAS,YAAY,mBACrB,CAAC,wBAAwB,SAAS,EAAE,KACpC,CAAC,eAAe,SAAS,WAAW,EAAE,KACtC,CAAC,eAAe,SAAS,SAAS,GAAG,KACrC,CAAC,MAAM,QAAQ,SAAS,KAAK,GAC5B;AACD,UAAM,IAAI,MAAM,+CAA+C;AAAA,EAChE;AACD;AAEA,SAAS,uBAAuB,UAAoB;AACnD,QAAM,QAAQ,oBAAI,IAAY;AAC9B,aAAW,QAAQ,SAAS,OAAO;AAClC,QACC,CAAC,QACD,OAAO,KAAK,SAAS,YACrB,OAAO,KAAK,kBAAkB,YAC9B,OAAO,KAAK,WAAW,YACvB,CAAC,iBAAiB,KAAK,KAAK,MAAM,KAClC,MAAM,IAAI,KAAK,IAAI,GAClB;AACD,YAAM,IAAI,MAAM,sCAAsC;AAAA,IACvD;AACA,UAAM,UAAU,OAAO,KAAK,KAAK,eAAe,QAAQ;AACxD,QAAI,QAAQ,SAAS,QAAQ,MAAM,KAAK,iBAAiBA,QAAO,OAAO,MAAM,KAAK,QAAQ;AACzF,YAAM,IAAI,MAAM,yCAAyC;AAAA,IAC1D;AACA,UAAM,IAAI,KAAK,IAAI;AAAA,EACpB;AACD;AAEA,SAAS,sBAAsB,QAA2B;AACzD,aAAW,CAAC,OAAO,OAAO,UAAU,KAAK;AAAA,IACxC,CAAC,UAAU,OAAO,YAAY,QAAQ,KAAK;AAAA,IAC3C,CAAC,UAAU,OAAO,YAAY,QAAQ,IAAI;AAAA,IAC1C,CAAC,aAAa,OAAO,YAAY,WAAW,KAAK;AAAA,EAClD,GAAY;AACX,QAAI,UAAU,YAAY,UAAU,KAAM;AAC1C,QACE,CAAC,cAAc,MAAM,WAAW,KACjC,MAAM,SAAS,IAAI,KACnB,oBAAoB,KAAK,KACzB,MAAM,MAAM,GAAG,EAAE,KAAK,CAAC,YAAY,YAAY,OAAO,YAAY,IAAI,GACrE;AACD,YAAM,IAAI,MAAM,+BAA+B,KAAK,GAAG;AAAA,IACxD;AAAA,EACD;AACD;AAEA,SAAS,yBAAyB,WAAmB;AACpD,MAAI,CAAC,wBAAwB,SAAS,GAAG;AACxC,UAAM,IAAI,MAAM,gCAAgC;AAAA,EACjD;AACD;AAEA,SAAS,wBAAwB,WAAmB;AACnD,SACC,UAAU,SAAS,KACnB,UAAU,UAAU,OACpB,cAAc,OACd,cAAc,QACd,CAAC,UAAU,SAAS,GAAG,KACvB,CAAC,UAAU,SAAS,IAAI,KACxB,CAAC,oBAAoB,SAAS;AAEhC;AAEA,SAAS,eAAe,OAAe,WAAmB;AACzD,SAAO,MAAM,SAAS,KAAK,MAAM,UAAU,aAAa,CAAC,oBAAoB,KAAK;AACnF;AAEA,SAAS,oBAAoB,OAAe;AAC3C,SAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,cAAc;AACrC,UAAM,OAAO,UAAU,YAAY,CAAC,KAAK;AACzC,WAAO,OAAO,MAAQ,SAAS;AAAA,EAChC,CAAC;AACF;AAEA,SAAS,eAAe,QAAsB;AAC7C,MAAI,CAAC,QAAQ,QAAS;AACtB,QAAM,OAAO,kBAAkB,QAC5B,OAAO,SACP,IAAI,aAAa,6BAA6B,YAAY;AAC9D;AAEA,SAASA,QAAO,OAAe;AAC9B,SAAOE,YAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AACvD;AAEA,SAASD,cAAa,OAAgB;AACrC,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC7D;",
|
|
6
|
+
"names": ["createHash", "sessionToken", "sha256", "errorMessage", "createHash"]
|
|
7
|
+
}
|
|
@@ -6,16 +6,16 @@ import {
|
|
|
6
6
|
setupSwitchActionFromLabel,
|
|
7
7
|
setupSwitchActionLabel,
|
|
8
8
|
useSyncSetup
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-SL64RLXR.ts";
|
|
10
|
+
import "./chunk-CHH26D4F.ts";
|
|
11
|
+
import "./chunk-LTBWGSBV.ts";
|
|
12
|
+
import "./chunk-C7XY5NF5.ts";
|
|
13
|
+
import "./chunk-6LP3MCR2.ts";
|
|
14
|
+
import "./chunk-TEN2ZBJV.ts";
|
|
11
15
|
import {
|
|
12
16
|
SetupPullRequiresUiError
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-HVUSHMVL.ts";
|
|
16
|
-
import "./chunk-5T442OP3.ts";
|
|
17
|
-
import "./chunk-F5QL2GPY.ts";
|
|
18
|
-
import "./chunk-YQ6UW7IF.ts";
|
|
17
|
+
} from "./chunk-2B2ELUF5.ts";
|
|
18
|
+
import "./chunk-JAAKLL6M.ts";
|
|
19
19
|
export {
|
|
20
20
|
SETUP_SWITCH_ACTION_OPTIONS,
|
|
21
21
|
SetupPullRequiresUiError,
|
|
@@ -24,4 +24,4 @@ export {
|
|
|
24
24
|
setupSwitchActionLabel,
|
|
25
25
|
useSyncSetup
|
|
26
26
|
};
|
|
27
|
-
//# sourceMappingURL=setup-switch-
|
|
27
|
+
//# sourceMappingURL=setup-switch-IS2PEZ3J.ts.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// @generated by scripts/build-runtime.mjs; do not edit.
|
|
2
|
+
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
|
+
import {
|
|
4
|
+
refreshTargetCompletions,
|
|
5
|
+
showGitSetup,
|
|
6
|
+
showS3Setup,
|
|
7
|
+
showWebDavSetup
|
|
8
|
+
} from "./chunk-KW7YQEZN.ts";
|
|
9
|
+
import "./chunk-Z4DQF6L3.ts";
|
|
10
|
+
import "./chunk-CHH26D4F.ts";
|
|
11
|
+
import {
|
|
12
|
+
safeTerminalText
|
|
13
|
+
} from "./chunk-LTBWGSBV.ts";
|
|
14
|
+
import "./chunk-LCRI3ABW.ts";
|
|
15
|
+
import {
|
|
16
|
+
localConfigPath,
|
|
17
|
+
validateConfigName
|
|
18
|
+
} from "./chunk-C7XY5NF5.ts";
|
|
19
|
+
import "./chunk-6LP3MCR2.ts";
|
|
20
|
+
import "./chunk-TEN2ZBJV.ts";
|
|
21
|
+
import "./chunk-CPEHGXJV.ts";
|
|
22
|
+
import {
|
|
23
|
+
errorMessage
|
|
24
|
+
} from "./chunk-2B2ELUF5.ts";
|
|
25
|
+
import "./chunk-JAAKLL6M.ts";
|
|
26
|
+
|
|
27
|
+
// src/ui/setup/setup-name-ui.ts
|
|
28
|
+
async function promptInitialSetupName(ctx, signal) {
|
|
29
|
+
while (!signal?.aborted) {
|
|
30
|
+
const hint = "For example: home or work. Leave blank for default.";
|
|
31
|
+
const guidance = ctx.mode === "tui" ? ctx.ui.theme.fg("muted", hint) : hint;
|
|
32
|
+
const value = await ctx.ui.input(`Sync setup name
|
|
33
|
+
${guidance}`, void 0, { signal });
|
|
34
|
+
if (signal?.aborted) {
|
|
35
|
+
throw signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted", "AbortError");
|
|
36
|
+
}
|
|
37
|
+
if (value === void 0) return void 0;
|
|
38
|
+
const name = value.trim() || "default";
|
|
39
|
+
try {
|
|
40
|
+
if (name.includes("<") || name.includes(">")) {
|
|
41
|
+
throw new Error("Replace example placeholders with your own name.");
|
|
42
|
+
}
|
|
43
|
+
validateConfigName(name, "sync setup");
|
|
44
|
+
return name;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
ctx.ui.notify(
|
|
47
|
+
`This name cannot be used for the sync setup. ${safeTerminalText(errorMessage(error))} Enter another name (for example, default).`,
|
|
48
|
+
"warning"
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return void 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/ui/setup/setup-wizard.ts
|
|
56
|
+
async function showSetupWizard(ctx, signal) {
|
|
57
|
+
if (ctx.mode !== "tui") {
|
|
58
|
+
ctx.ui.notify(
|
|
59
|
+
`Guided sync setup requires TUI mode for masked credential input. Create version 3 settings in ${safeTerminalText(localConfigPath())}.`,
|
|
60
|
+
"warning"
|
|
61
|
+
);
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
const preset = await ctx.ui.select(
|
|
65
|
+
"Set up sync\n\nWhere will Pi settings be stored?",
|
|
66
|
+
["Cloudflare R2", "Other S3-compatible storage", "WebDAV", "Git", "Cancel"],
|
|
67
|
+
{ signal }
|
|
68
|
+
);
|
|
69
|
+
if (signal?.aborted || !preset || preset === "Cancel") return false;
|
|
70
|
+
const targetName = await promptInitialSetupName(ctx, signal);
|
|
71
|
+
if (!targetName) return false;
|
|
72
|
+
if (preset === "WebDAV") {
|
|
73
|
+
const saved = await showWebDavSetup(ctx, targetName, signal);
|
|
74
|
+
if (signal?.aborted) return false;
|
|
75
|
+
if (saved) await refreshTargetCompletions();
|
|
76
|
+
return saved;
|
|
77
|
+
}
|
|
78
|
+
if (preset === "Git") {
|
|
79
|
+
const saved = await showGitSetup(ctx, targetName, signal);
|
|
80
|
+
if (signal?.aborted) return false;
|
|
81
|
+
if (saved) await refreshTargetCompletions();
|
|
82
|
+
return saved;
|
|
83
|
+
}
|
|
84
|
+
return showS3Setup(ctx, preset, targetName, signal);
|
|
85
|
+
}
|
|
86
|
+
export {
|
|
87
|
+
showSetupWizard
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=setup-wizard-IUB6ESEU.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/ui/setup/setup-name-ui.ts", "../../src/ui/setup/setup-wizard.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { validateConfigName } from \"../../settings/settings-validation.js\";\nimport { errorMessage } from \"../../sync/sync-errors.js\";\nimport { safeTerminalText } from \"../terminal-text.js\";\n\nexport async function promptInitialSetupName(ctx: ExtensionCommandContext, signal?: AbortSignal) {\n\twhile (!signal?.aborted) {\n\t\tconst hint = \"For example: home or work. Leave blank for default.\";\n\t\t// Pi styles the whole input title as accent; give only the guidance a muted role.\n\t\tconst guidance = ctx.mode === \"tui\" ? ctx.ui.theme.fg(\"muted\", hint) : hint;\n\t\t// This compact prompt owns its default hint; the general helper would repeat it.\n\t\tconst value = await ctx.ui.input(`Sync setup name\\n${guidance}`, undefined, { signal });\n\t\tif (signal?.aborted) {\n\t\t\tthrow signal.reason instanceof Error\n\t\t\t\t? signal.reason\n\t\t\t\t: new DOMException(\"The operation was aborted\", \"AbortError\");\n\t\t}\n\t\tif (value === undefined) return undefined;\n\t\tconst name = value.trim() || \"default\";\n\t\ttry {\n\t\t\tif (name.includes(\"<\") || name.includes(\">\")) {\n\t\t\t\tthrow new Error(\"Replace example placeholders with your own name.\");\n\t\t\t}\n\t\t\tvalidateConfigName(name, \"sync setup\");\n\t\t\treturn name;\n\t\t} catch (error) {\n\t\t\tctx.ui.notify(\n\t\t\t\t`This name cannot be used for the sync setup. ${safeTerminalText(errorMessage(error))} Enter another name (for example, default).`,\n\t\t\t\t\"warning\",\n\t\t\t);\n\t\t}\n\t}\n\treturn undefined;\n}\n", "import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { refreshTargetCompletions } from \"../../commands/setup-completions.js\";\nimport { localConfigPath } from \"../../settings/config-file.js\";\nimport { safeTerminalText } from \"../terminal-text.js\";\nimport { showGitSetup } from \"./git-ui.js\";\nimport { showS3Setup } from \"./s3-ui.js\";\nimport { promptInitialSetupName } from \"./setup-name-ui.js\";\nimport { showWebDavSetup } from \"./webdav-ui.js\";\n\nexport async function showSetupWizard(ctx: ExtensionCommandContext, signal?: AbortSignal) {\n\tif (ctx.mode !== \"tui\") {\n\t\tctx.ui.notify(\n\t\t\t`Guided sync setup requires TUI mode for masked credential input. Create version 3 settings in ${safeTerminalText(localConfigPath())}.`,\n\t\t\t\"warning\",\n\t\t);\n\t\treturn false;\n\t}\n\tconst preset = await ctx.ui.select(\n\t\t\"Set up sync\\n\\nWhere will Pi settings be stored?\",\n\t\t[\"Cloudflare R2\", \"Other S3-compatible storage\", \"WebDAV\", \"Git\", \"Cancel\"],\n\t\t{ signal },\n\t);\n\tif (signal?.aborted || !preset || preset === \"Cancel\") return false;\n\tconst targetName = await promptInitialSetupName(ctx, signal);\n\tif (!targetName) return false;\n\tif (preset === \"WebDAV\") {\n\t\tconst saved = await showWebDavSetup(ctx, targetName, signal);\n\t\tif (signal?.aborted) return false;\n\t\tif (saved) await refreshTargetCompletions();\n\t\treturn saved;\n\t}\n\tif (preset === \"Git\") {\n\t\tconst saved = await showGitSetup(ctx, targetName, signal);\n\t\tif (signal?.aborted) return false;\n\t\tif (saved) await refreshTargetCompletions();\n\t\treturn saved;\n\t}\n\treturn showS3Setup(ctx, preset, targetName, signal);\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,eAAsB,uBAAuB,KAA8B,QAAsB;AAChG,SAAO,CAAC,QAAQ,SAAS;AACxB,UAAM,OAAO;AAEb,UAAM,WAAW,IAAI,SAAS,QAAQ,IAAI,GAAG,MAAM,GAAG,SAAS,IAAI,IAAI;AAEvE,UAAM,QAAQ,MAAM,IAAI,GAAG,MAAM;AAAA,EAAoB,QAAQ,IAAI,QAAW,EAAE,OAAO,CAAC;AACtF,QAAI,QAAQ,SAAS;AACpB,YAAM,OAAO,kBAAkB,QAC5B,OAAO,SACP,IAAI,aAAa,6BAA6B,YAAY;AAAA,IAC9D;AACA,QAAI,UAAU,OAAW,QAAO;AAChC,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI;AACH,UAAI,KAAK,SAAS,GAAG,KAAK,KAAK,SAAS,GAAG,GAAG;AAC7C,cAAM,IAAI,MAAM,kDAAkD;AAAA,MACnE;AACA,yBAAmB,MAAM,YAAY;AACrC,aAAO;AAAA,IACR,SAAS,OAAO;AACf,UAAI,GAAG;AAAA,QACN,gDAAgD,iBAAiB,aAAa,KAAK,CAAC,CAAC;AAAA,QACrF;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;;;ACxBA,eAAsB,gBAAgB,KAA8B,QAAsB;AACzF,MAAI,IAAI,SAAS,OAAO;AACvB,QAAI,GAAG;AAAA,MACN,iGAAiG,iBAAiB,gBAAgB,CAAC,CAAC;AAAA,MACpI;AAAA,IACD;AACA,WAAO;AAAA,EACR;AACA,QAAM,SAAS,MAAM,IAAI,GAAG;AAAA,IAC3B;AAAA,IACA,CAAC,iBAAiB,+BAA+B,UAAU,OAAO,QAAQ;AAAA,IAC1E,EAAE,OAAO;AAAA,EACV;AACA,MAAI,QAAQ,WAAW,CAAC,UAAU,WAAW,SAAU,QAAO;AAC9D,QAAM,aAAa,MAAM,uBAAuB,KAAK,MAAM;AAC3D,MAAI,CAAC,WAAY,QAAO;AACxB,MAAI,WAAW,UAAU;AACxB,UAAM,QAAQ,MAAM,gBAAgB,KAAK,YAAY,MAAM;AAC3D,QAAI,QAAQ,QAAS,QAAO;AAC5B,QAAI,MAAO,OAAM,yBAAyB;AAC1C,WAAO;AAAA,EACR;AACA,MAAI,WAAW,OAAO;AACrB,UAAM,QAAQ,MAAM,aAAa,KAAK,YAAY,MAAM;AACxD,QAAI,QAAQ,QAAS,QAAO;AAC5B,QAAI,MAAO,OAAM,yBAAyB;AAC1C,WAAO;AAAA,EACR;AACA,SAAO,YAAY,KAAK,QAAQ,YAAY,MAAM;AACnD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -11,18 +11,19 @@ import {
|
|
|
11
11
|
regenerateSnapshotIdentity,
|
|
12
12
|
scanSnapshot,
|
|
13
13
|
sessionSnapshotPathFromAbsolute,
|
|
14
|
-
sessionStorageRoot,
|
|
15
14
|
snapshotIncludesSessions,
|
|
16
15
|
snapshotTarget,
|
|
17
16
|
snapshotWithoutSessions
|
|
18
|
-
} from "./chunk-
|
|
19
|
-
import
|
|
20
|
-
|
|
17
|
+
} from "./chunk-OEX4ABY6.ts";
|
|
18
|
+
import {
|
|
19
|
+
sessionStorageRoot
|
|
20
|
+
} from "./chunk-THMF4BVL.ts";
|
|
21
|
+
import "./chunk-T3HH3UEJ.ts";
|
|
21
22
|
import {
|
|
22
23
|
canonicalSnapshotPathForConfig,
|
|
23
24
|
isConfiguredSnapshotPath,
|
|
24
25
|
isDeniedPath
|
|
25
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-JAAKLL6M.ts";
|
|
26
27
|
export {
|
|
27
28
|
canonicalSnapshotPathForConfig,
|
|
28
29
|
collectFiles,
|
|
@@ -42,4 +43,4 @@ export {
|
|
|
42
43
|
snapshotTarget,
|
|
43
44
|
snapshotWithoutSessions
|
|
44
45
|
};
|
|
45
|
-
//# sourceMappingURL=snapshot-
|
|
46
|
+
//# sourceMappingURL=snapshot-HKEWCVK6.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// @generated by scripts/build-runtime.mjs; do not edit.
|
|
2
|
+
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
|
+
import {
|
|
4
|
+
inspectSync
|
|
5
|
+
} from "./chunk-SZWBGPID.ts";
|
|
6
|
+
import "./chunk-T2B5IU74.ts";
|
|
7
|
+
import "./chunk-AUSDLD6F.ts";
|
|
8
|
+
import "./chunk-NJFUIVYL.ts";
|
|
9
|
+
import "./chunk-CCSN3F47.ts";
|
|
10
|
+
import "./chunk-6LP3MCR2.ts";
|
|
11
|
+
import "./chunk-ZI5MXMEX.ts";
|
|
12
|
+
import "./chunk-TEN2ZBJV.ts";
|
|
13
|
+
import "./chunk-OEX4ABY6.ts";
|
|
14
|
+
import "./chunk-THMF4BVL.ts";
|
|
15
|
+
import "./chunk-T3HH3UEJ.ts";
|
|
16
|
+
import "./chunk-JAAKLL6M.ts";
|
|
17
|
+
export {
|
|
18
|
+
inspectSync
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=sync-inspection-CST2KL65.ts.map
|