Files
image-platform/apps/admin/src/infra/backend-api/generated/backend-api.generated.ts
S.Gromov 6a018826f5 feat: добавить рабочий dashboard admin
- добавлен Mantine theme provider и AppShell layout\n- сгенерирован Backend API клиент и добавлены infra/business хуки\n- добавлены таблица assets, detail/presets panels и create asset modal
2026-05-05 15:02:55 +03:00

1493 lines
42 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* eslint-disable */
/* tslint:disable */
// @ts-nocheck
/*
* ---------------------------------------------------------------
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
* ## ##
* ## AUTHOR: acacode ##
* ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
* ---------------------------------------------------------------
*/
export interface HealthResponseDto {
/**
* Имя сервиса, который вернул health-check ответ.
* @example "image-platform-api"
*/
service: string;
/**
* Текущее состояние сервиса.
* @example "ok"
*/
status: string;
}
export interface AssetResponseDto {
/**
* Внутренний UUID asset.
* @example "59fcf4f6-9891-4df4-8bb7-a4dbe570bb66"
*/
id: string;
/**
* Публичный идентификатор asset.
* @example "asset_demo"
*/
publicId: string;
/**
* Текущая версия source image.
* @example 1
*/
currentVersion: number;
/**
* Статус asset.
* @example "active"
*/
status: AssetResponseDtoStatusEnum;
/**
* Source URL текущей версии.
* @example "https://storage.yandexcloud.net/shared1318/img/1.jpg"
*/
sourceUrl: string;
/**
* Hostname source URL текущей версии.
* @example "storage.yandexcloud.net"
*/
sourceHost: string;
/**
* Дата создания asset.
* @example "2026-05-05T12:00:00.000Z"
*/
createdAt: string;
/**
* Дата обновления asset.
* @example "2026-05-05T12:00:00.000Z"
*/
updatedAt: string;
}
export interface AssetsListResponseDto {
/** Список assets. */
assets: AssetResponseDto[];
}
export interface CreateAssetRequestDto {
/**
* Публичный стабильный идентификатор asset. Если не передан, Backend сгенерирует идентификатор автоматически.
* @example "asset_123"
*/
publicId?: string;
/**
* Постоянная ссылка на исходное изображение. Сейчас поддерживаются только публичные http/https URL.
* @example "https://storage.yandexcloud.net/shared1318/img/1.jpg"
*/
sourceUrl: string;
}
export interface CreateAssetResponseDto {
/**
* Внутренний UUID asset в PostgreSQL.
* @example "59fcf4f6-9891-4df4-8bb7-a4dbe570bb66"
*/
id: string;
/**
* Публичный идентификатор asset для Gateway URL.
* @example "asset_123"
*/
publicId: string;
/**
* Номер версии source image. Используется в URL как `v{version}`.
* @example 1
*/
version: number;
/**
* Нормализованный hostname исходного изображения.
* @example "storage.yandexcloud.net"
*/
sourceHost: string;
/**
* Базовый путь Gateway для запроса variant. Width, quality и format передаются query params.
* @example "/images/asset_123/v1/card"
*/
imageBasePath: string;
}
export interface CreateAssetVersionRequestDto {
/**
* Постоянная ссылка на новую версию исходного изображения.
* @example "https://storage.yandexcloud.net/shared1318/img/1.jpg"
*/
sourceUrl: string;
}
export interface CreateAssetVersionResponseDto {
/**
* Внутренний UUID asset.
* @example "59fcf4f6-9891-4df4-8bb7-a4dbe570bb66"
*/
assetId: string;
/**
* Внутренний UUID новой версии source image.
* @example "3b5da974-bb7f-4d73-b172-d6ad9c244528"
*/
versionId: string;
/**
* Публичный идентификатор asset.
* @example "asset_demo"
*/
publicId: string;
/**
* Предыдущая активная версия source image.
* @example 1
*/
previousVersion: number;
/**
* Новая активная версия source image.
* @example 2
*/
version: number;
/**
* Нормализованный source URL новой версии.
* @example "https://storage.yandexcloud.net/shared1318/img/1.jpg"
*/
sourceUrl: string;
/**
* Hostname source URL новой версии.
* @example "storage.yandexcloud.net"
*/
sourceHost: string;
/**
* Базовый Gateway path для новой версии.
* @example "/images/asset_demo/v2/card"
*/
imageBasePath: string;
/**
* Дата создания версии.
* @example "2026-05-05T12:00:00.000Z"
*/
createdAt: string;
}
export interface AssetPictureImageResponseDto {
/**
* Fallback image URL для `<img src>`.
* @example "http://localhost:8888/images/asset_demo/v1/card?w=960&q=80&f=jpg"
*/
src: string;
/**
* Fallback image format.
* @example "jpg"
*/
format: AssetPictureImageResponseDtoFormatEnum;
/**
* Fallback image Content-Type.
* @example "image/jpeg"
*/
type: string;
/**
* Fallback image width.
* @example 960
*/
width: number;
/**
* Fallback image height. `0` означает auto height.
* @example 0
*/
height: number;
}
export interface AssetPictureSourceResponseDto {
/**
* Source format.
* @example "webp"
*/
format: AssetPictureSourceResponseDtoFormatEnum;
/**
* Source MIME type для `<source type>`.
* @example "image/webp"
*/
type: string;
/** Готовая строка srcset с width descriptors. */
srcSet: string;
}
export interface AssetPictureResponseDto {
/**
* Публичный идентификатор asset.
* @example "asset_demo"
*/
publicId: string;
/**
* Preset, для которого построен picture contract.
* @example "card"
*/
preset: string;
/**
* Версия source image.
* @example 1
*/
version: number;
/**
* Quality для всех URL.
* @example 80
*/
quality: number;
/**
* Значение sizes для `<img sizes>`.
* @example "100vw"
*/
sizes: string;
/**
* Width descriptors, вошедшие в srcset.
* @example [320,640,960]
*/
widths: string[];
/** Fallback image для `<img>`. */
image: AssetPictureImageResponseDto;
/** Sources для `<picture>`. */
sources: AssetPictureSourceResponseDto[];
}
export interface AssetVariantResponseDto {
/**
* Внутренний UUID variant.
* @example "7748d24e-5f30-4064-8ee8-4745a4d2aef1"
*/
id: string;
/**
* Preset или `custom`.
* @example "card"
*/
preset: string;
/**
* Версия source image, для которой создан variant.
* @example 1
*/
version: number;
/**
* Ширина variant.
* @example 640
*/
width: number;
/**
* Высота variant. `0` означает auto height.
* @example 0
*/
height: number;
/**
* Режим resize.
* @example "fit"
*/
resize: AssetVariantResponseDtoResizeEnum;
/**
* Качество variant.
* @example 80
*/
quality: number;
/**
* Запрошенный формат.
* @example "webp"
*/
requestedFormat: AssetVariantResponseDtoRequestedFormatEnum;
/**
* Фактический формат bytes.
* @example "webp"
*/
format: AssetVariantResponseDtoFormatEnum;
/**
* Статус генерации.
* @example "ready"
*/
status: AssetVariantResponseDtoStatusEnum;
/**
* Публичный Gateway URL для variant.
* @example "http://localhost:8888/images/asset_demo/v1/card?w=640&q=80&f=webp"
*/
url: string;
/**
* S3 key variant object.
* @example "variants/asset_demo/v1/abc.webp"
*/
s3Key: string;
/**
* Content-Type готового object.
* @example "image/webp"
*/
contentType?: object;
/**
* Размер готового object в bytes.
* @example 71844
*/
sizeBytes?: object;
/** Ошибка последней генерации, если status=`failed`. */
error?: object;
/**
* Дата создания variant.
* @example "2026-05-05T12:00:00.000Z"
*/
createdAt: string;
/**
* Дата обновления variant.
* @example "2026-05-05T12:00:00.000Z"
*/
updatedAt: string;
}
export interface AssetVariantsResponseDto {
/**
* Публичный идентификатор asset.
* @example "asset_demo"
*/
publicId: string;
/** Список variants. */
variants: AssetVariantResponseDto[];
}
export interface CreateAssetVariantsRequestDto {
/**
* Preset для генерации или `custom`.
* @example "card"
*/
preset: string;
/**
* Режим генерации: один variant или вся family preset.
* @example "single"
*/
mode?: CreateAssetVariantsRequestDtoModeEnum;
/**
* Версия source image. Если не передана, используется currentVersion asset.
* @example 1
*/
version?: number;
/**
* Ширина variant. Обязательна для responsive preset в mode=`single` и custom.
* @example 640
*/
width?: number;
/**
* Высота variant для custom. `0` или отсутствие означает auto height.
* @example 333
*/
height?: number;
/**
* Качество. Если не передано, берётся из preset/custom config.
* @example 80
*/
quality?: number;
/**
* Фактический формат для single generation.
* @example "webp"
*/
format?: CreateAssetVariantsRequestDtoFormatEnum;
/** Форматы для family generation. Если не переданы, используются все форматы preset. */
formats?: CreateAssetVariantsRequestDtoFormatsEnum[];
/**
* Resize mode для custom transforms.
* @example "fill"
*/
resize?: CreateAssetVariantsRequestDtoResizeEnum;
}
export interface CreateAssetVariantsResponseDto {
/**
* Публичный идентификатор asset.
* @example "asset_demo"
*/
publicId: string;
/**
* Версия source image, для которой поставлены jobs.
* @example 1
*/
version: number;
/** Созданные или переиспользованные variants. */
variants: AssetVariantResponseDto[];
}
export interface EnsureImageVariantRequestDto {
/**
* Публичный идентификатор asset из Gateway URL.
* @example "asset_123"
*/
assetId: string;
/**
* Версия source image из Gateway URL `v{version}`.
* @min 1
* @example 4
*/
version: number;
/**
* Имя preset трансформации. Сейчас используется как часть variant key.
* @example "card"
*/
preset: string;
/**
* Целевая ширина variant в пикселях. Обязательна для responsive presets и custom.
* @min 1
* @example 640
*/
width?: number;
/**
* Целевая высота variant в пикселях. `0` или отсутствие означает auto height.
* @min 0
* @example 420
*/
height?: number;
/**
* Качество сжатия для imgproxy. Если не передано, берётся из preset.
* @min 1
* @example 80
*/
quality?: number;
/**
* Формат, который запросил клиент. Для `auto` Gateway выбирает фактический формат по `Accept` header.
* @example "auto"
*/
requestedFormat?: EnsureImageVariantRequestDtoRequestedFormatEnum;
/**
* Режим resize для custom transforms. Для обычных presets берётся из preset config.
* @example "fit"
*/
resize?: EnsureImageVariantRequestDtoResizeEnum;
/**
* Фактический output format после negotiation. Именно этот формат попадает в S3 key и L1 cache key.
* @example "webp"
*/
format: EnsureImageVariantRequestDtoFormatEnum;
}
export interface PresetResponseDto {
/**
* Имя preset.
* @example "card"
*/
name: string;
/**
* Режим preset.
* @example "responsive"
*/
mode: PresetResponseDtoModeEnum;
/**
* Разрешённые форматы.
* @example ["avif","webp","jpg"]
*/
formats: string[];
/**
* Разрешённые значения quality.
* @example [75,80]
*/
qualities: string[];
/**
* Quality по умолчанию.
* @example 80
*/
quality: number;
/**
* Resize mode preset.
* @example "fit"
*/
resize: PresetResponseDtoResizeEnum;
/**
* Фиксированная ширина для fixed preset.
* @example 256
*/
width?: number;
/**
* Фиксированная высота для fixed preset.
* @example 256
*/
height?: number;
/**
* Разрешённые ширины для responsive preset.
* @example [320,640,960]
*/
widths?: string[];
}
export interface CustomTransformConfigResponseDto {
/**
* Включены ли custom transforms.
* @example true
*/
enabled: boolean;
/**
* Разрешённые форматы custom transforms.
* @example ["avif","webp","jpg","png"]
*/
formats: string[];
/**
* Максимальная ширина custom transform.
* @example 4096
*/
maxWidth: number;
/**
* Максимальная высота custom transform.
* @example 4096
*/
maxHeight: number;
/**
* Quality по умолчанию для custom transform.
* @example 80
*/
quality: number;
}
export interface PresetsResponseDto {
/** Static presets. */
presets: PresetResponseDto[];
/** Custom transform config. */
custom: CustomTransformConfigResponseDto;
/**
* Mock allowlist source hosts.
* @example ["storage.yandexcloud.net"]
*/
allowedSourceHosts: string[];
}
/**
* Статус asset.
* @example "active"
*/
export enum AssetResponseDtoStatusEnum {
Active = "active",
Disabled = "disabled",
Deleted = "deleted",
}
/**
* Fallback image format.
* @example "jpg"
*/
export enum AssetPictureImageResponseDtoFormatEnum {
Avif = "avif",
Webp = "webp",
Jpg = "jpg",
Png = "png",
}
/**
* Source format.
* @example "webp"
*/
export enum AssetPictureSourceResponseDtoFormatEnum {
Avif = "avif",
Webp = "webp",
Jpg = "jpg",
Png = "png",
}
/**
* Режим resize.
* @example "fit"
*/
export enum AssetVariantResponseDtoResizeEnum {
Fit = "fit",
Fill = "fill",
}
/**
* Запрошенный формат.
* @example "webp"
*/
export enum AssetVariantResponseDtoRequestedFormatEnum {
Auto = "auto",
Avif = "avif",
Webp = "webp",
Jpg = "jpg",
Png = "png",
}
/**
* Фактический формат bytes.
* @example "webp"
*/
export enum AssetVariantResponseDtoFormatEnum {
Avif = "avif",
Webp = "webp",
Jpg = "jpg",
Png = "png",
}
/**
* Статус генерации.
* @example "ready"
*/
export enum AssetVariantResponseDtoStatusEnum {
Pending = "pending",
Processing = "processing",
Ready = "ready",
Failed = "failed",
}
/**
* Режим генерации: один variant или вся family preset.
* @example "single"
*/
export enum CreateAssetVariantsRequestDtoModeEnum {
Single = "single",
Family = "family",
}
/**
* Фактический формат для single generation.
* @example "webp"
*/
export enum CreateAssetVariantsRequestDtoFormatEnum {
Avif = "avif",
Webp = "webp",
Jpg = "jpg",
Png = "png",
}
export enum CreateAssetVariantsRequestDtoFormatsEnum {
Avif = "avif",
Webp = "webp",
Jpg = "jpg",
Png = "png",
}
/**
* Resize mode для custom transforms.
* @example "fill"
*/
export enum CreateAssetVariantsRequestDtoResizeEnum {
Fit = "fit",
Fill = "fill",
}
/**
* Формат, который запросил клиент. Для `auto` Gateway выбирает фактический формат по `Accept` header.
* @example "auto"
*/
export enum EnsureImageVariantRequestDtoRequestedFormatEnum {
Auto = "auto",
Avif = "avif",
Webp = "webp",
Jpg = "jpg",
Png = "png",
}
/**
* Режим resize для custom transforms. Для обычных presets берётся из preset config.
* @example "fit"
*/
export enum EnsureImageVariantRequestDtoResizeEnum {
Fit = "fit",
Fill = "fill",
}
/**
* Фактический output format после negotiation. Именно этот формат попадает в S3 key и L1 cache key.
* @example "webp"
*/
export enum EnsureImageVariantRequestDtoFormatEnum {
Avif = "avif",
Webp = "webp",
Jpg = "jpg",
Png = "png",
}
/**
* Режим preset.
* @example "responsive"
*/
export enum PresetResponseDtoModeEnum {
Fixed = "fixed",
Responsive = "responsive",
}
/**
* Resize mode preset.
* @example "fit"
*/
export enum PresetResponseDtoResizeEnum {
Fit = "fit",
Fill = "fill",
}
export interface ListAssetsParams {
/**
* Максимальное количество assets в ответе.
* @example 50
*/
limit?: string;
/**
* Смещение для простого paging.
* @example 0
*/
offset?: string;
}
export interface GetAssetParams {
/**
* Публичный идентификатор asset.
* @example "asset_demo"
*/
publicId: string;
}
export interface CreateAssetVersionParams {
/**
* Публичный идентификатор asset.
* @example "asset_demo"
*/
publicId: string;
}
export interface GetAssetPictureParams {
/**
* Static preset для picture contract.
* @example "card"
*/
preset: string;
/**
* Версия source image. Если не передана, используется currentVersion asset.
* @example 1
*/
version?: string;
/**
* Quality. Если не передано, берётся default quality preset.
* @example 80
*/
quality?: string;
/**
* Значение для HTML `sizes`.
* @example "(min-width: 768px) 50vw, 100vw"
*/
sizes?: string;
/**
* Публичный идентификатор asset.
* @example "asset_demo"
*/
publicId: string;
}
export interface ListAssetVariantsParams {
/**
* Версия source image. Если не передана, возвращаются variants всех версий.
* @example 1
*/
version?: string;
/**
* Публичный идентификатор asset.
* @example "asset_demo"
*/
publicId: string;
}
export interface CreateAssetVariantsParams {
/**
* Публичный идентификатор asset.
* @example "asset_demo"
*/
publicId: string;
}
export namespace System {
/**
* @description Возвращает простой health-check ответ. Используется для локальной проверки, мониторинга и smoke tests.
* @tags system
* @name GetHealth
* @summary проверить состояние Backend API
* @request GET:/api/health
*/
export namespace GetHealth {
export type RequestParams = {};
export type RequestQuery = {};
export type RequestBody = never;
export type RequestHeaders = {};
export type ResponseBody = HealthResponseDto;
}
}
export namespace Assets {
/**
* @description Возвращает последние зарегистрированные assets вместе с source URL текущей версии.
* @tags assets
* @name ListAssets
* @summary получить список assets
* @request GET:/api/assets
*/
export namespace ListAssets {
export type RequestParams = {};
export type RequestQuery = {
/**
* Максимальное количество assets в ответе.
* @example 50
*/
limit?: string;
/**
* Смещение для простого paging.
* @example 0
*/
offset?: string;
};
export type RequestBody = never;
export type RequestHeaders = {};
export type ResponseBody = AssetsListResponseDto;
}
/**
* @description Создаёт asset и первую версию source image. Source URL сохраняется в PostgreSQL, а публичный image URL строится через Gateway без раскрытия исходной ссылки клиенту.
* @tags assets
* @name CreateAsset
* @summary зарегистрировать исходное изображение
* @request POST:/api/assets
*/
export namespace CreateAsset {
export type RequestParams = {};
export type RequestQuery = {};
export type RequestBody = CreateAssetRequestDto;
export type RequestHeaders = {};
export type ResponseBody = CreateAssetResponseDto;
}
/**
* @description Возвращает metadata asset и source URL текущей версии.
* @tags assets
* @name GetAsset
* @summary получить asset по publicId
* @request GET:/api/assets/{publicId}
*/
export namespace GetAsset {
export type RequestParams = {
/**
* Публичный идентификатор asset.
* @example "asset_demo"
*/
publicId: string;
};
export type RequestQuery = {};
export type RequestBody = never;
export type RequestHeaders = {};
export type ResponseBody = AssetResponseDto;
}
/**
* @description Регистрирует новый source URL для существующего asset, увеличивает currentVersion и тем самым создаёт новый immutable Gateway URL `/v{version}` без purge старых URLs.
* @tags assets
* @name CreateAssetVersion
* @summary создать новую версию source image
* @request POST:/api/assets/{publicId}/versions
*/
export namespace CreateAssetVersion {
export type RequestParams = {
/**
* Публичный идентификатор asset.
* @example "asset_demo"
*/
publicId: string;
};
export type RequestQuery = {};
export type RequestBody = CreateAssetVersionRequestDto;
export type RequestHeaders = {};
export type ResponseBody = CreateAssetVersionResponseDto;
}
/**
* @description Возвращает готовый контракт для `<picture>` и `<img>` по static preset: sources, srcset, fallback src, sizes и versioned Gateway URLs. Endpoint не ставит generation jobs: Gateway сгенерирует bytes lazy или отдаст cache.
* @tags assets
* @name GetAssetPicture
* @summary получить picture/srcset URLs
* @request GET:/api/assets/{publicId}/picture
*/
export namespace GetAssetPicture {
export type RequestParams = {
/**
* Публичный идентификатор asset.
* @example "asset_demo"
*/
publicId: string;
};
export type RequestQuery = {
/**
* Static preset для picture contract.
* @example "card"
*/
preset: string;
/**
* Версия source image. Если не передана, используется currentVersion asset.
* @example 1
*/
version?: string;
/**
* Quality. Если не передано, берётся default quality preset.
* @example 80
*/
quality?: string;
/**
* Значение для HTML `sizes`.
* @example "(min-width: 768px) 50vw, 100vw"
*/
sizes?: string;
};
export type RequestBody = never;
export type RequestHeaders = {};
export type ResponseBody = AssetPictureResponseDto;
}
/**
* @description Возвращает variants asset: preset/custom параметры, status, S3 key, public URL и ошибку генерации, если она была.
* @tags assets
* @name ListAssetVariants
* @summary получить variants asset
* @request GET:/api/assets/{publicId}/variants
*/
export namespace ListAssetVariants {
export type RequestParams = {
/**
* Публичный идентификатор asset.
* @example "asset_demo"
*/
publicId: string;
};
export type RequestQuery = {
/**
* Версия source image. Если не передана, возвращаются variants всех версий.
* @example 1
*/
version?: string;
};
export type RequestBody = never;
export type RequestHeaders = {};
export type ResponseBody = AssetVariantsResponseDto;
}
/**
* @description Business endpoint для явной подготовки variants. В режиме `single` создаёт один variant, в режиме `family` создаёт набор variants preset по всем разрешённым widths/formats. Endpoint не ждёт bytes, а возвращает созданные/переиспользованные rows и public URLs.
* @tags assets
* @name CreateAssetVariants
* @summary поставить generation jobs для variants
* @request POST:/api/assets/{publicId}/variants
*/
export namespace CreateAssetVariants {
export type RequestParams = {
/**
* Публичный идентификатор asset.
* @example "asset_demo"
*/
publicId: string;
};
export type RequestQuery = {};
export type RequestBody = CreateAssetVariantsRequestDto;
export type RequestHeaders = {};
export type ResponseBody = CreateAssetVariantsResponseDto;
}
}
export namespace InternalImages {
/**
* @description Внутренний endpoint для Gateway. На L1 cache miss Backend проверяет PostgreSQL и S3, создаёт variant при необходимости, публикует RabbitMQ job, ждёт генерацию worker и возвращает готовые image bytes.
* @tags internal-images
* @name EnsureImageVariant
* @summary подготовить variant изображения для Gateway
* @request POST:/api/internal/images/ensure
*/
export namespace EnsureImageVariant {
export type RequestParams = {};
export type RequestQuery = {};
export type RequestBody = EnsureImageVariantRequestDto;
export type RequestHeaders = {};
export type ResponseBody = File;
}
}
export namespace Presets {
/**
* @description Возвращает статический config presets, custom transform limits и mock allowlist source hosts.
* @tags presets
* @name GetPresets
* @summary получить доступные presets и custom config
* @request GET:/api/presets
*/
export namespace GetPresets {
export type RequestParams = {};
export type RequestQuery = {};
export type RequestBody = never;
export type RequestHeaders = {};
export type ResponseBody = PresetsResponseDto;
}
}
/**
* Фетчер для SWR
* Принимает URL и возвращает Promise с данными
*/
export const fetcher = <T = any>(url: string): Promise<T> => {
return fetch(url, {
headers: {
"Content-Type": "application/json",
},
}).then((res) => {
if (!res.ok) {
throw new Error(`HTTP Error ${res.status}`);
}
return res.json();
});
};
export type QueryParamsType = Record<string | number, any>;
export type ResponseFormat = keyof Omit<Body, "body" | "bodyUsed">;
export interface FullRequestParams extends Omit<RequestInit, "body"> {
/** set parameter to `true` for call `securityWorker` for this request */
secure?: boolean;
/** request path */
path: string;
/** content type of request body */
type?: ContentType;
/** query params */
query?: QueryParamsType;
/** format of response (i.e. response.json() -> format: "json") */
format?: ResponseFormat;
/** request body */
body?: unknown;
/** base url */
baseUrl?: string;
/** request cancellation token */
cancelToken?: CancelToken;
}
export type RequestParams = Omit<
FullRequestParams,
"body" | "method" | "query" | "path"
>;
export interface ApiConfig<SecurityDataType = unknown> {
baseUrl?: string;
baseApiParams?: Omit<RequestParams, "baseUrl" | "cancelToken" | "signal">;
securityWorker?: (
securityData: SecurityDataType | null,
) => Promise<RequestParams | void> | RequestParams | void;
customFetch?: typeof fetch;
}
export interface HttpResponse<D extends unknown, E extends unknown = unknown>
extends Response {
data: D;
error: E;
}
type CancelToken = Symbol | string | number;
export enum ContentType {
Json = "application/json",
JsonApi = "application/vnd.api+json",
FormData = "multipart/form-data",
UrlEncoded = "application/x-www-form-urlencoded",
Text = "text/plain",
}
export class HttpClient<SecurityDataType = unknown> {
public baseUrl: string = "";
private securityData: SecurityDataType | null = null;
private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"];
private abortControllers = new Map<CancelToken, AbortController>();
private customFetch = (...fetchParams: Parameters<typeof fetch>) =>
fetch(...fetchParams);
private baseApiParams: RequestParams = {
credentials: "same-origin",
headers: {},
redirect: "follow",
referrerPolicy: "no-referrer",
};
constructor(apiConfig: ApiConfig<SecurityDataType> = {}) {
Object.assign(this, apiConfig);
}
public setSecurityData = (data: SecurityDataType | null) => {
this.securityData = data;
};
protected encodeQueryParam(key: string, value: any) {
const encodedKey = encodeURIComponent(key);
return `${encodedKey}=${encodeURIComponent(typeof value === "number" ? value : `${value}`)}`;
}
protected addQueryParam(query: QueryParamsType, key: string) {
return this.encodeQueryParam(key, query[key]);
}
protected addArrayQueryParam(query: QueryParamsType, key: string) {
const value = query[key];
return value.map((v: any) => this.encodeQueryParam(key, v)).join("&");
}
protected toQueryString(rawQuery?: QueryParamsType): string {
const query = rawQuery || {};
const keys = Object.keys(query).filter(
(key) => "undefined" !== typeof query[key],
);
return keys
.map((key) =>
Array.isArray(query[key])
? this.addArrayQueryParam(query, key)
: this.addQueryParam(query, key),
)
.join("&");
}
protected addQueryParams(rawQuery?: QueryParamsType): string {
const queryString = this.toQueryString(rawQuery);
return queryString ? `?${queryString}` : "";
}
private contentFormatters: Record<ContentType, (input: any) => any> = {
[ContentType.Json]: (input: any) =>
input !== null && (typeof input === "object" || typeof input === "string")
? JSON.stringify(input)
: input,
[ContentType.JsonApi]: (input: any) =>
input !== null && (typeof input === "object" || typeof input === "string")
? JSON.stringify(input)
: input,
[ContentType.Text]: (input: any) =>
input !== null && typeof input !== "string"
? JSON.stringify(input)
: input,
[ContentType.FormData]: (input: any) => {
if (input instanceof FormData) {
return input;
}
return Object.keys(input || {}).reduce((formData, key) => {
const property = input[key];
formData.append(
key,
property instanceof Blob
? property
: typeof property === "object" && property !== null
? JSON.stringify(property)
: `${property}`,
);
return formData;
}, new FormData());
},
[ContentType.UrlEncoded]: (input: any) => this.toQueryString(input),
};
protected mergeRequestParams(
params1: RequestParams,
params2?: RequestParams,
): RequestParams {
return {
...this.baseApiParams,
...params1,
...(params2 || {}),
headers: {
...(this.baseApiParams.headers || {}),
...(params1.headers || {}),
...((params2 && params2.headers) || {}),
},
};
}
protected createAbortSignal = (
cancelToken: CancelToken,
): AbortSignal | undefined => {
if (this.abortControllers.has(cancelToken)) {
const abortController = this.abortControllers.get(cancelToken);
if (abortController) {
return abortController.signal;
}
return void 0;
}
const abortController = new AbortController();
this.abortControllers.set(cancelToken, abortController);
return abortController.signal;
};
public abortRequest = (cancelToken: CancelToken) => {
const abortController = this.abortControllers.get(cancelToken);
if (abortController) {
abortController.abort();
this.abortControllers.delete(cancelToken);
}
};
public request = async <T = any, E = any>({
body,
secure,
path,
type,
query,
format,
baseUrl,
cancelToken,
...params
}: FullRequestParams): Promise<T> => {
const secureParams =
((typeof secure === "boolean" ? secure : this.baseApiParams.secure) &&
this.securityWorker &&
(await this.securityWorker(this.securityData))) ||
{};
const requestParams = this.mergeRequestParams(params, secureParams);
const queryString = query && this.toQueryString(query);
const payloadFormatter = this.contentFormatters[type || ContentType.Json];
const responseFormat = format || requestParams.format;
return this.customFetch(
`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`,
{
...requestParams,
headers: {
...(requestParams.headers || {}),
...(type && type !== ContentType.FormData
? { "Content-Type": type }
: {}),
},
signal:
(cancelToken
? this.createAbortSignal(cancelToken)
: requestParams.signal) || null,
body:
typeof body === "undefined" || body === null
? null
: payloadFormatter(body),
},
).then(async (response) => {
const r = response as HttpResponse<T, E>;
r.data = null as unknown as T;
r.error = null as unknown as E;
const responseToParse = responseFormat ? response.clone() : response;
const data = !responseFormat
? r
: await responseToParse[responseFormat]()
.then((data) => {
if (r.ok) {
r.data = data;
} else {
r.error = data;
}
return r;
})
.catch((e) => {
r.error = e;
return r;
});
if (cancelToken) {
this.abortControllers.delete(cancelToken);
}
if (!response.ok) throw data;
return data.data;
});
};
}
/**
* @title Image Platform API
* @version 0.1.0
* @contact
*
* Backend API для управления image assets, metadata в PostgreSQL, S3 variants, RabbitMQ jobs и генерацией через imgproxy.
*/
export class Api<SecurityDataType extends unknown> {
http: HttpClient<SecurityDataType>;
constructor(http?: HttpClient<SecurityDataType>) {
this.http = http || new HttpClient<SecurityDataType>();
}
system = {
/**
* @description Возвращает простой health-check ответ. Используется для локальной проверки, мониторинга и smoke tests.
*
* @tags system
* @name GetHealth
* @summary проверить состояние Backend API
* @request GET:/api/health
*/
getHealth: (params: RequestParams = {}) =>
this.http.request<HealthResponseDto, any>({
path: `/api/health`,
method: "GET",
format: "json",
...params,
}),
};
assets = {
/**
* @description Возвращает последние зарегистрированные assets вместе с source URL текущей версии.
*
* @tags assets
* @name ListAssets
* @summary получить список assets
* @request GET:/api/assets
*/
listAssets: (query: ListAssetsParams, params: RequestParams = {}) =>
this.http.request<AssetsListResponseDto, any>({
path: `/api/assets`,
method: "GET",
query: query,
format: "json",
...params,
}),
/**
* @description Создаёт asset и первую версию source image. Source URL сохраняется в PostgreSQL, а публичный image URL строится через Gateway без раскрытия исходной ссылки клиенту.
*
* @tags assets
* @name CreateAsset
* @summary зарегистрировать исходное изображение
* @request POST:/api/assets
*/
createAsset: (data: CreateAssetRequestDto, params: RequestParams = {}) =>
this.http.request<CreateAssetResponseDto, void>({
path: `/api/assets`,
method: "POST",
body: data,
type: ContentType.Json,
format: "json",
...params,
}),
/**
* @description Возвращает metadata asset и source URL текущей версии.
*
* @tags assets
* @name GetAsset
* @summary получить asset по publicId
* @request GET:/api/assets/{publicId}
*/
getAsset: (
{ publicId, ...query }: GetAssetParams,
params: RequestParams = {},
) =>
this.http.request<AssetResponseDto, void>({
path: `/api/assets/${publicId}`,
method: "GET",
format: "json",
...params,
}),
/**
* @description Регистрирует новый source URL для существующего asset, увеличивает currentVersion и тем самым создаёт новый immutable Gateway URL `/v{version}` без purge старых URLs.
*
* @tags assets
* @name CreateAssetVersion
* @summary создать новую версию source image
* @request POST:/api/assets/{publicId}/versions
*/
createAssetVersion: (
{ publicId, ...query }: CreateAssetVersionParams,
data: CreateAssetVersionRequestDto,
params: RequestParams = {},
) =>
this.http.request<CreateAssetVersionResponseDto, void>({
path: `/api/assets/${publicId}/versions`,
method: "POST",
body: data,
type: ContentType.Json,
format: "json",
...params,
}),
/**
* @description Возвращает готовый контракт для `<picture>` и `<img>` по static preset: sources, srcset, fallback src, sizes и versioned Gateway URLs. Endpoint не ставит generation jobs: Gateway сгенерирует bytes lazy или отдаст cache.
*
* @tags assets
* @name GetAssetPicture
* @summary получить picture/srcset URLs
* @request GET:/api/assets/{publicId}/picture
*/
getAssetPicture: (
{ publicId, ...query }: GetAssetPictureParams,
params: RequestParams = {},
) =>
this.http.request<AssetPictureResponseDto, void>({
path: `/api/assets/${publicId}/picture`,
method: "GET",
query: query,
format: "json",
...params,
}),
/**
* @description Возвращает variants asset: preset/custom параметры, status, S3 key, public URL и ошибку генерации, если она была.
*
* @tags assets
* @name ListAssetVariants
* @summary получить variants asset
* @request GET:/api/assets/{publicId}/variants
*/
listAssetVariants: (
{ publicId, ...query }: ListAssetVariantsParams,
params: RequestParams = {},
) =>
this.http.request<AssetVariantsResponseDto, void>({
path: `/api/assets/${publicId}/variants`,
method: "GET",
query: query,
format: "json",
...params,
}),
/**
* @description Business endpoint для явной подготовки variants. В режиме `single` создаёт один variant, в режиме `family` создаёт набор variants preset по всем разрешённым widths/formats. Endpoint не ждёт bytes, а возвращает созданные/переиспользованные rows и public URLs.
*
* @tags assets
* @name CreateAssetVariants
* @summary поставить generation jobs для variants
* @request POST:/api/assets/{publicId}/variants
*/
createAssetVariants: (
{ publicId, ...query }: CreateAssetVariantsParams,
data: CreateAssetVariantsRequestDto,
params: RequestParams = {},
) =>
this.http.request<CreateAssetVariantsResponseDto, void>({
path: `/api/assets/${publicId}/variants`,
method: "POST",
body: data,
type: ContentType.Json,
format: "json",
...params,
}),
};
internalImages = {
/**
* @description Внутренний endpoint для Gateway. На L1 cache miss Backend проверяет PostgreSQL и S3, создаёт variant при необходимости, публикует RabbitMQ job, ждёт генерацию worker и возвращает готовые image bytes.
*
* @tags internal-images
* @name EnsureImageVariant
* @summary подготовить variant изображения для Gateway
* @request POST:/api/internal/images/ensure
*/
ensureImageVariant: (
data: EnsureImageVariantRequestDto,
params: RequestParams = {},
) =>
this.http.request<File, void>({
path: `/api/internal/images/ensure`,
method: "POST",
body: data,
type: ContentType.Json,
format: "blob",
...params,
}),
};
presets = {
/**
* @description Возвращает статический config presets, custom transform limits и mock allowlist source hosts.
*
* @tags presets
* @name GetPresets
* @summary получить доступные presets и custom config
* @request GET:/api/presets
*/
getPresets: (params: RequestParams = {}) =>
this.http.request<PresetsResponseDto, any>({
path: `/api/presets`,
method: "GET",
format: "json",
...params,
}),
};
}