array($this, 'sanitize'), 'show_in_rest' => false)); } public function defaults(): array { return array( 'connected' => '0', 'site_token' => '', 'install_key' => '', 'embed_key' => '', 'assistant_id' => '', 'assistant_slug' => '', 'assistant_name' => '', 'account_id' => '', 'site_id' => '', 'connected_domain' => '', 'plan' => 'lite', 'subscription_status' => '', 'trial_ends_at' => '', 'runtime_available' => '1', 'embed_enabled' => '1', 'auto_insert' => '1', 'position' => 'bottom-right', 'accent_color' => '#f97316', 'last_sync_at' => '', 'sync_error' => '', 'service_consent' => '0', 'pairing_id' => '', 'pairing_secret' => '', 'authorization_url' => '', 'pairing_expires_at' => '', 'version' => AIVA_LITE_VERSION, ); } public function get_all(): array { return wp_parse_args(get_option(AIVA_LITE_OPTION_KEY, array()), $this->defaults()); } public function get(string $key, $default = null) { $options = $this->get_all(); return $options[$key] ?? $default; } public function service_url(string $service): string { $urls = array( 'api' => array('AIVA_LITE_API_URL', 'https://api.aiva.aiintegrations.tech'), 'autobuild' => array('AIVA_LITE_AUTOBUILD_URL', 'https://autobuild.aiintegrations.tech'), 'dashboard' => array('AIVA_LITE_DASHBOARD_URL', 'https://dashboard.aiintegrations.tech'), 'widget' => array('AIVA_LITE_WIDGET_URL', 'https://aiva.aiintegrations.tech'), ); if (!isset($urls[$service])) { return ''; } list($constant, $fallback) = $urls[$service]; // Development endpoints require explicit configuration by the site owner. $value = defined($constant) ? constant($constant) : $fallback; $parts = wp_parse_url((string) $value); return !empty($parts['host']) && ($parts['scheme'] ?? '') === 'https' && empty($parts['user']) && empty($parts['pass']) ? untrailingslashit(esc_url_raw($value)) : $fallback; } public function dashboard_link(bool $billing = false): string { $id = $this->get('assistant_id'); $path = $id ? '/dashboard/assistant/' . rawurlencode($id) . ($billing ? '/billing' : '/overview') : '/dashboard/assistants'; return $this->service_url('dashboard') . $path; } public function update(array $values): void { update_option(AIVA_LITE_OPTION_KEY, $this->sanitize(array_merge($this->get_all(), $values)), false); } public function reset_pairing(): void { $this->update(array('pairing_id' => '', 'pairing_secret' => '', 'authorization_url' => '', 'pairing_expires_at' => '')); } public function reset_connection(): void { $values = array(); foreach (array('site_token', 'install_key', 'embed_key', 'assistant_id', 'assistant_slug', 'assistant_name', 'account_id', 'site_id', 'connected_domain', 'subscription_status', 'trial_ends_at', 'last_sync_at', 'sync_error') as $key) { $values[$key] = ''; } $this->update(array_merge($values, array('connected' => '0', 'plan' => 'lite'))); $this->reset_pairing(); delete_transient('aiva_lite_status_cache'); delete_transient('aiva_lite_summary_cache'); } public function mark_connected_from_payload(array $payload, string $install_key = ''): bool { if (empty($payload['assistant_id']) || empty($payload['assistant_slug']) || empty($payload['site_token']) || empty($payload['site_id'])) { return false; } $this->update(array( 'connected' => '1', 'service_consent' => '1', 'install_key' => '', 'site_token' => $payload['site_token'], 'site_id' => $payload['site_id'], 'account_id' => $payload['account_id'] ?? '', 'assistant_id' => $payload['assistant_id'], 'assistant_slug' => $payload['assistant_slug'], 'assistant_name' => $payload['assistant_name'] ?? $payload['assistant_slug'], 'connected_domain' => $payload['connected_domain'] ?? home_url(), )); $this->apply_status($payload); $this->reset_pairing(); delete_transient('aiva_lite_status_cache'); delete_transient('aiva_lite_summary_cache'); return true; } public function apply_status(array $payload): void { $this->update(array( 'plan' => $payload['plan'] ?? 'lite', 'subscription_status' => $payload['subscription_status'] ?? '', 'trial_ends_at' => $payload['trial_ends_at'] ?? '', 'runtime_available' => !empty($payload['runtime_available']) ? '1' : '0', 'last_sync_at' => current_time('mysql'), 'sync_error' => '', )); } public function sanitize($input): array { $input = is_array($input) ? $input : array(); $output = array(); foreach ($this->defaults() as $key => $default) { $value = $input[$key] ?? $default; if (!is_scalar($value)) { $value = $default; } if (in_array($key, array('connected', 'embed_enabled', 'auto_insert', 'service_consent', 'runtime_available'), true)) { $output[$key] = !empty($value) ? '1' : '0'; } elseif ($key === 'accent_color') { $output[$key] = sanitize_hex_color($value) ?: $default; } elseif ($key === 'position') { $output[$key] = $value === 'bottom-left' ? 'bottom-left' : 'bottom-right'; } elseif ($key === 'plan') { $output[$key] = in_array($value, array('lite', 'trial', 'paid'), true) ? $value : 'lite'; } elseif (in_array($key, array('connected_domain', 'authorization_url'), true)) { $output[$key] = esc_url_raw((string) $value, array('https', 'http')); } else { $output[$key] = sanitize_text_field((string) $value); } } return $output; } }