diff --git a/.gitignore b/.gitignore
index ce4b07b74..e05ff9d11 100644
--- a/.gitignore
+++ b/.gitignore
@@ -82,7 +82,7 @@ unraid-api/
.node-version
# Node.js built-in's like npm & corepack
-lib/
+lib/node_modules
# unraid-api & node binaries
bin/
@@ -91,11 +91,15 @@ sbin/unraid-api
# Unraid API readme/changelog
emhttp/plugins/dynamix.unraid.net
+# API / Web component / Connect functionality
+emhttp/plugins/dynamix.my.servers
+
# rc scripts
etc/rc.d/rc.flash_backup
etc/rc.d/rc.unraid-api
-etc/rc.d/rc0.d
-etc/rc.d/rc6.d
+
+etc/rc.d/rc6.d/K10flash-backup
+etc/rc.d/rc6.d/K20unraid-api
# API helper scripts
share/dynamix.unraid.net/
diff --git a/emhttp/plugins/dynamix.my.servers/.gitignore b/emhttp/plugins/dynamix.my.servers/.gitignore
deleted file mode 100644
index 7501eddf5..000000000
--- a/emhttp/plugins/dynamix.my.servers/.gitignore
+++ /dev/null
@@ -1,12 +0,0 @@
-# Provided by Unraid API
-Connect.page
-scripts/
-unraid-components/
-
-include/UpdateFlashBackup.php
-include/sso-login.php
-include/unraid-api.php
-include/welcome-modal.php
-include/myservers1.php
-include/state.php
-include/translations.php
diff --git a/emhttp/plugins/dynamix.my.servers/Registration.page b/emhttp/plugins/dynamix.my.servers/Registration.page
deleted file mode 100644
index dd60c4e03..000000000
--- a/emhttp/plugins/dynamix.my.servers/Registration.page
+++ /dev/null
@@ -1,23 +0,0 @@
-Menu="About:30"
-Type="xmenu"
-Title="Registration"
-Icon="icon-registration"
-Tag="pencil"
----
-check(true);
-?>
-
-
-
diff --git a/emhttp/plugins/dynamix.my.servers/data/server-state.php b/emhttp/plugins/dynamix.my.servers/data/server-state.php
deleted file mode 100644
index 2e0e97b2f..000000000
--- a/emhttp/plugins/dynamix.my.servers/data/server-state.php
+++ /dev/null
@@ -1,10 +0,0 @@
-getServerStateJson();
diff --git a/emhttp/plugins/dynamix.my.servers/include/activation-code-extractor.php b/emhttp/plugins/dynamix.my.servers/include/activation-code-extractor.php
deleted file mode 100644
index 53b91c016..000000000
--- a/emhttp/plugins/dynamix.my.servers/include/activation-code-extractor.php
+++ /dev/null
@@ -1,166 +0,0 @@
-data = $this->fetchJsonData();
- }
-
- /**
- * Fetch JSON data from all files matching the pattern.
- *
- * @return array Array of extracted JSON data.
- */
- private function fetchJsonData(): array {
- $data = [];
-
- if (!is_dir(self::DIR)) {
- return $data;
- }
-
- $files = scandir(self::DIR);
-
- if ($files === false || count($files) === 0) {
- return $data;
- }
-
- foreach ($files as $file) {
- $filePath = self::DIR . DIRECTORY_SEPARATOR . $file;
-
- if (preg_match(self::FILE_PATTERN, $file, $matches)) {
- // $activationCode = $matches[1];
- $fileContent = file_get_contents($filePath);
- $jsonData = json_decode($fileContent, true);
-
- if (json_last_error() === JSON_ERROR_NONE) {
- $data = $jsonData;
- } else {
- $data = ['error' => 'Invalid JSON format'];
- }
-
- break; // Stop after the first match
- }
- }
-
- if (isset($data['partnerName'])) {
- $this->partnerName = $data['partnerName'];
- }
-
- if (isset($data['partnerUrl'])) {
- $this->partnerUrl = $data['partnerUrl'];
- }
-
- /**
- * During the plg install, the partner logo asset is copied to the webgui images dir.
- */
- $logo = self::DOCROOT . self::WEBGUI_IMAGES_BASE_DIR . '/' . self::PARTNER_LOGO_FILE_NAME;
- if (file_exists($logo)) {
- $this->partnerLogoPath = $logo;
- }
-
- return $data;
- }
-
- /**
- * Get the partner logo path.
- *
- * @return string
- */
- public function getPartnerLogoPath(): string {
- return $this->partnerLogoPath;
- }
-
- /**
- * Get the extracted data.
- *
- * @return array
- */
- public function getData(): array {
- return $this->data;
- }
-
- /**
- * Retrieve the activation code data as JSON string with converted special characters to HTML entities
- *
- * @return string
- */
- public function getDataForHtmlAttr(): string {
- $json = json_encode($this->getData());
- return htmlspecialchars($json, ENT_QUOTES, 'UTF-8');
- }
-
- /**
- * Get the partner logo render string.
- *
- * @return string
- */
- public function getPartnerLogoRenderString(): string {
- if (empty($this->partnerLogoPath)) { // default logo
- return file_get_contents(self::DEFAULT_LOGO);
- }
-
- return file_get_contents($this->partnerLogoPath);
- }
-
- /**
- * Get the partner name.
- *
- * @return string
- */
- public function getPartnerName(): string {
- return $this->partnerName;
- }
-
- /**
- * Get the partner URL.
- *
- * @return string
- */
- public function getPartnerUrl(): string {
- return $this->partnerUrl;
- }
-
- /**
- * Output for debugging
- * @return void
- */
- public function debug(): void {
- echo "data: "; var_dump($this->data);
- echo "partnerName: "; var_dump($this->partnerName);
- echo "partnerUrl: "; var_dump($this->partnerUrl);
- echo "partnerLogoPath: "; var_dump($this->partnerLogoPath);
-
- echo $this->getPartnerLogoRenderString();
- }
-}
diff --git a/emhttp/plugins/dynamix.my.servers/include/myservers2.php b/emhttp/plugins/dynamix.my.servers/include/myservers2.php
deleted file mode 100644
index dc32fa806..000000000
--- a/emhttp/plugins/dynamix.my.servers/include/myservers2.php
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
diff --git a/emhttp/plugins/dynamix.my.servers/include/reboot-details.php b/emhttp/plugins/dynamix.my.servers/include/reboot-details.php
deleted file mode 100644
index 349ea8062..000000000
--- a/emhttp/plugins/dynamix.my.servers/include/reboot-details.php
+++ /dev/null
@@ -1,168 +0,0 @@
-rebootType;
- * ```
- */
-class RebootDetails
-{
- const CURRENT_CHANGES_TXT_PATH = '/boot/changes.txt';
- const CURRENT_README_RELATIVE_PATH = 'plugins/unRAIDServer/README.md';
- const CURRENT_VERSION_PATH = '/etc/unraid-version';
- const PREVIOUS_BZ_ROOT_PATH = '/boot/previous/bzroot';
- const PREVIOUS_CHANGES_TXT_PATH = '/boot/previous/changes.txt';
-
- private $currentVersion = '';
-
- public $rebootType = ''; // 'update', 'downgrade', 'thirdPartyDriversDownloading'
- public $rebootReleaseDate = '';
- public $rebootVersion = '';
-
- public $previousReleaseDate = '';
- public $previousVersion = '';
-
- /**
- * Constructs a new RebootDetails object and automatically detects the reboot type during initialization.
- */
- public function __construct()
- {
- $this->detectRebootType();
- }
-
- /**
- * Detects the type of reboot required based on the contents of the unRAID server's README.md file.
- * Sets the $rebootType property accordingly.
- */
- private function detectRebootType()
- {
- $docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
-
- /**
- * Read the reboot readme, and see if it says "REBOOT REQUIRED" or "DOWNGRADE"
- * only relying on the README.md file to save reads from the flash drive.
- * because we started allowing downgrades from the account.unraid.net Update OS page, we can't
- * fully rely on the README.md value of being accurate.
- * For instance if on 6.13.0-beta.2.1 then chose to "Downgrade" to 6.13.0-beta.1.10 from the account app
- * the README.md file would still say "REBOOT REQUIRED".
- */
- $rebootReadme = @file_get_contents("$docroot/" . self::CURRENT_README_RELATIVE_PATH, false, null, 0, 20) ?: '';
- $rebootDetected = preg_match("/^\*\*(REBOOT REQUIRED|DOWNGRADE)/", $rebootReadme);
- if (!$rebootDetected) {
- return;
- }
- /**
- * if a reboot is required, then:
- * get current Unraid version from /etc/unraid-version
- * then get the version of the last update from self::CURRENT_CHANGES_TXT_PATH
- * if they're different, then a reboot is required
- * if the version in self::CURRENT_CHANGES_TXT_PATH is less than the current version, then a downgrade is required
- * if the version in self::CURRENT_CHANGES_TXT_PATH is greater than the current version, then an update is required
- */
- $this->setCurrentVersion();
- $this->setRebootDetails();
- if ($this->currentVersion == '' || $this->rebootVersion == '') {
- return; // return to prevent potential incorrect outcome
- }
-
- $compareVersions = version_compare($this->rebootVersion, $this->currentVersion);
- switch ($compareVersions) {
- case -1:
- $this->setRebootType('downgrade');
- break;
- case 0:
- // we should never get here, but if we do, then no reboot is required and just return
- return;
- case 1:
- $this->setRebootType('update');
- break;
- }
-
- // Detect if third-party drivers were part of the update process
- $processWaitingThirdPartyDrivers = "inotifywait -q " . self::CURRENT_CHANGES_TXT_PATH . " -e move_self,delete_self";
- // Run the ps command to list processes and check if the process is running
- $ps_command = "ps aux | grep -E \"$processWaitingThirdPartyDrivers\" | grep -v \"grep -E\"";
- $output = shell_exec($ps_command) ?? '';
- if ($this->rebootType != '' && strpos($output, $processWaitingThirdPartyDrivers) !== false) {
- $this->setRebootType('thirdPartyDriversDownloading');
- }
- }
-
- /**
- * Detects and retrieves the version information related to the system reboot based on the contents of the '/boot/changes.txt' file.
- *
- * @return string The system version information or 'Not found' if not found, or 'File not found' if the file is not present.
- */
- private function readChangesTxt(string $file_path = self::CURRENT_CHANGES_TXT_PATH)
- {
- // Check if the file exists
- if (file_exists($file_path)) {
- exec("head -n4 $file_path", $rows);
- foreach ($rows as $row) {
- $i = stripos($row,'version');
- if ($i !== false) {
- [$version, $releaseDate] = explode(' ', trim(substr($row, $i+7)));
- break;
- }
- }
-
- return [
- 'releaseDate' => $releaseDate ?? 'Not found',
- 'version' => $version ?? 'Not found',
- ];
- } else {
- return 'File not found';
- }
- }
-
- /**
- * Sets the current version of the Unraid server for comparison with the reboot version.
- */
- private function setCurrentVersion() {
- // output ex: version="6.13.0-beta.2.1"
- $raw = @file_get_contents(self::CURRENT_VERSION_PATH) ?: '';
- // Regular expression to match the version between the quotes
- $pattern = '/version="([^"]+)"/';
- if (preg_match($pattern, $raw, $matches)) {
- $this->currentVersion = $matches[1];
- }
- }
-
- private function setRebootDetails()
- {
- $rebootDetails = $this->readChangesTxt();
- $this->rebootReleaseDate = $rebootDetails['releaseDate'];
- $this->rebootVersion = $rebootDetails['version'];
- }
-
- private function setRebootType($rebootType)
- {
- $this->rebootType = $rebootType;
- }
-
- /**
- * If self::PREVIOUS_BZ_ROOT_PATH exists, then the user has the option to downgrade to the previous version.
- * Parse the text file /boot/previous/changes.txt to get the version number of the previous version.
- * Then we move some files around and reboot.
- */
- public function setPrevious()
- {
- if (@file_exists(self::PREVIOUS_BZ_ROOT_PATH) && @file_exists(self::PREVIOUS_CHANGES_TXT_PATH)) {
- $parseOutput = $this->readChangesTxt(self::PREVIOUS_CHANGES_TXT_PATH);
- $this->previousVersion = $parseOutput['version'];
- $this->previousReleaseDate = $parseOutput['releaseDate'];
- }
- }
-}
diff --git a/emhttp/plugins/dynamix.my.servers/include/web-components-extractor.php b/emhttp/plugins/dynamix.my.servers/include/web-components-extractor.php
deleted file mode 100644
index f4d68fbcf..000000000
--- a/emhttp/plugins/dynamix.my.servers/include/web-components-extractor.php
+++ /dev/null
@@ -1,103 +0,0 @@
-findManifestFiles('manifest.json');
-
- foreach ($manifestFiles as $manifestPath) {
- $manifest = $this->getManifestContents($manifestPath);
- $subfolder = $this->getRelativePath($manifestPath);
-
- foreach ($manifest as $key => $value) {
- if (strpos($key, self::RICH_COMPONENTS_ENTRY) !== false && isset($value["file"])) {
- return ($subfolder ? $subfolder . '/' : '') . $value["file"];
- }
- }
- }
- return '';
- }
-
- private function getRichComponentsScript(): string
- {
- $jsFile = $this->getRichComponentsFile();
- if (empty($jsFile)) {
- return '';
- }
- return '';
- }
-
- private function getUnraidUiScriptHtml(): string
- {
- $manifestFiles = $this->findManifestFiles('ui.manifest.json');
-
- if (empty($manifestFiles)) {
- error_log("No ui.manifest.json found");
- return '';
- }
-
- $manifestPath = $manifestFiles[0]; // Use the first found manifest
- $manifest = $this->getManifestContents($manifestPath);
- $subfolder = $this->getRelativePath($manifestPath);
-
- if (!isset($manifest[self::UI_ENTRY]) || !isset($manifest[self::UI_STYLES_ENTRY])) {
- error_log("Required entries not found in ui.manifest.json");
- return '';
- }
-
- $jsFile = ($subfolder ? $subfolder . '/' : '') . $manifest[self::UI_ENTRY]['file'];
- $cssFile = ($subfolder ? $subfolder . '/' : '') . $manifest[self::UI_STYLES_ENTRY]['file'];
-
- return '';
- }
-
- public function getScriptTagHtml(): string
- {
- try {
- return $this->getRichComponentsScript() . $this->getUnraidUiScriptHtml();
- } catch (\Exception $e) {
- error_log("Error in WebComponentsExtractor::getScriptTagHtml: " . $e->getMessage());
- return "";
- }
- }
-}