feat(260925-bow): gesehene Version pro Benutzer merken - Spalte, Versionsfunktionen, API
- packages/shared: parseReleaseVersion, compareReleaseVersions, ReleaseNoticeResponse - getRunningRelease(): einzige Quelle der laufenden Version (APP_VERSION der API) - User.lastSeenReleaseVersion (nullbar, Migration 20260925120000) - GET /users/me/release-notice, POST /users/me/release-seen (gebunden an Benutzer und Mandant) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -93,6 +93,11 @@ export interface DesktopLatestResponse {
|
||||
* das native Type-Stripping von Node 24. Deshalb darf diese Datei nur
|
||||
* loeschbare Syntax enthalten — keine `enum`, kein `namespace`, keine
|
||||
* Parameter-Eigenschaften.
|
||||
*
|
||||
* Der zweite Laufzeit-Import sind `parseReleaseVersion`/`compareReleaseVersions`
|
||||
* weiter unten (quick-260925-bow) — dieselbe Regel gilt dort, und neue
|
||||
* Laufzeit-Funktionen gehoeren direkt in diese Datei (CJS-`require` findet
|
||||
* relative Importe ohne `.ts`-Endung nicht).
|
||||
*/
|
||||
export const WIDGET_TYPES = [
|
||||
'clock',
|
||||
@@ -123,3 +128,69 @@ export type WidgetType = (typeof WIDGET_TYPES)[number];
|
||||
export const WIDGET_MODULE_SLUGS: Partial<Record<WidgetType, string>> = {
|
||||
proxmox: 'proxmox',
|
||||
};
|
||||
|
||||
/**
|
||||
* Freigegebene Versionen (quick-260925-bow, D-02/D-06) — EINE Implementierung
|
||||
* fuer API und Web ("Was ist neu"-Fenster nach einem Versionswechsel).
|
||||
*
|
||||
* Laufzeit-Import aus `@tessera/shared` (siehe Warnkommentar ueber
|
||||
* `WIDGET_TYPES`): nur loeschbare Syntax, keine relativen Importe.
|
||||
*
|
||||
* Angenommen werden genau: optionales `v`, drei Zifferngruppen zu je 1 bis 6
|
||||
* Ziffern, optional der Describe-Anhang von `git describe`
|
||||
* (`-<Anzahl>-g<4 bis 40 Hex-Zeichen>`). Alles andere ist KEINE freigegebene
|
||||
* Version: `dev`, ein blosser Commit-Stempel, Vorabversionen wie `-rc.1`,
|
||||
* `-dirty`, Leerzeichen am Rand (kein Trimmen). Eingaben ueber 64 Zeichen
|
||||
* werden vor dem Muster abgewiesen; der Ausdruck ist verankert und hat keine
|
||||
* verschachtelten Wiederholungen.
|
||||
*/
|
||||
const RELEASE_VERSION_PATTERN = /^v?(\d{1,6})\.(\d{1,6})\.(\d{1,6})(?:-\d{1,6}-g[0-9a-f]{4,40})?$/;
|
||||
|
||||
const RELEASE_VERSION_MAX_LENGTH = 64;
|
||||
|
||||
/**
|
||||
* Liefert die kanonische Form `X.Y.Z` (ohne `v`, ohne fuehrende Nullen) oder
|
||||
* `null`, wenn die Eingabe keine freigegebene Version ist.
|
||||
* Beispiel: `v10.2.3-5-gabc1234` → `10.2.3`, `dev` → `null`.
|
||||
*/
|
||||
export function parseReleaseVersion(raw: string): string | null {
|
||||
if (typeof raw !== 'string' || raw.length > RELEASE_VERSION_MAX_LENGTH) {
|
||||
return null;
|
||||
}
|
||||
const match = RELEASE_VERSION_PATTERN.exec(raw);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
return `${Number(match[1])}.${Number(match[2])}.${Number(match[3])}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Numerischer Vergleich zweier freigegebener Versionen: -1, 0 oder 1.
|
||||
* `1.10.0` liegt ueber `1.9.0`. Wirft, wenn eine Seite nicht parsebar ist —
|
||||
* Aufrufer pruefen vorher mit `parseReleaseVersion`.
|
||||
*/
|
||||
export function compareReleaseVersions(a: string, b: string): number {
|
||||
const left = parseReleaseVersion(a);
|
||||
const right = parseReleaseVersion(b);
|
||||
if (left === null || right === null) {
|
||||
throw new Error(`Keine freigegebene Version: ${left === null ? a : b}`);
|
||||
}
|
||||
const l = left.split('.').map(Number);
|
||||
const r = right.split('.').map(Number);
|
||||
for (let i = 0; i < 3; i++) {
|
||||
if (l[i] > r[i]) return 1;
|
||||
if (l[i] < r[i]) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Antwort von `GET /users/me/release-notice` (quick-260925-bow).
|
||||
* `currentRelease` ist die laufende freigegebene Version der API
|
||||
* (`getRunningRelease()`, `null` auf `dev`-Staenden), `lastSeenReleaseVersion`
|
||||
* der gemerkte Stand des angemeldeten Benutzers (`null` = Bestandsbenutzer).
|
||||
*/
|
||||
export interface ReleaseNoticeResponse {
|
||||
currentRelease: string | null;
|
||||
lastSeenReleaseVersion: string | null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user