sitevision-cli 1.0.0-beta.10 → 1.0.0-beta.11
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
CHANGED
|
@@ -4,6 +4,7 @@ import { detectProject } from './utils/project-detection.js';
|
|
|
4
4
|
import { MainMenu } from './components/MainMenu.js';
|
|
5
5
|
import { InfoScreen } from './components/InfoScreen.js';
|
|
6
6
|
import { SetupFlow } from './components/SetupFlow.js';
|
|
7
|
+
import { DevPropertiesForm } from './components/DevPropertiesForm.js';
|
|
7
8
|
import { PasswordInput } from './components/PasswordInput.js';
|
|
8
9
|
import { KeychainPasswordChoice } from './components/KeychainPasswordChoice.js';
|
|
9
10
|
import { decideSigningStep } from './utils/signing-step.js';
|
|
@@ -135,6 +136,13 @@ export default function App({ project: initialProject }) {
|
|
|
135
136
|
case 'setup-signing':
|
|
136
137
|
setState('setup-signing');
|
|
137
138
|
break;
|
|
139
|
+
case 'change-auth':
|
|
140
|
+
if (!project.hasDevProperties || !project.devProperties) {
|
|
141
|
+
console.log('\x1b[31mDevelopment properties not configured. Create a .dev_properties.json file first.\x1b[0m');
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
setState('change-auth-method');
|
|
145
|
+
break;
|
|
138
146
|
case 'dev':
|
|
139
147
|
if (!project.hasDevProperties || !project.devProperties) {
|
|
140
148
|
console.log('\x1b[31mDevelopment properties not configured. Create a .dev_properties.json file first.\x1b[0m');
|
|
@@ -221,6 +229,12 @@ export default function App({ project: initialProject }) {
|
|
|
221
229
|
break;
|
|
222
230
|
}
|
|
223
231
|
};
|
|
232
|
+
if (state === 'change-auth-method') {
|
|
233
|
+
return (_jsx(DevPropertiesForm, { projectRoot: project.root, initialProperties: project.devProperties, packageJson: project.packageJson, authOnly: true, onComplete: () => {
|
|
234
|
+
reloadProject();
|
|
235
|
+
setState('menu');
|
|
236
|
+
}, onCancel: () => setState('menu') }));
|
|
237
|
+
}
|
|
224
238
|
if (state === 'setup') {
|
|
225
239
|
return (_jsx(SetupFlow, { project: project, onReload: reloadProject, onComplete: () => setState('menu') }));
|
|
226
240
|
}
|
|
@@ -293,7 +307,7 @@ export default function App({ project: initialProject }) {
|
|
|
293
307
|
if (project.devProperties)
|
|
294
308
|
project.devProperties.password = undefined;
|
|
295
309
|
setState('dev-password-input');
|
|
296
|
-
} }));
|
|
310
|
+
}, onChangeAuthMethod: () => setState('change-auth-method') }));
|
|
297
311
|
}
|
|
298
312
|
if (state === 'setup-signing') {
|
|
299
313
|
return (_jsx(SigningPropertiesForm, { projectRoot: project.root, onComplete: () => {
|
|
@@ -10,7 +10,8 @@ interface DeployScreenProps {
|
|
|
10
10
|
activate: boolean;
|
|
11
11
|
onBack?: () => void;
|
|
12
12
|
onRetryCredentials?: () => void;
|
|
13
|
+
onChangeAuthMethod?: () => void;
|
|
13
14
|
}
|
|
14
|
-
export declare function DeployScreen({ projectRoot, manifest, devProperties, force, production, activate, onBack, onRetryCredentials, }: DeployScreenProps): React.JSX.Element;
|
|
15
|
+
export declare function DeployScreen({ projectRoot, manifest, devProperties, force, production, activate, onBack, onRetryCredentials, onChangeAuthMethod, }: DeployScreenProps): React.JSX.Element;
|
|
15
16
|
export declare const deployCommand: Command;
|
|
16
17
|
export {};
|
package/dist/commands/deploy.js
CHANGED
|
@@ -6,10 +6,10 @@ import { deployApp, deployProduction } from '../utils/sitevision-api.js';
|
|
|
6
6
|
import { getZipPath, getSignedZipPath, getAppType, } from '../utils/project-detection.js';
|
|
7
7
|
import { zipExists } from '../utils/zip.js';
|
|
8
8
|
import { promptPassword, promptYesNo } from '../utils/password-prompt.js';
|
|
9
|
-
import { setDeployPassword, deleteSessionCookie } from '../utils/keychain.js';
|
|
9
|
+
import { setDeployPassword, deleteSessionCookie, deleteOAuth2RefreshToken, } from '../utils/keychain.js';
|
|
10
10
|
import { resolveOAuth2AccessToken } from '../utils/oauth2-auth.js';
|
|
11
11
|
import { AuthLoginScreen } from '../components/AuthLoginScreen.js';
|
|
12
|
-
export function DeployScreen({ projectRoot, manifest, devProperties, force, production, activate, onBack, onRetryCredentials, }) {
|
|
12
|
+
export function DeployScreen({ projectRoot, manifest, devProperties, force, production, activate, onBack, onRetryCredentials, onChangeAuthMethod, }) {
|
|
13
13
|
const [state, setState] = React.useState({
|
|
14
14
|
status: 'deploying',
|
|
15
15
|
message: production ? 'Deploying to production...' : 'Deploying to dev...',
|
|
@@ -23,19 +23,56 @@ export function DeployScreen({ projectRoot, manifest, devProperties, force, prod
|
|
|
23
23
|
sessionCookie: devProperties.sessionCookie,
|
|
24
24
|
});
|
|
25
25
|
const deployStartedRef = React.useRef(false);
|
|
26
|
+
const authMethod = devProperties.authMethod ?? 'basic';
|
|
27
|
+
// OAuth2 and cookie can re-authenticate in-place; basic re-prompts via the
|
|
28
|
+
// parent (TUI password entry).
|
|
29
|
+
const canRelogin = authMethod === 'oauth2' || authMethod === 'cookie';
|
|
30
|
+
// Discard the stored credential and force a fresh login. This is the
|
|
31
|
+
// "retry with new credentials" action for token/cookie auth — the usual fix
|
|
32
|
+
// when a session/token has expired (Sitevision reports that as a 400, not a
|
|
33
|
+
// 401, so it isn't auto-cleared).
|
|
34
|
+
const retryWithFreshLogin = () => {
|
|
35
|
+
const { domain, username } = devProperties;
|
|
36
|
+
if (authMethod === 'cookie' && domain && username) {
|
|
37
|
+
deleteSessionCookie(domain, username);
|
|
38
|
+
devProperties.sessionCookie = undefined;
|
|
39
|
+
}
|
|
40
|
+
else if (authMethod === 'oauth2' &&
|
|
41
|
+
domain &&
|
|
42
|
+
devProperties.oauth2?.clientId) {
|
|
43
|
+
deleteOAuth2RefreshToken(domain, devProperties.oauth2.clientId);
|
|
44
|
+
devProperties.accessToken = undefined;
|
|
45
|
+
}
|
|
46
|
+
setCredential({});
|
|
47
|
+
deployStartedRef.current = false;
|
|
48
|
+
setState({
|
|
49
|
+
status: 'deploying',
|
|
50
|
+
message: production
|
|
51
|
+
? 'Deploying to production...'
|
|
52
|
+
: 'Deploying to dev...',
|
|
53
|
+
});
|
|
54
|
+
setPhase('login');
|
|
55
|
+
};
|
|
26
56
|
useInput((input, key) => {
|
|
27
57
|
if (state.status !== 'deploying') {
|
|
28
58
|
if (onBack && (key.escape || input === 'q')) {
|
|
29
59
|
onBack();
|
|
30
60
|
}
|
|
31
|
-
if (
|
|
32
|
-
|
|
61
|
+
if (state.status === 'error' && input === 'r') {
|
|
62
|
+
if (canRelogin) {
|
|
63
|
+
retryWithFreshLogin();
|
|
64
|
+
}
|
|
65
|
+
else if (onRetryCredentials) {
|
|
66
|
+
onRetryCredentials();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (state.status === 'error' && input === 'm' && onChangeAuthMethod) {
|
|
70
|
+
onChangeAuthMethod();
|
|
33
71
|
}
|
|
34
72
|
}
|
|
35
73
|
});
|
|
36
74
|
// Decide once whether we can deploy straight away or must log in first.
|
|
37
75
|
React.useEffect(() => {
|
|
38
|
-
const authMethod = devProperties.authMethod ?? 'basic';
|
|
39
76
|
if (authMethod === 'basic' || devProperties.sessionCookie) {
|
|
40
77
|
setPhase('deploy');
|
|
41
78
|
return;
|
|
@@ -72,7 +109,6 @@ export function DeployScreen({ projectRoot, manifest, devProperties, force, prod
|
|
|
72
109
|
async function runDeploy() {
|
|
73
110
|
try {
|
|
74
111
|
const appType = getAppType(manifest);
|
|
75
|
-
const authMethod = devProperties.authMethod ?? 'basic';
|
|
76
112
|
// Credential resolved in the init effect / login screen.
|
|
77
113
|
const { accessToken, sessionCookie } = credential;
|
|
78
114
|
// A stale session fails without a clean 401 — clear the stored cookie
|
|
@@ -191,7 +227,7 @@ export function DeployScreen({ projectRoot, manifest, devProperties, force, prod
|
|
|
191
227
|
? 'Deploying'
|
|
192
228
|
: state.status === 'success'
|
|
193
229
|
? 'Deployed'
|
|
194
|
-
: 'Failed', message: state.message }) }), state.status === 'success' && (_jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Text, { color: "green", children: [production ? 'Production deployment' : 'Dev deployment', " complete"] }), state.executableId && (_jsxs(Text, { dimColor: true, children: ["Executable ID: ", state.executableId] })), force && _jsx(Text, { dimColor: true, children: "(Force mode - overwrote existing)" }), activate && production && _jsx(Text, { dimColor: true, children: "(Activated)" })] })), state.status === 'error' && state.error && (
|
|
230
|
+
: 'Failed', message: state.message }) }), state.status === 'success' && (_jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Text, { color: "green", children: [production ? 'Production deployment' : 'Dev deployment', " complete"] }), state.executableId && (_jsxs(Text, { dimColor: true, children: ["Executable ID: ", state.executableId] })), force && _jsx(Text, { dimColor: true, children: "(Force mode - overwrote existing)" }), activate && production && _jsx(Text, { dimColor: true, children: "(Activated)" })] })), state.status === 'error' && state.error && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "red", children: state.error }), canRelogin && (_jsx(Text, { color: "yellow", children: "This can happen when your session or token has expired \u2014 log in again to get fresh credentials." }))] })), state.status !== 'deploying' && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [state.status === 'error' && canRelogin && (_jsx(Text, { dimColor: true, children: "Press r to log in again with fresh credentials" })), state.status === 'error' && !canRelogin && onRetryCredentials && (_jsx(Text, { dimColor: true, children: "Press r to retry with new credentials" })), state.status === 'error' && onChangeAuthMethod && (_jsx(Text, { dimColor: true, children: "Press m to change auth method" })), onBack && _jsx(Text, { dimColor: true, children: "Press q or Esc to return to menu" })] }))] }));
|
|
195
231
|
}
|
|
196
232
|
export const deployCommand = {
|
|
197
233
|
name: 'deploy',
|
|
@@ -3,8 +3,9 @@ interface Props {
|
|
|
3
3
|
projectRoot: string;
|
|
4
4
|
initialProperties?: DevProperties;
|
|
5
5
|
packageJson: PackageJson;
|
|
6
|
+
authOnly?: boolean;
|
|
6
7
|
onComplete: () => void;
|
|
7
8
|
onCancel: () => void;
|
|
8
9
|
}
|
|
9
|
-
export declare function DevPropertiesForm({ projectRoot, initialProperties, packageJson, onComplete, onCancel, }: Props): import("react").JSX.Element;
|
|
10
|
+
export declare function DevPropertiesForm({ projectRoot, initialProperties, packageJson, authOnly, onComplete, onCancel, }: Props): import("react").JSX.Element;
|
|
10
11
|
export {};
|
|
@@ -32,7 +32,7 @@ function parseScopes(raw) {
|
|
|
32
32
|
.filter(Boolean);
|
|
33
33
|
return scopes.length > 0 ? scopes : undefined;
|
|
34
34
|
}
|
|
35
|
-
export function DevPropertiesForm({ projectRoot, initialProperties, packageJson, onComplete, onCancel, }) {
|
|
35
|
+
export function DevPropertiesForm({ projectRoot, initialProperties, packageJson, authOnly, onComplete, onCancel, }) {
|
|
36
36
|
const [stepIndex, setStepIndex] = useState(0);
|
|
37
37
|
const [properties, setProperties] = useState(() => {
|
|
38
38
|
const defaults = {
|
|
@@ -63,15 +63,17 @@ export function DevPropertiesForm({ projectRoot, initialProperties, packageJson,
|
|
|
63
63
|
: method === 'cookie'
|
|
64
64
|
? ['sessionLoginUrl']
|
|
65
65
|
: ['password'];
|
|
66
|
-
const steps =
|
|
67
|
-
'
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
66
|
+
const steps = authOnly
|
|
67
|
+
? ['authMethod', ...methodSteps]
|
|
68
|
+
: [
|
|
69
|
+
'domain',
|
|
70
|
+
'siteName',
|
|
71
|
+
'addonName',
|
|
72
|
+
'username',
|
|
73
|
+
'authMethod',
|
|
74
|
+
...methodSteps,
|
|
75
|
+
'useHTTP',
|
|
76
|
+
];
|
|
75
77
|
const currentStep = steps[stepIndex];
|
|
76
78
|
const redirectPort = initialProperties?.oauth2?.redirectPort ?? DEFAULT_REDIRECT_PORT;
|
|
77
79
|
const advance = () => {
|
|
@@ -51,6 +51,11 @@ export function MainMenu({ project, onSelect }) {
|
|
|
51
51
|
value: 'deploy-production',
|
|
52
52
|
description: 'Deploy to production server',
|
|
53
53
|
},
|
|
54
|
+
{
|
|
55
|
+
label: '🔑 Auth Method',
|
|
56
|
+
value: 'change-auth',
|
|
57
|
+
description: 'Change the deploy authentication method',
|
|
58
|
+
},
|
|
54
59
|
{
|
|
55
60
|
label: 'ℹ️ Info',
|
|
56
61
|
value: 'info',
|