diff --git a/frontend/src/client/@tanstack/react-query.gen.ts b/frontend/src/client/@tanstack/react-query.gen.ts new file mode 100644 index 0000000..4406ce7 --- /dev/null +++ b/frontend/src/client/@tanstack/react-query.gen.ts @@ -0,0 +1,147 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { queryOptions, type UseMutationOptions } from '@tanstack/react-query'; +import type { AxiosError } from 'axios'; + +import { client } from '../client.gen'; +import { type Options, TransfersService } from '../sdk.gen'; +import type { CancelTransferTransfersTransferIdDeleteData, CancelTransferTransfersTransferIdDeleteError, CancelTransferTransfersTransferIdDeleteResponse, GetTransferLogsTransfersTransferIdLogsGetData, GetTransferLogsTransfersTransferIdLogsGetError, GetTransferLogsTransfersTransferIdLogsGetResponse, GetTransferLogTransfersTransferIdLogsStreamGetData, GetTransferLogTransfersTransferIdLogsStreamGetError, GetTransferLogTransfersTransferIdLogsStreamGetResponse, GetTransfersTransfersGetData, GetTransfersTransfersGetError, GetTransfersTransfersGetResponse, GetTransferTransfersTransferIdGetData, GetTransferTransfersTransferIdGetError, GetTransferTransfersTransferIdGetResponse, NewTransferTransfersPostData, NewTransferTransfersPostError, NewTransferTransfersPostResponse } from '../types.gen'; + +export type QueryKey = [ + Pick & { + _id: string; + _infinite?: boolean; + tags?: ReadonlyArray; + } +]; + +const createQueryKey = (id: string, options?: TOptions, infinite?: boolean, tags?: ReadonlyArray): [ + QueryKey[0] +] => { + const params: QueryKey[0] = { _id: id, baseURL: options?.baseURL || (options?.client ?? client).getConfig().baseURL } as QueryKey[0]; + if (infinite) { + params._infinite = infinite; + } + if (tags) { + params.tags = tags; + } + if (options?.body) { + params.body = options.body; + } + if (options?.headers) { + params.headers = options.headers; + } + if (options?.path) { + params.path = options.path; + } + if (options?.query) { + params.query = options.query; + } + return [params]; +}; + +export const getTransfersTransfersGetQueryKey = (options?: Options) => createQueryKey('getTransfersTransfersGet', options); + +/** + * Get Transfers + */ +export const getTransfersTransfersGetOptions = (options?: Options) => queryOptions, GetTransfersTransfersGetResponse, ReturnType>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await TransfersService.getTransfersTransfersGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getTransfersTransfersGetQueryKey(options) +}); + +/** + * New Transfer + */ +export const newTransferTransfersPostMutation = (options?: Partial>): UseMutationOptions, Options> => { + const mutationOptions: UseMutationOptions, Options> = { + mutationFn: async (fnOptions) => { + const { data } = await TransfersService.newTransferTransfersPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Cancel Transfer + */ +export const cancelTransferTransfersTransferIdDeleteMutation = (options?: Partial>): UseMutationOptions, Options> => { + const mutationOptions: UseMutationOptions, Options> = { + mutationFn: async (fnOptions) => { + const { data } = await TransfersService.cancelTransferTransfersTransferIdDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getTransferTransfersTransferIdGetQueryKey = (options: Options) => createQueryKey('getTransferTransfersTransferIdGet', options); + +/** + * Get Transfer + */ +export const getTransferTransfersTransferIdGetOptions = (options: Options) => queryOptions, GetTransferTransfersTransferIdGetResponse, ReturnType>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await TransfersService.getTransferTransfersTransferIdGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getTransferTransfersTransferIdGetQueryKey(options) +}); + +export const getTransferLogsTransfersTransferIdLogsGetQueryKey = (options: Options) => createQueryKey('getTransferLogsTransfersTransferIdLogsGet', options); + +/** + * Get Transfer Logs + */ +export const getTransferLogsTransfersTransferIdLogsGetOptions = (options: Options) => queryOptions, GetTransferLogsTransfersTransferIdLogsGetResponse, ReturnType>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await TransfersService.getTransferLogsTransfersTransferIdLogsGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getTransferLogsTransfersTransferIdLogsGetQueryKey(options) +}); + +export const getTransferLogTransfersTransferIdLogsStreamGetQueryKey = (options: Options) => createQueryKey('getTransferLogTransfersTransferIdLogsStreamGet', options); + +/** + * Get Transfer Log + */ +export const getTransferLogTransfersTransferIdLogsStreamGetOptions = (options: Options) => queryOptions, GetTransferLogTransfersTransferIdLogsStreamGetResponse, ReturnType>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await TransfersService.getTransferLogTransfersTransferIdLogsStreamGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getTransferLogTransfersTransferIdLogsStreamGetQueryKey(options) +}); diff --git a/frontend/src/client/client.gen.ts b/frontend/src/client/client.gen.ts new file mode 100644 index 0000000..cab3c70 --- /dev/null +++ b/frontend/src/client/client.gen.ts @@ -0,0 +1,16 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { type ClientOptions, type Config, createClient, createConfig } from './client'; +import type { ClientOptions as ClientOptions2 } from './types.gen'; + +/** + * The `createClientConfig()` function will be called on client initialization + * and the returned object will become the client's initial configuration. + * + * You may want to initialize your client this way instead of calling + * `setConfig()`. This is useful for example if you're using Next.js + * to ensure your client always has the correct values. + */ +export type CreateClientConfig = (override?: Config) => Config & T>; + +export const client = createClient(createConfig()); diff --git a/frontend/src/client/client/client.gen.ts b/frontend/src/client/client/client.gen.ts new file mode 100644 index 0000000..a421bbe --- /dev/null +++ b/frontend/src/client/client/client.gen.ts @@ -0,0 +1,159 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { AxiosError, AxiosInstance, RawAxiosRequestHeaders } from 'axios'; +import axios from 'axios'; + +import { createSseClient } from '../core/serverSentEvents.gen'; +import type { HttpMethod } from '../core/types.gen'; +import { getValidRequestBody } from '../core/utils.gen'; +import type { Client, Config, RequestOptions } from './types.gen'; +import { buildUrl, createConfig, mergeConfigs, mergeHeaders, setAuthParams } from './utils.gen'; + +export const createClient = (config: Config = {}): Client => { + let _config = mergeConfigs(createConfig(), config); + + let instance: AxiosInstance; + + if (_config.axios && !('Axios' in _config.axios)) { + instance = _config.axios; + } else { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { auth, ...configWithoutAuth } = _config; + instance = axios.create(configWithoutAuth); + } + + const getConfig = (): Config => ({ ..._config }); + + const setConfig = (config: Config): Config => { + _config = mergeConfigs(_config, config); + instance.defaults = { + ...instance.defaults, + ..._config, + // @ts-expect-error + headers: mergeHeaders(instance.defaults.headers, _config.headers), + }; + return getConfig(); + }; + + const beforeRequest = async (options: RequestOptions) => { + const opts = { + ..._config, + ...options, + axios: options.axios ?? _config.axios ?? instance, + headers: mergeHeaders(_config.headers, options.headers), + }; + + if (opts.security) { + await setAuthParams({ + ...opts, + security: opts.security, + }); + } + + if (opts.requestValidator) { + await opts.requestValidator(opts); + } + + if (opts.body !== undefined && opts.bodySerializer) { + opts.body = opts.bodySerializer(opts.body); + } + + const url = buildUrl(opts); + + return { opts, url }; + }; + + // @ts-expect-error + const request: Client['request'] = async (options) => { + // @ts-expect-error + const { opts, url } = await beforeRequest(options); + try { + // assign Axios here for consistency with fetch + const _axios = opts.axios!; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { auth, ...optsWithoutAuth } = opts; + const response = await _axios({ + ...optsWithoutAuth, + baseURL: '', // the baseURL is already included in `url` + data: getValidRequestBody(opts), + headers: opts.headers as RawAxiosRequestHeaders, + // let `paramsSerializer()` handle query params if it exists + params: opts.paramsSerializer ? opts.query : undefined, + url, + }); + + let { data } = response; + + if (opts.responseType === 'json') { + if (opts.responseValidator) { + await opts.responseValidator(data); + } + + if (opts.responseTransformer) { + data = await opts.responseTransformer(data); + } + } + + return { + ...response, + data: data ?? {}, + }; + } catch (error) { + const e = error as AxiosError; + if (opts.throwOnError) { + throw e; + } + // @ts-expect-error + e.error = e.response?.data ?? {}; + return e; + } + }; + + const makeMethodFn = (method: Uppercase) => (options: RequestOptions) => + request({ ...options, method }); + + const makeSseFn = (method: Uppercase) => async (options: RequestOptions) => { + const { opts, url } = await beforeRequest(options); + return createSseClient({ + ...opts, + body: opts.body as BodyInit | null | undefined, + headers: opts.headers as Record, + method, + serializedBody: getValidRequestBody(opts) as BodyInit | null | undefined, + // @ts-expect-error + signal: opts.signal, + url, + }); + }; + + const _buildUrl: Client['buildUrl'] = (options) => + buildUrl({ axios: instance, ..._config, ...options }); + + return { + buildUrl: _buildUrl, + connect: makeMethodFn('CONNECT'), + delete: makeMethodFn('DELETE'), + get: makeMethodFn('GET'), + getConfig, + head: makeMethodFn('HEAD'), + instance, + options: makeMethodFn('OPTIONS'), + patch: makeMethodFn('PATCH'), + post: makeMethodFn('POST'), + put: makeMethodFn('PUT'), + request, + setConfig, + sse: { + connect: makeSseFn('CONNECT'), + delete: makeSseFn('DELETE'), + get: makeSseFn('GET'), + head: makeSseFn('HEAD'), + options: makeSseFn('OPTIONS'), + patch: makeSseFn('PATCH'), + post: makeSseFn('POST'), + put: makeSseFn('PUT'), + trace: makeSseFn('TRACE'), + }, + trace: makeMethodFn('TRACE'), + } as Client; +}; diff --git a/frontend/src/client/client/index.ts b/frontend/src/client/client/index.ts new file mode 100644 index 0000000..7bd7b98 --- /dev/null +++ b/frontend/src/client/client/index.ts @@ -0,0 +1,23 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { Auth } from '../core/auth.gen'; +export type { QuerySerializerOptions } from '../core/bodySerializer.gen'; +export { + formDataBodySerializer, + jsonBodySerializer, + urlSearchParamsBodySerializer, +} from '../core/bodySerializer.gen'; +export { buildClientParams } from '../core/params.gen'; +export { serializeQueryKeyValue } from '../core/queryKeySerializer.gen'; +export { createClient } from './client.gen'; +export type { + Client, + ClientOptions, + Config, + CreateClientConfig, + Options, + RequestOptions, + RequestResult, + TDataShape, +} from './types.gen'; +export { createConfig } from './utils.gen'; diff --git a/frontend/src/client/client/types.gen.ts b/frontend/src/client/client/types.gen.ts new file mode 100644 index 0000000..e789d42 --- /dev/null +++ b/frontend/src/client/client/types.gen.ts @@ -0,0 +1,161 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { + AxiosError, + AxiosInstance, + AxiosRequestHeaders, + AxiosResponse, + AxiosStatic, + CreateAxiosDefaults, +} from 'axios'; + +import type { Auth } from '../core/auth.gen'; +import type { + ServerSentEventsOptions, + ServerSentEventsResult, +} from '../core/serverSentEvents.gen'; +import type { Client as CoreClient, Config as CoreConfig } from '../core/types.gen'; + +export interface Config + extends Omit, CoreConfig { + /** + * Axios implementation. You can use this option to provide either an + * `AxiosStatic` or an `AxiosInstance`. + * + * @default axios + */ + axios?: AxiosStatic | AxiosInstance; + /** + * Base URL for all requests made by this client. + */ + baseURL?: T['baseURL']; + /** + * An object containing any HTTP headers that you want to pre-populate your + * `Headers` object with. + * + * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more} + */ + headers?: + | AxiosRequestHeaders + | Record< + string, + string | number | boolean | (string | number | boolean)[] | null | undefined | unknown + >; + /** + * Throw an error instead of returning it in the response? + * + * @default false + */ + throwOnError?: T['throwOnError']; +} + +export interface RequestOptions< + TData = unknown, + ThrowOnError extends boolean = boolean, + Url extends string = string, +> + extends + Config<{ + throwOnError: ThrowOnError; + }>, + Pick< + ServerSentEventsOptions, + | 'onRequest' + | 'onSseError' + | 'onSseEvent' + | 'sseDefaultRetryDelay' + | 'sseMaxRetryAttempts' + | 'sseMaxRetryDelay' + > { + /** + * Any body that you want to add to your request. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#body} + */ + body?: unknown; + path?: Record; + query?: Record; + /** + * Security mechanism(s) to use for the request. + */ + security?: ReadonlyArray; + url: Url; +} + +export interface ClientOptions { + baseURL?: string; + throwOnError?: boolean; +} + +export type RequestResult< + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = boolean, +> = ThrowOnError extends true + ? Promise ? TData[keyof TData] : TData>> + : Promise< + | (AxiosResponse ? TData[keyof TData] : TData> & { + error: undefined; + }) + | (AxiosError ? TError[keyof TError] : TError> & { + data: undefined; + error: TError extends Record ? TError[keyof TError] : TError; + }) + >; + +type MethodFn = ( + options: Omit, 'method'>, +) => RequestResult; + +type SseFn = ( + options: Omit, 'method'>, +) => Promise>; + +type RequestFn = ( + options: Omit, 'method'> & + Pick>, 'method'>, +) => RequestResult; + +type BuildUrlFn = < + TData extends { + body?: unknown; + path?: Record; + query?: Record; + url: string; + }, +>( + options: TData & Options, +) => string; + +export type Client = CoreClient & { + instance: AxiosInstance; +}; + +/** + * The `createClientConfig()` function will be called on client initialization + * and the returned object will become the client's initial configuration. + * + * You may want to initialize your client this way instead of calling + * `setConfig()`. This is useful for example if you're using Next.js + * to ensure your client always has the correct values. + */ +export type CreateClientConfig = ( + override?: Config, +) => Config & T>; + +export interface TDataShape { + body?: unknown; + headers?: unknown; + path?: unknown; + query?: unknown; + url: string; +} + +type OmitKeys = Pick>; + +export type Options< + TData extends TDataShape = TDataShape, + ThrowOnError extends boolean = boolean, + TResponse = unknown, +> = OmitKeys, 'body' | 'path' | 'query' | 'url'> & + ([TData] extends [never] ? unknown : Omit); diff --git a/frontend/src/client/client/utils.gen.ts b/frontend/src/client/client/utils.gen.ts new file mode 100644 index 0000000..1b4600f --- /dev/null +++ b/frontend/src/client/client/utils.gen.ts @@ -0,0 +1,208 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { getAuthToken } from '../core/auth.gen'; +import type { QuerySerializerOptions } from '../core/bodySerializer.gen'; +import { + serializeArrayParam, + serializeObjectParam, + serializePrimitiveParam, +} from '../core/pathSerializer.gen'; +import { getUrl } from '../core/utils.gen'; +import type { Client, ClientOptions, Config, RequestOptions } from './types.gen'; + +export const createQuerySerializer = ({ + parameters = {}, + ...args +}: QuerySerializerOptions = {}) => { + const querySerializer = (queryParams: T) => { + const search: string[] = []; + if (queryParams && typeof queryParams === 'object') { + for (const name in queryParams) { + const value = queryParams[name]; + + if (value === undefined || value === null) { + continue; + } + + const options = parameters[name] || args; + + if (Array.isArray(value)) { + const serializedArray = serializeArrayParam({ + allowReserved: options.allowReserved, + explode: true, + name, + style: 'form', + value, + ...options.array, + }); + if (serializedArray) search.push(serializedArray); + } else if (typeof value === 'object') { + const serializedObject = serializeObjectParam({ + allowReserved: options.allowReserved, + explode: true, + name, + style: 'deepObject', + value: value as Record, + ...options.object, + }); + if (serializedObject) search.push(serializedObject); + } else { + const serializedPrimitive = serializePrimitiveParam({ + allowReserved: options.allowReserved, + name, + value: value as string, + }); + if (serializedPrimitive) search.push(serializedPrimitive); + } + } + } + return search.join('&'); + }; + return querySerializer; +}; + +const checkForExistence = ( + options: Pick & { + headers: Record; + }, + name?: string, +): boolean => { + if (!name) { + return false; + } + if (name in options.headers || options.query?.[name]) { + return true; + } + if ( + 'Cookie' in options.headers && + options.headers['Cookie'] && + typeof options.headers['Cookie'] === 'string' + ) { + return options.headers['Cookie'].includes(`${name}=`); + } + return false; +}; + +export const setAuthParams = async ({ + security, + ...options +}: Pick, 'security'> & + Pick & { + headers: Record; + }) => { + for (const auth of security) { + if (checkForExistence(options, auth.name)) { + continue; + } + const token = await getAuthToken(auth, options.auth); + + if (!token) { + continue; + } + + const name = auth.name ?? 'Authorization'; + + switch (auth.in) { + case 'query': + if (!options.query) { + options.query = {}; + } + options.query[name] = token; + break; + case 'cookie': { + const value = `${name}=${token}`; + if ('Cookie' in options.headers && options.headers['Cookie']) { + options.headers['Cookie'] = `${options.headers['Cookie']}; ${value}`; + } else { + options.headers['Cookie'] = value; + } + break; + } + case 'header': + default: + options.headers[name] = token; + break; + } + } +}; + +export const buildUrl: Client['buildUrl'] = (options) => { + const instanceBaseUrl = options.axios?.defaults?.baseURL; + + const baseUrl = + !!options.baseURL && typeof options.baseURL === 'string' ? options.baseURL : instanceBaseUrl; + + return getUrl({ + baseUrl: baseUrl as string, + path: options.path, + // let `paramsSerializer()` handle query params if it exists + query: !options.paramsSerializer ? options.query : undefined, + querySerializer: + typeof options.querySerializer === 'function' + ? options.querySerializer + : createQuerySerializer(options.querySerializer), + url: options.url, + }); +}; + +export const mergeConfigs = (a: Config, b: Config): Config => { + const config = { ...a, ...b }; + config.headers = mergeHeaders(a.headers, b.headers); + return config; +}; + +/** + * Special Axios headers keywords allowing to set headers by request method. + */ +export const axiosHeadersKeywords = [ + 'common', + 'delete', + 'get', + 'head', + 'patch', + 'post', + 'put', +] as const; + +export const mergeHeaders = ( + ...headers: Array['headers'] | undefined> +): Record => { + const mergedHeaders: Record = {}; + for (const header of headers) { + if (!header || typeof header !== 'object') { + continue; + } + + const iterator = Object.entries(header); + + for (const [key, value] of iterator) { + if ( + axiosHeadersKeywords.includes(key as (typeof axiosHeadersKeywords)[number]) && + typeof value === 'object' + ) { + mergedHeaders[key] = { + ...(mergedHeaders[key] as Record), + ...value, + }; + } else if (value === null) { + delete mergedHeaders[key]; + } else if (Array.isArray(value)) { + for (const v of value) { + // @ts-expect-error + mergedHeaders[key] = [...(mergedHeaders[key] ?? []), v as string]; + } + } else if (value !== undefined) { + // assume object headers are meant to be JSON stringified, i.e. their + // content value in OpenAPI specification is 'application/json' + mergedHeaders[key] = typeof value === 'object' ? JSON.stringify(value) : (value as string); + } + } + } + return mergedHeaders; +}; + +export const createConfig = ( + override: Config & T> = {}, +): Config & T> => ({ + ...override, +}); diff --git a/frontend/src/client/core/auth.gen.ts b/frontend/src/client/core/auth.gen.ts new file mode 100644 index 0000000..3ebf994 --- /dev/null +++ b/frontend/src/client/core/auth.gen.ts @@ -0,0 +1,41 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type AuthToken = string | undefined; + +export interface Auth { + /** + * Which part of the request do we use to send the auth? + * + * @default 'header' + */ + in?: 'header' | 'query' | 'cookie'; + /** + * Header or query parameter name. + * + * @default 'Authorization' + */ + name?: string; + scheme?: 'basic' | 'bearer'; + type: 'apiKey' | 'http'; +} + +export const getAuthToken = async ( + auth: Auth, + callback: ((auth: Auth) => Promise | AuthToken) | AuthToken, +): Promise => { + const token = typeof callback === 'function' ? await callback(auth) : callback; + + if (!token) { + return; + } + + if (auth.scheme === 'bearer') { + return `Bearer ${token}`; + } + + if (auth.scheme === 'basic') { + return `Basic ${btoa(token)}`; + } + + return token; +}; diff --git a/frontend/src/client/core/bodySerializer.gen.ts b/frontend/src/client/core/bodySerializer.gen.ts new file mode 100644 index 0000000..67daca6 --- /dev/null +++ b/frontend/src/client/core/bodySerializer.gen.ts @@ -0,0 +1,82 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { ArrayStyle, ObjectStyle, SerializerOptions } from './pathSerializer.gen'; + +export type QuerySerializer = (query: Record) => string; + +export type BodySerializer = (body: unknown) => unknown; + +type QuerySerializerOptionsObject = { + allowReserved?: boolean; + array?: Partial>; + object?: Partial>; +}; + +export type QuerySerializerOptions = QuerySerializerOptionsObject & { + /** + * Per-parameter serialization overrides. When provided, these settings + * override the global array/object settings for specific parameter names. + */ + parameters?: Record; +}; + +const serializeFormDataPair = (data: FormData, key: string, value: unknown): void => { + if (typeof value === 'string' || value instanceof Blob) { + data.append(key, value); + } else if (value instanceof Date) { + data.append(key, value.toISOString()); + } else { + data.append(key, JSON.stringify(value)); + } +}; + +const serializeUrlSearchParamsPair = (data: URLSearchParams, key: string, value: unknown): void => { + if (typeof value === 'string') { + data.append(key, value); + } else { + data.append(key, JSON.stringify(value)); + } +}; + +export const formDataBodySerializer = { + bodySerializer: (body: unknown): FormData => { + const data = new FormData(); + + Object.entries(body as Record).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeFormDataPair(data, key, v)); + } else { + serializeFormDataPair(data, key, value); + } + }); + + return data; + }, +}; + +export const jsonBodySerializer = { + bodySerializer: (body: unknown): string => + JSON.stringify(body, (_key, value) => (typeof value === 'bigint' ? value.toString() : value)), +}; + +export const urlSearchParamsBodySerializer = { + bodySerializer: (body: unknown): string => { + const data = new URLSearchParams(); + + Object.entries(body as Record).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeUrlSearchParamsPair(data, key, v)); + } else { + serializeUrlSearchParamsPair(data, key, value); + } + }); + + return data.toString(); + }, +}; diff --git a/frontend/src/client/core/params.gen.ts b/frontend/src/client/core/params.gen.ts new file mode 100644 index 0000000..7955601 --- /dev/null +++ b/frontend/src/client/core/params.gen.ts @@ -0,0 +1,169 @@ +// This file is auto-generated by @hey-api/openapi-ts + +type Slot = 'body' | 'headers' | 'path' | 'query'; + +export type Field = + | { + in: Exclude; + /** + * Field name. This is the name we want the user to see and use. + */ + key: string; + /** + * Field mapped name. This is the name we want to use in the request. + * If omitted, we use the same value as `key`. + */ + map?: string; + } + | { + in: Extract; + /** + * Key isn't required for bodies. + */ + key?: string; + map?: string; + } + | { + /** + * Field name. This is the name we want the user to see and use. + */ + key: string; + /** + * Field mapped name. This is the name we want to use in the request. + * If `in` is omitted, `map` aliases `key` to the transport layer. + */ + map: Slot; + }; + +export interface Fields { + allowExtra?: Partial>; + args?: ReadonlyArray; +} + +export type FieldsConfig = ReadonlyArray; + +const extraPrefixesMap: Record = { + $body_: 'body', + $headers_: 'headers', + $path_: 'path', + $query_: 'query', +}; +const extraPrefixes = Object.entries(extraPrefixesMap); + +type KeyMap = Map< + string, + | { + in: Slot; + map?: string; + } + | { + in?: never; + map: Slot; + } +>; + +const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { + if (!map) { + map = new Map(); + } + + for (const config of fields) { + if ('in' in config) { + if (config.key) { + map.set(config.key, { + in: config.in, + map: config.map, + }); + } + } else if ('key' in config) { + map.set(config.key, { + map: config.map, + }); + } else if (config.args) { + buildKeyMap(config.args, map); + } + } + + return map; +}; + +interface Params { + body: unknown; + headers: Record; + path: Record; + query: Record; +} + +const stripEmptySlots = (params: Params) => { + for (const [slot, value] of Object.entries(params)) { + if (value && typeof value === 'object' && !Array.isArray(value) && !Object.keys(value).length) { + delete params[slot as Slot]; + } + } +}; + +export const buildClientParams = (args: ReadonlyArray, fields: FieldsConfig) => { + const params: Params = { + body: {}, + headers: {}, + path: {}, + query: {}, + }; + + const map = buildKeyMap(fields); + + let config: FieldsConfig[number] | undefined; + + for (const [index, arg] of args.entries()) { + if (fields[index]) { + config = fields[index]; + } + + if (!config) { + continue; + } + + if ('in' in config) { + if (config.key) { + const field = map.get(config.key)!; + const name = field.map || config.key; + if (field.in) { + (params[field.in] as Record)[name] = arg; + } + } else { + params.body = arg; + } + } else { + for (const [key, value] of Object.entries(arg ?? {})) { + const field = map.get(key); + + if (field) { + if (field.in) { + const name = field.map || key; + (params[field.in] as Record)[name] = value; + } else { + params[field.map] = value; + } + } else { + const extra = extraPrefixes.find(([prefix]) => key.startsWith(prefix)); + + if (extra) { + const [prefix, slot] = extra; + (params[slot] as Record)[key.slice(prefix.length)] = value; + } else if ('allowExtra' in config && config.allowExtra) { + for (const [slot, allowed] of Object.entries(config.allowExtra)) { + if (allowed) { + (params[slot as Slot] as Record)[key] = value; + break; + } + } + } + } + } + } + } + + stripEmptySlots(params); + + return params; +}; diff --git a/frontend/src/client/core/pathSerializer.gen.ts b/frontend/src/client/core/pathSerializer.gen.ts new file mode 100644 index 0000000..994b284 --- /dev/null +++ b/frontend/src/client/core/pathSerializer.gen.ts @@ -0,0 +1,171 @@ +// This file is auto-generated by @hey-api/openapi-ts + +interface SerializeOptions extends SerializePrimitiveOptions, SerializerOptions {} + +interface SerializePrimitiveOptions { + allowReserved?: boolean; + name: string; +} + +export interface SerializerOptions { + /** + * @default true + */ + explode: boolean; + style: T; +} + +export type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited'; +export type ArraySeparatorStyle = ArrayStyle | MatrixStyle; +type MatrixStyle = 'label' | 'matrix' | 'simple'; +export type ObjectStyle = 'form' | 'deepObject'; +type ObjectSeparatorStyle = ObjectStyle | MatrixStyle; + +interface SerializePrimitiveParam extends SerializePrimitiveOptions { + value: string; +} + +export const separatorArrayExplode = (style: ArraySeparatorStyle) => { + switch (style) { + case 'label': + return '.'; + case 'matrix': + return ';'; + case 'simple': + return ','; + default: + return '&'; + } +}; + +export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => { + switch (style) { + case 'form': + return ','; + case 'pipeDelimited': + return '|'; + case 'spaceDelimited': + return '%20'; + default: + return ','; + } +}; + +export const separatorObjectExplode = (style: ObjectSeparatorStyle) => { + switch (style) { + case 'label': + return '.'; + case 'matrix': + return ';'; + case 'simple': + return ','; + default: + return '&'; + } +}; + +export const serializeArrayParam = ({ + allowReserved, + explode, + name, + style, + value, +}: SerializeOptions & { + value: unknown[]; +}) => { + if (!explode) { + const joinedValues = ( + allowReserved ? value : value.map((v) => encodeURIComponent(v as string)) + ).join(separatorArrayNoExplode(style)); + switch (style) { + case 'label': + return `.${joinedValues}`; + case 'matrix': + return `;${name}=${joinedValues}`; + case 'simple': + return joinedValues; + default: + return `${name}=${joinedValues}`; + } + } + + const separator = separatorArrayExplode(style); + const joinedValues = value + .map((v) => { + if (style === 'label' || style === 'simple') { + return allowReserved ? v : encodeURIComponent(v as string); + } + + return serializePrimitiveParam({ + allowReserved, + name, + value: v as string, + }); + }) + .join(separator); + return style === 'label' || style === 'matrix' ? separator + joinedValues : joinedValues; +}; + +export const serializePrimitiveParam = ({ + allowReserved, + name, + value, +}: SerializePrimitiveParam) => { + if (value === undefined || value === null) { + return ''; + } + + if (typeof value === 'object') { + throw new Error( + 'Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.', + ); + } + + return `${name}=${allowReserved ? value : encodeURIComponent(value)}`; +}; + +export const serializeObjectParam = ({ + allowReserved, + explode, + name, + style, + value, + valueOnly, +}: SerializeOptions & { + value: Record | Date; + valueOnly?: boolean; +}) => { + if (value instanceof Date) { + return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`; + } + + if (style !== 'deepObject' && !explode) { + let values: string[] = []; + Object.entries(value).forEach(([key, v]) => { + values = [...values, key, allowReserved ? (v as string) : encodeURIComponent(v as string)]; + }); + const joinedValues = values.join(','); + switch (style) { + case 'form': + return `${name}=${joinedValues}`; + case 'label': + return `.${joinedValues}`; + case 'matrix': + return `;${name}=${joinedValues}`; + default: + return joinedValues; + } + } + + const separator = separatorObjectExplode(style); + const joinedValues = Object.entries(value) + .map(([key, v]) => + serializePrimitiveParam({ + allowReserved, + name: style === 'deepObject' ? `${name}[${key}]` : key, + value: v as string, + }), + ) + .join(separator); + return style === 'label' || style === 'matrix' ? separator + joinedValues : joinedValues; +}; diff --git a/frontend/src/client/core/queryKeySerializer.gen.ts b/frontend/src/client/core/queryKeySerializer.gen.ts new file mode 100644 index 0000000..5000df6 --- /dev/null +++ b/frontend/src/client/core/queryKeySerializer.gen.ts @@ -0,0 +1,117 @@ +// This file is auto-generated by @hey-api/openapi-ts + +/** + * JSON-friendly union that mirrors what Pinia Colada can hash. + */ +export type JsonValue = + | null + | string + | number + | boolean + | JsonValue[] + | { [key: string]: JsonValue }; + +/** + * Replacer that converts non-JSON values (bigint, Date, etc.) to safe substitutes. + */ +export const queryKeyJsonReplacer = (_key: string, value: unknown) => { + if (value === undefined || typeof value === 'function' || typeof value === 'symbol') { + return undefined; + } + if (typeof value === 'bigint') { + return value.toString(); + } + if (value instanceof Date) { + return value.toISOString(); + } + return value; +}; + +/** + * Safely stringifies a value and parses it back into a JsonValue. + */ +export const stringifyToJsonValue = (input: unknown): JsonValue | undefined => { + try { + const json = JSON.stringify(input, queryKeyJsonReplacer); + if (json === undefined) { + return undefined; + } + return JSON.parse(json) as JsonValue; + } catch { + return undefined; + } +}; + +/** + * Detects plain objects (including objects with a null prototype). + */ +const isPlainObject = (value: unknown): value is Record => { + if (value === null || typeof value !== 'object') { + return false; + } + const prototype = Object.getPrototypeOf(value as object); + return prototype === Object.prototype || prototype === null; +}; + +/** + * Turns URLSearchParams into a sorted JSON object for deterministic keys. + */ +const serializeSearchParams = (params: URLSearchParams): JsonValue => { + const entries = Array.from(params.entries()).sort(([a], [b]) => a.localeCompare(b)); + const result: Record = {}; + + for (const [key, value] of entries) { + const existing = result[key]; + if (existing === undefined) { + result[key] = value; + continue; + } + + if (Array.isArray(existing)) { + (existing as string[]).push(value); + } else { + result[key] = [existing, value]; + } + } + + return result; +}; + +/** + * Normalizes any accepted value into a JSON-friendly shape for query keys. + */ +export const serializeQueryKeyValue = (value: unknown): JsonValue | undefined => { + if (value === null) { + return null; + } + + if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { + return value; + } + + if (value === undefined || typeof value === 'function' || typeof value === 'symbol') { + return undefined; + } + + if (typeof value === 'bigint') { + return value.toString(); + } + + if (value instanceof Date) { + return value.toISOString(); + } + + if (Array.isArray(value)) { + return stringifyToJsonValue(value); + } + + if (typeof URLSearchParams !== 'undefined' && value instanceof URLSearchParams) { + return serializeSearchParams(value); + } + + if (isPlainObject(value)) { + return stringifyToJsonValue(value); + } + + return undefined; +}; diff --git a/frontend/src/client/core/serverSentEvents.gen.ts b/frontend/src/client/core/serverSentEvents.gen.ts new file mode 100644 index 0000000..6aa6cf0 --- /dev/null +++ b/frontend/src/client/core/serverSentEvents.gen.ts @@ -0,0 +1,243 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { Config } from './types.gen'; + +export type ServerSentEventsOptions = Omit & + Pick & { + /** + * Fetch API implementation. You can use this option to provide a custom + * fetch instance. + * + * @default globalThis.fetch + */ + fetch?: typeof fetch; + /** + * Implementing clients can call request interceptors inside this hook. + */ + onRequest?: (url: string, init: RequestInit) => Promise; + /** + * Callback invoked when a network or parsing error occurs during streaming. + * + * This option applies only if the endpoint returns a stream of events. + * + * @param error The error that occurred. + */ + onSseError?: (error: unknown) => void; + /** + * Callback invoked when an event is streamed from the server. + * + * This option applies only if the endpoint returns a stream of events. + * + * @param event Event streamed from the server. + * @returns Nothing (void). + */ + onSseEvent?: (event: StreamEvent) => void; + serializedBody?: RequestInit['body']; + /** + * Default retry delay in milliseconds. + * + * This option applies only if the endpoint returns a stream of events. + * + * @default 3000 + */ + sseDefaultRetryDelay?: number; + /** + * Maximum number of retry attempts before giving up. + */ + sseMaxRetryAttempts?: number; + /** + * Maximum retry delay in milliseconds. + * + * Applies only when exponential backoff is used. + * + * This option applies only if the endpoint returns a stream of events. + * + * @default 30000 + */ + sseMaxRetryDelay?: number; + /** + * Optional sleep function for retry backoff. + * + * Defaults to using `setTimeout`. + */ + sseSleepFn?: (ms: number) => Promise; + url: string; + }; + +export interface StreamEvent { + data: TData; + event?: string; + id?: string; + retry?: number; +} + +export type ServerSentEventsResult = { + stream: AsyncGenerator< + TData extends Record ? TData[keyof TData] : TData, + TReturn, + TNext + >; +}; + +export const createSseClient = ({ + onRequest, + onSseError, + onSseEvent, + responseTransformer, + responseValidator, + sseDefaultRetryDelay, + sseMaxRetryAttempts, + sseMaxRetryDelay, + sseSleepFn, + url, + ...options +}: ServerSentEventsOptions): ServerSentEventsResult => { + let lastEventId: string | undefined; + + const sleep = sseSleepFn ?? ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms))); + + const createStream = async function* () { + let retryDelay: number = sseDefaultRetryDelay ?? 3000; + let attempt = 0; + const signal = options.signal ?? new AbortController().signal; + + while (true) { + if (signal.aborted) break; + + attempt++; + + const headers = + options.headers instanceof Headers + ? options.headers + : new Headers(options.headers as Record | undefined); + + if (lastEventId !== undefined) { + headers.set('Last-Event-ID', lastEventId); + } + + try { + const requestInit: RequestInit = { + redirect: 'follow', + ...options, + body: options.serializedBody, + headers, + signal, + }; + let request = new Request(url, requestInit); + if (onRequest) { + request = await onRequest(url, requestInit); + } + // fetch must be assigned here, otherwise it would throw the error: + // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation + const _fetch = options.fetch ?? globalThis.fetch; + const response = await _fetch(request); + + if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`); + + if (!response.body) throw new Error('No body in SSE response'); + + const reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); + + let buffer = ''; + + const abortHandler = () => { + try { + reader.cancel(); + } catch { + // noop + } + }; + + signal.addEventListener('abort', abortHandler); + + try { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + buffer += value; + // Normalize line endings: CRLF -> LF, then CR -> LF + buffer = buffer.replace(/\r\n/g, '\n').replace(/\r/g, '\n'); + + const chunks = buffer.split('\n\n'); + buffer = chunks.pop() ?? ''; + + for (const chunk of chunks) { + const lines = chunk.split('\n'); + const dataLines: Array = []; + let eventName: string | undefined; + + for (const line of lines) { + if (line.startsWith('data:')) { + dataLines.push(line.replace(/^data:\s*/, '')); + } else if (line.startsWith('event:')) { + eventName = line.replace(/^event:\s*/, ''); + } else if (line.startsWith('id:')) { + lastEventId = line.replace(/^id:\s*/, ''); + } else if (line.startsWith('retry:')) { + const parsed = Number.parseInt(line.replace(/^retry:\s*/, ''), 10); + if (!Number.isNaN(parsed)) { + retryDelay = parsed; + } + } + } + + let data: unknown; + let parsedJson = false; + + if (dataLines.length) { + const rawData = dataLines.join('\n'); + try { + data = JSON.parse(rawData); + parsedJson = true; + } catch { + data = rawData; + } + } + + if (parsedJson) { + if (responseValidator) { + await responseValidator(data); + } + + if (responseTransformer) { + data = await responseTransformer(data); + } + } + + onSseEvent?.({ + data, + event: eventName, + id: lastEventId, + retry: retryDelay, + }); + + if (dataLines.length) { + yield data as any; + } + } + } + } finally { + signal.removeEventListener('abort', abortHandler); + reader.releaseLock(); + } + + break; // exit loop on normal completion + } catch (error) { + // connection failed or aborted; retry after delay + onSseError?.(error); + + if (sseMaxRetryAttempts !== undefined && attempt >= sseMaxRetryAttempts) { + break; // stop after firing error + } + + // exponential backoff: double retry each attempt, cap at 30s + const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 30000); + await sleep(backoff); + } + } + }; + + const stream = createStream(); + + return { stream }; +}; diff --git a/frontend/src/client/core/types.gen.ts b/frontend/src/client/core/types.gen.ts new file mode 100644 index 0000000..9746325 --- /dev/null +++ b/frontend/src/client/core/types.gen.ts @@ -0,0 +1,104 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { Auth, AuthToken } from './auth.gen'; +import type { BodySerializer, QuerySerializer, QuerySerializerOptions } from './bodySerializer.gen'; + +export type HttpMethod = + | 'connect' + | 'delete' + | 'get' + | 'head' + | 'options' + | 'patch' + | 'post' + | 'put' + | 'trace'; + +export type Client< + RequestFn = never, + Config = unknown, + MethodFn = never, + BuildUrlFn = never, + SseFn = never, +> = { + /** + * Returns the final request URL. + */ + buildUrl: BuildUrlFn; + getConfig: () => Config; + request: RequestFn; + setConfig: (config: Config) => Config; +} & { + [K in HttpMethod]: MethodFn; +} & ([SseFn] extends [never] ? { sse?: never } : { sse: { [K in HttpMethod]: SseFn } }); + +export interface Config { + /** + * Auth token or a function returning auth token. The resolved value will be + * added to the request payload as defined by its `security` array. + */ + auth?: ((auth: Auth) => Promise | AuthToken) | AuthToken; + /** + * A function for serializing request body parameter. By default, + * {@link JSON.stringify()} will be used. + */ + bodySerializer?: BodySerializer | null; + /** + * An object containing any HTTP headers that you want to pre-populate your + * `Headers` object with. + * + * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more} + */ + headers?: + | RequestInit['headers'] + | Record< + string, + string | number | boolean | (string | number | boolean)[] | null | undefined | unknown + >; + /** + * The request method. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more} + */ + method?: Uppercase; + /** + * A function for serializing request query parameters. By default, arrays + * will be exploded in form style, objects will be exploded in deepObject + * style, and reserved characters are percent-encoded. + * + * This method will have no effect if the native `paramsSerializer()` Axios + * API function is used. + * + * {@link https://swagger.io/docs/specification/serialization/#query View examples} + */ + querySerializer?: QuerySerializer | QuerySerializerOptions; + /** + * A function validating request data. This is useful if you want to ensure + * the request conforms to the desired shape, so it can be safely sent to + * the server. + */ + requestValidator?: (data: unknown) => Promise; + /** + * A function transforming response data before it's returned. This is useful + * for post-processing data, e.g. converting ISO strings into Date objects. + */ + responseTransformer?: (data: unknown) => Promise; + /** + * A function validating response data. This is useful if you want to ensure + * the response conforms to the desired shape, so it can be safely passed to + * the transformers and returned to the user. + */ + responseValidator?: (data: unknown) => Promise; +} + +type IsExactlyNeverOrNeverUndefined = [T] extends [never] + ? true + : [T] extends [never | undefined] + ? [undefined] extends [T] + ? false + : true + : false; + +export type OmitNever> = { + [K in keyof T as IsExactlyNeverOrNeverUndefined extends true ? never : K]: T[K]; +}; diff --git a/frontend/src/client/core/utils.gen.ts b/frontend/src/client/core/utils.gen.ts new file mode 100644 index 0000000..e7ddbe3 --- /dev/null +++ b/frontend/src/client/core/utils.gen.ts @@ -0,0 +1,140 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { BodySerializer, QuerySerializer } from './bodySerializer.gen'; +import { + type ArraySeparatorStyle, + serializeArrayParam, + serializeObjectParam, + serializePrimitiveParam, +} from './pathSerializer.gen'; + +export interface PathSerializer { + path: Record; + url: string; +} + +export const PATH_PARAM_RE = /\{[^{}]+\}/g; + +export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { + let url = _url; + const matches = _url.match(PATH_PARAM_RE); + if (matches) { + for (const match of matches) { + let explode = false; + let name = match.substring(1, match.length - 1); + let style: ArraySeparatorStyle = 'simple'; + + if (name.endsWith('*')) { + explode = true; + name = name.substring(0, name.length - 1); + } + + if (name.startsWith('.')) { + name = name.substring(1); + style = 'label'; + } else if (name.startsWith(';')) { + name = name.substring(1); + style = 'matrix'; + } + + const value = path[name]; + + if (value === undefined || value === null) { + continue; + } + + if (Array.isArray(value)) { + url = url.replace(match, serializeArrayParam({ explode, name, style, value })); + continue; + } + + if (typeof value === 'object') { + url = url.replace( + match, + serializeObjectParam({ + explode, + name, + style, + value: value as Record, + valueOnly: true, + }), + ); + continue; + } + + if (style === 'matrix') { + url = url.replace( + match, + `;${serializePrimitiveParam({ + name, + value: value as string, + })}`, + ); + continue; + } + + const replaceValue = encodeURIComponent( + style === 'label' ? `.${value as string}` : (value as string), + ); + url = url.replace(match, replaceValue); + } + } + return url; +}; + +export const getUrl = ({ + baseUrl, + path, + query, + querySerializer, + url: _url, +}: { + baseUrl?: string; + path?: Record; + query?: Record; + querySerializer: QuerySerializer; + url: string; +}) => { + const pathUrl = _url.startsWith('/') ? _url : `/${_url}`; + let url = (baseUrl ?? '') + pathUrl; + if (path) { + url = defaultPathSerializer({ path, url }); + } + let search = query ? querySerializer(query) : ''; + if (search.startsWith('?')) { + search = search.substring(1); + } + if (search) { + url += `?${search}`; + } + return url; +}; + +export function getValidRequestBody(options: { + body?: unknown; + bodySerializer?: BodySerializer | null; + serializedBody?: unknown; +}) { + const hasBody = options.body !== undefined; + const isSerializedBody = hasBody && options.bodySerializer; + + if (isSerializedBody) { + if ('serializedBody' in options) { + const hasSerializedBody = + options.serializedBody !== undefined && options.serializedBody !== ''; + + return hasSerializedBody ? options.serializedBody : null; + } + + // not all clients implement a serializedBody property (i.e. client-axios) + return options.body !== '' ? options.body : null; + } + + // plain/text body + if (hasBody) { + return options.body; + } + + // no body was provided + return undefined; +} diff --git a/frontend/src/client/index.ts b/frontend/src/client/index.ts new file mode 100644 index 0000000..93531eb --- /dev/null +++ b/frontend/src/client/index.ts @@ -0,0 +1,4 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export { type Options, TransfersService } from './sdk.gen'; +export type { BatchProcessingPipelineParameters, BinaryDataStreamingDataHandlerParameters, BinaryFileWritingDataHandlerParameters, CancelTransferTransfersTransferIdDeleteData, CancelTransferTransfersTransferIdDeleteError, CancelTransferTransfersTransferIdDeleteErrors, CancelTransferTransfersTransferIdDeleteResponse, CancelTransferTransfersTransferIdDeleteResponses, ClientOptions, ConstValueParameters, ConsumerConnectionInfo, GenericRandomNumpyArrayParameters, GetTransferLogsTransfersTransferIdLogsGetData, GetTransferLogsTransfersTransferIdLogsGetError, GetTransferLogsTransfersTransferIdLogsGetErrors, GetTransferLogsTransfersTransferIdLogsGetResponse, GetTransferLogsTransfersTransferIdLogsGetResponses, GetTransferLogTransfersTransferIdLogsStreamGetData, GetTransferLogTransfersTransferIdLogsStreamGetError, GetTransferLogTransfersTransferIdLogsStreamGetErrors, GetTransferLogTransfersTransferIdLogsStreamGetResponse, GetTransferLogTransfersTransferIdLogsStreamGetResponses, GetTransfersTransfersGetData, GetTransfersTransfersGetError, GetTransfersTransfersGetErrors, GetTransfersTransfersGetResponse, GetTransfersTransfersGetResponses, GetTransferTransfersTransferIdGetData, GetTransferTransfersTransferIdGetError, GetTransferTransfersTransferIdGetErrors, GetTransferTransfersTransferIdGetResponse, GetTransferTransfersTransferIdGetResponses, Hdf5BinarySerializerParameters, HttpValidationError, InternalEventSourceParameters, LogReadMode, LogStream, Message, NewTransferTransfersPostData, NewTransferTransfersPostError, NewTransferTransfersPostErrors, NewTransferTransfersPostResponse, NewTransferTransfersPostResponses, Parameters, PeaknetPreprocessingPipelineParameters, Psana1DetectorInterfaceParameters, Psana1EventSourceParameters, Psana1TimestampParameters, Psana2DetectorInterfaceParameters, Psana2EventSourceParameters, Psana2RunInfoParameters, Psana2TimestampParameters, SimplonBinarySerializerParameters, SourceIdentifierParameters, TransferCreate, TransferDetail, TransferLogIndex, TransferLogStreamInfo, TransferPublic, TransfersPublic, TransferState, TransitionPublic, TransitionSource, ValidationError } from './types.gen'; diff --git a/frontend/src/client/schemas.gen.ts b/frontend/src/client/schemas.gen.ts new file mode 100644 index 0000000..2686457 --- /dev/null +++ b/frontend/src/client/schemas.gen.ts @@ -0,0 +1,1081 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export const BatchProcessingPipelineParametersSchema = { + additionalProperties: false, + description: 'Configuration parameters for the Batch Processing Pipeline\n\nThis pipeline accumulates individual events into fixed-size batches before\npassing them downstream\n\nAttributes:\n\n type: Discriminator field, must be ``"BatchProcessingPipeline"``\n\n batch_size: Number of events to accumulate per batch', + properties: { + batch_size: { + title: 'Batch Size', + type: 'integer' + }, + type: { + const: 'BatchProcessingPipeline', + title: 'Type', + type: 'string' + } + }, + required: [ + 'type', + 'batch_size' + ], + title: 'BatchProcessingPipelineParameters', + type: 'object' +} as const; + +export const BinaryDataStreamingDataHandlerParametersSchema = { + additionalProperties: false, + description: 'Configuration parameters for the Binary Data Streaming Data Handler\n\nThis data handler forwards serialized byte objects to one or more remote\nendpoints over a ZMQ PUSH socket\n\nAttributes:\n\n type: Discriminator field, must be ``"BinaryDataStreamingDataHandler"``\n\n urls: List of endpoint URLs to bind to (server mode) or connect to\n (client mode)\n\n distribute: Boolean, if True: round robin connect the ranks, False: all ranks connect to all urls and send the same data\n\n buffer: buffer size, if set to 0 the OS default is used\n\n role: Whether this node acts as the ZMQ ``"server"`` (binds) or\n ``"client"`` (connects). Defaults to ``"server"``\n\n library: Underlying transport library to use. Currently only ``"zmq"``\n is supported. Defaults to ``"zmq"``\n\n socket_type: Socket pattern to use. Currently only ``"push"`` is\n supported. Defaults to ``"push"``', + properties: { + buffer: { + default: 0, + title: 'Buffer', + type: 'integer' + }, + distribute: { + default: true, + title: 'Distribute', + type: 'boolean' + }, + library: { + const: 'zmq', + default: 'zmq', + title: 'Library', + type: 'string' + }, + role: { + default: 'client', + enum: [ + 'server', + 'client' + ], + title: 'Role', + type: 'string' + }, + socket_type: { + const: 'push', + default: 'push', + title: 'Socket Type', + type: 'string' + }, + type: { + const: 'BinaryDataStreamingDataHandler', + title: 'Type', + type: 'string' + }, + urls: { + items: { + type: 'string' + }, + title: 'Urls', + type: 'array' + } + }, + required: [ + 'type', + 'urls' + ], + title: 'BinaryDataStreamingDataHandlerParameters', + type: 'object' +} as const; + +export const BinaryFileWritingDataHandlerParametersSchema = { + additionalProperties: false, + description: 'Configuration parameters for the Binary File Writing Data Handler\n\nThis data handler writes each serialized byte object to a separate file on\nthe filesystem\n\nAttributes:\n\n type: Discriminator field, must be ``"BinaryFileWritingDataHandler"``\n\n file_prefix: Optional string prepended to every output filename,\n separated from the rest of the name by an underscore. Defaults to\n ``""`` (no prefix)\n\n file_suffix: File extension used for output files, without the leading\n dot. Defaults to ``"h5"``\n\n write_directory: Directory in which output files are created. The\n directory is created (including parents) if it does not already\n exist. Defaults to the current working directory', + properties: { + file_prefix: { + default: '', + title: 'File Prefix', + type: 'string' + }, + file_suffix: { + default: 'h5', + title: 'File Suffix', + type: 'string' + }, + type: { + const: 'BinaryFileWritingDataHandler', + title: 'Type', + type: 'string' + }, + write_directory: { + format: 'path', + title: 'Write Directory', + type: 'string' + } + }, + required: [ + 'type' + ], + title: 'BinaryFileWritingDataHandlerParameters', + type: 'object' +} as const; + +export const ConstValueParametersSchema = { + additionalProperties: false, + description: 'Parameters for ConstValue class', + properties: { + dtype: { + title: 'Dtype', + type: 'string' + }, + type: { + const: 'ConstValue', + title: 'Type', + type: 'string' + }, + value: { + anyOf: [ + { + type: 'integer' + }, + { + type: 'number' + }, + { + items: { + anyOf: [ + { + type: 'integer' + }, + { + type: 'number' + } + ] + }, + type: 'array' + } + ], + title: 'Value' + } + }, + required: [ + 'type', + 'value', + 'dtype' + ], + title: 'ConstValueParameters', + type: 'object' +} as const; + +export const ConsumerConnectionInfoSchema = { + description: 'The cache push socket the consumer connects to.', + properties: { + host: { + title: 'Host', + type: 'string' + }, + port: { + title: 'Port', + type: 'integer' + }, + uri: { + title: 'Uri', + type: 'string' + } + }, + required: [ + 'host', + 'port', + 'uri' + ], + title: 'ConsumerConnectionInfo', + type: 'object' +} as const; + +export const GenericRandomNumpyArrayParametersSchema = { + additionalProperties: false, + description: 'Parameters for the GenericRandomNumpyArray class', + properties: { + always_random: { + default: true, + title: 'Always Random', + type: 'boolean' + }, + array_dtype: { + title: 'Array Dtype', + type: 'string' + }, + array_shape: { + anyOf: [ + { + type: 'integer' + }, + { + items: { + type: 'integer' + }, + type: 'array' + } + ], + title: 'Array Shape' + }, + type: { + const: 'GenericRandomNumpyArray', + title: 'Type', + type: 'string' + } + }, + required: [ + 'type', + 'array_shape', + 'array_dtype' + ], + title: 'GenericRandomNumpyArrayParameters', + type: 'object' +} as const; + +export const HDF5BinarySerializerParametersSchema = { + additionalProperties: false, + description: 'Configuration parameters for the HDF5 binary serializer\n\nThis serializer encodes a batch of event data arrays into an in-memory\nHDF5 file. Optional compression can be applied to each dataset\n\nAttributes:\n\n type: Discriminator field, must be ``"HDF5BinarySerializer"``\n\n compression_level: Compression level passed to the chosen algorithm.\n Interpretation depends on the algorithm. Defaults to ``3``\n\n compression: Compression algorithm to use. Supported values are\n ``"gzip"``, ``"gzip_with_shuffle"``, ``"bitshuffle_with_lz4"``,\n ``"bitshuffle_with_zstd"``, and ``"zfp"``. Set to ``None`` to\n disable compression. Defaults to ``None``\n\n fields: Dictionary storing the mapping from data source name to the\n HDF5 dataset path under which that source\'s data will be stored', + properties: { + compression: { + anyOf: [ + { + enum: [ + 'gzip', + 'gzip_with_shuffle', + 'bitshuffle_with_lz4', + 'bitshuffle_with_zstd', + 'zfp' + ], + type: 'string' + }, + { + type: 'null' + } + ], + title: 'Compression' + }, + compression_level: { + default: 0, + title: 'Compression Level', + type: 'integer' + }, + fields: { + additionalProperties: { + type: 'string' + }, + title: 'Fields', + type: 'object' + }, + type: { + const: 'HDF5BinarySerializer', + title: 'Type', + type: 'string' + } + }, + required: [ + 'type', + 'fields' + ], + title: 'HDF5BinarySerializerParameters', + type: 'object' +} as const; + +export const HTTPValidationErrorSchema = { + properties: { + detail: { + items: { + $ref: '#/components/schemas/ValidationError' + }, + title: 'Detail', + type: 'array' + } + }, + title: 'HTTPValidationError', + type: 'object' +} as const; + +export const InternalEventSourceParametersSchema = { + additionalProperties: true, + description: 'Configuration parameters for the Internal Event Source\n\nThis event source generates synthetic events entirely in-process and does\nnot depend on any external data-acquisition framework. It is intended\nmainly for testing and development\n\nAttributes:\n\n type: Discriminator field, must be ``"InternalEventSource"``\n\n number_of_events_to_generate: Total number of synthetic events to\n produce before the source is exhausted', + properties: { + number_of_events_to_generate: { + title: 'Number Of Events To Generate', + type: 'integer' + }, + type: { + const: 'InternalEventSource', + title: 'Type', + type: 'string' + } + }, + required: [ + 'type', + 'number_of_events_to_generate' + ], + title: 'InternalEventSourceParameters', + type: 'object' +} as const; + +export const LogReadModeSchema = { + enum: [ + 'head', + 'tail' + ], + title: 'LogReadMode', + type: 'string' +} as const; + +export const LogStreamSchema = { + enum: [ + 'cache', + 'producer_stdout', + 'producer_stderr' + ], + title: 'LogStream', + type: 'string' +} as const; + +export const MessageSchema = { + properties: { + message: { + title: 'Message', + type: 'string' + } + }, + required: [ + 'message' + ], + title: 'Message', + type: 'object' +} as const; + +export const ParametersSchema = { + additionalProperties: false, + description: 'Top-level configuration parameters for an lclstreamer run\n\nThis model aggregates all sub-component configuration into a single object\n\nAttributes:\n\n source_identifier: A string that uniquely identifies the data source\n (e.g. a psana data source string)\n\n skip_incomplete_events: When ``True``, events for which one or more\n data sources returned no data are silently dropped from the stream\n\n event_source: Configuration for the event source\n\n data_sources: Mapping from arbitrary data source names to the\n configuration parameters of each data source\n\n processing_pipeline: Configuration for the Processing Pipeline applied\n to the event stream\n\n data_serializer: Configuration for the serializer that converts\n processed events into byte objects\n\n data_handlers: Ordered list of data handler configurations; each\n handler receives the serialized byte object in turn', + properties: { + data_handlers: { + items: { + discriminator: { + mapping: { + BinaryDataStreamingDataHandler: '#/components/schemas/BinaryDataStreamingDataHandlerParameters', + BinaryFileWritingDataHandler: '#/components/schemas/BinaryFileWritingDataHandlerParameters' + }, + propertyName: 'type' + }, + oneOf: [ + { + $ref: '#/components/schemas/BinaryDataStreamingDataHandlerParameters' + }, + { + $ref: '#/components/schemas/BinaryFileWritingDataHandlerParameters' + } + ] + }, + title: 'Data Handlers', + type: 'array' + }, + data_serializer: { + discriminator: { + mapping: { + HDF5BinarySerializer: '#/components/schemas/HDF5BinarySerializerParameters', + SimplonBinarySerializer: '#/components/schemas/SimplonBinarySerializerParameters' + }, + propertyName: 'type' + }, + oneOf: [ + { + $ref: '#/components/schemas/HDF5BinarySerializerParameters' + }, + { + $ref: '#/components/schemas/SimplonBinarySerializerParameters' + } + ], + title: 'Data Serializer' + }, + data_sources: { + additionalProperties: { + discriminator: { + mapping: { + ConstValue: '#/components/schemas/ConstValueParameters', + GenericRandomNumpyArray: '#/components/schemas/GenericRandomNumpyArrayParameters', + Psana1DetectorInterface: '#/components/schemas/Psana1DetectorInterfaceParameters', + Psana1Timestamp: '#/components/schemas/Psana1TimestampParameters', + Psana2DetectorInterface: '#/components/schemas/Psana2DetectorInterfaceParameters', + Psana2RunInfo: '#/components/schemas/Psana2RunInfoParameters', + Psana2Timestamp: '#/components/schemas/Psana2TimestampParameters', + SourceIdentifier: '#/components/schemas/SourceIdentifierParameters' + }, + propertyName: 'type' + }, + oneOf: [ + { + $ref: '#/components/schemas/GenericRandomNumpyArrayParameters' + }, + { + $ref: '#/components/schemas/ConstValueParameters' + }, + { + $ref: '#/components/schemas/Psana1DetectorInterfaceParameters' + }, + { + $ref: '#/components/schemas/Psana2DetectorInterfaceParameters' + }, + { + $ref: '#/components/schemas/Psana1TimestampParameters' + }, + { + $ref: '#/components/schemas/Psana2TimestampParameters' + }, + { + $ref: '#/components/schemas/SourceIdentifierParameters' + }, + { + $ref: '#/components/schemas/Psana2RunInfoParameters' + } + ] + }, + title: 'Data Sources', + type: 'object' + }, + event_source: { + discriminator: { + mapping: { + InternalEventSource: '#/components/schemas/InternalEventSourceParameters', + Psana1EventSource: '#/components/schemas/Psana1EventSourceParameters', + Psana2EventSource: '#/components/schemas/Psana2EventSourceParameters' + }, + propertyName: 'type' + }, + oneOf: [ + { + $ref: '#/components/schemas/InternalEventSourceParameters' + }, + { + $ref: '#/components/schemas/Psana1EventSourceParameters' + }, + { + $ref: '#/components/schemas/Psana2EventSourceParameters' + } + ], + title: 'Event Source' + }, + processing_pipeline: { + discriminator: { + mapping: { + BatchProcessingPipeline: '#/components/schemas/BatchProcessingPipelineParameters', + PeaknetPreprocessingPipeline: '#/components/schemas/PeaknetPreprocessingPipelineParameters' + }, + propertyName: 'type' + }, + oneOf: [ + { + $ref: '#/components/schemas/BatchProcessingPipelineParameters' + }, + { + $ref: '#/components/schemas/PeaknetPreprocessingPipelineParameters' + } + ], + title: 'Processing Pipeline' + }, + skip_incomplete_events: { + title: 'Skip Incomplete Events', + type: 'boolean' + }, + source_identifier: { + title: 'Source Identifier', + type: 'string' + } + }, + required: [ + 'source_identifier', + 'skip_incomplete_events', + 'event_source', + 'data_sources', + 'processing_pipeline', + 'data_serializer', + 'data_handlers' + ], + title: 'Parameters', + type: 'object' +} as const; + +export const PeaknetPreprocessingPipelineParametersSchema = { + additionalProperties: false, + description: 'Configuration parameters for the PeakNet Preprocessing Pipeline\n\nThis pipeline pads detector images to a uniform size, accumulates them\ninto batches, and optionally adds a channel dimension, preparing the data\nfor inference with the PeakNet model\n\nAttributes:\n\n type: Discriminator field, must be ``"PeaknetPreprocessingPipeline"``\n\n batch_size: Number of events to accumulate per batch\n\n target_height: Target image height (in pixels) after padding\n\n target_width: Target image width (in pixels) after padding\n\n pad_style: How to distribute padding around the image; either\n ``"center"`` (equal padding on both sides) or ``"bottom-right"``\n (padding added only to the bottom and right edges)\n Defaults to ``"center"``\n\n add_channel_dim: Whether to insert a channel dimension after batching,\n converting (B, H, W) arrays to (B, C, H, W). Defaults to ``True``\n\n num_channels: Number of channels to produce when ``add_channel_dim``\n is ``True``. Defaults to ``1``', + properties: { + add_channel_dim: { + default: true, + title: 'Add Channel Dim', + type: 'boolean' + }, + batch_size: { + title: 'Batch Size', + type: 'integer' + }, + num_channels: { + default: 1, + title: 'Num Channels', + type: 'integer' + }, + pad_style: { + default: 'center', + enum: [ + 'center', + 'bottom-right' + ], + title: 'Pad Style', + type: 'string' + }, + target_height: { + title: 'Target Height', + type: 'integer' + }, + target_width: { + title: 'Target Width', + type: 'integer' + }, + type: { + const: 'PeaknetPreprocessingPipeline', + title: 'Type', + type: 'string' + } + }, + required: [ + 'type', + 'batch_size', + 'target_height', + 'target_width' + ], + title: 'PeaknetPreprocessingPipelineParameters', + type: 'object' +} as const; + +export const Psana1DetectorInterfaceParametersSchema = { + additionalProperties: false, + properties: { + psana_fields: { + anyOf: [ + { + items: { + type: 'string' + }, + type: 'array' + }, + { + type: 'string' + }, + { + type: 'null' + } + ], + title: 'Psana Fields' + }, + psana_name: { + title: 'Psana Name', + type: 'string' + }, + type: { + const: 'Psana1DetectorInterface', + title: 'Type', + type: 'string' + } + }, + required: [ + 'psana_name', + 'type' + ], + title: 'Psana1DetectorInterfaceParameters', + type: 'object' +} as const; + +export const Psana1EventSourceParametersSchema = { + additionalProperties: false, + description: 'Configuration parameters for the Psana1 Event Source\n\nThis event source reads events using the psana1 framework (LCLS-I)\n\nAttributes:\n\n type: Discriminator field, must be ``"Psana1EventSource"``', + properties: { + type: { + const: 'Psana1EventSource', + title: 'Type', + type: 'string' + } + }, + required: [ + 'type' + ], + title: 'Psana1EventSourceParameters', + type: 'object' +} as const; + +export const Psana1TimestampParametersSchema = { + additionalProperties: false, + description: 'Parameters for psana1 timestamp interface', + properties: { + type: { + const: 'Psana1Timestamp', + title: 'Type', + type: 'string' + } + }, + required: [ + 'type' + ], + title: 'Psana1TimestampParameters', + type: 'object' +} as const; + +export const Psana2DetectorInterfaceParametersSchema = { + additionalProperties: false, + properties: { + dtype: { + anyOf: [ + { + type: 'string' + }, + { + type: 'null' + } + ], + title: 'Dtype' + }, + psana_fields: { + anyOf: [ + { + items: { + type: 'string' + }, + type: 'array' + }, + { + type: 'string' + }, + { + type: 'null' + } + ], + title: 'Psana Fields' + }, + psana_name: { + title: 'Psana Name', + type: 'string' + }, + type: { + const: 'Psana2DetectorInterface', + title: 'Type', + type: 'string' + } + }, + required: [ + 'psana_name', + 'type' + ], + title: 'Psana2DetectorInterfaceParameters', + type: 'object' +} as const; + +export const Psana2EventSourceParametersSchema = { + additionalProperties: false, + description: 'Configuration parameters for the Psana2 Event Source\n\nThis event source reads events using the psana2 framework (LCLS-II)\n\nAttributes:\n\n type: Discriminator field, must be ``"Psana2EventSource"``', + properties: { + type: { + const: 'Psana2EventSource', + title: 'Type', + type: 'string' + } + }, + required: [ + 'type' + ], + title: 'Psana2EventSourceParameters', + type: 'object' +} as const; + +export const Psana2RunInfoParametersSchema = { + additionalProperties: false, + description: 'Parameters for run info data source interface', + properties: { + type: { + const: 'Psana2RunInfo', + title: 'Type', + type: 'string' + } + }, + required: [ + 'type' + ], + title: 'Psana2RunInfoParameters', + type: 'object' +} as const; + +export const Psana2TimestampParametersSchema = { + additionalProperties: false, + description: 'Parameters for psana2 timestamp interface', + properties: { + type: { + const: 'Psana2Timestamp', + title: 'Type', + type: 'string' + } + }, + required: [ + 'type' + ], + title: 'Psana2TimestampParameters', + type: 'object' +} as const; + +export const SimplonBinarySerializerParametersSchema = { + additionalProperties: false, + description: 'Configuration parameters for the Simplon binary serializer\n\nThis serializer encodes event data into the Simplon 1.8 binary message\nformat as specified by Dectris\n\nAttributes:\n\n type: Discriminator field, must be ``"SimplonBinarySerializer"``\n\n data_source_to_serialize: Name of the data source whose array will be\n compressed and embedded in each Simplon image message\n\n polarization_fraction: Fraction of linear polarization of the X-ray\n beam (between 0 and 1)\n\n polarization_axis: Three-element list representing the polarization\n axis direction vector\n\n data_collection_rate: Human-readable string describing the nominal\n data collection rate (e.g. ``"120 Hz"``)\n\n detector_name: Human-readable name of the detector\n\n detector_type: Model or type string identifying the detector hardware', + properties: { + data_collection_rate: { + title: 'Data Collection Rate', + type: 'string' + }, + data_source_to_serialize: { + title: 'Data Source To Serialize', + type: 'string' + }, + detector_name: { + title: 'Detector Name', + type: 'string' + }, + detector_type: { + title: 'Detector Type', + type: 'string' + }, + polarization_axis: { + items: { + type: 'number' + }, + title: 'Polarization Axis', + type: 'array' + }, + polarization_fraction: { + title: 'Polarization Fraction', + type: 'number' + }, + type: { + const: 'SimplonBinarySerializer', + title: 'Type', + type: 'string' + } + }, + required: [ + 'type', + 'data_source_to_serialize', + 'polarization_fraction', + 'polarization_axis', + 'data_collection_rate', + 'detector_name', + 'detector_type' + ], + title: 'SimplonBinarySerializerParameters', + type: 'object' +} as const; + +export const SourceIdentifierParametersSchema = { + additionalProperties: false, + description: 'Parameters for source identifier data source interface', + properties: { + type: { + const: 'SourceIdentifier', + title: 'Type', + type: 'string' + } + }, + required: [ + 'type' + ], + title: 'SourceIdentifierParameters', + type: 'object' +} as const; + +export const TransferCreateSchema = { + properties: { + parameters: { + $ref: '#/components/schemas/Parameters' + } + }, + required: [ + 'parameters' + ], + title: 'TransferCreate', + type: 'object' +} as const; + +export const TransferDetailSchema = { + properties: { + connection_info: { + anyOf: [ + { + $ref: '#/components/schemas/ConsumerConnectionInfo' + }, + { + type: 'null' + } + ] + }, + created_at: { + format: 'date-time', + title: 'Created At', + type: 'string' + }, + id: { + format: 'uuid', + title: 'Id', + type: 'string' + }, + requested_by: { + title: 'Requested By', + type: 'string' + }, + state: { + $ref: '#/components/schemas/TransferState' + }, + transitions: { + default: [], + items: { + $ref: '#/components/schemas/TransitionPublic' + }, + title: 'Transitions', + type: 'array' + } + }, + required: [ + 'id', + 'created_at', + 'requested_by', + 'state' + ], + title: 'TransferDetail', + type: 'object' +} as const; + +export const TransferLogIndexSchema = { + properties: { + streams: { + items: { + $ref: '#/components/schemas/TransferLogStreamInfo' + }, + title: 'Streams', + type: 'array' + }, + transfer_id: { + format: 'uuid', + title: 'Transfer Id', + type: 'string' + } + }, + required: [ + 'transfer_id', + 'streams' + ], + title: 'TransferLogIndex', + type: 'object' +} as const; + +export const TransferLogStreamInfoSchema = { + description: 'One log stream\'s resolved location and (best-effort) availability.', + properties: { + available: { + title: 'Available', + type: 'boolean' + }, + modified_at: { + anyOf: [ + { + format: 'date-time', + type: 'string' + }, + { + type: 'null' + } + ], + title: 'Modified At' + }, + path: { + format: 'path', + title: 'Path', + type: 'string' + }, + size: { + anyOf: [ + { + type: 'integer' + }, + { + type: 'null' + } + ], + title: 'Size' + }, + stream: { + $ref: '#/components/schemas/LogStream' + } + }, + required: [ + 'stream', + 'path', + 'available' + ], + title: 'TransferLogStreamInfo', + type: 'object' +} as const; + +export const TransferPublicSchema = { + properties: { + connection_info: { + anyOf: [ + { + $ref: '#/components/schemas/ConsumerConnectionInfo' + }, + { + type: 'null' + } + ] + }, + created_at: { + format: 'date-time', + title: 'Created At', + type: 'string' + }, + id: { + format: 'uuid', + title: 'Id', + type: 'string' + }, + requested_by: { + title: 'Requested By', + type: 'string' + }, + state: { + $ref: '#/components/schemas/TransferState' + } + }, + required: [ + 'id', + 'created_at', + 'requested_by', + 'state' + ], + title: 'TransferPublic', + type: 'object' +} as const; + +export const TransferStateSchema = { + enum: [ + 'provisioning', + 'ready', + 'canceling', + 'canceled', + 'completed', + 'failed' + ], + title: 'TransferState', + type: 'string' +} as const; + +export const TransfersPublicSchema = { + properties: { + count: { + title: 'Count', + type: 'integer' + }, + data: { + items: { + $ref: '#/components/schemas/TransferPublic' + }, + title: 'Data', + type: 'array' + } + }, + required: [ + 'data', + 'count' + ], + title: 'TransfersPublic', + type: 'object' +} as const; + +export const TransitionPublicSchema = { + properties: { + created_at: { + format: 'date-time', + title: 'Created At', + type: 'string' + }, + info: { + anyOf: [ + { + type: 'string' + }, + { + type: 'null' + } + ], + title: 'Info' + }, + source: { + anyOf: [ + { + $ref: '#/components/schemas/TransitionSource' + }, + { + type: 'null' + } + ] + }, + state: { + $ref: '#/components/schemas/TransferState' + } + }, + required: [ + 'created_at', + 'state' + ], + title: 'TransitionPublic', + type: 'object' +} as const; + +export const TransitionSourceSchema = { + enum: [ + 'producer', + 'cache', + 'user', + 'orchestrator' + ], + title: 'TransitionSource', + type: 'string' +} as const; + +export const ValidationErrorSchema = { + properties: { + ctx: { + title: 'Context', + type: 'object' + }, + input: { + title: 'Input' + }, + loc: { + items: { + anyOf: [ + { + type: 'string' + }, + { + type: 'integer' + } + ] + }, + title: 'Location', + type: 'array' + }, + msg: { + title: 'Message', + type: 'string' + }, + type: { + title: 'Error Type', + type: 'string' + } + }, + required: [ + 'loc', + 'msg', + 'type' + ], + title: 'ValidationError', + type: 'object' +} as const; diff --git a/frontend/src/client/sdk.gen.ts b/frontend/src/client/sdk.gen.ts new file mode 100644 index 0000000..2c23ce4 --- /dev/null +++ b/frontend/src/client/sdk.gen.ts @@ -0,0 +1,104 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { Client, Options as Options2, TDataShape } from './client'; +import { client } from './client.gen'; +import type { CancelTransferTransfersTransferIdDeleteData, CancelTransferTransfersTransferIdDeleteErrors, CancelTransferTransfersTransferIdDeleteResponses, GetTransferLogsTransfersTransferIdLogsGetData, GetTransferLogsTransfersTransferIdLogsGetErrors, GetTransferLogsTransfersTransferIdLogsGetResponses, GetTransferLogTransfersTransferIdLogsStreamGetData, GetTransferLogTransfersTransferIdLogsStreamGetErrors, GetTransferLogTransfersTransferIdLogsStreamGetResponses, GetTransfersTransfersGetData, GetTransfersTransfersGetErrors, GetTransfersTransfersGetResponses, GetTransferTransfersTransferIdGetData, GetTransferTransfersTransferIdGetErrors, GetTransferTransfersTransferIdGetResponses, NewTransferTransfersPostData, NewTransferTransfersPostErrors, NewTransferTransfersPostResponses } from './types.gen'; +import { zCancelTransferTransfersTransferIdDeleteResponse, zGetTransferLogsTransfersTransferIdLogsGetResponse, zGetTransferLogTransfersTransferIdLogsStreamGetResponse, zGetTransfersTransfersGetResponse, zGetTransferTransfersTransferIdGetResponse, zNewTransferTransfersPostResponse } from './zod.gen'; + +export type Options = Options2 & { + /** + * You can provide a client instance returned by `createClient()` instead of + * individual options. This might be also useful if you want to implement a + * custom client. + */ + client?: Client; + /** + * You can pass arbitrary values through the `meta` object. This can be + * used to access values that aren't defined as part of the SDK function. + */ + meta?: Record; +}; + +export class TransfersService { + /** + * Get Transfers + */ + public static getTransfersTransfersGet(options?: Options) { + return (options?.client ?? client).get({ + responseType: 'json', + responseValidator: async (data) => await zGetTransfersTransfersGetResponse.parseAsync(data), + security: [{ scheme: 'bearer', type: 'http' }], + url: '/transfers/', + ...options + }); + } + + /** + * New Transfer + */ + public static newTransferTransfersPost(options: Options) { + return (options.client ?? client).post({ + responseType: 'json', + responseValidator: async (data) => await zNewTransferTransfersPostResponse.parseAsync(data), + security: [{ scheme: 'bearer', type: 'http' }], + url: '/transfers/', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } + }); + } + + /** + * Cancel Transfer + */ + public static cancelTransferTransfersTransferIdDelete(options: Options) { + return (options.client ?? client).delete({ + responseType: 'json', + responseValidator: async (data) => await zCancelTransferTransfersTransferIdDeleteResponse.parseAsync(data), + security: [{ scheme: 'bearer', type: 'http' }], + url: '/transfers/{transfer_id}', + ...options + }); + } + + /** + * Get Transfer + */ + public static getTransferTransfersTransferIdGet(options: Options) { + return (options.client ?? client).get({ + responseType: 'json', + responseValidator: async (data) => await zGetTransferTransfersTransferIdGetResponse.parseAsync(data), + security: [{ scheme: 'bearer', type: 'http' }], + url: '/transfers/{transfer_id}', + ...options + }); + } + + /** + * Get Transfer Logs + */ + public static getTransferLogsTransfersTransferIdLogsGet(options: Options) { + return (options.client ?? client).get({ + responseType: 'json', + responseValidator: async (data) => await zGetTransferLogsTransfersTransferIdLogsGetResponse.parseAsync(data), + security: [{ scheme: 'bearer', type: 'http' }], + url: '/transfers/{transfer_id}/logs', + ...options + }); + } + + /** + * Get Transfer Log + */ + public static getTransferLogTransfersTransferIdLogsStreamGet(options: Options) { + return (options.client ?? client).get({ + responseType: 'text', + responseValidator: async (data) => await zGetTransferLogTransfersTransferIdLogsStreamGetResponse.parseAsync(data), + security: [{ scheme: 'bearer', type: 'http' }], + url: '/transfers/{transfer_id}/logs/{stream}', + ...options + }); + } +} diff --git a/frontend/src/client/types.gen.ts b/frontend/src/client/types.gen.ts new file mode 100644 index 0000000..d4a4050 --- /dev/null +++ b/frontend/src/client/types.gen.ts @@ -0,0 +1,989 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseURL: `${string}://${string}` | (string & {}); +}; + +/** + * BatchProcessingPipelineParameters + * + * Configuration parameters for the Batch Processing Pipeline + * + * This pipeline accumulates individual events into fixed-size batches before + * passing them downstream + * + * Attributes: + * + * type: Discriminator field, must be ``"BatchProcessingPipeline"`` + * + * batch_size: Number of events to accumulate per batch + */ +export type BatchProcessingPipelineParameters = { + /** + * Batch Size + */ + batch_size: number; + /** + * Type + */ + type: 'BatchProcessingPipeline'; +}; + +/** + * BinaryDataStreamingDataHandlerParameters + * + * Configuration parameters for the Binary Data Streaming Data Handler + * + * This data handler forwards serialized byte objects to one or more remote + * endpoints over a ZMQ PUSH socket + * + * Attributes: + * + * type: Discriminator field, must be ``"BinaryDataStreamingDataHandler"`` + * + * urls: List of endpoint URLs to bind to (server mode) or connect to + * (client mode) + * + * distribute: Boolean, if True: round robin connect the ranks, False: all ranks connect to all urls and send the same data + * + * buffer: buffer size, if set to 0 the OS default is used + * + * role: Whether this node acts as the ZMQ ``"server"`` (binds) or + * ``"client"`` (connects). Defaults to ``"server"`` + * + * library: Underlying transport library to use. Currently only ``"zmq"`` + * is supported. Defaults to ``"zmq"`` + * + * socket_type: Socket pattern to use. Currently only ``"push"`` is + * supported. Defaults to ``"push"`` + */ +export type BinaryDataStreamingDataHandlerParameters = { + /** + * Buffer + */ + buffer?: number; + /** + * Distribute + */ + distribute?: boolean; + /** + * Library + */ + library?: 'zmq'; + /** + * Role + */ + role?: 'server' | 'client'; + /** + * Socket Type + */ + socket_type?: 'push'; + /** + * Type + */ + type: 'BinaryDataStreamingDataHandler'; + /** + * Urls + */ + urls: Array; +}; + +/** + * BinaryFileWritingDataHandlerParameters + * + * Configuration parameters for the Binary File Writing Data Handler + * + * This data handler writes each serialized byte object to a separate file on + * the filesystem + * + * Attributes: + * + * type: Discriminator field, must be ``"BinaryFileWritingDataHandler"`` + * + * file_prefix: Optional string prepended to every output filename, + * separated from the rest of the name by an underscore. Defaults to + * ``""`` (no prefix) + * + * file_suffix: File extension used for output files, without the leading + * dot. Defaults to ``"h5"`` + * + * write_directory: Directory in which output files are created. The + * directory is created (including parents) if it does not already + * exist. Defaults to the current working directory + */ +export type BinaryFileWritingDataHandlerParameters = { + /** + * File Prefix + */ + file_prefix?: string; + /** + * File Suffix + */ + file_suffix?: string; + /** + * Type + */ + type: 'BinaryFileWritingDataHandler'; + /** + * Write Directory + */ + write_directory?: string; +}; + +/** + * ConstValueParameters + * + * Parameters for ConstValue class + */ +export type ConstValueParameters = { + /** + * Dtype + */ + dtype: string; + /** + * Type + */ + type: 'ConstValue'; + /** + * Value + */ + value: number | number | Array; +}; + +/** + * ConsumerConnectionInfo + * + * The cache push socket the consumer connects to. + */ +export type ConsumerConnectionInfo = { + /** + * Host + */ + host: string; + /** + * Port + */ + port: number; + /** + * Uri + */ + uri: string; +}; + +/** + * GenericRandomNumpyArrayParameters + * + * Parameters for the GenericRandomNumpyArray class + */ +export type GenericRandomNumpyArrayParameters = { + /** + * Always Random + */ + always_random?: boolean; + /** + * Array Dtype + */ + array_dtype: string; + /** + * Array Shape + */ + array_shape: number | Array; + /** + * Type + */ + type: 'GenericRandomNumpyArray'; +}; + +/** + * HDF5BinarySerializerParameters + * + * Configuration parameters for the HDF5 binary serializer + * + * This serializer encodes a batch of event data arrays into an in-memory + * HDF5 file. Optional compression can be applied to each dataset + * + * Attributes: + * + * type: Discriminator field, must be ``"HDF5BinarySerializer"`` + * + * compression_level: Compression level passed to the chosen algorithm. + * Interpretation depends on the algorithm. Defaults to ``3`` + * + * compression: Compression algorithm to use. Supported values are + * ``"gzip"``, ``"gzip_with_shuffle"``, ``"bitshuffle_with_lz4"``, + * ``"bitshuffle_with_zstd"``, and ``"zfp"``. Set to ``None`` to + * disable compression. Defaults to ``None`` + * + * fields: Dictionary storing the mapping from data source name to the + * HDF5 dataset path under which that source's data will be stored + */ +export type Hdf5BinarySerializerParameters = { + /** + * Compression + */ + compression?: 'gzip' | 'gzip_with_shuffle' | 'bitshuffle_with_lz4' | 'bitshuffle_with_zstd' | 'zfp' | null; + /** + * Compression Level + */ + compression_level?: number; + /** + * Fields + */ + fields: { + [key: string]: string; + }; + /** + * Type + */ + type: 'HDF5BinarySerializer'; +}; + +/** + * HTTPValidationError + */ +export type HttpValidationError = { + /** + * Detail + */ + detail?: Array; +}; + +/** + * InternalEventSourceParameters + * + * Configuration parameters for the Internal Event Source + * + * This event source generates synthetic events entirely in-process and does + * not depend on any external data-acquisition framework. It is intended + * mainly for testing and development + * + * Attributes: + * + * type: Discriminator field, must be ``"InternalEventSource"`` + * + * number_of_events_to_generate: Total number of synthetic events to + * produce before the source is exhausted + */ +export type InternalEventSourceParameters = { + /** + * Number Of Events To Generate + */ + number_of_events_to_generate: number; + /** + * Type + */ + type: 'InternalEventSource'; + [key: string]: unknown; +}; + +/** + * LogReadMode + */ +export type LogReadMode = 'head' | 'tail'; + +/** + * LogStream + */ +export type LogStream = 'cache' | 'producer_stdout' | 'producer_stderr'; + +/** + * Message + */ +export type Message = { + /** + * Message + */ + message: string; +}; + +/** + * Parameters + * + * Top-level configuration parameters for an lclstreamer run + * + * This model aggregates all sub-component configuration into a single object + * + * Attributes: + * + * source_identifier: A string that uniquely identifies the data source + * (e.g. a psana data source string) + * + * skip_incomplete_events: When ``True``, events for which one or more + * data sources returned no data are silently dropped from the stream + * + * event_source: Configuration for the event source + * + * data_sources: Mapping from arbitrary data source names to the + * configuration parameters of each data source + * + * processing_pipeline: Configuration for the Processing Pipeline applied + * to the event stream + * + * data_serializer: Configuration for the serializer that converts + * processed events into byte objects + * + * data_handlers: Ordered list of data handler configurations; each + * handler receives the serialized byte object in turn + */ +export type Parameters = { + /** + * Data Handlers + */ + data_handlers: Array<({ + type: 'BinaryDataStreamingDataHandler'; + } & BinaryDataStreamingDataHandlerParameters) | ({ + type: 'BinaryFileWritingDataHandler'; + } & BinaryFileWritingDataHandlerParameters)>; + /** + * Data Serializer + */ + data_serializer: ({ + type: 'HDF5BinarySerializer'; + } & Hdf5BinarySerializerParameters) | ({ + type: 'SimplonBinarySerializer'; + } & SimplonBinarySerializerParameters); + /** + * Data Sources + */ + data_sources: { + [key: string]: ({ + type: 'GenericRandomNumpyArray'; + } & GenericRandomNumpyArrayParameters) | ({ + type: 'ConstValue'; + } & ConstValueParameters) | ({ + type: 'Psana1DetectorInterface'; + } & Psana1DetectorInterfaceParameters) | ({ + type: 'Psana2DetectorInterface'; + } & Psana2DetectorInterfaceParameters) | ({ + type: 'Psana1Timestamp'; + } & Psana1TimestampParameters) | ({ + type: 'Psana2Timestamp'; + } & Psana2TimestampParameters) | ({ + type: 'SourceIdentifier'; + } & SourceIdentifierParameters) | ({ + type: 'Psana2RunInfo'; + } & Psana2RunInfoParameters); + }; + /** + * Event Source + */ + event_source: ({ + type: 'InternalEventSource'; + } & InternalEventSourceParameters) | ({ + type: 'Psana1EventSource'; + } & Psana1EventSourceParameters) | ({ + type: 'Psana2EventSource'; + } & Psana2EventSourceParameters); + /** + * Processing Pipeline + */ + processing_pipeline: ({ + type: 'BatchProcessingPipeline'; + } & BatchProcessingPipelineParameters) | ({ + type: 'PeaknetPreprocessingPipeline'; + } & PeaknetPreprocessingPipelineParameters); + /** + * Skip Incomplete Events + */ + skip_incomplete_events: boolean; + /** + * Source Identifier + */ + source_identifier: string; +}; + +/** + * PeaknetPreprocessingPipelineParameters + * + * Configuration parameters for the PeakNet Preprocessing Pipeline + * + * This pipeline pads detector images to a uniform size, accumulates them + * into batches, and optionally adds a channel dimension, preparing the data + * for inference with the PeakNet model + * + * Attributes: + * + * type: Discriminator field, must be ``"PeaknetPreprocessingPipeline"`` + * + * batch_size: Number of events to accumulate per batch + * + * target_height: Target image height (in pixels) after padding + * + * target_width: Target image width (in pixels) after padding + * + * pad_style: How to distribute padding around the image; either + * ``"center"`` (equal padding on both sides) or ``"bottom-right"`` + * (padding added only to the bottom and right edges) + * Defaults to ``"center"`` + * + * add_channel_dim: Whether to insert a channel dimension after batching, + * converting (B, H, W) arrays to (B, C, H, W). Defaults to ``True`` + * + * num_channels: Number of channels to produce when ``add_channel_dim`` + * is ``True``. Defaults to ``1`` + */ +export type PeaknetPreprocessingPipelineParameters = { + /** + * Add Channel Dim + */ + add_channel_dim?: boolean; + /** + * Batch Size + */ + batch_size: number; + /** + * Num Channels + */ + num_channels?: number; + /** + * Pad Style + */ + pad_style?: 'center' | 'bottom-right'; + /** + * Target Height + */ + target_height: number; + /** + * Target Width + */ + target_width: number; + /** + * Type + */ + type: 'PeaknetPreprocessingPipeline'; +}; + +/** + * Psana1DetectorInterfaceParameters + */ +export type Psana1DetectorInterfaceParameters = { + /** + * Psana Fields + */ + psana_fields?: Array | string | null; + /** + * Psana Name + */ + psana_name: string; + /** + * Type + */ + type: 'Psana1DetectorInterface'; +}; + +/** + * Psana1EventSourceParameters + * + * Configuration parameters for the Psana1 Event Source + * + * This event source reads events using the psana1 framework (LCLS-I) + * + * Attributes: + * + * type: Discriminator field, must be ``"Psana1EventSource"`` + */ +export type Psana1EventSourceParameters = { + /** + * Type + */ + type: 'Psana1EventSource'; +}; + +/** + * Psana1TimestampParameters + * + * Parameters for psana1 timestamp interface + */ +export type Psana1TimestampParameters = { + /** + * Type + */ + type: 'Psana1Timestamp'; +}; + +/** + * Psana2DetectorInterfaceParameters + */ +export type Psana2DetectorInterfaceParameters = { + /** + * Dtype + */ + dtype?: string | null; + /** + * Psana Fields + */ + psana_fields?: Array | string | null; + /** + * Psana Name + */ + psana_name: string; + /** + * Type + */ + type: 'Psana2DetectorInterface'; +}; + +/** + * Psana2EventSourceParameters + * + * Configuration parameters for the Psana2 Event Source + * + * This event source reads events using the psana2 framework (LCLS-II) + * + * Attributes: + * + * type: Discriminator field, must be ``"Psana2EventSource"`` + */ +export type Psana2EventSourceParameters = { + /** + * Type + */ + type: 'Psana2EventSource'; +}; + +/** + * Psana2RunInfoParameters + * + * Parameters for run info data source interface + */ +export type Psana2RunInfoParameters = { + /** + * Type + */ + type: 'Psana2RunInfo'; +}; + +/** + * Psana2TimestampParameters + * + * Parameters for psana2 timestamp interface + */ +export type Psana2TimestampParameters = { + /** + * Type + */ + type: 'Psana2Timestamp'; +}; + +/** + * SimplonBinarySerializerParameters + * + * Configuration parameters for the Simplon binary serializer + * + * This serializer encodes event data into the Simplon 1.8 binary message + * format as specified by Dectris + * + * Attributes: + * + * type: Discriminator field, must be ``"SimplonBinarySerializer"`` + * + * data_source_to_serialize: Name of the data source whose array will be + * compressed and embedded in each Simplon image message + * + * polarization_fraction: Fraction of linear polarization of the X-ray + * beam (between 0 and 1) + * + * polarization_axis: Three-element list representing the polarization + * axis direction vector + * + * data_collection_rate: Human-readable string describing the nominal + * data collection rate (e.g. ``"120 Hz"``) + * + * detector_name: Human-readable name of the detector + * + * detector_type: Model or type string identifying the detector hardware + */ +export type SimplonBinarySerializerParameters = { + /** + * Data Collection Rate + */ + data_collection_rate: string; + /** + * Data Source To Serialize + */ + data_source_to_serialize: string; + /** + * Detector Name + */ + detector_name: string; + /** + * Detector Type + */ + detector_type: string; + /** + * Polarization Axis + */ + polarization_axis: Array; + /** + * Polarization Fraction + */ + polarization_fraction: number; + /** + * Type + */ + type: 'SimplonBinarySerializer'; +}; + +/** + * SourceIdentifierParameters + * + * Parameters for source identifier data source interface + */ +export type SourceIdentifierParameters = { + /** + * Type + */ + type: 'SourceIdentifier'; +}; + +/** + * TransferCreate + */ +export type TransferCreate = { + parameters: Parameters; +}; + +/** + * TransferDetail + */ +export type TransferDetail = { + connection_info?: ConsumerConnectionInfo | null; + /** + * Created At + */ + created_at: string; + /** + * Id + */ + id: string; + /** + * Requested By + */ + requested_by: string; + state: TransferState; + /** + * Transitions + */ + transitions?: Array; +}; + +/** + * TransferLogIndex + */ +export type TransferLogIndex = { + /** + * Streams + */ + streams: Array; + /** + * Transfer Id + */ + transfer_id: string; +}; + +/** + * TransferLogStreamInfo + * + * One log stream's resolved location and (best-effort) availability. + */ +export type TransferLogStreamInfo = { + /** + * Available + */ + available: boolean; + /** + * Modified At + */ + modified_at?: string | null; + /** + * Path + */ + path: string; + /** + * Size + */ + size?: number | null; + stream: LogStream; +}; + +/** + * TransferPublic + */ +export type TransferPublic = { + connection_info?: ConsumerConnectionInfo | null; + /** + * Created At + */ + created_at: string; + /** + * Id + */ + id: string; + /** + * Requested By + */ + requested_by: string; + state: TransferState; +}; + +/** + * TransferState + */ +export type TransferState = 'provisioning' | 'ready' | 'canceling' | 'canceled' | 'completed' | 'failed'; + +/** + * TransfersPublic + */ +export type TransfersPublic = { + /** + * Count + */ + count: number; + /** + * Data + */ + data: Array; +}; + +/** + * TransitionPublic + */ +export type TransitionPublic = { + /** + * Created At + */ + created_at: string; + /** + * Info + */ + info?: string | null; + source?: TransitionSource | null; + state: TransferState; +}; + +/** + * TransitionSource + */ +export type TransitionSource = 'producer' | 'cache' | 'user' | 'orchestrator'; + +/** + * ValidationError + */ +export type ValidationError = { + /** + * Context + */ + ctx?: { + [key: string]: unknown; + }; + /** + * Input + */ + input?: unknown; + /** + * Location + */ + loc: Array; + /** + * Message + */ + msg: string; + /** + * Error Type + */ + type: string; +}; + +export type GetTransfersTransfersGetData = { + body?: never; + path?: never; + query?: { + /** + * Skip + */ + skip?: number; + /** + * Limit + */ + limit?: number; + /** + * State + */ + state?: TransferState | null; + }; + url: '/transfers/'; +}; + +export type GetTransfersTransfersGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetTransfersTransfersGetError = GetTransfersTransfersGetErrors[keyof GetTransfersTransfersGetErrors]; + +export type GetTransfersTransfersGetResponses = { + /** + * Successful Response + */ + 200: TransfersPublic; +}; + +export type GetTransfersTransfersGetResponse = GetTransfersTransfersGetResponses[keyof GetTransfersTransfersGetResponses]; + +export type NewTransferTransfersPostData = { + body: TransferCreate; + path?: never; + query?: never; + url: '/transfers/'; +}; + +export type NewTransferTransfersPostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type NewTransferTransfersPostError = NewTransferTransfersPostErrors[keyof NewTransferTransfersPostErrors]; + +export type NewTransferTransfersPostResponses = { + /** + * Successful Response + */ + 201: TransferPublic; +}; + +export type NewTransferTransfersPostResponse = NewTransferTransfersPostResponses[keyof NewTransferTransfersPostResponses]; + +export type CancelTransferTransfersTransferIdDeleteData = { + body?: never; + path: { + /** + * Transfer Id + */ + transfer_id: string; + }; + query?: never; + url: '/transfers/{transfer_id}'; +}; + +export type CancelTransferTransfersTransferIdDeleteErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type CancelTransferTransfersTransferIdDeleteError = CancelTransferTransfersTransferIdDeleteErrors[keyof CancelTransferTransfersTransferIdDeleteErrors]; + +export type CancelTransferTransfersTransferIdDeleteResponses = { + /** + * Successful Response + */ + 200: Message; +}; + +export type CancelTransferTransfersTransferIdDeleteResponse = CancelTransferTransfersTransferIdDeleteResponses[keyof CancelTransferTransfersTransferIdDeleteResponses]; + +export type GetTransferTransfersTransferIdGetData = { + body?: never; + path: { + /** + * Transfer Id + */ + transfer_id: string; + }; + query?: never; + url: '/transfers/{transfer_id}'; +}; + +export type GetTransferTransfersTransferIdGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetTransferTransfersTransferIdGetError = GetTransferTransfersTransferIdGetErrors[keyof GetTransferTransfersTransferIdGetErrors]; + +export type GetTransferTransfersTransferIdGetResponses = { + /** + * Successful Response + */ + 200: TransferDetail; +}; + +export type GetTransferTransfersTransferIdGetResponse = GetTransferTransfersTransferIdGetResponses[keyof GetTransferTransfersTransferIdGetResponses]; + +export type GetTransferLogsTransfersTransferIdLogsGetData = { + body?: never; + path: { + /** + * Transfer Id + */ + transfer_id: string; + }; + query?: never; + url: '/transfers/{transfer_id}/logs'; +}; + +export type GetTransferLogsTransfersTransferIdLogsGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetTransferLogsTransfersTransferIdLogsGetError = GetTransferLogsTransfersTransferIdLogsGetErrors[keyof GetTransferLogsTransfersTransferIdLogsGetErrors]; + +export type GetTransferLogsTransfersTransferIdLogsGetResponses = { + /** + * Successful Response + */ + 200: TransferLogIndex; +}; + +export type GetTransferLogsTransfersTransferIdLogsGetResponse = GetTransferLogsTransfersTransferIdLogsGetResponses[keyof GetTransferLogsTransfersTransferIdLogsGetResponses]; + +export type GetTransferLogTransfersTransferIdLogsStreamGetData = { + body?: never; + path: { + /** + * Transfer Id + */ + transfer_id: string; + stream: LogStream; + }; + query?: { + mode?: LogReadMode; + /** + * Lines + */ + lines?: number; + /** + * Bytes + */ + bytes?: number | null; + }; + url: '/transfers/{transfer_id}/logs/{stream}'; +}; + +export type GetTransferLogTransfersTransferIdLogsStreamGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetTransferLogTransfersTransferIdLogsStreamGetError = GetTransferLogTransfersTransferIdLogsStreamGetErrors[keyof GetTransferLogTransfersTransferIdLogsStreamGetErrors]; + +export type GetTransferLogTransfersTransferIdLogsStreamGetResponses = { + /** + * Successful Response + */ + 200: string; +}; + +export type GetTransferLogTransfersTransferIdLogsStreamGetResponse = GetTransferLogTransfersTransferIdLogsStreamGetResponses[keyof GetTransferLogTransfersTransferIdLogsStreamGetResponses]; diff --git a/frontend/src/client/zod.gen.ts b/frontend/src/client/zod.gen.ts new file mode 100644 index 0000000..efd3e42 --- /dev/null +++ b/frontend/src/client/zod.gen.ts @@ -0,0 +1,662 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import * as z from 'zod'; + +/** + * BatchProcessingPipelineParameters + * + * Configuration parameters for the Batch Processing Pipeline + * + * This pipeline accumulates individual events into fixed-size batches before + * passing them downstream + * + * Attributes: + * + * type: Discriminator field, must be ``"BatchProcessingPipeline"`` + * + * batch_size: Number of events to accumulate per batch + */ +export const zBatchProcessingPipelineParameters = z.object({ + batch_size: z.int(), + type: z.literal('BatchProcessingPipeline') +}); + +/** + * BinaryDataStreamingDataHandlerParameters + * + * Configuration parameters for the Binary Data Streaming Data Handler + * + * This data handler forwards serialized byte objects to one or more remote + * endpoints over a ZMQ PUSH socket + * + * Attributes: + * + * type: Discriminator field, must be ``"BinaryDataStreamingDataHandler"`` + * + * urls: List of endpoint URLs to bind to (server mode) or connect to + * (client mode) + * + * distribute: Boolean, if True: round robin connect the ranks, False: all ranks connect to all urls and send the same data + * + * buffer: buffer size, if set to 0 the OS default is used + * + * role: Whether this node acts as the ZMQ ``"server"`` (binds) or + * ``"client"`` (connects). Defaults to ``"server"`` + * + * library: Underlying transport library to use. Currently only ``"zmq"`` + * is supported. Defaults to ``"zmq"`` + * + * socket_type: Socket pattern to use. Currently only ``"push"`` is + * supported. Defaults to ``"push"`` + */ +export const zBinaryDataStreamingDataHandlerParameters = z.object({ + buffer: z.int().optional().default(0), + distribute: z.boolean().optional().default(true), + library: z.literal('zmq').optional().default('zmq'), + role: z.enum(['server', 'client']).optional(), + socket_type: z.literal('push').optional().default('push'), + type: z.literal('BinaryDataStreamingDataHandler'), + urls: z.array(z.string()) +}); + +/** + * BinaryFileWritingDataHandlerParameters + * + * Configuration parameters for the Binary File Writing Data Handler + * + * This data handler writes each serialized byte object to a separate file on + * the filesystem + * + * Attributes: + * + * type: Discriminator field, must be ``"BinaryFileWritingDataHandler"`` + * + * file_prefix: Optional string prepended to every output filename, + * separated from the rest of the name by an underscore. Defaults to + * ``""`` (no prefix) + * + * file_suffix: File extension used for output files, without the leading + * dot. Defaults to ``"h5"`` + * + * write_directory: Directory in which output files are created. The + * directory is created (including parents) if it does not already + * exist. Defaults to the current working directory + */ +export const zBinaryFileWritingDataHandlerParameters = z.object({ + file_prefix: z.string().optional().default(''), + file_suffix: z.string().optional().default('h5'), + type: z.literal('BinaryFileWritingDataHandler'), + write_directory: z.string().optional() +}); + +/** + * ConstValueParameters + * + * Parameters for ConstValue class + */ +export const zConstValueParameters = z.object({ + dtype: z.string(), + type: z.literal('ConstValue'), + value: z.union([ + z.int(), + z.number(), + z.array(z.union([z.int(), z.number()])) + ]) +}); + +/** + * ConsumerConnectionInfo + * + * The cache push socket the consumer connects to. + */ +export const zConsumerConnectionInfo = z.object({ + host: z.string(), + port: z.int(), + uri: z.string() +}); + +/** + * GenericRandomNumpyArrayParameters + * + * Parameters for the GenericRandomNumpyArray class + */ +export const zGenericRandomNumpyArrayParameters = z.object({ + always_random: z.boolean().optional().default(true), + array_dtype: z.string(), + array_shape: z.union([ + z.int(), + z.array(z.int()) + ]), + type: z.literal('GenericRandomNumpyArray') +}); + +/** + * HDF5BinarySerializerParameters + * + * Configuration parameters for the HDF5 binary serializer + * + * This serializer encodes a batch of event data arrays into an in-memory + * HDF5 file. Optional compression can be applied to each dataset + * + * Attributes: + * + * type: Discriminator field, must be ``"HDF5BinarySerializer"`` + * + * compression_level: Compression level passed to the chosen algorithm. + * Interpretation depends on the algorithm. Defaults to ``3`` + * + * compression: Compression algorithm to use. Supported values are + * ``"gzip"``, ``"gzip_with_shuffle"``, ``"bitshuffle_with_lz4"``, + * ``"bitshuffle_with_zstd"``, and ``"zfp"``. Set to ``None`` to + * disable compression. Defaults to ``None`` + * + * fields: Dictionary storing the mapping from data source name to the + * HDF5 dataset path under which that source's data will be stored + */ +export const zHdf5BinarySerializerParameters = z.object({ + compression: z.enum([ + 'gzip', + 'gzip_with_shuffle', + 'bitshuffle_with_lz4', + 'bitshuffle_with_zstd', + 'zfp' + ]).nullish(), + compression_level: z.int().optional().default(0), + fields: z.record(z.string(), z.string()), + type: z.literal('HDF5BinarySerializer') +}); + +/** + * InternalEventSourceParameters + * + * Configuration parameters for the Internal Event Source + * + * This event source generates synthetic events entirely in-process and does + * not depend on any external data-acquisition framework. It is intended + * mainly for testing and development + * + * Attributes: + * + * type: Discriminator field, must be ``"InternalEventSource"`` + * + * number_of_events_to_generate: Total number of synthetic events to + * produce before the source is exhausted + */ +export const zInternalEventSourceParameters = z.object({ + number_of_events_to_generate: z.int(), + type: z.literal('InternalEventSource') +}); + +/** + * LogReadMode + */ +export const zLogReadMode = z.enum(['head', 'tail']); + +/** + * LogStream + */ +export const zLogStream = z.enum([ + 'cache', + 'producer_stdout', + 'producer_stderr' +]); + +/** + * Message + */ +export const zMessage = z.object({ + message: z.string() +}); + +/** + * PeaknetPreprocessingPipelineParameters + * + * Configuration parameters for the PeakNet Preprocessing Pipeline + * + * This pipeline pads detector images to a uniform size, accumulates them + * into batches, and optionally adds a channel dimension, preparing the data + * for inference with the PeakNet model + * + * Attributes: + * + * type: Discriminator field, must be ``"PeaknetPreprocessingPipeline"`` + * + * batch_size: Number of events to accumulate per batch + * + * target_height: Target image height (in pixels) after padding + * + * target_width: Target image width (in pixels) after padding + * + * pad_style: How to distribute padding around the image; either + * ``"center"`` (equal padding on both sides) or ``"bottom-right"`` + * (padding added only to the bottom and right edges) + * Defaults to ``"center"`` + * + * add_channel_dim: Whether to insert a channel dimension after batching, + * converting (B, H, W) arrays to (B, C, H, W). Defaults to ``True`` + * + * num_channels: Number of channels to produce when ``add_channel_dim`` + * is ``True``. Defaults to ``1`` + */ +export const zPeaknetPreprocessingPipelineParameters = z.object({ + add_channel_dim: z.boolean().optional().default(true), + batch_size: z.int(), + num_channels: z.int().optional().default(1), + pad_style: z.enum(['center', 'bottom-right']).optional(), + target_height: z.int(), + target_width: z.int(), + type: z.literal('PeaknetPreprocessingPipeline') +}); + +/** + * Psana1DetectorInterfaceParameters + */ +export const zPsana1DetectorInterfaceParameters = z.object({ + psana_fields: z.union([ + z.array(z.string()), + z.string() + ]).nullish(), + psana_name: z.string(), + type: z.literal('Psana1DetectorInterface') +}); + +/** + * Psana1EventSourceParameters + * + * Configuration parameters for the Psana1 Event Source + * + * This event source reads events using the psana1 framework (LCLS-I) + * + * Attributes: + * + * type: Discriminator field, must be ``"Psana1EventSource"`` + */ +export const zPsana1EventSourceParameters = z.object({ + type: z.literal('Psana1EventSource') +}); + +/** + * Psana1TimestampParameters + * + * Parameters for psana1 timestamp interface + */ +export const zPsana1TimestampParameters = z.object({ + type: z.literal('Psana1Timestamp') +}); + +/** + * Psana2DetectorInterfaceParameters + */ +export const zPsana2DetectorInterfaceParameters = z.object({ + dtype: z.string().nullish(), + psana_fields: z.union([ + z.array(z.string()), + z.string() + ]).nullish(), + psana_name: z.string(), + type: z.literal('Psana2DetectorInterface') +}); + +/** + * Psana2EventSourceParameters + * + * Configuration parameters for the Psana2 Event Source + * + * This event source reads events using the psana2 framework (LCLS-II) + * + * Attributes: + * + * type: Discriminator field, must be ``"Psana2EventSource"`` + */ +export const zPsana2EventSourceParameters = z.object({ + type: z.literal('Psana2EventSource') +}); + +/** + * Psana2RunInfoParameters + * + * Parameters for run info data source interface + */ +export const zPsana2RunInfoParameters = z.object({ + type: z.literal('Psana2RunInfo') +}); + +/** + * Psana2TimestampParameters + * + * Parameters for psana2 timestamp interface + */ +export const zPsana2TimestampParameters = z.object({ + type: z.literal('Psana2Timestamp') +}); + +/** + * SimplonBinarySerializerParameters + * + * Configuration parameters for the Simplon binary serializer + * + * This serializer encodes event data into the Simplon 1.8 binary message + * format as specified by Dectris + * + * Attributes: + * + * type: Discriminator field, must be ``"SimplonBinarySerializer"`` + * + * data_source_to_serialize: Name of the data source whose array will be + * compressed and embedded in each Simplon image message + * + * polarization_fraction: Fraction of linear polarization of the X-ray + * beam (between 0 and 1) + * + * polarization_axis: Three-element list representing the polarization + * axis direction vector + * + * data_collection_rate: Human-readable string describing the nominal + * data collection rate (e.g. ``"120 Hz"``) + * + * detector_name: Human-readable name of the detector + * + * detector_type: Model or type string identifying the detector hardware + */ +export const zSimplonBinarySerializerParameters = z.object({ + data_collection_rate: z.string(), + data_source_to_serialize: z.string(), + detector_name: z.string(), + detector_type: z.string(), + polarization_axis: z.array(z.number()), + polarization_fraction: z.number(), + type: z.literal('SimplonBinarySerializer') +}); + +/** + * SourceIdentifierParameters + * + * Parameters for source identifier data source interface + */ +export const zSourceIdentifierParameters = z.object({ + type: z.literal('SourceIdentifier') +}); + +/** + * Parameters + * + * Top-level configuration parameters for an lclstreamer run + * + * This model aggregates all sub-component configuration into a single object + * + * Attributes: + * + * source_identifier: A string that uniquely identifies the data source + * (e.g. a psana data source string) + * + * skip_incomplete_events: When ``True``, events for which one or more + * data sources returned no data are silently dropped from the stream + * + * event_source: Configuration for the event source + * + * data_sources: Mapping from arbitrary data source names to the + * configuration parameters of each data source + * + * processing_pipeline: Configuration for the Processing Pipeline applied + * to the event stream + * + * data_serializer: Configuration for the serializer that converts + * processed events into byte objects + * + * data_handlers: Ordered list of data handler configurations; each + * handler receives the serialized byte object in turn + */ +export const zParameters = z.object({ + data_handlers: z.array(z.union([z.object({ + type: z.literal('BinaryDataStreamingDataHandler') + }).and(zBinaryDataStreamingDataHandlerParameters), z.object({ + type: z.literal('BinaryFileWritingDataHandler') + }).and(zBinaryFileWritingDataHandlerParameters)])), + data_serializer: z.union([ + z.object({ + type: z.literal('HDF5BinarySerializer') + }).and(zHdf5BinarySerializerParameters), + z.object({ + type: z.literal('SimplonBinarySerializer') + }).and(zSimplonBinarySerializerParameters) + ]), + data_sources: z.record(z.string(), z.union([ + z.object({ + type: z.literal('GenericRandomNumpyArray') + }).and(zGenericRandomNumpyArrayParameters), + z.object({ + type: z.literal('ConstValue') + }).and(zConstValueParameters), + z.object({ + type: z.literal('Psana1DetectorInterface') + }).and(zPsana1DetectorInterfaceParameters), + z.object({ + type: z.literal('Psana2DetectorInterface') + }).and(zPsana2DetectorInterfaceParameters), + z.object({ + type: z.literal('Psana1Timestamp') + }).and(zPsana1TimestampParameters), + z.object({ + type: z.literal('Psana2Timestamp') + }).and(zPsana2TimestampParameters), + z.object({ + type: z.literal('SourceIdentifier') + }).and(zSourceIdentifierParameters), + z.object({ + type: z.literal('Psana2RunInfo') + }).and(zPsana2RunInfoParameters) + ])), + event_source: z.union([ + z.object({ + type: z.literal('InternalEventSource') + }).and(zInternalEventSourceParameters), + z.object({ + type: z.literal('Psana1EventSource') + }).and(zPsana1EventSourceParameters), + z.object({ + type: z.literal('Psana2EventSource') + }).and(zPsana2EventSourceParameters) + ]), + processing_pipeline: z.union([ + z.object({ + type: z.literal('BatchProcessingPipeline') + }).and(zBatchProcessingPipelineParameters), + z.object({ + type: z.literal('PeaknetPreprocessingPipeline') + }).and(zPeaknetPreprocessingPipelineParameters) + ]), + skip_incomplete_events: z.boolean(), + source_identifier: z.string() +}); + +/** + * TransferCreate + */ +export const zTransferCreate = z.object({ + parameters: zParameters +}); + +/** + * TransferLogStreamInfo + * + * One log stream's resolved location and (best-effort) availability. + */ +export const zTransferLogStreamInfo = z.object({ + available: z.boolean(), + modified_at: z.iso.datetime().nullish(), + path: z.string(), + size: z.int().nullish(), + stream: zLogStream +}); + +/** + * TransferLogIndex + */ +export const zTransferLogIndex = z.object({ + streams: z.array(zTransferLogStreamInfo), + transfer_id: z.uuid() +}); + +/** + * TransferState + */ +export const zTransferState = z.enum([ + 'provisioning', + 'ready', + 'canceling', + 'canceled', + 'completed', + 'failed' +]); + +/** + * TransferPublic + */ +export const zTransferPublic = z.object({ + connection_info: zConsumerConnectionInfo.nullish(), + created_at: z.iso.datetime(), + id: z.uuid(), + requested_by: z.string(), + state: zTransferState +}); + +/** + * TransfersPublic + */ +export const zTransfersPublic = z.object({ + count: z.int(), + data: z.array(zTransferPublic) +}); + +/** + * TransitionSource + */ +export const zTransitionSource = z.enum([ + 'producer', + 'cache', + 'user', + 'orchestrator' +]); + +/** + * TransitionPublic + */ +export const zTransitionPublic = z.object({ + created_at: z.iso.datetime(), + info: z.string().nullish(), + source: zTransitionSource.nullish(), + state: zTransferState +}); + +/** + * TransferDetail + */ +export const zTransferDetail = z.object({ + connection_info: zConsumerConnectionInfo.nullish(), + created_at: z.iso.datetime(), + id: z.uuid(), + requested_by: z.string(), + state: zTransferState, + transitions: z.array(zTransitionPublic).optional().default([]) +}); + +/** + * ValidationError + */ +export const zValidationError = z.object({ + ctx: z.record(z.string(), z.unknown()).optional(), + input: z.unknown().optional(), + loc: z.array(z.union([z.string(), z.int()])), + msg: z.string(), + type: z.string() +}); + +/** + * HTTPValidationError + */ +export const zHttpValidationError = z.object({ + detail: z.array(zValidationError).optional() +}); + +export const zGetTransfersTransfersGetData = z.object({ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + skip: z.int().optional().default(0), + limit: z.int().optional().default(100), + state: zTransferState.nullish() + }).optional() +}); + +/** + * Successful Response + */ +export const zGetTransfersTransfersGetResponse = zTransfersPublic; + +export const zNewTransferTransfersPostData = z.object({ + body: zTransferCreate, + path: z.never().optional(), + query: z.never().optional() +}); + +/** + * Successful Response + */ +export const zNewTransferTransfersPostResponse = zTransferPublic; + +export const zCancelTransferTransfersTransferIdDeleteData = z.object({ + body: z.never().optional(), + path: z.object({ + transfer_id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * Successful Response + */ +export const zCancelTransferTransfersTransferIdDeleteResponse = zMessage; + +export const zGetTransferTransfersTransferIdGetData = z.object({ + body: z.never().optional(), + path: z.object({ + transfer_id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * Successful Response + */ +export const zGetTransferTransfersTransferIdGetResponse = zTransferDetail; + +export const zGetTransferLogsTransfersTransferIdLogsGetData = z.object({ + body: z.never().optional(), + path: z.object({ + transfer_id: z.uuid() + }), + query: z.never().optional() +}); + +/** + * Successful Response + */ +export const zGetTransferLogsTransfersTransferIdLogsGetResponse = zTransferLogIndex; + +export const zGetTransferLogTransfersTransferIdLogsStreamGetData = z.object({ + body: z.never().optional(), + path: z.object({ + transfer_id: z.uuid(), + stream: zLogStream + }), + query: z.object({ + mode: zLogReadMode.optional().default('tail'), + lines: z.int().optional().default(200), + bytes: z.int().nullish() + }).optional() +}); + +/** + * Successful Response + */ +export const zGetTransferLogTransfersTransferIdLogsStreamGetResponse = z.string();