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

View File

@@ -57,15 +57,15 @@ return [
'per_tenant' => false,
// ── 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,
// 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',
// ── 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',
// openlog() facility constant. Common values: LOG_USER, LOG_LOCAL0 … LOG_LOCAL7

View File

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

View File

@@ -20,8 +20,10 @@ class PlainFileLogger implements LoggerInterface
*/
public function __construct(string $logDir, string $channel = 'app')
{
if (!is_dir($logDir)) {
@mkdir($logDir, 0775, true);
}
$this->logFile = rtrim($logDir, '/') . '/' . $channel . '.log';
$this->ensureWritablePath();
}
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
{
$this->ensureWritablePath();
$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');
$line = $timestamp . ' ' . $this->interpolate((string) $message, $context) . PHP_EOL;
if (@file_put_contents($this->logFile, $line, FILE_APPEND | LOCK_EX) === false) {
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);
}
@file_put_contents($this->logFile, $line, FILE_APPEND | LOCK_EX);
}
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/poppins": "5.2.7",
"@fontsource/public-sans": "5.2.7",
"@fontsource/roboto": "5.2.10",
"@fontsource/roboto": "5.2.9",
"@mdi/font": "7.4.47",
"@tsconfig/node24": "24.0.4",
"@typescript-eslint/parser": "^8.55.0",
@@ -34,30 +34,30 @@
"vee-validate": "^4.15.1",
"vite-plugin-vuetify": "2.1.3",
"vue": "3.5.28",
"vue-router": "5.0.6",
"vue-router": "5.0.2",
"vue3-perfect-scrollbar": "2.0.0",
"vuetify": "4.0.6"
"vuetify": "3.11.8"
},
"devDependencies": {
"@eslint/js": "^10.0.0",
"@eslint/js": "^9.18.0",
"@types/dompurify": "^3.2.0",
"@types/node": "25.6.0",
"@vitejs/plugin-vue": "6.0.6",
"@types/node": "25.2.3",
"@vitejs/plugin-vue": "6.0.4",
"@vitest/coverage-v8": "^4.0.18",
"@vitest/ui": "^4.0.18",
"@vue/eslint-config-prettier": "10.2.0",
"@vue/test-utils": "^2.4.8",
"@vue/tsconfig": "0.9.1",
"eslint": "^10.0.0",
"eslint-plugin-vue": "10.9.1",
"jsdom": "^29.0.0",
"prettier": "3.8.3",
"sass": "1.99.0",
"@vue/tsconfig": "0.8.1",
"eslint": "^9.39.4",
"eslint-plugin-vue": "10.7.0",
"jsdom": "^28.1.0",
"prettier": "3.8.1",
"sass": "1.97.3",
"sass-loader": "16.0.7",
"typescript": "6.0.3",
"typescript": "5.9.3",
"typescript-eslint": "^8.59.0",
"vite": "8.0.10",
"vite-plugin-static-copy": "^4.0.0",
"vite-plugin-static-copy": "^3.4.0",
"vitest": "^4.0.18",
"vue-cli-plugin-vuetify": "2.5.8",
"vue-tsc": "^3.2.7"

View File

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

View File

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

View File

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

View File

@@ -68,10 +68,11 @@ interface ServiceCollectionMutableInterface extends ServiceBaseInterface {
*
* @param string|int $identifier Collection ID
* @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

View File

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