1 Commits

Author SHA1 Message Date
acf0e62a73 chore(deps): update dependency vite to v8
All checks were successful
JS Unit Tests / test (pull_request) Successful in 20s
Build Test / build (pull_request) Successful in 23s
PHP Unit Tests / test (pull_request) Successful in 1m26s
2026-04-25 20:06:18 +00:00
11 changed files with 542 additions and 314 deletions

24
composer.lock generated
View File

@@ -393,16 +393,16 @@
}, },
{ {
"name": "phpseclib/phpseclib", "name": "phpseclib/phpseclib",
"version": "3.0.52", "version": "3.0.51",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpseclib/phpseclib.git", "url": "https://github.com/phpseclib/phpseclib.git",
"reference": "2adaefc83df2ec548558307690f376dd7d4f4fce" "reference": "d59c94077f9c9915abb51ddb52ce85188ece1748"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/2adaefc83df2ec548558307690f376dd7d4f4fce", "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/d59c94077f9c9915abb51ddb52ce85188ece1748",
"reference": "2adaefc83df2ec548558307690f376dd7d4f4fce", "reference": "d59c94077f9c9915abb51ddb52ce85188ece1748",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -483,7 +483,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/phpseclib/phpseclib/issues", "issues": "https://github.com/phpseclib/phpseclib/issues",
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.52" "source": "https://github.com/phpseclib/phpseclib/tree/3.0.51"
}, },
"funding": [ "funding": [
{ {
@@ -499,7 +499,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-04-27T07:02:15+00:00" "time": "2026-04-10T01:33:53+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",
@@ -606,16 +606,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v7.4.9", "version": "v7.4.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "d7d2b64a45a89d607865927b176fa51c33ddbb58" "reference": "1e92e39c51f95b88e3d66fa2d9f06d1fb45dd707"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/d7d2b64a45a89d607865927b176fa51c33ddbb58", "url": "https://api.github.com/repos/symfony/console/zipball/1e92e39c51f95b88e3d66fa2d9f06d1fb45dd707",
"reference": "d7d2b64a45a89d607865927b176fa51c33ddbb58", "reference": "1e92e39c51f95b88e3d66fa2d9f06d1fb45dd707",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -680,7 +680,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v7.4.9" "source": "https://github.com/symfony/console/tree/v7.4.8"
}, },
"funding": [ "funding": [
{ {
@@ -700,7 +700,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-04-22T15:21:55+00:00" "time": "2026-03-30T13:54:39+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",

View File

@@ -57,15 +57,15 @@ return [
'per_tenant' => false, 'per_tenant' => false,
// ── file driver options ──────────────────────────────────────────────── // ── file driver options ────────────────────────────────────────────────
// Absolute path to the log directory. null = <project_root>/var/logs // Absolute path to the log directory. null = <project_root>/var/log
'path' => null, 'path' => null,
// Log channel — used as the filename without extension. // Log channel — used as the filename without extension.
// 'app' → var/logs/app.jsonl (or var/logs/tenant/{id}/app.jsonl when per_tenant = true) // 'app' → var/log/app.jsonl (or var/log/tenant/{id}/app.jsonl when per_tenant = true)
'channel' => 'app', 'channel' => 'app',
// ── syslog driver options ────────────────────────────────────────────── // ── syslog driver options ──────────────────────────────────────────────
// Identity tag passed to openlog(); visible in /var/logs/syslog and journalctl -t ktrix // Identity tag passed to openlog(); visible in /var/log/syslog and journalctl -t ktrix
'ident' => 'ktrix', 'ident' => 'ktrix',
// openlog() facility constant. Common values: LOG_USER, LOG_LOCAL0 … LOG_LOCAL7 // openlog() facility constant. Common values: LOG_USER, LOG_LOCAL0 … LOG_LOCAL7

View File

@@ -79,7 +79,7 @@ class LoggerFactory
$path = $logConfig['path'] ?? null; $path = $logConfig['path'] ?? null;
if ($path === null || $path === '') { if ($path === null || $path === '') {
$path = $projectDir . '/var/logs'; $path = $projectDir . '/var/log';
} }
return new FileLogger($path, $channel); return new FileLogger($path, $channel);

View File

@@ -20,8 +20,10 @@ class PlainFileLogger implements LoggerInterface
*/ */
public function __construct(string $logDir, string $channel = 'app') public function __construct(string $logDir, string $channel = 'app')
{ {
if (!is_dir($logDir)) {
@mkdir($logDir, 0775, true);
}
$this->logFile = rtrim($logDir, '/') . '/' . $channel . '.log'; $this->logFile = rtrim($logDir, '/') . '/' . $channel . '.log';
$this->ensureWritablePath();
} }
public function emergency($message, array $context = []): void { $this->log('emergency', $message, $context); } public function emergency($message, array $context = []): void { $this->log('emergency', $message, $context); }
@@ -35,38 +37,12 @@ class PlainFileLogger implements LoggerInterface
public function log($level, $message, array $context = []): void public function log($level, $message, array $context = []): void
{ {
$this->ensureWritablePath();
$dt = \DateTimeImmutable::createFromFormat('U.u', sprintf('%.6F', microtime(true))); $dt = \DateTimeImmutable::createFromFormat('U.u', sprintf('%.6F', microtime(true)));
$timestamp = $dt?->format('Y-m-d H:i:s.u') ?? date('Y-m-d H:i:s'); $timestamp = $dt?->format('Y-m-d H:i:s.u') ?? date('Y-m-d H:i:s');
$line = $timestamp . ' ' . $this->interpolate((string) $message, $context) . PHP_EOL; $line = $timestamp . ' ' . $this->interpolate((string) $message, $context) . PHP_EOL;
if (@file_put_contents($this->logFile, $line, FILE_APPEND | LOCK_EX) === false) { @file_put_contents($this->logFile, $line, FILE_APPEND | LOCK_EX);
error_log(sprintf('Failed to write to log file: %s', $this->logFile));
}
}
private function ensureWritablePath(): void
{
$logDir = dirname($this->logFile);
if (!is_dir($logDir)) {
@mkdir($logDir, 0777, true);
}
if (is_dir($logDir)) {
@chmod($logDir, 0777);
}
if (!file_exists($this->logFile)) {
@touch($this->logFile);
}
clearstatcache(true, $this->logFile);
if (file_exists($this->logFile)) {
@chmod($this->logFile, 0666);
}
} }
private function interpolate(string $message, array $context): string private function interpolate(string $message, array $context): string

739
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,7 @@
"@fontsource/inter": "5.2.8", "@fontsource/inter": "5.2.8",
"@fontsource/poppins": "5.2.7", "@fontsource/poppins": "5.2.7",
"@fontsource/public-sans": "5.2.7", "@fontsource/public-sans": "5.2.7",
"@fontsource/roboto": "5.2.10", "@fontsource/roboto": "5.2.9",
"@mdi/font": "7.4.47", "@mdi/font": "7.4.47",
"@tsconfig/node24": "24.0.4", "@tsconfig/node24": "24.0.4",
"@typescript-eslint/parser": "^8.55.0", "@typescript-eslint/parser": "^8.55.0",
@@ -34,30 +34,30 @@
"vee-validate": "^4.15.1", "vee-validate": "^4.15.1",
"vite-plugin-vuetify": "2.1.3", "vite-plugin-vuetify": "2.1.3",
"vue": "3.5.28", "vue": "3.5.28",
"vue-router": "5.0.6", "vue-router": "5.0.2",
"vue3-perfect-scrollbar": "2.0.0", "vue3-perfect-scrollbar": "2.0.0",
"vuetify": "4.0.6" "vuetify": "3.11.8"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^10.0.0", "@eslint/js": "^9.18.0",
"@types/dompurify": "^3.2.0", "@types/dompurify": "^3.2.0",
"@types/node": "25.6.0", "@types/node": "25.2.3",
"@vitejs/plugin-vue": "6.0.6", "@vitejs/plugin-vue": "6.0.4",
"@vitest/coverage-v8": "^4.0.18", "@vitest/coverage-v8": "^4.0.18",
"@vitest/ui": "^4.0.18", "@vitest/ui": "^4.0.18",
"@vue/eslint-config-prettier": "10.2.0", "@vue/eslint-config-prettier": "10.2.0",
"@vue/test-utils": "^2.4.8", "@vue/test-utils": "^2.4.8",
"@vue/tsconfig": "0.9.1", "@vue/tsconfig": "0.8.1",
"eslint": "^10.0.0", "eslint": "^9.39.4",
"eslint-plugin-vue": "10.9.1", "eslint-plugin-vue": "10.7.0",
"jsdom": "^29.0.0", "jsdom": "^28.1.0",
"prettier": "3.8.3", "prettier": "3.8.1",
"sass": "1.99.0", "sass": "1.97.3",
"sass-loader": "16.0.7", "sass-loader": "16.0.7",
"typescript": "6.0.3", "typescript": "5.9.3",
"typescript-eslint": "^8.59.0", "typescript-eslint": "^8.59.0",
"vite": "8.0.10", "vite": "8.0.10",
"vite-plugin-static-copy": "^4.0.0", "vite-plugin-static-copy": "^3.4.0",
"vitest": "^4.0.18", "vitest": "^4.0.18",
"vue-cli-plugin-vuetify": "2.5.8", "vue-cli-plugin-vuetify": "2.5.8",
"vue-tsc": "^3.2.7" "vue-tsc": "^3.2.7"

View File

@@ -1,9 +1,15 @@
{ {
"$schema": "https://docs.renovatebot.com/renovate-schema.json", "$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"], "extends": [
"enabledManagers": ["npm", "composer", "github-actions"], "config:recommended"
"timezone": "UTC", ],
"schedule": ["* 0-3 * * *"], "enabledManagers": [
"npm",
"composer"
],
"schedule": [
"before 3am"
],
"dependencyDashboard": true, "dependencyDashboard": true,
"prConcurrentLimit": 5, "prConcurrentLimit": 5,
"prHourlyLimit": 2 "prHourlyLimit": 2

View File

@@ -20,7 +20,6 @@ use JsonSerializable;
*/ */
enum CollectionRoles: string implements JsonSerializable { enum CollectionRoles: string implements JsonSerializable {
case None = '';
case Inbox = 'inbox'; case Inbox = 'inbox';
case Drafts = 'drafts'; case Drafts = 'drafts';
case Sent = 'sent'; case Sent = 'sent';
@@ -29,6 +28,7 @@ enum CollectionRoles: string implements JsonSerializable {
case Archive = 'archive'; case Archive = 'archive';
case Outbox = 'outbox'; case Outbox = 'outbox';
case Queue = 'queue'; case Queue = 'queue';
case Custom = 'custom';
public function jsonSerialize(): string { public function jsonSerialize(): string {
return $this->value; return $this->value;

View File

@@ -38,7 +38,6 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface {
// Collection Filter // Collection Filter
public const CAPABILITY_COLLECTION_FILTER_LABEL = 'label'; public const CAPABILITY_COLLECTION_FILTER_LABEL = 'label';
public const CAPABILITY_COLLECTION_FILTER_ROLE = 'role'; public const CAPABILITY_COLLECTION_FILTER_ROLE = 'role';
public const CAPABILITY_COLLECTION_FILTER_SUBSCRIBED = 'subscribed';
// Collection Sort // Collection Sort
public const CAPABILITY_COLLECTION_SORT_LABEL = 'label'; public const CAPABILITY_COLLECTION_SORT_LABEL = 'label';
public const CAPABILITY_COLLECTION_SORT_RANK = 'rank'; public const CAPABILITY_COLLECTION_SORT_RANK = 'rank';

View File

@@ -68,10 +68,11 @@ interface ServiceCollectionMutableInterface extends ServiceBaseInterface {
* *
* @param string|int $identifier Collection ID * @param string|int $identifier Collection ID
* @param bool $force Force deletion even if not empty * @param bool $force Force deletion even if not empty
* @param bool $recursive Recursively delete contents
* *
* @return CollectionBaseInterface|true Collection object on soft delete, true on hard delete * @return bool True if deleted
*/ */
public function collectionDelete(string|int $identifier, bool $force = false): CollectionBaseInterface | true; public function collectionDelete(string|int $identifier, bool $force = false, bool $recursive = false): bool;
/** /**
* Moves a collection to a new parent * Moves a collection to a new parent

View File

@@ -47,8 +47,7 @@ export default defineConfig(({ mode }) => ({
targets: [ targets: [
{ {
src: path.resolve(__dirname, 'core/lib/index.php'), src: path.resolve(__dirname, 'core/lib/index.php'),
dest: '.', dest: path.resolve(__dirname, 'public'),
rename: { stripBase: true },
}, },
], ],
}), }),