Skip to content

Commit b4feee5

Browse files
committed
Merge branch 'feature/v2.5.0' into hawk/testing
2 parents 220f7f5 + a7c48fa commit b4feee5

659 files changed

Lines changed: 112945 additions & 14070 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ APP_FALLBACK_LOCALE="en_US"
5656
APP_FAKER_LOCALE="de_DE"
5757

5858
APP_KEY=
59-
APP_PREVIOS_KEYS=
59+
APP_PREVIOUS_KEYS=
6060

6161
APP_MAINTENANCE_DRIVER="cache"
6262
APP_MAINTENANCE_STORE="database"

.github/workflows/deploy-hawk-prod.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ jobs:
4444
target: app_prod
4545
tags: ${{ steps.meta.outputs.tags }}
4646
labels: ${{ steps.meta.outputs.labels }}
47+
build-args: |
48+
CACHE_BUSTER=${{ github.sha }}
4749
4850
deploy:
4951
runs-on: ubuntu-latest

.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,19 @@
88
node_modules
99
vendor
1010

11+
# Generated icons
12+
resources/js/components/ui/icons/iconset/*
13+
1114
# Credentials
1215
auth.json
1316

1417
# Editors
1518
.idea/*
1619
.fleet
1720
.vscode
21+
/.fleet
22+
/.idea
23+
/.vscode
1824

1925
# PHPUnit
2026
.phpunit.coverage
@@ -45,3 +51,10 @@ npm-debug.log
4551
yarn-error.log
4652
.DS_Store
4753
_architecture
54+
55+
# Dev Stuff
56+
DbgCommand.php
57+
_docker_production_test
58+
.devcontainer
59+
.agents
60+
skills-lock.json

.phpstorm.meta.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@
44

55
namespace PHPSTORM_META {
66

7+
use App\Services\System\Container\ServiceLocator;
8+
79
override(ServiceLocatorTrait::getService(0), type(0));
10+
override(ServiceLocator::get(0), type(0));
811
}

.vite/vitePluginCssLayers.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type {Plugin} from 'vite';
2+
3+
interface CssLayerEntry {
4+
path: string;
5+
layer: string;
6+
}
7+
8+
export function vitePluginCssLayers(entries: CssLayerEntry[]): Plugin {
9+
return {
10+
name: 'vite-plugin-css-layers',
11+
enforce: 'pre',
12+
transform(code, id) {
13+
const cleanId = id.split('?')[0];
14+
15+
if (!cleanId.endsWith('.css')) return null;
16+
17+
const match = entries.find(e => cleanId.endsWith(e.path));
18+
if (!match) return null;
19+
20+
return `@layer ${match.layer} {\n${code}\n}`;
21+
}
22+
};
23+
}

.vite/vitePluginHugeicons.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import type {Plugin} from 'vite';
2+
import {existsSync, mkdirSync, readFileSync, writeFileSync} from 'node:fs';
3+
import {resolve} from 'node:path';
4+
5+
// Bump this when the generated file template changes to force regeneration.
6+
const PLUGIN_VERSION = '1';
7+
8+
type IconData = readonly (readonly [string, Record<string, string | number>])[];
9+
10+
function iconsPkgVersion(): string {
11+
const pkgJson = JSON.parse(
12+
readFileSync(
13+
resolve(process.cwd(), 'node_modules/@hugeicons/core-free-icons/package.json'),
14+
'utf-8'
15+
)
16+
) as { version: string };
17+
return pkgJson.version;
18+
}
19+
20+
function needsRegeneration(outputDir: string): boolean {
21+
const markerPath = resolve(outputDir, '.gen-version');
22+
if (!existsSync(markerPath)) return true;
23+
const expected = `${iconsPkgVersion()}:${PLUGIN_VERSION}`;
24+
return readFileSync(markerPath, 'utf-8').trim() !== expected;
25+
}
26+
27+
function writeVersionMarker(outputDir: string): void {
28+
writeFileSync(
29+
resolve(outputDir, '.gen-version'),
30+
`${iconsPkgVersion()}:${PLUGIN_VERSION}`,
31+
'utf-8'
32+
);
33+
}
34+
35+
async function loadAllIcons(): Promise<Map<string, IconData>> {
36+
const pkg = await import('@hugeicons/core-free-icons') as Record<string, unknown>;
37+
const icons = new Map<string, IconData>();
38+
for (const [name, data] of Object.entries(pkg)) {
39+
if (name.endsWith('Icon') && Array.isArray(data)) {
40+
icons.set(name, data as IconData);
41+
}
42+
}
43+
return icons;
44+
}
45+
46+
function stripReactKey(data: IconData): unknown[][] {
47+
return data.map(([tag, attrs]) => {
48+
const {key: _key, ...rest} = attrs as Record<string, unknown>;
49+
return [tag, rest];
50+
});
51+
}
52+
53+
function generateSvelteFile(data: IconData): string {
54+
return `<!-- Auto-generated by vitePluginHugeicons — do not edit. -->
55+
<script lang="ts">
56+
import {HugeiconsIcon, type HugeiconsProps, type IconSvgElement} from '@hugeicons/svelte';
57+
const iconData:IconSvgElement = ${JSON.stringify(stripReactKey(data))};
58+
let {...props}: HugeiconsProps = $props();
59+
</script>
60+
<HugeiconsIcon icon={iconData} strokeWidth={2} {...props} />
61+
`;
62+
}
63+
64+
export function vitePluginHugeicons(outputDir: string): Plugin {
65+
async function generate() {
66+
if (!needsRegeneration(outputDir)) return;
67+
68+
mkdirSync(outputDir, {recursive: true});
69+
const icons = await loadAllIcons();
70+
71+
for (const [name, data] of icons) {
72+
writeFileSync(resolve(outputDir, `${name}.svelte`), generateSvelteFile(data), 'utf-8');
73+
}
74+
75+
writeVersionMarker(outputDir);
76+
}
77+
78+
return {
79+
name: 'vite-plugin-hugeicons',
80+
async buildStart() {
81+
await generate();
82+
},
83+
configureServer() {
84+
void generate();
85+
}
86+
};
87+
}

_changelog/next-upgrade.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,73 @@ FILE_CONVERTER_BINARY_GHOSTSCRIPT=/path/to/gs
7373
## 2. Remove no longer required env variables:
7474

7575
In this version we introduced a better solution to propagate the "reverb" (websocket) configuration to the frontend. Therefore the values must no longer be available at build time. For you, there is no need to intervene, but you probably like your `.env` file to be clean and tidy, so you can remove the `VITE_REVERB_*` variables from there.
76+
77+
## 3. Upgrade PHP to 8.3
78+
79+
The minimum PHP version is now **8.3** (raised from 8.2). Before deploying, ensure your host or Docker base image provides it.
80+
81+
> **Note:** If you are running HAWKI in Docker, the official image (`neunerlei/php-nginx:8.3`) is already updated and no further action is needed.
82+
83+
The following PHP extensions are now explicitly required — enable them if they are not already active on your server:
84+
85+
```
86+
curl, dom, fileinfo, libxml, openssl, zip, gd
87+
```
88+
89+
## 4. Configure encryption salts before migrating
90+
91+
This version introduces five application-level encryption salts. These **must be set in your `.env` before running `php artisan migrate`** — if they are missing, `SaltProvider` will auto-generate them at runtime, but the values will differ on every boot, permanently breaking any data encrypted with the previous values.
92+
93+
Generate each salt with `openssl rand -base64 32` and add them to your `.env`:
94+
95+
```
96+
APP_ENCRYPTION_SALT_USERDATA=
97+
APP_ENCRYPTION_SALT_INVITATION=
98+
APP_ENCRYPTION_SALT_AI_CRYPTO=
99+
APP_ENCRYPTION_SALT_PASSKEY=
100+
APP_ENCRYPTION_SALT_BACKUP=
101+
```
102+
103+
> **Note:** If you are running HAWKI in Docker, these salts must also be present in `_docker_production/.env` before the first container start after upgrading.
104+
105+
## 5. Run all database migrations
106+
107+
This version introduces many new tables. After setting the salts above, run:
108+
109+
```bash
110+
php artisan migrate
111+
```
112+
113+
## 6. Sync AI tools, MCP servers, and model config into the database
114+
115+
AI tools and MCP servers have been migrated from static configuration files to database-backed models. After migrating, populate them from your existing configuration:
116+
117+
```bash
118+
php artisan ai:tools:sync
119+
php artisan ai:config:sync
120+
```
121+
122+
## 7. Update custom code referencing removed classes
123+
124+
The following classes have been removed. Update any custom code that references them:
125+
126+
| Removed | Replacement |
127+
|---|---|
128+
| `FileConverterFactory` | Inject `FileConverterInterface` directly; call `isAvailable()` to check if a converter is configured |
129+
| `AttachmentService` / `AttachmentFactory` | `AttachmentRepository` |
130+
| `MessageHandlerFactory` | Resolve `PrivateMessageHandler` / `GroupMessageHandler` from the Laravel service container |
131+
| `ExternalCommunicationCheck` middleware | `ExternalAccessMiddleware` or `AppAccessMiddleware` — configure feature toggles in `config/external_access.php` |
132+
133+
## 8. Update custom code reading `AiModel` attributes
134+
135+
The following `AiModel` attributes now return **typed value objects** instead of raw arrays or strings. Any code reading them with direct array access must be updated to use the value object API:
136+
137+
`input`, `output`, `parameters`, `status`, `demand`, `capabilities`, `settings`
138+
139+
## 9. Update custom storage service calls
140+
141+
All method signatures on `FileStorageService` and `AvatarStorageService` have changed as part of the storage layer overhaul. Any custom code calling these services directly must be updated to use the new API.
142+
143+
## 10. Update custom AI provider implementations
144+
145+
If you have custom AI provider implementations, they must now implement `ProviderAdapterInterface` and be registered with `ProviderAdapterRegistry`. The previous inheritance-based approach is no longer supported.

0 commit comments

Comments
 (0)