diff --git a/openapi-ts.config.ts b/openapi-ts.config.ts new file mode 100644 index 0000000..9a6d935 --- /dev/null +++ b/openapi-ts.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from "@hey-api/openapi-ts"; + +export default defineConfig({ + input: "http://localhost:8000/openapi.json", + output: "src/client", + plugins: [ + "@hey-api/client-axios", + "@hey-api/client-next", + "@tanstack/react-query", + ], +}); diff --git a/package.json b/package.json index df906ad..d851c86 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "build": "next build", "start": "next start", "lint": "next lint", - "generate-client": "openapi --input http://127.0.0.1:8000/openapi.json --output ./src/client --client axios --useOptions --useUnionTypes --exportSchemas true && prettier --write ./src/client/**/*.ts" + "generate-client": "openapi-ts && prettier --write ./src/client/**/*.ts && git add ./src/client" }, "dependencies": { "@dnd-kit/core": "^6.3.1", @@ -29,7 +29,6 @@ "lexorank": "^1.0.5", "libphonenumber-js": "^1.12.10", "next": "15.3.3", - "openapi-typescript-codegen": "^0.29.0", "react": "19.1.0", "react-dom": "19.1.0", "react-imask": "^7.6.1", @@ -40,6 +39,9 @@ "devDependencies": { "@babel/core": "^7.27.4", "@eslint/js": "^9.29.0", + "@hey-api/client-axios": "^0.9.1", + "@hey-api/client-next": "^0.5.1", + "@hey-api/openapi-ts": "^0.80.1", "@ianvs/prettier-plugin-sort-imports": "^4.4.2", "@storybook/nextjs": "^8.6.8", "@storybook/react": "^8.6.8", diff --git a/src/app/deals/contexts/ProjectsContext.tsx b/src/app/deals/contexts/ProjectsContext.tsx index 4303e7a..5c13e7f 100644 --- a/src/app/deals/contexts/ProjectsContext.tsx +++ b/src/app/deals/contexts/ProjectsContext.tsx @@ -7,7 +7,7 @@ import React, { useEffect, useState, } from "react"; -import useProjects from "@/app/deals/hooks/useProjects"; +import useProjectsList from "@/hooks/useProjectsList"; import { ProjectSchema } from "@/types/ProjectSchema"; type ProjectsContextState = { @@ -23,7 +23,7 @@ const ProjectsContext = createContext( ); const useProjectsContextState = () => { - const { projects, refetchProjects } = useProjects(); + const { projects } = useProjectsList(); const [selectedProject, setSelectedProject] = useState(null); diff --git a/src/app/deals/hooks/useProjects.ts b/src/app/deals/hooks/useProjects.ts deleted file mode 100644 index 5ec90b3..0000000 --- a/src/app/deals/hooks/useProjects.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { useEffect, useState } from "react"; -import { ProjectSchema } from "@/types/ProjectSchema"; - -const useProjects = () => { - const [projects, setProjects] = useState([]); - - useEffect(() => { - const mockProjects = [ - { id: 1, name: "Проект 1" }, - { id: 2, name: "Проект 2" }, - { id: 3, name: "Проект 3" }, - ]; - setProjects(mockProjects); - }, []); - - const refetchProjects = () => {}; - - return { - projects, - setProjects, - refetchProjects, - }; -}; - -export default useProjects; diff --git a/src/client/@tanstack/react-query.gen.ts b/src/client/@tanstack/react-query.gen.ts new file mode 100644 index 0000000..a630ccb --- /dev/null +++ b/src/client/@tanstack/react-query.gen.ts @@ -0,0 +1,63 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { queryOptions } from "@tanstack/react-query"; +import { client as _heyApiClient } from "../client.gen"; +import { getProjects, type Options } from "../sdk.gen"; +import type { GetProjectsData } from "../types.gen"; + +export type QueryKey = [ + Pick & { + _id: string; + _infinite?: boolean; + }, +]; + +const createQueryKey = ( + id: string, + options?: TOptions, + infinite?: boolean +): [QueryKey[0]] => { + const params: QueryKey[0] = { + _id: id, + baseURL: + options?.baseURL || + (options?.client ?? _heyApiClient).getConfig().baseURL, + } as QueryKey[0]; + if (infinite) { + params._infinite = infinite; + } + 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 getProjectsQueryKey = (options?: Options) => + createQueryKey("getProjects", options); + +/** + * Get Projects + */ +export const getProjectsOptions = (options?: Options) => { + return queryOptions({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getProjects({ + ...options, + ...queryKey[0], + signal, + throwOnError: true, + }); + return data; + }, + queryKey: getProjectsQueryKey(options), + }); +}; diff --git a/src/client/client.gen.ts b/src/client/client.gen.ts new file mode 100644 index 0000000..aaac1be --- /dev/null +++ b/src/client/client.gen.ts @@ -0,0 +1,28 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { + createClient, + createConfig, + type Config, + type ClientOptions as DefaultClientOptions, +} from "./client"; +import type { ClientOptions } 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({ + baseURL: "http://localhost:8000", + }) +); diff --git a/src/client/client/client.ts b/src/client/client/client.ts new file mode 100644 index 0000000..e94e50a --- /dev/null +++ b/src/client/client/client.ts @@ -0,0 +1,114 @@ +import type { AxiosError, RawAxiosRequestHeaders } from "axios"; +import axios from "axios"; +import type { Client, Config } from "./types"; +import { + buildUrl, + createConfig, + mergeConfigs, + mergeHeaders, + setAuthParams, +} from "./utils"; + +export const createClient = (config: Config = {}): Client => { + let _config = mergeConfigs(createConfig(), config); + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { auth, ...configWithoutAuth } = _config; + const 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(); + }; + + // @ts-expect-error + const request: Client["request"] = async options => { + 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 && opts.bodySerializer) { + opts.body = opts.bodySerializer(opts.body); + } + + const url = buildUrl(opts); + + 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: opts.baseURL as string, + data: opts.body, + 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; + } + }; + + return { + buildUrl, + delete: options => request({ ...options, method: "DELETE" }), + get: options => request({ ...options, method: "GET" }), + getConfig, + head: options => request({ ...options, method: "HEAD" }), + instance, + options: options => request({ ...options, method: "OPTIONS" }), + patch: options => request({ ...options, method: "PATCH" }), + post: options => request({ ...options, method: "POST" }), + put: options => request({ ...options, method: "PUT" }), + request, + setConfig, + } as Client; +}; diff --git a/src/client/client/index.ts b/src/client/client/index.ts new file mode 100644 index 0000000..b73b654 --- /dev/null +++ b/src/client/client/index.ts @@ -0,0 +1,21 @@ +export type { Auth } from "../core/auth"; +export type { QuerySerializerOptions } from "../core/bodySerializer"; +export { + formDataBodySerializer, + jsonBodySerializer, + urlSearchParamsBodySerializer, +} from "../core/bodySerializer"; +export { buildClientParams } from "../core/params"; +export { createClient } from "./client"; +export type { + Client, + ClientOptions, + Config, + CreateClientConfig, + Options, + OptionsLegacyParser, + RequestOptions, + RequestResult, + TDataShape, +} from "./types"; +export { createConfig } from "./utils"; diff --git a/src/client/client/types.ts b/src/client/client/types.ts new file mode 100644 index 0000000..4d72bd6 --- /dev/null +++ b/src/client/client/types.ts @@ -0,0 +1,183 @@ +import type { + AxiosError, + AxiosInstance, + AxiosRequestHeaders, + AxiosResponse, + AxiosStatic, + CreateAxiosDefaults, +} from "axios"; +import type { Auth } from "../core/auth"; +import type { Client as CoreClient, Config as CoreConfig } from "../core/types"; + +export interface Config + extends Omit< + CreateAxiosDefaults, + "auth" | "baseURL" | "headers" | "method" + >, + CoreConfig { + /** + * Axios implementation. You can use this option to provide a custom + * Axios instance. + * + * @default axios + */ + axios?: AxiosStatic; + /** + * 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< + ThrowOnError extends boolean = boolean, + Url extends string = string, +> extends Config<{ + throwOnError: ThrowOnError; + }> { + /** + * 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 type RequestResult< + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = boolean, +> = ThrowOnError extends true + ? Promise< + AxiosResponse< + TData extends Record ? TData[keyof TData] : TData + > + > + : Promise< + | (AxiosResponse< + TData extends Record + ? TData[keyof TData] + : TData + > & { error: undefined }) + | (AxiosError< + TError extends Record + ? TError[keyof TError] + : TError + > & { + data: undefined; + error: TError extends Record + ? TError[keyof TError] + : TError; + }) + >; + +export interface ClientOptions { + baseURL?: string; + throwOnError?: boolean; +} + +type MethodFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, +>( + options: Omit, "method"> +) => RequestResult; + +type RequestFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, +>( + options: Omit, "method"> & + Pick>, "method"> +) => RequestResult; + +type BuildUrlFn = < + TData extends { + body?: unknown; + path?: Record; + query?: Record; + url: string; + }, +>( + options: Pick & Omit, "axios"> +) => 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, +> = OmitKeys, "body" | "path" | "query" | "url"> & + Omit; + +export type OptionsLegacyParser< + TData = unknown, + ThrowOnError extends boolean = boolean, +> = TData extends { body?: any } + ? TData extends { headers?: any } + ? OmitKeys, "body" | "headers" | "url"> & + TData + : OmitKeys, "body" | "url"> & + TData & + Pick, "headers"> + : TData extends { headers?: any } + ? OmitKeys, "headers" | "url"> & + TData & + Pick, "body"> + : OmitKeys, "url"> & TData; diff --git a/src/client/client/utils.ts b/src/client/client/utils.ts new file mode 100644 index 0000000..8d86d8a --- /dev/null +++ b/src/client/client/utils.ts @@ -0,0 +1,292 @@ +import { getAuthToken } from "../core/auth"; +import type { + QuerySerializer, + QuerySerializerOptions, +} from "../core/bodySerializer"; +import type { ArraySeparatorStyle } from "../core/pathSerializer"; +import { + serializeArrayParam, + serializeObjectParam, + serializePrimitiveParam, +} from "../core/pathSerializer"; +import type { Client, ClientOptions, Config, RequestOptions } from "./types"; + +interface PathSerializer { + path: Record; + url: string; +} + +const PATH_PARAM_RE = /\{[^{}]+\}/g; + +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 createQuerySerializer = ({ + allowReserved, + array, + object, +}: 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; + } + + if (Array.isArray(value)) { + const serializedArray = serializeArrayParam({ + allowReserved, + explode: true, + name, + style: "form", + value, + ...array, + }); + if (serializedArray) search.push(serializedArray); + } else if (typeof value === "object") { + const serializedObject = serializeObjectParam({ + allowReserved, + explode: true, + name, + style: "deepObject", + value: value as Record, + ...object, + }); + if (serializedObject) search.push(serializedObject); + } else { + const serializedPrimitive = serializePrimitiveParam({ + allowReserved, + name, + value: value as string, + }); + if (serializedPrimitive) search.push(serializedPrimitive); + } + } + } + return search.join("&"); + }; + return querySerializer; +}; + +export const setAuthParams = async ({ + security, + ...options +}: Pick, "security"> & + Pick & { + headers: Record; + }) => { + for (const auth of security) { + 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; + } + + return; + } +}; + +export const buildUrl: Client["buildUrl"] = options => { + const url = getUrl({ + 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, + }); + return url; +}; + +export const getUrl = ({ + path, + query, + querySerializer, + url: _url, +}: { + path?: Record; + query?: Record; + querySerializer: QuerySerializer; + url: string; +}) => { + const pathUrl = _url.startsWith("/") ? _url : `/${_url}`; + let url = 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 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/src/client/core/ApiError.ts b/src/client/core/ApiError.ts deleted file mode 100644 index f25aa06..0000000 --- a/src/client/core/ApiError.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -import type { ApiRequestOptions } from "./ApiRequestOptions"; -import type { ApiResult } from "./ApiResult"; - -export class ApiError extends Error { - public readonly url: string; - public readonly status: number; - public readonly statusText: string; - public readonly body: any; - public readonly request: ApiRequestOptions; - - constructor( - request: ApiRequestOptions, - response: ApiResult, - message: string - ) { - super(message); - - this.name = "ApiError"; - this.url = response.url; - this.status = response.status; - this.statusText = response.statusText; - this.body = response.body; - this.request = request; - } -} diff --git a/src/client/core/ApiRequestOptions.ts b/src/client/core/ApiRequestOptions.ts deleted file mode 100644 index cff730e..0000000 --- a/src/client/core/ApiRequestOptions.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export type ApiRequestOptions = { - readonly method: - | "GET" - | "PUT" - | "POST" - | "DELETE" - | "OPTIONS" - | "HEAD" - | "PATCH"; - readonly url: string; - readonly path?: Record; - readonly cookies?: Record; - readonly headers?: Record; - readonly query?: Record; - readonly formData?: Record; - readonly body?: any; - readonly mediaType?: string; - readonly responseHeader?: string; - readonly errors?: Record; -}; diff --git a/src/client/core/ApiResult.ts b/src/client/core/ApiResult.ts deleted file mode 100644 index ee1126e..0000000 --- a/src/client/core/ApiResult.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export type ApiResult = { - readonly url: string; - readonly ok: boolean; - readonly status: number; - readonly statusText: string; - readonly body: any; -}; diff --git a/src/client/core/CancelablePromise.ts b/src/client/core/CancelablePromise.ts deleted file mode 100644 index 183e413..0000000 --- a/src/client/core/CancelablePromise.ts +++ /dev/null @@ -1,130 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export class CancelError extends Error { - constructor(message: string) { - super(message); - this.name = "CancelError"; - } - - public get isCancelled(): boolean { - return true; - } -} - -export interface OnCancel { - readonly isResolved: boolean; - readonly isRejected: boolean; - readonly isCancelled: boolean; - - (cancelHandler: () => void): void; -} - -export class CancelablePromise implements Promise { - #isResolved: boolean; - #isRejected: boolean; - #isCancelled: boolean; - readonly #cancelHandlers: (() => void)[]; - readonly #promise: Promise; - #resolve?: (value: T | PromiseLike) => void; - #reject?: (reason?: any) => void; - - constructor( - executor: ( - resolve: (value: T | PromiseLike) => void, - reject: (reason?: any) => void, - onCancel: OnCancel - ) => void - ) { - this.#isResolved = false; - this.#isRejected = false; - this.#isCancelled = false; - this.#cancelHandlers = []; - this.#promise = new Promise((resolve, reject) => { - this.#resolve = resolve; - this.#reject = reject; - - const onResolve = (value: T | PromiseLike): void => { - if (this.#isResolved || this.#isRejected || this.#isCancelled) { - return; - } - this.#isResolved = true; - if (this.#resolve) this.#resolve(value); - }; - - const onReject = (reason?: any): void => { - if (this.#isResolved || this.#isRejected || this.#isCancelled) { - return; - } - this.#isRejected = true; - if (this.#reject) this.#reject(reason); - }; - - const onCancel = (cancelHandler: () => void): void => { - if (this.#isResolved || this.#isRejected || this.#isCancelled) { - return; - } - this.#cancelHandlers.push(cancelHandler); - }; - - Object.defineProperty(onCancel, "isResolved", { - get: (): boolean => this.#isResolved, - }); - - Object.defineProperty(onCancel, "isRejected", { - get: (): boolean => this.#isRejected, - }); - - Object.defineProperty(onCancel, "isCancelled", { - get: (): boolean => this.#isCancelled, - }); - - return executor(onResolve, onReject, onCancel as OnCancel); - }); - } - - get [Symbol.toStringTag]() { - return "Cancellable Promise"; - } - - public then( - onFulfilled?: ((value: T) => TResult1 | PromiseLike) | null, - onRejected?: ((reason: any) => TResult2 | PromiseLike) | null - ): Promise { - return this.#promise.then(onFulfilled, onRejected); - } - - public catch( - onRejected?: ((reason: any) => TResult | PromiseLike) | null - ): Promise { - return this.#promise.catch(onRejected); - } - - public finally(onFinally?: (() => void) | null): Promise { - return this.#promise.finally(onFinally); - } - - public cancel(): void { - if (this.#isResolved || this.#isRejected || this.#isCancelled) { - return; - } - this.#isCancelled = true; - if (this.#cancelHandlers.length) { - try { - for (const cancelHandler of this.#cancelHandlers) { - cancelHandler(); - } - } catch (error) { - console.warn("Cancellation threw an error", error); - return; - } - } - this.#cancelHandlers.length = 0; - if (this.#reject) this.#reject(new CancelError("Request aborted")); - } - - public get isCancelled(): boolean { - return this.#isCancelled; - } -} diff --git a/src/client/core/OpenAPI.ts b/src/client/core/OpenAPI.ts deleted file mode 100644 index af29cb1..0000000 --- a/src/client/core/OpenAPI.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -import type { ApiRequestOptions } from "./ApiRequestOptions"; - -type Resolver = (options: ApiRequestOptions) => Promise; -type Headers = Record; - -export type OpenAPIConfig = { - BASE: string; - VERSION: string; - WITH_CREDENTIALS: boolean; - CREDENTIALS: "include" | "omit" | "same-origin"; - TOKEN?: string | Resolver | undefined; - USERNAME?: string | Resolver | undefined; - PASSWORD?: string | Resolver | undefined; - HEADERS?: Headers | Resolver | undefined; - ENCODE_PATH?: ((path: string) => string) | undefined; -}; - -export const OpenAPI: OpenAPIConfig = { - BASE: "", - VERSION: "0.1.0", - WITH_CREDENTIALS: false, - CREDENTIALS: "include", - TOKEN: undefined, - USERNAME: undefined, - PASSWORD: undefined, - HEADERS: undefined, - ENCODE_PATH: undefined, -}; diff --git a/src/client/core/auth.ts b/src/client/core/auth.ts new file mode 100644 index 0000000..cb59986 --- /dev/null +++ b/src/client/core/auth.ts @@ -0,0 +1,40 @@ +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/src/client/core/bodySerializer.ts b/src/client/core/bodySerializer.ts new file mode 100644 index 0000000..25d311e --- /dev/null +++ b/src/client/core/bodySerializer.ts @@ -0,0 +1,92 @@ +import type { + ArrayStyle, + ObjectStyle, + SerializerOptions, +} from "./pathSerializer"; + +export type QuerySerializer = (query: Record) => string; + +export type BodySerializer = (body: any) => any; + +export interface QuerySerializerOptions { + allowReserved?: boolean; + array?: SerializerOptions; + object?: SerializerOptions; +} + +const serializeFormDataPair = ( + data: FormData, + key: string, + value: unknown +): void => { + if (typeof value === "string" || value instanceof Blob) { + data.append(key, value); + } 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: < + T extends Record | Array>, + >( + body: T + ): FormData => { + const data = new FormData(); + + Object.entries(body).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: T): string => + JSON.stringify(body, (_key, value) => + typeof value === "bigint" ? value.toString() : value + ), +}; + +export const urlSearchParamsBodySerializer = { + bodySerializer: < + T extends Record | Array>, + >( + body: T + ): string => { + const data = new URLSearchParams(); + + Object.entries(body).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/src/client/core/params.ts b/src/client/core/params.ts new file mode 100644 index 0000000..c407be3 --- /dev/null +++ b/src/client/core/params.ts @@ -0,0 +1,156 @@ +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; + }; + +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; + } +>; + +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 (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" && !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; + (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) { + const name = field.map || key; + (params[field.in] as Record)[name] = 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 { + for (const [slot, allowed] of Object.entries( + config.allowExtra ?? {} + )) { + if (allowed) { + ( + params[slot as Slot] as Record< + string, + unknown + > + )[key] = value; + break; + } + } + } + } + } + } + } + + stripEmptySlots(params); + + return params; +}; diff --git a/src/client/core/pathSerializer.ts b/src/client/core/pathSerializer.ts new file mode 100644 index 0000000..c66aeff --- /dev/null +++ b/src/client/core/pathSerializer.ts @@ -0,0 +1,183 @@ +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/src/client/core/request.ts b/src/client/core/request.ts deleted file mode 100644 index 66d3344..0000000 --- a/src/client/core/request.ts +++ /dev/null @@ -1,372 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -import axios from "axios"; -import type { - AxiosError, - AxiosInstance, - AxiosRequestConfig, - AxiosResponse, -} from "axios"; -import FormData from "form-data"; -import { ApiError } from "./ApiError"; -import type { ApiRequestOptions } from "./ApiRequestOptions"; -import type { ApiResult } from "./ApiResult"; -import { CancelablePromise } from "./CancelablePromise"; -import type { OnCancel } from "./CancelablePromise"; -import type { OpenAPIConfig } from "./OpenAPI"; - -export const isDefined = ( - value: T | null | undefined -): value is Exclude => { - return value !== undefined && value !== null; -}; - -export const isString = (value: any): value is string => { - return typeof value === "string"; -}; - -export const isStringWithValue = (value: any): value is string => { - return isString(value) && value !== ""; -}; - -export const isBlob = (value: any): value is Blob => { - return ( - typeof value === "object" && - typeof value.type === "string" && - typeof value.stream === "function" && - typeof value.arrayBuffer === "function" && - typeof value.constructor === "function" && - typeof value.constructor.name === "string" && - /^(Blob|File)$/.test(value.constructor.name) && - /^(Blob|File)$/.test(value[Symbol.toStringTag]) - ); -}; - -export const isFormData = (value: any): value is FormData => { - return value instanceof FormData; -}; - -export const isSuccess = (status: number): boolean => { - return status >= 200 && status < 300; -}; - -export const base64 = (str: string): string => { - try { - return btoa(str); - } catch (err) { - // @ts-ignore - return Buffer.from(str).toString("base64"); - } -}; - -export const getQueryString = (params: Record): string => { - const qs: string[] = []; - - const append = (key: string, value: any) => { - qs.push( - `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}` - ); - }; - - const process = (key: string, value: any) => { - if (isDefined(value)) { - if (Array.isArray(value)) { - value.forEach(v => { - process(key, v); - }); - } else if (typeof value === "object") { - Object.entries(value).forEach(([k, v]) => { - process(`${key}[${k}]`, v); - }); - } else { - append(key, value); - } - } - }; - - Object.entries(params).forEach(([key, value]) => { - process(key, value); - }); - - if (qs.length > 0) { - return `?${qs.join("&")}`; - } - - return ""; -}; - -const getUrl = (config: OpenAPIConfig, options: ApiRequestOptions): string => { - const encoder = config.ENCODE_PATH || encodeURI; - - const path = options.url - .replace("{api-version}", config.VERSION) - .replace(/{(.*?)}/g, (substring: string, group: string) => { - if (options.path?.hasOwnProperty(group)) { - return encoder(String(options.path[group])); - } - return substring; - }); - - const url = `${config.BASE}${path}`; - if (options.query) { - return `${url}${getQueryString(options.query)}`; - } - return url; -}; - -export const getFormData = ( - options: ApiRequestOptions -): FormData | undefined => { - if (options.formData) { - const formData = new FormData(); - - const process = (key: string, value: any) => { - if (isString(value) || isBlob(value)) { - formData.append(key, value); - } else { - formData.append(key, JSON.stringify(value)); - } - }; - - Object.entries(options.formData) - .filter(([_, value]) => isDefined(value)) - .forEach(([key, value]) => { - if (Array.isArray(value)) { - value.forEach(v => process(key, v)); - } else { - process(key, value); - } - }); - - return formData; - } - return undefined; -}; - -type Resolver = (options: ApiRequestOptions) => Promise; - -export const resolve = async ( - options: ApiRequestOptions, - resolver?: T | Resolver -): Promise => { - if (typeof resolver === "function") { - return (resolver as Resolver)(options); - } - return resolver; -}; - -export const getHeaders = async ( - config: OpenAPIConfig, - options: ApiRequestOptions, - formData?: FormData -): Promise> => { - const [token, username, password, additionalHeaders] = await Promise.all([ - resolve(options, config.TOKEN), - resolve(options, config.USERNAME), - resolve(options, config.PASSWORD), - resolve(options, config.HEADERS), - ]); - - const formHeaders = - (typeof formData?.getHeaders === "function" && - formData?.getHeaders()) || - {}; - - const headers = Object.entries({ - Accept: "application/json", - ...additionalHeaders, - ...options.headers, - ...formHeaders, - }) - .filter(([_, value]) => isDefined(value)) - .reduce( - (headers, [key, value]) => ({ - ...headers, - [key]: String(value), - }), - {} as Record - ); - - if (isStringWithValue(token)) { - headers["Authorization"] = `Bearer ${token}`; - } - - if (isStringWithValue(username) && isStringWithValue(password)) { - const credentials = base64(`${username}:${password}`); - headers["Authorization"] = `Basic ${credentials}`; - } - - if (options.body !== undefined) { - if (options.mediaType) { - headers["Content-Type"] = options.mediaType; - } else if (isBlob(options.body)) { - headers["Content-Type"] = - options.body.type || "application/octet-stream"; - } else if (isString(options.body)) { - headers["Content-Type"] = "text/plain"; - } else if (!isFormData(options.body)) { - headers["Content-Type"] = "application/json"; - } - } - - return headers; -}; - -export const getRequestBody = (options: ApiRequestOptions): any => { - if (options.body) { - return options.body; - } - return undefined; -}; - -export const sendRequest = async ( - config: OpenAPIConfig, - options: ApiRequestOptions, - url: string, - body: any, - formData: FormData | undefined, - headers: Record, - onCancel: OnCancel, - axiosClient: AxiosInstance -): Promise> => { - const source = axios.CancelToken.source(); - - const requestConfig: AxiosRequestConfig = { - url, - headers, - data: body ?? formData, - method: options.method, - withCredentials: config.WITH_CREDENTIALS, - withXSRFToken: - config.CREDENTIALS === "include" ? config.WITH_CREDENTIALS : false, - cancelToken: source.token, - }; - - onCancel(() => source.cancel("The user aborted a request.")); - - try { - return await axiosClient.request(requestConfig); - } catch (error) { - const axiosError = error as AxiosError; - if (axiosError.response) { - return axiosError.response; - } - throw error; - } -}; - -export const getResponseHeader = ( - response: AxiosResponse, - responseHeader?: string -): string | undefined => { - if (responseHeader) { - const content = response.headers[responseHeader]; - if (isString(content)) { - return content; - } - } - return undefined; -}; - -export const getResponseBody = (response: AxiosResponse): any => { - if (response.status !== 204) { - return response.data; - } - return undefined; -}; - -export const catchErrorCodes = ( - options: ApiRequestOptions, - result: ApiResult -): void => { - const errors: Record = { - 400: "Bad Request", - 401: "Unauthorized", - 403: "Forbidden", - 404: "Not Found", - 500: "Internal Server Error", - 502: "Bad Gateway", - 503: "Service Unavailable", - ...options.errors, - }; - - const error = errors[result.status]; - if (error) { - throw new ApiError(options, result, error); - } - - if (!result.ok) { - const errorStatus = result.status ?? "unknown"; - const errorStatusText = result.statusText ?? "unknown"; - const errorBody = (() => { - try { - return JSON.stringify(result.body, null, 2); - } catch (e) { - return undefined; - } - })(); - - throw new ApiError( - options, - result, - `Generic Error: status: ${errorStatus}; status text: ${errorStatusText}; body: ${errorBody}` - ); - } -}; - -/** - * Request method - * @param config The OpenAPI configuration object - * @param options The request options from the service - * @param axiosClient The axios client instance to use - * @returns CancelablePromise - * @throws ApiError - */ -export const request = ( - config: OpenAPIConfig, - options: ApiRequestOptions, - axiosClient: AxiosInstance = axios -): CancelablePromise => { - return new CancelablePromise(async (resolve, reject, onCancel) => { - try { - const url = getUrl(config, options); - const formData = getFormData(options); - const body = getRequestBody(options); - const headers = await getHeaders(config, options, formData); - - if (!onCancel.isCancelled) { - const response = await sendRequest( - config, - options, - url, - body, - formData, - headers, - onCancel, - axiosClient - ); - const responseBody = getResponseBody(response); - const responseHeader = getResponseHeader( - response, - options.responseHeader - ); - - const result: ApiResult = { - url, - ok: isSuccess(response.status), - status: response.status, - statusText: response.statusText, - body: responseHeader ?? responseBody, - }; - - catchErrorCodes(options, result); - - resolve(result.body); - } - } catch (error) { - reject(error); - } - }); -}; diff --git a/src/client/core/types.ts b/src/client/core/types.ts new file mode 100644 index 0000000..8d2802f --- /dev/null +++ b/src/client/core/types.ts @@ -0,0 +1,118 @@ +import type { Auth, AuthToken } from "./auth"; +import type { + BodySerializer, + QuerySerializer, + QuerySerializerOptions, +} from "./bodySerializer"; + +export interface Client< + RequestFn = never, + Config = unknown, + MethodFn = never, + BuildUrlFn = never, +> { + /** + * Returns the final request URL. + */ + buildUrl: BuildUrlFn; + connect: MethodFn; + delete: MethodFn; + get: MethodFn; + getConfig: () => Config; + head: MethodFn; + options: MethodFn; + patch: MethodFn; + post: MethodFn; + put: MethodFn; + request: RequestFn; + setConfig: (config: Config) => Config; + trace: MethodFn; +} + +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?: + | "CONNECT" + | "DELETE" + | "GET" + | "HEAD" + | "OPTIONS" + | "PATCH" + | "POST" + | "PUT" + | "TRACE"; + /** + * 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/src/client/index.ts b/src/client/index.ts index 8f7ea7f..da87079 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -1,8 +1,3 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export { ApiError } from "./core/ApiError"; -export { CancelablePromise, CancelError } from "./core/CancelablePromise"; -export { OpenAPI } from "./core/OpenAPI"; -export type { OpenAPIConfig } from "./core/OpenAPI"; +// This file is auto-generated by @hey-api/openapi-ts +export * from "./types.gen"; +export * from "./sdk.gen"; diff --git a/src/client/sdk.gen.ts b/src/client/sdk.gen.ts new file mode 100644 index 0000000..22a0ae4 --- /dev/null +++ b/src/client/sdk.gen.ts @@ -0,0 +1,39 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { Client, Options as ClientOptions, TDataShape } from "./client"; +import { client as _heyApiClient } from "./client.gen"; +import type { GetProjectsData, GetProjectsResponses } from "./types.gen"; + +export type Options< + TData extends TDataShape = TDataShape, + ThrowOnError extends boolean = boolean, +> = ClientOptions & { + /** + * 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; +}; + +/** + * Get Projects + */ +export const getProjects = ( + options?: Options +) => { + return (options?.client ?? _heyApiClient).get< + GetProjectsResponses, + unknown, + ThrowOnError + >({ + responseType: "json", + url: "/project/", + ...options, + }); +}; diff --git a/src/client/types.gen.ts b/src/client/types.gen.ts new file mode 100644 index 0000000..4ad913d --- /dev/null +++ b/src/client/types.gen.ts @@ -0,0 +1,46 @@ +// This file is auto-generated by @hey-api/openapi-ts + +/** + * GetProjectsResponse + */ +export type GetProjectsResponse = { + /** + * Projects + */ + projects: Array; +}; + +/** + * ProjectSchema + */ +export type ProjectSchema = { + /** + * Name + */ + name: string; + /** + * Id + */ + id: number; +}; + +export type GetProjectsData = { + body?: never; + path?: never; + query?: never; + url: "/project/"; +}; + +export type GetProjectsResponses = { + /** + * Successful Response + */ + 200: GetProjectsResponse; +}; + +export type GetProjectsResponse2 = + GetProjectsResponses[keyof GetProjectsResponses]; + +export type ClientOptions = { + baseURL: "http://localhost:8000" | (string & {}); +}; diff --git a/src/hooks/useProjectsList.ts b/src/hooks/useProjectsList.ts new file mode 100644 index 0000000..b656ac3 --- /dev/null +++ b/src/hooks/useProjectsList.ts @@ -0,0 +1,12 @@ +import { useQuery } from "@tanstack/react-query"; +import { getProjectsOptions } from "@/client/@tanstack/react-query.gen"; + +const useProjectsList = () => { + const { data, refetch, isLoading } = useQuery({ + ...getProjectsOptions(), + }); + const projects = !data ? [] : data.projects; + return { projects, refetch, isLoading }; +}; + +export default useProjectsList; diff --git a/yarn.lock b/yarn.lock index 0397bf5..ea478a9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -29,17 +29,6 @@ __metadata: languageName: node linkType: hard -"@apidevtools/json-schema-ref-parser@npm:^11.5.4": - version: 11.9.3 - resolution: "@apidevtools/json-schema-ref-parser@npm:11.9.3" - dependencies: - "@jsdevtools/ono": "npm:^7.1.3" - "@types/json-schema": "npm:^7.0.15" - js-yaml: "npm:^4.1.0" - checksum: 10c0/5745813b3d964279f387677b7a903ba6634cdeaf879ff3a331a694392cbc923763f398506df190be114f2574b8b570baab3e367c2194bb35f50147ff6cf27d7a - languageName: node - linkType: hard - "@asamuzakjp/css-color@npm:^3.2.0": version: 3.2.0 resolution: "@asamuzakjp/css-color@npm:3.2.0" @@ -1948,6 +1937,57 @@ __metadata: languageName: node linkType: hard +"@hey-api/client-axios@npm:^0.9.1": + version: 0.9.1 + resolution: "@hey-api/client-axios@npm:0.9.1" + peerDependencies: + "@hey-api/openapi-ts": < 2 + axios: ">= 1.0.0 < 2" + checksum: 10c0/61cca384edcb1b1a877554d82846837a907b93380c1bee1725b41b048619115d60a5e2405980e7df1e2f0d318a8bc750248f6d2672a5a0f398fcba3b639a8f1c + languageName: node + linkType: hard + +"@hey-api/client-next@npm:^0.5.1": + version: 0.5.1 + resolution: "@hey-api/client-next@npm:0.5.1" + peerDependencies: + "@hey-api/openapi-ts": < 2 + checksum: 10c0/111ac8f4f85244661b99561e7dae36eee99558752b953dee070a5a588d5f50433034ed528035c4d911e2914850704e88ad1312de5475bc13ffe73748cceace62 + languageName: node + linkType: hard + +"@hey-api/json-schema-ref-parser@npm:1.0.6": + version: 1.0.6 + resolution: "@hey-api/json-schema-ref-parser@npm:1.0.6" + dependencies: + "@jsdevtools/ono": "npm:^7.1.3" + "@types/json-schema": "npm:^7.0.15" + js-yaml: "npm:^4.1.0" + lodash: "npm:^4.17.21" + checksum: 10c0/a3d15b2316ef5a4442131386aa61e196af4f0e01064d5c66a598cf0ea5b9217dce57cb40e98278cdac9548a7e27ecc5cf9146fe301b9371aefd81a0933553252 + languageName: node + linkType: hard + +"@hey-api/openapi-ts@npm:^0.80.1": + version: 0.80.1 + resolution: "@hey-api/openapi-ts@npm:0.80.1" + dependencies: + "@hey-api/json-schema-ref-parser": "npm:1.0.6" + ansi-colors: "npm:4.1.3" + c12: "npm:2.0.1" + color-support: "npm:1.1.3" + commander: "npm:13.0.0" + handlebars: "npm:4.7.8" + open: "npm:10.1.2" + semver: "npm:7.7.2" + peerDependencies: + typescript: ^5.5.3 + bin: + openapi-ts: bin/index.cjs + checksum: 10c0/5c203712b6d3e4ad502518c830b702f239c46150d31544b491e85873c419c85ade3f12109699716d39acb8b9351c80c399355d49a5fc92fd458cab9380a7e6d0 + languageName: node + linkType: hard + "@humanfs/core@npm:^0.19.1": version: 0.19.1 resolution: "@humanfs/core@npm:0.19.1" @@ -4668,6 +4708,13 @@ __metadata: languageName: node linkType: hard +"ansi-colors@npm:4.1.3": + version: 4.1.3 + resolution: "ansi-colors@npm:4.1.3" + checksum: 10c0/ec87a2f59902f74e61eada7f6e6fe20094a628dab765cfdbd03c3477599368768cffccdb5d3bb19a1b6c99126783a143b1fee31aab729b31ffe5836c7e5e28b9 + languageName: node + linkType: hard + "ansi-escapes@npm:^4.3.2": version: 4.3.2 resolution: "ansi-escapes@npm:4.3.2" @@ -5384,6 +5431,15 @@ __metadata: languageName: node linkType: hard +"bundle-name@npm:^4.1.0": + version: 4.1.0 + resolution: "bundle-name@npm:4.1.0" + dependencies: + run-applescript: "npm:^7.0.0" + checksum: 10c0/8e575981e79c2bcf14d8b1c027a3775c095d362d1382312f444a7c861b0e21513c0bd8db5bd2b16e50ba0709fa622d4eab6b53192d222120305e68359daece29 + languageName: node + linkType: hard + "busboy@npm:1.6.0": version: 1.6.0 resolution: "busboy@npm:1.6.0" @@ -5393,6 +5449,31 @@ __metadata: languageName: node linkType: hard +"c12@npm:2.0.1": + version: 2.0.1 + resolution: "c12@npm:2.0.1" + dependencies: + chokidar: "npm:^4.0.1" + confbox: "npm:^0.1.7" + defu: "npm:^6.1.4" + dotenv: "npm:^16.4.5" + giget: "npm:^1.2.3" + jiti: "npm:^2.3.0" + mlly: "npm:^1.7.1" + ohash: "npm:^1.1.4" + pathe: "npm:^1.1.2" + perfect-debounce: "npm:^1.0.0" + pkg-types: "npm:^1.2.0" + rc9: "npm:^2.1.2" + peerDependencies: + magicast: ^0.3.5 + peerDependenciesMeta: + magicast: + optional: true + checksum: 10c0/6a019047918102eda28c29988990fdf38aa88df05f94c5e06cbc501365dcdd80df2a7726d17d67882871ca931fd8d025a66d46bbc361275eeb0bcb849a06369a + languageName: node + linkType: hard + "cacache@npm:^19.0.1": version: 19.0.1 resolution: "cacache@npm:19.0.1" @@ -5573,6 +5654,22 @@ __metadata: languageName: node linkType: hard +"chokidar@npm:^4.0.1": + version: 4.0.3 + resolution: "chokidar@npm:4.0.3" + dependencies: + readdirp: "npm:^4.0.1" + checksum: 10c0/a58b9df05bb452f7d105d9e7229ac82fa873741c0c40ddcc7bb82f8a909fbe3f7814c9ebe9bc9a2bef9b737c0ec6e2d699d179048ef06ad3ec46315df0ebe6ad + languageName: node + linkType: hard + +"chownr@npm:^2.0.0": + version: 2.0.0 + resolution: "chownr@npm:2.0.0" + checksum: 10c0/594754e1303672171cc04e50f6c398ae16128eb134a88f801bf5354fd96f205320f23536a045d9abd8b51024a149696e51231565891d4efdab8846021ecf88e6 + languageName: node + linkType: hard + "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -5611,6 +5708,15 @@ __metadata: languageName: node linkType: hard +"citty@npm:^0.1.6": + version: 0.1.6 + resolution: "citty@npm:0.1.6" + dependencies: + consola: "npm:^3.2.3" + checksum: 10c0/d26ad82a9a4a8858c7e149d90b878a3eceecd4cfd3e2ed3cd5f9a06212e451fb4f8cbe0fa39a3acb1b3e8f18e22db8ee5def5829384bad50e823d4b301609b48 + languageName: node + linkType: hard + "cjs-module-lexer@npm:^1.2.3": version: 1.4.3 resolution: "cjs-module-lexer@npm:1.4.3" @@ -5706,6 +5812,15 @@ __metadata: languageName: node linkType: hard +"color-support@npm:1.1.3": + version: 1.1.3 + resolution: "color-support@npm:1.1.3" + bin: + color-support: bin.js + checksum: 10c0/8ffeaa270a784dc382f62d9be0a98581db43e11eee301af14734a6d089bd456478b1a8b3e7db7ca7dc5b18a75f828f775c44074020b51c05fc00e6d0992b1cc6 + languageName: node + linkType: hard + "color@npm:^4.2.3": version: 4.2.3 resolution: "color@npm:4.2.3" @@ -5739,10 +5854,10 @@ __metadata: languageName: node linkType: hard -"commander@npm:^12.0.0": - version: 12.1.0 - resolution: "commander@npm:12.1.0" - checksum: 10c0/6e1996680c083b3b897bfc1cfe1c58dfbcd9842fd43e1aaf8a795fbc237f65efcc860a3ef457b318e73f29a4f4a28f6403c3d653d021d960e4632dd45bde54a9 +"commander@npm:13.0.0": + version: 13.0.0 + resolution: "commander@npm:13.0.0" + checksum: 10c0/8ba1e2b83bfdbcefd967aa505f5f5dc58202aa5f8e10437f61f6980dd8a69f868dba439a261f9fb72fc543c5f6fe58140e37b001a4c70b92ae22527abe94dfe1 languageName: node linkType: hard @@ -5788,6 +5903,20 @@ __metadata: languageName: node linkType: hard +"confbox@npm:^0.1.7, confbox@npm:^0.1.8": + version: 0.1.8 + resolution: "confbox@npm:0.1.8" + checksum: 10c0/fc2c68d97cb54d885b10b63e45bd8da83a8a71459d3ecf1825143dd4c7f9f1b696b3283e07d9d12a144c1301c2ebc7842380bdf0014e55acc4ae1c9550102418 + languageName: node + linkType: hard + +"consola@npm:^3.2.3, consola@npm:^3.4.0": + version: 3.4.2 + resolution: "consola@npm:3.4.2" + checksum: 10c0/7cebe57ecf646ba74b300bcce23bff43034ed6fbec9f7e39c27cee1dc00df8a21cd336b466ad32e304ea70fba04ec9e890c200270de9a526ce021ba8a7e4c11a + languageName: node + linkType: hard + "console-browserify@npm:^1.2.0": version: 1.2.0 resolution: "console-browserify@npm:1.2.0" @@ -5926,6 +6055,9 @@ __metadata: "@dnd-kit/core": "npm:^6.3.1" "@dnd-kit/sortable": "npm:^10.0.0" "@eslint/js": "npm:^9.29.0" + "@hey-api/client-axios": "npm:^0.9.1" + "@hey-api/client-next": "npm:^0.5.1" + "@hey-api/openapi-ts": "npm:^0.80.1" "@ianvs/prettier-plugin-sort-imports": "npm:^4.4.2" "@mantine/core": "npm:8.1.2" "@mantine/form": "npm:^8.1.3" @@ -5966,7 +6098,6 @@ __metadata: lexorank: "npm:^1.0.5" libphonenumber-js: "npm:^1.12.10" next: "npm:15.3.3" - openapi-typescript-codegen: "npm:^0.29.0" postcss: "npm:^8.5.6" postcss-preset-mantine: "npm:1.17.0" postcss-simple-vars: "npm:^7.0.1" @@ -6229,6 +6360,23 @@ __metadata: languageName: node linkType: hard +"default-browser-id@npm:^5.0.0": + version: 5.0.0 + resolution: "default-browser-id@npm:5.0.0" + checksum: 10c0/957fb886502594c8e645e812dfe93dba30ed82e8460d20ce39c53c5b0f3e2afb6ceaec2249083b90bdfbb4cb0f34e1f73fde3d68cac00becdbcfd894156b5ead + languageName: node + linkType: hard + +"default-browser@npm:^5.2.1": + version: 5.2.1 + resolution: "default-browser@npm:5.2.1" + dependencies: + bundle-name: "npm:^4.1.0" + default-browser-id: "npm:^5.0.0" + checksum: 10c0/73f17dc3c58026c55bb5538749597db31f9561c0193cd98604144b704a981c95a466f8ecc3c2db63d8bfd04fb0d426904834cfc91ae510c6aeb97e13c5167c4d + languageName: node + linkType: hard + "define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4": version: 1.1.4 resolution: "define-data-property@npm:1.1.4" @@ -6247,6 +6395,13 @@ __metadata: languageName: node linkType: hard +"define-lazy-prop@npm:^3.0.0": + version: 3.0.0 + resolution: "define-lazy-prop@npm:3.0.0" + checksum: 10c0/5ab0b2bf3fa58b3a443140bbd4cd3db1f91b985cc8a246d330b9ac3fc0b6a325a6d82bddc0b055123d745b3f9931afeea74a5ec545439a1630b9c8512b0eeb49 + languageName: node + linkType: hard + "define-properties@npm:^1.1.3, define-properties@npm:^1.2.1": version: 1.2.1 resolution: "define-properties@npm:1.2.1" @@ -6258,6 +6413,13 @@ __metadata: languageName: node linkType: hard +"defu@npm:^6.1.4": + version: 6.1.4 + resolution: "defu@npm:6.1.4" + checksum: 10c0/2d6cc366262dc0cb8096e429368e44052fdf43ed48e53ad84cc7c9407f890301aa5fcb80d0995abaaf842b3949f154d060be4160f7a46cb2bc2f7726c81526f5 + languageName: node + linkType: hard + "delayed-stream@npm:~1.0.0": version: 1.0.0 resolution: "delayed-stream@npm:1.0.0" @@ -6282,6 +6444,13 @@ __metadata: languageName: node linkType: hard +"destr@npm:^2.0.3": + version: 2.0.5 + resolution: "destr@npm:2.0.5" + checksum: 10c0/efabffe7312a45ad90d79975376be958c50069f1156b94c181199763a7f971e113bd92227c26b94a169c71ca7dbc13583b7e96e5164743969fc79e1ff153e646 + languageName: node + linkType: hard + "detect-libc@npm:^2.0.3, detect-libc@npm:^2.0.4": version: 2.0.4 resolution: "detect-libc@npm:2.0.4" @@ -6443,6 +6612,13 @@ __metadata: languageName: node linkType: hard +"dotenv@npm:^16.4.5": + version: 16.6.1 + resolution: "dotenv@npm:16.6.1" + checksum: 10c0/15ce56608326ea0d1d9414a5c8ee6dcf0fffc79d2c16422b4ac2268e7e2d76ff5a572d37ffe747c377de12005f14b3cc22361e79fc7f1061cce81f77d2c973dc + languageName: node + linkType: hard + "dunder-proto@npm:^1.0.0, dunder-proto@npm:^1.0.1": version: 1.0.1 resolution: "dunder-proto@npm:1.0.1" @@ -7518,14 +7694,12 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^11.2.0": - version: 11.3.0 - resolution: "fs-extra@npm:11.3.0" +"fs-minipass@npm:^2.0.0": + version: 2.1.0 + resolution: "fs-minipass@npm:2.1.0" dependencies: - graceful-fs: "npm:^4.2.0" - jsonfile: "npm:^6.0.1" - universalify: "npm:^2.0.0" - checksum: 10c0/5f95e996186ff45463059feb115a22fb048bdaf7e487ecee8a8646c78ed8fdca63630e3077d4c16ce677051f5e60d3355a06f3cd61f3ca43f48cc58822a44d0a + minipass: "npm:^3.0.0" + checksum: 10c0/703d16522b8282d7299337539c3ed6edddd1afe82435e4f5b76e34a79cd74e488a8a0e26a636afc2440e1a23b03878e2122e3a2cfe375a5cf63c37d92b86a004 languageName: node linkType: hard @@ -7673,6 +7847,23 @@ __metadata: languageName: node linkType: hard +"giget@npm:^1.2.3": + version: 1.2.5 + resolution: "giget@npm:1.2.5" + dependencies: + citty: "npm:^0.1.6" + consola: "npm:^3.4.0" + defu: "npm:^6.1.4" + node-fetch-native: "npm:^1.6.6" + nypm: "npm:^0.5.4" + pathe: "npm:^2.0.3" + tar: "npm:^6.2.1" + bin: + giget: dist/cli.mjs + checksum: 10c0/0c541589b8a10274f5adb6cd34a568829939182f50b3d80f8bb891e974b889f0fc629a5d702920456037cc9c90fba84cf3860bad7a22a46bc51a5c55998f24a9 + languageName: node + linkType: hard + "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -7816,7 +8007,7 @@ __metadata: languageName: node linkType: hard -"handlebars@npm:^4.7.8": +"handlebars@npm:4.7.8": version: 4.7.8 resolution: "handlebars@npm:4.7.8" dependencies: @@ -8366,6 +8557,15 @@ __metadata: languageName: node linkType: hard +"is-docker@npm:^3.0.0": + version: 3.0.0 + resolution: "is-docker@npm:3.0.0" + bin: + is-docker: cli.js + checksum: 10c0/d2c4f8e6d3e34df75a5defd44991b6068afad4835bb783b902fa12d13ebdb8f41b2a199dcb0b5ed2cb78bfee9e4c0bbdb69c2d9646f4106464674d3e697a5856 + languageName: node + linkType: hard + "is-extglob@npm:^2.1.1": version: 2.1.1 resolution: "is-extglob@npm:2.1.1" @@ -8417,6 +8617,17 @@ __metadata: languageName: node linkType: hard +"is-inside-container@npm:^1.0.0": + version: 1.0.0 + resolution: "is-inside-container@npm:1.0.0" + dependencies: + is-docker: "npm:^3.0.0" + bin: + is-inside-container: cli.js + checksum: 10c0/a8efb0e84f6197e6ff5c64c52890fa9acb49b7b74fed4da7c95383965da6f0fa592b4dbd5e38a79f87fc108196937acdbcd758fcefc9b140e479b39ce1fcd1cd + languageName: node + linkType: hard + "is-map@npm:^2.0.3": version: 2.0.3 resolution: "is-map@npm:2.0.3" @@ -8572,6 +8783,15 @@ __metadata: languageName: node linkType: hard +"is-wsl@npm:^3.1.0": + version: 3.1.0 + resolution: "is-wsl@npm:3.1.0" + dependencies: + is-inside-container: "npm:^1.0.0" + checksum: 10c0/d3317c11995690a32c362100225e22ba793678fe8732660c6de511ae71a0ff05b06980cf21f98a6bf40d7be0e9e9506f859abe00a1118287d63e53d0a3d06947 + languageName: node + linkType: hard + "isarray@npm:^2.0.5": version: 2.0.5 resolution: "isarray@npm:2.0.5" @@ -9231,7 +9451,7 @@ __metadata: languageName: node linkType: hard -"jiti@npm:^2.4.2": +"jiti@npm:^2.3.0, jiti@npm:^2.4.2": version: 2.5.1 resolution: "jiti@npm:2.5.1" bin: @@ -10060,6 +10280,13 @@ __metadata: languageName: node linkType: hard +"minipass@npm:^5.0.0": + version: 5.0.0 + resolution: "minipass@npm:5.0.0" + checksum: 10c0/a91d8043f691796a8ac88df039da19933ef0f633e3d7f0d35dcd5373af49131cf2399bfc355f41515dc495e3990369c3858cd319e5c2722b4753c90bf3152462 + languageName: node + linkType: hard + "minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2": version: 7.1.2 resolution: "minipass@npm:7.1.2" @@ -10067,6 +10294,16 @@ __metadata: languageName: node linkType: hard +"minizlib@npm:^2.1.1": + version: 2.1.2 + resolution: "minizlib@npm:2.1.2" + dependencies: + minipass: "npm:^3.0.0" + yallist: "npm:^4.0.0" + checksum: 10c0/64fae024e1a7d0346a1102bb670085b17b7f95bf6cfdf5b128772ec8faf9ea211464ea4add406a3a6384a7d87a0cd1a96263692134323477b4fb43659a6cab78 + languageName: node + linkType: hard + "minizlib@npm:^3.0.1": version: 3.0.2 resolution: "minizlib@npm:3.0.2" @@ -10076,6 +10313,15 @@ __metadata: languageName: node linkType: hard +"mkdirp@npm:^1.0.3": + version: 1.0.4 + resolution: "mkdirp@npm:1.0.4" + bin: + mkdirp: bin/cmd.js + checksum: 10c0/46ea0f3ffa8bc6a5bc0c7081ffc3907777f0ed6516888d40a518c5111f8366d97d2678911ad1a6882bf592fa9de6c784fea32e1687bb94e1f4944170af48a5cf + languageName: node + linkType: hard + "mkdirp@npm:^3.0.1": version: 3.0.1 resolution: "mkdirp@npm:3.0.1" @@ -10085,6 +10331,18 @@ __metadata: languageName: node linkType: hard +"mlly@npm:^1.7.1, mlly@npm:^1.7.4": + version: 1.7.4 + resolution: "mlly@npm:1.7.4" + dependencies: + acorn: "npm:^8.14.0" + pathe: "npm:^2.0.1" + pkg-types: "npm:^1.3.0" + ufo: "npm:^1.5.4" + checksum: 10c0/69e738218a13d6365caf930e0ab4e2b848b84eec261597df9788cefb9930f3e40667be9cb58a4718834ba5f97a6efeef31d3b5a95f4388143fd4e0d0deff72ff + languageName: node + linkType: hard + "motion-dom@npm:^12.23.9": version: 12.23.9 resolution: "motion-dom@npm:12.23.9" @@ -10232,6 +10490,13 @@ __metadata: languageName: node linkType: hard +"node-fetch-native@npm:^1.6.6": + version: 1.6.7 + resolution: "node-fetch-native@npm:1.6.7" + checksum: 10c0/8b748300fb053d21ca4d3db9c3ff52593d5e8f8a2d9fe90cbfad159676e324b954fdaefab46aeca007b5b9edab3d150021c4846444e4e8ab1f4e44cd3807be87 + languageName: node + linkType: hard + "node-gyp@npm:latest": version: 11.2.0 resolution: "node-gyp@npm:11.2.0" @@ -10351,6 +10616,22 @@ __metadata: languageName: node linkType: hard +"nypm@npm:^0.5.4": + version: 0.5.4 + resolution: "nypm@npm:0.5.4" + dependencies: + citty: "npm:^0.1.6" + consola: "npm:^3.4.0" + pathe: "npm:^2.0.3" + pkg-types: "npm:^1.3.1" + tinyexec: "npm:^0.3.2" + ufo: "npm:^1.5.4" + bin: + nypm: dist/cli.mjs + checksum: 10c0/4b4661d2e460f4f8e96338669776dc3be4ed895bd34208ac188b5b8b438553aab737d41a5699cdc716f078fba9048b3d40b7d8a55c2544f9453536f837d323dc + languageName: node + linkType: hard + "object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" @@ -10439,6 +10720,13 @@ __metadata: languageName: node linkType: hard +"ohash@npm:^1.1.4": + version: 1.1.6 + resolution: "ohash@npm:1.1.6" + checksum: 10c0/3c25dde77662fffa3fa956b8975d7324311e3df15d9cf8d79b466ac3508f313e02b8ed3041d967810f68e00af344a5a3c4288be0208143c1844ba0f3cc83f777 + languageName: node + linkType: hard + "once@npm:^1.3.0": version: 1.4.0 resolution: "once@npm:1.4.0" @@ -10457,6 +10745,18 @@ __metadata: languageName: node linkType: hard +"open@npm:10.1.2": + version: 10.1.2 + resolution: "open@npm:10.1.2" + dependencies: + default-browser: "npm:^5.2.1" + define-lazy-prop: "npm:^3.0.0" + is-inside-container: "npm:^1.0.0" + is-wsl: "npm:^3.1.0" + checksum: 10c0/1bee796f06e549ce764f693272100323fbc04da8fa3c5b0402d6c2d11b3d76fa0aac0be7535e710015ff035326638e3b9a563f3b0e7ac3266473ed5663caae6d + languageName: node + linkType: hard + "open@npm:^8.0.4": version: 8.4.2 resolution: "open@npm:8.4.2" @@ -10468,21 +10768,6 @@ __metadata: languageName: node linkType: hard -"openapi-typescript-codegen@npm:^0.29.0": - version: 0.29.0 - resolution: "openapi-typescript-codegen@npm:0.29.0" - dependencies: - "@apidevtools/json-schema-ref-parser": "npm:^11.5.4" - camelcase: "npm:^6.3.0" - commander: "npm:^12.0.0" - fs-extra: "npm:^11.2.0" - handlebars: "npm:^4.7.8" - bin: - openapi: bin/index.js - checksum: 10c0/df4a7e6bb6e8044906249b1adfeaa46b3ed0bb887e782914195d9de579dbda9a3494356f4174517dd3cd2f93f58dce7b6b246ae54d06e0fad7f224a011e0aefb - languageName: node - linkType: hard - "opener@npm:^1.5.2": version: 1.5.2 resolution: "opener@npm:1.5.2" @@ -10729,6 +11014,20 @@ __metadata: languageName: node linkType: hard +"pathe@npm:^1.1.2": + version: 1.1.2 + resolution: "pathe@npm:1.1.2" + checksum: 10c0/64ee0a4e587fb0f208d9777a6c56e4f9050039268faaaaecd50e959ef01bf847b7872785c36483fa5cdcdbdfdb31fef2ff222684d4fc21c330ab60395c681897 + languageName: node + linkType: hard + +"pathe@npm:^2.0.1, pathe@npm:^2.0.3": + version: 2.0.3 + resolution: "pathe@npm:2.0.3" + checksum: 10c0/c118dc5a8b5c4166011b2b70608762e260085180bb9e33e80a50dcdb1e78c010b1624f4280c492c92b05fc276715a4c357d1f9edc570f8f1b3d90b6839ebaca1 + languageName: node + linkType: hard + "pathval@npm:^2.0.0": version: 2.0.1 resolution: "pathval@npm:2.0.1" @@ -10750,6 +11049,13 @@ __metadata: languageName: node linkType: hard +"perfect-debounce@npm:^1.0.0": + version: 1.0.0 + resolution: "perfect-debounce@npm:1.0.0" + checksum: 10c0/e2baac416cae046ef1b270812cf9ccfb0f91c04ea36ac7f5b00bc84cb7f41bdbba087c0ab21b4e02a7ef3a1f1f6db399f137cecec46868bd7d8d88c2a9ee431f + languageName: node + linkType: hard + "picocolors@npm:^1.0.0, picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" @@ -10796,6 +11102,17 @@ __metadata: languageName: node linkType: hard +"pkg-types@npm:^1.2.0, pkg-types@npm:^1.3.0, pkg-types@npm:^1.3.1": + version: 1.3.1 + resolution: "pkg-types@npm:1.3.1" + dependencies: + confbox: "npm:^0.1.8" + mlly: "npm:^1.7.4" + pathe: "npm:^2.0.1" + checksum: 10c0/19e6cb8b66dcc66c89f2344aecfa47f2431c988cfa3366bdfdcfb1dd6695f87dcce37fbd90fe9d1605e2f4440b77f391e83c23255347c35cf84e7fd774d7fcea + languageName: node + linkType: hard + "pnp-webpack-plugin@npm:^1.7.0": version: 1.7.0 resolution: "pnp-webpack-plugin@npm:1.7.0" @@ -11215,6 +11532,16 @@ __metadata: languageName: node linkType: hard +"rc9@npm:^2.1.2": + version: 2.1.2 + resolution: "rc9@npm:2.1.2" + dependencies: + defu: "npm:^6.1.4" + destr: "npm:^2.0.3" + checksum: 10c0/a2ead3b94bf033e35e4ea40d70062a09feddb8f589c3f5a8fe4e9342976974296aee9f6e9e72bd5e78e6ae4b7bc16dc244f63699fd7322c16314e3238db982c9 + languageName: node + linkType: hard + "react-docgen-typescript@npm:^2.2.2": version: 2.4.0 resolution: "react-docgen-typescript@npm:2.4.0" @@ -11447,6 +11774,13 @@ __metadata: languageName: node linkType: hard +"readdirp@npm:^4.0.1": + version: 4.1.2 + resolution: "readdirp@npm:4.1.2" + checksum: 10c0/60a14f7619dec48c9c850255cd523e2717001b0e179dc7037cfa0895da7b9e9ab07532d324bfb118d73a710887d1e35f79c495fa91582784493e085d18c72c62 + languageName: node + linkType: hard + "readdirp@npm:~3.6.0": version: 3.6.0 resolution: "readdirp@npm:3.6.0" @@ -11779,6 +12113,13 @@ __metadata: languageName: node linkType: hard +"run-applescript@npm:^7.0.0": + version: 7.0.0 + resolution: "run-applescript@npm:7.0.0" + checksum: 10c0/bd821bbf154b8e6c8ecffeaf0c33cebbb78eb2987476c3f6b420d67ab4c5301faa905dec99ded76ebb3a7042b4e440189ae6d85bbbd3fc6e8d493347ecda8bfe + languageName: node + linkType: hard + "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -11908,6 +12249,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:7.7.2, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.2, semver@npm:^7.6.3, semver@npm:^7.7.2": + version: 7.7.2 + resolution: "semver@npm:7.7.2" + bin: + semver: bin/semver.js + checksum: 10c0/aca305edfbf2383c22571cb7714f48cadc7ac95371b4b52362fb8eeffdfbc0de0669368b82b2b15978f8848f01d7114da65697e56cd8c37b0dab8c58e543f9ea + languageName: node + linkType: hard + "semver@npm:^6.0.0, semver@npm:^6.3.1": version: 6.3.1 resolution: "semver@npm:6.3.1" @@ -11917,15 +12267,6 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.2, semver@npm:^7.6.3, semver@npm:^7.7.2": - version: 7.7.2 - resolution: "semver@npm:7.7.2" - bin: - semver: bin/semver.js - checksum: 10c0/aca305edfbf2383c22571cb7714f48cadc7ac95371b4b52362fb8eeffdfbc0de0669368b82b2b15978f8848f01d7114da65697e56cd8c37b0dab8c58e543f9ea - languageName: node - linkType: hard - "serialize-javascript@npm:^6.0.2": version: 6.0.2 resolution: "serialize-javascript@npm:6.0.2" @@ -12891,6 +13232,20 @@ __metadata: languageName: node linkType: hard +"tar@npm:^6.2.1": + version: 6.2.1 + resolution: "tar@npm:6.2.1" + dependencies: + chownr: "npm:^2.0.0" + fs-minipass: "npm:^2.0.0" + minipass: "npm:^5.0.0" + minizlib: "npm:^2.1.1" + mkdirp: "npm:^1.0.3" + yallist: "npm:^4.0.0" + checksum: 10c0/a5eca3eb50bc11552d453488344e6507156b9193efd7635e98e867fab275d527af53d8866e2370cd09dfe74378a18111622ace35af6a608e5223a7d27fe99537 + languageName: node + linkType: hard + "tar@npm:^7.4.3": version: 7.4.3 resolution: "tar@npm:7.4.3" @@ -12968,6 +13323,13 @@ __metadata: languageName: node linkType: hard +"tinyexec@npm:^0.3.2": + version: 0.3.2 + resolution: "tinyexec@npm:0.3.2" + checksum: 10c0/3efbf791a911be0bf0821eab37a3445c2ba07acc1522b1fa84ae1e55f10425076f1290f680286345ed919549ad67527d07281f1c19d584df3b74326909eb1f90 + languageName: node + linkType: hard + "tinyglobby@npm:^0.2.12": version: 0.2.14 resolution: "tinyglobby@npm:0.2.14" @@ -13290,6 +13652,13 @@ __metadata: languageName: node linkType: hard +"ufo@npm:^1.5.4": + version: 1.6.1 + resolution: "ufo@npm:1.6.1" + checksum: 10c0/5a9f041e5945fba7c189d5410508cbcbefef80b253ed29aa2e1f8a2b86f4bd51af44ee18d4485e6d3468c92be9bf4a42e3a2b72dcaf27ce39ce947ec994f1e6b + languageName: node + linkType: hard + "uglify-js@npm:^3.1.4": version: 3.19.3 resolution: "uglify-js@npm:3.19.3"