refactor(admin/invites): regenerate types; remove InviteListItem cast
All checks were successful
CI / Unit & Component Tests (pull_request) Successful in 3m20s
CI / OCR Service Tests (pull_request) Successful in 22s
CI / Backend Unit Tests (pull_request) Successful in 3m17s
CI / fail2ban Regex (pull_request) Successful in 41s
CI / Semgrep Security Scan (pull_request) Successful in 20s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m0s

After adding @Schema(requiredMode=REQUIRED) to InviteListItemDTO.shareableUrl,
npm run generate:api now emits shareableUrl as required. Replace the hand-rolled
InviteListItem interface with a type alias to the generated InviteListItemDTO
and remove the two 'as unknown as InviteListItem' casts + TODO comments.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-19 13:22:32 +02:00
parent 49ac1984dd
commit 6cfb1899a1
2 changed files with 130 additions and 26 deletions

View File

@@ -180,6 +180,22 @@ export interface paths {
patch?: never;
trace?: never;
};
"/api/users/{id}/force-logout": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
post: operations["forceLogout"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/users/me/password": {
parameters: {
query?: never;
@@ -580,6 +596,38 @@ export interface paths {
patch?: never;
trace?: never;
};
"/api/auth/logout": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
post: operations["logout"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/auth/login": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
post: operations["login"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/auth/forgot-password": {
parameters: {
query?: never;
@@ -1849,7 +1897,7 @@ export interface components {
status: string;
/** Format: date-time */
createdAt: string;
shareableUrl?: string;
shareableUrl: string;
};
GroupDTO: {
name?: string;
@@ -2011,13 +2059,17 @@ export interface components {
lastName?: string;
notifyOnMention?: boolean;
};
LoginRequest: {
email?: string;
password?: string;
};
ForgotPasswordRequest: {
email?: string;
};
ImportStatus: {
/** @enum {string} */
state?: "IDLE" | "RUNNING" | "DONE" | "FAILED";
message?: string;
statusCode?: string;
/** Format: int32 */
processed?: number;
/** Format: date-time */
@@ -2255,14 +2307,14 @@ export interface components {
/** Format: int32 */
totalPages?: number;
pageable?: components["schemas"]["PageableObject"];
first?: boolean;
last?: boolean;
/** Format: int32 */
size?: number;
content?: components["schemas"]["NotificationDTO"][];
/** Format: int32 */
number?: number;
sort?: components["schemas"]["SortObject"];
first?: boolean;
last?: boolean;
/** Format: int32 */
numberOfElements?: number;
empty?: boolean;
@@ -2410,7 +2462,7 @@ export interface components {
};
ActivityFeedItemDTO: {
/** @enum {string} */
kind: "FILE_UPLOADED" | "STATUS_CHANGED" | "METADATA_UPDATED" | "TEXT_SAVED" | "BLOCK_REVIEWED" | "ANNOTATION_CREATED" | "COMMENT_ADDED" | "MENTION_CREATED" | "USER_CREATED" | "USER_DELETED" | "GROUP_MEMBERSHIP_CHANGED";
kind: "FILE_UPLOADED" | "STATUS_CHANGED" | "METADATA_UPDATED" | "TEXT_SAVED" | "BLOCK_REVIEWED" | "ANNOTATION_CREATED" | "COMMENT_ADDED" | "MENTION_CREATED" | "USER_CREATED" | "USER_DELETED" | "GROUP_MEMBERSHIP_CHANGED" | "LOGIN_SUCCESS" | "LOGIN_FAILED" | "LOGOUT" | "ADMIN_FORCE_LOGOUT" | "LOGIN_RATE_LIMITED";
actor?: components["schemas"]["ActivityActorDTO"];
/** Format: uuid */
documentId: string;
@@ -2954,6 +3006,30 @@ export interface operations {
};
};
};
forceLogout: {
parameters: {
query?: never;
header?: never;
path: {
id: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": {
[key: string]: unknown;
};
};
};
};
};
changePassword: {
parameters: {
query?: never;
@@ -3547,6 +3623,7 @@ export interface operations {
query?: never;
header?: never;
path: {
documentId: string;
blockId: string;
};
cookie?: never;
@@ -3597,6 +3674,7 @@ export interface operations {
header?: never;
path: {
documentId: string;
blockId: string;
commentId: string;
};
cookie?: never;
@@ -3791,6 +3869,48 @@ export interface operations {
};
};
};
logout: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
login: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["LoginRequest"];
};
};
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": components["schemas"]["AppUser"];
};
};
};
};
forgotPassword: {
parameters: {
query?: never;
@@ -4985,7 +5105,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": components["schemas"]["DocumentDensityResult"];
"application/json": components["schemas"]["DocumentDensityResult"];
};
};
};
@@ -5061,7 +5181,7 @@ export interface operations {
query?: {
limit?: number;
/** @description Filter by audit kinds; omit for all rollup-eligible kinds */
kinds?: ("FILE_UPLOADED" | "STATUS_CHANGED" | "METADATA_UPDATED" | "TEXT_SAVED" | "BLOCK_REVIEWED" | "ANNOTATION_CREATED" | "COMMENT_ADDED" | "MENTION_CREATED" | "USER_CREATED" | "USER_DELETED" | "GROUP_MEMBERSHIP_CHANGED")[];
kinds?: ("FILE_UPLOADED" | "STATUS_CHANGED" | "METADATA_UPDATED" | "TEXT_SAVED" | "BLOCK_REVIEWED" | "ANNOTATION_CREATED" | "COMMENT_ADDED" | "MENTION_CREATED" | "USER_CREATED" | "USER_DELETED" | "GROUP_MEMBERSHIP_CHANGED" | "LOGIN_SUCCESS" | "LOGIN_FAILED" | "LOGOUT" | "ADMIN_FORCE_LOGOUT" | "LOGIN_RATE_LIMITED")[];
};
header?: never;
path?: never;

View File

@@ -4,21 +4,7 @@ import { getErrorMessage } from '$lib/shared/errors';
import type { Actions, PageServerLoad } from './$types';
import type { components } from '$lib/generated/api';
// The spec marks shareableUrl optional but the backend always populates it.
// Keeping the required shape here avoids null-guarding throughout the page component.
export interface InviteListItem {
id: string;
code: string;
displayCode: string;
label?: string;
useCount: number;
maxUses?: number;
expiresAt?: string;
revoked: boolean;
status: string;
createdAt: string;
shareableUrl: string;
}
export type InviteListItem = components['schemas']['InviteListItemDTO'];
export type UserGroup = components['schemas']['UserGroup'];
const VALID_STATUSES = ['ACTIVE', 'REVOKED', 'EXPIRED'] as const;
@@ -42,8 +28,7 @@ export const load: PageServerLoad = async ({ url, fetch }) => {
const code = (invitesResult.error as unknown as { code?: string })?.code;
loadError = code ?? 'INTERNAL_ERROR';
} else {
// TODO: remove cast after next npm run generate:api — shareableUrl is now @Schema(requiredMode=REQUIRED)
invites = (invitesResult.data ?? []) as unknown as InviteListItem[];
invites = (invitesResult.data ?? []) as InviteListItem[];
}
let groups: UserGroup[] = [];
@@ -81,8 +66,7 @@ export const actions = {
return fail(result.response.status, { createError: code ?? 'INTERNAL_ERROR' });
}
// TODO: remove cast after next npm run generate:api — shareableUrl is now @Schema(requiredMode=REQUIRED)
return { created: result.data! as unknown as InviteListItem };
return { created: result.data! as InviteListItem };
},
revoke: async ({ request, fetch }) => {