Files
feuerwerk/api/lib/PluginStore.php
T
2026-09-17 19:00:03 +02:00

53 lines
1.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
/**
* The editor plugins in `data/plugins/`: one ES module per `.js` file, and every file there is
* active. Read-only for now – putting a file there is done by hand, by the build and by the e2e
* seeder. The folder is not served statically: a module is only ever handed out by its bare file
* name, so no request can reach past it.
*/
final class PluginStore
{
public function __construct(private readonly string $dir)
{
}
/** A file name as it may be asked for: no path, no leading dot, `.js` at the end. */
public static function isValidName(string $name): bool
{
return (bool) preg_match('/^[A-Za-z0-9][A-Za-z0-9._-]*\.js$/', $name);
}
/**
* Sorted by file name, which is also the order the editor activates them in.
*
* @return list<array{file: string, bytes: int, updatedAt: int}>
*/
public function list(): array
{
$files = is_dir($this->dir) ? scandir($this->dir) : [];
$out = [];
foreach ($files === false ? [] : $files as $file) {
$path = "{$this->dir}/{$file}";
if (!self::isValidName($file) || !is_file($path)) {
continue;
}
$out[] = ['file' => $file, 'bytes' => (int) filesize($path), 'updatedAt' => (int) filemtime($path)];
}
usort($out, static fn (array $a, array $b): int => strcmp($a['file'], $b['file']));
return $out;
}
/** The module's source, or null when there is no such plugin. */
public function read(string $file): ?string
{
$path = "{$this->dir}/{$file}";
if (!self::isValidName($file) || !is_file($path)) {
return null;
}
$source = file_get_contents($path);
return $source === false ? null : $source;
}
}