@narumitw/pi-sync 0.52.1 → 0.53.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -4
- package/dist/chunks/{chunk-WKPX2SIC.ts → chunk-FJGNDYGC.ts} +2 -2
- package/dist/chunks/{chunk-NLS2NV3K.ts → chunk-QDPED3XJ.ts} +67 -8
- package/dist/chunks/{chunk-NLS2NV3K.ts.map → chunk-QDPED3XJ.ts.map} +3 -3
- package/dist/chunks/{chunk-QHSQCK7L.ts → chunk-SDZCTCYQ.ts} +4 -4
- package/dist/chunks/{chunk-2CBF6SMT.ts → chunk-TRCSEIAQ.ts} +2 -2
- package/dist/chunks/{chunk-7D6RDCVC.ts → chunk-WFKUKVCP.ts} +2 -2
- package/dist/chunks/{chunk-UETBKTDI.ts → chunk-YDVQYUHE.ts} +1 -1
- package/dist/chunks/{chunk-UETBKTDI.ts.map → chunk-YDVQYUHE.ts.map} +2 -2
- package/dist/chunks/{conflict-review-4WPGCXFB.ts → conflict-review-JANNPKKS.ts} +4 -4
- package/dist/chunks/{git-backend-HLGKUQJT.ts → git-backend-FD7AVSK6.ts} +2 -2
- package/dist/chunks/{manager-result-dispatcher-VIDT3QBU.ts → manager-result-dispatcher-AAEAYX57.ts} +4 -4
- package/dist/chunks/{manager-ui-HSMHS3OK.ts → manager-ui-MHAHAKG3.ts} +7 -7
- package/dist/chunks/{remote-selection-ui-SMF5CLFO.ts → remote-selection-ui-Q2HUIBTL.ts} +3 -3
- package/dist/chunks/{s3-backend-DJ2NT3SZ.ts → s3-backend-AQGV6LFT.ts} +116 -12
- package/dist/chunks/s3-backend-AQGV6LFT.ts.map +7 -0
- package/dist/chunks/{sync-inspection-VBJF2FWC.ts → sync-inspection-K45QVLHB.ts} +3 -3
- package/dist/chunks/{sync-operations-RHNECOOG.ts → sync-operations-Y27F5T7W.ts} +5 -5
- package/dist/chunks/{webdav-backend-ETQGSI6I.ts → webdav-backend-TBILVEQK.ts} +2 -2
- package/dist/index.ts +5 -5
- package/package.json +1 -1
- package/src/backends/s3/s3-backend.ts +45 -6
- package/src/backends/s3/s3-client.ts +36 -7
- package/src/backends/s3/s3-conditions.ts +67 -0
- package/src/backends/sync-backend.ts +2 -0
- package/src/sync/merge-transfer-error.ts +72 -0
- package/src/sync/merged-sync.ts +8 -5
- package/dist/chunks/s3-backend-DJ2NT3SZ.ts.map +0 -7
- /package/dist/chunks/{chunk-WKPX2SIC.ts.map → chunk-FJGNDYGC.ts.map} +0 -0
- /package/dist/chunks/{chunk-QHSQCK7L.ts.map → chunk-SDZCTCYQ.ts.map} +0 -0
- /package/dist/chunks/{chunk-2CBF6SMT.ts.map → chunk-TRCSEIAQ.ts.map} +0 -0
- /package/dist/chunks/{chunk-7D6RDCVC.ts.map → chunk-WFKUKVCP.ts.map} +0 -0
- /package/dist/chunks/{conflict-review-4WPGCXFB.ts.map → conflict-review-JANNPKKS.ts.map} +0 -0
- /package/dist/chunks/{git-backend-HLGKUQJT.ts.map → git-backend-FD7AVSK6.ts.map} +0 -0
- /package/dist/chunks/{manager-result-dispatcher-VIDT3QBU.ts.map → manager-result-dispatcher-AAEAYX57.ts.map} +0 -0
- /package/dist/chunks/{manager-ui-HSMHS3OK.ts.map → manager-ui-MHAHAKG3.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-SMF5CLFO.ts.map → remote-selection-ui-Q2HUIBTL.ts.map} +0 -0
- /package/dist/chunks/{sync-inspection-VBJF2FWC.ts.map → sync-inspection-K45QVLHB.ts.map} +0 -0
- /package/dist/chunks/{sync-operations-RHNECOOG.ts.map → sync-operations-Y27F5T7W.ts.map} +0 -0
- /package/dist/chunks/{webdav-backend-ETQGSI6I.ts.map → webdav-backend-TBILVEQK.ts.map} +0 -0
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
var createSyncBackend = async (config) => {
|
|
6
6
|
switch (config.backend.type) {
|
|
7
7
|
case "s3": {
|
|
8
|
-
const { S3SyncBackend } = await import("./s3-backend-
|
|
8
|
+
const { S3SyncBackend } = await import("./s3-backend-AQGV6LFT.ts");
|
|
9
9
|
return new S3SyncBackend(config.backend);
|
|
10
10
|
}
|
|
11
11
|
case "webdav": {
|
|
12
|
-
const { WebDavSyncBackend } = await import("./webdav-backend-
|
|
12
|
+
const { WebDavSyncBackend } = await import("./webdav-backend-TBILVEQK.ts");
|
|
13
13
|
return new WebDavSyncBackend(config.backend);
|
|
14
14
|
}
|
|
15
15
|
case "git": {
|
|
16
|
-
const { GitSyncBackend } = await import("./git-backend-
|
|
16
|
+
const { GitSyncBackend } = await import("./git-backend-FD7AVSK6.ts");
|
|
17
17
|
return new GitSyncBackend(config.backend);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -22,4 +22,4 @@ var createSyncBackend = async (config) => {
|
|
|
22
22
|
export {
|
|
23
23
|
createSyncBackend
|
|
24
24
|
};
|
|
25
|
-
//# sourceMappingURL=chunk-
|
|
25
|
+
//# sourceMappingURL=chunk-SDZCTCYQ.ts.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-V6VZ5TLG.ts";
|
|
6
6
|
import {
|
|
7
7
|
createSyncBackend
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-SDZCTCYQ.ts";
|
|
9
9
|
import {
|
|
10
10
|
setSyncStatus
|
|
11
11
|
} from "./chunk-K3RIEL6J.ts";
|
|
@@ -603,4 +603,4 @@ export {
|
|
|
603
603
|
runCancellableOperation,
|
|
604
604
|
showRemoteSelectionReview
|
|
605
605
|
};
|
|
606
|
-
//# sourceMappingURL=chunk-
|
|
606
|
+
//# sourceMappingURL=chunk-TRCSEIAQ.ts.map
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "./chunk-BDB4IDM3.ts";
|
|
7
7
|
import {
|
|
8
8
|
createSyncBackend
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-SDZCTCYQ.ts";
|
|
10
10
|
import {
|
|
11
11
|
throwIfAborted
|
|
12
12
|
} from "./chunk-PWMWOJP4.ts";
|
|
@@ -47,4 +47,4 @@ async function inspectSync(config, options, signal, factory = createSyncBackend)
|
|
|
47
47
|
export {
|
|
48
48
|
inspectSync
|
|
49
49
|
};
|
|
50
|
-
//# sourceMappingURL=chunk-
|
|
50
|
+
//# sourceMappingURL=chunk-WFKUKVCP.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/backends/sync-backend.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Snapshot, SnapshotSelection } from \"../snapshot/snapshot-types.js\";\n\nexport type PublicationCapability =\n | \"read-check-write-verify\"\n | \"conditional-required\"\n | \"atomic-conditional\"\n | \"lease-protected\";\n\nexport interface RemoteHead {\n /** Backend-owned reference used only to retrieve this immutable snapshot. */\n snapshotRef: string;\n /** Backend-neutral snapshot content identity retained in local sync state. */\n snapshotId: string;\n revision: string;\n createdAt: string;\n machine: string;\n syncSessions: boolean;\n /** Validated lightweight projection; revalidate it against the immutable snapshot before adoption. */\n selection?: SnapshotSelection;\n}\n\nexport interface RemoteHistoryEntry {\n snapshotRef: string;\n snapshotId: string;\n createdAt: string;\n machine: string;\n syncSessions: boolean;\n}\n\nexport type ExpectedRemoteHead = { kind: \"missing\" } | { kind: \"revision\"; revision: string };\n\nexport interface PublishSnapshotOptions {\n signal?: AbortSignal;\n /** Called at the backend's active-head commit boundary. */\n onCommit?: () => void;\n}\n\nexport interface PublishSnapshotResult {\n head: RemoteHead;\n warnings: string[];\n}\n\nexport interface BackendDiagnostic {\n key: string;\n level: \"info\" | \"warning\" | \"error\";\n message: string;\n}\n\nexport interface SyncBackend {\n readonly identity: string;\n readonly destination: string;\n readonly capability: PublicationCapability;\n /** Compare opaque revisions produced by this backend identity. */\n sameRevision(left: string, right: string): boolean;\n readHead(signal?: AbortSignal): Promise<RemoteHead | undefined>;\n readSnapshot(reference: string, signal?: AbortSignal): Promise<Snapshot>;\n publishSnapshot(\n snapshot: Snapshot,\n expected: ExpectedRemoteHead,\n options?: PublishSnapshotOptions,\n ): Promise<PublishSnapshotResult>;\n listHistory(signal?: AbortSignal): Promise<RemoteHistoryEntry[]>;\n diagnose(signal?: AbortSignal): Promise<BackendDiagnostic[]>;\n}\n\nexport class SyncBackendConflictError extends Error {\n readonly code = \"SYNC_BACKEND_CONFLICT\";\n readonly phase: \"before-commit\" | \"after-commit\";\n readonly currentHead?: RemoteHead;\n readonly candidateMayHaveBeenActive: boolean;\n\n constructor(\n message: string,\n options: ErrorOptions & {\n phase?: \"before-commit\" | \"after-commit\";\n currentHead?: RemoteHead;\n candidateMayHaveBeenActive?: boolean;\n } = {},\n ) {\n super(message, options);\n this.name = \"SyncBackendConflictError\";\n this.phase = options.phase ?? \"before-commit\";\n this.currentHead = options.currentHead;\n this.candidateMayHaveBeenActive = options.candidateMayHaveBeenActive ?? false;\n }\n}\n\nexport class SyncBackendPublicationOutcomeUnknownError extends Error {\n readonly code = \"SYNC_BACKEND_PUBLICATION_OUTCOME_UNKNOWN\";\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"SyncBackendPublicationOutcomeUnknownError\";\n }\n}\n\nexport function expectedRemoteHead(head: RemoteHead | undefined): ExpectedRemoteHead {\n return head ? { kind: \"revision\", revision: head.revision } : { kind: \"missing\" };\n}\n"],
|
|
5
|
-
"mappings": ";;;;
|
|
4
|
+
"sourcesContent": ["import type { Snapshot, SnapshotSelection } from \"../snapshot/snapshot-types.js\";\n\nexport type PublicationCapability =\n | \"read-check-write-verify\"\n | \"conditional-required\"\n | \"atomic-conditional\"\n | \"lease-protected\";\n\nexport interface RemoteHead {\n /** Backend-owned reference used only to retrieve this immutable snapshot. */\n snapshotRef: string;\n /** Backend-neutral snapshot content identity retained in local sync state. */\n snapshotId: string;\n revision: string;\n createdAt: string;\n machine: string;\n syncSessions: boolean;\n /** Validated lightweight projection; revalidate it against the immutable snapshot before adoption. */\n selection?: SnapshotSelection;\n}\n\nexport interface RemoteHistoryEntry {\n snapshotRef: string;\n snapshotId: string;\n createdAt: string;\n machine: string;\n syncSessions: boolean;\n}\n\nexport type ExpectedRemoteHead = { kind: \"missing\" } | { kind: \"revision\"; revision: string };\n\nexport interface PublishSnapshotOptions {\n signal?: AbortSignal;\n /** Called at the backend's active-head commit boundary. */\n onCommit?: () => void;\n}\n\nexport interface PublishSnapshotResult {\n head: RemoteHead;\n warnings: string[];\n}\n\nexport interface BackendDiagnostic {\n key: string;\n level: \"info\" | \"warning\" | \"error\";\n message: string;\n}\n\nexport interface SyncBackend {\n readonly identity: string;\n readonly destination: string;\n readonly capability: PublicationCapability;\n /** Compare opaque revisions produced by this backend identity. */\n sameRevision(left: string, right: string): boolean;\n /** Recovery-only equivalence for retiring an inactive candidate; never authorizes publication or apply. */\n matchesUncommittedRecoveryHead?(current: RemoteHead, recorded: RemoteHead): boolean;\n readHead(signal?: AbortSignal): Promise<RemoteHead | undefined>;\n readSnapshot(reference: string, signal?: AbortSignal): Promise<Snapshot>;\n publishSnapshot(\n snapshot: Snapshot,\n expected: ExpectedRemoteHead,\n options?: PublishSnapshotOptions,\n ): Promise<PublishSnapshotResult>;\n listHistory(signal?: AbortSignal): Promise<RemoteHistoryEntry[]>;\n diagnose(signal?: AbortSignal): Promise<BackendDiagnostic[]>;\n}\n\nexport class SyncBackendConflictError extends Error {\n readonly code = \"SYNC_BACKEND_CONFLICT\";\n readonly phase: \"before-commit\" | \"after-commit\";\n readonly currentHead?: RemoteHead;\n readonly candidateMayHaveBeenActive: boolean;\n\n constructor(\n message: string,\n options: ErrorOptions & {\n phase?: \"before-commit\" | \"after-commit\";\n currentHead?: RemoteHead;\n candidateMayHaveBeenActive?: boolean;\n } = {},\n ) {\n super(message, options);\n this.name = \"SyncBackendConflictError\";\n this.phase = options.phase ?? \"before-commit\";\n this.currentHead = options.currentHead;\n this.candidateMayHaveBeenActive = options.candidateMayHaveBeenActive ?? false;\n }\n}\n\nexport class SyncBackendPublicationOutcomeUnknownError extends Error {\n readonly code = \"SYNC_BACKEND_PUBLICATION_OUTCOME_UNKNOWN\";\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"SyncBackendPublicationOutcomeUnknownError\";\n }\n}\n\nexport function expectedRemoteHead(head: RemoteHead | undefined): ExpectedRemoteHead {\n return head ? { kind: \"revision\", revision: head.revision } : { kind: \"missing\" };\n}\n"],
|
|
5
|
+
"mappings": ";;;;AAmEO,IAAM,2BAAN,cAAuC,MAAM;AAAA,EACzC,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EAET,YACE,SACA,UAII,CAAC,GACL;AACA,UAAM,SAAS,OAAO;AACtB,SAAK,OAAO;AACZ,SAAK,QAAQ,QAAQ,SAAS;AAC9B,SAAK,cAAc,QAAQ;AAC3B,SAAK,6BAA6B,QAAQ,8BAA8B;AAAA,EAC1E;AACF;AAEO,IAAM,4CAAN,cAAwD,MAAM;AAAA,EAC1D,OAAO;AAAA,EAEhB,YAAY,SAAiB,SAAwB;AACnD,UAAM,SAAS,OAAO;AACtB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,SAAS,mBAAmB,MAAkD;AACnF,SAAO,OAAO,EAAE,MAAM,YAAY,UAAU,KAAK,SAAS,IAAI,EAAE,MAAM,UAAU;AAClF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import {
|
|
4
4
|
confirmMergeReview,
|
|
5
5
|
mergeSync
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-QDPED3XJ.ts";
|
|
7
7
|
import {
|
|
8
8
|
conflictArtifactFingerprint,
|
|
9
9
|
readConflictArtifact
|
|
@@ -12,7 +12,7 @@ import "./chunk-BDB4IDM3.ts";
|
|
|
12
12
|
import "./chunk-V6VZ5TLG.ts";
|
|
13
13
|
import {
|
|
14
14
|
createSyncBackend
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-SDZCTCYQ.ts";
|
|
16
16
|
import "./chunk-ANWNQIR7.ts";
|
|
17
17
|
import {
|
|
18
18
|
captureMutationOwner
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
} from "./chunk-3B4Z2SKV.ts";
|
|
35
35
|
import "./chunk-2JZFHNLM.ts";
|
|
36
36
|
import "./chunk-T2SJD3N7.ts";
|
|
37
|
-
import "./chunk-
|
|
37
|
+
import "./chunk-YDVQYUHE.ts";
|
|
38
38
|
import "./chunk-ZX2Q6THB.ts";
|
|
39
39
|
import "./chunk-7D5SF7P3.ts";
|
|
40
40
|
import "./chunk-A6HU4ERM.ts";
|
|
@@ -172,4 +172,4 @@ async function showConflicts(ctx, options, factory = createSyncBackend) {
|
|
|
172
172
|
export {
|
|
173
173
|
showConflicts
|
|
174
174
|
};
|
|
175
|
-
//# sourceMappingURL=conflict-review-
|
|
175
|
+
//# sourceMappingURL=conflict-review-JANNPKKS.ts.map
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
SyncBackendConflictError,
|
|
15
15
|
SyncBackendPublicationOutcomeUnknownError
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-YDVQYUHE.ts";
|
|
17
17
|
import {
|
|
18
18
|
syncErrorGuidance
|
|
19
19
|
} from "./chunk-G4RUXRWZ.ts";
|
|
@@ -1075,4 +1075,4 @@ export {
|
|
|
1075
1075
|
gitBackendIdentity,
|
|
1076
1076
|
isSupportedGitVersion
|
|
1077
1077
|
};
|
|
1078
|
-
//# sourceMappingURL=git-backend-
|
|
1078
|
+
//# sourceMappingURL=git-backend-FD7AVSK6.ts.map
|
package/dist/chunks/{manager-result-dispatcher-VIDT3QBU.ts → manager-result-dispatcher-AAEAYX57.ts}
RENAMED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
3
|
import {
|
|
4
4
|
dispatchManagerResult
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-FJGNDYGC.ts";
|
|
6
|
+
import "./chunk-TRCSEIAQ.ts";
|
|
7
7
|
import "./chunk-V6VZ5TLG.ts";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-SDZCTCYQ.ts";
|
|
9
9
|
import "./chunk-K3RIEL6J.ts";
|
|
10
10
|
import "./chunk-AMJRUXFT.ts";
|
|
11
11
|
import "./chunk-CHSIAC4N.ts";
|
|
@@ -20,4 +20,4 @@ import "./chunk-HUZ5CR4W.ts";
|
|
|
20
20
|
export {
|
|
21
21
|
dispatchManagerResult
|
|
22
22
|
};
|
|
23
|
-
//# sourceMappingURL=manager-result-dispatcher-
|
|
23
|
+
//# sourceMappingURL=manager-result-dispatcher-AAEAYX57.ts.map
|
|
@@ -23,12 +23,12 @@ import {
|
|
|
23
23
|
} from "./chunk-4SBTAVFL.ts";
|
|
24
24
|
import {
|
|
25
25
|
dispatchManagerResult
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-FJGNDYGC.ts";
|
|
27
27
|
import {
|
|
28
28
|
runCancellableOperation
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-TRCSEIAQ.ts";
|
|
30
30
|
import "./chunk-V6VZ5TLG.ts";
|
|
31
|
-
import "./chunk-
|
|
31
|
+
import "./chunk-SDZCTCYQ.ts";
|
|
32
32
|
import {
|
|
33
33
|
SETUP_SWITCH_ACTION_OPTIONS,
|
|
34
34
|
saveOnSwitch,
|
|
@@ -172,7 +172,7 @@ function blockedSyncMenuItem(label, manager) {
|
|
|
172
172
|
};
|
|
173
173
|
}
|
|
174
174
|
async function showManagerAttention(ctx, attention, runRoute, signal, onSelectionResolved) {
|
|
175
|
-
const { showRemoteSelectionReview } = await import("./remote-selection-ui-
|
|
175
|
+
const { showRemoteSelectionReview } = await import("./remote-selection-ui-Q2HUIBTL.ts");
|
|
176
176
|
if (signal?.aborted) return "close";
|
|
177
177
|
const review = await showRemoteSelectionReview(ctx, attention.decision.setupName, signal, void 0, {
|
|
178
178
|
decision: attention.decision,
|
|
@@ -908,7 +908,7 @@ async function showSyncSettings(ctx, runRoute, signal) {
|
|
|
908
908
|
},
|
|
909
909
|
"remote-include": async ({ signal: actionSignal }) => {
|
|
910
910
|
const reviewSignal = signal ? AbortSignal.any([signal, actionSignal]) : actionSignal;
|
|
911
|
-
const { showRemoteSelectionReview } = await import("./remote-selection-ui-
|
|
911
|
+
const { showRemoteSelectionReview } = await import("./remote-selection-ui-Q2HUIBTL.ts");
|
|
912
912
|
if (reviewSignal.aborted) return { kind: "rejected" };
|
|
913
913
|
const review = await showRemoteSelectionReview(ctx, setupName, reviewSignal, void 0, {
|
|
914
914
|
origin: "settings",
|
|
@@ -1563,7 +1563,7 @@ async function showSyncManager(ctx, runRoute, sessionSignal, options = {}) {
|
|
|
1563
1563
|
if (!attention) {
|
|
1564
1564
|
const observation = options.getObservation?.();
|
|
1565
1565
|
if (!observation) return { kind: "stay" };
|
|
1566
|
-
const { showRemoteSelectionReview } = await import("./remote-selection-ui-
|
|
1566
|
+
const { showRemoteSelectionReview } = await import("./remote-selection-ui-Q2HUIBTL.ts");
|
|
1567
1567
|
if (sessionSignal?.aborted) return { kind: "close" };
|
|
1568
1568
|
const config = await loadConfig();
|
|
1569
1569
|
if (sessionSignal?.aborted) return { kind: "close" };
|
|
@@ -1729,4 +1729,4 @@ function syncMainMenuItem(label) {
|
|
|
1729
1729
|
export {
|
|
1730
1730
|
showSyncManager
|
|
1731
1731
|
};
|
|
1732
|
-
//# sourceMappingURL=manager-ui-
|
|
1732
|
+
//# sourceMappingURL=manager-ui-MHAHAKG3.ts.map
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
3
|
import {
|
|
4
4
|
showRemoteSelectionReview
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-TRCSEIAQ.ts";
|
|
6
6
|
import "./chunk-V6VZ5TLG.ts";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-SDZCTCYQ.ts";
|
|
8
8
|
import "./chunk-K3RIEL6J.ts";
|
|
9
9
|
import "./chunk-AMJRUXFT.ts";
|
|
10
10
|
import "./chunk-CHSIAC4N.ts";
|
|
@@ -19,4 +19,4 @@ import "./chunk-HUZ5CR4W.ts";
|
|
|
19
19
|
export {
|
|
20
20
|
showRemoteSelectionReview
|
|
21
21
|
};
|
|
22
|
-
//# sourceMappingURL=remote-selection-ui-
|
|
22
|
+
//# sourceMappingURL=remote-selection-ui-Q2HUIBTL.ts.map
|
|
@@ -8,7 +8,7 @@ import "./chunk-T2SJD3N7.ts";
|
|
|
8
8
|
import {
|
|
9
9
|
SyncBackendConflictError,
|
|
10
10
|
SyncBackendPublicationOutcomeUnknownError
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-YDVQYUHE.ts";
|
|
12
12
|
import {
|
|
13
13
|
decodeSnapshot,
|
|
14
14
|
encodeSnapshot
|
|
@@ -143,16 +143,21 @@ var S3Client = class {
|
|
|
143
143
|
}
|
|
144
144
|
throw lastError;
|
|
145
145
|
}
|
|
146
|
-
async putJson(key, value) {
|
|
146
|
+
async putJson(key, value, options = {}) {
|
|
147
147
|
const body = Buffer.from(JSON.stringify(value, null, " "), "utf8");
|
|
148
|
-
await this.putBuffer(key, body, "application/json");
|
|
148
|
+
await this.putBuffer(key, body, "application/json", options);
|
|
149
149
|
}
|
|
150
150
|
async putBuffer(key, body, contentType, options = {}) {
|
|
151
151
|
const headers = { "content-type": contentType };
|
|
152
152
|
if (options.ifAbsent) headers["if-none-match"] = "*";
|
|
153
|
+
if (options.ifMatch) headers["if-match"] = options.ifMatch;
|
|
153
154
|
const response = await this.request("PUT", key, body, headers);
|
|
154
|
-
if (options.ifAbsent && response.status === 412) {
|
|
155
|
-
|
|
155
|
+
if ((options.ifAbsent || options.ifMatch) && (response.status === 412 || response.status === 409)) {
|
|
156
|
+
await response.body?.cancel();
|
|
157
|
+
if (options.ifAbsent && response.status === 412) throw new S3ObjectAlreadyExistsError(key);
|
|
158
|
+
if (options.ifAbsent || options.ifMatch) {
|
|
159
|
+
throw new S3HttpError(`S3 conditional PUT rejected (${response.status}).`, response.status);
|
|
160
|
+
}
|
|
156
161
|
}
|
|
157
162
|
if (!response.ok) {
|
|
158
163
|
throw new S3HttpError(
|
|
@@ -160,6 +165,17 @@ var S3Client = class {
|
|
|
160
165
|
response.status
|
|
161
166
|
);
|
|
162
167
|
}
|
|
168
|
+
await response.body?.cancel();
|
|
169
|
+
}
|
|
170
|
+
async delete(key) {
|
|
171
|
+
const response = await this.request("DELETE", key);
|
|
172
|
+
if (!response.ok && response.status !== 404) {
|
|
173
|
+
throw new S3HttpError(
|
|
174
|
+
`S3 DELETE failed (${response.status}): ${await this.readErrorText(response)}`,
|
|
175
|
+
response.status
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
await response.body?.cancel();
|
|
163
179
|
}
|
|
164
180
|
async request(method, key, body, extraHeaders = {}) {
|
|
165
181
|
const url = new URL(this.endpoint.toString());
|
|
@@ -170,7 +186,9 @@ var S3Client = class {
|
|
|
170
186
|
method,
|
|
171
187
|
url,
|
|
172
188
|
body,
|
|
173
|
-
|
|
189
|
+
// Transfer compression can weaken an object's ETag (R2 JSON responses).
|
|
190
|
+
// Read the original representation for exact checksums and strong If-Match tokens.
|
|
191
|
+
extraHeaders: method === "GET" ? { ...extraHeaders, "accept-encoding": "identity" } : extraHeaders,
|
|
174
192
|
accessKeyId: this.config.profile.accessKeyId,
|
|
175
193
|
secretAccessKey: this.config.profile.secretAccessKey,
|
|
176
194
|
sessionToken: sessionToken2,
|
|
@@ -331,6 +349,66 @@ function isSecurityTokenInvalidArgument(text) {
|
|
|
331
349
|
return text.includes("<Code>InvalidArgument</Code>") && text.includes("<Message>X-Amz-Security-Token</Message>");
|
|
332
350
|
}
|
|
333
351
|
|
|
352
|
+
// src/backends/s3/s3-conditions.ts
|
|
353
|
+
import { randomUUID } from "node:crypto";
|
|
354
|
+
function requireS3Etag(value) {
|
|
355
|
+
if (!value || !/^"[^"\r\n]+"$/u.test(value)) throw new Error("S3 conditional publication requires a strong ETag.");
|
|
356
|
+
return value;
|
|
357
|
+
}
|
|
358
|
+
async function verifyS3Conditions(config, signal) {
|
|
359
|
+
const key = posixJoin(
|
|
360
|
+
config.destination.prefix === "./" ? "" : config.destination.prefix,
|
|
361
|
+
".pi-sync-probes",
|
|
362
|
+
randomUUID()
|
|
363
|
+
);
|
|
364
|
+
const client = new S3Client(config, signal);
|
|
365
|
+
let failure;
|
|
366
|
+
let attempted = false;
|
|
367
|
+
try {
|
|
368
|
+
signal?.throwIfAborted();
|
|
369
|
+
attempted = true;
|
|
370
|
+
await client.putBuffer(key, Buffer.from("first"), "text/plain", { ifAbsent: true });
|
|
371
|
+
const first = await client.getBuffer(key);
|
|
372
|
+
const etag = requireS3Etag(first.etag);
|
|
373
|
+
if (!first.value?.equals(Buffer.from("first"))) throw new Error("S3 conditional probe read did not match.");
|
|
374
|
+
await expectRejected(client.putBuffer(key, Buffer.from("ignored"), "text/plain", { ifAbsent: true }));
|
|
375
|
+
await expectRejected(client.putBuffer(key, Buffer.from("ignored"), "text/plain", { ifMatch: '"pi-sync-stale"' }));
|
|
376
|
+
const unchanged = await client.getBuffer(key);
|
|
377
|
+
if (!unchanged.value?.equals(first.value) || unchanged.etag !== etag)
|
|
378
|
+
throw new Error("S3 failed precondition changed the probe.");
|
|
379
|
+
await client.putBuffer(key, Buffer.from("second"), "text/plain", { ifMatch: etag });
|
|
380
|
+
const second = await client.getBuffer(key);
|
|
381
|
+
if (!second.value?.equals(Buffer.from("second")) || requireS3Etag(second.etag) === etag) {
|
|
382
|
+
throw new Error("S3 conditional write did not rotate the probe ETag.");
|
|
383
|
+
}
|
|
384
|
+
await expectRejected(client.putBuffer(key, Buffer.from("ignored"), "text/plain", { ifMatch: etag }));
|
|
385
|
+
const final = await client.getBuffer(key);
|
|
386
|
+
if (!final.value?.equals(second.value) || final.etag !== second.etag)
|
|
387
|
+
throw new Error("S3 stale ETag changed the probe.");
|
|
388
|
+
signal?.throwIfAborted();
|
|
389
|
+
} catch (error) {
|
|
390
|
+
failure = error;
|
|
391
|
+
}
|
|
392
|
+
if (attempted) {
|
|
393
|
+
try {
|
|
394
|
+
await new S3Client(config, AbortSignal.timeout(1e4)).delete(key);
|
|
395
|
+
} catch (error) {
|
|
396
|
+
throw new Error(`S3 probe cleanup failed; remove ${key}.`, { cause: failure ?? error });
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (failure) throw failure;
|
|
400
|
+
signal?.throwIfAborted();
|
|
401
|
+
}
|
|
402
|
+
async function expectRejected(operation) {
|
|
403
|
+
try {
|
|
404
|
+
await operation;
|
|
405
|
+
} catch (error) {
|
|
406
|
+
if (error instanceof S3ObjectAlreadyExistsError || error instanceof S3HttpError && error.status === 412) return;
|
|
407
|
+
throw error;
|
|
408
|
+
}
|
|
409
|
+
throw new Error("S3 server ignored a write precondition; publication stopped for safety.");
|
|
410
|
+
}
|
|
411
|
+
|
|
334
412
|
// src/backends/s3/s3-backend.ts
|
|
335
413
|
var VERSION = 1;
|
|
336
414
|
var POST_COMMIT_TIMEOUT_MS = 3e4;
|
|
@@ -346,12 +424,17 @@ var S3SyncBackend = class {
|
|
|
346
424
|
postCommitTimeoutMs;
|
|
347
425
|
identity;
|
|
348
426
|
destination;
|
|
349
|
-
capability = "
|
|
427
|
+
capability = "conditional-required";
|
|
350
428
|
checksums = /* @__PURE__ */ new Map();
|
|
429
|
+
recoveryHead;
|
|
351
430
|
sameRevision(left, right) {
|
|
352
431
|
return left === right;
|
|
353
432
|
}
|
|
433
|
+
matchesUncommittedRecoveryHead(current, recorded) {
|
|
434
|
+
return this.sameRevision(current.revision, recorded.revision) || current.snapshotId === recorded.snapshotId && current.snapshotRef === recorded.snapshotRef && current.revision === this.recoveryHead?.current && recorded.revision === this.recoveryHead?.legacy;
|
|
435
|
+
}
|
|
354
436
|
async readHead(signal) {
|
|
437
|
+
this.recoveryHead = void 0;
|
|
355
438
|
const object = await new S3Client(this.config, signal).getJson(latestKey(this.config));
|
|
356
439
|
throwIfAborted(signal);
|
|
357
440
|
if (object.missing) return void 0;
|
|
@@ -361,7 +444,14 @@ var S3SyncBackend = class {
|
|
|
361
444
|
this.config.destination.namespace
|
|
362
445
|
);
|
|
363
446
|
this.registerChecksum(pointer.snapshot, pointer.sha256);
|
|
364
|
-
|
|
447
|
+
const head = remoteHead(pointer, this.identity, object.etag);
|
|
448
|
+
if (object.etag && /^"[^"\r\n]+"$/u.test(object.etag)) {
|
|
449
|
+
this.recoveryHead = {
|
|
450
|
+
current: head.revision,
|
|
451
|
+
legacy: remoteHead(pointer, this.identity, `W/${object.etag}`).revision
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
return head;
|
|
365
455
|
}
|
|
366
456
|
async readSnapshot(reference, signal) {
|
|
367
457
|
const expectedChecksum = this.checksums.get(reference) ?? await this.resolveChecksum(reference, signal);
|
|
@@ -381,6 +471,8 @@ var S3SyncBackend = class {
|
|
|
381
471
|
async publishSnapshot(snapshot, expected, options = {}) {
|
|
382
472
|
throwIfAborted(options.signal);
|
|
383
473
|
assertSnapshotIdentity(snapshot, this.config.destination.namespace);
|
|
474
|
+
await verifyS3Conditions(this.config, options.signal);
|
|
475
|
+
throwIfAborted(options.signal);
|
|
384
476
|
const stagedKey = snapshotKey(this.config, snapshot.id);
|
|
385
477
|
const encoded = await encodeSnapshot(snapshot);
|
|
386
478
|
throwIfAborted(options.signal);
|
|
@@ -416,12 +508,18 @@ var S3SyncBackend = class {
|
|
|
416
508
|
currentHead: current
|
|
417
509
|
});
|
|
418
510
|
}
|
|
511
|
+
const condition = currentObject.missing ? { ifAbsent: true } : { ifMatch: requireS3Etag(currentObject.etag) };
|
|
419
512
|
throwIfAborted(options.signal);
|
|
420
513
|
options.onCommit?.();
|
|
421
514
|
const commitClient = new S3Client(this.config, AbortSignal.timeout(this.postCommitTimeoutMs));
|
|
422
515
|
try {
|
|
423
|
-
await commitClient.putJson(latestKey(this.config), pointer);
|
|
516
|
+
await commitClient.putJson(latestKey(this.config), pointer, condition);
|
|
424
517
|
} catch (error) {
|
|
518
|
+
if (error instanceof S3ObjectAlreadyExistsError || error instanceof S3HttpError && (error.status === 412 || error.status === 409)) {
|
|
519
|
+
throw new SyncBackendConflictError("Remote conditional publication was rejected; reread and retry.", {
|
|
520
|
+
cause: error
|
|
521
|
+
});
|
|
522
|
+
}
|
|
425
523
|
throw new SyncBackendPublicationOutcomeUnknownError(
|
|
426
524
|
`Remote publication outcome is unknown: ${errorMessage2(error)}`,
|
|
427
525
|
{ cause: error }
|
|
@@ -543,8 +641,14 @@ var S3SyncBackend = class {
|
|
|
543
641
|
async updateHistory(client, pointer) {
|
|
544
642
|
const object = await client.getJson(historyKey(this.config));
|
|
545
643
|
const snapshots = object.missing ? [] : requireHistory(object.value, this.config.destination.namespace);
|
|
546
|
-
const
|
|
547
|
-
|
|
644
|
+
const existing = snapshots.find((snapshot) => snapshot.snapshot === pointer.snapshot);
|
|
645
|
+
if (existing) {
|
|
646
|
+
if (!samePointer(existing, pointer)) throw new Error("Remote history rebound an immutable snapshot reference.");
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
const next = [...snapshots, pointer].slice(-100);
|
|
650
|
+
const condition = object.missing ? { ifAbsent: true } : { ifMatch: requireS3Etag(object.etag) };
|
|
651
|
+
await client.putJson(historyKey(this.config), { version: VERSION, snapshots: next }, condition);
|
|
548
652
|
}
|
|
549
653
|
};
|
|
550
654
|
function latestKey(config) {
|
|
@@ -731,4 +835,4 @@ export {
|
|
|
731
835
|
snapshotKey,
|
|
732
836
|
storageRoot
|
|
733
837
|
};
|
|
734
|
-
//# sourceMappingURL=s3-backend-
|
|
838
|
+
//# sourceMappingURL=s3-backend-AQGV6LFT.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/backends/s3/s3-backend.ts", "../../src/backends/s3/s3-client.ts", "../../src/backends/s3/s3-conditions.ts"],
|
|
4
|
+
"sourcesContent": ["import { createHash } from \"node:crypto\";\nimport { encodeKey, posixJoin } from \"../../paths.js\";\nimport { sessionTokenWarnings } from \"../../settings/config.js\";\nimport { decodeSnapshot, encodeSnapshot } from \"../../snapshot/snapshot-codec.js\";\nimport type { Snapshot } from \"../../snapshot/snapshot-types.js\";\nimport { validatePortableSnapshot } from \"../../sync/local-fields.js\";\nimport { syncErrorGuidance } from \"../../sync/sync-error-guidance.js\";\nimport { portableSnapshotSelection } from \"../../sync/sync-policy.js\";\nimport type { LatestPointer, RemoteObject, ResolvedS3Backend } from \"../backend-types.js\";\nimport {\n type BackendDiagnostic,\n type ExpectedRemoteHead,\n type PublishSnapshotOptions,\n type PublishSnapshotResult,\n type RemoteHead,\n type RemoteHistoryEntry,\n type SyncBackend,\n SyncBackendConflictError,\n SyncBackendPublicationOutcomeUnknownError,\n} from \"../sync-backend.js\";\nimport { S3Client, S3HttpError, S3ObjectAlreadyExistsError } from \"./s3-client.js\";\nimport { requireS3Etag, verifyS3Conditions } from \"./s3-conditions.js\";\n\nconst VERSION = 1;\nconst POST_COMMIT_TIMEOUT_MS = 30_000;\n\nexport class S3SyncBackend implements SyncBackend {\n readonly identity: string;\n readonly destination: string;\n readonly capability = \"conditional-required\" as const;\n private readonly checksums = new Map<string, string>();\n private recoveryHead?: { current: string; legacy: string };\n\n constructor(\n private readonly config: ResolvedS3Backend,\n private readonly postCommitTimeoutMs = POST_COMMIT_TIMEOUT_MS,\n ) {\n assertSafeDestination(config);\n this.identity = s3BackendIdentity(config);\n this.destination = s3Destination(config);\n }\n\n sameRevision(left: string, right: string) {\n return left === right;\n }\n\n matchesUncommittedRecoveryHead(current: RemoteHead, recorded: RemoteHead) {\n return (\n this.sameRevision(current.revision, recorded.revision) ||\n (current.snapshotId === recorded.snapshotId &&\n current.snapshotRef === recorded.snapshotRef &&\n current.revision === this.recoveryHead?.current &&\n recorded.revision === this.recoveryHead?.legacy)\n );\n }\n\n async readHead(signal?: AbortSignal): Promise<RemoteHead | undefined> {\n this.recoveryHead = undefined;\n const object = await new S3Client(this.config, signal).getJson<LatestPointer>(latestKey(this.config));\n throwIfAborted(signal);\n if (object.missing) return undefined;\n const pointer = requirePointer(\n object.value,\n \"Remote latest pointer is malformed.\",\n this.config.destination.namespace,\n );\n this.registerChecksum(pointer.snapshot, pointer.sha256);\n const head = remoteHead(pointer, this.identity, object.etag);\n if (object.etag && /^\"[^\"\\r\\n]+\"$/u.test(object.etag)) {\n // Old clients hashed R2's compression-weakened ETag. Bind the alias to the\n // exact current pointer and strong ETag, solely for inactive-journal retirement.\n this.recoveryHead = {\n current: head.revision,\n legacy: remoteHead(pointer, this.identity, `W/${object.etag}`).revision,\n };\n }\n return head;\n }\n\n async readSnapshot(reference: string, signal?: AbortSignal): Promise<Snapshot> {\n const expectedChecksum = this.checksums.get(reference) ?? (await this.resolveChecksum(reference, signal));\n const object = await new S3Client(this.config, signal).getBuffer(snapshotKey(this.config, reference));\n throwIfAborted(signal);\n if (!object.value) throw new Error(`Snapshot not found: ${reference}`);\n if (expectedChecksum && sha256(object.value) !== expectedChecksum) {\n throw new Error(\"Remote snapshot checksum mismatch.\");\n }\n const snapshot = await decodeSnapshot(object.value, { signal });\n if (snapshot.id !== reference || snapshot.profile !== this.config.destination.namespace) {\n throw new Error(\"Remote snapshot identity mismatch.\");\n }\n validateSnapshotBundle(snapshot);\n return snapshot;\n }\n\n async publishSnapshot(\n snapshot: Snapshot,\n expected: ExpectedRemoteHead,\n options: PublishSnapshotOptions = {},\n ): Promise<PublishSnapshotResult> {\n throwIfAborted(options.signal);\n assertSnapshotIdentity(snapshot, this.config.destination.namespace);\n await verifyS3Conditions(this.config, options.signal);\n throwIfAborted(options.signal);\n const stagedKey = snapshotKey(this.config, snapshot.id);\n const encoded = await encodeSnapshot(snapshot);\n throwIfAborted(options.signal);\n const pointer = pointerFor(this.config, snapshot, sha256(encoded));\n const cancellableClient = new S3Client(this.config, options.signal);\n try {\n await cancellableClient.putBuffer(stagedKey, encoded, \"application/gzip\", {\n ifAbsent: true,\n });\n } catch (error) {\n if (!(error instanceof S3ObjectAlreadyExistsError)) throw error;\n const existing = await cancellableClient.getBuffer(stagedKey);\n if (!existing.value || sha256(existing.value) !== pointer.sha256) {\n throw new SyncBackendConflictError(\n `Immutable snapshot id already exists with different content: ${snapshot.id}`,\n );\n }\n }\n const currentObject = await cancellableClient.getJson<LatestPointer>(latestKey(this.config));\n throwIfAborted(options.signal);\n let current: RemoteHead | undefined;\n if (!currentObject.missing) {\n const currentPointer = requirePointer(\n currentObject.value,\n \"Remote latest pointer is malformed.\",\n this.config.destination.namespace,\n );\n this.registerChecksum(currentPointer.snapshot, currentPointer.sha256);\n current = remoteHead(currentPointer, this.identity, currentObject.etag);\n }\n if (!matchesExpected(current, expected)) {\n throw new SyncBackendConflictError(\"Remote changed while pushing. Run /sync pull first, then retry.\", {\n currentHead: current,\n });\n }\n const condition = currentObject.missing ? { ifAbsent: true } : { ifMatch: requireS3Etag(currentObject.etag) };\n throwIfAborted(options.signal);\n options.onCommit?.();\n\n // The active-head PUT is the publication boundary. Do not bind it or its\n // verification to a user-cancellation signal after the boundary begins.\n const commitClient = new S3Client(this.config, AbortSignal.timeout(this.postCommitTimeoutMs));\n try {\n await commitClient.putJson(latestKey(this.config), pointer, condition);\n } catch (error) {\n if (\n error instanceof S3ObjectAlreadyExistsError ||\n (error instanceof S3HttpError && (error.status === 412 || error.status === 409))\n ) {\n throw new SyncBackendConflictError(\"Remote conditional publication was rejected; reread and retry.\", {\n cause: error,\n });\n }\n throw new SyncBackendPublicationOutcomeUnknownError(\n `Remote publication outcome is unknown: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n\n let verifiedObject: RemoteObject<LatestPointer>;\n try {\n verifiedObject = await commitClient.getJson<LatestPointer>(latestKey(this.config));\n } catch (error) {\n throw new SyncBackendPublicationOutcomeUnknownError(\n `Remote snapshot may be active, but publication could not be verified: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n let verifiedPointer: LatestPointer;\n try {\n verifiedPointer = requirePointer(\n verifiedObject.value,\n \"Remote latest pointer is malformed after publication.\",\n this.config.destination.namespace,\n );\n } catch (error) {\n throw new SyncBackendPublicationOutcomeUnknownError(\n `Remote snapshot may be active, but publication verification was malformed: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n if (!samePointer(verifiedPointer, pointer)) {\n throw new SyncBackendConflictError(\n \"Remote latest changed immediately after push. Run /sync status before continuing.\",\n {\n phase: \"after-commit\",\n currentHead: remoteHead(verifiedPointer, this.identity, verifiedObject.etag),\n candidateMayHaveBeenActive: true,\n },\n );\n }\n this.registerChecksum(verifiedPointer.snapshot, verifiedPointer.sha256);\n const head = remoteHead(verifiedPointer, this.identity, verifiedObject.etag);\n const warning = await this.updateHistorySafely(commitClient, pointer);\n return { head, warnings: warning ? [warning] : [] };\n }\n\n async listHistory(signal?: AbortSignal): Promise<RemoteHistoryEntry[]> {\n const object = await new S3Client(this.config, signal).getJson<{\n version: number;\n snapshots: LatestPointer[];\n }>(historyKey(this.config));\n throwIfAborted(signal);\n if (object.missing) return [];\n const pointers = requireHistory(object.value, this.config.destination.namespace);\n for (const pointer of pointers) {\n const known = this.checksums.get(pointer.snapshot);\n if (known && known !== pointer.sha256) {\n throw new Error(\"Remote history conflicts with an already observed snapshot checksum.\");\n }\n }\n for (const pointer of pointers) this.registerChecksum(pointer.snapshot, pointer.sha256);\n return pointers.map(remoteHistoryEntry);\n }\n\n async diagnose(signal?: AbortSignal): Promise<BackendDiagnostic[]> {\n throwIfAborted(signal);\n const diagnostics: BackendDiagnostic[] = [\n {\n key: \"s3-config\",\n level: \"info\",\n message: `s3 config: ok (${this.config.destination.bucket}/${storageRoot(this.config)})`,\n },\n ...sessionTokenWarnings(this.config.profile).map((message) => ({\n key: \"s3-session-token\",\n level: \"warning\" as const,\n message,\n })),\n ];\n const deadline = AbortSignal.timeout(10_000);\n const probeSignal = signal ? AbortSignal.any([signal, deadline]) : deadline;\n try {\n const result = await new S3Client(this.config, probeSignal).diagnoseRead(latestKey(this.config));\n throwIfAborted(probeSignal);\n const messages = {\n readable: \"s3 remote read: HTTP success. Snapshot contents and write access are not tested.\",\n \"missing-key\":\n \"s3 remote read: no snapshot at this path (NoSuchKey). Write access is not tested; verify the bucket and path before first sync.\",\n \"missing-bucket\":\n \"s3 remote read: bucket not found (NoSuchBucket). Create the bucket with your provider or edit the setup's bucket name.\",\n \"unknown-404\":\n \"s3 remote read: HTTP 404; cannot confirm whether the bucket or snapshot is missing. Verify the endpoint, bucket, and path with your provider. Write access is not tested.\",\n };\n diagnostics.push({\n key: \"s3-read\",\n level: result === \"readable\" ? \"info\" : \"warning\",\n message: messages[result],\n });\n } catch (error) {\n throwIfAborted(signal);\n diagnostics.push({\n key: \"s3-read\",\n level: \"warning\",\n message: syncErrorGuidance(deadline.aborted ? new Error(\"S3 diagnostic request timed out.\") : error),\n });\n }\n return diagnostics;\n }\n\n private async resolveChecksum(reference: string, signal?: AbortSignal) {\n await this.readHead(signal);\n const headChecksum = this.checksums.get(reference);\n if (headChecksum) return headChecksum;\n await this.listHistory(signal);\n return this.checksums.get(reference);\n }\n\n private registerChecksum(reference: string, checksum: string) {\n const known = this.checksums.get(reference);\n if (known && known !== checksum) {\n throw new Error(\"Remote snapshot reference was rebound to a different checksum.\");\n }\n this.checksums.set(reference, checksum);\n }\n\n private async updateHistorySafely(client: S3Client, pointer: LatestPointer) {\n try {\n await this.updateHistory(client, pointer);\n return undefined;\n } catch (error) {\n return `Remote snapshot is active, but history could not be updated: ${errorMessage(error)}. Run /sync doctor before relying on history.`;\n }\n }\n\n private async updateHistory(client: S3Client, pointer: LatestPointer) {\n const object = await client.getJson<{ version: number; snapshots: LatestPointer[] }>(historyKey(this.config));\n const snapshots = object.missing ? [] : requireHistory(object.value, this.config.destination.namespace);\n const existing = snapshots.find((snapshot) => snapshot.snapshot === pointer.snapshot);\n if (existing) {\n if (!samePointer(existing, pointer)) throw new Error(\"Remote history rebound an immutable snapshot reference.\");\n return;\n }\n const next = [...snapshots, pointer].slice(-100);\n const condition = object.missing ? { ifAbsent: true } : { ifMatch: requireS3Etag(object.etag) };\n await client.putJson(historyKey(this.config), { version: VERSION, snapshots: next }, condition);\n }\n}\n\nexport function latestKey(config: ResolvedS3Backend) {\n return posixJoin(storageRoot(config), \"latest.json\");\n}\n\nexport function historyKey(config: ResolvedS3Backend) {\n return posixJoin(storageRoot(config), \"history.json\");\n}\n\nexport function snapshotKey(config: ResolvedS3Backend, id: string) {\n requireSnapshotReference(id);\n return posixJoin(storageRoot(config), \"snapshots\", `${id}.json.gz`);\n}\n\nexport function storageRoot(config: ResolvedS3Backend) {\n return config.destination.prefix === \"./\" ? \"\" : config.destination.prefix;\n}\n\nexport function pointerFor(config: ResolvedS3Backend, snapshot: Snapshot, checksum: string): LatestPointer {\n return {\n version: VERSION,\n profile: config.destination.namespace,\n snapshot: snapshot.id,\n sha256: checksum,\n createdAt: snapshot.createdAt,\n machine: snapshot.machine,\n syncSessions: snapshot.syncSessions === true || snapshot.files.some((file) => file.path.startsWith(\"sessions/\")),\n ...(snapshot.selection === undefined ? {} : { selection: snapshot.selection }),\n };\n}\n\nexport function s3BackendIdentity(config: ResolvedS3Backend) {\n const destination = JSON.stringify([\n secretFreeEndpoint(config.profile.endpoint),\n trimSlashes(config.destination.bucket),\n trimSlashes(config.destination.prefix),\n ]);\n return `s3:${sha256(Buffer.from(destination))}`;\n}\n\nfunction s3Destination(config: ResolvedS3Backend) {\n let host = secretFreeEndpoint(config.profile.endpoint);\n try {\n host = new URL(host).hostname;\n } catch {\n host = \"invalid S3 endpoint\";\n }\n return `${host} \u00B7 ${config.destination.bucket}/${storageRoot(config)}`;\n}\n\nfunction secretFreeEndpoint(value: string) {\n const normalized = value.trim();\n try {\n const url = new URL(normalized);\n url.username = \"\";\n url.password = \"\";\n return url.toString();\n } catch {\n return normalized.replace(/\\/\\/[^/@\\s]+@/u, \"//\");\n }\n}\n\nfunction trimSlashes(value: string) {\n return value.replace(/^\\/+|\\/+$/g, \"\");\n}\n\nfunction remoteHistoryEntry(pointer: LatestPointer): RemoteHistoryEntry {\n return {\n snapshotRef: pointer.snapshot,\n snapshotId: pointer.snapshot,\n createdAt: pointer.createdAt,\n machine: pointer.machine,\n syncSessions: pointer.syncSessions === true,\n };\n}\n\nfunction remoteHead(pointer: LatestPointer, identity: string, etag?: string): RemoteHead {\n return {\n snapshotRef: pointer.snapshot,\n snapshotId: pointer.snapshot,\n revision: `s3:${sha256(Buffer.from(canonicalJson([identity, etag ?? null, pointer])))}`,\n createdAt: pointer.createdAt,\n machine: pointer.machine,\n syncSessions: pointer.syncSessions === true,\n ...(pointer.selection === undefined ? {} : { selection: pointer.selection }),\n };\n}\n\nfunction samePointer(left: LatestPointer, right: LatestPointer) {\n return canonicalJson(left) === canonicalJson(right);\n}\n\nfunction canonicalJson(value: unknown) {\n return JSON.stringify(canonicalValue(value));\n}\n\nfunction canonicalValue(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(canonicalValue);\n if (!value || typeof value !== \"object\") return value;\n return Object.fromEntries(\n Object.keys(value)\n .sort()\n .map((key) => [key, canonicalValue((value as Record<string, unknown>)[key])]),\n );\n}\n\nfunction matchesExpected(head: RemoteHead | undefined, expected: ExpectedRemoteHead) {\n if (expected.kind === \"missing\") return head === undefined;\n return head?.revision === expected.revision;\n}\n\nfunction requirePointer(value: LatestPointer | undefined, message: string, expectedProfile: string) {\n if (\n !value ||\n value.version !== VERSION ||\n value.profile !== expectedProfile ||\n typeof value.snapshot !== \"string\" ||\n !isSafeSnapshotReference(value.snapshot) ||\n typeof value.sha256 !== \"string\" ||\n !/^[0-9a-f]{64}$/.test(value.sha256) ||\n typeof value.createdAt !== \"string\" ||\n !isSafeMetadata(value.createdAt, 64) ||\n typeof value.machine !== \"string\" ||\n !isSafeMetadata(value.machine, 256) ||\n (value.syncSessions !== undefined && typeof value.syncSessions !== \"boolean\")\n ) {\n throw new Error(message);\n }\n if (value.selection !== undefined) portableSnapshotSelection(value.selection);\n return value;\n}\n\nfunction requireHistory(value: { version: number; snapshots: LatestPointer[] } | undefined, expectedProfile: string) {\n if (!value || value.version !== VERSION || !Array.isArray(value.snapshots)) {\n throw new Error(\"Remote history is malformed.\");\n }\n const pointers = value.snapshots.map((pointer) =>\n requirePointer(pointer, \"Remote history entry is malformed.\", expectedProfile),\n );\n const references = new Set<string>();\n for (const pointer of pointers) {\n if (references.has(pointer.snapshot)) {\n throw new Error(\"Remote history contains duplicate snapshot references.\");\n }\n references.add(pointer.snapshot);\n }\n return pointers;\n}\n\nfunction assertSnapshotIdentity(snapshot: Snapshot, expectedProfile: string) {\n validatePortableSnapshot(snapshot);\n if (\n snapshot.profile !== expectedProfile ||\n !isSafeSnapshotReference(snapshot.id) ||\n !isSafeMetadata(snapshot.createdAt, 64) ||\n !isSafeMetadata(snapshot.machine, 256) ||\n !Array.isArray(snapshot.files)\n ) {\n throw new Error(\"Invalid snapshot identity for S3 publication.\");\n }\n}\n\nfunction validateSnapshotBundle(snapshot: Snapshot) {\n const paths = new Set<string>();\n for (const file of snapshot.files) {\n if (\n !file ||\n typeof file.path !== \"string\" ||\n typeof file.contentBase64 !== \"string\" ||\n typeof file.sha256 !== \"string\" ||\n !/^[0-9a-f]{64}$/.test(file.sha256) ||\n paths.has(file.path)\n ) {\n throw new Error(\"Remote snapshot bundle is malformed.\");\n }\n const content = Buffer.from(file.contentBase64, \"base64\");\n if (content.toString(\"base64\") !== file.contentBase64 || sha256(content) !== file.sha256) {\n throw new Error(\"Remote snapshot file checksum mismatch.\");\n }\n paths.add(file.path);\n }\n}\n\nfunction assertSafeDestination(config: ResolvedS3Backend) {\n for (const [label, value, allowEmpty] of [\n [\"bucket\", config.destination.bucket, false],\n [\"prefix\", config.destination.prefix, true],\n [\"namespace\", config.destination.namespace, false],\n ] as const) {\n if (label === \"prefix\" && value === \"./\") continue;\n if (\n (!allowEmpty && value.length === 0) ||\n value.includes(\"\\\\\") ||\n hasControlCharacter(value) ||\n value.split(\"/\").some((segment) => segment === \".\" || segment === \"..\")\n ) {\n throw new Error(`Invalid S3 storage location ${label}.`);\n }\n }\n}\n\nfunction requireSnapshotReference(reference: string) {\n if (!isSafeSnapshotReference(reference)) {\n throw new Error(\"Invalid S3 snapshot reference.\");\n }\n}\n\nfunction isSafeSnapshotReference(reference: string) {\n return (\n reference.length > 0 &&\n reference.length <= 512 &&\n reference !== \".\" &&\n reference !== \"..\" &&\n !reference.includes(\"/\") &&\n !reference.includes(\"\\\\\") &&\n !hasControlCharacter(reference)\n );\n}\n\nfunction isSafeMetadata(value: string, maxLength: number) {\n return value.length > 0 && value.length <= maxLength && !hasControlCharacter(value);\n}\n\nfunction hasControlCharacter(value: string) {\n return [...value].some((character) => {\n const code = character.codePointAt(0) ?? 0;\n return code < 0x20 || code === 0x7f;\n });\n}\n\nfunction throwIfAborted(signal?: AbortSignal) {\n if (!signal?.aborted) return;\n throw signal.reason instanceof Error ? signal.reason : new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n\nfunction sha256(value: Buffer) {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport { encodeKey };\n", "import { createHash, createHmac } from \"node:crypto\";\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport { encodeKey, posixJoin } from \"../../paths.js\";\nimport type { RemoteObject, ResolvedS3Backend } from \"../backend-types.js\";\n\nconst MAX_JSON_RESPONSE_BYTES = 1024 * 1024;\nconst MAX_SNAPSHOT_RESPONSE_BYTES = 256 * 1024 * 1024;\nconst MAX_ERROR_RESPONSE_BYTES = 64 * 1024;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 30_000;\n\nfunction iso8601Basic(date: Date) {\n return date.toISOString().replace(/[:-]|\\.\\d{3}/g, \"\");\n}\n\nfunction isCloudflareR2Endpoint(endpoint: string | undefined) {\n const value = endpoint?.trim();\n if (!value) return false;\n try {\n const hostname = new URL(value).hostname.toLowerCase();\n return hostname === \"r2.cloudflarestorage.com\" || hostname.endsWith(\".r2.cloudflarestorage.com\");\n } catch {\n return false;\n }\n}\n\nexport class S3ObjectAlreadyExistsError extends Error {\n constructor(readonly key: string) {\n super(`S3 object already exists: ${key}`);\n this.name = \"S3ObjectAlreadyExistsError\";\n }\n}\n\nexport class S3HttpError extends Error {\n constructor(\n message: string,\n readonly status: number,\n ) {\n super(message);\n this.name = \"S3HttpError\";\n }\n}\n\nexport class S3Client {\n private config: ResolvedS3Backend;\n private endpoint: URL;\n private signal?: AbortSignal;\n private requestTimeoutMs: number;\n private omitSessionTokenAfterRejection = false;\n\n constructor(config: ResolvedS3Backend, signal?: AbortSignal, requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS) {\n this.config = config;\n this.endpoint = new URL(config.profile.endpoint);\n this.signal = signal;\n this.requestTimeoutMs = requestTimeoutMs;\n }\n\n /** Read-only access probe. A bare 404 cannot distinguish a missing key from a missing bucket. */\n async diagnoseRead(key: string): Promise<\"readable\" | \"missing-key\" | \"missing-bucket\" | \"unknown-404\"> {\n this.signal?.throwIfAborted();\n const response = await this.request(\"GET\", key);\n if (response.ok) {\n await response.body?.cancel();\n this.signal?.throwIfAborted();\n return \"readable\";\n }\n const detail = await this.readErrorText(response);\n this.signal?.throwIfAborted();\n if (response.status === 404) {\n const code = /<Code>\\s*([A-Za-z]+)\\s*<\\/Code>/u.exec(detail)?.[1];\n if (code === \"NoSuchBucket\") return \"missing-bucket\";\n if (code === \"NoSuchKey\") return \"missing-key\";\n return \"unknown-404\";\n }\n throw new S3HttpError(`S3 remote read failed (HTTP ${response.status}).`, response.status);\n }\n\n async getJson<T>(key: string): Promise<RemoteObject<T>> {\n const maxAttempts = 3;\n let lastError: unknown;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const object = await this.request(\"GET\", key);\n if (object.status === 404) return { missing: true };\n if (!object.ok) {\n throw new S3HttpError(`S3 GET failed (${object.status}): ${await this.readErrorText(object)}`, object.status);\n }\n const body = await readBoundedText(object, MAX_JSON_RESPONSE_BYTES, \"S3 JSON response\");\n // R2 can intermittently return an empty 200 body (read-after-write\n // inconsistency on a long-lived keep-alive connection), which makes\n // response.json() throw \"JSON Parse error: Unexpected EOF\" under Bun.\n // Retry so the transient blip is absorbed instead of surfacing as a\n // \"pi-sync auto sync skipped\" warning on every session start.\n if (body.length > 0) {\n return {\n value: JSON.parse(body) as T,\n etag: normalizeEtag(object.headers.get(\"etag\")),\n missing: false,\n };\n }\n lastError = new Error(`S3 GET returned an empty body for ${key}`);\n if (attempt < maxAttempts) {\n await sleep(250 * attempt, undefined, { signal: this.signal });\n }\n }\n throw lastError;\n }\n\n async getBuffer(key: string): Promise<RemoteObject<Buffer>> {\n const maxAttempts = 3;\n let lastError: unknown;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const object = await this.request(\"GET\", key);\n if (object.status === 404) return { missing: true };\n if (!object.ok) {\n throw new S3HttpError(`S3 GET failed (${object.status}): ${await this.readErrorText(object)}`, object.status);\n }\n const buffer = await readBoundedBuffer(object, MAX_SNAPSHOT_RESPONSE_BYTES, \"S3 snapshot response\");\n // R2 can intermittently return an empty 200 body on a long-lived\n // keep-alive connection (same root cause as the getJson retry\n // above). getBuffer is only used for snapshot .json.gz payloads,\n // which are always non-empty, so an empty body is a transient\n // blip, not a legitimate response. Retry so the checksum guard\n // downstream doesn't surface it as \"Remote snapshot checksum\n // mismatch\".\n if (buffer.length > 0) {\n return { value: buffer, etag: normalizeEtag(object.headers.get(\"etag\")), missing: false };\n }\n lastError = new Error(`S3 GET returned an empty body for ${key}`);\n if (attempt < maxAttempts) {\n await sleep(250 * attempt, undefined, { signal: this.signal });\n }\n }\n throw lastError;\n }\n\n async putJson(key: string, value: unknown, options: { ifAbsent?: boolean; ifMatch?: string } = {}) {\n const body = Buffer.from(JSON.stringify(value, null, \"\\t\"), \"utf8\");\n await this.putBuffer(key, body, \"application/json\", options);\n }\n\n async putBuffer(\n key: string,\n body: Buffer,\n contentType: string,\n options: { ifAbsent?: boolean; ifMatch?: string } = {},\n ) {\n const headers: Record<string, string> = { \"content-type\": contentType };\n if (options.ifAbsent) headers[\"if-none-match\"] = \"*\";\n if (options.ifMatch) headers[\"if-match\"] = options.ifMatch;\n const response = await this.request(\"PUT\", key, body, headers);\n if ((options.ifAbsent || options.ifMatch) && (response.status === 412 || response.status === 409)) {\n await response.body?.cancel();\n if (options.ifAbsent && response.status === 412) throw new S3ObjectAlreadyExistsError(key);\n if (options.ifAbsent || options.ifMatch) {\n throw new S3HttpError(`S3 conditional PUT rejected (${response.status}).`, response.status);\n }\n }\n if (!response.ok) {\n throw new S3HttpError(\n `S3 PUT failed (${response.status}): ${await this.readErrorText(response)}`,\n response.status,\n );\n }\n await response.body?.cancel();\n }\n\n async delete(key: string) {\n const response = await this.request(\"DELETE\", key);\n if (!response.ok && response.status !== 404) {\n throw new S3HttpError(\n `S3 DELETE failed (${response.status}): ${await this.readErrorText(response)}`,\n response.status,\n );\n }\n await response.body?.cancel();\n }\n\n private async request(\n method: \"GET\" | \"PUT\" | \"DELETE\",\n key: string,\n body?: Buffer,\n extraHeaders: Record<string, string> = {},\n ) {\n const url = new URL(this.endpoint.toString());\n url.pathname = posixJoin(url.pathname, this.config.destination.bucket, encodeKey(key));\n const send = async (sessionToken: string | undefined) => {\n const transportSignal = this.transportSignal();\n const headers = await signedHeaders({\n method,\n url,\n body,\n // Transfer compression can weaken an object's ETag (R2 JSON responses).\n // Read the original representation for exact checksums and strong If-Match tokens.\n extraHeaders: method === \"GET\" ? { ...extraHeaders, \"accept-encoding\": \"identity\" } : extraHeaders,\n accessKeyId: this.config.profile.accessKeyId,\n secretAccessKey: this.config.profile.secretAccessKey,\n sessionToken,\n region: this.config.profile.region,\n });\n try {\n return await fetch(url, {\n method,\n headers,\n body: body ? new Uint8Array(body) : undefined,\n signal: transportSignal,\n });\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") throw error;\n if (error instanceof Error && error.name === \"TimeoutError\") {\n throw new Error(\"S3 request timed out.\", { cause: error });\n }\n throw new Error(`S3 request failed: ${this.redact(errorMessage(error))}`, { cause: error });\n }\n };\n const sessionToken = this.omitSessionTokenAfterRejection ? undefined : this.config.profile.sessionToken;\n const response = await send(sessionToken);\n try {\n if (!(await this.shouldRetryWithoutSessionToken(response, sessionToken))) return response;\n } catch (error) {\n await response.body?.cancel().catch(() => undefined);\n throw error;\n }\n await response.body?.cancel();\n const retry = await send(undefined);\n if (retry.ok || retry.status === 404) this.omitSessionTokenAfterRejection = true;\n return retry;\n }\n\n private transportSignal() {\n const timeout = AbortSignal.timeout(this.requestTimeoutMs);\n return this.signal ? AbortSignal.any([this.signal, timeout]) : timeout;\n }\n\n private async shouldRetryWithoutSessionToken(response: Response, sessionToken: string | undefined) {\n if (\n !sessionToken ||\n !isCloudflareR2Endpoint(this.config.profile.endpoint) ||\n response.ok ||\n response.status !== 400\n ) {\n return false;\n }\n return isSecurityTokenInvalidArgument(\n await readBoundedText(response.clone(), MAX_ERROR_RESPONSE_BYTES, \"S3 error response\"),\n );\n }\n\n private async readErrorText(response: Response) {\n try {\n return this.redact(await readBoundedText(response, MAX_ERROR_RESPONSE_BYTES, \"S3 error response\"));\n } catch (error) {\n return this.redact(errorMessage(error));\n }\n }\n\n private redact(value: string) {\n let redacted = value;\n let endpointUsername: string | undefined;\n let endpointPassword: string | undefined;\n let endpointQueryValues: string[] = [];\n try {\n const endpoint = new URL(this.config.profile.endpoint);\n endpointUsername = endpoint.username;\n endpointPassword = endpoint.password;\n endpointQueryValues = [...endpoint.searchParams.values()];\n } catch {\n // The constructor already validates normal runtime endpoints.\n }\n for (const secret of [\n this.config.profile.accessKeyId,\n this.config.profile.secretAccessKey,\n this.config.profile.sessionToken,\n endpointUsername,\n endpointPassword,\n ...endpointQueryValues,\n ]) {\n if (secret) redacted = redacted.replaceAll(secret, \"[REDACTED]\");\n }\n return redacted;\n }\n}\n\nasync function readBoundedText(response: Response, limit: number, label: string) {\n return (await readBoundedBuffer(response, limit, label)).toString(\"utf8\");\n}\n\nasync function readBoundedBuffer(response: Response, limit: number, label: string) {\n const contentLength = Number(response.headers.get(\"content-length\"));\n if (Number.isFinite(contentLength) && contentLength > limit) {\n // Do not await cancellation of a cloned stream before its sibling can be released.\n void response.body?.cancel().catch(() => undefined);\n throw new Error(`${label} exceeds the ${limit}-byte limit.`);\n }\n if (!response.body) return Buffer.alloc(0);\n const reader = response.body.getReader();\n const chunks: Buffer[] = [];\n let total = 0;\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > limit) {\n void reader.cancel().catch(() => undefined);\n throw new Error(`${label} exceeds the ${limit}-byte limit.`);\n }\n chunks.push(Buffer.from(value));\n }\n } finally {\n reader.releaseLock();\n }\n return Buffer.concat(chunks, total);\n}\n\nfunction errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error);\n}\n\nasync function signedHeaders(input: {\n method: string;\n url: URL;\n body?: Buffer;\n extraHeaders: Record<string, string>;\n accessKeyId: string;\n secretAccessKey: string;\n sessionToken?: string;\n region: string;\n}) {\n const now = new Date();\n const amzDate = iso8601Basic(now);\n const dateStamp = amzDate.slice(0, 8);\n const payloadHash = sha256(input.body ?? Buffer.alloc(0));\n const headers: Record<string, string> = {\n ...lowercaseKeys(input.extraHeaders),\n host: input.url.host,\n \"x-amz-content-sha256\": payloadHash,\n \"x-amz-date\": amzDate,\n };\n if (input.sessionToken) headers[\"x-amz-security-token\"] = input.sessionToken;\n const signedHeaderNames = Object.keys(headers).sort();\n const canonicalHeaders = signedHeaderNames.map((name) => `${name}:${headers[name]?.trim()}\\n`).join(\"\");\n const canonicalRequest = [\n input.method,\n input.url.pathname,\n input.url.searchParams.toString(),\n canonicalHeaders,\n signedHeaderNames.join(\";\"),\n payloadHash,\n ].join(\"\\n\");\n const scope = `${dateStamp}/${input.region}/s3/aws4_request`;\n const stringToSign = [\"AWS4-HMAC-SHA256\", amzDate, scope, sha256(Buffer.from(canonicalRequest))].join(\"\\n\");\n const signingKey = hmac(\n hmac(hmac(hmac(Buffer.from(`AWS4${input.secretAccessKey}`), dateStamp), input.region), \"s3\"),\n \"aws4_request\",\n );\n const signature = createHmac(\"sha256\", signingKey).update(stringToSign).digest(\"hex\");\n return {\n ...headers,\n authorization: `AWS4-HMAC-SHA256 Credential=${input.accessKeyId}/${scope}, SignedHeaders=${signedHeaderNames.join(\";\")}, Signature=${signature}`,\n };\n}\n\nfunction hmac(key: Buffer, value: string) {\n return createHmac(\"sha256\", key).update(value).digest();\n}\n\nfunction sha256(value: Buffer) {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction lowercaseKeys(value: Record<string, string>) {\n return Object.fromEntries(Object.entries(value).map(([key, item]) => [key.toLowerCase(), item]));\n}\n\nfunction normalizeEtag(value: string | null) {\n return value ?? undefined;\n}\n\nfunction isSecurityTokenInvalidArgument(text: string) {\n return text.includes(\"<Code>InvalidArgument</Code>\") && text.includes(\"<Message>X-Amz-Security-Token</Message>\");\n}\n", "import { randomUUID } from \"node:crypto\";\nimport { posixJoin } from \"../../paths.js\";\nimport type { ResolvedS3Backend } from \"../backend-types.js\";\nimport { S3Client, S3HttpError, S3ObjectAlreadyExistsError } from \"./s3-client.js\";\n\nexport function requireS3Etag(value: string | undefined) {\n if (!value || !/^\"[^\"\\r\\n]+\"$/u.test(value)) throw new Error(\"S3 conditional publication requires a strong ETag.\");\n return value;\n}\n\n/** Never probe the active pointer or immutable snapshots; ignored conditions must not corrupt either. */\nexport async function verifyS3Conditions(config: ResolvedS3Backend, signal?: AbortSignal) {\n const key = posixJoin(\n config.destination.prefix === \"./\" ? \"\" : config.destination.prefix,\n \".pi-sync-probes\",\n randomUUID(),\n );\n const client = new S3Client(config, signal);\n let failure: unknown;\n let attempted = false;\n try {\n signal?.throwIfAborted();\n attempted = true;\n await client.putBuffer(key, Buffer.from(\"first\"), \"text/plain\", { ifAbsent: true });\n const first = await client.getBuffer(key);\n const etag = requireS3Etag(first.etag);\n if (!first.value?.equals(Buffer.from(\"first\"))) throw new Error(\"S3 conditional probe read did not match.\");\n await expectRejected(client.putBuffer(key, Buffer.from(\"ignored\"), \"text/plain\", { ifAbsent: true }));\n await expectRejected(client.putBuffer(key, Buffer.from(\"ignored\"), \"text/plain\", { ifMatch: '\"pi-sync-stale\"' }));\n const unchanged = await client.getBuffer(key);\n if (!unchanged.value?.equals(first.value) || unchanged.etag !== etag)\n throw new Error(\"S3 failed precondition changed the probe.\");\n await client.putBuffer(key, Buffer.from(\"second\"), \"text/plain\", { ifMatch: etag });\n const second = await client.getBuffer(key);\n if (!second.value?.equals(Buffer.from(\"second\")) || requireS3Etag(second.etag) === etag) {\n throw new Error(\"S3 conditional write did not rotate the probe ETag.\");\n }\n await expectRejected(client.putBuffer(key, Buffer.from(\"ignored\"), \"text/plain\", { ifMatch: etag }));\n const final = await client.getBuffer(key);\n if (!final.value?.equals(second.value) || final.etag !== second.etag)\n throw new Error(\"S3 stale ETag changed the probe.\");\n signal?.throwIfAborted();\n } catch (error) {\n failure = error;\n }\n // Cleanup has its own bounded deadline even when the owning session was cancelled.\n if (attempted) {\n try {\n await new S3Client(config, AbortSignal.timeout(10_000)).delete(key);\n } catch (error) {\n throw new Error(`S3 probe cleanup failed; remove ${key}.`, { cause: failure ?? error });\n }\n }\n if (failure) throw failure;\n signal?.throwIfAborted();\n}\n\nasync function expectRejected(operation: Promise<void>) {\n try {\n await operation;\n } catch (error) {\n // 409 is retryable contention, not proof that a failed condition was enforced.\n if (error instanceof S3ObjectAlreadyExistsError || (error instanceof S3HttpError && error.status === 412)) return;\n throw error;\n }\n throw new Error(\"S3 server ignored a write precondition; publication stopped for safety.\");\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;AAChC,SAAO,KAAK,YAAY,EAAE,QAAQ,iBAAiB,EAAE;AACvD;AAEA,SAAS,uBAAuB,UAA8B;AAC5D,QAAM,QAAQ,UAAU,KAAK;AAC7B,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI;AACF,UAAM,WAAW,IAAI,IAAI,KAAK,EAAE,SAAS,YAAY;AACrD,WAAO,aAAa,8BAA8B,SAAS,SAAS,2BAA2B;AAAA,EACjG,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,6BAAN,cAAyC,MAAM;AAAA,EACpD,YAAqB,KAAa;AAChC,UAAM,6BAA6B,GAAG,EAAE;AADrB;AAEnB,SAAK,OAAO;AAAA,EACd;AAAA,EAHqB;AAIvB;AAEO,IAAM,cAAN,cAA0B,MAAM;AAAA,EACrC,YACE,SACS,QACT;AACA,UAAM,OAAO;AAFJ;AAGT,SAAK,OAAO;AAAA,EACd;AAAA,EAJW;AAKb;AAEO,IAAM,WAAN,MAAe;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,iCAAiC;AAAA,EAEzC,YAAY,QAA2B,QAAsB,mBAAmB,4BAA4B;AAC1G,SAAK,SAAS;AACd,SAAK,WAAW,IAAI,IAAI,OAAO,QAAQ,QAAQ;AAC/C,SAAK,SAAS;AACd,SAAK,mBAAmB;AAAA,EAC1B;AAAA;AAAA,EAGA,MAAM,aAAa,KAAqF;AACtG,SAAK,QAAQ,eAAe;AAC5B,UAAM,WAAW,MAAM,KAAK,QAAQ,OAAO,GAAG;AAC9C,QAAI,SAAS,IAAI;AACf,YAAM,SAAS,MAAM,OAAO;AAC5B,WAAK,QAAQ,eAAe;AAC5B,aAAO;AAAA,IACT;AACA,UAAM,SAAS,MAAM,KAAK,cAAc,QAAQ;AAChD,SAAK,QAAQ,eAAe;AAC5B,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,OAAO,mCAAmC,KAAK,MAAM,IAAI,CAAC;AAChE,UAAI,SAAS,eAAgB,QAAO;AACpC,UAAI,SAAS,YAAa,QAAO;AACjC,aAAO;AAAA,IACT;AACA,UAAM,IAAI,YAAY,+BAA+B,SAAS,MAAM,MAAM,SAAS,MAAM;AAAA,EAC3F;AAAA,EAEA,MAAM,QAAW,KAAuC;AACtD,UAAM,cAAc;AACpB,QAAI;AACJ,aAAS,UAAU,GAAG,WAAW,aAAa,WAAW;AACvD,YAAM,SAAS,MAAM,KAAK,QAAQ,OAAO,GAAG;AAC5C,UAAI,OAAO,WAAW,IAAK,QAAO,EAAE,SAAS,KAAK;AAClD,UAAI,CAAC,OAAO,IAAI;AACd,cAAM,IAAI,YAAY,kBAAkB,OAAO,MAAM,MAAM,MAAM,KAAK,cAAc,MAAM,CAAC,IAAI,OAAO,MAAM;AAAA,MAC9G;AACA,YAAM,OAAO,MAAM,gBAAgB,QAAQ,yBAAyB,kBAAkB;AAMtF,UAAI,KAAK,SAAS,GAAG;AACnB,eAAO;AAAA,UACL,OAAO,KAAK,MAAM,IAAI;AAAA,UACtB,MAAM,cAAc,OAAO,QAAQ,IAAI,MAAM,CAAC;AAAA,UAC9C,SAAS;AAAA,QACX;AAAA,MACF;AACA,kBAAY,IAAI,MAAM,qCAAqC,GAAG,EAAE;AAChE,UAAI,UAAU,aAAa;AACzB,cAAM,MAAM,MAAM,SAAS,QAAW,EAAE,QAAQ,KAAK,OAAO,CAAC;AAAA,MAC/D;AAAA,IACF;AACA,UAAM;AAAA,EACR;AAAA,EAEA,MAAM,UAAU,KAA4C;AAC1D,UAAM,cAAc;AACpB,QAAI;AACJ,aAAS,UAAU,GAAG,WAAW,aAAa,WAAW;AACvD,YAAM,SAAS,MAAM,KAAK,QAAQ,OAAO,GAAG;AAC5C,UAAI,OAAO,WAAW,IAAK,QAAO,EAAE,SAAS,KAAK;AAClD,UAAI,CAAC,OAAO,IAAI;AACd,cAAM,IAAI,YAAY,kBAAkB,OAAO,MAAM,MAAM,MAAM,KAAK,cAAc,MAAM,CAAC,IAAI,OAAO,MAAM;AAAA,MAC9G;AACA,YAAM,SAAS,MAAM,kBAAkB,QAAQ,6BAA6B,sBAAsB;AAQlG,UAAI,OAAO,SAAS,GAAG;AACrB,eAAO,EAAE,OAAO,QAAQ,MAAM,cAAc,OAAO,QAAQ,IAAI,MAAM,CAAC,GAAG,SAAS,MAAM;AAAA,MAC1F;AACA,kBAAY,IAAI,MAAM,qCAAqC,GAAG,EAAE;AAChE,UAAI,UAAU,aAAa;AACzB,cAAM,MAAM,MAAM,SAAS,QAAW,EAAE,QAAQ,KAAK,OAAO,CAAC;AAAA,MAC/D;AAAA,IACF;AACA,UAAM;AAAA,EACR;AAAA,EAEA,MAAM,QAAQ,KAAa,OAAgB,UAAoD,CAAC,GAAG;AACjG,UAAM,OAAO,OAAO,KAAK,KAAK,UAAU,OAAO,MAAM,GAAI,GAAG,MAAM;AAClE,UAAM,KAAK,UAAU,KAAK,MAAM,oBAAoB,OAAO;AAAA,EAC7D;AAAA,EAEA,MAAM,UACJ,KACA,MACA,aACA,UAAoD,CAAC,GACrD;AACA,UAAM,UAAkC,EAAE,gBAAgB,YAAY;AACtE,QAAI,QAAQ,SAAU,SAAQ,eAAe,IAAI;AACjD,QAAI,QAAQ,QAAS,SAAQ,UAAU,IAAI,QAAQ;AACnD,UAAM,WAAW,MAAM,KAAK,QAAQ,OAAO,KAAK,MAAM,OAAO;AAC7D,SAAK,QAAQ,YAAY,QAAQ,aAAa,SAAS,WAAW,OAAO,SAAS,WAAW,MAAM;AACjG,YAAM,SAAS,MAAM,OAAO;AAC5B,UAAI,QAAQ,YAAY,SAAS,WAAW,IAAK,OAAM,IAAI,2BAA2B,GAAG;AACzF,UAAI,QAAQ,YAAY,QAAQ,SAAS;AACvC,cAAM,IAAI,YAAY,gCAAgC,SAAS,MAAM,MAAM,SAAS,MAAM;AAAA,MAC5F;AAAA,IACF;AACA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI;AAAA,QACR,kBAAkB,SAAS,MAAM,MAAM,MAAM,KAAK,cAAc,QAAQ,CAAC;AAAA,QACzE,SAAS;AAAA,MACX;AAAA,IACF;AACA,UAAM,SAAS,MAAM,OAAO;AAAA,EAC9B;AAAA,EAEA,MAAM,OAAO,KAAa;AACxB,UAAM,WAAW,MAAM,KAAK,QAAQ,UAAU,GAAG;AACjD,QAAI,CAAC,SAAS,MAAM,SAAS,WAAW,KAAK;AAC3C,YAAM,IAAI;AAAA,QACR,qBAAqB,SAAS,MAAM,MAAM,MAAM,KAAK,cAAc,QAAQ,CAAC;AAAA,QAC5E,SAAS;AAAA,MACX;AAAA,IACF;AACA,UAAM,SAAS,MAAM,OAAO;AAAA,EAC9B;AAAA,EAEA,MAAc,QACZ,QACA,KACA,MACA,eAAuC,CAAC,GACxC;AACA,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;AACvD,YAAM,kBAAkB,KAAK,gBAAgB;AAC7C,YAAM,UAAU,MAAM,cAAc;AAAA,QAClC;AAAA,QACA;AAAA,QACA;AAAA;AAAA;AAAA,QAGA,cAAc,WAAW,QAAQ,EAAE,GAAG,cAAc,mBAAmB,WAAW,IAAI;AAAA,QACtF,aAAa,KAAK,OAAO,QAAQ;AAAA,QACjC,iBAAiB,KAAK,OAAO,QAAQ;AAAA,QACrC,cAAAA;AAAA,QACA,QAAQ,KAAK,OAAO,QAAQ;AAAA,MAC9B,CAAC;AACD,UAAI;AACF,eAAO,MAAM,MAAM,KAAK;AAAA,UACtB;AAAA,UACA;AAAA,UACA,MAAM,OAAO,IAAI,WAAW,IAAI,IAAI;AAAA,UACpC,QAAQ;AAAA,QACV,CAAC;AAAA,MACH,SAAS,OAAO;AACd,YAAI,iBAAiB,SAAS,MAAM,SAAS,aAAc,OAAM;AACjE,YAAI,iBAAiB,SAAS,MAAM,SAAS,gBAAgB;AAC3D,gBAAM,IAAI,MAAM,yBAAyB,EAAE,OAAO,MAAM,CAAC;AAAA,QAC3D;AACA,cAAM,IAAI,MAAM,sBAAsB,KAAK,OAAO,aAAa,KAAK,CAAC,CAAC,IAAI,EAAE,OAAO,MAAM,CAAC;AAAA,MAC5F;AAAA,IACF;AACA,UAAM,eAAe,KAAK,iCAAiC,SAAY,KAAK,OAAO,QAAQ;AAC3F,UAAM,WAAW,MAAM,KAAK,YAAY;AACxC,QAAI;AACF,UAAI,CAAE,MAAM,KAAK,+BAA+B,UAAU,YAAY,EAAI,QAAO;AAAA,IACnF,SAAS,OAAO;AACd,YAAM,SAAS,MAAM,OAAO,EAAE,MAAM,MAAM,MAAS;AACnD,YAAM;AAAA,IACR;AACA,UAAM,SAAS,MAAM,OAAO;AAC5B,UAAM,QAAQ,MAAM,KAAK,MAAS;AAClC,QAAI,MAAM,MAAM,MAAM,WAAW,IAAK,MAAK,iCAAiC;AAC5E,WAAO;AAAA,EACT;AAAA,EAEQ,kBAAkB;AACxB,UAAM,UAAU,YAAY,QAAQ,KAAK,gBAAgB;AACzD,WAAO,KAAK,SAAS,YAAY,IAAI,CAAC,KAAK,QAAQ,OAAO,CAAC,IAAI;AAAA,EACjE;AAAA,EAEA,MAAc,+BAA+B,UAAoB,cAAkC;AACjG,QACE,CAAC,gBACD,CAAC,uBAAuB,KAAK,OAAO,QAAQ,QAAQ,KACpD,SAAS,MACT,SAAS,WAAW,KACpB;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,MACL,MAAM,gBAAgB,SAAS,MAAM,GAAG,0BAA0B,mBAAmB;AAAA,IACvF;AAAA,EACF;AAAA,EAEA,MAAc,cAAc,UAAoB;AAC9C,QAAI;AACF,aAAO,KAAK,OAAO,MAAM,gBAAgB,UAAU,0BAA0B,mBAAmB,CAAC;AAAA,IACnG,SAAS,OAAO;AACd,aAAO,KAAK,OAAO,aAAa,KAAK,CAAC;AAAA,IACxC;AAAA,EACF;AAAA,EAEQ,OAAO,OAAe;AAC5B,QAAI,WAAW;AACf,QAAI;AACJ,QAAI;AACJ,QAAI,sBAAgC,CAAC;AACrC,QAAI;AACF,YAAM,WAAW,IAAI,IAAI,KAAK,OAAO,QAAQ,QAAQ;AACrD,yBAAmB,SAAS;AAC5B,yBAAmB,SAAS;AAC5B,4BAAsB,CAAC,GAAG,SAAS,aAAa,OAAO,CAAC;AAAA,IAC1D,QAAQ;AAAA,IAER;AACA,eAAW,UAAU;AAAA,MACnB,KAAK,OAAO,QAAQ;AAAA,MACpB,KAAK,OAAO,QAAQ;AAAA,MACpB,KAAK,OAAO,QAAQ;AAAA,MACpB;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL,GAAG;AACD,UAAI,OAAQ,YAAW,SAAS,WAAW,QAAQ,YAAY;AAAA,IACjE;AACA,WAAO;AAAA,EACT;AACF;AAEA,eAAe,gBAAgB,UAAoB,OAAe,OAAe;AAC/E,UAAQ,MAAM,kBAAkB,UAAU,OAAO,KAAK,GAAG,SAAS,MAAM;AAC1E;AAEA,eAAe,kBAAkB,UAAoB,OAAe,OAAe;AACjF,QAAM,gBAAgB,OAAO,SAAS,QAAQ,IAAI,gBAAgB,CAAC;AACnE,MAAI,OAAO,SAAS,aAAa,KAAK,gBAAgB,OAAO;AAE3D,SAAK,SAAS,MAAM,OAAO,EAAE,MAAM,MAAM,MAAS;AAClD,UAAM,IAAI,MAAM,GAAG,KAAK,gBAAgB,KAAK,cAAc;AAAA,EAC7D;AACA,MAAI,CAAC,SAAS,KAAM,QAAO,OAAO,MAAM,CAAC;AACzC,QAAM,SAAS,SAAS,KAAK,UAAU;AACvC,QAAM,SAAmB,CAAC;AAC1B,MAAI,QAAQ;AACZ,MAAI;AACF,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,KAAM;AACV,eAAS,MAAM;AACf,UAAI,QAAQ,OAAO;AACjB,aAAK,OAAO,OAAO,EAAE,MAAM,MAAM,MAAS;AAC1C,cAAM,IAAI,MAAM,GAAG,KAAK,gBAAgB,KAAK,cAAc;AAAA,MAC7D;AACA,aAAO,KAAK,OAAO,KAAK,KAAK,CAAC;AAAA,IAChC;AAAA,EACF,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACA,SAAO,OAAO,OAAO,QAAQ,KAAK;AACpC;AAEA,SAAS,aAAa,OAAgB;AACpC,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;AAEA,eAAe,cAAc,OAS1B;AACD,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,IACtC,GAAG,cAAc,MAAM,YAAY;AAAA,IACnC,MAAM,MAAM,IAAI;AAAA,IAChB,wBAAwB;AAAA,IACxB,cAAc;AAAA,EAChB;AACA,MAAI,MAAM,aAAc,SAAQ,sBAAsB,IAAI,MAAM;AAChE,QAAM,oBAAoB,OAAO,KAAK,OAAO,EAAE,KAAK;AACpD,QAAM,mBAAmB,kBAAkB,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,QAAQ,IAAI,GAAG,KAAK,CAAC;AAAA,CAAI,EAAE,KAAK,EAAE;AACtG,QAAM,mBAAmB;AAAA,IACvB,MAAM;AAAA,IACN,MAAM,IAAI;AAAA,IACV,MAAM,IAAI,aAAa,SAAS;AAAA,IAChC;AAAA,IACA,kBAAkB,KAAK,GAAG;AAAA,IAC1B;AAAA,EACF,EAAE,KAAK,IAAI;AACX,QAAM,QAAQ,GAAG,SAAS,IAAI,MAAM,MAAM;AAC1C,QAAM,eAAe,CAAC,oBAAoB,SAAS,OAAO,OAAO,OAAO,KAAK,gBAAgB,CAAC,CAAC,EAAE,KAAK,IAAI;AAC1G,QAAM,aAAa;AAAA,IACjB,KAAK,KAAK,KAAK,OAAO,KAAK,OAAO,MAAM,eAAe,EAAE,GAAG,SAAS,GAAG,MAAM,MAAM,GAAG,IAAI;AAAA,IAC3F;AAAA,EACF;AACA,QAAM,YAAY,WAAW,UAAU,UAAU,EAAE,OAAO,YAAY,EAAE,OAAO,KAAK;AACpF,SAAO;AAAA,IACL,GAAG;AAAA,IACH,eAAe,+BAA+B,MAAM,WAAW,IAAI,KAAK,mBAAmB,kBAAkB,KAAK,GAAG,CAAC,eAAe,SAAS;AAAA,EAChJ;AACF;AAEA,SAAS,KAAK,KAAa,OAAe;AACxC,SAAO,WAAW,UAAU,GAAG,EAAE,OAAO,KAAK,EAAE,OAAO;AACxD;AAEA,SAAS,OAAO,OAAe;AAC7B,SAAO,WAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AACxD;AAEA,SAAS,cAAc,OAA+B;AACpD,SAAO,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,YAAY,GAAG,IAAI,CAAC,CAAC;AACjG;AAEA,SAAS,cAAc,OAAsB;AAC3C,SAAO,SAAS;AAClB;AAEA,SAAS,+BAA+B,MAAc;AACpD,SAAO,KAAK,SAAS,8BAA8B,KAAK,KAAK,SAAS,yCAAyC;AACjH;;;AC3XA,SAAS,kBAAkB;AAKpB,SAAS,cAAc,OAA2B;AACvD,MAAI,CAAC,SAAS,CAAC,iBAAiB,KAAK,KAAK,EAAG,OAAM,IAAI,MAAM,oDAAoD;AACjH,SAAO;AACT;AAGA,eAAsB,mBAAmB,QAA2B,QAAsB;AACxF,QAAM,MAAM;AAAA,IACV,OAAO,YAAY,WAAW,OAAO,KAAK,OAAO,YAAY;AAAA,IAC7D;AAAA,IACA,WAAW;AAAA,EACb;AACA,QAAM,SAAS,IAAI,SAAS,QAAQ,MAAM;AAC1C,MAAI;AACJ,MAAI,YAAY;AAChB,MAAI;AACF,YAAQ,eAAe;AACvB,gBAAY;AACZ,UAAM,OAAO,UAAU,KAAK,OAAO,KAAK,OAAO,GAAG,cAAc,EAAE,UAAU,KAAK,CAAC;AAClF,UAAM,QAAQ,MAAM,OAAO,UAAU,GAAG;AACxC,UAAM,OAAO,cAAc,MAAM,IAAI;AACrC,QAAI,CAAC,MAAM,OAAO,OAAO,OAAO,KAAK,OAAO,CAAC,EAAG,OAAM,IAAI,MAAM,0CAA0C;AAC1G,UAAM,eAAe,OAAO,UAAU,KAAK,OAAO,KAAK,SAAS,GAAG,cAAc,EAAE,UAAU,KAAK,CAAC,CAAC;AACpG,UAAM,eAAe,OAAO,UAAU,KAAK,OAAO,KAAK,SAAS,GAAG,cAAc,EAAE,SAAS,kBAAkB,CAAC,CAAC;AAChH,UAAM,YAAY,MAAM,OAAO,UAAU,GAAG;AAC5C,QAAI,CAAC,UAAU,OAAO,OAAO,MAAM,KAAK,KAAK,UAAU,SAAS;AAC9D,YAAM,IAAI,MAAM,2CAA2C;AAC7D,UAAM,OAAO,UAAU,KAAK,OAAO,KAAK,QAAQ,GAAG,cAAc,EAAE,SAAS,KAAK,CAAC;AAClF,UAAM,SAAS,MAAM,OAAO,UAAU,GAAG;AACzC,QAAI,CAAC,OAAO,OAAO,OAAO,OAAO,KAAK,QAAQ,CAAC,KAAK,cAAc,OAAO,IAAI,MAAM,MAAM;AACvF,YAAM,IAAI,MAAM,qDAAqD;AAAA,IACvE;AACA,UAAM,eAAe,OAAO,UAAU,KAAK,OAAO,KAAK,SAAS,GAAG,cAAc,EAAE,SAAS,KAAK,CAAC,CAAC;AACnG,UAAM,QAAQ,MAAM,OAAO,UAAU,GAAG;AACxC,QAAI,CAAC,MAAM,OAAO,OAAO,OAAO,KAAK,KAAK,MAAM,SAAS,OAAO;AAC9D,YAAM,IAAI,MAAM,kCAAkC;AACpD,YAAQ,eAAe;AAAA,EACzB,SAAS,OAAO;AACd,cAAU;AAAA,EACZ;AAEA,MAAI,WAAW;AACb,QAAI;AACF,YAAM,IAAI,SAAS,QAAQ,YAAY,QAAQ,GAAM,CAAC,EAAE,OAAO,GAAG;AAAA,IACpE,SAAS,OAAO;AACd,YAAM,IAAI,MAAM,mCAAmC,GAAG,KAAK,EAAE,OAAO,WAAW,MAAM,CAAC;AAAA,IACxF;AAAA,EACF;AACA,MAAI,QAAS,OAAM;AACnB,UAAQ,eAAe;AACzB;AAEA,eAAe,eAAe,WAA0B;AACtD,MAAI;AACF,UAAM;AAAA,EACR,SAAS,OAAO;AAEd,QAAI,iBAAiB,8BAA+B,iBAAiB,eAAe,MAAM,WAAW,IAAM;AAC3G,UAAM;AAAA,EACR;AACA,QAAM,IAAI,MAAM,yEAAyE;AAC3F;;;AF3CA,IAAM,UAAU;AAChB,IAAM,yBAAyB;AAExB,IAAM,gBAAN,MAA2C;AAAA,EAOhD,YACmB,QACA,sBAAsB,wBACvC;AAFiB;AACA;AAEjB,0BAAsB,MAAM;AAC5B,SAAK,WAAW,kBAAkB,MAAM;AACxC,SAAK,cAAc,cAAc,MAAM;AAAA,EACzC;AAAA,EANmB;AAAA,EACA;AAAA,EARV;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACL,YAAY,oBAAI,IAAoB;AAAA,EAC7C;AAAA,EAWR,aAAa,MAAc,OAAe;AACxC,WAAO,SAAS;AAAA,EAClB;AAAA,EAEA,+BAA+B,SAAqB,UAAsB;AACxE,WACE,KAAK,aAAa,QAAQ,UAAU,SAAS,QAAQ,KACpD,QAAQ,eAAe,SAAS,cAC/B,QAAQ,gBAAgB,SAAS,eACjC,QAAQ,aAAa,KAAK,cAAc,WACxC,SAAS,aAAa,KAAK,cAAc;AAAA,EAE/C;AAAA,EAEA,MAAM,SAAS,QAAuD;AACpE,SAAK,eAAe;AACpB,UAAM,SAAS,MAAM,IAAI,SAAS,KAAK,QAAQ,MAAM,EAAE,QAAuB,UAAU,KAAK,MAAM,CAAC;AACpG,mBAAe,MAAM;AACrB,QAAI,OAAO,QAAS,QAAO;AAC3B,UAAM,UAAU;AAAA,MACd,OAAO;AAAA,MACP;AAAA,MACA,KAAK,OAAO,YAAY;AAAA,IAC1B;AACA,SAAK,iBAAiB,QAAQ,UAAU,QAAQ,MAAM;AACtD,UAAM,OAAO,WAAW,SAAS,KAAK,UAAU,OAAO,IAAI;AAC3D,QAAI,OAAO,QAAQ,iBAAiB,KAAK,OAAO,IAAI,GAAG;AAGrD,WAAK,eAAe;AAAA,QAClB,SAAS,KAAK;AAAA,QACd,QAAQ,WAAW,SAAS,KAAK,UAAU,KAAK,OAAO,IAAI,EAAE,EAAE;AAAA,MACjE;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,aAAa,WAAmB,QAAyC;AAC7E,UAAM,mBAAmB,KAAK,UAAU,IAAI,SAAS,KAAM,MAAM,KAAK,gBAAgB,WAAW,MAAM;AACvG,UAAM,SAAS,MAAM,IAAI,SAAS,KAAK,QAAQ,MAAM,EAAE,UAAU,YAAY,KAAK,QAAQ,SAAS,CAAC;AACpG,mBAAe,MAAM;AACrB,QAAI,CAAC,OAAO,MAAO,OAAM,IAAI,MAAM,uBAAuB,SAAS,EAAE;AACrE,QAAI,oBAAoBC,QAAO,OAAO,KAAK,MAAM,kBAAkB;AACjE,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AACA,UAAM,WAAW,MAAM,eAAe,OAAO,OAAO,EAAE,OAAO,CAAC;AAC9D,QAAI,SAAS,OAAO,aAAa,SAAS,YAAY,KAAK,OAAO,YAAY,WAAW;AACvF,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AACA,2BAAuB,QAAQ;AAC/B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,gBACJ,UACA,UACA,UAAkC,CAAC,GACH;AAChC,mBAAe,QAAQ,MAAM;AAC7B,2BAAuB,UAAU,KAAK,OAAO,YAAY,SAAS;AAClE,UAAM,mBAAmB,KAAK,QAAQ,QAAQ,MAAM;AACpD,mBAAe,QAAQ,MAAM;AAC7B,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;AACF,YAAM,kBAAkB,UAAU,WAAW,SAAS,oBAAoB;AAAA,QACxE,UAAU;AAAA,MACZ,CAAC;AAAA,IACH,SAAS,OAAO;AACd,UAAI,EAAE,iBAAiB,4BAA6B,OAAM;AAC1D,YAAM,WAAW,MAAM,kBAAkB,UAAU,SAAS;AAC5D,UAAI,CAAC,SAAS,SAASA,QAAO,SAAS,KAAK,MAAM,QAAQ,QAAQ;AAChE,cAAM,IAAI;AAAA,UACR,gEAAgE,SAAS,EAAE;AAAA,QAC7E;AAAA,MACF;AAAA,IACF;AACA,UAAM,gBAAgB,MAAM,kBAAkB,QAAuB,UAAU,KAAK,MAAM,CAAC;AAC3F,mBAAe,QAAQ,MAAM;AAC7B,QAAI;AACJ,QAAI,CAAC,cAAc,SAAS;AAC1B,YAAM,iBAAiB;AAAA,QACrB,cAAc;AAAA,QACd;AAAA,QACA,KAAK,OAAO,YAAY;AAAA,MAC1B;AACA,WAAK,iBAAiB,eAAe,UAAU,eAAe,MAAM;AACpE,gBAAU,WAAW,gBAAgB,KAAK,UAAU,cAAc,IAAI;AAAA,IACxE;AACA,QAAI,CAAC,gBAAgB,SAAS,QAAQ,GAAG;AACvC,YAAM,IAAI,yBAAyB,mEAAmE;AAAA,QACpG,aAAa;AAAA,MACf,CAAC;AAAA,IACH;AACA,UAAM,YAAY,cAAc,UAAU,EAAE,UAAU,KAAK,IAAI,EAAE,SAAS,cAAc,cAAc,IAAI,EAAE;AAC5G,mBAAe,QAAQ,MAAM;AAC7B,YAAQ,WAAW;AAInB,UAAM,eAAe,IAAI,SAAS,KAAK,QAAQ,YAAY,QAAQ,KAAK,mBAAmB,CAAC;AAC5F,QAAI;AACF,YAAM,aAAa,QAAQ,UAAU,KAAK,MAAM,GAAG,SAAS,SAAS;AAAA,IACvE,SAAS,OAAO;AACd,UACE,iBAAiB,8BAChB,iBAAiB,gBAAgB,MAAM,WAAW,OAAO,MAAM,WAAW,MAC3E;AACA,cAAM,IAAI,yBAAyB,kEAAkE;AAAA,UACnG,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AACA,YAAM,IAAI;AAAA,QACR,0CAA0CC,cAAa,KAAK,CAAC;AAAA,QAC7D,EAAE,OAAO,MAAM;AAAA,MACjB;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACF,uBAAiB,MAAM,aAAa,QAAuB,UAAU,KAAK,MAAM,CAAC;AAAA,IACnF,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,yEAAyEA,cAAa,KAAK,CAAC;AAAA,QAC5F,EAAE,OAAO,MAAM;AAAA,MACjB;AAAA,IACF;AACA,QAAI;AACJ,QAAI;AACF,wBAAkB;AAAA,QAChB,eAAe;AAAA,QACf;AAAA,QACA,KAAK,OAAO,YAAY;AAAA,MAC1B;AAAA,IACF,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,8EAA8EA,cAAa,KAAK,CAAC;AAAA,QACjG,EAAE,OAAO,MAAM;AAAA,MACjB;AAAA,IACF;AACA,QAAI,CAAC,YAAY,iBAAiB,OAAO,GAAG;AAC1C,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,UACE,OAAO;AAAA,UACP,aAAa,WAAW,iBAAiB,KAAK,UAAU,eAAe,IAAI;AAAA,UAC3E,4BAA4B;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;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,EACpD;AAAA,EAEA,MAAM,YAAY,QAAqD;AACrE,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;AAC9B,YAAM,QAAQ,KAAK,UAAU,IAAI,QAAQ,QAAQ;AACjD,UAAI,SAAS,UAAU,QAAQ,QAAQ;AACrC,cAAM,IAAI,MAAM,sEAAsE;AAAA,MACxF;AAAA,IACF;AACA,eAAW,WAAW,SAAU,MAAK,iBAAiB,QAAQ,UAAU,QAAQ,MAAM;AACtF,WAAO,SAAS,IAAI,kBAAkB;AAAA,EACxC;AAAA,EAEA,MAAM,SAAS,QAAoD;AACjE,mBAAe,MAAM;AACrB,UAAM,cAAmC;AAAA,MACvC;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,SAAS,kBAAkB,KAAK,OAAO,YAAY,MAAM,IAAI,YAAY,KAAK,MAAM,CAAC;AAAA,MACvF;AAAA,MACA,GAAG,qBAAqB,KAAK,OAAO,OAAO,EAAE,IAAI,CAAC,aAAa;AAAA,QAC7D,KAAK;AAAA,QACL,OAAO;AAAA,QACP;AAAA,MACF,EAAE;AAAA,IACJ;AACA,UAAM,WAAW,YAAY,QAAQ,GAAM;AAC3C,UAAM,cAAc,SAAS,YAAY,IAAI,CAAC,QAAQ,QAAQ,CAAC,IAAI;AACnE,QAAI;AACF,YAAM,SAAS,MAAM,IAAI,SAAS,KAAK,QAAQ,WAAW,EAAE,aAAa,UAAU,KAAK,MAAM,CAAC;AAC/F,qBAAe,WAAW;AAC1B,YAAM,WAAW;AAAA,QACf,UAAU;AAAA,QACV,eACE;AAAA,QACF,kBACE;AAAA,QACF,eACE;AAAA,MACJ;AACA,kBAAY,KAAK;AAAA,QACf,KAAK;AAAA,QACL,OAAO,WAAW,aAAa,SAAS;AAAA,QACxC,SAAS,SAAS,MAAM;AAAA,MAC1B,CAAC;AAAA,IACH,SAAS,OAAO;AACd,qBAAe,MAAM;AACrB,kBAAY,KAAK;AAAA,QACf,KAAK;AAAA,QACL,OAAO;AAAA,QACP,SAAS,kBAAkB,SAAS,UAAU,IAAI,MAAM,kCAAkC,IAAI,KAAK;AAAA,MACrG,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,gBAAgB,WAAmB,QAAsB;AACrE,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,EACrC;AAAA,EAEQ,iBAAiB,WAAmB,UAAkB;AAC5D,UAAM,QAAQ,KAAK,UAAU,IAAI,SAAS;AAC1C,QAAI,SAAS,UAAU,UAAU;AAC/B,YAAM,IAAI,MAAM,gEAAgE;AAAA,IAClF;AACA,SAAK,UAAU,IAAI,WAAW,QAAQ;AAAA,EACxC;AAAA,EAEA,MAAc,oBAAoB,QAAkB,SAAwB;AAC1E,QAAI;AACF,YAAM,KAAK,cAAc,QAAQ,OAAO;AACxC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,aAAO,gEAAgEA,cAAa,KAAK,CAAC;AAAA,IAC5F;AAAA,EACF;AAAA,EAEA,MAAc,cAAc,QAAkB,SAAwB;AACpE,UAAM,SAAS,MAAM,OAAO,QAAyD,WAAW,KAAK,MAAM,CAAC;AAC5G,UAAM,YAAY,OAAO,UAAU,CAAC,IAAI,eAAe,OAAO,OAAO,KAAK,OAAO,YAAY,SAAS;AACtG,UAAM,WAAW,UAAU,KAAK,CAAC,aAAa,SAAS,aAAa,QAAQ,QAAQ;AACpF,QAAI,UAAU;AACZ,UAAI,CAAC,YAAY,UAAU,OAAO,EAAG,OAAM,IAAI,MAAM,yDAAyD;AAC9G;AAAA,IACF;AACA,UAAM,OAAO,CAAC,GAAG,WAAW,OAAO,EAAE,MAAM,IAAI;AAC/C,UAAM,YAAY,OAAO,UAAU,EAAE,UAAU,KAAK,IAAI,EAAE,SAAS,cAAc,OAAO,IAAI,EAAE;AAC9F,UAAM,OAAO,QAAQ,WAAW,KAAK,MAAM,GAAG,EAAE,SAAS,SAAS,WAAW,KAAK,GAAG,SAAS;AAAA,EAChG;AACF;AAEO,SAAS,UAAU,QAA2B;AACnD,SAAO,UAAU,YAAY,MAAM,GAAG,aAAa;AACrD;AAEO,SAAS,WAAW,QAA2B;AACpD,SAAO,UAAU,YAAY,MAAM,GAAG,cAAc;AACtD;AAEO,SAAS,YAAY,QAA2B,IAAY;AACjE,2BAAyB,EAAE;AAC3B,SAAO,UAAU,YAAY,MAAM,GAAG,aAAa,GAAG,EAAE,UAAU;AACpE;AAEO,SAAS,YAAY,QAA2B;AACrD,SAAO,OAAO,YAAY,WAAW,OAAO,KAAK,OAAO,YAAY;AACtE;AAEO,SAAS,WAAW,QAA2B,UAAoB,UAAiC;AACzG,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SAAS,OAAO,YAAY;AAAA,IAC5B,UAAU,SAAS;AAAA,IACnB,QAAQ;AAAA,IACR,WAAW,SAAS;AAAA,IACpB,SAAS,SAAS;AAAA,IAClB,cAAc,SAAS,iBAAiB,QAAQ,SAAS,MAAM,KAAK,CAAC,SAAS,KAAK,KAAK,WAAW,WAAW,CAAC;AAAA,IAC/G,GAAI,SAAS,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,SAAS,UAAU;AAAA,EAC9E;AACF;AAEO,SAAS,kBAAkB,QAA2B;AAC3D,QAAM,cAAc,KAAK,UAAU;AAAA,IACjC,mBAAmB,OAAO,QAAQ,QAAQ;AAAA,IAC1C,YAAY,OAAO,YAAY,MAAM;AAAA,IACrC,YAAY,OAAO,YAAY,MAAM;AAAA,EACvC,CAAC;AACD,SAAO,MAAMD,QAAO,OAAO,KAAK,WAAW,CAAC,CAAC;AAC/C;AAEA,SAAS,cAAc,QAA2B;AAChD,MAAI,OAAO,mBAAmB,OAAO,QAAQ,QAAQ;AACrD,MAAI;AACF,WAAO,IAAI,IAAI,IAAI,EAAE;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO,GAAG,IAAI,SAAM,OAAO,YAAY,MAAM,IAAI,YAAY,MAAM,CAAC;AACtE;AAEA,SAAS,mBAAmB,OAAe;AACzC,QAAM,aAAa,MAAM,KAAK;AAC9B,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,UAAU;AAC9B,QAAI,WAAW;AACf,QAAI,WAAW;AACf,WAAO,IAAI,SAAS;AAAA,EACtB,QAAQ;AACN,WAAO,WAAW,QAAQ,kBAAkB,IAAI;AAAA,EAClD;AACF;AAEA,SAAS,YAAY,OAAe;AAClC,SAAO,MAAM,QAAQ,cAAc,EAAE;AACvC;AAEA,SAAS,mBAAmB,SAA4C;AACtE,SAAO;AAAA,IACL,aAAa,QAAQ;AAAA,IACrB,YAAY,QAAQ;AAAA,IACpB,WAAW,QAAQ;AAAA,IACnB,SAAS,QAAQ;AAAA,IACjB,cAAc,QAAQ,iBAAiB;AAAA,EACzC;AACF;AAEA,SAAS,WAAW,SAAwB,UAAkB,MAA2B;AACvF,SAAO;AAAA,IACL,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,EAC5E;AACF;AAEA,SAAS,YAAY,MAAqB,OAAsB;AAC9D,SAAO,cAAc,IAAI,MAAM,cAAc,KAAK;AACpD;AAEA,SAAS,cAAc,OAAgB;AACrC,SAAO,KAAK,UAAU,eAAe,KAAK,CAAC;AAC7C;AAEA,SAAS,eAAe,OAAyB;AAC/C,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,cAAc;AACzD,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,SAAO,OAAO;AAAA,IACZ,OAAO,KAAK,KAAK,EACd,KAAK,EACL,IAAI,CAAC,QAAQ,CAAC,KAAK,eAAgB,MAAkC,GAAG,CAAC,CAAC,CAAC;AAAA,EAChF;AACF;AAEA,SAAS,gBAAgB,MAA8B,UAA8B;AACnF,MAAI,SAAS,SAAS,UAAW,QAAO,SAAS;AACjD,SAAO,MAAM,aAAa,SAAS;AACrC;AAEA,SAAS,eAAe,OAAkC,SAAiB,iBAAyB;AAClG,MACE,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,WACnE;AACA,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AACA,MAAI,MAAM,cAAc,OAAW,2BAA0B,MAAM,SAAS;AAC5E,SAAO;AACT;AAEA,SAAS,eAAe,OAAoE,iBAAyB;AACnH,MAAI,CAAC,SAAS,MAAM,YAAY,WAAW,CAAC,MAAM,QAAQ,MAAM,SAAS,GAAG;AAC1E,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAChD;AACA,QAAM,WAAW,MAAM,UAAU;AAAA,IAAI,CAAC,YACpC,eAAe,SAAS,sCAAsC,eAAe;AAAA,EAC/E;AACA,QAAM,aAAa,oBAAI,IAAY;AACnC,aAAW,WAAW,UAAU;AAC9B,QAAI,WAAW,IAAI,QAAQ,QAAQ,GAAG;AACpC,YAAM,IAAI,MAAM,wDAAwD;AAAA,IAC1E;AACA,eAAW,IAAI,QAAQ,QAAQ;AAAA,EACjC;AACA,SAAO;AACT;AAEA,SAAS,uBAAuB,UAAoB,iBAAyB;AAC3E,2BAAyB,QAAQ;AACjC,MACE,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,GAC7B;AACA,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AACF;AAEA,SAAS,uBAAuB,UAAoB;AAClD,QAAM,QAAQ,oBAAI,IAAY;AAC9B,aAAW,QAAQ,SAAS,OAAO;AACjC,QACE,CAAC,QACD,OAAO,KAAK,SAAS,YACrB,OAAO,KAAK,kBAAkB,YAC9B,OAAO,KAAK,WAAW,YACvB,CAAC,iBAAiB,KAAK,KAAK,MAAM,KAClC,MAAM,IAAI,KAAK,IAAI,GACnB;AACA,YAAM,IAAI,MAAM,sCAAsC;AAAA,IACxD;AACA,UAAM,UAAU,OAAO,KAAK,KAAK,eAAe,QAAQ;AACxD,QAAI,QAAQ,SAAS,QAAQ,MAAM,KAAK,iBAAiBA,QAAO,OAAO,MAAM,KAAK,QAAQ;AACxF,YAAM,IAAI,MAAM,yCAAyC;AAAA,IAC3D;AACA,UAAM,IAAI,KAAK,IAAI;AAAA,EACrB;AACF;AAEA,SAAS,sBAAsB,QAA2B;AACxD,aAAW,CAAC,OAAO,OAAO,UAAU,KAAK;AAAA,IACvC,CAAC,UAAU,OAAO,YAAY,QAAQ,KAAK;AAAA,IAC3C,CAAC,UAAU,OAAO,YAAY,QAAQ,IAAI;AAAA,IAC1C,CAAC,aAAa,OAAO,YAAY,WAAW,KAAK;AAAA,EACnD,GAAY;AACV,QAAI,UAAU,YAAY,UAAU,KAAM;AAC1C,QACG,CAAC,cAAc,MAAM,WAAW,KACjC,MAAM,SAAS,IAAI,KACnB,oBAAoB,KAAK,KACzB,MAAM,MAAM,GAAG,EAAE,KAAK,CAAC,YAAY,YAAY,OAAO,YAAY,IAAI,GACtE;AACA,YAAM,IAAI,MAAM,+BAA+B,KAAK,GAAG;AAAA,IACzD;AAAA,EACF;AACF;AAEA,SAAS,yBAAyB,WAAmB;AACnD,MAAI,CAAC,wBAAwB,SAAS,GAAG;AACvC,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AACF;AAEA,SAAS,wBAAwB,WAAmB;AAClD,SACE,UAAU,SAAS,KACnB,UAAU,UAAU,OACpB,cAAc,OACd,cAAc,QACd,CAAC,UAAU,SAAS,GAAG,KACvB,CAAC,UAAU,SAAS,IAAI,KACxB,CAAC,oBAAoB,SAAS;AAElC;AAEA,SAAS,eAAe,OAAe,WAAmB;AACxD,SAAO,MAAM,SAAS,KAAK,MAAM,UAAU,aAAa,CAAC,oBAAoB,KAAK;AACpF;AAEA,SAAS,oBAAoB,OAAe;AAC1C,SAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,cAAc;AACpC,UAAM,OAAO,UAAU,YAAY,CAAC,KAAK;AACzC,WAAO,OAAO,MAAQ,SAAS;AAAA,EACjC,CAAC;AACH;AAEA,SAAS,eAAe,QAAsB;AAC5C,MAAI,CAAC,QAAQ,QAAS;AACtB,QAAM,OAAO,kBAAkB,QAAQ,OAAO,SAAS,IAAI,aAAa,6BAA6B,YAAY;AACnH;AAEA,SAASA,QAAO,OAAe;AAC7B,SAAOE,YAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AACxD;AAEA,SAASD,cAAa,OAAgB;AACpC,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;",
|
|
6
|
+
"names": ["createHash", "sessionToken", "sha256", "errorMessage", "createHash"]
|
|
7
|
+
}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
3
|
import {
|
|
4
4
|
inspectSync
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-WFKUKVCP.ts";
|
|
6
6
|
import "./chunk-BDB4IDM3.ts";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-SDZCTCYQ.ts";
|
|
8
8
|
import "./chunk-PWMWOJP4.ts";
|
|
9
9
|
import "./chunk-4QVPTIZB.ts";
|
|
10
10
|
import "./chunk-BVVP33U5.ts";
|
|
@@ -17,4 +17,4 @@ import "./chunk-HUZ5CR4W.ts";
|
|
|
17
17
|
export {
|
|
18
18
|
inspectSync
|
|
19
19
|
};
|
|
20
|
-
//# sourceMappingURL=sync-inspection-
|
|
20
|
+
//# sourceMappingURL=sync-inspection-K45QVLHB.ts.map
|