Refactor auto-generated schemas and types formatting
Some checks failed
Build and Push Docker Images / changes (push) Successful in 5s
Build and Push Docker Images / build-backend (push) Has been skipped
Build and Push Docker Images / build-frontend (push) Failing after 42s

Updated the formatting for auto-generated schemas, types, and related files to adhere to consistent coding standards (e.g., double quotes, indentation). No functional changes were made, ensuring behavior remains identical.
This commit is contained in:
2025-03-05 10:13:33 +01:00
parent ffa3f2ffd3
commit c61ad52331
12 changed files with 1193 additions and 914 deletions

View File

@@ -1,16 +1,16 @@
import type { NextConfig } from "next"; import type { NextConfig } from "next";
const nextConfig: NextConfig = { const nextConfig: NextConfig = {
output: 'standalone', output: "standalone",
// Ensure we can connect to the backend in Docker // Ensure we can connect to the backend in Docker
async rewrites() { async rewrites() {
return [ return [
{ {
source: '/api/:path*', source: "/api/:path*",
destination: 'http://backend:8000/:path*', destination: "http://backend:8000/:path*",
}, },
]; ];
}, },
}; };
export default nextConfig; export default nextConfig;

View File

@@ -1,28 +1,27 @@
import {defineConfig} from '@hey-api/openapi-ts'; import { defineConfig } from "@hey-api/openapi-ts";
import path from "path"; import path from "path";
const API_URL = process.env.NEXT_PUBLIC_BACKEND_API_URL || 'http://localhost:8000'; const API_URL =
process.env.NEXT_PUBLIC_BACKEND_API_URL || "http://localhost:8000";
const OPENAPI_URL = `${API_URL}/api/v1/openapi.json`; const OPENAPI_URL = `${API_URL}/api/v1/openapi.json`;
const OUTPUT_DIR = path.resolve(__dirname, './src/client'); const OUTPUT_DIR = path.resolve(__dirname, "./src/client");
// const OPENAPI_FILE = path.resolve(__dirname, './openapi.json'); // const OPENAPI_FILE = path.resolve(__dirname, './openapi.json');
export default defineConfig({ export default defineConfig({
input: input: OPENAPI_URL,
OPENAPI_URL, output: {
output: { format: "prettier",
format: 'prettier', lint: "eslint",
lint: 'eslint', path: OUTPUT_DIR,
path: OUTPUT_DIR, },
plugins: [
"@hey-api/client-axios",
"@hey-api/schemas",
"@hey-api/sdk",
{
enums: "javascript",
name: "@hey-api/typescript",
}, },
plugins: [ "@tanstack/react-query",
'@hey-api/client-axios', ],
'@hey-api/schemas', });
'@hey-api/sdk',
{
enums: 'javascript',
name: '@hey-api/typescript',
},
'@tanstack/react-query',
],
});

View File

@@ -26,7 +26,10 @@
"@types/react-dom": "^19", "@types/react-dom": "^19",
"eslint": "^9", "eslint": "^9",
"eslint-config-next": "15.2.0", "eslint-config-next": "15.2.0",
"eslint-config-prettier": "^10.0.2",
"eslint-plugin-prettier": "^5.2.3",
"openapi-typescript-codegen": "^0.29.0", "openapi-typescript-codegen": "^0.29.0",
"prettier": "^3.5.3",
"tailwindcss": "^4", "tailwindcss": "^4",
"typescript": "^5" "typescript": "^5"
} }
@@ -890,6 +893,19 @@
"node": ">=12.4.0" "node": ">=12.4.0"
} }
}, },
"node_modules/@pkgr/core": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz",
"integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/unts"
}
},
"node_modules/@rtsao/scc": { "node_modules/@rtsao/scc": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
@@ -2594,6 +2610,19 @@
} }
} }
}, },
"node_modules/eslint-config-prettier": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.2.tgz",
"integrity": "sha512-1105/17ZIMjmCOJOPNfVdbXafLCLj3hPmkmB7dLgt7XsQ/zkxSuDerE/xgO3RxoHysR1N1whmquY0lSn2O0VLg==",
"dev": true,
"license": "MIT",
"bin": {
"eslint-config-prettier": "build/bin/cli.js"
},
"peerDependencies": {
"eslint": ">=7.0.0"
}
},
"node_modules/eslint-import-resolver-node": { "node_modules/eslint-import-resolver-node": {
"version": "0.3.9", "version": "0.3.9",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
@@ -2763,6 +2792,37 @@
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9"
} }
}, },
"node_modules/eslint-plugin-prettier": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz",
"integrity": "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==",
"dev": true,
"license": "MIT",
"dependencies": {
"prettier-linter-helpers": "^1.0.0",
"synckit": "^0.9.1"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint-plugin-prettier"
},
"peerDependencies": {
"@types/eslint": ">=8.0.0",
"eslint": ">=8.0.0",
"eslint-config-prettier": "*",
"prettier": ">=3.0.0"
},
"peerDependenciesMeta": {
"@types/eslint": {
"optional": true
},
"eslint-config-prettier": {
"optional": true
}
}
},
"node_modules/eslint-plugin-react": { "node_modules/eslint-plugin-react": {
"version": "7.37.4", "version": "7.37.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz",
@@ -2938,6 +2998,13 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-diff": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
"integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/fast-glob": { "node_modules/fast-glob": {
"version": "3.3.1", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
@@ -5032,6 +5099,35 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/prettier": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prettier-linter-helpers": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
"integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-diff": "^1.1.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/prop-types": { "node_modules/prop-types": {
"version": "15.8.1", "version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -5755,6 +5851,23 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/synckit": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz",
"integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@pkgr/core": "^0.1.0",
"tslib": "^2.6.2"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/unts"
}
},
"node_modules/tailwindcss": { "node_modules/tailwindcss": {
"version": "4.0.9", "version": "4.0.9",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.9.tgz", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.9.tgz",

View File

@@ -9,6 +9,7 @@
"lint": "next lint", "lint": "next lint",
"docker:build": "docker build -t eventspace-frontend .", "docker:build": "docker build -t eventspace-frontend .",
"docker:run": "docker run -p 3000:3000 eventspace-frontend", "docker:run": "docker run -p 3000:3000 eventspace-frontend",
"format": "prettier --write .",
"openapi-ts": "openapi-ts" "openapi-ts": "openapi-ts"
}, },
"dependencies": { "dependencies": {
@@ -30,7 +31,10 @@
"@types/react-dom": "^19", "@types/react-dom": "^19",
"eslint": "^9", "eslint": "^9",
"eslint-config-next": "15.2.0", "eslint-config-next": "15.2.0",
"eslint-config-prettier": "^10.0.2",
"eslint-plugin-prettier": "^5.2.3",
"openapi-typescript-codegen": "^0.29.0", "openapi-typescript-codegen": "^0.29.0",
"prettier": "^3.5.3",
"tailwindcss": "^4", "tailwindcss": "^4",
"typescript": "^5" "typescript": "^5"
} }

View File

@@ -1,227 +1,292 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
import { type Options, rootGet, register, login, loginOauth, refreshToken, changePassword, getCurrentUserInfo } from '../sdk.gen'; import {
import { queryOptions, type UseMutationOptions } from '@tanstack/react-query'; type Options,
import type { RootGetData, RegisterData, RegisterError, RegisterResponse, LoginData, LoginError, LoginResponse, LoginOauthData, LoginOauthError, LoginOauthResponse, RefreshTokenData, RefreshTokenError, RefreshTokenResponse, ChangePasswordData, ChangePasswordError, GetCurrentUserInfoData } from '../types.gen'; rootGet,
import type { AxiosError } from 'axios'; register,
import { client as _heyApiClient } from '../client.gen'; login,
loginOauth,
refreshToken,
changePassword,
getCurrentUserInfo,
} from "../sdk.gen";
import { queryOptions, type UseMutationOptions } from "@tanstack/react-query";
import type {
RootGetData,
RegisterData,
RegisterError,
RegisterResponse,
LoginData,
LoginError,
LoginResponse,
LoginOauthData,
LoginOauthError,
LoginOauthResponse,
RefreshTokenData,
RefreshTokenError,
RefreshTokenResponse,
ChangePasswordData,
ChangePasswordError,
GetCurrentUserInfoData,
} from "../types.gen";
import type { AxiosError } from "axios";
import { client as _heyApiClient } from "../client.gen";
export type QueryKey<TOptions extends Options> = [ export type QueryKey<TOptions extends Options> = [
Pick<TOptions, 'baseURL' | 'body' | 'headers' | 'path' | 'query'> & { Pick<TOptions, "baseURL" | "body" | "headers" | "path" | "query"> & {
_id: string; _id: string;
_infinite?: boolean; _infinite?: boolean;
} },
]; ];
const createQueryKey = <TOptions extends Options>(id: string, options?: TOptions, infinite?: boolean): [ const createQueryKey = <TOptions extends Options>(
QueryKey<TOptions>[0] id: string,
] => { options?: TOptions,
const params: QueryKey<TOptions>[0] = { _id: id, baseURL: (options?.client ?? _heyApiClient).getConfig().baseURL } as QueryKey<TOptions>[0]; infinite?: boolean,
if (infinite) { ): [QueryKey<TOptions>[0]] => {
params._infinite = infinite; const params: QueryKey<TOptions>[0] = {
} _id: id,
if (options?.body) { baseURL: (options?.client ?? _heyApiClient).getConfig().baseURL,
params.body = options.body; } as QueryKey<TOptions>[0];
} if (infinite) {
if (options?.headers) { params._infinite = infinite;
params.headers = options.headers; }
} if (options?.body) {
if (options?.path) { params.body = options.body;
params.path = options.path; }
} if (options?.headers) {
if (options?.query) { params.headers = options.headers;
params.query = options.query; }
} if (options?.path) {
return [ params.path = options.path;
params }
]; if (options?.query) {
params.query = options.query;
}
return [params];
}; };
export const rootGetQueryKey = (options?: Options<RootGetData>) => createQueryKey('rootGet', options); export const rootGetQueryKey = (options?: Options<RootGetData>) =>
createQueryKey("rootGet", options);
export const rootGetOptions = (options?: Options<RootGetData>) => { export const rootGetOptions = (options?: Options<RootGetData>) => {
return queryOptions({ return queryOptions({
queryFn: async ({ queryKey, signal }) => { queryFn: async ({ queryKey, signal }) => {
const { data } = await rootGet({ const { data } = await rootGet({
...options, ...options,
...queryKey[0], ...queryKey[0],
signal, signal,
throwOnError: true throwOnError: true,
}); });
return data; return data;
}, },
queryKey: rootGetQueryKey(options) queryKey: rootGetQueryKey(options),
}); });
}; };
export const registerQueryKey = (options: Options<RegisterData>) => createQueryKey('register', options); export const registerQueryKey = (options: Options<RegisterData>) =>
createQueryKey("register", options);
export const registerOptions = (options: Options<RegisterData>) => { export const registerOptions = (options: Options<RegisterData>) => {
return queryOptions({ return queryOptions({
queryFn: async ({ queryKey, signal }) => { queryFn: async ({ queryKey, signal }) => {
const { data } = await register({ const { data } = await register({
...options, ...options,
...queryKey[0], ...queryKey[0],
signal, signal,
throwOnError: true throwOnError: true,
}); });
return data; return data;
}, },
queryKey: registerQueryKey(options) queryKey: registerQueryKey(options),
}); });
}; };
export const registerMutation = (options?: Partial<Options<RegisterData>>) => { export const registerMutation = (options?: Partial<Options<RegisterData>>) => {
const mutationOptions: UseMutationOptions<RegisterResponse, AxiosError<RegisterError>, Options<RegisterData>> = { const mutationOptions: UseMutationOptions<
mutationFn: async (localOptions) => { RegisterResponse,
const { data } = await register({ AxiosError<RegisterError>,
...options, Options<RegisterData>
...localOptions, > = {
throwOnError: true mutationFn: async (localOptions) => {
}); const { data } = await register({
return data; ...options,
} ...localOptions,
}; throwOnError: true,
return mutationOptions; });
return data;
},
};
return mutationOptions;
}; };
export const loginQueryKey = (options: Options<LoginData>) => createQueryKey('login', options); export const loginQueryKey = (options: Options<LoginData>) =>
createQueryKey("login", options);
export const loginOptions = (options: Options<LoginData>) => { export const loginOptions = (options: Options<LoginData>) => {
return queryOptions({ return queryOptions({
queryFn: async ({ queryKey, signal }) => { queryFn: async ({ queryKey, signal }) => {
const { data } = await login({ const { data } = await login({
...options, ...options,
...queryKey[0], ...queryKey[0],
signal, signal,
throwOnError: true throwOnError: true,
}); });
return data; return data;
}, },
queryKey: loginQueryKey(options) queryKey: loginQueryKey(options),
}); });
}; };
export const loginMutation = (options?: Partial<Options<LoginData>>) => { export const loginMutation = (options?: Partial<Options<LoginData>>) => {
const mutationOptions: UseMutationOptions<LoginResponse, AxiosError<LoginError>, Options<LoginData>> = { const mutationOptions: UseMutationOptions<
mutationFn: async (localOptions) => { LoginResponse,
const { data } = await login({ AxiosError<LoginError>,
...options, Options<LoginData>
...localOptions, > = {
throwOnError: true mutationFn: async (localOptions) => {
}); const { data } = await login({
return data; ...options,
} ...localOptions,
}; throwOnError: true,
return mutationOptions; });
return data;
},
};
return mutationOptions;
}; };
export const loginOauthQueryKey = (options: Options<LoginOauthData>) => createQueryKey('loginOauth', options); export const loginOauthQueryKey = (options: Options<LoginOauthData>) =>
createQueryKey("loginOauth", options);
export const loginOauthOptions = (options: Options<LoginOauthData>) => { export const loginOauthOptions = (options: Options<LoginOauthData>) => {
return queryOptions({ return queryOptions({
queryFn: async ({ queryKey, signal }) => { queryFn: async ({ queryKey, signal }) => {
const { data } = await loginOauth({ const { data } = await loginOauth({
...options, ...options,
...queryKey[0], ...queryKey[0],
signal, signal,
throwOnError: true throwOnError: true,
}); });
return data; return data;
}, },
queryKey: loginOauthQueryKey(options) queryKey: loginOauthQueryKey(options),
}); });
}; };
export const loginOauthMutation = (options?: Partial<Options<LoginOauthData>>) => { export const loginOauthMutation = (
const mutationOptions: UseMutationOptions<LoginOauthResponse, AxiosError<LoginOauthError>, Options<LoginOauthData>> = { options?: Partial<Options<LoginOauthData>>,
mutationFn: async (localOptions) => { ) => {
const { data } = await loginOauth({ const mutationOptions: UseMutationOptions<
...options, LoginOauthResponse,
...localOptions, AxiosError<LoginOauthError>,
throwOnError: true Options<LoginOauthData>
}); > = {
return data; mutationFn: async (localOptions) => {
} const { data } = await loginOauth({
}; ...options,
return mutationOptions; ...localOptions,
throwOnError: true,
});
return data;
},
};
return mutationOptions;
}; };
export const refreshTokenQueryKey = (options: Options<RefreshTokenData>) => createQueryKey('refreshToken', options); export const refreshTokenQueryKey = (options: Options<RefreshTokenData>) =>
createQueryKey("refreshToken", options);
export const refreshTokenOptions = (options: Options<RefreshTokenData>) => { export const refreshTokenOptions = (options: Options<RefreshTokenData>) => {
return queryOptions({ return queryOptions({
queryFn: async ({ queryKey, signal }) => { queryFn: async ({ queryKey, signal }) => {
const { data } = await refreshToken({ const { data } = await refreshToken({
...options, ...options,
...queryKey[0], ...queryKey[0],
signal, signal,
throwOnError: true throwOnError: true,
}); });
return data; return data;
}, },
queryKey: refreshTokenQueryKey(options) queryKey: refreshTokenQueryKey(options),
}); });
}; };
export const refreshTokenMutation = (options?: Partial<Options<RefreshTokenData>>) => { export const refreshTokenMutation = (
const mutationOptions: UseMutationOptions<RefreshTokenResponse, AxiosError<RefreshTokenError>, Options<RefreshTokenData>> = { options?: Partial<Options<RefreshTokenData>>,
mutationFn: async (localOptions) => { ) => {
const { data } = await refreshToken({ const mutationOptions: UseMutationOptions<
...options, RefreshTokenResponse,
...localOptions, AxiosError<RefreshTokenError>,
throwOnError: true Options<RefreshTokenData>
}); > = {
return data; mutationFn: async (localOptions) => {
} const { data } = await refreshToken({
}; ...options,
return mutationOptions; ...localOptions,
throwOnError: true,
});
return data;
},
};
return mutationOptions;
}; };
export const changePasswordQueryKey = (options: Options<ChangePasswordData>) => createQueryKey('changePassword', options); export const changePasswordQueryKey = (options: Options<ChangePasswordData>) =>
createQueryKey("changePassword", options);
export const changePasswordOptions = (options: Options<ChangePasswordData>) => { export const changePasswordOptions = (options: Options<ChangePasswordData>) => {
return queryOptions({ return queryOptions({
queryFn: async ({ queryKey, signal }) => { queryFn: async ({ queryKey, signal }) => {
const { data } = await changePassword({ const { data } = await changePassword({
...options, ...options,
...queryKey[0], ...queryKey[0],
signal, signal,
throwOnError: true throwOnError: true,
}); });
return data; return data;
}, },
queryKey: changePasswordQueryKey(options) queryKey: changePasswordQueryKey(options),
}); });
}; };
export const changePasswordMutation = (options?: Partial<Options<ChangePasswordData>>) => { export const changePasswordMutation = (
const mutationOptions: UseMutationOptions<unknown, AxiosError<ChangePasswordError>, Options<ChangePasswordData>> = { options?: Partial<Options<ChangePasswordData>>,
mutationFn: async (localOptions) => { ) => {
const { data } = await changePassword({ const mutationOptions: UseMutationOptions<
...options, unknown,
...localOptions, AxiosError<ChangePasswordError>,
throwOnError: true Options<ChangePasswordData>
}); > = {
return data; mutationFn: async (localOptions) => {
} const { data } = await changePassword({
}; ...options,
return mutationOptions; ...localOptions,
throwOnError: true,
});
return data;
},
};
return mutationOptions;
}; };
export const getCurrentUserInfoQueryKey = (options?: Options<GetCurrentUserInfoData>) => createQueryKey('getCurrentUserInfo', options); export const getCurrentUserInfoQueryKey = (
options?: Options<GetCurrentUserInfoData>,
) => createQueryKey("getCurrentUserInfo", options);
export const getCurrentUserInfoOptions = (options?: Options<GetCurrentUserInfoData>) => { export const getCurrentUserInfoOptions = (
return queryOptions({ options?: Options<GetCurrentUserInfoData>,
queryFn: async ({ queryKey, signal }) => { ) => {
const { data } = await getCurrentUserInfo({ return queryOptions({
...options, queryFn: async ({ queryKey, signal }) => {
...queryKey[0], const { data } = await getCurrentUserInfo({
signal, ...options,
throwOnError: true ...queryKey[0],
}); signal,
return data; throwOnError: true,
}, });
queryKey: getCurrentUserInfoQueryKey(options) return data;
}); },
}; queryKey: getCurrentUserInfoQueryKey(options),
});
};

View File

@@ -1,7 +1,12 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
import type { ClientOptions } from './types.gen'; import type { ClientOptions } from "./types.gen";
import { type Config, type ClientOptions as DefaultClientOptions, createClient, createConfig } from '@hey-api/client-axios'; import {
type Config,
type ClientOptions as DefaultClientOptions,
createClient,
createConfig,
} from "@hey-api/client-axios";
/** /**
* The `createClientConfig()` function will be called on client initialization * The `createClientConfig()` function will be called on client initialization
@@ -11,8 +16,13 @@ import { type Config, type ClientOptions as DefaultClientOptions, createClient,
* `setConfig()`. This is useful for example if you're using Next.js * `setConfig()`. This is useful for example if you're using Next.js
* to ensure your client always has the correct values. * to ensure your client always has the correct values.
*/ */
export type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> = (override?: Config<DefaultClientOptions & T>) => Config<Required<DefaultClientOptions> & T>; export type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> =
(
override?: Config<DefaultClientOptions & T>,
) => Config<Required<DefaultClientOptions> & T>;
export const client = createClient(createConfig<ClientOptions>({ export const client = createClient(
baseURL: 'http://localhost:8000' createConfig<ClientOptions>({
})); baseURL: "http://localhost:8000",
}),
);

View File

@@ -1,3 +1,3 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
export * from './types.gen'; export * from "./types.gen";
export * from './sdk.gen'; export * from "./sdk.gen";

View File

@@ -1,290 +1,297 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
export const Body_change_passwordSchema = { export const Body_change_passwordSchema = {
properties: { properties: {
current_password: { current_password: {
type: 'string', type: "string",
title: 'Current Password' title: "Current Password",
},
new_password: {
type: 'string',
title: 'New Password'
}
}, },
type: 'object', new_password: {
required: ['current_password', 'new_password'], type: "string",
title: 'Body_change_password' title: "New Password",
},
},
type: "object",
required: ["current_password", "new_password"],
title: "Body_change_password",
} as const; } as const;
export const Body_login_oauthSchema = { export const Body_login_oauthSchema = {
properties: { properties: {
grant_type: { grant_type: {
anyOf: [ anyOf: [
{ {
type: 'string', type: "string",
pattern: '^password$' pattern: "^password$",
},
{
type: 'null'
}
],
title: 'Grant Type'
}, },
username: { {
type: 'string', type: "null",
title: 'Username'
}, },
password: { ],
type: 'string', title: "Grant Type",
title: 'Password'
},
scope: {
type: 'string',
title: 'Scope',
default: ''
},
client_id: {
anyOf: [
{
type: 'string'
},
{
type: 'null'
}
],
title: 'Client Id'
},
client_secret: {
anyOf: [
{
type: 'string'
},
{
type: 'null'
}
],
title: 'Client Secret'
}
}, },
type: 'object', username: {
required: ['username', 'password'], type: "string",
title: 'Body_login_oauth' title: "Username",
},
password: {
type: "string",
title: "Password",
},
scope: {
type: "string",
title: "Scope",
default: "",
},
client_id: {
anyOf: [
{
type: "string",
},
{
type: "null",
},
],
title: "Client Id",
},
client_secret: {
anyOf: [
{
type: "string",
},
{
type: "null",
},
],
title: "Client Secret",
},
},
type: "object",
required: ["username", "password"],
title: "Body_login_oauth",
} as const; } as const;
export const HTTPValidationErrorSchema = { export const HTTPValidationErrorSchema = {
properties: { properties: {
detail: { detail: {
items: { items: {
'$ref': '#/components/schemas/ValidationError' $ref: "#/components/schemas/ValidationError",
}, },
type: 'array', type: "array",
title: 'Detail' title: "Detail",
}
}, },
type: 'object', },
title: 'HTTPValidationError' type: "object",
title: "HTTPValidationError",
} as const; } as const;
export const LoginRequestSchema = { export const LoginRequestSchema = {
properties: { properties: {
email: { email: {
type: 'string', type: "string",
format: 'email', format: "email",
title: 'Email' title: "Email",
},
password: {
type: 'string',
title: 'Password'
}
}, },
type: 'object', password: {
required: ['email', 'password'], type: "string",
title: 'LoginRequest' title: "Password",
},
},
type: "object",
required: ["email", "password"],
title: "LoginRequest",
} as const; } as const;
export const RefreshTokenRequestSchema = { export const RefreshTokenRequestSchema = {
properties: { properties: {
refresh_token: { refresh_token: {
type: 'string', type: "string",
title: 'Refresh Token' title: "Refresh Token",
}
}, },
type: 'object', },
required: ['refresh_token'], type: "object",
title: 'RefreshTokenRequest' required: ["refresh_token"],
title: "RefreshTokenRequest",
} as const; } as const;
export const TokenSchema = { export const TokenSchema = {
properties: { properties: {
access_token: { access_token: {
type: 'string', type: "string",
title: 'Access Token' title: "Access Token",
},
refresh_token: {
anyOf: [
{
type: 'string'
},
{
type: 'null'
}
],
title: 'Refresh Token'
},
token_type: {
type: 'string',
title: 'Token Type',
default: 'bearer'
}
}, },
type: 'object', refresh_token: {
required: ['access_token'], anyOf: [
title: 'Token' {
type: "string",
},
{
type: "null",
},
],
title: "Refresh Token",
},
token_type: {
type: "string",
title: "Token Type",
default: "bearer",
},
},
type: "object",
required: ["access_token"],
title: "Token",
} as const; } as const;
export const UserCreateSchema = { export const UserCreateSchema = {
properties: { properties: {
email: { email: {
type: 'string', type: "string",
format: 'email', format: "email",
title: 'Email' title: "Email",
},
first_name: {
type: 'string',
title: 'First Name'
},
last_name: {
anyOf: [
{
type: 'string'
},
{
type: 'null'
}
],
title: 'Last Name'
},
phone_number: {
anyOf: [
{
type: 'string'
},
{
type: 'null'
}
],
title: 'Phone Number'
},
password: {
type: 'string',
title: 'Password'
},
is_superuser: {
type: 'boolean',
title: 'Is Superuser',
default: false
}
}, },
type: 'object', first_name: {
required: ['email', 'first_name', 'password'], type: "string",
title: 'UserCreate' title: "First Name",
},
last_name: {
anyOf: [
{
type: "string",
},
{
type: "null",
},
],
title: "Last Name",
},
phone_number: {
anyOf: [
{
type: "string",
},
{
type: "null",
},
],
title: "Phone Number",
},
password: {
type: "string",
title: "Password",
},
is_superuser: {
type: "boolean",
title: "Is Superuser",
default: false,
},
},
type: "object",
required: ["email", "first_name", "password"],
title: "UserCreate",
} as const; } as const;
export const UserResponseSchema = { export const UserResponseSchema = {
properties: { properties: {
email: { email: {
type: 'string', type: "string",
format: 'email', format: "email",
title: 'Email' title: "Email",
},
first_name: {
type: 'string',
title: 'First Name'
},
last_name: {
anyOf: [
{
type: 'string'
},
{
type: 'null'
}
],
title: 'Last Name'
},
phone_number: {
anyOf: [
{
type: 'string'
},
{
type: 'null'
}
],
title: 'Phone Number'
},
id: {
type: 'string',
format: 'uuid',
title: 'Id'
},
is_active: {
type: 'boolean',
title: 'Is Active'
},
is_superuser: {
type: 'boolean',
title: 'Is Superuser'
},
created_at: {
type: 'string',
format: 'date-time',
title: 'Created At'
},
updated_at: {
anyOf: [
{
type: 'string',
format: 'date-time'
},
{
type: 'null'
}
],
title: 'Updated At'
}
}, },
type: 'object', first_name: {
required: ['email', 'first_name', 'id', 'is_active', 'is_superuser', 'created_at'], type: "string",
title: 'UserResponse' title: "First Name",
},
last_name: {
anyOf: [
{
type: "string",
},
{
type: "null",
},
],
title: "Last Name",
},
phone_number: {
anyOf: [
{
type: "string",
},
{
type: "null",
},
],
title: "Phone Number",
},
id: {
type: "string",
format: "uuid",
title: "Id",
},
is_active: {
type: "boolean",
title: "Is Active",
},
is_superuser: {
type: "boolean",
title: "Is Superuser",
},
created_at: {
type: "string",
format: "date-time",
title: "Created At",
},
updated_at: {
anyOf: [
{
type: "string",
format: "date-time",
},
{
type: "null",
},
],
title: "Updated At",
},
},
type: "object",
required: [
"email",
"first_name",
"id",
"is_active",
"is_superuser",
"created_at",
],
title: "UserResponse",
} as const; } as const;
export const ValidationErrorSchema = { export const ValidationErrorSchema = {
properties: { properties: {
loc: { loc: {
items: { items: {
anyOf: [ anyOf: [
{ {
type: 'string' type: "string",
}, },
{ {
type: 'integer' type: "integer",
} },
] ],
}, },
type: 'array', type: "array",
title: 'Location' title: "Location",
},
msg: {
type: 'string',
title: 'Message'
},
type: {
type: 'string',
title: 'Error Type'
}
}, },
type: 'object', msg: {
required: ['loc', 'msg', 'type'], type: "string",
title: 'ValidationError' title: "Message",
} as const; },
type: {
type: "string",
title: "Error Type",
},
},
type: "object",
required: ["loc", "msg", "type"],
title: "ValidationError",
} as const;

View File

@@ -1,32 +1,65 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
import { type Options as ClientOptions, type TDataShape, type Client, urlSearchParamsBodySerializer } from '@hey-api/client-axios'; import {
import type { RootGetData, RootGetResponse, RegisterData, RegisterResponse, RegisterError, LoginData, LoginResponse, LoginError, LoginOauthData, LoginOauthResponse, LoginOauthError, RefreshTokenData, RefreshTokenResponse, RefreshTokenError, ChangePasswordData, ChangePasswordError, GetCurrentUserInfoData, GetCurrentUserInfoResponse } from './types.gen'; type Options as ClientOptions,
import { client as _heyApiClient } from './client.gen'; type TDataShape,
type Client,
urlSearchParamsBodySerializer,
} from "@hey-api/client-axios";
import type {
RootGetData,
RootGetResponse,
RegisterData,
RegisterResponse,
RegisterError,
LoginData,
LoginResponse,
LoginError,
LoginOauthData,
LoginOauthResponse,
LoginOauthError,
RefreshTokenData,
RefreshTokenResponse,
RefreshTokenError,
ChangePasswordData,
ChangePasswordError,
GetCurrentUserInfoData,
GetCurrentUserInfoResponse,
} from "./types.gen";
import { client as _heyApiClient } from "./client.gen";
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & { export type Options<
/** TData extends TDataShape = TDataShape,
* You can provide a client instance returned by `createClient()` instead of ThrowOnError extends boolean = boolean,
* individual options. This might be also useful if you want to implement a > = ClientOptions<TData, ThrowOnError> & {
* custom client. /**
*/ * You can provide a client instance returned by `createClient()` instead of
client?: Client; * individual options. This might be also useful if you want to implement a
/** * custom 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. client?: Client;
*/ /**
meta?: Record<string, unknown>; * 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<string, unknown>;
}; };
/** /**
* Root * Root
*/ */
export const rootGet = <ThrowOnError extends boolean = false>(options?: Options<RootGetData, ThrowOnError>) => { export const rootGet = <ThrowOnError extends boolean = false>(
return (options?.client ?? _heyApiClient).get<RootGetResponse, unknown, ThrowOnError>({ options?: Options<RootGetData, ThrowOnError>,
responseType: 'text', ) => {
url: '/', return (options?.client ?? _heyApiClient).get<
...options RootGetResponse,
}); unknown,
ThrowOnError
>({
responseType: "text",
url: "/",
...options,
});
}; };
/** /**
@@ -36,15 +69,21 @@ export const rootGet = <ThrowOnError extends boolean = false>(options?: Options<
* Returns: * Returns:
* The created user information. * The created user information.
*/ */
export const register = <ThrowOnError extends boolean = false>(options: Options<RegisterData, ThrowOnError>) => { export const register = <ThrowOnError extends boolean = false>(
return (options.client ?? _heyApiClient).post<RegisterResponse, RegisterError, ThrowOnError>({ options: Options<RegisterData, ThrowOnError>,
url: '/api/v1/auth/register', ) => {
...options, return (options.client ?? _heyApiClient).post<
headers: { RegisterResponse,
'Content-Type': 'application/json', RegisterError,
...options?.headers ThrowOnError
} >({
}); url: "/api/v1/auth/register",
...options,
headers: {
"Content-Type": "application/json",
...options?.headers,
},
});
}; };
/** /**
@@ -54,15 +93,21 @@ export const register = <ThrowOnError extends boolean = false>(options: Options<
* Returns: * Returns:
* Access and refresh tokens. * Access and refresh tokens.
*/ */
export const login = <ThrowOnError extends boolean = false>(options: Options<LoginData, ThrowOnError>) => { export const login = <ThrowOnError extends boolean = false>(
return (options.client ?? _heyApiClient).post<LoginResponse, LoginError, ThrowOnError>({ options: Options<LoginData, ThrowOnError>,
url: '/api/v1/auth/login', ) => {
...options, return (options.client ?? _heyApiClient).post<
headers: { LoginResponse,
'Content-Type': 'application/json', LoginError,
...options?.headers ThrowOnError
} >({
}); url: "/api/v1/auth/login",
...options,
headers: {
"Content-Type": "application/json",
...options?.headers,
},
});
}; };
/** /**
@@ -72,16 +117,22 @@ export const login = <ThrowOnError extends boolean = false>(options: Options<Log
* Returns: * Returns:
* Access and refresh tokens. * Access and refresh tokens.
*/ */
export const loginOauth = <ThrowOnError extends boolean = false>(options: Options<LoginOauthData, ThrowOnError>) => { export const loginOauth = <ThrowOnError extends boolean = false>(
return (options.client ?? _heyApiClient).post<LoginOauthResponse, LoginOauthError, ThrowOnError>({ options: Options<LoginOauthData, ThrowOnError>,
...urlSearchParamsBodySerializer, ) => {
url: '/api/v1/auth/login/oauth', return (options.client ?? _heyApiClient).post<
...options, LoginOauthResponse,
headers: { LoginOauthError,
'Content-Type': 'application/x-www-form-urlencoded', ThrowOnError
...options?.headers >({
} ...urlSearchParamsBodySerializer,
}); url: "/api/v1/auth/login/oauth",
...options,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
...options?.headers,
},
});
}; };
/** /**
@@ -91,15 +142,21 @@ export const loginOauth = <ThrowOnError extends boolean = false>(options: Option
* Returns: * Returns:
* New access and refresh tokens. * New access and refresh tokens.
*/ */
export const refreshToken = <ThrowOnError extends boolean = false>(options: Options<RefreshTokenData, ThrowOnError>) => { export const refreshToken = <ThrowOnError extends boolean = false>(
return (options.client ?? _heyApiClient).post<RefreshTokenResponse, RefreshTokenError, ThrowOnError>({ options: Options<RefreshTokenData, ThrowOnError>,
url: '/api/v1/auth/refresh', ) => {
...options, return (options.client ?? _heyApiClient).post<
headers: { RefreshTokenResponse,
'Content-Type': 'application/json', RefreshTokenError,
...options?.headers ThrowOnError
} >({
}); url: "/api/v1/auth/refresh",
...options,
headers: {
"Content-Type": "application/json",
...options?.headers,
},
});
}; };
/** /**
@@ -108,21 +165,27 @@ export const refreshToken = <ThrowOnError extends boolean = false>(options: Opti
* *
* Requires authentication. * Requires authentication.
*/ */
export const changePassword = <ThrowOnError extends boolean = false>(options: Options<ChangePasswordData, ThrowOnError>) => { export const changePassword = <ThrowOnError extends boolean = false>(
return (options.client ?? _heyApiClient).post<unknown, ChangePasswordError, ThrowOnError>({ options: Options<ChangePasswordData, ThrowOnError>,
security: [ ) => {
{ return (options.client ?? _heyApiClient).post<
scheme: 'bearer', unknown,
type: 'http' ChangePasswordError,
} ThrowOnError
], >({
url: '/api/v1/auth/change-password', security: [
...options, {
headers: { scheme: "bearer",
'Content-Type': 'application/json', type: "http",
...options?.headers },
} ],
}); url: "/api/v1/auth/change-password",
...options,
headers: {
"Content-Type": "application/json",
...options?.headers,
},
});
}; };
/** /**
@@ -131,15 +194,21 @@ export const changePassword = <ThrowOnError extends boolean = false>(options: Op
* *
* Requires authentication. * Requires authentication.
*/ */
export const getCurrentUserInfo = <ThrowOnError extends boolean = false>(options?: Options<GetCurrentUserInfoData, ThrowOnError>) => { export const getCurrentUserInfo = <ThrowOnError extends boolean = false>(
return (options?.client ?? _heyApiClient).get<GetCurrentUserInfoResponse, unknown, ThrowOnError>({ options?: Options<GetCurrentUserInfoData, ThrowOnError>,
security: [ ) => {
{ return (options?.client ?? _heyApiClient).get<
scheme: 'bearer', GetCurrentUserInfoResponse,
type: 'http' unknown,
} ThrowOnError
], >({
url: '/api/v1/auth/me', security: [
...options {
}); scheme: "bearer",
}; type: "http",
},
],
url: "/api/v1/auth/me",
...options,
});
};

View File

@@ -1,220 +1,223 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
export type BodyChangePassword = { export type BodyChangePassword = {
current_password: string; current_password: string;
new_password: string; new_password: string;
}; };
export type BodyLoginOauth = { export type BodyLoginOauth = {
grant_type?: string | null; grant_type?: string | null;
username: string; username: string;
password: string; password: string;
scope?: string; scope?: string;
client_id?: string | null; client_id?: string | null;
client_secret?: string | null; client_secret?: string | null;
}; };
export type HttpValidationError = { export type HttpValidationError = {
detail?: Array<ValidationError>; detail?: Array<ValidationError>;
}; };
export type LoginRequest = { export type LoginRequest = {
email: string; email: string;
password: string; password: string;
}; };
export type RefreshTokenRequest = { export type RefreshTokenRequest = {
refresh_token: string; refresh_token: string;
}; };
export type Token = { export type Token = {
access_token: string; access_token: string;
refresh_token?: string | null; refresh_token?: string | null;
token_type?: string; token_type?: string;
}; };
export type UserCreate = { export type UserCreate = {
email: string; email: string;
first_name: string; first_name: string;
last_name?: string | null; last_name?: string | null;
phone_number?: string | null; phone_number?: string | null;
password: string; password: string;
is_superuser?: boolean; is_superuser?: boolean;
}; };
export type UserResponse = { export type UserResponse = {
email: string; email: string;
first_name: string; first_name: string;
last_name?: string | null; last_name?: string | null;
phone_number?: string | null; phone_number?: string | null;
id: string; id: string;
is_active: boolean; is_active: boolean;
is_superuser: boolean; is_superuser: boolean;
created_at: string; created_at: string;
updated_at?: string | null; updated_at?: string | null;
}; };
export type ValidationError = { export type ValidationError = {
loc: Array<string | number>; loc: Array<string | number>;
msg: string; msg: string;
type: string; type: string;
}; };
export type RootGetData = { export type RootGetData = {
body?: never; body?: never;
path?: never; path?: never;
query?: never; query?: never;
url: '/'; url: "/";
}; };
export type RootGetResponses = { export type RootGetResponses = {
/** /**
* Successful Response * Successful Response
*/ */
200: string; 200: string;
}; };
export type RootGetResponse = RootGetResponses[keyof RootGetResponses]; export type RootGetResponse = RootGetResponses[keyof RootGetResponses];
export type RegisterData = { export type RegisterData = {
body: UserCreate; body: UserCreate;
path?: never; path?: never;
query?: never; query?: never;
url: '/api/v1/auth/register'; url: "/api/v1/auth/register";
}; };
export type RegisterErrors = { export type RegisterErrors = {
/** /**
* Validation Error * Validation Error
*/ */
422: HttpValidationError; 422: HttpValidationError;
}; };
export type RegisterError = RegisterErrors[keyof RegisterErrors]; export type RegisterError = RegisterErrors[keyof RegisterErrors];
export type RegisterResponses = { export type RegisterResponses = {
/** /**
* Successful Response * Successful Response
*/ */
201: UserResponse; 201: UserResponse;
}; };
export type RegisterResponse = RegisterResponses[keyof RegisterResponses]; export type RegisterResponse = RegisterResponses[keyof RegisterResponses];
export type LoginData = { export type LoginData = {
body: LoginRequest; body: LoginRequest;
path?: never; path?: never;
query?: never; query?: never;
url: '/api/v1/auth/login'; url: "/api/v1/auth/login";
}; };
export type LoginErrors = { export type LoginErrors = {
/** /**
* Validation Error * Validation Error
*/ */
422: HttpValidationError; 422: HttpValidationError;
}; };
export type LoginError = LoginErrors[keyof LoginErrors]; export type LoginError = LoginErrors[keyof LoginErrors];
export type LoginResponses = { export type LoginResponses = {
/** /**
* Successful Response * Successful Response
*/ */
200: Token; 200: Token;
}; };
export type LoginResponse = LoginResponses[keyof LoginResponses]; export type LoginResponse = LoginResponses[keyof LoginResponses];
export type LoginOauthData = { export type LoginOauthData = {
body: BodyLoginOauth; body: BodyLoginOauth;
path?: never; path?: never;
query?: never; query?: never;
url: '/api/v1/auth/login/oauth'; url: "/api/v1/auth/login/oauth";
}; };
export type LoginOauthErrors = { export type LoginOauthErrors = {
/** /**
* Validation Error * Validation Error
*/ */
422: HttpValidationError; 422: HttpValidationError;
}; };
export type LoginOauthError = LoginOauthErrors[keyof LoginOauthErrors]; export type LoginOauthError = LoginOauthErrors[keyof LoginOauthErrors];
export type LoginOauthResponses = { export type LoginOauthResponses = {
/** /**
* Successful Response * Successful Response
*/ */
200: Token; 200: Token;
}; };
export type LoginOauthResponse = LoginOauthResponses[keyof LoginOauthResponses]; export type LoginOauthResponse = LoginOauthResponses[keyof LoginOauthResponses];
export type RefreshTokenData = { export type RefreshTokenData = {
body: RefreshTokenRequest; body: RefreshTokenRequest;
path?: never; path?: never;
query?: never; query?: never;
url: '/api/v1/auth/refresh'; url: "/api/v1/auth/refresh";
}; };
export type RefreshTokenErrors = { export type RefreshTokenErrors = {
/** /**
* Validation Error * Validation Error
*/ */
422: HttpValidationError; 422: HttpValidationError;
}; };
export type RefreshTokenError = RefreshTokenErrors[keyof RefreshTokenErrors]; export type RefreshTokenError = RefreshTokenErrors[keyof RefreshTokenErrors];
export type RefreshTokenResponses = { export type RefreshTokenResponses = {
/** /**
* Successful Response * Successful Response
*/ */
200: Token; 200: Token;
}; };
export type RefreshTokenResponse = RefreshTokenResponses[keyof RefreshTokenResponses]; export type RefreshTokenResponse =
RefreshTokenResponses[keyof RefreshTokenResponses];
export type ChangePasswordData = { export type ChangePasswordData = {
body: BodyChangePassword; body: BodyChangePassword;
path?: never; path?: never;
query?: never; query?: never;
url: '/api/v1/auth/change-password'; url: "/api/v1/auth/change-password";
}; };
export type ChangePasswordErrors = { export type ChangePasswordErrors = {
/** /**
* Validation Error * Validation Error
*/ */
422: HttpValidationError; 422: HttpValidationError;
}; };
export type ChangePasswordError = ChangePasswordErrors[keyof ChangePasswordErrors]; export type ChangePasswordError =
ChangePasswordErrors[keyof ChangePasswordErrors];
export type ChangePasswordResponses = { export type ChangePasswordResponses = {
/** /**
* Successful Response * Successful Response
*/ */
200: unknown; 200: unknown;
}; };
export type GetCurrentUserInfoData = { export type GetCurrentUserInfoData = {
body?: never; body?: never;
path?: never; path?: never;
query?: never; query?: never;
url: '/api/v1/auth/me'; url: "/api/v1/auth/me";
}; };
export type GetCurrentUserInfoResponses = { export type GetCurrentUserInfoResponses = {
/** /**
* Successful Response * Successful Response
*/ */
200: UserResponse; 200: UserResponse;
}; };
export type GetCurrentUserInfoResponse = GetCurrentUserInfoResponses[keyof GetCurrentUserInfoResponses]; export type GetCurrentUserInfoResponse =
GetCurrentUserInfoResponses[keyof GetCurrentUserInfoResponses];
export type ClientOptions = { export type ClientOptions = {
baseURL: 'http://localhost:8000' | (string & {}); baseURL: "http://localhost:8000" | (string & {});
}; };

View File

@@ -1,45 +1,53 @@
'use client'; "use client";
import React, {createContext, useContext, useState, useEffect, ReactNode, useCallback, useMemo} from 'react'; import React, {
import {useRouter, usePathname} from 'next/navigation'; createContext,
import {jwtDecode} from 'jwt-decode'; ReactNode,
import {client} from '@/client/client.gen'; useCallback,
import {useMutation, useQueryClient, useQuery, type UseQueryOptions} from '@tanstack/react-query'; useContext,
import {loginMutation, getCurrentUserInfoOptions} from '@/client/@tanstack/react-query.gen'; useEffect,
import {LoginRequest, UserResponse, Token} from '@/client/types.gen'; useMemo,
useState,
} from "react";
import { usePathname, useRouter } from "next/navigation";
import { jwtDecode } from "jwt-decode";
import { client } from "@/client/client.gen";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
getCurrentUserInfoOptions,
loginMutation,
} from "@/client/@tanstack/react-query.gen";
import { LoginRequest, Token, UserResponse } from "@/client/types.gen";
// JWT token payload interface // JWT token payload interface
interface TokenPayload { interface TokenPayload {
sub: string; sub: string;
exp: number; exp: number;
role?: string; role?: string;
[key: string]: any; [key: string]: any;
} }
// Auth context state interface // Auth context state interface
interface AuthContextState { interface AuthContextState {
user: UserResponse | null; user: UserResponse | null;
isAuthenticated: boolean; isAuthenticated: boolean;
isLoading: boolean; isLoading: boolean;
error: Error | null; error: Error | null;
login: (credentials: LoginRequest) => Promise<void>; login: (credentials: LoginRequest) => Promise<void>;
logout: () => void; logout: () => void;
refreshToken: () => Promise<void>; refreshToken: () => Promise<void>;
} }
// Default context state // Default context state
const defaultAuthState: AuthContextState = { const defaultAuthState: AuthContextState = {
user: null, user: null,
isAuthenticated: false, isAuthenticated: false,
isLoading: true, isLoading: true,
error: null, error: null,
login: async () => { login: async () => {},
}, logout: () => {},
logout: () => { refreshToken: async () => {},
},
refreshToken: async () => {
},
}; };
// Create context // Create context
@@ -47,255 +55,256 @@ const AuthContext = createContext<AuthContextState>(defaultAuthState);
// Custom hook to use the auth context // Custom hook to use the auth context
export const useAuth = () => { export const useAuth = () => {
const context = useContext(AuthContext); const context = useContext(AuthContext);
if (!context) { if (!context) {
throw new Error('useAuth must be used within an AuthProvider'); throw new Error("useAuth must be used within an AuthProvider");
} }
return context; return context;
}; };
// Token management // Token management
const TOKEN_KEY = 'accessToken'; const TOKEN_KEY = "accessToken";
const REFRESH_TOKEN_KEY = 'refreshToken'; const REFRESH_TOKEN_KEY = "refreshToken";
// Get token from storage // Get token from storage
const getStoredToken = (): string | null => { const getStoredToken = (): string | null => {
if (typeof window === 'undefined') return null; if (typeof window === "undefined") return null;
return localStorage.getItem(TOKEN_KEY); return localStorage.getItem(TOKEN_KEY);
}; };
// Store token in storage // Store token in storage
const storeToken = (token: string | null, refreshToken: string | null = null): void => { const storeToken = (
if (typeof window === 'undefined') return; token: string | null,
refreshToken: string | null = null,
): void => {
if (typeof window === "undefined") return;
if (token) { if (token) {
localStorage.setItem(TOKEN_KEY, token); localStorage.setItem(TOKEN_KEY, token);
if (refreshToken) { if (refreshToken) {
localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken); localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken);
}
} else {
localStorage.removeItem(TOKEN_KEY);
localStorage.removeItem(REFRESH_TOKEN_KEY);
} }
} else {
localStorage.removeItem(TOKEN_KEY);
localStorage.removeItem(REFRESH_TOKEN_KEY);
}
}; };
// Check if token is expired // Check if token is expired
const isTokenExpired = (token: string): boolean => { const isTokenExpired = (token: string): boolean => {
try { try {
const decoded = jwtDecode<TokenPayload>(token); const decoded = jwtDecode<TokenPayload>(token);
const currentTime = Date.now() / 1000; const currentTime = Date.now() / 1000;
// Add a buffer of 10 seconds to prevent edge cases // Add a buffer of 10 seconds to prevent edge cases
return decoded.exp < currentTime - 10; return decoded.exp < currentTime - 10;
} catch (error) { } catch (error) {
return true; return true;
} }
}; };
// Auth Provider Props // Auth Provider Props
interface AuthProviderProps { interface AuthProviderProps {
children: ReactNode; children: ReactNode;
} }
// Auth Provider Component // Auth Provider Component
export const AuthProvider: React.FC<AuthProviderProps> = ({children}: AuthProviderProps) => { export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
const [isInitializing, setIsInitializing] = useState(true); const [isInitializing, setIsInitializing] = useState(true);
const router = useRouter(); const router = useRouter();
const pathname = usePathname(); const pathname = usePathname();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
// Set up login mutation // Set up login mutation
const loginMutationHook = useMutation(loginMutation()); const loginMutationHook = useMutation(loginMutation());
// Configure API client with token if available // Configure API client with token if available
useEffect(() => { useEffect(() => {
const token = getStoredToken(); const token = getStoredToken();
if (token) { if (token) {
client.setConfig({ client.setConfig({
headers: { headers: {
Authorization: `Bearer ${token}` Authorization: `Bearer ${token}`,
} },
}); });
} }
}, []); }, []);
const hasValidToken = useCallback((): boolean => { // Check if current token is valid (not expired)
const token = getStoredToken(); const hasValidToken = useCallback((): boolean => {
return Boolean(token && !isTokenExpired(token)); const token = getStoredToken();
}, []); return Boolean(token && !isTokenExpired(token));
}, []);
// Create query options // Create query options
const userQueryOptions = { const userQueryOptions = {
...getCurrentUserInfoOptions(), ...getCurrentUserInfoOptions(),
enabled: hasValidToken(), enabled: hasValidToken(),
retry: false, retry: false,
staleTime: 5 * 60 * 1000, // 5 minutes staleTime: 5 * 60 * 1000, // 5 minutes
} as UseQueryOptions; };
// Use the query without onError in the options // Use the query without onError in the options
const {data: user, isLoading, error, refetch} = useQuery(userQueryOptions); const { data: user, isLoading, error, refetch } = useQuery(userQueryOptions);
// Handle error with a separate effect // Handle error with a separate effect
useEffect(() => { useEffect(() => {
if (error) { if (error) {
// Clear tokens on error (unauthorized) // Clear tokens on error (unauthorized)
storeToken(null); storeToken(null);
} }
}, [error]); }, [error]);
// Login function // Login function
const login = useCallback(async (credentials: LoginRequest): Promise<void> => { const login = useCallback(
try { async (credentials: LoginRequest): Promise<void> => {
const response = await loginMutationHook.mutateAsync({ try {
body: credentials const response = await loginMutationHook.mutateAsync({
}); body: credentials,
});
// Store tokens // Store tokens
storeToken(response.access_token, response.refresh_token || null); storeToken(response.access_token, response.refresh_token || null);
// Configure client with new token // Configure client with new token
client.setConfig({
headers: {
Authorization: `Bearer ${response.access_token}`
}
});
// Trigger user data fetch
await refetch();
// Redirect after login
if (pathname === '/login') {
router.push('/dashboard');
}
} catch (error) {
console.error('Login failed:', error);
throw error;
}
}, [loginMutationHook, refetch, router, pathname]);
// Logout function
const logout = useCallback((): void => {
// Clear tokens
storeToken(null);
// Remove auth headers
client.setConfig({ client.setConfig({
headers: { headers: {
Authorization: undefined Authorization: `Bearer ${response.access_token}`,
} },
}); });
// Clear user from cache // Trigger user data fetch
queryClient.invalidateQueries({ await refetch();
queryKey: getCurrentUserInfoOptions().queryKey
// Redirect after login
if (pathname === "/login") {
router.push("/dashboard");
}
} catch (error) {
console.error("Login failed:", error);
throw error;
}
},
[loginMutationHook, refetch, router, pathname],
);
// Logout function
const logout = useCallback((): void => {
// Clear tokens
storeToken(null);
// Remove auth headers
client.setConfig({
headers: {
Authorization: undefined,
},
});
// Clear user from cache
queryClient.invalidateQueries({
queryKey: getCurrentUserInfoOptions().queryKey,
});
// Redirect to login page
router.push("/login");
}, [router, queryClient]);
// Refresh token function
const refreshToken = useCallback(async (): Promise<void> => {
const refreshTokenValue = localStorage.getItem(REFRESH_TOKEN_KEY);
if (!refreshTokenValue) {
logout();
return;
}
try {
const response = await client.post<Token>({
url: "/api/v1/auth/refresh",
body: { refresh_token: refreshTokenValue },
});
const newTokens = response.data;
if (newTokens) {
// Store new tokens
storeToken(newTokens.access_token, newTokens.refresh_token || null);
// Update client headers
client.setConfig({
headers: {
Authorization: `Bearer ${newTokens.access_token}`,
},
}); });
}
// Refetch user data
await refetch();
} catch (error) {
console.error("Token refresh failed:", error);
logout();
}
}, [logout, refetch]);
// Redirect to login page // Check token validity and refresh if needed on route changes
router.push('/login'); useEffect(() => {
}, [router, queryClient]); const token = getStoredToken();
// Refresh token function if (token && isTokenExpired(token)) {
const refreshToken = useCallback(async (): Promise<void> => { refreshToken();
const refreshTokenValue = localStorage.getItem(REFRESH_TOKEN_KEY); }
if (!refreshTokenValue) { setIsInitializing(false);
logout(); }, [pathname, refreshToken]);
return;
}
try { // Protected routes logic
const response = await client.post<Token>({ useEffect(() => {
url: '/api/v1/auth/refresh', if (isInitializing) return;
body: {refresh_token: refreshTokenValue},
});
const newTokens = response.data; const protectedRoutes = [
"/admin",
"/dashboard",
"/events/create",
"/events/edit",
"/profile",
];
if (newTokens) { const publicOnlyRoutes = ["/login", "/register"];
// Store new tokens
storeToken(newTokens.access_token, newTokens.refresh_token || null);
// Update client headers const publicRoutes = ["/", "/invite", "/rsvp"];
client.setConfig({
headers: {
Authorization: `Bearer ${newTokens.access_token}`
}
});
} const isProtectedRoute = protectedRoutes.some((route) =>
// Refetch user data pathname?.startsWith(route),
await refetch(); );
} catch (error) { const isPublicOnlyRoute = publicOnlyRoutes.some(
console.error('Token refresh failed:', error); (route) => pathname === route,
logout();
}
}, [logout, refetch]);
// Check token validity and refresh if needed on route changes
useEffect(() => {
const token = getStoredToken();
if (token && isTokenExpired(token)) {
refreshToken();
}
setIsInitializing(false);
}, [pathname, refreshToken]);
// Protected routes logic
useEffect(() => {
if (isInitializing) return;
const protectedRoutes = [
'/admin',
'/dashboard',
'/events/create',
'/events/edit',
'/profile',
];
const publicOnlyRoutes = [
'/login',
'/register',
];
const publicRoutes = [
'/',
'/invite',
'/rsvp',
];
const isProtectedRoute = protectedRoutes.some(route => pathname?.startsWith(route));
const isPublicOnlyRoute = publicOnlyRoutes.some(route => pathname === route);
// Handle loading state
if (isLoading && isProtectedRoute) return;
// Redirect to login if not authenticated but trying to access protected route
if (isProtectedRoute && !user) {
router.push(`/login?redirect=${encodeURIComponent(pathname || '')}`);
}
// Redirect to dashboard if authenticated but trying to access public-only route
if (isPublicOnlyRoute && user) {
router.push('/dashboard');
}
}, [user, isLoading, pathname, router, isInitializing]);
// Create the context value
const value = useMemo<AuthContextState>(() => ({
user: user as UserResponse | null,
isAuthenticated: !!user,
isLoading: isInitializing || isLoading,
error: error as Error | null,
login,
logout,
refreshToken,
}), [user, isInitializing, isLoading, error, login, logout, refreshToken]);
return (
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
); );
};
// Handle loading state
if (isLoading && isProtectedRoute) return;
// Redirect to login if not authenticated but trying to access protected route
if (isProtectedRoute && !user) {
router.push(`/login?redirect=${encodeURIComponent(pathname || "")}`);
}
// Redirect to dashboard if authenticated but trying to access public-only route
if (isPublicOnlyRoute && user) {
router.push("/dashboard");
}
}, [user, isLoading, pathname, router, isInitializing]);
// Create the context value
const value = useMemo<AuthContextState>(
() => ({
user: user as UserResponse | null,
isAuthenticated: !!user,
isLoading: isInitializing || isLoading,
error: error as Error | null,
login,
logout,
refreshToken,
}),
[user, isInitializing, isLoading, error, login, logout, refreshToken],
);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};

View File

@@ -1,7 +1,7 @@
declare namespace API { declare namespace API {
interface ErrorResponse { interface ErrorResponse {
detail: string; detail: string;
} }
// Add more types as you develop your API // Add more types as you develop your API
} }