@narumitw/pi-sync 0.50.2 → 0.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/chunks/{chunk-6LP3MCR2.ts → chunk-2JZFHNLM.ts} +3 -5
- package/dist/chunks/chunk-2JZFHNLM.ts.map +7 -0
- package/dist/chunks/{chunk-LCRI3ABW.ts → chunk-2RZSQWBH.ts} +8 -19
- package/dist/chunks/chunk-2RZSQWBH.ts.map +7 -0
- package/dist/chunks/{chunk-IJ6FJFA5.ts → chunk-4AIHXRKE.ts} +11 -17
- package/dist/chunks/chunk-4AIHXRKE.ts.map +7 -0
- package/dist/chunks/{chunk-C7XY5NF5.ts → chunk-4MPIH46N.ts} +29 -51
- package/dist/chunks/chunk-4MPIH46N.ts.map +7 -0
- package/dist/chunks/{chunk-5B3FXBLE.ts → chunk-6546TS54.ts} +16 -20
- package/dist/chunks/chunk-6546TS54.ts.map +7 -0
- package/dist/chunks/{chunk-Q2TUM5X6.ts → chunk-6NT3YFGY.ts} +2 -2
- package/dist/chunks/chunk-6NT3YFGY.ts.map +7 -0
- package/dist/chunks/{chunk-2B2ELUF5.ts → chunk-7D5SF7P3.ts} +1 -1
- package/dist/chunks/chunk-7D5SF7P3.ts.map +7 -0
- package/dist/chunks/{chunk-4CHTZMEO.ts → chunk-7KHKWL3Q.ts} +37 -55
- package/dist/chunks/chunk-7KHKWL3Q.ts.map +7 -0
- package/dist/chunks/{chunk-ZI5MXMEX.ts → chunk-BVVP33U5.ts} +2 -4
- package/dist/chunks/chunk-BVVP33U5.ts.map +7 -0
- package/dist/chunks/{chunk-SZWBGPID.ts → chunk-DM4X4FIA.ts} +8 -13
- package/dist/chunks/chunk-DM4X4FIA.ts.map +7 -0
- package/dist/chunks/{chunk-SL64RLXR.ts → chunk-DZUSTGQV.ts} +8 -16
- package/dist/chunks/chunk-DZUSTGQV.ts.map +7 -0
- package/dist/chunks/{chunk-G4RNQQZS.ts → chunk-E42GXD6D.ts} +13 -19
- package/dist/chunks/chunk-E42GXD6D.ts.map +7 -0
- package/dist/chunks/{chunk-Z4DQF6L3.ts → chunk-ECYCNZOE.ts} +1 -1
- package/dist/chunks/chunk-ECYCNZOE.ts.map +7 -0
- package/dist/chunks/{chunk-OEX4ABY6.ts → chunk-EEJPYTWE.ts} +11 -21
- package/dist/chunks/chunk-EEJPYTWE.ts.map +7 -0
- package/dist/chunks/{chunk-CPEHGXJV.ts → chunk-G4RUXRWZ.ts} +3 -5
- package/dist/chunks/chunk-G4RUXRWZ.ts.map +7 -0
- package/dist/chunks/{chunk-T2B5IU74.ts → chunk-HGJH56KR.ts} +4 -4
- package/dist/chunks/chunk-HGJH56KR.ts.map +7 -0
- package/dist/chunks/{chunk-JAAKLL6M.ts → chunk-IVXEDPAD.ts} +10 -34
- package/dist/chunks/chunk-IVXEDPAD.ts.map +7 -0
- package/dist/chunks/chunk-K3RIEL6J.ts +20 -0
- package/dist/chunks/chunk-K3RIEL6J.ts.map +7 -0
- package/dist/chunks/{chunk-LTBWGSBV.ts → chunk-MSSW6F3R.ts} +1 -1
- package/dist/chunks/chunk-MSSW6F3R.ts.map +7 -0
- package/dist/chunks/{chunk-T3HH3UEJ.ts → chunk-OVDTF5CH.ts} +4 -10
- package/dist/chunks/chunk-OVDTF5CH.ts.map +7 -0
- package/dist/chunks/{chunk-NJFUIVYL.ts → chunk-PWMWOJP4.ts} +1 -1
- package/dist/chunks/chunk-PWMWOJP4.ts.map +7 -0
- package/dist/chunks/{chunk-HUDQATCL.ts → chunk-Q32CQWPM.ts} +6 -8
- package/dist/chunks/chunk-Q32CQWPM.ts.map +7 -0
- package/dist/chunks/{chunk-ETTRJDNP.ts → chunk-QLSN7AGX.ts} +6 -13
- package/dist/chunks/chunk-QLSN7AGX.ts.map +7 -0
- package/dist/chunks/{chunk-THMF4BVL.ts → chunk-SWUXA3MH.ts} +1 -1
- package/dist/chunks/chunk-SWUXA3MH.ts.map +7 -0
- package/dist/chunks/{chunk-TEN2ZBJV.ts → chunk-T2SJD3N7.ts} +2 -4
- package/dist/chunks/chunk-T2SJD3N7.ts.map +7 -0
- package/dist/chunks/{chunk-AUSDLD6F.ts → chunk-T56RNRZJ.ts} +10 -26
- package/dist/chunks/chunk-T56RNRZJ.ts.map +7 -0
- package/dist/chunks/{chunk-KW7YQEZN.ts → chunk-UA7RXOIT.ts} +48 -100
- package/dist/chunks/chunk-UA7RXOIT.ts.map +7 -0
- package/dist/chunks/{chunk-D5X27LCA.ts → chunk-UETBKTDI.ts} +1 -1
- package/dist/chunks/chunk-UETBKTDI.ts.map +7 -0
- package/dist/chunks/{chunk-CHH26D4F.ts → chunk-YFADF5ZQ.ts} +7 -6
- package/dist/chunks/chunk-YFADF5ZQ.ts.map +7 -0
- package/dist/chunks/{chunk-CCSN3F47.ts → chunk-YPXGU5OR.ts} +4 -4
- package/dist/chunks/chunk-YPXGU5OR.ts.map +7 -0
- package/dist/chunks/{file-selection-FTTKAOYX.ts → file-selection-RAVHRYFG.ts} +14 -26
- package/dist/chunks/file-selection-RAVHRYFG.ts.map +7 -0
- package/dist/chunks/{git-backend-GMVS4PD4.ts → git-backend-IAANDL3K.ts} +41 -104
- package/dist/chunks/git-backend-IAANDL3K.ts.map +7 -0
- package/dist/chunks/manager-result-dispatcher-OTUMQM26.ts +23 -0
- package/dist/chunks/{manager-ui-5KLKVMRC.ts → manager-ui-763NEKJY.ts} +124 -251
- package/dist/chunks/manager-ui-763NEKJY.ts.map +7 -0
- package/dist/chunks/remote-selection-ui-TZTJF32Y.ts +22 -0
- package/dist/chunks/{s3-backend-66O4FGBH.ts → s3-backend-XGXUOPUN.ts} +23 -54
- package/dist/chunks/s3-backend-XGXUOPUN.ts.map +7 -0
- package/dist/chunks/{setup-switch-IS2PEZ3J.ts → setup-switch-5G2VNJHL.ts} +9 -9
- package/dist/chunks/{setup-wizard-IUB6ESEU.ts → setup-wizard-YIEWGX32.ts} +12 -12
- package/dist/chunks/setup-wizard-YIEWGX32.ts.map +7 -0
- package/dist/chunks/{snapshot-HKEWCVK6.ts → snapshot-JL5DFSXI.ts} +5 -5
- package/dist/chunks/sync-inspection-P3ENJLNF.ts +20 -0
- package/dist/chunks/{sync-operations-LBX3GKCM.ts → sync-operations-AR76EB6C.ts} +85 -201
- package/dist/chunks/sync-operations-AR76EB6C.ts.map +7 -0
- package/dist/chunks/{sync-state-Q2FTXTW6.ts → sync-state-VHJUZ4YG.ts} +6 -6
- package/dist/chunks/{webdav-backend-ECIKD7SO.ts → webdav-backend-3EGUONAT.ts} +20 -51
- package/dist/chunks/webdav-backend-3EGUONAT.ts.map +7 -0
- package/dist/index.ts +49 -74
- package/dist/index.ts.map +3 -3
- package/docs/settings.md +9 -0
- package/package.json +61 -62
- package/src/backends/backend-factory.ts +15 -15
- package/src/backends/backend-identity.ts +31 -31
- package/src/backends/backend-types.ts +42 -42
- package/src/backends/git/git-backend.ts +714 -788
- package/src/backends/git/git-config.ts +104 -111
- package/src/backends/git/git-runner.ts +230 -247
- package/src/backends/git/git-storage.ts +228 -245
- package/src/backends/s3/s3-backend.ts +408 -441
- package/src/backends/s3/s3-client.ts +288 -333
- package/src/backends/sync-backend.ts +65 -65
- package/src/backends/webdav/webdav-backend.ts +542 -589
- package/src/backends/webdav/webdav-client.ts +292 -316
- package/src/backends/webdav/webdav-config.ts +57 -68
- package/src/commands/command-execution.ts +270 -289
- package/src/commands/command-handler.ts +160 -163
- package/src/commands/command-types.ts +13 -13
- package/src/commands/command.ts +190 -196
- package/src/commands/setup-completions.ts +1 -1
- package/src/paths.ts +47 -47
- package/src/settings/config-errors.ts +4 -5
- package/src/settings/config-file.ts +473 -506
- package/src/settings/config.ts +171 -174
- package/src/settings/settings-management.ts +191 -216
- package/src/settings/settings-store.ts +63 -77
- package/src/settings/settings-types.ts +78 -75
- package/src/settings/settings-validation.ts +328 -364
- package/src/snapshot/session-paths.ts +41 -55
- package/src/snapshot/snapshot-apply.ts +197 -229
- package/src/snapshot/snapshot-codec.ts +29 -31
- package/src/snapshot/snapshot-paths.ts +4 -6
- package/src/snapshot/snapshot-transaction.ts +161 -170
- package/src/snapshot/snapshot-types.ts +24 -24
- package/src/snapshot/snapshot.ts +310 -343
- package/src/state/json-file.ts +11 -11
- package/src/state/lock.ts +226 -242
- package/src/state/lockfile-fs.ts +20 -20
- package/src/state/operation-availability.ts +36 -41
- package/src/state/state-directory.ts +171 -173
- package/src/state/state-types.ts +15 -15
- package/src/state/sync-state-store.ts +23 -23
- package/src/sync/automatic-sync.ts +75 -80
- package/src/sync/remote-snapshot.ts +52 -60
- package/src/sync/setup-switch.ts +99 -114
- package/src/sync/signals.ts +3 -5
- package/src/sync/startup-check.ts +97 -111
- package/src/sync/sync-decision.ts +76 -80
- package/src/sync/sync-error-guidance.ts +41 -48
- package/src/sync/sync-errors.ts +10 -10
- package/src/sync/sync-inspection.ts +29 -33
- package/src/sync/sync-loaders.ts +28 -36
- package/src/sync/sync-mutations.ts +510 -622
- package/src/sync/sync-operations.ts +7 -7
- package/src/sync/sync-policy.ts +296 -326
- package/src/sync/sync-queries.ts +175 -194
- package/src/sync/sync-state.ts +74 -100
- package/src/sync-extension.ts +89 -101
- package/src/sync.ts +26 -26
- package/src/types.ts +37 -37
- package/src/ui/automatic-sync-summary.ts +1 -3
- package/src/ui/cancellable-operation.ts +92 -112
- package/src/ui/file-selection.ts +250 -274
- package/src/ui/manager-attention.ts +51 -63
- package/src/ui/manager-recovery.ts +48 -57
- package/src/ui/manager-result-dispatcher.ts +62 -76
- package/src/ui/manager-state.ts +200 -232
- package/src/ui/manager-ui.ts +264 -362
- package/src/ui/remote-selection-ui.ts +547 -588
- package/src/ui/secret-input.ts +198 -214
- package/src/ui/settings-ui.ts +175 -172
- package/src/ui/setup/git-ui.ts +232 -261
- package/src/ui/setup/s3-credentials-ui.ts +58 -65
- package/src/ui/setup/s3-ui.ts +171 -195
- package/src/ui/setup/setup-actions.ts +91 -101
- package/src/ui/setup/setup-location-ui.ts +121 -137
- package/src/ui/setup/setup-name-ui.ts +27 -27
- package/src/ui/setup/setup-prompts.ts +65 -65
- package/src/ui/setup/setup-review.ts +58 -59
- package/src/ui/setup/setup-switcher.ts +156 -160
- package/src/ui/setup/setup-wizard.ts +28 -28
- package/src/ui/setup/text-input.ts +54 -58
- package/src/ui/setup/webdav-ui.ts +246 -293
- package/src/ui/storage-connections-ui.ts +317 -369
- package/src/ui/sync-attention.ts +148 -164
- package/src/ui/sync-format.ts +110 -121
- package/src/ui/sync-resolution-ui.ts +147 -153
- package/src/ui/sync-setups-ui.ts +218 -238
- package/src/ui/sync-status.ts +17 -0
- package/src/ui/terminal-text.ts +2 -2
- package/dist/chunks/chunk-2B2ELUF5.ts.map +0 -7
- package/dist/chunks/chunk-4CHTZMEO.ts.map +0 -7
- package/dist/chunks/chunk-5B3FXBLE.ts.map +0 -7
- package/dist/chunks/chunk-6LP3MCR2.ts.map +0 -7
- package/dist/chunks/chunk-AUSDLD6F.ts.map +0 -7
- package/dist/chunks/chunk-C7XY5NF5.ts.map +0 -7
- package/dist/chunks/chunk-CCSN3F47.ts.map +0 -7
- package/dist/chunks/chunk-CHH26D4F.ts.map +0 -7
- package/dist/chunks/chunk-CPEHGXJV.ts.map +0 -7
- package/dist/chunks/chunk-D5X27LCA.ts.map +0 -7
- package/dist/chunks/chunk-ETTRJDNP.ts.map +0 -7
- package/dist/chunks/chunk-G4RNQQZS.ts.map +0 -7
- package/dist/chunks/chunk-HUDQATCL.ts.map +0 -7
- package/dist/chunks/chunk-IJ6FJFA5.ts.map +0 -7
- package/dist/chunks/chunk-JAAKLL6M.ts.map +0 -7
- package/dist/chunks/chunk-KW7YQEZN.ts.map +0 -7
- package/dist/chunks/chunk-LCRI3ABW.ts.map +0 -7
- package/dist/chunks/chunk-LTBWGSBV.ts.map +0 -7
- package/dist/chunks/chunk-NJFUIVYL.ts.map +0 -7
- package/dist/chunks/chunk-OEX4ABY6.ts.map +0 -7
- package/dist/chunks/chunk-Q2TUM5X6.ts.map +0 -7
- package/dist/chunks/chunk-SL64RLXR.ts.map +0 -7
- package/dist/chunks/chunk-SZWBGPID.ts.map +0 -7
- package/dist/chunks/chunk-T2B5IU74.ts.map +0 -7
- package/dist/chunks/chunk-T3HH3UEJ.ts.map +0 -7
- package/dist/chunks/chunk-TEN2ZBJV.ts.map +0 -7
- package/dist/chunks/chunk-THMF4BVL.ts.map +0 -7
- package/dist/chunks/chunk-Z4DQF6L3.ts.map +0 -7
- package/dist/chunks/chunk-ZI5MXMEX.ts.map +0 -7
- package/dist/chunks/file-selection-FTTKAOYX.ts.map +0 -7
- package/dist/chunks/git-backend-GMVS4PD4.ts.map +0 -7
- package/dist/chunks/manager-result-dispatcher-FKIBM3GO.ts +0 -22
- package/dist/chunks/manager-ui-5KLKVMRC.ts.map +0 -7
- package/dist/chunks/remote-selection-ui-D7RBRJNL.ts +0 -21
- package/dist/chunks/s3-backend-66O4FGBH.ts.map +0 -7
- package/dist/chunks/setup-wizard-IUB6ESEU.ts.map +0 -7
- package/dist/chunks/sync-inspection-CST2KL65.ts +0 -20
- package/dist/chunks/sync-operations-LBX3GKCM.ts.map +0 -7
- package/dist/chunks/webdav-backend-ECIKD7SO.ts.map +0 -7
- /package/dist/chunks/{manager-result-dispatcher-FKIBM3GO.ts.map → manager-result-dispatcher-OTUMQM26.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-D7RBRJNL.ts.map → remote-selection-ui-TZTJF32Y.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-IS2PEZ3J.ts.map → setup-switch-5G2VNJHL.ts.map} +0 -0
- /package/dist/chunks/{snapshot-HKEWCVK6.ts.map → snapshot-JL5DFSXI.ts.map} +0 -0
- /package/dist/chunks/{sync-inspection-CST2KL65.ts.map → sync-inspection-P3ENJLNF.ts.map} +0 -0
- /package/dist/chunks/{sync-state-Q2FTXTW6.ts.map → sync-state-VHJUZ4YG.ts.map} +0 -0
|
@@ -3,82 +3,75 @@ import { promptSecret } from "../secret-input.js";
|
|
|
3
3
|
import { requiredValueInput } from "./text-input.js";
|
|
4
4
|
|
|
5
5
|
export interface ChosenS3Credentials {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
profileFields: { accessKeyId?: string; secretAccessKey?: string };
|
|
7
|
+
summary: string;
|
|
8
|
+
ready: boolean;
|
|
9
|
+
replace?: boolean;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export async function chooseS3CredentialUpdate(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
ctx: ExtensionCommandContext,
|
|
14
|
+
profile: Record<string, unknown>,
|
|
15
|
+
signal?: AbortSignal,
|
|
16
16
|
) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const selected = await chooseS3Credentials(ctx, signal);
|
|
35
|
-
return selected ? { ...selected, replace: true } : undefined;
|
|
17
|
+
const hasStored =
|
|
18
|
+
typeof profile.accessKeyId === "string" &&
|
|
19
|
+
profile.accessKeyId.length > 0 &&
|
|
20
|
+
typeof profile.secretAccessKey === "string" &&
|
|
21
|
+
profile.secretAccessKey.length > 0;
|
|
22
|
+
if (hasStored) {
|
|
23
|
+
const action = await ctx.ui.select("Credentials", ["Keep current credentials", "Replace credentials", "Cancel"], {
|
|
24
|
+
signal,
|
|
25
|
+
});
|
|
26
|
+
throwIfAborted(signal);
|
|
27
|
+
if (!action || action === "Cancel") return undefined;
|
|
28
|
+
if (action === "Keep current credentials") {
|
|
29
|
+
return { profileFields: {}, summary: "Unchanged (values hidden)", ready: true };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const selected = await chooseS3Credentials(ctx, signal);
|
|
33
|
+
return selected ? { ...selected, replace: true } : undefined;
|
|
36
34
|
}
|
|
37
35
|
|
|
38
|
-
export function applyS3CredentialUpdate(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
delete next.sessionToken;
|
|
47
|
-
}
|
|
48
|
-
return { ...next, ...credentials.profileFields };
|
|
36
|
+
export function applyS3CredentialUpdate(profile: Record<string, unknown>, credentials: ChosenS3Credentials) {
|
|
37
|
+
const next = { ...profile };
|
|
38
|
+
if (credentials.replace) {
|
|
39
|
+
delete next.accessKeyId;
|
|
40
|
+
delete next.secretAccessKey;
|
|
41
|
+
delete next.sessionToken;
|
|
42
|
+
}
|
|
43
|
+
return { ...next, ...credentials.profileFields };
|
|
49
44
|
}
|
|
50
45
|
|
|
51
46
|
export async function chooseS3Credentials(
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
ctx: ExtensionCommandContext,
|
|
48
|
+
signal?: AbortSignal,
|
|
54
49
|
): Promise<ChosenS3Credentials | undefined> {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
50
|
+
const choice = await ctx.ui.select(
|
|
51
|
+
"Credentials\n\nCredentials are stored in the private pi-sync settings file. Secret values are masked during input and never shown afterward.",
|
|
52
|
+
["Store credentials privately", "Cancel"],
|
|
53
|
+
{ signal },
|
|
54
|
+
);
|
|
55
|
+
throwIfAborted(signal);
|
|
56
|
+
if (choice !== "Store credentials privately") return undefined;
|
|
57
|
+
const accessKeyId = await requiredValueInput(
|
|
58
|
+
ctx,
|
|
59
|
+
"Access key ID\n\nUse the S3 API access key ID issued by your provider, not the secret access key.",
|
|
60
|
+
"access-key-id",
|
|
61
|
+
signal,
|
|
62
|
+
);
|
|
63
|
+
if (!accessKeyId) return undefined;
|
|
64
|
+
const secretAccessKey = await promptSecret(ctx, "Secret access key", { signal });
|
|
65
|
+
throwIfAborted(signal);
|
|
66
|
+
if (secretAccessKey === undefined) return undefined;
|
|
67
|
+
return {
|
|
68
|
+
profileFields: { accessKeyId, secretAccessKey },
|
|
69
|
+
summary: "Stored privately (values hidden)",
|
|
70
|
+
ready: true,
|
|
71
|
+
};
|
|
77
72
|
}
|
|
78
73
|
|
|
79
74
|
function throwIfAborted(signal?: AbortSignal) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
? signal.reason
|
|
83
|
-
: new DOMException("The operation was aborted", "AbortError");
|
|
75
|
+
if (!signal?.aborted) return;
|
|
76
|
+
throw signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted", "AbortError");
|
|
84
77
|
}
|
package/src/ui/setup/s3-ui.ts
CHANGED
|
@@ -1,217 +1,193 @@
|
|
|
1
1
|
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { refreshTargetCompletions } from "../../commands/setup-completions.js";
|
|
3
|
-
import {
|
|
4
|
-
addSyncSetup,
|
|
5
|
-
saveNewV3Settings,
|
|
6
|
-
updateSyncSetup,
|
|
7
|
-
} from "../../settings/settings-management.js";
|
|
3
|
+
import { addSyncSetup, saveNewV3Settings, updateSyncSetup } from "../../settings/settings-management.js";
|
|
8
4
|
import type { PartialConfig } from "../../settings/settings-types.js";
|
|
9
|
-
import {
|
|
10
|
-
normalizeS3Bucket,
|
|
11
|
-
normalizeS3Endpoint,
|
|
12
|
-
normalizeStoragePath,
|
|
13
|
-
} from "../../settings/settings-validation.js";
|
|
5
|
+
import { normalizeS3Bucket, normalizeS3Endpoint, normalizeStoragePath } from "../../settings/settings-validation.js";
|
|
14
6
|
import { automaticSyncSummary } from "../automatic-sync-summary.js";
|
|
15
7
|
import { safeTerminalText } from "../terminal-text.js";
|
|
16
8
|
import { chooseS3Credentials } from "./s3-credentials-ui.js";
|
|
17
9
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
10
|
+
chooseAdditionalRemoteLocation,
|
|
11
|
+
chooseInitialRemoteLocation,
|
|
12
|
+
promptAvailableSetupStorage,
|
|
21
13
|
} from "./setup-location-ui.js";
|
|
22
14
|
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
15
|
+
chooseAutomaticSync,
|
|
16
|
+
chooseSessions,
|
|
17
|
+
chooseSetupContent,
|
|
18
|
+
includedContentLines,
|
|
19
|
+
readSetupConnection,
|
|
28
20
|
} from "./setup-prompts.js";
|
|
29
21
|
import { saveReviewedDraft } from "./setup-review.js";
|
|
30
22
|
import { requiredInput, requiredValueInput } from "./text-input.js";
|
|
31
23
|
|
|
32
24
|
export async function showS3Setup(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
25
|
+
ctx: ExtensionCommandContext,
|
|
26
|
+
preset: string,
|
|
27
|
+
targetName: string,
|
|
28
|
+
signal?: AbortSignal,
|
|
37
29
|
) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
ctx.ui.notify(
|
|
117
|
-
`Sync setup “${safeTerminalText(targetName)}” saved. Choose Sync now to start.`,
|
|
118
|
-
"info",
|
|
119
|
-
);
|
|
120
|
-
return true;
|
|
30
|
+
const endpoint = await requiredValueInput(
|
|
31
|
+
ctx,
|
|
32
|
+
preset === "Cloudflare R2"
|
|
33
|
+
? "Cloudflare R2 endpoint\n\nCopy the S3 API endpoint from your R2 account; replace <account-id>."
|
|
34
|
+
: "S3-compatible endpoint\n\nUse your provider's S3 API URL, not its web console.",
|
|
35
|
+
preset === "Cloudflare R2" ? "https://<account-id>.r2.cloudflarestorage.com" : "https://s3.example.com",
|
|
36
|
+
signal,
|
|
37
|
+
normalizeS3Endpoint,
|
|
38
|
+
);
|
|
39
|
+
if (!endpoint) return false;
|
|
40
|
+
const region =
|
|
41
|
+
preset === "Cloudflare R2"
|
|
42
|
+
? "auto"
|
|
43
|
+
: await requiredInput(
|
|
44
|
+
ctx,
|
|
45
|
+
"Storage region\n\nUse the region assigned to your bucket by the provider.",
|
|
46
|
+
"us-east-1",
|
|
47
|
+
signal,
|
|
48
|
+
);
|
|
49
|
+
if (!region) return false;
|
|
50
|
+
const location = await chooseInitialRemoteLocation(ctx, preset, targetName, signal);
|
|
51
|
+
if (!location) return false;
|
|
52
|
+
const credentials = await chooseS3Credentials(ctx, signal);
|
|
53
|
+
if (!credentials) return false;
|
|
54
|
+
const include = await chooseSetupContent(ctx, signal);
|
|
55
|
+
if (!include) return false;
|
|
56
|
+
const automatic = await chooseAutomaticSync(ctx, signal);
|
|
57
|
+
if (automatic === undefined) return false;
|
|
58
|
+
const sessions = await chooseSessions(ctx, signal);
|
|
59
|
+
if (sessions === undefined) return false;
|
|
60
|
+
const saved = await saveReviewedDraft(
|
|
61
|
+
ctx,
|
|
62
|
+
"Review sync setup",
|
|
63
|
+
[
|
|
64
|
+
`Sync setup: ${safeTerminalText(targetName)}`,
|
|
65
|
+
`Storage connection: ${safeTerminalText(location.connectionName)} (${preset})`,
|
|
66
|
+
`Endpoint: ${safeTerminalText(endpoint)}`,
|
|
67
|
+
`Region: ${safeTerminalText(region)}`,
|
|
68
|
+
`Bucket: ${safeTerminalText(location.bucket)}`,
|
|
69
|
+
`Storage location: ${safeTerminalText(location.path)}`,
|
|
70
|
+
...includedContentLines(include, sessions),
|
|
71
|
+
`Automatic sync: ${automaticSyncSummary(automatic)}`,
|
|
72
|
+
`Credentials: ${credentials.summary}`,
|
|
73
|
+
"The bucket must already exist. Saving does not contact remote storage or start syncing.",
|
|
74
|
+
],
|
|
75
|
+
"Save sync setup",
|
|
76
|
+
(saveSignal) =>
|
|
77
|
+
saveNewV3Settings(
|
|
78
|
+
{
|
|
79
|
+
setupName: targetName,
|
|
80
|
+
connectionName: location.connectionName,
|
|
81
|
+
connection: {
|
|
82
|
+
type: "s3",
|
|
83
|
+
endpoint,
|
|
84
|
+
region,
|
|
85
|
+
credentials: {
|
|
86
|
+
accessKeyId: credentials.profileFields.accessKeyId ?? "",
|
|
87
|
+
secretAccessKey: credentials.profileFields.secretAccessKey ?? "",
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
setup: {
|
|
91
|
+
storage: {
|
|
92
|
+
connection: location.connectionName,
|
|
93
|
+
bucket: location.bucket,
|
|
94
|
+
path: location.path,
|
|
95
|
+
},
|
|
96
|
+
sync: { include: [...include, ...(sessions ? ["sessions"] : [])], automatic },
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
saveSignal,
|
|
100
|
+
),
|
|
101
|
+
signal,
|
|
102
|
+
);
|
|
103
|
+
if (!saved || signal?.aborted) return false;
|
|
104
|
+
await refreshTargetCompletions();
|
|
105
|
+
if (!signal?.aborted)
|
|
106
|
+
ctx.ui.notify(`Sync setup “${safeTerminalText(targetName)}” saved. Choose Sync now to start.`, "info");
|
|
107
|
+
return true;
|
|
121
108
|
}
|
|
122
109
|
|
|
123
110
|
export async function showAddS3Target(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
111
|
+
ctx: ExtensionCommandContext,
|
|
112
|
+
raw: Record<string, unknown>,
|
|
113
|
+
profile: string,
|
|
114
|
+
name: string,
|
|
115
|
+
signal?: AbortSignal,
|
|
129
116
|
) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
signal,
|
|
162
|
-
);
|
|
163
|
-
if (!saved || signal?.aborted) return;
|
|
164
|
-
await refreshTargetCompletions();
|
|
165
|
-
if (!signal?.aborted) ctx.ui.notify(`Added sync setup “${safeTerminalText(name)}”.`, "info");
|
|
117
|
+
const location = await chooseAdditionalRemoteLocation(ctx, raw, profile, name, signal);
|
|
118
|
+
if (!location) return;
|
|
119
|
+
const storage = await promptAvailableSetupStorage(ctx, { connection: profile, ...location }, signal);
|
|
120
|
+
if (!storage) return;
|
|
121
|
+
const include = await chooseSetupContent(ctx, signal);
|
|
122
|
+
if (!include) return;
|
|
123
|
+
const automatic = await chooseAutomaticSync(ctx, signal);
|
|
124
|
+
if (automatic === undefined) return;
|
|
125
|
+
const connection = await readSetupConnection(profile, signal);
|
|
126
|
+
if (connection.type !== "s3") throw new Error("Storage connection changed; reopen setup.");
|
|
127
|
+
const saved = await saveReviewedDraft(
|
|
128
|
+
ctx,
|
|
129
|
+
"Review new sync setup",
|
|
130
|
+
[
|
|
131
|
+
`Sync setup: ${safeTerminalText(name)}`,
|
|
132
|
+
`Storage connection: ${safeTerminalText(profile)}`,
|
|
133
|
+
`Endpoint: ${safeTerminalText(connection.endpoint)}`,
|
|
134
|
+
`Bucket: ${safeTerminalText(storage.bucket)}`,
|
|
135
|
+
`Storage location: ${safeTerminalText(storage.path)}`,
|
|
136
|
+
...includedContentLines(include),
|
|
137
|
+
`Automatic sync: ${automaticSyncSummary(automatic)}`,
|
|
138
|
+
"Only the current setup is checked at startup. Shutdown can push selected content when sessions are included.",
|
|
139
|
+
"The bucket must already exist. Adding this setup does not sync or modify remote data.",
|
|
140
|
+
],
|
|
141
|
+
"Add sync setup",
|
|
142
|
+
(saveSignal) => addSyncSetup(name, { storage, sync: { include, automatic } }, saveSignal, connection),
|
|
143
|
+
signal,
|
|
144
|
+
);
|
|
145
|
+
if (!saved || signal?.aborted) return;
|
|
146
|
+
await refreshTargetCompletions();
|
|
147
|
+
if (!signal?.aborted) ctx.ui.notify(`Added sync setup “${safeTerminalText(name)}”.`, "info");
|
|
166
148
|
}
|
|
167
149
|
|
|
168
|
-
export async function showEditS3Target(
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
{ expectedStorage: partial, expectedConnection: connection, signal: saveSignal },
|
|
212
|
-
),
|
|
213
|
-
signal,
|
|
214
|
-
);
|
|
215
|
-
if (saved && !signal?.aborted)
|
|
216
|
-
ctx.ui.notify(`Saved sync setup “${safeTerminalText(partial.setupName)}”.`, "info");
|
|
150
|
+
export async function showEditS3Target(ctx: ExtensionCommandContext, partial: PartialConfig, signal?: AbortSignal) {
|
|
151
|
+
const bucket = await requiredInput(
|
|
152
|
+
ctx,
|
|
153
|
+
"Bucket\n\nUse an existing bucket; pi-sync will not create it.",
|
|
154
|
+
partial.bucket ?? "pi-sync",
|
|
155
|
+
signal,
|
|
156
|
+
normalizeS3Bucket,
|
|
157
|
+
);
|
|
158
|
+
if (!bucket) return;
|
|
159
|
+
const storagePath = await requiredInput(
|
|
160
|
+
ctx,
|
|
161
|
+
"Storage path\n\nPath inside the bucket, not your local filesystem. ./ uses the bucket root.",
|
|
162
|
+
partial.storagePath,
|
|
163
|
+
signal,
|
|
164
|
+
normalizeStoragePath,
|
|
165
|
+
);
|
|
166
|
+
if (!storagePath) return;
|
|
167
|
+
const connection = await readSetupConnection(partial.connectionName, signal);
|
|
168
|
+
if (connection.type !== "s3") throw new Error("Storage connection changed; reopen setup.");
|
|
169
|
+
const saved = await saveReviewedDraft(
|
|
170
|
+
ctx,
|
|
171
|
+
"Review sync setup",
|
|
172
|
+
[
|
|
173
|
+
`Sync setup: ${safeTerminalText(partial.setupName)}`,
|
|
174
|
+
`Storage connection: ${safeTerminalText(partial.connectionName)}`,
|
|
175
|
+
`Endpoint: ${safeTerminalText(connection.endpoint)}`,
|
|
176
|
+
`Bucket: ${safeTerminalText(partial.bucket ?? "missing")} → ${safeTerminalText(bucket)}`,
|
|
177
|
+
`Storage path: ${safeTerminalText(partial.storagePath)} → ${safeTerminalText(storagePath)}`,
|
|
178
|
+
"Saving changes the future storage location only; it does not move or delete remote data.",
|
|
179
|
+
],
|
|
180
|
+
"Save sync setup",
|
|
181
|
+
(saveSignal) =>
|
|
182
|
+
updateSyncSetup(
|
|
183
|
+
partial.setupName,
|
|
184
|
+
(setup) => {
|
|
185
|
+
if (typeof setup.storage.bucket !== "string") throw new Error("Sync setup storage type changed; reopen it.");
|
|
186
|
+
return { ...setup, storage: { ...setup.storage, bucket, path: storagePath } };
|
|
187
|
+
},
|
|
188
|
+
{ expectedStorage: partial, expectedConnection: connection, signal: saveSignal },
|
|
189
|
+
),
|
|
190
|
+
signal,
|
|
191
|
+
);
|
|
192
|
+
if (saved && !signal?.aborted) ctx.ui.notify(`Saved sync setup “${safeTerminalText(partial.setupName)}”.`, "info");
|
|
217
193
|
}
|