@narumitw/pi-sync 0.50.3 → 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-YDWUZVPN.ts → chunk-7KHKWL3Q.ts} +28 -47
- 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-YHEMENKV.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-DHVFS4QK.ts → chunk-UA7RXOIT.ts} +37 -90
- 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-IPAOAWZA.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-JUJZYNNM.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 +89 -101
- 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 +197 -205
- 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-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-DHVFS4QK.ts.map +0 -7
- package/dist/chunks/chunk-ETTRJDNP.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-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-YDWUZVPN.ts.map +0 -7
- package/dist/chunks/chunk-YHEMENKV.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-ASKGOSW5.ts +0 -22
- package/dist/chunks/manager-ui-IPAOAWZA.ts.map +0 -7
- package/dist/chunks/remote-selection-ui-QDNR7WEI.ts +0 -21
- package/dist/chunks/s3-backend-66O4FGBH.ts.map +0 -7
- package/dist/chunks/setup-wizard-JUJZYNNM.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-ASKGOSW5.ts.map → manager-result-dispatcher-OTUMQM26.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-QDNR7WEI.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
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
normalizeWebDavPath,
|
|
4
|
+
normalizeWebDavUrl,
|
|
5
|
+
validateWebDavCredentials,
|
|
6
6
|
} from "../../backends/webdav/webdav-config.js";
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
addStorageConnection,
|
|
9
|
+
addSyncSetup,
|
|
10
|
+
saveNewV3Settings,
|
|
11
|
+
updateStorageConnection,
|
|
12
|
+
updateSyncSetup,
|
|
13
13
|
} from "../../settings/settings-management.js";
|
|
14
14
|
import type { PartialConfig } from "../../settings/settings-types.js";
|
|
15
15
|
import { automaticSyncSummary } from "../automatic-sync-summary.js";
|
|
@@ -17,314 +17,267 @@ import { promptSecret } from "../secret-input.js";
|
|
|
17
17
|
import { safeTerminalText as safe } from "../terminal-text.js";
|
|
18
18
|
import { promptAvailableSetupStorage } from "./setup-location-ui.js";
|
|
19
19
|
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
chooseAutomaticSync,
|
|
21
|
+
chooseSessions,
|
|
22
|
+
chooseSetupContent,
|
|
23
|
+
includedContentLines,
|
|
24
|
+
promptResourceName,
|
|
25
|
+
readSetupConnection,
|
|
26
26
|
} from "./setup-prompts.js";
|
|
27
27
|
import { saveReviewedDraft } from "./setup-review.js";
|
|
28
28
|
import { promptTextInput } from "./text-input.js";
|
|
29
29
|
|
|
30
|
-
export async function showWebDavSetup(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
if (saved && !signal?.aborted)
|
|
81
|
-
ctx.ui.notify(`Sync setup “${safe(targetName)}” saved. Choose Sync now to start.`, "info");
|
|
82
|
-
return saved;
|
|
30
|
+
export async function showWebDavSetup(ctx: ExtensionCommandContext, targetName: string, signal?: AbortSignal) {
|
|
31
|
+
const url = await promptWebDavUrl(ctx, signal);
|
|
32
|
+
if (!url) return false;
|
|
33
|
+
const username = await promptUsername(ctx, signal);
|
|
34
|
+
if (!username) return false;
|
|
35
|
+
const password = await promptSecret(ctx, "WebDAV password", { signal });
|
|
36
|
+
signal?.throwIfAborted();
|
|
37
|
+
if (password === undefined) return false;
|
|
38
|
+
const remotePath = await chooseDestination(ctx, signal);
|
|
39
|
+
if (!remotePath) return false;
|
|
40
|
+
const include = await chooseSetupContent(ctx, signal);
|
|
41
|
+
if (!include) return false;
|
|
42
|
+
const automatic = await chooseAutomaticSync(ctx, signal);
|
|
43
|
+
if (automatic === undefined) return false;
|
|
44
|
+
const sessions = await chooseSessions(ctx, signal);
|
|
45
|
+
if (sessions === undefined) return false;
|
|
46
|
+
const saved = await saveReviewedDraft(
|
|
47
|
+
ctx,
|
|
48
|
+
"Review WebDAV setup",
|
|
49
|
+
[
|
|
50
|
+
`Sync setup: ${safe(targetName)}`,
|
|
51
|
+
`Storage connection: ${safe(targetName)} (WebDAV)`,
|
|
52
|
+
`URL: ${safe(url)}`,
|
|
53
|
+
`Storage location: ${safe(remotePath)}`,
|
|
54
|
+
"Username and password: stored privately (values hidden)",
|
|
55
|
+
...includedContentLines(include, sessions),
|
|
56
|
+
`Automatic sync: ${automaticSyncSummary(automatic)}`,
|
|
57
|
+
"Check setup tests whether this server can safely save sync updates using a temporary probe.",
|
|
58
|
+
"Saving does not contact remote storage or start syncing.",
|
|
59
|
+
],
|
|
60
|
+
"Save setup",
|
|
61
|
+
(saveSignal) =>
|
|
62
|
+
saveNewV3Settings(
|
|
63
|
+
{
|
|
64
|
+
setupName: targetName,
|
|
65
|
+
connectionName: targetName,
|
|
66
|
+
connection: { type: "webdav", url, credentials: { username, password } },
|
|
67
|
+
setup: {
|
|
68
|
+
storage: { connection: targetName, path: remotePath },
|
|
69
|
+
sync: { include: [...include, ...(sessions ? ["sessions"] : [])], automatic },
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
saveSignal,
|
|
73
|
+
),
|
|
74
|
+
signal,
|
|
75
|
+
);
|
|
76
|
+
if (saved && !signal?.aborted)
|
|
77
|
+
ctx.ui.notify(`Sync setup “${safe(targetName)}” saved. Choose Sync now to start.`, "info");
|
|
78
|
+
return saved;
|
|
83
79
|
}
|
|
84
80
|
|
|
85
81
|
export async function showAddWebDavTarget(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
82
|
+
ctx: ExtensionCommandContext,
|
|
83
|
+
name: string,
|
|
84
|
+
profile: string,
|
|
85
|
+
signal?: AbortSignal,
|
|
90
86
|
) {
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
addSyncSetup(name, { storage, sync: { include, automatic } }, saveSignal, connection),
|
|
120
|
-
signal,
|
|
121
|
-
);
|
|
122
|
-
if (saved && !signal?.aborted) ctx.ui.notify(`Added sync setup “${safe(name)}”.`, "info");
|
|
123
|
-
return saved;
|
|
87
|
+
const remotePath = await chooseDestination(ctx, signal);
|
|
88
|
+
if (!remotePath) return false;
|
|
89
|
+
const storage = await promptAvailableSetupStorage(ctx, { connection: profile, path: remotePath }, signal);
|
|
90
|
+
if (!storage) return false;
|
|
91
|
+
const include = await chooseSetupContent(ctx, signal);
|
|
92
|
+
if (!include) return false;
|
|
93
|
+
const automatic = await chooseAutomaticSync(ctx, signal);
|
|
94
|
+
if (automatic === undefined) return false;
|
|
95
|
+
const connection = await readSetupConnection(profile, signal);
|
|
96
|
+
if (connection.type !== "webdav") throw new Error("Storage connection changed; reopen setup.");
|
|
97
|
+
const saved = await saveReviewedDraft(
|
|
98
|
+
ctx,
|
|
99
|
+
"Review WebDAV sync setup",
|
|
100
|
+
[
|
|
101
|
+
`Sync setup: ${safe(name)}`,
|
|
102
|
+
`Storage connection: ${safe(profile)}`,
|
|
103
|
+
`URL: ${safe(connection.url)}`,
|
|
104
|
+
`Storage location: ${safe(storage.path)}`,
|
|
105
|
+
...includedContentLines(include),
|
|
106
|
+
`Automatic sync: ${automaticSyncSummary(automatic)}`,
|
|
107
|
+
"Adding this setup does not sync or modify remote data.",
|
|
108
|
+
],
|
|
109
|
+
"Add sync setup",
|
|
110
|
+
(saveSignal) => addSyncSetup(name, { storage, sync: { include, automatic } }, saveSignal, connection),
|
|
111
|
+
signal,
|
|
112
|
+
);
|
|
113
|
+
if (saved && !signal?.aborted) ctx.ui.notify(`Added sync setup “${safe(name)}”.`, "info");
|
|
114
|
+
return saved;
|
|
124
115
|
}
|
|
125
116
|
|
|
126
|
-
export async function showEditWebDavTarget(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
signal,
|
|
156
|
-
);
|
|
157
|
-
if (saved && !signal?.aborted)
|
|
158
|
-
ctx.ui.notify(`Saved sync setup “${safe(partial.setupName)}”.`, "info");
|
|
159
|
-
return saved;
|
|
117
|
+
export async function showEditWebDavTarget(ctx: ExtensionCommandContext, partial: PartialConfig, signal?: AbortSignal) {
|
|
118
|
+
const remotePath = await chooseDestination(ctx, signal, partial.storagePath);
|
|
119
|
+
if (!remotePath) return false;
|
|
120
|
+
const connection = await readSetupConnection(partial.connectionName, signal);
|
|
121
|
+
if (connection.type !== "webdav") throw new Error("Storage connection changed; reopen setup.");
|
|
122
|
+
const saved = await saveReviewedDraft(
|
|
123
|
+
ctx,
|
|
124
|
+
"Review sync setup",
|
|
125
|
+
[
|
|
126
|
+
`Sync setup: ${safe(partial.setupName)}`,
|
|
127
|
+
`Storage connection: ${safe(partial.connectionName)}`,
|
|
128
|
+
`URL: ${safe(connection.url)}`,
|
|
129
|
+
`Storage path: ${safe(partial.storagePath)} → ${safe(remotePath)}`,
|
|
130
|
+
"Saving changes the future storage location only; it does not move or delete remote data.",
|
|
131
|
+
],
|
|
132
|
+
"Save sync setup",
|
|
133
|
+
(saveSignal) =>
|
|
134
|
+
updateSyncSetup(
|
|
135
|
+
partial.setupName,
|
|
136
|
+
(setup) => ({
|
|
137
|
+
...setup,
|
|
138
|
+
storage: { ...setup.storage, path: remotePath },
|
|
139
|
+
}),
|
|
140
|
+
{ expectedStorage: partial, expectedConnection: connection, signal: saveSignal },
|
|
141
|
+
),
|
|
142
|
+
signal,
|
|
143
|
+
);
|
|
144
|
+
if (saved && !signal?.aborted) ctx.ui.notify(`Saved sync setup “${safe(partial.setupName)}”.`, "info");
|
|
145
|
+
return saved;
|
|
160
146
|
}
|
|
161
147
|
|
|
162
|
-
export async function showAddWebDavStorageProfile(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
{ type: "webdav", url, credentials: { username, password } },
|
|
190
|
-
saveSignal,
|
|
191
|
-
),
|
|
192
|
-
signal,
|
|
193
|
-
);
|
|
194
|
-
if (saved && !signal?.aborted) ctx.ui.notify(`Added storage connection “${safe(name)}”.`, "info");
|
|
195
|
-
return saved;
|
|
148
|
+
export async function showAddWebDavStorageProfile(ctx: ExtensionCommandContext, signal?: AbortSignal) {
|
|
149
|
+
const name = await promptResourceName(ctx, "storage connection", "webdav", signal, true);
|
|
150
|
+
if (!name) return false;
|
|
151
|
+
const url = await promptWebDavUrl(ctx, signal);
|
|
152
|
+
if (!url) return false;
|
|
153
|
+
const username = await promptUsername(ctx, signal);
|
|
154
|
+
if (!username) return false;
|
|
155
|
+
const password = await promptSecret(ctx, "WebDAV password", { signal });
|
|
156
|
+
signal?.throwIfAborted();
|
|
157
|
+
if (password === undefined) return false;
|
|
158
|
+
const saved = await saveReviewedDraft(
|
|
159
|
+
ctx,
|
|
160
|
+
"Review storage connection",
|
|
161
|
+
[
|
|
162
|
+
`Name: ${safe(name)}`,
|
|
163
|
+
"Type: WebDAV",
|
|
164
|
+
`URL: ${safe(url)}`,
|
|
165
|
+
"Username and password: stored privately (values hidden)",
|
|
166
|
+
"Adding a connection does not contact the server or start syncing.",
|
|
167
|
+
],
|
|
168
|
+
"Add storage connection",
|
|
169
|
+
(saveSignal) =>
|
|
170
|
+
addStorageConnection(name, { type: "webdav", url, credentials: { username, password } }, saveSignal),
|
|
171
|
+
signal,
|
|
172
|
+
);
|
|
173
|
+
if (saved && !signal?.aborted) ctx.ui.notify(`Added storage connection “${safe(name)}”.`, "info");
|
|
174
|
+
return saved;
|
|
196
175
|
}
|
|
197
176
|
|
|
198
177
|
export async function showEditWebDavStorageProfile(
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
178
|
+
ctx: ExtensionCommandContext,
|
|
179
|
+
name: string,
|
|
180
|
+
profile: Record<string, unknown>,
|
|
181
|
+
signal?: AbortSignal,
|
|
182
|
+
affectedSetups?: string[],
|
|
204
183
|
) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
password: password ?? current.credentials.password,
|
|
259
|
-
},
|
|
260
|
-
};
|
|
261
|
-
},
|
|
262
|
-
affectedSetups,
|
|
263
|
-
saveSignal,
|
|
264
|
-
),
|
|
265
|
-
signal,
|
|
266
|
-
);
|
|
267
|
-
if (saved && !signal?.aborted) ctx.ui.notify(`Saved storage connection “${safe(name)}”.`, "info");
|
|
268
|
-
return saved;
|
|
184
|
+
const url = await promptWebDavUrl(ctx, signal, typeof profile.url === "string" ? profile.url : undefined);
|
|
185
|
+
if (!url) return false;
|
|
186
|
+
const username = await promptUsername(ctx, signal);
|
|
187
|
+
if (!username) return false;
|
|
188
|
+
const hasPassword = typeof profile.password === "string" && profile.password.length > 0;
|
|
189
|
+
const passwordAction = hasPassword
|
|
190
|
+
? await select(ctx, "WebDAV password", ["Keep current password", "Replace password", "Cancel"], signal)
|
|
191
|
+
: "Replace password";
|
|
192
|
+
if (!passwordAction || passwordAction === "Cancel") return false;
|
|
193
|
+
const replacePassword = passwordAction === "Replace password";
|
|
194
|
+
const password = replacePassword ? await promptSecret(ctx, "New WebDAV password", { signal }) : undefined;
|
|
195
|
+
signal?.throwIfAborted();
|
|
196
|
+
if (replacePassword && password === undefined) return false;
|
|
197
|
+
const saved = await saveReviewedDraft(
|
|
198
|
+
ctx,
|
|
199
|
+
"Review storage connection",
|
|
200
|
+
[
|
|
201
|
+
`Storage connection: ${safe(name)}`,
|
|
202
|
+
`URL: ${safe(String(profile.url))} → ${safe(url)}`,
|
|
203
|
+
"Username: stored privately (value hidden)",
|
|
204
|
+
`Password: ${replacePassword ? "will be replaced" : "unchanged"} (value hidden)`,
|
|
205
|
+
`Affected sync setups: ${affectedSetups?.length ? affectedSetups.map(safe).join(", ") : "None"}`,
|
|
206
|
+
"Saving changes future storage access for every affected setup; it does not move remote data.",
|
|
207
|
+
],
|
|
208
|
+
"Save storage connection",
|
|
209
|
+
(saveSignal) =>
|
|
210
|
+
updateStorageConnection(
|
|
211
|
+
name,
|
|
212
|
+
(current) => {
|
|
213
|
+
if (
|
|
214
|
+
current.type !== "webdav" ||
|
|
215
|
+
current.url !== profile.url ||
|
|
216
|
+
current.credentials.username !== profile.username ||
|
|
217
|
+
current.credentials.password !== profile.password
|
|
218
|
+
)
|
|
219
|
+
throw new Error("Storage connection changed while it was open; reopen it.");
|
|
220
|
+
return {
|
|
221
|
+
...current,
|
|
222
|
+
url,
|
|
223
|
+
credentials: {
|
|
224
|
+
...current.credentials,
|
|
225
|
+
username,
|
|
226
|
+
password: password ?? current.credentials.password,
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
},
|
|
230
|
+
affectedSetups,
|
|
231
|
+
saveSignal,
|
|
232
|
+
),
|
|
233
|
+
signal,
|
|
234
|
+
);
|
|
235
|
+
if (saved && !signal?.aborted) ctx.ui.notify(`Saved storage connection “${safe(name)}”.`, "info");
|
|
236
|
+
return saved;
|
|
269
237
|
}
|
|
270
238
|
|
|
271
|
-
async function chooseDestination(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
"WebDAV storage path\n\nFolder relative to the collection URL, not your local filesystem.\n./ uses the collection root. Use different folders for independent setups.",
|
|
279
|
-
{ defaultValue: current, validate: normalizeWebDavPath },
|
|
280
|
-
signal,
|
|
281
|
-
);
|
|
239
|
+
async function chooseDestination(ctx: ExtensionCommandContext, signal?: AbortSignal, current = "./") {
|
|
240
|
+
return promptTextInput(
|
|
241
|
+
ctx,
|
|
242
|
+
"WebDAV storage path\n\nFolder relative to the collection URL, not your local filesystem.\n./ uses the collection root. Use different folders for independent setups.",
|
|
243
|
+
{ defaultValue: current, validate: normalizeWebDavPath },
|
|
244
|
+
signal,
|
|
245
|
+
);
|
|
282
246
|
}
|
|
283
247
|
|
|
284
248
|
async function promptUsername(ctx: ExtensionCommandContext, signal?: AbortSignal) {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
249
|
+
return promptTextInput(
|
|
250
|
+
ctx,
|
|
251
|
+
"WebDAV username\n\nEnter the account username; stored values remain hidden.",
|
|
252
|
+
{
|
|
253
|
+
example: "user",
|
|
254
|
+
validate: (value) => {
|
|
255
|
+
validateWebDavCredentials(value);
|
|
256
|
+
return value;
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
signal,
|
|
260
|
+
);
|
|
297
261
|
}
|
|
298
262
|
|
|
299
|
-
async function promptWebDavUrl(
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
if (!url) throw new Error("WebDAV URL is required.");
|
|
314
|
-
return url;
|
|
315
|
-
},
|
|
316
|
-
},
|
|
317
|
-
signal,
|
|
318
|
-
);
|
|
263
|
+
async function promptWebDavUrl(ctx: ExtensionCommandContext, signal?: AbortSignal, current?: string) {
|
|
264
|
+
return promptTextInput(
|
|
265
|
+
ctx,
|
|
266
|
+
"WebDAV collection URL\n\nUse the HTTPS WebDAV URL from your provider, not its web login page.",
|
|
267
|
+
{
|
|
268
|
+
...(current ? { defaultValue: current } : { example: "https://cloud.example.com/remote.php/dav/files/user" }),
|
|
269
|
+
validate: (value) => {
|
|
270
|
+
const url = normalizeWebDavUrl(value);
|
|
271
|
+
if (!url) throw new Error("WebDAV URL is required.");
|
|
272
|
+
return url;
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
signal,
|
|
276
|
+
);
|
|
319
277
|
}
|
|
320
278
|
|
|
321
|
-
async function select(
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
signal?: AbortSignal,
|
|
326
|
-
) {
|
|
327
|
-
const value = await ctx.ui.select(title, options, { signal });
|
|
328
|
-
signal?.throwIfAborted();
|
|
329
|
-
return value;
|
|
279
|
+
async function select(ctx: ExtensionCommandContext, title: string, options: string[], signal?: AbortSignal) {
|
|
280
|
+
const value = await ctx.ui.select(title, options, { signal });
|
|
281
|
+
signal?.throwIfAborted();
|
|
282
|
+
return value;
|
|
330
283
|
}
|