Skip to content

HestiaCP API v3 - Structural cleanup - #11

Draft
neto737 wants to merge 19 commits into
mainfrom
v3.0
Draft

neto737 wants to merge 19 commits into
mainfrom
v3.0

Conversation

@neto737

@neto737 neto737 commented Oct 19, 2026 •

Copy link
Copy Markdown
Owner

Platform

  • Require PHP 8.3 or later (breaking).
  • Use PHP 8.3 features: add #[\Override] to every process() and getTimeout() override, so a signature change in the parent can't silently turn an override into a separate method, and give the class constants types (public const int OK = 0, protected const string FORMAT_JSON = 'json').

Commands

  • Make commands stateless: replace setLastResponse() + process() with process(ResponseInterface $response): mixed. A command currently stores the last response on itself, so it describes both the request and the result of its last run, and sending the same instance twice overwrites the first result (breaking for classes that implement ICommand or override process()).
  • Remove the deprecated verb-namespace class names (Add\User, Lists\Users, …) kept since 2.1.0, along with their test in tests/Command/DeprecatedNamesTest.php (breaking). Delete the Add, Change, Delete, Lists, Suspend and Unsuspend folders. In Backup, delete only User.php and Users.php: the rest of that folder is the backup module's commands.
  • Remove the deprecated ARG_* constants (breaking for custom commands that still use them).
  • Make Command::getResponseCode() and Command::defaultProcess() protected. Only subclasses use them, but as public methods they are part of the API (breaking for code that calls them from outside a command).
  • Replace the public static ResponseCode::$messages array with a private const MESSAGES, and keep ResponseCode::getMessage() as the way to read them. Any code can currently overwrite the messages at runtime, for every client in the process (breaking for code that reads or writes $messages directly).

Credentials and host

  • Remove the deprecated Credentials constructor and setters (breaking).
  • Make Host immutable, like Credentials: readonly properties, no setHostname(), setPort() or setCredentials() (or with*() methods that return a copy), and remove Client::setHost(). A shared client can currently be switched to another server while in use. Rewrite the UPGRADING.md advice to pass new Credentials to Host::setCredentials() (breaking).
  • Mark secrets with #[\SensitiveParameter] so they don't show up in stack traces and logged exceptions: the password, secret key and hash parameters of Credentials, Client::simpleFactory(), the module methods that take a password, and the commands AddUser, ChangeUserPassword, AddMailAccount, ChangeMailAccountPassword, AddDatabase, ChangeDatabasePassword, AddWebDomainFtp and ChangeWebDomainFtpPassword. Add a __debugInfo() to Credentials that masks the secrets in var_dump().

Modules

  • Remove the module cache in Client::loadModule() and create the module on each getModule*() call. Modules are thin wrappers with no state of their own, and the cache already caused the per-user bug fixed in 2.0.0 (breaking: repeated calls no longer return the same instance).
  • Remove the empty IModule marker interface (breaking for code that type-hints it).

Exceptions

  • Stop extending InvalidResponseException from ProcessException. "This host isn't HestiaCP" is a setup error, not a failed command, and catching ProcessException shouldn't catch it. Make it a subclass of ClientException or a sibling of ProcessException (breaking).
  • Throw InvalidResponseException instead of ProcessException (code 0) when a list command's body isn't valid JSON, or isn't a JSON object or array. HestiaCP never sends that, so like a non-numeric exit code it means the host isn't HestiaCP. Update the table in docs/errors.md (breaking for code that catches it as ProcessException).
  • Extend the SPL exceptions, so Exceptions\InvalidArgumentException is a \InvalidArgumentException and Exceptions\RuntimeException a \RuntimeException, with a shared marker interface replacing the Exceptions\Exception base class. Code that catches the standard types would then catch them too (breaking for code that catches Exceptions\Exception).

Tests and tooling

  • Group the tests by module to mirror src: move the tests in tests/Command/AddTest.php, ChangeTest.php, DeleteTest.php, ListsTest.php, SuspendTest.php and UnsuspendTest.php, still grouped by verb, into UserTest, MailTest, WebTest, DatabaseTest and the other module test files.
  • Raise PHPStan from level 6 to level 8, to catch null-handling mistakes.

@codecov

codecov Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.85%. Comparing base (155e419) to head (eece17c).

Additional details and impacted files
@@             Coverage Diff              @@
##               main      #11      +/-   ##
============================================
+ Coverage     99.72%   99.85%   +0.13%     
+ Complexity      627      609      -18     
============================================
  Files           129      129              
  Lines          1449     1411      -38     
============================================
- Hits           1445     1409      -36     
+ Misses            4        2       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@neto737
neto737 marked this pull request as draft October 19, 2026 09:50
@neto737 neto737 changed the title [WIP] HestiaCP API v3 - Structural cleanup HestiaCP API v3 - Structural cleanup Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant