sitevision-cli 0.4.0-beta.1 → 0.4.0-beta.2
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/dist/app.js +53 -15
- package/dist/components/KeychainPasswordChoice.d.ts +8 -0
- package/dist/components/KeychainPasswordChoice.js +30 -0
- package/dist/components/PasswordInput.d.ts +3 -1
- package/dist/components/PasswordInput.js +3 -3
- package/dist/utils/signing-step.d.ts +15 -0
- package/dist/utils/signing-step.js +16 -0
- package/package.json +1 -1
package/dist/app.js
CHANGED
|
@@ -1,20 +1,48 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
2
|
+
import { useMemo, useState } from 'react';
|
|
3
3
|
import { MainMenu } from './components/MainMenu.js';
|
|
4
4
|
import { InfoScreen } from './components/InfoScreen.js';
|
|
5
5
|
import { SetupFlow } from './components/SetupFlow.js';
|
|
6
6
|
import { PasswordInput } from './components/PasswordInput.js';
|
|
7
|
+
import { KeychainPasswordChoice } from './components/KeychainPasswordChoice.js';
|
|
8
|
+
import { decideSigningStep } from './utils/signing-step.js';
|
|
7
9
|
import { DevScreen } from './commands/dev.js';
|
|
8
10
|
import { BuildScreen } from './commands/build.js';
|
|
9
11
|
import { DeployScreen } from './commands/deploy.js';
|
|
10
12
|
import { SignScreen } from './commands/sign.js';
|
|
11
13
|
import { SigningPropertiesForm } from './components/SigningPropertiesForm.js';
|
|
12
|
-
import { setDeployPassword as saveDeployPassword, setSigningPassword as saveSigningPassword, } from './utils/keychain.js';
|
|
14
|
+
import { getSigningPassword, setDeployPassword as saveDeployPassword, setSigningPassword as saveSigningPassword, } from './utils/keychain.js';
|
|
13
15
|
export default function App({ project }) {
|
|
14
16
|
const [state, setState] = useState('setup');
|
|
15
17
|
const [currentCommand, setCurrentCommand] = useState('');
|
|
16
18
|
const [signingPassword, setSigningPassword] = useState('');
|
|
17
19
|
const [devPassword, setDevPassword] = useState('');
|
|
20
|
+
// When true, skip the keychain "use saved / enter new" choice and go straight
|
|
21
|
+
// to manual entry (e.g. the saved password just failed and we're retrying).
|
|
22
|
+
const [signingRetry, setSigningRetry] = useState(false);
|
|
23
|
+
// Read the saved signing password from the keychain once (keychain access is
|
|
24
|
+
// slow and this component re-renders frequently).
|
|
25
|
+
const signingUsername = project.devProperties?.signingUsername;
|
|
26
|
+
const storedSigningPassword = useMemo(() => (signingUsername ? getSigningPassword(signingUsername) : null), [signingUsername]);
|
|
27
|
+
// Decide the next step once a signing password is needed: proceed if we already
|
|
28
|
+
// have one this session, offer the keychain choice if one is saved, otherwise
|
|
29
|
+
// prompt for manual entry.
|
|
30
|
+
const routeToSigningStep = (command = currentCommand) => {
|
|
31
|
+
const step = decideSigningStep({
|
|
32
|
+
hasSessionPassword: Boolean(signingPassword),
|
|
33
|
+
hasStoredPassword: Boolean(storedSigningPassword),
|
|
34
|
+
isRetry: signingRetry,
|
|
35
|
+
});
|
|
36
|
+
if (step === 'proceed') {
|
|
37
|
+
setState(command === 'dev-signed' ? 'dev' : 'sign');
|
|
38
|
+
}
|
|
39
|
+
else if (step === 'choice') {
|
|
40
|
+
setState('signing-password-choice');
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
setState('signing-password-input');
|
|
44
|
+
}
|
|
45
|
+
};
|
|
18
46
|
// Check if dev password is available (either from file or session)
|
|
19
47
|
const hasDevPassword = Boolean(project.devProperties?.password || devPassword);
|
|
20
48
|
// Get effective dev properties with session password if needed
|
|
@@ -35,8 +63,8 @@ export default function App({ project }) {
|
|
|
35
63
|
}
|
|
36
64
|
// Continue to the intended command
|
|
37
65
|
if (currentCommand === 'dev' || currentCommand === 'dev-signed') {
|
|
38
|
-
if (currentCommand === 'dev-signed'
|
|
39
|
-
|
|
66
|
+
if (currentCommand === 'dev-signed') {
|
|
67
|
+
routeToSigningStep();
|
|
40
68
|
}
|
|
41
69
|
else {
|
|
42
70
|
setState('dev');
|
|
@@ -46,6 +74,15 @@ export default function App({ project }) {
|
|
|
46
74
|
setState('deploy');
|
|
47
75
|
}
|
|
48
76
|
};
|
|
77
|
+
const handleUseSavedSigning = () => {
|
|
78
|
+
if (storedSigningPassword) {
|
|
79
|
+
setSigningPassword(storedSigningPassword);
|
|
80
|
+
}
|
|
81
|
+
setState(currentCommand === 'dev-signed' ? 'dev' : 'sign');
|
|
82
|
+
};
|
|
83
|
+
const handleEnterNewSigning = () => {
|
|
84
|
+
setState('signing-password-input');
|
|
85
|
+
};
|
|
49
86
|
const handleSigningPasswordSubmit = (password, remember) => {
|
|
50
87
|
setSigningPassword(password);
|
|
51
88
|
if (remember && project.devProperties?.signingUsername && password) {
|
|
@@ -60,6 +97,8 @@ export default function App({ project }) {
|
|
|
60
97
|
};
|
|
61
98
|
const handleCommandSelect = (command) => {
|
|
62
99
|
setCurrentCommand(command);
|
|
100
|
+
// Fresh selection from the menu — re-offer the saved keychain password.
|
|
101
|
+
setSigningRetry(false);
|
|
63
102
|
switch (command) {
|
|
64
103
|
case 'info':
|
|
65
104
|
setState('info');
|
|
@@ -92,11 +131,8 @@ export default function App({ project }) {
|
|
|
92
131
|
if (!hasDevPassword) {
|
|
93
132
|
setState('dev-password-input');
|
|
94
133
|
}
|
|
95
|
-
else if (!signingPassword) {
|
|
96
|
-
setState('signing-password-input');
|
|
97
|
-
}
|
|
98
134
|
else {
|
|
99
|
-
|
|
135
|
+
routeToSigningStep(command);
|
|
100
136
|
}
|
|
101
137
|
break;
|
|
102
138
|
case 'sign':
|
|
@@ -108,12 +144,7 @@ export default function App({ project }) {
|
|
|
108
144
|
console.log('\x1b[31mSigning credentials not configured. Run svc setup-signing first.\x1b[0m');
|
|
109
145
|
return;
|
|
110
146
|
}
|
|
111
|
-
|
|
112
|
-
setState('sign');
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
setState('signing-password-input');
|
|
116
|
-
}
|
|
147
|
+
routeToSigningStep(command);
|
|
117
148
|
break;
|
|
118
149
|
case 'build':
|
|
119
150
|
setState('build');
|
|
@@ -146,8 +177,13 @@ export default function App({ project }) {
|
|
|
146
177
|
if (state === 'dev-password-input') {
|
|
147
178
|
return (_jsx(PasswordInput, { label: "Enter Development Password (usually Sitevision Cloud Password)", showRememberOption: Boolean(project.devProperties?.domain && project.devProperties?.username), onSubmit: handleDevPasswordSubmit, onCancel: () => setState('menu') }, "dev-password"));
|
|
148
179
|
}
|
|
180
|
+
if (state === 'signing-password-choice') {
|
|
181
|
+
return (_jsx(KeychainPasswordChoice, { onUseSaved: handleUseSavedSigning, onEnterNew: handleEnterNewSigning, onCancel: () => setState('menu') }, "signing-password-choice"));
|
|
182
|
+
}
|
|
149
183
|
if (state === 'signing-password-input') {
|
|
150
|
-
return (_jsx(PasswordInput, { label: "Enter Signing Password (developer.sitevision.se)", showRememberOption: Boolean(project.devProperties?.signingUsername),
|
|
184
|
+
return (_jsx(PasswordInput, { label: "Enter Signing Password (developer.sitevision.se)", showRememberOption: Boolean(project.devProperties?.signingUsername), defaultRemember: Boolean(storedSigningPassword), rememberLabel: storedSigningPassword
|
|
185
|
+
? 'Update saved password in OS keychain: '
|
|
186
|
+
: 'Save to OS keychain: ', onSubmit: handleSigningPasswordSubmit, onCancel: () => setState('menu') }, "signing-password"));
|
|
151
187
|
}
|
|
152
188
|
if (state === 'dev') {
|
|
153
189
|
return (_jsx(DevScreen, { projectRoot: project.root, manifest: project.manifest, devProperties: getEffectiveDevProperties(), signed: currentCommand === 'dev-signed', onBack: () => setState('menu'), onRetryCredentials: () => {
|
|
@@ -156,6 +192,8 @@ export default function App({ project }) {
|
|
|
156
192
|
project.devProperties.password = undefined;
|
|
157
193
|
if (currentCommand === 'dev-signed') {
|
|
158
194
|
setSigningPassword('');
|
|
195
|
+
// The saved password may be what failed — don't re-offer it.
|
|
196
|
+
setSigningRetry(true);
|
|
159
197
|
}
|
|
160
198
|
setState('dev-password-input');
|
|
161
199
|
}, signingCredentials: currentCommand === 'dev-signed' &&
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box, Text, useInput } from 'ink';
|
|
4
|
+
const OPTIONS = [
|
|
5
|
+
{ label: 'Use saved password from keychain', value: 'saved' },
|
|
6
|
+
{ label: 'Enter a new password', value: 'new' },
|
|
7
|
+
];
|
|
8
|
+
export function KeychainPasswordChoice({ label = 'A signing password is saved in your OS keychain.', onUseSaved, onEnterNew, onCancel, }) {
|
|
9
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
10
|
+
useInput((_input, key) => {
|
|
11
|
+
if (key.upArrow) {
|
|
12
|
+
setSelectedIndex(prev => (prev === 0 ? OPTIONS.length - 1 : prev - 1));
|
|
13
|
+
}
|
|
14
|
+
else if (key.downArrow) {
|
|
15
|
+
setSelectedIndex(prev => (prev === OPTIONS.length - 1 ? 0 : prev + 1));
|
|
16
|
+
}
|
|
17
|
+
else if (key.return) {
|
|
18
|
+
if (selectedIndex === 0) {
|
|
19
|
+
onUseSaved();
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
onEnterNew();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else if (key.escape) {
|
|
26
|
+
onCancel();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: label }) }), OPTIONS.map((option, index) => (_jsxs(Text, { color: index === selectedIndex ? 'green' : undefined, children: [index === selectedIndex ? '❯ ' : ' ', option.label] }, option.value))), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move, Enter to select, Esc to cancel" }) })] }));
|
|
30
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
interface Props {
|
|
2
2
|
label?: string;
|
|
3
3
|
showRememberOption?: boolean;
|
|
4
|
+
defaultRemember?: boolean;
|
|
5
|
+
rememberLabel?: string;
|
|
4
6
|
onSubmit: (password: string, remember: boolean) => void;
|
|
5
7
|
onCancel: () => void;
|
|
6
8
|
}
|
|
7
|
-
export declare function PasswordInput({ label, showRememberOption, onSubmit, onCancel, }: Props): import("react").JSX.Element;
|
|
9
|
+
export declare function PasswordInput({ label, showRememberOption, defaultRemember, rememberLabel, onSubmit, onCancel, }: Props): import("react").JSX.Element;
|
|
8
10
|
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { Box, Text, useInput } from 'ink';
|
|
4
|
-
export function PasswordInput({ label = 'Enter Signing Password', showRememberOption = false, onSubmit, onCancel, }) {
|
|
4
|
+
export function PasswordInput({ label = 'Enter Signing Password', showRememberOption = false, defaultRemember = false, rememberLabel = 'Save to OS keychain: ', onSubmit, onCancel, }) {
|
|
5
5
|
const [password, setPassword] = useState('');
|
|
6
|
-
const [remember, setRemember] = useState(
|
|
6
|
+
const [remember, setRemember] = useState(defaultRemember);
|
|
7
7
|
useInput((input, key) => {
|
|
8
8
|
if (key.return) {
|
|
9
9
|
onSubmit(password, remember);
|
|
@@ -26,5 +26,5 @@ export function PasswordInput({ label = 'Enter Signing Password', showRememberOp
|
|
|
26
26
|
setPassword(prev => prev + input);
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
|
-
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: label }) }), _jsx(Box, { borderStyle: "round", borderColor: "cyan", paddingX: 1, children: _jsx(Text, { children: '*'.repeat(password.length) }) }), showRememberOption && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children:
|
|
29
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: label }) }), _jsx(Box, { borderStyle: "round", borderColor: "cyan", paddingX: 1, children: _jsx(Text, { children: '*'.repeat(password.length) }) }), showRememberOption && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: rememberLabel }), _jsxs(Text, { color: remember ? 'green' : 'gray', children: ["[", remember ? 'x' : ' ', "]"] }), _jsx(Text, { dimColor: true, children: " (Tab to toggle)" })] })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Press Enter to submit, Esc to cancel" }) })] }));
|
|
30
30
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type SigningStep = 'proceed' | 'choice' | 'input';
|
|
2
|
+
/**
|
|
3
|
+
* Decide what to do when a signing password is needed.
|
|
4
|
+
*
|
|
5
|
+
* - `proceed`: a password is already available this session — use it.
|
|
6
|
+
* - `choice`: a password is saved in the keychain — ask whether to use it or
|
|
7
|
+
* enter a new one.
|
|
8
|
+
* - `input`: prompt for a password (nothing saved, or a saved one just failed
|
|
9
|
+
* and we're retrying).
|
|
10
|
+
*/
|
|
11
|
+
export declare function decideSigningStep(options: {
|
|
12
|
+
hasSessionPassword: boolean;
|
|
13
|
+
hasStoredPassword: boolean;
|
|
14
|
+
isRetry: boolean;
|
|
15
|
+
}): SigningStep;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decide what to do when a signing password is needed.
|
|
3
|
+
*
|
|
4
|
+
* - `proceed`: a password is already available this session — use it.
|
|
5
|
+
* - `choice`: a password is saved in the keychain — ask whether to use it or
|
|
6
|
+
* enter a new one.
|
|
7
|
+
* - `input`: prompt for a password (nothing saved, or a saved one just failed
|
|
8
|
+
* and we're retrying).
|
|
9
|
+
*/
|
|
10
|
+
export function decideSigningStep(options) {
|
|
11
|
+
if (options.hasSessionPassword)
|
|
12
|
+
return 'proceed';
|
|
13
|
+
if (options.hasStoredPassword && !options.isRetry)
|
|
14
|
+
return 'choice';
|
|
15
|
+
return 'input';
|
|
16
|
+
}
|