- Remove non-existent src/Core/Service/ from CLAUDE.md L1 packages list - Fix LifecycleEventsTest: remove dependency on McpToolHandler interface (lives in core-mcp, not needed since McpToolsRegistering stores class name strings) - Run Laravel Pint to fix PSR-12 violations across all source and test files - Add missing declare(strict_types=1) to 18 PHP files (tests, seeders, Layout.php, GenerateServiceOgImages.php) Co-Authored-By: Virgil <virgil@lethean.io>
206 lines
6.3 KiB
PHP
206 lines
6.3 KiB
PHP
<?php
|
|
|
|
/*
|
|
* Core PHP Framework
|
|
*
|
|
* Licensed under the European Union Public Licence (EUPL) v1.2.
|
|
* See LICENSE file for details.
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Core\Cdn\Services;
|
|
|
|
use Core\Helpers\Cdn;
|
|
use Flux\AssetManager;
|
|
use Flux\Flux;
|
|
|
|
/**
|
|
* CDN-aware Flux asset service.
|
|
*
|
|
* In development: Uses standard Laravel routes (/flux/flux.js)
|
|
* In production: Uses CDN URLs (cdn.host.uk.com/flux/flux.min.js)
|
|
*
|
|
* Requires Flux assets to be uploaded to CDN storage zone.
|
|
*
|
|
* URL building is delegated to CdnUrlBuilder for consistency across services.
|
|
*
|
|
* ## Methods
|
|
*
|
|
* | Method | Returns | Description |
|
|
* |--------|---------|-------------|
|
|
* | `scripts()` | `string` | Get Flux scripts tag with CDN awareness |
|
|
* | `editorScripts()` | `string` | Get Flux editor scripts (Pro only) |
|
|
* | `editorStyles()` | `string` | Get Flux editor styles (Pro only) |
|
|
* | `shouldUseCdn()` | `bool` | Check if CDN should be used |
|
|
* | `getCdnAssetPaths()` | `array<string, string>` | Get source-to-CDN path mapping |
|
|
*
|
|
* @see CdnUrlBuilder For the underlying URL building logic
|
|
*/
|
|
class FluxCdnService
|
|
{
|
|
protected CdnUrlBuilder $urlBuilder;
|
|
|
|
public function __construct(?CdnUrlBuilder $urlBuilder = null)
|
|
{
|
|
$this->urlBuilder = $urlBuilder ?? new CdnUrlBuilder;
|
|
}
|
|
|
|
/**
|
|
* Get the Flux scripts tag with CDN awareness.
|
|
*
|
|
* @param array<string, mixed> $options Options like ['nonce' => 'abc123']
|
|
* @return string HTML script tag
|
|
*/
|
|
public function scripts(array $options = []): string
|
|
{
|
|
$nonce = isset($options['nonce']) ? ' nonce="'.$options['nonce'].'"' : '';
|
|
|
|
// Use CDN when enabled (respects CDN_FORCE_LOCAL for testing)
|
|
if (! $this->shouldUseCdn()) {
|
|
return app('flux')->scripts($options);
|
|
}
|
|
|
|
// In production, use CDN URL (no vBucket - shared platform asset)
|
|
$versionHash = $this->getVersionHash();
|
|
$filename = config('app.debug') ? 'flux.js' : 'flux.min.js';
|
|
$url = $this->cdnUrl("flux/{$filename}", $versionHash);
|
|
|
|
return '<script src="'.$url.'" data-navigate-once'.$nonce.'></script>';
|
|
}
|
|
|
|
/**
|
|
* Get the Flux editor scripts tag with CDN awareness.
|
|
*
|
|
* @return string HTML script tag for Flux editor
|
|
*
|
|
* @throws \Exception When Flux Pro is not available
|
|
*/
|
|
public function editorScripts(): string
|
|
{
|
|
if (! Flux::pro()) {
|
|
throw new \Exception('Flux Pro is required to use the Flux editor.');
|
|
}
|
|
|
|
// Use CDN when enabled (respects CDN_FORCE_LOCAL for testing)
|
|
if (! $this->shouldUseCdn()) {
|
|
return AssetManager::editorScripts();
|
|
}
|
|
|
|
// In production, use CDN URL (no vBucket - shared platform asset)
|
|
$versionHash = $this->getVersionHash('/editor.js');
|
|
$filename = config('app.debug') ? 'editor.js' : 'editor.min.js';
|
|
$url = $this->cdnUrl("flux/{$filename}", $versionHash);
|
|
|
|
return '<script src="'.$url.'" defer></script>';
|
|
}
|
|
|
|
/**
|
|
* Get the Flux editor styles tag with CDN awareness.
|
|
*
|
|
* @return string HTML link tag for Flux editor styles
|
|
*
|
|
* @throws \Exception When Flux Pro is not available
|
|
*/
|
|
public function editorStyles(): string
|
|
{
|
|
if (! Flux::pro()) {
|
|
throw new \Exception('Flux Pro is required to use the Flux editor.');
|
|
}
|
|
|
|
// Use CDN when enabled (respects CDN_FORCE_LOCAL for testing)
|
|
if (! $this->shouldUseCdn()) {
|
|
return AssetManager::editorStyles();
|
|
}
|
|
|
|
// In production, use CDN URL (no vBucket - shared platform asset)
|
|
$versionHash = $this->getVersionHash('/editor.css');
|
|
$url = $this->cdnUrl('flux/editor.css', $versionHash);
|
|
|
|
return '<link rel="stylesheet" href="'.$url.'">';
|
|
}
|
|
|
|
/**
|
|
* Get version hash from Flux manifest.
|
|
*
|
|
* @param string $key Manifest key to look up
|
|
* @return string 8-character hash for cache busting
|
|
*/
|
|
protected function getVersionHash(string $key = '/flux.js'): string
|
|
{
|
|
$manifestPath = Flux::pro()
|
|
? base_path('vendor/admin/flux-pro/dist/manifest.json')
|
|
: base_path('vendor/admin/flux/dist/manifest.json');
|
|
|
|
if (! file_exists($manifestPath)) {
|
|
return substr(md5(config('app.version', '1.0')), 0, 8);
|
|
}
|
|
|
|
$manifest = json_decode(file_get_contents($manifestPath), true);
|
|
|
|
return $manifest[$key] ?? substr(md5(config('app.version', '1.0')), 0, 8);
|
|
}
|
|
|
|
/**
|
|
* Check if we should use CDN for Flux assets.
|
|
*
|
|
* Respects CDN_FORCE_LOCAL for testing.
|
|
*
|
|
* @return bool True if CDN should be used, false for local assets
|
|
*/
|
|
public function shouldUseCdn(): bool
|
|
{
|
|
return Cdn::isEnabled();
|
|
}
|
|
|
|
/**
|
|
* Build CDN URL for shared platform assets (no vBucket scoping).
|
|
*
|
|
* Flux assets are shared across all workspaces, so they don't use
|
|
* workspace-specific vBucket prefixes.
|
|
*
|
|
* @param string $path Asset path relative to CDN root
|
|
* @param string|null $version Optional version hash for cache busting
|
|
* @return string Full CDN URL with optional version query parameter
|
|
*/
|
|
protected function cdnUrl(string $path, ?string $version = null): string
|
|
{
|
|
$cdnUrl = config('cdn.urls.cdn');
|
|
|
|
if (empty($cdnUrl)) {
|
|
$baseUrl = asset($path);
|
|
|
|
return $this->urlBuilder->withVersion($baseUrl, $version);
|
|
}
|
|
|
|
$url = $this->urlBuilder->cdn($path);
|
|
|
|
return $this->urlBuilder->withVersion($url, $version);
|
|
}
|
|
|
|
/**
|
|
* Get the list of Flux files that should be uploaded to CDN.
|
|
*
|
|
* @return array<string, string> Map of source path => CDN path
|
|
*/
|
|
public function getCdnAssetPaths(): array
|
|
{
|
|
$basePath = Flux::pro()
|
|
? base_path('vendor/admin/flux-pro/dist')
|
|
: base_path('vendor/admin/flux/dist');
|
|
|
|
$files = [
|
|
"{$basePath}/flux.js" => 'flux/flux.js',
|
|
"{$basePath}/flux.min.js" => 'flux/flux.min.js',
|
|
];
|
|
|
|
// Add editor files for Pro
|
|
if (Flux::pro()) {
|
|
$files["{$basePath}/editor.js"] = 'flux/editor.js';
|
|
$files["{$basePath}/editor.min.js"] = 'flux/editor.min.js';
|
|
$files["{$basePath}/editor.css"] = 'flux/editor.css';
|
|
}
|
|
|
|
return $files;
|
|
}
|
|
}
|