feat(16.3-01): account token API with OpenAPI and phrase keys

- Add list/create/revoke/scopes handlers, validation, and soft revoke
- Regenerate admin OpenAPI and TS types; inventory and conformance cases
- Add server-side api_tokens phrase keys (en/pl)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-11 01:51:11 +02:00
parent 183583e0e9
commit ffdb5d00ca
13 changed files with 1430 additions and 49 deletions

View File

@@ -14,7 +14,7 @@ export interface paths {
get?: never;
/**
* Update my account
* @description Saves the signed-in admin's own first name, last name, email and subtitle; the row is the token subject, never a request value. Only the AdminAccountRequest keys are accepted: any other key (login, role_id, is_superuser, permissions, is_activated, id) is a 422 on that key and nothing is written. The email must be valid, 6 to 255 characters, and not equal (ignoring case) the email or login of another admin. A non-empty password needs current_password, at least 4 characters, at most 72 bytes and an equal password_confirmation; it ends every other session, and a cookie session receives a fresh cookie.
* @description Saves the signed-in admin's own first name, last name, email and subtitle; the row is the token subject, never a request value. Only the AdminAccountRequest keys are accepted: any other key (login, role_id, is_superuser, permissions, is_activated, id) is a 422 on that key and nothing is written. The email must be valid, 6 to 255 characters, and not equal (ignoring case) the email or login of another admin. A non-empty password needs current_password, at least 4 characters, at most 72 bytes and an equal password_confirmation; it ends every other session, and a cookie session receives a fresh cookie. Personal API tokens are refused (403 interactive_only).
*/
put: {
parameters: {
@@ -210,6 +210,247 @@ export interface paths {
patch?: never;
trace?: never;
};
"/account/tokens": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* List my API tokens
* @description Lists the signed-in admin's personal API tokens, newest first. Revoked tokens are hidden unless revoked=1. Personal API tokens are refused (403 interactive_only).
*/
get: {
parameters: {
query?: {
/** @description Include revoked tokens when 1 or true */
revoked?: string;
};
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["cabana.Envelope-array_cabana_AdminAPIToken"];
};
};
/** @description Unauthorized */
401: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
};
};
/** @description Forbidden */
403: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
};
};
};
};
put?: never;
/**
* Create an API token
* @description Creates a personal API token for the signed-in admin. The plaintext token is returned exactly once in the 201 body. Personal API tokens are refused (403 interactive_only).
*/
post: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** @description Name, expiry and scopes */
requestBody: {
content: {
"application/json": components["schemas"]["cabana.AdminAPITokenRequest"];
};
};
responses: {
/** @description Created */
201: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["cabana.Envelope-cabana_AdminAPITokenCreated"];
};
};
/** @description Unauthorized */
401: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
};
};
/** @description Forbidden */
403: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
};
};
/** @description Unprocessable Entity */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
};
};
};
};
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/account/tokens/scopes": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* List available API token scopes
* @description Lists framework and plugin scopes the signed-in admin may pick when creating a token. Personal API tokens are refused (403 interactive_only).
*/
get: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["cabana.Envelope-array_cabana_AdminAPITokenScope"];
};
};
/** @description Unauthorized */
401: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
};
};
/** @description Forbidden */
403: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
};
};
};
};
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/account/tokens/{id}": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
post?: never;
/**
* Revoke an API token
* @description Soft-revokes one of the signed-in admin's active personal API tokens. Personal API tokens are refused (403 interactive_only).
*/
delete: {
parameters: {
query?: never;
header?: never;
path: {
/** @description Token id */
id: number;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["cabana.Envelope-cabana_AdminAPIToken"];
};
};
/** @description Unauthorized */
401: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
};
};
/** @description Forbidden */
403: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
};
};
/** @description Not Found */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["cabana.ErrorEnvelope"];
};
};
};
};
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/auth/login": {
parameters: {
query?: never;
@@ -4669,6 +4910,41 @@ export interface paths {
export type webhooks = Record<string, never>;
export interface components {
schemas: {
"cabana.AdminAPIToken": {
created_at: string;
expired: boolean;
expires_at: string;
hint: string;
id: number;
last_used_at: string;
name: string;
revoked_at: string;
scopes: components["schemas"]["cabana.AdminAPITokenScope"][];
};
"cabana.AdminAPITokenCreated": {
created_at: string;
expired: boolean;
expires_at: string;
hint: string;
id: number;
last_used_at: string;
name: string;
revoked_at: string;
scopes: components["schemas"]["cabana.AdminAPITokenScope"][];
token: string;
};
"cabana.AdminAPITokenRequest": {
expires: string;
name: string;
scopes: string[];
};
"cabana.AdminAPITokenScope": {
description: string;
known: boolean;
label: string;
name: string;
read_only: boolean;
};
"cabana.AdminAccountRequest": {
current_password?: string;
email: string;
@@ -4774,6 +5050,14 @@ export interface components {
scripts: string[];
styles: string[];
};
"cabana.Envelope-array_cabana_AdminAPIToken": {
data: components["schemas"]["cabana.AdminAPIToken"][];
meta: components["schemas"]["cabana.SuccessMeta"];
};
"cabana.Envelope-array_cabana_AdminAPITokenScope": {
data: components["schemas"]["cabana.AdminAPITokenScope"][];
meta: components["schemas"]["cabana.SuccessMeta"];
};
"cabana.Envelope-array_cabana_FileItem": {
data: components["schemas"]["cabana.FileItem"][];
meta: components["schemas"]["cabana.SuccessMeta"];
@@ -4790,6 +5074,14 @@ export interface components {
data: components["schemas"]["cabana.SettingsEntry"][];
meta: components["schemas"]["cabana.SuccessMeta"];
};
"cabana.Envelope-cabana_AdminAPIToken": {
data: components["schemas"]["cabana.AdminAPIToken"];
meta: components["schemas"]["cabana.SuccessMeta"];
};
"cabana.Envelope-cabana_AdminAPITokenCreated": {
data: components["schemas"]["cabana.AdminAPITokenCreated"];
meta: components["schemas"]["cabana.SuccessMeta"];
};
"cabana.Envelope-cabana_AdminActionResult": {
data: components["schemas"]["cabana.AdminActionResult"];
meta: components["schemas"]["cabana.SuccessMeta"];