Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: api types #200

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions src/@types/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Copyright 2025 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { paths } from '@/app/api/schema';

export type ApiResponse<
Path extends keyof paths,
Method extends keyof paths[Path] & ('get' | 'post' | 'delete') = 'get',
ContentType extends
| 'application/json'
| 'text/event-stream' = 'application/json',
> = paths[Path][Method] extends {
responses: {
200: {
content: {
'application/json'?: infer JSON;
'text/event-stream'?: infer EventStream;
};
};
};
}
? ContentType extends 'application/json'
? JSON extends Record<string, any>
? JSON
: never
: EventStream extends Record<string, any>
? EventStream
: never
: never;

export type ApiRequestBody<
Path extends keyof paths,
Method extends keyof paths[Path] &
('get' | 'post' | 'delete' | 'put') = 'post',
ContentType extends
| 'application/json'
| 'multipart/form-data' = 'application/json',
> = paths[Path][Method] extends {
requestBody?: {
content: {
'application/json'?: infer JSON;
'multipart/form-data'?: infer FormData;
};
};
}
? ContentType extends 'application/json'
? JSON extends Record<string, any>
? JSON
: never
: FormData extends Record<string, any>
? FormData
: never
: never;

export type ApiQuery<
Path extends keyof paths,
Method extends keyof paths[Path] & 'get' = 'get',
> = paths[Path][Method] extends {
parameters: { query?: infer Q };
}
? Q extends Record<string, any>
? Q
: never
: never;
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ import {
listMessagesWithFiles,
MESSAGES_PAGE_SIZE,
} from '@/app/api/rsc';
import { MessageResponse } from '@/app/api/threads-messages/types';
import { ensureDefaultOrganizationId } from '@/app/auth/rsc';
import { AppBuilder } from '@/modules/apps/builder/AppBuilder';
import { AppBuilderProvider } from '@/modules/apps/builder/AppBuilderProvider';
import { extractCodeFromMessageContent } from '@/modules/apps/utils';
import { getMessagesFromThreadMessages } from '@/modules/chat/utils';
import { LayoutInitializer } from '@/store/layout/LayouInitializer';
import { notFound } from 'next/navigation';
import { getMessagesFromThreadMessages } from '@/modules/chat/utils';
import { MessageResult } from '@/app/api/threads-messages/types';
import { getAppBuilderNavbarProps } from '../../../utils';

interface Props {
Expand Down Expand Up @@ -75,7 +75,7 @@ export default async function AppBuilderPage({
);
}

function getLastMessageWithStreamlitCode(messages: MessageResult[]) {
function getLastMessageWithStreamlitCode(messages: MessageResponse[]) {
const chatMessages = getMessagesFromThreadMessages(messages);
return chatMessages.findLast((message) =>
Boolean(extractCodeFromMessageContent(message.content)),
Expand Down
6 changes: 3 additions & 3 deletions src/app/api/api-keys/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@

import { client } from '../client';
import { assertSuccessResponse, getRequestHeaders } from '../utils';
import { ApiKeysCreateBody, ApiKeysListQuery } from './types';
import { ApiKeyCreateBody, ApiKeysListQuery } from './types';

export async function createApiKey(
organizationId: string,
projectId: string,
body: ApiKeysCreateBody,
body: ApiKeyCreateBody,
) {
const res = await client.POST(
'/v1/organization/projects/{project_id}/api_keys',
Expand Down Expand Up @@ -71,7 +71,7 @@ export async function updateApiKey(
organizationId: string,
projectId: string,
id: string,
body: ApiKeysCreateBody,
body: ApiKeyCreateBody,
) {
const res = await client.POST(
'/v1/organization/projects/{project_id}/api_keys/{api_key_id}',
Expand Down
30 changes: 11 additions & 19 deletions src/app/api/api-keys/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,20 @@
* limitations under the License.
*/

import { paths } from '../schema';
import { FetchParamsOrderBy } from '../utils';
import { ApiQuery, ApiRequestBody, ApiResponse } from '@/@types/utils';

export type ApiKeysCreateBody = NonNullable<
paths['/v1/organization/projects/{project_id}/api_keys']['post']['requestBody']
>['content']['application/json'];

export type ApiKey = NonNullable<
paths['/v1/organization/projects/{project_id}/api_keys/{api_key_id}']['get']['responses']['200']['content']['application/json']
>;
export type ApiKeysListResponse =
ApiResponse<'/v1/organization/projects/{project_id}/api_keys'>;

export type ApiKeyDeleteResult = NonNullable<
paths['/v1/organization/projects/{project_id}/api_keys/{api_key_id}']['delete']['responses']['200']['content']['application/json']
>;
export type ApiKeyResponse =
ApiResponse<'/v1/organization/projects/{project_id}/api_keys/{api_key_id}'>;

export type ApiKeysListQuery = NonNullable<
paths['/v1/organization/api_keys']['get']['parameters']['query']
export type ApiKeyDeleteResponse = ApiResponse<
'/v1/organization/projects/{project_id}/api_keys/{api_key_id}',
'delete'
>;

export type ApiKeysListOrderBy = FetchParamsOrderBy<ApiKeysListQuery>;

export type ApiKeysListResponse =
paths['/v1/organization/projects/{project_id}/api_keys']['get']['responses']['200']['content']['application/json'];
export type ApiKeyCreateBody =
ApiRequestBody<'/v1/organization/projects/{project_id}/api_keys'>;

export type ApiKeysList = ApiKeysListResponse['data'];
export type ApiKeysListQuery = ApiQuery<'/v1/organization/api_keys'>;
12 changes: 6 additions & 6 deletions src/app/api/apps/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
* limitations under the License.
*/

import { paths } from '../schema';
import { ApiRequestBody, ApiResponse } from '@/@types/utils';

export type ChatCompletionResponse =
paths['/v1/chat/completions']['post']['responses']['200']['content']['application/json'];
export type ChatCompletionResponse = ApiResponse<
'/v1/chat/completions',
'post'
>;

export type ChatCompletionCreateBody = NonNullable<
paths['/v1/chat/completions']['post']['requestBody']
>['content']['application/json'];
export type ChatCompletionCreateBody = ApiRequestBody<'/v1/chat/completions'>;
26 changes: 10 additions & 16 deletions src/app/api/artifacts/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,22 @@
* limitations under the License.
*/

import { paths } from '../schema';
import { ApiQuery, ApiRequestBody, ApiResponse } from '@/@types/utils';
import { FetchParamsOrderBy } from '../utils';

export type ArtifactsListResponse =
paths['/v1/artifacts']['get']['responses']['200']['content']['application/json'];
export type ArtifactsListResponse = ApiResponse<'/v1/artifacts'>;

export type ArtifactResult =
paths['/v1/artifacts/{artifact_id}']['get']['responses']['200']['content']['application/json'];
export type ArtifactResponse = ApiResponse<'/v1/artifacts/{artifact_id}'>;

export type ArtifactDeleteResult =
paths['/v1/artifacts/{artifact_id}']['delete']['responses']['200']['content']['application/json'];
export type ArtifactDeleteResponse = ApiResponse<
'/v1/artifacts/{artifact_id}',
'delete'
>;

export type ArtifactCreateBody = NonNullable<
paths['/v1/artifacts']['post']['requestBody']
>['content']['application/json'];
export type ArtifactCreateBody = ApiRequestBody<'/v1/artifacts'>;

export type ArtifactUpdateBody = NonNullable<
paths['/v1/artifacts/{artifact_id}']['post']['requestBody']
>['content']['application/json'];
export type ArtifactUpdateBody = ApiRequestBody<'/v1/artifacts/{artifact_id}'>;

export type ArtifactsListQuery = NonNullable<
paths['/v1/artifacts']['get']['parameters']['query']
>;
export type ArtifactsListQuery = ApiQuery<'/v1/artifacts'>;

export type ArtifactsListQueryOrderBy = FetchParamsOrderBy<ArtifactsListQuery>;
34 changes: 15 additions & 19 deletions src/app/api/assistants/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,41 +14,37 @@
* limitations under the License.
*/

import { paths } from '../schema';
import { ApiQuery, ApiRequestBody, ApiResponse } from '@/@types/utils';
import { FetchParamsOrderBy } from '../utils';

export type AssistantsListResponse =
paths['/v1/assistants']['get']['responses']['200']['content']['application/json'];
export type AssistantsListResponse = ApiResponse<'/v1/assistants'>;

export type AssistantResult =
paths['/v1/assistants/{assistant_id}']['get']['responses']['200']['content']['application/json'];
export type AssistantResponse = ApiResponse<'/v1/assistants/{assistant_id}'>;

export type AssistantDeleteResult =
paths['/v1/assistants/{assistant_id}']['delete']['responses']['200']['content']['application/json'];

type AssistantCreateBodyApi = NonNullable<
paths['/v1/assistants']['post']['requestBody']
>['content']['application/json'];

export type ToolResources = Pick<
NonNullable<AssistantCreateBodyApi['tool_resources']>,
'code_interpreter' | 'file_search'
export type AssistantDeleteResponse = ApiResponse<
'/v1/assistants/{assistant_id}',
'delete'
>;

type AssistantCreateBodyApi = ApiRequestBody<'/v1/assistants', 'post'>;

export type AssistantCreateBody = Omit<
AssistantCreateBodyApi,
'tool_resources'
> & {
tool_resources?: ToolResources;
};

export type AssistantsListQuery = NonNullable<
paths['/v1/assistants']['get']['parameters']['query']
>;
export type AssistantsListQuery = ApiQuery<'/v1/assistants'>;

export type AssistantsListQueryOrderBy =
FetchParamsOrderBy<AssistantsListQuery>;

export type AssistantModel = AssistantCreateBody['model'];

export type AssistantTool = AssistantResult['tools'][number];
export type AssistantTool = AssistantResponse['tools'][number];

export type ToolResources = Pick<
NonNullable<AssistantCreateBodyApi['tool_resources']>,
'code_interpreter' | 'file_search'
>;
17 changes: 9 additions & 8 deletions src/app/api/files/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@
* limitations under the License.
*/

import { readFile } from '.';
import { paths } from '../schema';
import { ApiRequestBody, ApiResponse } from '@/@types/utils';

export type FileCreateBody =
paths['/v1/files']['post']['requestBody']['content']['multipart/form-data'];
export type FileResponse = ApiResponse<'/v1/files/{file_id}'>;

export type FileCreateResponse =
paths['/v1/files']['post']['responses']['200']['content']['application/json'];
export type FileCreateResponse = ApiResponse<'/v1/files', 'post'>;

export type FilePurpose = FileCreateBody['purpose'];
export type FileCreateBody = ApiRequestBody<
'/v1/files',
'post',
'multipart/form-data'
>;

export type FileEntity = NonNullable<Awaited<ReturnType<typeof readFile>>>;
export type FilePurpose = FileCreateBody['purpose'];
7 changes: 5 additions & 2 deletions src/app/api/organization-users/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@

import { client } from '../client';
import { assertSuccessResponse, getRequestHeaders } from '../utils';
import { UsersListQuery } from './types';
import { OrganizationUsersListQuery } from './types';

export async function listUsers(organizationId: string, query: UsersListQuery) {
export async function listOrganizationUsers(
organizationId: string,
query: OrganizationUsersListQuery,
) {
const res = await client.GET('/v1/organization/users', {
params: {
query,
Expand Down
14 changes: 5 additions & 9 deletions src/app/api/organization-users/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,11 @@
* limitations under the License.
*/

import { listUsers } from '.';
import { paths } from '../schema';
import { ApiQuery, ApiResponse } from '@/@types/utils';

export type UsersListQuery = NonNullable<
paths['/v1/organization/users']['get']['parameters']['query']
>;
export type OrganizationUsersListResponse =
ApiResponse<'/v1/organization/users'>;

export type UsersListResponse = NonNullable<
Awaited<ReturnType<typeof listUsers>>
>;
export type OrganizationUsersListQuery = ApiQuery<'/v1/organization/users'>;

export type OrganizationUser = UsersListResponse['data'][number];
export type OrganizationUser = OrganizationUsersListResponse['data'][number];
34 changes: 16 additions & 18 deletions src/app/api/projects-users/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,26 @@
* limitations under the License.
*/

import { listProjectUsers } from '.';
import { paths } from '../schema';
import { ApiQuery, ApiRequestBody, ApiResponse } from '@/@types/utils';

export type ProjectUsersListQuery = NonNullable<
paths['/v1/organization/projects/{project_id}/users']['get']['parameters']['query']
>;
export type ProjectUsersListResponse =
ApiResponse<'/v1/organization/projects/{project_id}/users'>;

export type ProjectUserResponse =
ApiResponse<'/v1/organization/projects/{project_id}/users/{user_id}'>;

export type ProjectUsersListResponse = NonNullable<
Awaited<ReturnType<typeof listProjectUsers>>
export type ProjectUserCreateResponse = ApiResponse<
'/v1/organization/projects/{project_id}/users',
'post'
>;

export type ProjectUser = ProjectUsersListResponse['data'][number];
export type ProjectUserRole = ProjectUser['role'];
export type ProjectUserCreateBody =
ApiRequestBody<'/v1/organization/projects/{project_id}/users'>;

export type ProjectUserCreateBody = NonNullable<
paths['/v1/organization/projects/{project_id}/users']['post']['requestBody']['content']['application/json']
>;
export type ProjectUserUpdateBody =
ApiRequestBody<'/v1/organization/projects/{project_id}/users/{user_id}'>;

export type ProjectUserCreateResponse = NonNullable<
paths['/v1/organization/projects/{project_id}/users']['post']['responses']['200']['content']['application/json']
>;
export type ProjectUsersListQuery =
ApiQuery<'/v1/organization/projects/{project_id}/users'>;

export type ProjectUserUpdateBody = NonNullable<
paths['/v1/organization/projects/{project_id}/users/{user_id}']['post']['requestBody']
>['content']['application/json'];
export type ProjectUserRole = ProjectUserResponse['role'];
Loading