sitevision-cli 0.3.1-beta.2 → 0.4.0-beta.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.
Files changed (48) hide show
  1. package/dist/app.d.ts +1 -2
  2. package/dist/app.js +19 -14
  3. package/dist/cli.js +48 -24
  4. package/dist/commands/build.d.ts +1 -1
  5. package/dist/commands/build.js +8 -32
  6. package/dist/commands/deploy.js +19 -20
  7. package/dist/commands/dev.js +12 -32
  8. package/dist/commands/index.js +1 -1
  9. package/dist/commands/info.js +3 -53
  10. package/dist/commands/setup-signing.js +2 -2
  11. package/dist/commands/sign.d.ts +1 -1
  12. package/dist/commands/sign.js +14 -20
  13. package/dist/components/DevPropertiesForm.d.ts +1 -2
  14. package/dist/components/DevPropertiesForm.js +15 -30
  15. package/dist/components/InfoScreen.d.ts +1 -2
  16. package/dist/components/InfoScreen.js +2 -50
  17. package/dist/components/MainMenu.d.ts +1 -2
  18. package/dist/components/MainMenu.js +5 -70
  19. package/dist/components/PasswordInput.d.ts +1 -2
  20. package/dist/components/PasswordInput.js +7 -19
  21. package/dist/components/ProcessOutput.d.ts +1 -2
  22. package/dist/components/ProcessOutput.js +3 -5
  23. package/dist/components/SetupFlow.d.ts +1 -2
  24. package/dist/components/SetupFlow.js +12 -87
  25. package/dist/components/SigningPropertiesForm.d.ts +1 -2
  26. package/dist/components/SigningPropertiesForm.js +7 -18
  27. package/dist/components/StatusIndicator.d.ts +1 -2
  28. package/dist/components/StatusIndicator.js +6 -12
  29. package/dist/components/TextInput.d.ts +1 -2
  30. package/dist/components/TextInput.js +5 -13
  31. package/dist/components/WelcomeScreen.d.ts +14 -0
  32. package/dist/components/WelcomeScreen.js +53 -0
  33. package/dist/utils/branding.d.ts +12 -0
  34. package/dist/utils/branding.js +29 -0
  35. package/dist/utils/config.d.ts +17 -0
  36. package/dist/utils/config.js +57 -0
  37. package/dist/utils/password-prompt.js +2 -2
  38. package/dist/utils/process-runner.d.ts +6 -6
  39. package/dist/utils/process-runner.js +12 -42
  40. package/dist/utils/project-detection.d.ts +1 -1
  41. package/dist/utils/project-detection.js +7 -3
  42. package/dist/utils/sitevision-api.js +1 -1
  43. package/dist/utils/version-check.js +3 -3
  44. package/dist/utils/webpack-runner.d.ts +2 -2
  45. package/dist/utils/webpack-runner.js +15 -42
  46. package/dist/utils/zip.js +5 -7
  47. package/package.json +23 -30
  48. package/readme.md +11 -7
@@ -1,12 +1,13 @@
1
- import React, { useState } from 'react';
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
2
3
  import { Box, Text } from 'ink';
3
4
  import { TextInput } from './TextInput.js';
4
- import { writeDevProperties, readDevProperties } from '../utils/project-detection.js';
5
+ import { writeDevProperties, readDevProperties, } from '../utils/project-detection.js';
5
6
  const STEPS = [
6
7
  { id: 'username', label: 'Signing Username' },
7
8
  { id: 'certificate', label: 'Certificate Name' },
8
9
  ];
9
- export function SigningPropertiesForm({ projectRoot, onComplete, onCancel }) {
10
+ export function SigningPropertiesForm({ projectRoot, onComplete, onCancel, }) {
10
11
  const [stepIndex, setStepIndex] = useState(0);
11
12
  // Read existing properties to preserve other fields
12
13
  const [properties, setProperties] = useState(() => readDevProperties(projectRoot) || {});
@@ -26,24 +27,12 @@ export function SigningPropertiesForm({ projectRoot, onComplete, onCancel }) {
26
27
  const renderInput = () => {
27
28
  switch (currentStep?.id) {
28
29
  case 'username':
29
- return (React.createElement(TextInput, { key: "username", label: "Signing Username (developer.sitevision.se)", defaultValue: properties.signingUsername, onSubmit: (value) => handleNext('signingUsername', value), onCancel: onCancel }));
30
+ return (_jsx(TextInput, { label: "Signing Username (developer.sitevision.se)", defaultValue: properties.signingUsername, onSubmit: (value) => handleNext('signingUsername', value), onCancel: onCancel }, "username"));
30
31
  case 'certificate':
31
- return (React.createElement(TextInput, { key: "certificate", label: "Certificate Name (Optional)", defaultValue: properties.certificateName, placeholder: "Leave empty for default", onSubmit: (value) => handleNext('certificateName', value), onCancel: onCancel }));
32
+ return (_jsx(TextInput, { label: "Certificate Name (Optional)", defaultValue: properties.certificateName, placeholder: "Leave empty for default", onSubmit: (value) => handleNext('certificateName', value), onCancel: onCancel }, "certificate"));
32
33
  default:
33
34
  return null;
34
35
  }
35
36
  };
36
- return (React.createElement(Box, { flexDirection: "column", padding: 1 },
37
- React.createElement(Box, { marginBottom: 1 },
38
- React.createElement(Text, { bold: true, color: "cyan" }, "Setup Signing Properties"),
39
- React.createElement(Text, null,
40
- " Step ",
41
- stepIndex + 1,
42
- " of ",
43
- STEPS.length,
44
- ": ",
45
- currentStep?.label)),
46
- React.createElement(Box, { marginBottom: 1 }, STEPS.map((s, i) => (React.createElement(Box, { key: s.id, marginRight: 1 },
47
- React.createElement(Text, { color: i === stepIndex ? 'green' : i < stepIndex ? 'green' : 'gray' }, i < stepIndex ? '✓' : i === stepIndex ? '●' : '○'))))),
48
- React.createElement(Box, { borderStyle: "single", borderColor: "gray", padding: 1 }, renderInput())));
37
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "Setup Signing Properties" }), _jsxs(Text, { children: [' ', "Step ", stepIndex + 1, " of ", STEPS.length, ": ", currentStep?.label] })] }), _jsx(Box, { marginBottom: 1, children: STEPS.map((s, i) => (_jsx(Box, { marginRight: 1, children: _jsx(Text, { color: i === stepIndex ? 'green' : i < stepIndex ? 'green' : 'gray', children: i < stepIndex ? '✓' : i === stepIndex ? '●' : '○' }) }, s.id))) }), _jsx(Box, { borderStyle: "single", borderColor: "gray", padding: 1, children: renderInput() })] }));
49
38
  }
@@ -1,9 +1,8 @@
1
- import React from 'react';
2
1
  export type Status = 'pending' | 'running' | 'success' | 'error';
3
2
  interface Props {
4
3
  status: Status;
5
4
  label: string;
6
5
  message?: string;
7
6
  }
8
- export declare function StatusIndicator({ status, label, message }: Props): React.JSX.Element;
7
+ export declare function StatusIndicator({ status, label, message }: Props): import("react").JSX.Element;
9
8
  export {};
@@ -1,18 +1,17 @@
1
- import React from 'react';
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text } from 'ink';
3
3
  import Spinner from 'ink-spinner';
4
4
  export function StatusIndicator({ status, label, message }) {
5
5
  const getIcon = () => {
6
6
  switch (status) {
7
7
  case 'pending':
8
- return React.createElement(Text, { dimColor: true }, "\u25CB");
8
+ return _jsx(Text, { dimColor: true, children: "\u25CB" });
9
9
  case 'running':
10
- return (React.createElement(Text, { color: "cyan" },
11
- React.createElement(Spinner, { type: "dots" })));
10
+ return (_jsx(Text, { color: "cyan", children: _jsx(Spinner, { type: "dots" }) }));
12
11
  case 'success':
13
- return React.createElement(Text, { color: "green" }, "\u2713");
12
+ return _jsx(Text, { color: "green", children: "\u2713" });
14
13
  case 'error':
15
- return React.createElement(Text, { color: "red" }, "\u2717");
14
+ return _jsx(Text, { color: "red", children: "\u2717" });
16
15
  }
17
16
  };
18
17
  const getColor = () => {
@@ -27,10 +26,5 @@ export function StatusIndicator({ status, label, message }) {
27
26
  return 'red';
28
27
  }
29
28
  };
30
- return (React.createElement(Box, null,
31
- getIcon(),
32
- React.createElement(Box, { marginLeft: 1 },
33
- React.createElement(Text, { color: getColor(), bold: true }, label)),
34
- message && (React.createElement(Box, { marginLeft: 1 },
35
- React.createElement(Text, { dimColor: true }, message)))));
29
+ return (_jsxs(Box, { children: [getIcon(), _jsx(Box, { marginLeft: 1, children: _jsx(Text, { color: getColor(), bold: true, children: label }) }), message && (_jsx(Box, { marginLeft: 1, children: _jsx(Text, { dimColor: true, children: message }) }))] }));
36
30
  }
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  interface Props {
3
2
  label: string;
4
3
  defaultValue?: string;
@@ -7,5 +6,5 @@ interface Props {
7
6
  onCancel?: () => void;
8
7
  type?: 'text' | 'password';
9
8
  }
10
- export declare function TextInput({ label, defaultValue, placeholder, onSubmit, onCancel, type, }: Props): React.JSX.Element;
9
+ export declare function TextInput({ label, defaultValue, placeholder, onSubmit, onCancel, type, }: Props): import("react").JSX.Element;
11
10
  export {};
@@ -1,4 +1,5 @@
1
- import React, { useState } from 'react';
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
2
3
  import { Box, Text, useInput } from 'ink';
3
4
  export function TextInput({ label, defaultValue = '', placeholder, onSubmit, onCancel, type = 'text', }) {
4
5
  const [value, setValue] = useState(defaultValue);
@@ -17,21 +18,12 @@ export function TextInput({ label, defaultValue = '', placeholder, onSubmit, onC
17
18
  return;
18
19
  }
19
20
  if (key.delete || key.backspace) {
20
- setValue((prev) => prev.slice(0, -1));
21
+ setValue(prev => prev.slice(0, -1));
21
22
  return;
22
23
  }
23
24
  if (!key.ctrl && !key.meta) {
24
- setValue((prev) => prev + input);
25
+ setValue(prev => prev + input);
25
26
  }
26
27
  });
27
- return (React.createElement(Box, { flexDirection: "column", padding: 1 },
28
- React.createElement(Box, { marginBottom: 1 },
29
- React.createElement(Text, { bold: true, color: "cyan" }, label)),
30
- React.createElement(Box, { borderStyle: "round", borderColor: "cyan", paddingX: 1 },
31
- React.createElement(Text, null, type === 'password' ? '*'.repeat(value.length) : value),
32
- value === '' && placeholder && (React.createElement(Text, { dimColor: true }, placeholder))),
33
- React.createElement(Box, { marginTop: 1 },
34
- React.createElement(Text, { dimColor: true },
35
- "Press Enter to submit",
36
- onCancel ? ', Esc to cancel' : ''))));
28
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: label }) }), _jsxs(Box, { borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [_jsx(Text, { children: type === 'password' ? '*'.repeat(value.length) : value }), value === '' && placeholder && _jsx(Text, { dimColor: true, children: placeholder })] }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["Press Enter to submit", onCancel ? ', Esc to cancel' : ''] }) })] }));
37
29
  }
@@ -0,0 +1,14 @@
1
+ import { type ProjectInfo } from '../utils/project-detection.js';
2
+ interface Props {
3
+ project: ProjectInfo;
4
+ onComplete: () => void;
5
+ }
6
+ /**
7
+ * First-run welcome screen. Shows the branding once and, when signing
8
+ * credentials are configured but no password is stored yet, offers to save the
9
+ * signing password to the OS keychain. If signing isn't set up, it just shows
10
+ * the branding — the user can still save a signing password later (the regular
11
+ * signing flow offers a "remember" option every time).
12
+ */
13
+ export declare function WelcomeScreen({ project, onComplete }: Props): import("react").JSX.Element;
14
+ export {};
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { Box, Text, useInput } from 'ink';
4
+ import { PasswordInput } from './PasswordInput.js';
5
+ import { getSigningPassword, setSigningPassword as saveSigningPassword, } from '../utils/keychain.js';
6
+ import { LOGO, AUTHOR } from '../utils/branding.js';
7
+ function Banner() {
8
+ return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [LOGO.map((line, index) => (_jsx(Text, { color: "cyan", children: line }, index))), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: ' a tool by ' }), _jsx(Text, { bold: true, children: AUTHOR })] })] }));
9
+ }
10
+ /**
11
+ * First-run welcome screen. Shows the branding once and, when signing
12
+ * credentials are configured but no password is stored yet, offers to save the
13
+ * signing password to the OS keychain. If signing isn't set up, it just shows
14
+ * the branding — the user can still save a signing password later (the regular
15
+ * signing flow offers a "remember" option every time).
16
+ */
17
+ export function WelcomeScreen({ project, onComplete }) {
18
+ const signingUsername = project.devProperties?.signingUsername;
19
+ const canSaveSigning = Boolean(signingUsername) && !getSigningPassword(signingUsername);
20
+ const [step, setStep] = useState('prompt');
21
+ const [resultMessage, setResultMessage] = useState('');
22
+ useInput((input, key) => {
23
+ if (step === 'prompt') {
24
+ if (canSaveSigning && (input === 'y' || input === 'Y')) {
25
+ setStep('password');
26
+ }
27
+ else if (input === 'n' || input === 'N' || key.return) {
28
+ onComplete();
29
+ }
30
+ }
31
+ else if (step === 'done') {
32
+ onComplete();
33
+ }
34
+ });
35
+ if (step === 'password') {
36
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Banner, {}), _jsx(PasswordInput, { label: "Enter Signing Password (developer.sitevision.se)", onSubmit: password => {
37
+ if (password && signingUsername) {
38
+ const saved = saveSigningPassword(signingUsername, password);
39
+ setResultMessage(saved
40
+ ? '✓ Signing password saved to the OS keychain.'
41
+ : 'Could not access the keychain; password not saved.');
42
+ }
43
+ else {
44
+ setResultMessage('Skipped — no password entered.');
45
+ }
46
+ setStep('done');
47
+ }, onCancel: onComplete })] }));
48
+ }
49
+ if (step === 'done') {
50
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Banner, {}), _jsx(Text, { color: resultMessage.startsWith('✓') ? 'green' : 'yellow', children: resultMessage }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Press any key to continue\u2026" }) })] }));
51
+ }
52
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Banner, {}), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: "Welcome to Sitevision CLI! \uD83D\uDC4B" }) }), canSaveSigning ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: "Save your signing password to the OS keychain now? (y/n)" }), _jsx(Text, { dimColor: true, children: "So you won't be asked for it every time you sign." })] })) : (_jsxs(Box, { flexDirection: "column", children: [signingUsername ? (_jsx(Text, { dimColor: true, children: "Your signing password is already saved in the keychain." })) : (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: "Signing credentials aren't configured yet." }), _jsx(Text, { dimColor: true, children: "Run \"svc setup-signing\" later to enable app signing." })] })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { children: "Press Enter to continue\u2026" }) })] }))] }));
53
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Shared CLI branding — the logo art and author line. Used both by the Ink
3
+ * first-run welcome screen and the non-interactive "what's new" update banner,
4
+ * so the two stay identical.
5
+ */
6
+ export declare const LOGO: string[];
7
+ export declare const AUTHOR = "Rasmus S\u00F6derstr\u00F6m";
8
+ /**
9
+ * Print the logo + author line straight to stdout (non-interactive), mirroring
10
+ * how the masthead is printed. Used for the update banner.
11
+ */
12
+ export declare function printBranding(): void;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Shared CLI branding — the logo art and author line. Used both by the Ink
3
+ * first-run welcome screen and the non-interactive "what's new" update banner,
4
+ * so the two stay identical.
5
+ */
6
+ const CYAN = '\x1b[36m';
7
+ const BOLD = '\x1b[1m';
8
+ const DIM = '\x1b[2m';
9
+ const RESET = '\x1b[0m';
10
+ export const LOGO = [
11
+ ' ┌──────────┐',
12
+ ' │ │ ▐ ▗ ▗',
13
+ ' │ ▄▖ ▞ │ ▄▖ ▄▖ ▄▟ ▄▖ ▖▄ ▄▖ ▗▟▄ ▖▄ ▄▖ ▗▄▄ ▄▖ ▗▄ ▄▖ ▗▟▄',
14
+ ' │ ▐ ▝ ▞ │ ▐ ▝ ▐▘▜ ▐▘▜ ▐▘▐ ▛ ▘▐ ▝ ▐ ▛ ▘▐▘▜ ▐▐▐ ▐ ▝ ▐▐ ▐▘▐ ▐',
15
+ ' │ ▀▚ ▞ │ ▀▚ ▐ ▐ ▐ ▐ ▐▀▀ ▌ ▀▚ ▐ ▌ ▐ ▐ ▐▐▐ ▀▚ ▐▐ ▐▀▀ ▐',
16
+ ' │ ▝▄▞▞ │ ▝▄▞ ▝▙▛ ▝▙█ ▝▙▞ ▌ ▝▄▞ ▝▄ ▌ ▝▙▛ ▐▐▐ ▝▄▞ ▖ ▐▐ ▝▙▞ ▝▄',
17
+ ' └──────────┘ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄',
18
+ ];
19
+ export const AUTHOR = 'Rasmus Söderström';
20
+ /**
21
+ * Print the logo + author line straight to stdout (non-interactive), mirroring
22
+ * how the masthead is printed. Used for the update banner.
23
+ */
24
+ export function printBranding() {
25
+ for (const line of LOGO) {
26
+ console.log(`${CYAN}${line}${RESET}`);
27
+ }
28
+ console.log(`${DIM} a tool by ${RESET}${BOLD}${AUTHOR}${RESET}`);
29
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * True until the user has completed the first-run welcome at least once.
3
+ */
4
+ export declare function isFirstRun(): boolean;
5
+ /**
6
+ * Persist that the first-run welcome has been seen.
7
+ */
8
+ export declare function markFirstRunComplete(): void;
9
+ /**
10
+ * The CLI version that was last run, or undefined if never recorded (a fresh
11
+ * install, or a user who completed first-run before version tracking existed).
12
+ */
13
+ export declare function getLastSeenVersion(): string | undefined;
14
+ /**
15
+ * Persist the CLI version that just ran, so the next run can detect an upgrade.
16
+ */
17
+ export declare function setLastSeenVersion(version: string): void;
@@ -0,0 +1,57 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import os from 'node:os';
4
+ function configDir() {
5
+ const base = process.env['XDG_CONFIG_HOME'] || path.join(os.homedir(), '.config');
6
+ return path.join(base, 'sitevision-cli');
7
+ }
8
+ function configFile() {
9
+ return path.join(configDir(), 'config.json');
10
+ }
11
+ function readConfig() {
12
+ try {
13
+ return JSON.parse(fs.readFileSync(configFile(), 'utf8'));
14
+ }
15
+ catch {
16
+ return {};
17
+ }
18
+ }
19
+ function writeConfig(config) {
20
+ try {
21
+ fs.mkdirSync(configDir(), { recursive: true });
22
+ fs.writeFileSync(configFile(), JSON.stringify(config, null, 2));
23
+ }
24
+ catch {
25
+ // Best-effort: if we can't persist the flag the welcome screen simply
26
+ // shows again next time, which is harmless.
27
+ }
28
+ }
29
+ /**
30
+ * True until the user has completed the first-run welcome at least once.
31
+ */
32
+ export function isFirstRun() {
33
+ return !readConfig().firstRunCompleted;
34
+ }
35
+ /**
36
+ * Persist that the first-run welcome has been seen.
37
+ */
38
+ export function markFirstRunComplete() {
39
+ const config = readConfig();
40
+ config.firstRunCompleted = true;
41
+ writeConfig(config);
42
+ }
43
+ /**
44
+ * The CLI version that was last run, or undefined if never recorded (a fresh
45
+ * install, or a user who completed first-run before version tracking existed).
46
+ */
47
+ export function getLastSeenVersion() {
48
+ return readConfig().lastSeenVersion;
49
+ }
50
+ /**
51
+ * Persist the CLI version that just ran, so the next run can detect an upgrade.
52
+ */
53
+ export function setLastSeenVersion(version) {
54
+ const config = readConfig();
55
+ config.lastSeenVersion = version;
56
+ writeConfig(config);
57
+ }
@@ -2,7 +2,7 @@
2
2
  * Prompt for a yes/no answer. Returns true for y/Y, false otherwise (incl. empty / Enter).
3
3
  */
4
4
  export function promptYesNo(prompt) {
5
- return new Promise((resolve) => {
5
+ return new Promise(resolve => {
6
6
  process.stdout.write(prompt);
7
7
  const stdin = process.stdin;
8
8
  stdin.setRawMode(true);
@@ -26,7 +26,7 @@ export function promptYesNo(prompt) {
26
26
  * Prompt for password input with masked display
27
27
  */
28
28
  export function promptPassword(prompt) {
29
- return new Promise((resolve) => {
29
+ return new Promise(resolve => {
30
30
  process.stdout.write(prompt);
31
31
  const stdin = process.stdin;
32
32
  stdin.setRawMode(true);
@@ -8,14 +8,14 @@ export interface ProcessResult {
8
8
  output: ProcessOutput[];
9
9
  }
10
10
  export declare class ProcessRunner extends EventEmitter {
11
- private command;
12
- private args;
13
- private cwd?;
14
- private interactive;
15
- private customEnv?;
16
11
  private process;
17
12
  private output;
18
- constructor(command: string, args?: string[], cwd?: string | undefined, interactive?: boolean, customEnv?: Record<string, string> | undefined);
13
+ private readonly command;
14
+ private readonly args;
15
+ private readonly cwd?;
16
+ private readonly interactive;
17
+ private readonly customEnv?;
18
+ constructor(command: string, args?: string[], cwd?: string, interactive?: boolean, customEnv?: Record<string, string>);
19
19
  run(): Promise<ProcessResult>;
20
20
  kill(): void;
21
21
  getOutput(): ProcessOutput[];
@@ -1,50 +1,20 @@
1
1
  import { spawn } from 'child_process';
2
2
  import { EventEmitter } from 'events';
3
3
  export class ProcessRunner extends EventEmitter {
4
+ process = null;
5
+ output = [];
6
+ command;
7
+ args;
8
+ cwd;
9
+ interactive;
10
+ customEnv;
4
11
  constructor(command, args = [], cwd, interactive = false, customEnv) {
5
12
  super();
6
- Object.defineProperty(this, "command", {
7
- enumerable: true,
8
- configurable: true,
9
- writable: true,
10
- value: command
11
- });
12
- Object.defineProperty(this, "args", {
13
- enumerable: true,
14
- configurable: true,
15
- writable: true,
16
- value: args
17
- });
18
- Object.defineProperty(this, "cwd", {
19
- enumerable: true,
20
- configurable: true,
21
- writable: true,
22
- value: cwd
23
- });
24
- Object.defineProperty(this, "interactive", {
25
- enumerable: true,
26
- configurable: true,
27
- writable: true,
28
- value: interactive
29
- });
30
- Object.defineProperty(this, "customEnv", {
31
- enumerable: true,
32
- configurable: true,
33
- writable: true,
34
- value: customEnv
35
- });
36
- Object.defineProperty(this, "process", {
37
- enumerable: true,
38
- configurable: true,
39
- writable: true,
40
- value: null
41
- });
42
- Object.defineProperty(this, "output", {
43
- enumerable: true,
44
- configurable: true,
45
- writable: true,
46
- value: []
47
- });
13
+ this.command = command;
14
+ this.args = args;
15
+ this.cwd = cwd;
16
+ this.interactive = interactive;
17
+ this.customEnv = customEnv;
48
18
  }
49
19
  run() {
50
20
  return new Promise((resolve, reject) => {
@@ -1,5 +1,5 @@
1
1
  import type { SitevisionManifest, DevProperties, ProjectInfo, ProjectPaths, SimpleAppType, ApiEndpoints } from '../types/index.js';
2
- export type { SitevisionManifest, DevProperties, ProjectInfo } from '../types/index.js';
2
+ export type { SitevisionManifest, DevProperties, ProjectInfo, } from '../types/index.js';
3
3
  /**
4
4
  * Get standard project paths for a given root directory
5
5
  */
@@ -179,10 +179,13 @@ export function detectProject(cwd = process.cwd()) {
179
179
  hasDevProperties = true;
180
180
  try {
181
181
  const parsed = JSON.parse(fs.readFileSync(devPropertiesPath, 'utf-8'));
182
- hasLegacyPassword = typeof parsed.password === 'string' && parsed.password.length > 0;
182
+ hasLegacyPassword =
183
+ typeof parsed.password === 'string' && parsed.password.length > 0;
183
184
  devProperties = parsed;
184
185
  // Resolve deploy password: env var > keychain (file is legacy-only)
185
- if (!hasLegacyPassword && devProperties.domain && devProperties.username) {
186
+ if (!hasLegacyPassword &&
187
+ devProperties.domain &&
188
+ devProperties.username) {
186
189
  const envPassword = process.env['SITEVISION_DEPLOY_PASSWORD'];
187
190
  if (envPassword) {
188
191
  devProperties.password = envPassword;
@@ -272,7 +275,8 @@ export function readDevProperties(projectRoot) {
272
275
  * it is held in the OS keychain instead.
273
276
  */
274
277
  export function writeDevProperties(projectRoot, properties) {
275
- const devPropertiesPath = findDevPropertiesPath(projectRoot) || getDefaultDevPropertiesPath(projectRoot);
278
+ const devPropertiesPath = findDevPropertiesPath(projectRoot) ||
279
+ getDefaultDevPropertiesPath(projectRoot);
276
280
  const { password: _password, ...persisted } = properties;
277
281
  fs.writeFileSync(devPropertiesPath, JSON.stringify(persisted, null, 2));
278
282
  }
@@ -74,7 +74,7 @@ function makeRequest(url, options) {
74
74
  method: options.method,
75
75
  headers,
76
76
  };
77
- const req = transport.request(requestOptions, (res) => {
77
+ const req = transport.request(requestOptions, res => {
78
78
  const chunks = [];
79
79
  res.on('data', (chunk) => {
80
80
  chunks.push(chunk);
@@ -26,9 +26,9 @@ function isNewer(a, b) {
26
26
  * failed check never blocks startup or surfaces an error to the user.
27
27
  */
28
28
  export function checkForUpdate(packageName, currentVersion, timeoutMs = 1500) {
29
- return new Promise((resolve) => {
29
+ return new Promise(resolve => {
30
30
  const url = `https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`;
31
- const request = https.get(url, { timeout: timeoutMs, headers: { accept: 'application/json' } }, (response) => {
31
+ const request = https.get(url, { timeout: timeoutMs, headers: { accept: 'application/json' } }, response => {
32
32
  if (response.statusCode !== 200) {
33
33
  response.resume();
34
34
  resolve(null);
@@ -36,7 +36,7 @@ export function checkForUpdate(packageName, currentVersion, timeoutMs = 1500) {
36
36
  }
37
37
  let body = '';
38
38
  response.setEncoding('utf8');
39
- response.on('data', (chunk) => {
39
+ response.on('data', chunk => {
40
40
  body += chunk;
41
41
  });
42
42
  response.on('end', () => {
@@ -6,12 +6,12 @@
6
6
  */
7
7
  import type { BuildOptions, BuildResult } from '../types/index.js';
8
8
  export declare class WebpackRunner {
9
- private projectRoot;
10
- private options;
11
9
  private webpack;
12
10
  private config;
13
11
  private compiler;
14
12
  private watcher;
13
+ private readonly projectRoot;
14
+ private readonly options;
15
15
  constructor(projectRoot: string, options: BuildOptions);
16
16
  /**
17
17
  * Initialize webpack by loading it from the project's node_modules
@@ -12,43 +12,15 @@ import { copyChunksToResources } from './zip.js';
12
12
  // WEBPACK RUNNER CLASS
13
13
  // =============================================================================
14
14
  export class WebpackRunner {
15
+ webpack = null;
16
+ config = null;
17
+ compiler = null;
18
+ watcher = null;
19
+ projectRoot;
20
+ options;
15
21
  constructor(projectRoot, options) {
16
- Object.defineProperty(this, "projectRoot", {
17
- enumerable: true,
18
- configurable: true,
19
- writable: true,
20
- value: projectRoot
21
- });
22
- Object.defineProperty(this, "options", {
23
- enumerable: true,
24
- configurable: true,
25
- writable: true,
26
- value: options
27
- });
28
- Object.defineProperty(this, "webpack", {
29
- enumerable: true,
30
- configurable: true,
31
- writable: true,
32
- value: null
33
- });
34
- Object.defineProperty(this, "config", {
35
- enumerable: true,
36
- configurable: true,
37
- writable: true,
38
- value: null
39
- });
40
- Object.defineProperty(this, "compiler", {
41
- enumerable: true,
42
- configurable: true,
43
- writable: true,
44
- value: null
45
- });
46
- Object.defineProperty(this, "watcher", {
47
- enumerable: true,
48
- configurable: true,
49
- writable: true,
50
- value: null
51
- });
22
+ this.projectRoot = projectRoot;
23
+ this.options = options;
52
24
  }
53
25
  /**
54
26
  * Initialize webpack by loading it from the project's node_modules
@@ -110,7 +82,8 @@ export class WebpackRunner {
110
82
  this.config = configFactory;
111
83
  }
112
84
  // Override mode
113
- this.config.mode = this.options.mode === 'development' ? 'development' : 'production';
85
+ this.config.mode =
86
+ this.options.mode === 'development' ? 'development' : 'production';
114
87
  }
115
88
  catch (error) {
116
89
  throw new Error(`Failed to load webpack config: ${error instanceof Error ? error.message : String(error)}`);
@@ -124,12 +97,12 @@ export class WebpackRunner {
124
97
  return {
125
98
  success: !stats.hasErrors(),
126
99
  outputPath: this.config?.output?.path,
127
- errors: json.errors?.map((e) => e.message) || [],
128
- warnings: json.warnings?.map((w) => w.message) || [],
100
+ errors: json.errors?.map(e => e.message) || [],
101
+ warnings: json.warnings?.map(w => w.message) || [],
129
102
  stats: {
130
103
  time: json.time || 0,
131
104
  hash: json.hash || '',
132
- assets: json.assets?.map((a) => a.name) || [],
105
+ assets: json.assets?.map(a => a.name) || [],
133
106
  },
134
107
  };
135
108
  }
@@ -178,7 +151,7 @@ export class WebpackRunner {
178
151
  if (!this.webpack || !this.config) {
179
152
  throw new Error('Webpack not initialized');
180
153
  }
181
- return new Promise((resolve) => {
154
+ return new Promise(resolve => {
182
155
  this.compiler = this.webpack(this.config);
183
156
  this.watcher = this.compiler.watch({
184
157
  aggregateTimeout: 300,
@@ -214,7 +187,7 @@ export class WebpackRunner {
214
187
  * Stop watching and close the compiler
215
188
  */
216
189
  async close() {
217
- return new Promise((resolve) => {
190
+ return new Promise(resolve => {
218
191
  if (this.watcher) {
219
192
  this.watcher.close(() => {
220
193
  this.watcher = null;
package/dist/utils/zip.js CHANGED
@@ -41,19 +41,17 @@ export async function createZip(sourceDir, outputPath) {
41
41
  zipProcess.stderr?.on('data', (data) => {
42
42
  stderr += data.toString();
43
43
  });
44
- zipProcess.on('error', (error) => {
44
+ zipProcess.on('error', error => {
45
45
  // If zip command not found, try alternative methods
46
46
  if (error.code === 'ENOENT') {
47
47
  // Fall back to tar on systems without zip
48
- createZipWithTar(sourceDir, outputPath)
49
- .then(resolve)
50
- .catch(reject);
48
+ createZipWithTar(sourceDir, outputPath).then(resolve).catch(reject);
51
49
  }
52
50
  else {
53
51
  reject(new Error(`Zip process error: ${error.message}`));
54
52
  }
55
53
  });
56
- zipProcess.on('close', (code) => {
54
+ zipProcess.on('close', code => {
57
55
  if (code === 0) {
58
56
  resolve(outputPath);
59
57
  }
@@ -91,10 +89,10 @@ async function createZipWithPowerShell(sourceDir, outputPath) {
91
89
  psProcess.stderr?.on('data', (data) => {
92
90
  stderr += data.toString();
93
91
  });
94
- psProcess.on('error', (error) => {
92
+ psProcess.on('error', error => {
95
93
  reject(new Error(`PowerShell error: ${error.message}`));
96
94
  });
97
- psProcess.on('close', (code) => {
95
+ psProcess.on('close', code => {
98
96
  if (code === 0) {
99
97
  resolve(absoluteOutputPath);
100
98
  }