sitevision-cli 1.0.0-beta.31 → 1.0.0-beta.33
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/CHANGELOG.md +70 -0
- package/LICENSE +21 -0
- package/dist/cli.js +73 -34
- package/dist/commands/TaskScreen.js +32 -0
- package/dist/commands/build.js +6 -185
- package/dist/commands/deploy.js +85 -238
- package/dist/commands/dev.js +34 -37
- package/dist/commands/info.js +1 -1
- package/dist/commands/setup-signing.js +43 -28
- package/dist/commands/sign.js +9 -86
- package/dist/commands/use-finish.js +17 -0
- package/dist/commands/watch.js +0 -8
- package/dist/components/AuthLoginScreen.js +27 -12
- package/dist/scaffold/inquirer-stub.js +119 -0
- package/dist/scaffold/register.js +15 -0
- package/dist/shell/ConfigForm.js +174 -29
- package/dist/shell/Frame.js +4 -1
- package/dist/shell/Help.js +2 -1
- package/dist/shell/Settings.js +59 -6
- package/dist/shell/Shell.js +361 -43
- package/dist/shell/Tabs.js +8 -2
- package/dist/shell/actions.js +0 -0
- package/dist/utils/config.js +46 -3
- package/dist/utils/create-app.js +226 -0
- package/dist/utils/i18n.js +68 -13
- package/dist/utils/jsonc.js +2 -1
- package/dist/utils/keychain.js +44 -4
- package/dist/utils/oauth2-auth.js +35 -7
- package/dist/utils/password-prompt.js +23 -3
- package/dist/utils/process-runner.js +8 -3
- package/dist/utils/project-detection.js +172 -44
- package/dist/utils/session-cookie-auth.js +5 -4
- package/dist/utils/sitevision-api.js +21 -14
- package/dist/utils/sitevision-scripts-runner.js +32 -15
- package/dist/utils/tasks.js +132 -66
- package/dist/utils/version-check.js +3 -3
- package/dist/utils/webpack-runner.js +6 -5
- package/dist/utils/workspace.js +41 -3
- package/dist/utils/zip.js +18 -19
- package/package.json +24 -3
- package/readme.md +11 -4
- package/dist/app.d.ts +0 -6
- package/dist/app.js +0 -321
- package/dist/cli.d.ts +0 -2
- package/dist/commands/build.d.ts +0 -12
- package/dist/commands/deploy.d.ts +0 -17
- package/dist/commands/dev.d.ts +0 -14
- package/dist/commands/index.d.ts +0 -4
- package/dist/commands/info.d.ts +0 -2
- package/dist/commands/setup-signing.d.ts +0 -2
- package/dist/commands/sign.d.ts +0 -14
- package/dist/commands/types.d.ts +0 -18
- package/dist/commands/watch.d.ts +0 -2
- package/dist/components/AnimatedLogo.d.ts +0 -10
- package/dist/components/AuthLoginScreen.d.ts +0 -21
- package/dist/components/DevPropertiesForm.d.ts +0 -11
- package/dist/components/DevPropertiesForm.js +0 -246
- package/dist/components/InfoScreen.d.ts +0 -7
- package/dist/components/InfoScreen.js +0 -14
- package/dist/components/KeychainPasswordChoice.d.ts +0 -8
- package/dist/components/KeychainPasswordChoice.js +0 -30
- package/dist/components/MainMenu.d.ts +0 -7
- package/dist/components/MainMenu.js +0 -88
- package/dist/components/PasswordInput.d.ts +0 -10
- package/dist/components/ProcessOutput.d.ts +0 -6
- package/dist/components/ProcessOutput.js +0 -30
- package/dist/components/SetupFlow.d.ts +0 -8
- package/dist/components/SetupFlow.js +0 -233
- package/dist/components/SigningPropertiesForm.d.ts +0 -7
- package/dist/components/SigningPropertiesForm.js +0 -38
- package/dist/components/StatusIndicator.d.ts +0 -8
- package/dist/components/TextInput.d.ts +0 -10
- package/dist/components/TextInput.js +0 -29
- package/dist/components/WelcomeScreen.d.ts +0 -14
- package/dist/shell/AddonPicker.d.ts +0 -14
- package/dist/shell/Changelog.d.ts +0 -10
- package/dist/shell/CommandPalette.d.ts +0 -12
- package/dist/shell/ConfigForm.d.ts +0 -36
- package/dist/shell/Frame.d.ts +0 -59
- package/dist/shell/Help.d.ts +0 -9
- package/dist/shell/Popover.d.ts +0 -12
- package/dist/shell/Settings.d.ts +0 -6
- package/dist/shell/Shell.d.ts +0 -10
- package/dist/shell/Tabs.d.ts +0 -36
- package/dist/shell/actions.d.ts +0 -48
- package/dist/types/index.d.ts +0 -295
- package/dist/utils/branding.d.ts +0 -28
- package/dist/utils/config.d.ts +0 -27
- package/dist/utils/environments.d.ts +0 -20
- package/dist/utils/i18n.d.ts +0 -12
- package/dist/utils/jsonc.d.ts +0 -19
- package/dist/utils/keychain.d.ts +0 -15
- package/dist/utils/oauth2-auth.d.ts +0 -64
- package/dist/utils/password-prompt.d.ts +0 -14
- package/dist/utils/process-runner.d.ts +0 -31
- package/dist/utils/project-detection.d.ts +0 -202
- package/dist/utils/session-cookie-auth.d.ts +0 -35
- package/dist/utils/signing-password.d.ts +0 -12
- package/dist/utils/signing-step.d.ts +0 -15
- package/dist/utils/signing-step.js +0 -16
- package/dist/utils/sitevision-api.d.ts +0 -155
- package/dist/utils/sitevision-scripts-runner.d.ts +0 -84
- package/dist/utils/tasks.d.ts +0 -50
- package/dist/utils/version-check.d.ts +0 -9
- package/dist/utils/webpack-runner.d.ts +0 -76
- package/dist/utils/workspace.d.ts +0 -17
- package/dist/utils/zip.d.ts +0 -71
package/dist/commands/deploy.js
CHANGED
|
@@ -1,92 +1,81 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import
|
|
3
|
-
import { render, Box, Text, useInput } from 'ink';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { render, Box, Text, useApp, useInput, useStdin } from 'ink';
|
|
4
|
+
import { TaskScreen } from './TaskScreen.js';
|
|
5
|
+
import { useFinish } from './use-finish.js';
|
|
6
|
+
import { resolveDeployPasswordForCli } from './dev.js';
|
|
4
7
|
import { StatusIndicator } from '../components/StatusIndicator.js';
|
|
5
|
-
import { deployApp, deployProduction } from '../utils/sitevision-api.js';
|
|
6
|
-
import { getDeployZipPath, getSignedZipPath, getAppType, } from '../utils/project-detection.js';
|
|
7
|
-
import { zipExists } from '../utils/zip.js';
|
|
8
|
-
import { promptPassword, promptYesNo } from '../utils/password-prompt.js';
|
|
9
|
-
import { setDeployPassword, deleteSessionCookie, deleteOAuth2RefreshToken, } from '../utils/keychain.js';
|
|
10
|
-
import { resolveOAuth2AccessToken } from '../utils/oauth2-auth.js';
|
|
11
8
|
import { AuthLoginScreen } from '../components/AuthLoginScreen.js';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
9
|
+
import { deleteSessionCookie, deleteOAuth2RefreshToken, } from '../utils/keychain.js';
|
|
10
|
+
import { resolveOAuth2AccessToken } from '../utils/oauth2-auth.js';
|
|
11
|
+
import { startDeploy, useTasks } from '../utils/tasks.js';
|
|
12
|
+
import { toDeployConfig } from '../utils/workspace.js';
|
|
13
|
+
/** Standalone `svc deploy`: log in if needed, then run the shell's deploy task. */
|
|
14
|
+
export function DeployScreen({ project, force, production, activate, }) {
|
|
15
|
+
const devProperties = project.devProperties;
|
|
16
|
+
const { exit } = useApp();
|
|
17
|
+
// Undefined, not false, on a pipe; and useInput reads undefined as active.
|
|
18
|
+
const interactive = Boolean(useStdin().isRawModeSupported);
|
|
19
|
+
// 'init' resolves cached credentials, 'login' shows the login screen,
|
|
20
|
+
// 'deploy' starts the task.
|
|
21
|
+
const [phase, setPhase] = useState('init');
|
|
22
|
+
const [credential, setCredential] = useState({
|
|
22
23
|
accessToken: devProperties.accessToken,
|
|
23
24
|
sessionCookie: devProperties.sessionCookie,
|
|
24
25
|
});
|
|
25
|
-
const
|
|
26
|
+
const [task, setTask] = useState();
|
|
27
|
+
// Anything that goes wrong before there is a task to show it.
|
|
28
|
+
const [failure, setFailure] = useState();
|
|
26
29
|
const authMethod = devProperties.authMethod ?? 'basic';
|
|
27
|
-
// OAuth2 and cookie can re-authenticate in
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
|
|
30
|
+
// OAuth2 and cookie can re-authenticate in place, given a terminal to do it in.
|
|
31
|
+
const canRelogin = interactive && (authMethod === 'oauth2' || authMethod === 'cookie');
|
|
32
|
+
const live = useTasks().find(t => t.id === task?.id) ?? task;
|
|
33
|
+
const failed = Boolean(failure) || live?.status === 'error';
|
|
34
|
+
useFinish(failure && !task ? 'error' : undefined, canRelogin);
|
|
35
|
+
// A browser login needs a terminal; without one only env credentials work.
|
|
36
|
+
const startLogin = () => {
|
|
37
|
+
if (interactive) {
|
|
38
|
+
setPhase('login');
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
setFailure('No stored login and no terminal to log in from. Set SITEVISION_ACCESS_TOKEN or SITEVISION_SESSION_COOKIE.');
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
// Drop the stored credential and log in again: the usual fix for an expired
|
|
45
|
+
// session or token, which Sitevision reports as a 400 rather than a 401.
|
|
34
46
|
const retryWithFreshLogin = () => {
|
|
35
47
|
const { domain, username } = devProperties;
|
|
36
|
-
if (authMethod === 'cookie'
|
|
48
|
+
if (authMethod === 'cookie') {
|
|
37
49
|
deleteSessionCookie(domain, username);
|
|
38
|
-
devProperties.sessionCookie = undefined;
|
|
39
50
|
}
|
|
40
|
-
else if (
|
|
41
|
-
domain &&
|
|
42
|
-
devProperties.oauth2?.clientId) {
|
|
51
|
+
else if (devProperties.oauth2?.clientId) {
|
|
43
52
|
deleteOAuth2RefreshToken(domain, devProperties.oauth2.clientId);
|
|
44
|
-
devProperties.accessToken = undefined;
|
|
45
53
|
}
|
|
46
54
|
setCredential({});
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
status: 'deploying',
|
|
50
|
-
message: production
|
|
51
|
-
? 'Deploying to production...'
|
|
52
|
-
: 'Deploying to dev...',
|
|
53
|
-
});
|
|
55
|
+
setFailure(undefined);
|
|
56
|
+
setTask(undefined);
|
|
54
57
|
setPhase('login');
|
|
55
58
|
};
|
|
56
59
|
useInput((input, key) => {
|
|
57
|
-
if (
|
|
58
|
-
if (onBack && (key.escape || input === 'q')) {
|
|
59
|
-
onBack();
|
|
60
|
-
}
|
|
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();
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
// Decide once whether we can deploy straight away or must log in first.
|
|
75
|
-
React.useEffect(() => {
|
|
76
|
-
if (authMethod === 'basic' || devProperties.sessionCookie) {
|
|
77
|
-
setPhase('deploy');
|
|
60
|
+
if (!failed)
|
|
78
61
|
return;
|
|
62
|
+
if (input === 'r')
|
|
63
|
+
retryWithFreshLogin();
|
|
64
|
+
if (key.escape || input === 'q')
|
|
65
|
+
exit();
|
|
66
|
+
}, { isActive: canRelogin });
|
|
67
|
+
// Decide once whether to deploy straight away or log in first.
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (authMethod === 'basic' || credential.sessionCookie) {
|
|
70
|
+
setPhase('deploy');
|
|
79
71
|
}
|
|
80
|
-
if (authMethod === 'cookie') {
|
|
81
|
-
|
|
82
|
-
setPhase('login');
|
|
83
|
-
return;
|
|
72
|
+
else if (authMethod === 'cookie') {
|
|
73
|
+
startLogin();
|
|
84
74
|
}
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
75
|
+
else if (credential.accessToken) {
|
|
76
|
+
setPhase('deploy');
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
90
79
|
void (async () => {
|
|
91
80
|
const token = await resolveOAuth2AccessToken(devProperties);
|
|
92
81
|
if (token) {
|
|
@@ -94,194 +83,52 @@ export function DeployScreen({ projectRoot, manifest, devProperties, force, prod
|
|
|
94
83
|
setPhase('deploy');
|
|
95
84
|
}
|
|
96
85
|
else {
|
|
97
|
-
|
|
86
|
+
startLogin();
|
|
98
87
|
}
|
|
99
88
|
})();
|
|
100
|
-
return;
|
|
101
89
|
}
|
|
102
|
-
setPhase('deploy');
|
|
103
90
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
104
91
|
}, []);
|
|
105
|
-
|
|
106
|
-
if (phase !== 'deploy' ||
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (phase !== 'deploy' || task)
|
|
94
|
+
return;
|
|
95
|
+
const complete = toDeployConfig({ ...devProperties, ...credential });
|
|
96
|
+
if ('error' in complete) {
|
|
97
|
+
setFailure(complete.error);
|
|
107
98
|
return;
|
|
108
|
-
deployStartedRef.current = true;
|
|
109
|
-
async function runDeploy() {
|
|
110
|
-
try {
|
|
111
|
-
const appType = getAppType(manifest);
|
|
112
|
-
// Credential resolved in the init effect / login screen.
|
|
113
|
-
const { accessToken, sessionCookie } = credential;
|
|
114
|
-
// A stale session fails without a clean 401 — clear the stored cookie
|
|
115
|
-
// so the next run re-authenticates. Skip when SITEVISION_SESSION_COOKIE
|
|
116
|
-
// is set: detection re-reads it first, so clearing would just replay
|
|
117
|
-
// the same dead cookie in a loop.
|
|
118
|
-
const clearStaleCookie = (result) => {
|
|
119
|
-
if (result.authExpired &&
|
|
120
|
-
authMethod === 'cookie' &&
|
|
121
|
-
!process.env['SITEVISION_SESSION_COOKIE'] &&
|
|
122
|
-
devProperties.domain &&
|
|
123
|
-
devProperties.username) {
|
|
124
|
-
deleteSessionCookie(devProperties.domain, devProperties.username);
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
if (production) {
|
|
128
|
-
// Production deployment requires a signed zip
|
|
129
|
-
const signedZipPath = getSignedZipPath(projectRoot, manifest);
|
|
130
|
-
if (!zipExists(signedZipPath)) {
|
|
131
|
-
setState({
|
|
132
|
-
status: 'error',
|
|
133
|
-
error: `Signed zip not found: ${signedZipPath}\nRun 'sign' first to create the signed zip.`,
|
|
134
|
-
});
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
const config = {
|
|
138
|
-
domain: devProperties.domain,
|
|
139
|
-
siteName: devProperties.siteName,
|
|
140
|
-
addonName: devProperties.addonName,
|
|
141
|
-
username: devProperties.username,
|
|
142
|
-
password: devProperties.password,
|
|
143
|
-
accessToken,
|
|
144
|
-
sessionCookie,
|
|
145
|
-
useHTTP: devProperties.useHTTPForDevDeploy,
|
|
146
|
-
activate,
|
|
147
|
-
};
|
|
148
|
-
const result = await deployProduction(signedZipPath, config, appType);
|
|
149
|
-
if (!result.success) {
|
|
150
|
-
clearStaleCookie(result);
|
|
151
|
-
setState({
|
|
152
|
-
status: 'error',
|
|
153
|
-
error: result.error || 'Deployment failed',
|
|
154
|
-
});
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
setState({
|
|
158
|
-
status: 'success',
|
|
159
|
-
message: result.message || 'Deployed to production successfully',
|
|
160
|
-
executableId: result.executableId,
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
const zipPath = getDeployZipPath(projectRoot, manifest);
|
|
165
|
-
if (!zipExists(zipPath)) {
|
|
166
|
-
setState({
|
|
167
|
-
status: 'error',
|
|
168
|
-
error: `Zip not found: ${zipPath}\nRun 'build' first to create the zip.`,
|
|
169
|
-
});
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
const config = {
|
|
173
|
-
domain: devProperties.domain,
|
|
174
|
-
siteName: devProperties.siteName,
|
|
175
|
-
addonName: devProperties.addonName,
|
|
176
|
-
username: devProperties.username,
|
|
177
|
-
password: devProperties.password,
|
|
178
|
-
accessToken,
|
|
179
|
-
sessionCookie,
|
|
180
|
-
useHTTP: devProperties.useHTTPForDevDeploy,
|
|
181
|
-
};
|
|
182
|
-
const result = await deployApp(zipPath, config, appType, force);
|
|
183
|
-
if (!result.success) {
|
|
184
|
-
clearStaleCookie(result);
|
|
185
|
-
setState({
|
|
186
|
-
status: 'error',
|
|
187
|
-
error: result.error || 'Deployment failed',
|
|
188
|
-
});
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
setState({
|
|
192
|
-
status: 'success',
|
|
193
|
-
message: 'Deployed to dev successfully',
|
|
194
|
-
executableId: result.executableId,
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
catch (error) {
|
|
199
|
-
setState({
|
|
200
|
-
status: 'error',
|
|
201
|
-
error: error instanceof Error ? error.message : String(error),
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
99
|
}
|
|
205
|
-
|
|
100
|
+
setTask(startDeploy(project, complete.config, { force, production, activate }));
|
|
206
101
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
207
|
-
}, [phase]);
|
|
208
|
-
if (phase === 'login' &&
|
|
209
|
-
return (_jsx(AuthLoginScreen, { method:
|
|
210
|
-
|
|
211
|
-
: 'oauth2', devProperties: devProperties, onComplete: cred => {
|
|
212
|
-
setCredential(cred);
|
|
102
|
+
}, [phase, task]);
|
|
103
|
+
if (phase === 'login' && !failure) {
|
|
104
|
+
return (_jsx(AuthLoginScreen, { method: authMethod === 'cookie' ? 'cookie' : 'oauth2', devProperties: devProperties, onComplete: next => {
|
|
105
|
+
setCredential(next);
|
|
213
106
|
setPhase('deploy');
|
|
214
|
-
}, onError:
|
|
215
|
-
|
|
216
|
-
}, onCancel: () => {
|
|
217
|
-
if (onBack) {
|
|
218
|
-
onBack();
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
setState({ status: 'error', error: 'Login cancelled.' });
|
|
222
|
-
}
|
|
107
|
+
}, onError: setFailure, onCancel: () => {
|
|
108
|
+
setFailure('Login cancelled.');
|
|
223
109
|
} }));
|
|
224
110
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
111
|
+
const retryHint = failed && canRelogin && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "yellow", children: "This can happen when your session or token has expired." }), _jsx(Text, { dimColor: true, children: "Press r to log in again with fresh credentials, q to quit" })] }));
|
|
112
|
+
if (task) {
|
|
113
|
+
return (_jsx(TaskScreen, { task: task, stay: canRelogin, children: retryHint }));
|
|
114
|
+
}
|
|
115
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(StatusIndicator, { status: failure ? 'error' : 'running', label: failure ? 'Failed' : 'Preparing', message: failure }), retryHint] }));
|
|
230
116
|
}
|
|
231
117
|
export const deployCommand = {
|
|
232
118
|
name: 'deploy',
|
|
233
119
|
description: 'Deploy the application',
|
|
234
120
|
requiresProject: true,
|
|
235
|
-
flags: {
|
|
236
|
-
force: {
|
|
237
|
-
type: 'boolean',
|
|
238
|
-
description: 'Force deployment (overwrite existing)',
|
|
239
|
-
alias: 'f',
|
|
240
|
-
default: false,
|
|
241
|
-
},
|
|
242
|
-
production: {
|
|
243
|
-
type: 'boolean',
|
|
244
|
-
description: 'Deploy to production (requires signed app)',
|
|
245
|
-
alias: 'p',
|
|
246
|
-
default: false,
|
|
247
|
-
},
|
|
248
|
-
activate: {
|
|
249
|
-
type: 'boolean',
|
|
250
|
-
description: 'Activate the app after production deployment',
|
|
251
|
-
alias: 'a',
|
|
252
|
-
default: false,
|
|
253
|
-
},
|
|
254
|
-
},
|
|
255
121
|
async execute({ project, flags }) {
|
|
256
|
-
|
|
257
|
-
if (
|
|
258
|
-
console.log(
|
|
259
|
-
|
|
122
|
+
const complete = toDeployConfig(project.devProperties);
|
|
123
|
+
if ('error' in complete) {
|
|
124
|
+
console.log(`\n\x1b[33m${complete.error}\x1b[0m\n`);
|
|
125
|
+
process.exitCode = 1;
|
|
260
126
|
return;
|
|
261
127
|
}
|
|
262
|
-
//
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
const authMethod = project.devProperties.authMethod ?? 'basic';
|
|
266
|
-
if (authMethod === 'basic' && !project.devProperties.password) {
|
|
267
|
-
const { domain, username } = project.devProperties;
|
|
268
|
-
console.log('');
|
|
269
|
-
const password = await promptPassword(`Deploy password for ${username}@${domain}: `);
|
|
270
|
-
if (!password) {
|
|
271
|
-
console.log('\x1b[31mError: Password is required\x1b[0m');
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
const remember = await promptYesNo('Save password to OS keychain? (y/N): ');
|
|
275
|
-
if (remember && domain && username) {
|
|
276
|
-
setDeployPassword(domain, username, password);
|
|
277
|
-
}
|
|
278
|
-
project.devProperties.password = password;
|
|
279
|
-
}
|
|
280
|
-
const production = Boolean(flags['production']);
|
|
281
|
-
const force = Boolean(flags['force']);
|
|
282
|
-
const activate = Boolean(flags['activate']);
|
|
128
|
+
// OAuth2 and cookie log in inside DeployScreen; basic asks here.
|
|
129
|
+
if (!(await resolveDeployPasswordForCli(project.devProperties)))
|
|
130
|
+
return;
|
|
283
131
|
// Production deploys use the already-signed zip; `sign` is run separately.
|
|
284
|
-
|
|
285
|
-
await waitUntilExit();
|
|
132
|
+
await render(_jsx(DeployScreen, { project: project, force: Boolean(flags['force']), production: Boolean(flags['production']), activate: Boolean(flags['activate']) })).waitUntilExit();
|
|
286
133
|
},
|
|
287
134
|
};
|
package/dist/commands/dev.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { render, Box, Text, useApp, useInput, useStdout } from 'ink';
|
|
3
|
+
import { render, Box, Text, useApp, useInput, useStdin, useStdout } from 'ink';
|
|
4
4
|
import { StatusIndicator } from '../components/StatusIndicator.js';
|
|
5
5
|
import { promptPassword, promptYesNo } from '../utils/password-prompt.js';
|
|
6
6
|
import { setDeployPassword } from '../utils/keychain.js';
|
|
7
7
|
import { resolveSigningPassword } from '../utils/signing-password.js';
|
|
8
8
|
import { startDev, useTasks } from '../utils/tasks.js';
|
|
9
|
+
import { toDeployConfig } from '../utils/workspace.js';
|
|
9
10
|
import { Log } from '../shell/Tabs.js';
|
|
10
11
|
/** Standalone `svc dev` / `svc watch`: one task, its log, Ctrl+C or q to stop. */
|
|
11
12
|
export function DevScreen({ project, options }) {
|
|
@@ -15,12 +16,15 @@ export function DevScreen({ project, options }) {
|
|
|
15
16
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
16
17
|
const task = React.useMemo(() => startDev(project, options), []);
|
|
17
18
|
const live = tasks.find(t => t.id === task.id) ?? task;
|
|
19
|
+
const { isRawModeSupported } = useStdin();
|
|
18
20
|
useInput((input, key) => {
|
|
19
21
|
if (key.escape || input === 'q') {
|
|
20
22
|
live.stop();
|
|
21
23
|
exit();
|
|
22
24
|
}
|
|
23
|
-
}
|
|
25
|
+
},
|
|
26
|
+
// Undefined, not false, on a pipe; and useInput reads undefined as active.
|
|
27
|
+
{ isActive: Boolean(isRawModeSupported) });
|
|
24
28
|
const status = live.status === 'running'
|
|
25
29
|
? live.phase === 'error'
|
|
26
30
|
? 'error'
|
|
@@ -36,12 +40,14 @@ export async function resolveSigningForCli(project) {
|
|
|
36
40
|
!project.devProperties?.signingUsername) {
|
|
37
41
|
console.log('\n\x1b[33mSigning credentials not configured.\x1b[0m');
|
|
38
42
|
console.log('Run \x1b[36msetup-signing\x1b[0m to configure credentials.\n');
|
|
43
|
+
process.exitCode = 1;
|
|
39
44
|
return undefined;
|
|
40
45
|
}
|
|
41
46
|
const signingUsername = project.devProperties.signingUsername;
|
|
42
47
|
const password = await resolveSigningPassword(signingUsername);
|
|
43
48
|
if (!password) {
|
|
44
49
|
console.log('\x1b[31mError: Password is required for signed mode\x1b[0m');
|
|
50
|
+
process.exitCode = 1;
|
|
45
51
|
return undefined;
|
|
46
52
|
}
|
|
47
53
|
return {
|
|
@@ -50,23 +56,34 @@ export async function resolveSigningForCli(project) {
|
|
|
50
56
|
certificateName: project.devProperties.certificateName,
|
|
51
57
|
};
|
|
52
58
|
}
|
|
59
|
+
/** Basic auth without a stored password: ask for it. False when there is none. */
|
|
60
|
+
export async function resolveDeployPasswordForCli(dev) {
|
|
61
|
+
if ((dev.authMethod ?? 'basic') !== 'basic' || dev.password)
|
|
62
|
+
return true;
|
|
63
|
+
const { domain, username } = dev;
|
|
64
|
+
console.log('');
|
|
65
|
+
const password = await promptPassword(`Deploy password for ${username}@${domain}: `);
|
|
66
|
+
if (!password) {
|
|
67
|
+
console.log('\x1b[31mError: Password is required\x1b[0m');
|
|
68
|
+
process.exitCode = 1;
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
if (await promptYesNo('Save password to OS keychain? (y/N): ')) {
|
|
72
|
+
setDeployPassword(domain, username, password);
|
|
73
|
+
}
|
|
74
|
+
dev.password = password;
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
53
77
|
export const devCommand = {
|
|
54
78
|
name: 'dev',
|
|
55
79
|
description: 'Start development server with watch mode',
|
|
56
80
|
requiresProject: true,
|
|
57
|
-
flags: {
|
|
58
|
-
signed: {
|
|
59
|
-
type: 'boolean',
|
|
60
|
-
description: 'Use signed mode (sign before each deploy)',
|
|
61
|
-
alias: 's',
|
|
62
|
-
default: false,
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
81
|
async execute({ project, flags }) {
|
|
66
82
|
const dev = project.devProperties;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
console.log('
|
|
83
|
+
const incomplete = toDeployConfig(dev);
|
|
84
|
+
if (!dev || 'error' in incomplete) {
|
|
85
|
+
console.log(`\n\x1b[33m${'error' in incomplete ? incomplete.error : ''}\x1b[0m\n`);
|
|
86
|
+
process.exitCode = 1;
|
|
70
87
|
return;
|
|
71
88
|
}
|
|
72
89
|
// The standalone command only prompts for a basic password; OAuth2/cookie
|
|
@@ -75,22 +92,11 @@ export const devCommand = {
|
|
|
75
92
|
!dev.accessToken &&
|
|
76
93
|
!dev.sessionCookie) {
|
|
77
94
|
console.log('\n\x1b[33mNo token/cookie available. Run `svc` and use Dev from the shell, or set SITEVISION_ACCESS_TOKEN / SITEVISION_SESSION_COOKIE.\x1b[0m\n');
|
|
95
|
+
process.exitCode = 1;
|
|
78
96
|
return;
|
|
79
97
|
}
|
|
80
|
-
if ((
|
|
81
|
-
|
|
82
|
-
console.log('');
|
|
83
|
-
const pw = await promptPassword(`Deploy password for ${username}@${domain}: `);
|
|
84
|
-
if (!pw) {
|
|
85
|
-
console.log('\x1b[31mError: Password is required\x1b[0m');
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
const remember = await promptYesNo('Save password to OS keychain? (y/N): ');
|
|
89
|
-
if (remember && domain && username) {
|
|
90
|
-
setDeployPassword(domain, username, pw);
|
|
91
|
-
}
|
|
92
|
-
dev.password = pw;
|
|
93
|
-
}
|
|
98
|
+
if (!(await resolveDeployPasswordForCli(dev)))
|
|
99
|
+
return;
|
|
94
100
|
let signingCredentials;
|
|
95
101
|
if (flags['signed']) {
|
|
96
102
|
signingCredentials = await resolveSigningForCli(project);
|
|
@@ -100,16 +106,7 @@ export const devCommand = {
|
|
|
100
106
|
const { waitUntilExit } = render(_jsx(DevScreen, { project: project, options: {
|
|
101
107
|
deploy: true,
|
|
102
108
|
signingCredentials,
|
|
103
|
-
deployConfig: {
|
|
104
|
-
domain: dev.domain,
|
|
105
|
-
siteName: dev.siteName,
|
|
106
|
-
addonName: dev.addonName,
|
|
107
|
-
username: dev.username,
|
|
108
|
-
password: dev.password,
|
|
109
|
-
accessToken: dev.accessToken,
|
|
110
|
-
sessionCookie: dev.sessionCookie,
|
|
111
|
-
useHTTP: dev.useHTTPForDevDeploy,
|
|
112
|
-
},
|
|
109
|
+
deployConfig: { ...incomplete.config, password: dev.password },
|
|
113
110
|
} }));
|
|
114
111
|
await waitUntilExit();
|
|
115
112
|
},
|
package/dist/commands/info.js
CHANGED
|
@@ -4,7 +4,7 @@ import { Box, Text } from 'ink';
|
|
|
4
4
|
import { getAppType, localizedText } from '../utils/project-detection.js';
|
|
5
5
|
function InfoScreen({ project }) {
|
|
6
6
|
const appType = getAppType(project.manifest);
|
|
7
|
-
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Sitevision Project Information" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Name: " }), _jsx(Text, { children: localizedText(project.manifest.name) })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "ID: " }), _jsx(Text, { children: project.manifest.id })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Version: " }), _jsx(Text, { children: project.manifest.version })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Type: " }), _jsx(Text, { color: "green", children: project.manifest.type }), _jsxs(Text, { dimColor: true, children: [" (", appType, ")"] })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Bundled: " }), _jsx(Text, { children: project.manifest.bundled ? 'Yes' : 'No' })] })] }), project.hasDevProperties && project.devProperties && (_jsxs(_Fragment, { children: [_jsx(Box, { marginTop: 1, marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Development Configuration" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Domain: " }), _jsx(Text, { children: project.devProperties.domain })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Site: " }), _jsx(Text, { children: project.devProperties.siteName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Addon: " }), _jsx(Text, { children: project.devProperties.addonName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Username: " }), _jsx(Text, { children: project.devProperties.username })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Use HTTP: " }), _jsx(Text, { children: project.devProperties.useHTTPForDevDeploy ? 'Yes' : 'No' })] })] })] })), !project.hasDevProperties && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: ["\u26A0 No dev properties found. Run", ' ', _jsx(Text, { bold: true, children: "
|
|
7
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Sitevision Project Information" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Name: " }), _jsx(Text, { children: localizedText(project.manifest.name) })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "ID: " }), _jsx(Text, { children: project.manifest.id })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Version: " }), _jsx(Text, { children: project.manifest.version })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Type: " }), _jsx(Text, { color: "green", children: project.manifest.type }), _jsxs(Text, { dimColor: true, children: [" (", appType, ")"] })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Bundled: " }), _jsx(Text, { children: project.manifest.bundled ? 'Yes' : 'No' })] })] }), project.hasDevProperties && project.devProperties && (_jsxs(_Fragment, { children: [_jsx(Box, { marginTop: 1, marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Development Configuration" }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Domain: " }), _jsx(Text, { children: project.devProperties.domain })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Site: " }), _jsx(Text, { children: project.devProperties.siteName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Addon: " }), _jsx(Text, { children: project.devProperties.addonName })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Username: " }), _jsx(Text, { children: project.devProperties.username })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Use HTTP: " }), _jsx(Text, { children: project.devProperties.useHTTPForDevDeploy ? 'Yes' : 'No' })] })] })] })), !project.hasDevProperties && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: ["\u26A0 No dev properties found. Run ", _jsx(Text, { bold: true, children: "svc" }), " and press", ' ', _jsx(Text, { bold: true, children: "e" }), " to configure."] }) })), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { bold: true, children: "Project Root: " }), _jsx(Text, { dimColor: true, children: project.root })] })] }));
|
|
8
8
|
}
|
|
9
9
|
export const infoCommand = {
|
|
10
10
|
name: 'info',
|