From b0a3399774c6f32cd956460ad6beeb0d169b9071 Mon Sep 17 00:00:00 2001 From: Coding On Star <447357187@qq.com> Date: Tue, 19 May 2026 13:02:17 +0800 Subject: [PATCH 1/7] feat: enhance app creation tracking with source and template ID (#36369) Co-authored-by: CodingOnStar --- .../explore/explore-app-list-flow.test.tsx | 4 +- .../app-list/__tests__/index.spec.tsx | 2 + .../app/create-app-dialog/app-list/index.tsx | 2 +- .../create-app-modal/__tests__/index.spec.tsx | 2 +- .../components/app/create-app-modal/index.tsx | 2 +- .../__tests__/index.spec.tsx | 4 +- .../app/create-from-dsl-modal/index.tsx | 4 +- .../components/apps/__tests__/index.spec.tsx | 38 ++++++-- web/app/components/apps/index.tsx | 39 +++++--- .../explore/app-list/__tests__/index.spec.tsx | 16 ++-- web/app/components/explore/app-list/index.tsx | 33 +++++-- web/hooks/use-import-dsl.ts | 6 +- .../__tests__/create-app-tracking.spec.ts | 88 ++++++++++++++++--- web/utils/create-app-tracking.ts | 64 ++++++++++---- 14 files changed, 231 insertions(+), 73 deletions(-) diff --git a/web/__tests__/explore/explore-app-list-flow.test.tsx b/web/__tests__/explore/explore-app-list-flow.test.tsx index 96798ac6a9..dbbbbee456 100644 --- a/web/__tests__/explore/explore-app-list-flow.test.tsx +++ b/web/__tests__/explore/explore-app-list-flow.test.tsx @@ -236,8 +236,8 @@ describe('Explore App List Flow', () => { mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onSuccess?: () => void, onPending?: () => void }) => { options.onPending?.() }) - mockHandleImportDSLConfirm.mockImplementation(async (options: { onSuccess?: () => void }) => { - options.onSuccess?.() + mockHandleImportDSLConfirm.mockImplementation(async (options: { onSuccess?: (payload: { app_mode: AppModeEnum }) => void }) => { + options.onSuccess?.({ app_mode: AppModeEnum.CHAT }) }) renderAppList(true, onSuccess) diff --git a/web/app/components/app/create-app-dialog/app-list/__tests__/index.spec.tsx b/web/app/components/app/create-app-dialog/app-list/__tests__/index.spec.tsx index cd6c6b57eb..6f76273c77 100644 --- a/web/app/components/app/create-app-dialog/app-list/__tests__/index.spec.tsx +++ b/web/app/components/app/create-app-dialog/app-list/__tests__/index.spec.tsx @@ -247,7 +247,9 @@ describe('Apps', () => { }) expect(mockTrackCreateApp).toHaveBeenCalledWith({ + source: 'studio_template_list', appMode: AppModeEnum.CHAT, + templateId: 'Alpha', }) expect(mockToastSuccess).toHaveBeenCalledWith('app.newApp.appCreated') expect(onSuccess).toHaveBeenCalled() diff --git a/web/app/components/app/create-app-dialog/app-list/index.tsx b/web/app/components/app/create-app-dialog/app-list/index.tsx index b0f0b8ca59..20bb18460b 100644 --- a/web/app/components/app/create-app-dialog/app-list/index.tsx +++ b/web/app/components/app/create-app-dialog/app-list/index.tsx @@ -127,7 +127,7 @@ const Apps = ({ icon_background, description, }) - trackCreateApp({ appMode: mode }) + trackCreateApp({ source: 'studio_template_list', appMode: mode, templateId: currApp?.app_id }) setIsShowCreateModal(false) toast.success(t('newApp.appCreated', { ns: 'app' })) diff --git a/web/app/components/app/create-app-modal/__tests__/index.spec.tsx b/web/app/components/app/create-app-modal/__tests__/index.spec.tsx index 24fb21747f..bf1e698fc6 100644 --- a/web/app/components/app/create-app-modal/__tests__/index.spec.tsx +++ b/web/app/components/app/create-app-modal/__tests__/index.spec.tsx @@ -170,7 +170,7 @@ describe('CreateAppModal', () => { mode: AppModeEnum.ADVANCED_CHAT, })) - expect(mockTrackCreateApp).toHaveBeenCalledWith({ appMode: AppModeEnum.ADVANCED_CHAT }) + expect(mockTrackCreateApp).toHaveBeenCalledWith({ source: 'studio_blank', appMode: AppModeEnum.ADVANCED_CHAT }) expect(mockToastSuccess).toHaveBeenCalledWith('app.newApp.appCreated') expect(onSuccess).toHaveBeenCalled() expect(onClose).toHaveBeenCalled() diff --git a/web/app/components/app/create-app-modal/index.tsx b/web/app/components/app/create-app-modal/index.tsx index c27231bc87..e81ad0f862 100644 --- a/web/app/components/app/create-app-modal/index.tsx +++ b/web/app/components/app/create-app-modal/index.tsx @@ -79,7 +79,7 @@ function CreateApp({ onClose, onSuccess, onCreateFromTemplate, defaultAppMode }: mode: appMode, }) - trackCreateApp({ appMode: app.mode }) + trackCreateApp({ source: 'studio_blank', appMode: app.mode }) toast.success(t('newApp.appCreated', { ns: 'app' })) onSuccess() diff --git a/web/app/components/app/create-from-dsl-modal/__tests__/index.spec.tsx b/web/app/components/app/create-from-dsl-modal/__tests__/index.spec.tsx index dac5b22ee6..c6be430fac 100644 --- a/web/app/components/app/create-from-dsl-modal/__tests__/index.spec.tsx +++ b/web/app/components/app/create-from-dsl-modal/__tests__/index.spec.tsx @@ -197,7 +197,7 @@ describe('CreateFromDSLModal', () => { mode: DSLImportMode.YAML_URL, yaml_url: 'https://example.com/app.yml', }) - expect(mockTrackCreateApp).toHaveBeenCalledWith({ appMode: AppModeEnum.CHAT }) + expect(mockTrackCreateApp).toHaveBeenCalledWith({ source: 'studio_upload', appMode: AppModeEnum.CHAT }) expect(handleSuccess).toHaveBeenCalledTimes(1) expect(handleClose).toHaveBeenCalledTimes(1) expect(localStorage.getItem(NEED_REFRESH_APP_LIST_KEY)).toBe('1') @@ -304,7 +304,7 @@ describe('CreateFromDSLModal', () => { expect(mockImportDSLConfirm).toHaveBeenCalledWith({ import_id: 'import-3', }) - expect(mockTrackCreateApp).toHaveBeenCalledWith({ appMode: AppModeEnum.WORKFLOW }) + expect(mockTrackCreateApp).toHaveBeenCalledWith({ source: 'studio_upload', appMode: AppModeEnum.WORKFLOW }) }) it('should close the DSL mismatch modal when dialog requests close', async () => { diff --git a/web/app/components/app/create-from-dsl-modal/index.tsx b/web/app/components/app/create-from-dsl-modal/index.tsx index 5b8a4e7469..85ed284506 100644 --- a/web/app/components/app/create-from-dsl-modal/index.tsx +++ b/web/app/components/app/create-from-dsl-modal/index.tsx @@ -110,7 +110,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS return const { id, status, app_id, app_mode, imported_dsl_version, current_dsl_version } = response if (status === DSLImportStatus.COMPLETED || status === DSLImportStatus.COMPLETED_WITH_WARNINGS) { - trackCreateApp({ appMode: app_mode }) + trackCreateApp({ source: 'studio_upload', appMode: app_mode }) if (onSuccess) onSuccess() @@ -171,7 +171,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS const { status, app_id, app_mode } = response if (status === DSLImportStatus.COMPLETED) { - trackCreateApp({ appMode: app_mode }) + trackCreateApp({ source: 'studio_upload', appMode: app_mode }) if (onSuccess) onSuccess() if (onClose) diff --git a/web/app/components/apps/__tests__/index.spec.tsx b/web/app/components/apps/__tests__/index.spec.tsx index 7085852e8f..32ebd35eba 100644 --- a/web/app/components/apps/__tests__/index.spec.tsx +++ b/web/app/components/apps/__tests__/index.spec.tsx @@ -262,8 +262,8 @@ describe('Apps', () => { }) it('should track template preview creation after a successful import', async () => { - mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onSuccess?: () => void }) => { - options.onSuccess?.() + mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onSuccess?: (payload: { app_mode: AppModeEnum }) => void }) => { + options.onSuccess?.({ app_mode: AppModeEnum.CHAT }) }) renderWithClient() @@ -275,7 +275,9 @@ describe('Apps', () => { await waitFor(() => { expect(mockFetchAppDetail).toHaveBeenCalledWith('template-1') expect(mockTrackCreateApp).toHaveBeenCalledWith({ + source: 'studio_template_preview', appMode: AppModeEnum.CHAT, + templateId: 'template-1', }) }) }) @@ -284,8 +286,8 @@ describe('Apps', () => { mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onPending?: () => void }) => { options.onPending?.() }) - mockHandleImportDSLConfirm.mockImplementation(async (options: { onSuccess?: () => void }) => { - options.onSuccess?.() + mockHandleImportDSLConfirm.mockImplementation(async (options: { onSuccess?: (payload: { app_mode: AppModeEnum }) => void }) => { + options.onSuccess?.({ app_mode: AppModeEnum.WORKFLOW }) }) renderWithClient() @@ -299,7 +301,9 @@ describe('Apps', () => { await waitFor(() => { expect(mockHandleImportDSLConfirm).toHaveBeenCalledTimes(1) expect(mockTrackCreateApp).toHaveBeenCalledWith({ - appMode: AppModeEnum.CHAT, + source: 'studio_template_preview', + appMode: AppModeEnum.WORKFLOW, + templateId: 'template-1', }) }) }) @@ -365,8 +369,8 @@ describe('Apps', () => { }) it('should import DSL from marketplace template on confirm', async () => { - mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onSuccess?: () => void }) => { - options.onSuccess?.() + mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onSuccess?: (payload: { app_mode: AppModeEnum }) => void }) => { + options.onSuccess?.({ app_mode: AppModeEnum.CHAT }) }) mockSearchParams = new URLSearchParams('template-id=tpl-42') renderWithClient() @@ -378,14 +382,22 @@ describe('Apps', () => { { mode: 'yaml-content', yaml_content: 'yaml-dsl-content' }, expect.objectContaining({ onSuccess: expect.any(Function) }), ) + expect(mockTrackCreateApp).toHaveBeenCalledWith({ + source: 'external', + appMode: AppModeEnum.CHAT, + templateId: 'tpl-42', + }) expect(mockReplace).toHaveBeenCalled() }) }) - it('should show DSL confirm modal when marketplace import is pending', async () => { + it('should track marketplace template creation after confirming a pending import', async () => { mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onPending?: () => void }) => { options.onPending?.() }) + mockHandleImportDSLConfirm.mockImplementation(async (options: { onSuccess?: (payload: { app_mode: AppModeEnum }) => void }) => { + options.onSuccess?.({ app_mode: AppModeEnum.WORKFLOW }) + }) mockSearchParams = new URLSearchParams('template-id=tpl-42') renderWithClient() @@ -395,6 +407,16 @@ describe('Apps', () => { expect(screen.getByTestId('dsl-confirm-modal')).toBeInTheDocument() expect(mockReplace).toHaveBeenCalled() }) + + fireEvent.click(screen.getByTestId('confirm-dsl')) + + await waitFor(() => { + expect(mockTrackCreateApp).toHaveBeenCalledWith({ + source: 'external', + appMode: AppModeEnum.WORKFLOW, + templateId: 'tpl-42', + }) + }) }) }) diff --git a/web/app/components/apps/index.tsx b/web/app/components/apps/index.tsx index c42132e890..9c99411883 100644 --- a/web/app/components/apps/index.tsx +++ b/web/app/components/apps/index.tsx @@ -1,6 +1,7 @@ 'use client' import type { CreateAppModalProps } from '../explore/create-app-modal' import type { TryAppSelection } from '@/types/try-app' +import type { TrackCreateAppParams } from '@/utils/create-app-tracking' import { useCallback, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { useEducationInit } from '@/app/education-apply/hooks' @@ -31,6 +32,7 @@ const Apps = () => { const [currentTryAppParams, setCurrentTryAppParams] = useState(undefined) const currentCreateAppModeRef = useRef(null) + const currentCreateAppTrackingRef = useRef | null>(null) const currApp = currentTryAppParams?.app const [isShowTryAppPanel, setIsShowTryAppPanel] = useState(false) const hideTryAppPanel = useCallback(() => { @@ -46,13 +48,24 @@ const Apps = () => { const [isShowCreateModal, setIsShowCreateModal] = useState(false) const handleShowFromTryApp = useCallback(() => { + currentCreateAppTrackingRef.current = { + source: 'studio_template_preview', + templateId: currentTryAppParams?.appId || currentTryAppParams?.app.app_id, + } setIsShowCreateModal(true) - }, []) - const trackCurrentCreateApp = useCallback(() => { - if (!currentCreateAppModeRef.current) + }, [currentTryAppParams?.app.app_id, currentTryAppParams?.appId]) + const trackCurrentCreateApp = useCallback((appMode?: TryAppSelection['app']['app']['mode'] | null) => { + const currentCreateAppTracking = currentCreateAppTrackingRef.current + const resolvedAppMode = appMode ?? currentCreateAppModeRef.current + if (!resolvedAppMode || !currentCreateAppTracking) return - trackCreateApp({ appMode: currentCreateAppModeRef.current }) + trackCreateApp({ + ...currentCreateAppTracking, + appMode: resolvedAppMode, + }) + currentCreateAppTrackingRef.current = null + currentCreateAppModeRef.current = null }, []) const [controlRefreshList, setControlRefreshList] = useState(0) @@ -81,19 +94,25 @@ const Apps = () => { const onConfirmDSL = useCallback(async () => { await handleImportDSLConfirm({ - onSuccess: () => { - trackCurrentCreateApp() + onSuccess: (response) => { + trackCurrentCreateApp(response.app_mode) onSuccess() }, }) }, [handleImportDSLConfirm, onSuccess, trackCurrentCreateApp]) const handleMarketplaceTemplateConfirm = useCallback(async (dslContent: string) => { + currentCreateAppModeRef.current = null + currentCreateAppTrackingRef.current = { + source: 'external', + templateId: templateId || undefined, + } await handleImportDSL({ mode: DSLImportMode.YAML_CONTENT, yaml_content: dslContent, }, { - onSuccess: () => { + onSuccess: (response) => { + trackCurrentCreateApp(response.app_mode) handleCloseTemplateModal() onSuccess() }, @@ -102,7 +121,7 @@ const Apps = () => { setShowDSLConfirmModal(true) }, }) - }, [handleImportDSL, handleCloseTemplateModal, onSuccess]) + }, [handleImportDSL, handleCloseTemplateModal, onSuccess, templateId, trackCurrentCreateApp]) const onCreate: CreateAppModalProps['onConfirm'] = useCallback(async ({ name, @@ -127,8 +146,8 @@ const Apps = () => { description, } await handleImportDSL(payload, { - onSuccess: () => { - trackCurrentCreateApp() + onSuccess: (response) => { + trackCurrentCreateApp(response.app_mode) setIsShowCreateModal(false) }, onPending: () => { diff --git a/web/app/components/explore/app-list/__tests__/index.spec.tsx b/web/app/components/explore/app-list/__tests__/index.spec.tsx index 7c9bdb7b23..0986df44e0 100644 --- a/web/app/components/explore/app-list/__tests__/index.spec.tsx +++ b/web/app/components/explore/app-list/__tests__/index.spec.tsx @@ -239,8 +239,8 @@ describe('AppList', () => { mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onSuccess?: () => void, onPending?: () => void }) => { options.onPending?.() }) - mockHandleImportDSLConfirm.mockImplementation(async (options: { onSuccess?: () => void }) => { - options.onSuccess?.() + mockHandleImportDSLConfirm.mockImplementation(async (options: { onSuccess?: (payload: { app_mode: AppModeEnum }) => void }) => { + options.onSuccess?.({ app_mode: AppModeEnum.CHAT }) }) renderAppList(true, onSuccess) @@ -257,7 +257,9 @@ describe('AppList', () => { await waitFor(() => { expect(mockHandleImportDSLConfirm).toHaveBeenCalledTimes(1) expect(mockTrackCreateApp).toHaveBeenCalledWith({ + source: 'explore_template_list', appMode: AppModeEnum.CHAT, + templateId: 'app-1', }) expect(onSuccess).toHaveBeenCalledTimes(1) }) @@ -351,8 +353,8 @@ describe('AppList', () => { allList: [createApp()], }; (fetchAppDetail as unknown as Mock).mockResolvedValue({ export_data: 'yaml', mode: AppModeEnum.CHAT }) - mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onSuccess?: () => void }) => { - options.onSuccess?.() + mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onSuccess?: (payload: { app_mode: AppModeEnum }) => void }) => { + options.onSuccess?.({ app_mode: AppModeEnum.CHAT }) }) renderAppList(true) @@ -417,8 +419,8 @@ describe('AppList', () => { allList: [createApp()], }; (fetchAppDetail as unknown as Mock).mockResolvedValue({ export_data: 'yaml', mode: AppModeEnum.CHAT }) - mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onSuccess?: () => void }) => { - options.onSuccess?.() + mockHandleImportDSL.mockImplementation(async (_payload: unknown, options: { onSuccess?: (payload: { app_mode: AppModeEnum }) => void }) => { + options.onSuccess?.({ app_mode: AppModeEnum.CHAT }) }) renderAppList(true) @@ -429,7 +431,9 @@ describe('AppList', () => { await waitFor(() => { expect(mockTrackCreateApp).toHaveBeenCalledWith({ + source: 'explore_template_preview', appMode: AppModeEnum.CHAT, + templateId: 'app-1', }) }) }) diff --git a/web/app/components/explore/app-list/index.tsx b/web/app/components/explore/app-list/index.tsx index 86a0bbc6c0..41485e0e89 100644 --- a/web/app/components/explore/app-list/index.tsx +++ b/web/app/components/explore/app-list/index.tsx @@ -3,6 +3,7 @@ import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal' import type { App } from '@/models/explore' import type { TryAppSelection } from '@/types/try-app' +import type { TrackCreateAppParams } from '@/utils/create-app-tracking' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { useSuspenseQuery } from '@tanstack/react-query' @@ -107,6 +108,7 @@ const Apps = ({ const [currentTryApp, setCurrentTryApp] = useState(undefined) const currentCreateAppModeRef = useRef(null) + const currentCreateAppTrackingRef = useRef | null>(null) const isShowTryAppPanel = !!currentTryApp const hideTryAppPanel = useCallback(() => { setCurrentTryApp(undefined) @@ -116,13 +118,24 @@ const Apps = ({ }, []) const handleShowFromTryApp = useCallback(() => { setCurrApp(currentTryApp?.app || null) + currentCreateAppTrackingRef.current = { + source: 'explore_template_preview', + templateId: currentTryApp?.appId || currentTryApp?.app.app_id, + } setIsShowCreateModal(true) - }, [currentTryApp?.app]) - const trackCurrentCreateApp = useCallback(() => { - if (!currentCreateAppModeRef.current) + }, [currentTryApp?.app, currentTryApp?.appId]) + const trackCurrentCreateApp = useCallback((appMode?: App['app']['mode'] | null) => { + const currentCreateAppTracking = currentCreateAppTrackingRef.current + const resolvedAppMode = appMode ?? currentCreateAppModeRef.current + if (!resolvedAppMode || !currentCreateAppTracking) return - trackCreateApp({ appMode: currentCreateAppModeRef.current }) + trackCreateApp({ + ...currentCreateAppTracking, + appMode: resolvedAppMode, + }) + currentCreateAppTrackingRef.current = null + currentCreateAppModeRef.current = null }, []) const onCreate: CreateAppModalProps['onConfirm'] = useCallback(async ({ @@ -148,8 +161,8 @@ const Apps = ({ description, } await handleImportDSL(payload, { - onSuccess: () => { - trackCurrentCreateApp() + onSuccess: (response) => { + trackCurrentCreateApp(response.app_mode) setIsShowCreateModal(false) }, onPending: () => { @@ -160,8 +173,8 @@ const Apps = ({ const onConfirmDSL = useCallback(async () => { await handleImportDSLConfirm({ - onSuccess: () => { - trackCurrentCreateApp() + onSuccess: (response) => { + trackCurrentCreateApp(response.app_mode) onSuccess?.() }, }) @@ -242,6 +255,10 @@ const Apps = ({ app={app} canCreate={hasEditPermission} onCreate={() => { + currentCreateAppTrackingRef.current = { + source: 'explore_template_list', + templateId: app.app_id, + } setCurrApp(app) setIsShowCreateModal(true) }} diff --git a/web/hooks/use-import-dsl.ts b/web/hooks/use-import-dsl.ts index 1ece2a27f0..83b11157cf 100644 --- a/web/hooks/use-import-dsl.ts +++ b/web/hooks/use-import-dsl.ts @@ -32,7 +32,7 @@ type DSLPayload = { description?: string } type ResponseCallback = { - onSuccess?: () => void + onSuccess?: (payload: DSLImportResponse) => void onPending?: (payload: DSLImportResponse) => void onFailed?: () => void } @@ -85,7 +85,7 @@ export const useImportDSL = () => { toast.success(message) else toast.warning(message, { description }) - onSuccess?.() + onSuccess?.(response) localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1') await handleCheckPluginDependencies(app_id) getRedirection(isCurrentWorkspaceEditor, { id: app_id, mode: app_mode }, push) @@ -134,7 +134,7 @@ export const useImportDSL = () => { return if (status === DSLImportStatus.COMPLETED) { - onSuccess?.() + onSuccess?.(response) toast.success(t('newApp.appCreated', { ns: 'app' })) await handleCheckPluginDependencies(app_id) localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1') diff --git a/web/utils/__tests__/create-app-tracking.spec.ts b/web/utils/__tests__/create-app-tracking.spec.ts index b732d8d3b8..67e641811e 100644 --- a/web/utils/__tests__/create-app-tracking.spec.ts +++ b/web/utils/__tests__/create-app-tracking.spec.ts @@ -55,11 +55,12 @@ describe('create-app-tracking', () => { }) describe('buildCreateAppEventPayload', () => { - it('should build original payloads with normalized app mode and timestamp', () => { + it('should build payloads with source, normalized app mode, and timestamp', () => { expect(buildCreateAppEventPayload({ + source: 'studio_blank', appMode: AppModeEnum.ADVANCED_CHAT, }, null, new Date(2026, 3, 13, 14, 5, 9))).toEqual({ - source: 'original', + source: 'studio_blank', app_mode: 'chatflow', time: '04-13-14:05:09', }) @@ -67,9 +68,10 @@ describe('create-app-tracking', () => { it('should map agent mode into the canonical app mode bucket', () => { expect(buildCreateAppEventPayload({ + source: 'studio_blank', appMode: AppModeEnum.AGENT_CHAT, }, null, new Date(2026, 3, 13, 9, 8, 7))).toEqual({ - source: 'original', + source: 'studio_blank', app_mode: 'agent', time: '04-13-09:08:07', }) @@ -77,17 +79,19 @@ describe('create-app-tracking', () => { it('should fold legacy non-agent modes into chatflow', () => { expect(buildCreateAppEventPayload({ + source: 'studio_blank', appMode: AppModeEnum.CHAT, }, null, new Date(2026, 3, 13, 8, 0, 1))).toEqual({ - source: 'original', + source: 'studio_blank', app_mode: 'chatflow', time: '04-13-08:00:01', }) expect(buildCreateAppEventPayload({ + source: 'studio_blank', appMode: AppModeEnum.COMPLETION, }, null, new Date(2026, 3, 13, 8, 0, 2))).toEqual({ - source: 'original', + source: 'studio_blank', app_mode: 'chatflow', time: '04-13-08:00:02', }) @@ -95,29 +99,56 @@ describe('create-app-tracking', () => { it('should map workflow mode into the workflow bucket', () => { expect(buildCreateAppEventPayload({ + source: 'studio_blank', appMode: AppModeEnum.WORKFLOW, }, null, new Date(2026, 3, 13, 7, 6, 5))).toEqual({ - source: 'original', + source: 'studio_blank', app_mode: 'workflow', time: '04-13-07:06:05', }) }) + it('should include template_id for template sources', () => { + expect(buildCreateAppEventPayload({ + source: 'studio_template_list', + appMode: AppModeEnum.CHAT, + templateId: 'template-1', + }, null, new Date(2026, 3, 13, 8, 0, 1))).toEqual({ + source: 'studio_template_list', + app_mode: 'chatflow', + time: '04-13-08:00:01', + template_id: 'template-1', + }) + }) + it('should prefer external attribution when present', () => { expect(buildCreateAppEventPayload( { + source: 'studio_template_list', appMode: AppModeEnum.WORKFLOW, + templateId: 'template-1', }, { utmSource: 'linkedin', utmCampaign: 'agent-launch', }, + new Date(2026, 3, 13, 7, 6, 5), )).toEqual({ source: 'external', + app_mode: 'workflow', + time: '04-13-07:06:05', + template_id: 'template-1', utm_source: 'linkedin', utm_campaign: 'agent-launch', }) }) + + it('should not build external payloads without attribution', () => { + expect(buildCreateAppEventPayload({ + source: 'external', + appMode: AppModeEnum.WORKFLOW, + }, null, new Date(2026, 3, 13, 7, 6, 5))).toBeNull() + }) }) describe('trackCreateApp', () => { @@ -126,20 +157,24 @@ describe('create-app-tracking', () => { searchParams: new URLSearchParams('utm_source=newsletter&slug=how-to-build-rag-agent'), }) - trackCreateApp({ appMode: AppModeEnum.WORKFLOW }) + trackCreateApp({ source: 'studio_template_list', appMode: AppModeEnum.WORKFLOW, templateId: 'template-1' }) expect(amplitude.trackEvent).toHaveBeenNthCalledWith(1, 'create_app', { source: 'external', + app_mode: 'workflow', + time: expect.stringMatching(/^\d{2}-\d{2}-\d{2}:\d{2}:\d{2}$/), + template_id: 'template-1', utm_source: 'blog', utm_campaign: 'how-to-build-rag-agent', }) - trackCreateApp({ appMode: AppModeEnum.WORKFLOW }) + trackCreateApp({ source: 'studio_template_list', appMode: AppModeEnum.WORKFLOW, templateId: 'template-1' }) expect(amplitude.trackEvent).toHaveBeenNthCalledWith(2, 'create_app', { - source: 'original', + source: 'studio_template_list', app_mode: 'workflow', time: expect.stringMatching(/^\d{2}-\d{2}-\d{2}:\d{2}:\d{2}$/), + template_id: 'template-1', }) }) @@ -152,16 +187,19 @@ describe('create-app-tracking', () => { window.history.replaceState({}, '', '/explore') - trackCreateApp({ appMode: AppModeEnum.CHAT }) + trackCreateApp({ source: 'explore_template_preview', appMode: AppModeEnum.CHAT, templateId: 'template-2' }) expect(amplitude.trackEvent).toHaveBeenCalledWith('create_app', { source: 'external', + app_mode: 'chatflow', + time: expect.stringMatching(/^\d{2}-\d{2}-\d{2}:\d{2}:\d{2}$/), + template_id: 'template-2', utm_source: 'linkedin', utm_campaign: 'agent-launch', }) }) - it('should fall back to the original payload when window is unavailable', () => { + it('should fall back to the provided source when window is unavailable', () => { const originalWindow = globalThis.window try { @@ -170,10 +208,10 @@ describe('create-app-tracking', () => { value: undefined, }) - trackCreateApp({ appMode: AppModeEnum.AGENT_CHAT }) + trackCreateApp({ source: 'studio_blank', appMode: AppModeEnum.AGENT_CHAT }) expect(amplitude.trackEvent).toHaveBeenCalledWith('create_app', { - source: 'original', + source: 'studio_blank', app_mode: 'agent', time: expect.stringMatching(/^\d{2}-\d{2}-\d{2}:\d{2}:\d{2}$/), }) @@ -185,5 +223,29 @@ describe('create-app-tracking', () => { }) } }) + + it('should read, normalize, and consume snake_case sessionStorage attribution', () => { + window.sessionStorage.setItem('create_app_external_attribution', JSON.stringify({ + utm_source: 'twitter', + utm_campaign: 'launch-week', + })) + + trackCreateApp({ source: 'studio_blank', appMode: AppModeEnum.CHAT }) + + expect(amplitude.trackEvent).toHaveBeenCalledWith('create_app', { + source: 'external', + app_mode: 'chatflow', + time: expect.stringMatching(/^\d{2}-\d{2}-\d{2}:\d{2}:\d{2}$/), + utm_source: 'twitter/x', + utm_campaign: 'launch-week', + }) + expect(window.sessionStorage.getItem('create_app_external_attribution')).toBeNull() + }) + + it('should not track external source without remembered attribution', () => { + trackCreateApp({ source: 'external', appMode: AppModeEnum.WORKFLOW, templateId: 'template-1' }) + + expect(amplitude.trackEvent).not.toHaveBeenCalled() + }) }) }) diff --git a/web/utils/create-app-tracking.ts b/web/utils/create-app-tracking.ts index f56e2c13fa..800171c894 100644 --- a/web/utils/create-app-tracking.ts +++ b/web/utils/create-app-tracking.ts @@ -6,12 +6,13 @@ const CREATE_APP_EXTERNAL_ATTRIBUTION_STORAGE_KEY = 'create_app_external_attribu const CREATE_APP_EXTERNAL_ATTRIBUTION_QUERY_KEYS = ['utm_source', 'utm_campaign', 'slug'] as const const EXTERNAL_UTM_SOURCE_MAP = { - blog: 'blog', - dify_blog: 'blog', - linkedin: 'linkedin', - newsletter: 'blog', - twitter: 'twitter/x', - x: 'twitter/x', + 'blog': 'blog', + 'dify_blog': 'blog', + 'linkedin': 'linkedin', + 'newsletter': 'blog', + 'twitter': 'twitter/x', + 'twitter/x': 'twitter/x', + 'x': 'twitter/x', } as const type SearchParamReader = { @@ -20,8 +21,19 @@ type SearchParamReader = { type OriginalCreateAppMode = 'workflow' | 'chatflow' | 'agent' -type TrackCreateAppParams = { +type CreateAppSource + = | 'external' + | 'explore_template_list' + | 'explore_template_preview' + | 'studio_blank' + | 'studio_template_list' + | 'studio_template_preview' + | 'studio_upload' + +export type TrackCreateAppParams = { + source: CreateAppSource appMode: AppModeEnum + templateId?: string } type ExternalCreateAppAttribution = { @@ -173,7 +185,20 @@ export const extractExternalCreateAppAttribution = ({ } const readRememberedExternalCreateAppAttribution = (): ExternalCreateAppAttribution | null => { - return parseJSONRecord(window.sessionStorage.getItem(CREATE_APP_EXTERNAL_ATTRIBUTION_STORAGE_KEY)) as ExternalCreateAppAttribution | null + const attribution = parseJSONRecord(window.sessionStorage.getItem(CREATE_APP_EXTERNAL_ATTRIBUTION_STORAGE_KEY)) + const utmSource = mapExternalUtmSource( + getObjectStringValue(attribution?.utmSource) ?? getObjectStringValue(attribution?.utm_source), + ) + + if (!utmSource) + return null + + const utmCampaign = getObjectStringValue(attribution?.utmCampaign) ?? getObjectStringValue(attribution?.utm_campaign) + + return { + utmSource, + ...(utmCampaign ? { utmCampaign } : {}), + } } const writeRememberedExternalCreateAppAttribution = (attribution: ExternalCreateAppAttribution) => { @@ -214,18 +239,22 @@ export const buildCreateAppEventPayload = ( externalAttribution?: ExternalCreateAppAttribution | null, currentTime = new Date(), ) => { - if (externalAttribution) { - return { - source: 'external', - utm_source: externalAttribution.utmSource, - ...(externalAttribution.utmCampaign ? { utm_campaign: externalAttribution.utmCampaign } : {}), - } satisfies Record - } + const source = externalAttribution ? 'external' : params.source + + if (source === 'external' && !externalAttribution) + return null return { - source: 'original', + source, app_mode: mapOriginalCreateAppMode(params.appMode), time: formatCreateAppTime(currentTime), + ...(params.templateId ? { template_id: params.templateId } : {}), + ...(externalAttribution + ? { + utm_source: externalAttribution.utmSource, + ...(externalAttribution.utmCampaign ? { utm_campaign: externalAttribution.utmCampaign } : {}), + } + : {}), } satisfies Record } @@ -233,6 +262,9 @@ export const trackCreateApp = (params: TrackCreateAppParams) => { const externalAttribution = resolveCurrentExternalCreateAppAttribution() const payload = buildCreateAppEventPayload(params, externalAttribution) + if (!payload) + return + if (externalAttribution) clearRememberedExternalCreateAppAttribution() From 7f392b6950c2e6fd1b5b7f746badb3b4581d705d Mon Sep 17 00:00:00 2001 From: -LAN- Date: Tue, 19 May 2026 13:27:26 +0800 Subject: [PATCH 2/7] chore(release): bump version to 1.14.2 (#36313) Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- api/pyproject.toml | 2 +- api/uv.lock | 2 +- docker/docker-compose-template.yaml | 10 +++++----- docker/docker-compose.yaml | 10 +++++----- web/package.json | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/api/pyproject.toml b/api/pyproject.toml index 3ddc1e30a9..95fc38e2c8 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "dify-api" -version = "1.14.1" +version = "1.14.2" requires-python = "~=3.12.0" dependencies = [ diff --git a/api/uv.lock b/api/uv.lock index bb150e8cf3..5ffda81f39 100644 --- a/api/uv.lock +++ b/api/uv.lock @@ -1323,7 +1323,7 @@ docs = [ [[package]] name = "dify-api" -version = "1.14.1" +version = "1.14.2" source = { virtual = "." } dependencies = [ { name = "aliyun-log-python-sdk" }, diff --git a/docker/docker-compose-template.yaml b/docker/docker-compose-template.yaml index 9d5018f6e7..d3cff12a4b 100644 --- a/docker/docker-compose-template.yaml +++ b/docker/docker-compose-template.yaml @@ -220,7 +220,7 @@ services: # API service api: <<: *shared-api-worker-config - image: langgenius/dify-api:1.14.1 + image: langgenius/dify-api:1.14.2 environment: MODE: api SENTRY_DSN: ${API_SENTRY_DSN:-} @@ -264,7 +264,7 @@ services: # WebSocket service for workflow collaboration. api_websocket: <<: *shared-api-worker-config - image: langgenius/dify-api:1.14.1 + image: langgenius/dify-api:1.14.2 profiles: - collaboration environment: @@ -290,7 +290,7 @@ services: # The Celery worker for processing all queues (dataset, workflow, mail, etc.) worker: <<: *shared-worker-config - image: langgenius/dify-api:1.14.1 + image: langgenius/dify-api:1.14.2 environment: MODE: worker SENTRY_DSN: ${API_SENTRY_DSN:-} @@ -333,7 +333,7 @@ services: # Celery beat for scheduling periodic tasks. worker_beat: <<: *shared-worker-beat-config - image: langgenius/dify-api:1.14.1 + image: langgenius/dify-api:1.14.2 environment: MODE: beat depends_on: @@ -366,7 +366,7 @@ services: # Frontend web application. web: - image: langgenius/dify-web:1.14.1 + image: langgenius/dify-web:1.14.2 restart: always env_file: - path: ./envs/core-services/web.env diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 63df56ddd5..da94f7f16c 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -226,7 +226,7 @@ services: # API service api: <<: *shared-api-worker-config - image: langgenius/dify-api:1.14.1 + image: langgenius/dify-api:1.14.2 environment: MODE: api SENTRY_DSN: ${API_SENTRY_DSN:-} @@ -270,7 +270,7 @@ services: # WebSocket service for workflow collaboration. api_websocket: <<: *shared-api-worker-config - image: langgenius/dify-api:1.14.1 + image: langgenius/dify-api:1.14.2 profiles: - collaboration environment: @@ -296,7 +296,7 @@ services: # The Celery worker for processing all queues (dataset, workflow, mail, etc.) worker: <<: *shared-worker-config - image: langgenius/dify-api:1.14.1 + image: langgenius/dify-api:1.14.2 environment: MODE: worker SENTRY_DSN: ${API_SENTRY_DSN:-} @@ -339,7 +339,7 @@ services: # Celery beat for scheduling periodic tasks. worker_beat: <<: *shared-worker-beat-config - image: langgenius/dify-api:1.14.1 + image: langgenius/dify-api:1.14.2 environment: MODE: beat depends_on: @@ -372,7 +372,7 @@ services: # Frontend web application. web: - image: langgenius/dify-web:1.14.1 + image: langgenius/dify-web:1.14.2 restart: always env_file: - path: ./envs/core-services/web.env diff --git a/web/package.json b/web/package.json index be373a1e68..9f8a4f095c 100644 --- a/web/package.json +++ b/web/package.json @@ -1,7 +1,7 @@ { "name": "dify-web", "type": "module", - "version": "1.14.1", + "version": "1.14.2", "private": true, "imports": { "#i18n": { From 04d62867af40ebe30e3fefb74fab5245452ca47c Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Tue, 19 May 2026 13:38:57 +0800 Subject: [PATCH 3/7] feat(dify-ui): add shared form primitives (#36334) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- api/controllers/console/extension.py | 24 +- .../console/test_api_based_extension.py | 126 ++++++++++ .../controllers/console/test_extension.py | 14 +- eslint-suppressions.json | 5 - packages/dify-ui/README.md | 47 +++- packages/dify-ui/package.json | 12 + .../checkbox-group/__tests__/index.spec.tsx | 32 +-- .../src/checkbox-group/index.stories.tsx | 35 +-- .../dify-ui/src/checkbox/index.stories.tsx | 2 +- packages/dify-ui/src/dialog/index.stories.tsx | 85 +++++++ .../src/field/__tests__/index.spec.tsx | 126 ++++++++++ packages/dify-ui/src/field/index.stories.tsx | 111 +++++++++ packages/dify-ui/src/field/index.tsx | 154 ++++++++++++ .../src/fieldset/__tests__/index.spec.tsx | 21 ++ .../dify-ui/src/fieldset/index.stories.tsx | 56 +++++ packages/dify-ui/src/fieldset/index.tsx | 41 ++++ .../dify-ui/src/form/__tests__/index.spec.tsx | 53 +++++ packages/dify-ui/src/form/index.stories.tsx | 70 ++++++ packages/dify-ui/src/form/index.tsx | 11 + .../src/number-field/index.stories.tsx | 2 +- packages/dify-ui/src/select/index.stories.tsx | 2 +- packages/dify-ui/src/slider/index.stories.tsx | 2 +- packages/dify-ui/src/switch/index.stories.tsx | 2 +- packages/dify-ui/vite.config.ts | 3 + .../external-data-tool-modal.spec.tsx | 2 +- .../tools/external-data-tool-modal.tsx | 2 +- .../checkbox-list/__tests__/index.spec.tsx | 2 + .../components/base/checkbox-list/index.tsx | 224 ++++++++++-------- .../moderation-setting-modal.spec.tsx | 2 +- .../moderation/moderation-setting-modal.tsx | 2 +- .../base/form/components/base/base-field.tsx | 1 + .../account-setting/__tests__/index.spec.tsx | 24 +- .../__tests__/empty.spec.tsx | 2 +- .../__tests__/index.spec.tsx | 115 ++++++--- .../__tests__/item.spec.tsx | 63 +++-- .../__tests__/modal.spec.tsx | 145 +++++++----- .../__tests__/selector.spec.tsx | 62 +++-- .../api-based-extension-page/empty.tsx | 4 +- .../api-based-extension-page/index.tsx | 59 +++-- .../api-based-extension-page/item.tsx | 46 ++-- .../api-based-extension-page/modal.tsx | 188 +++++++++------ .../api-based-extension-page/selector.tsx | 26 +- .../header/account-setting/index.tsx | 2 +- .../__tests__/index.spec.tsx | 14 ++ .../install-from-github/index.tsx | 41 ++-- .../steps/selectPackage.tsx | 143 ++++++----- .../_base/components/form-input-item.tsx | 1 + web/service/client.spec.ts | 101 +++++++- web/service/client.ts | 40 ++++ web/service/common.ts | 25 -- web/service/use-common.ts | 9 - 51 files changed, 1824 insertions(+), 557 deletions(-) create mode 100644 api/tests/test_containers_integration_tests/controllers/console/test_api_based_extension.py create mode 100644 packages/dify-ui/src/field/__tests__/index.spec.tsx create mode 100644 packages/dify-ui/src/field/index.stories.tsx create mode 100644 packages/dify-ui/src/field/index.tsx create mode 100644 packages/dify-ui/src/fieldset/__tests__/index.spec.tsx create mode 100644 packages/dify-ui/src/fieldset/index.stories.tsx create mode 100644 packages/dify-ui/src/fieldset/index.tsx create mode 100644 packages/dify-ui/src/form/__tests__/index.spec.tsx create mode 100644 packages/dify-ui/src/form/index.stories.tsx create mode 100644 packages/dify-ui/src/form/index.tsx diff --git a/api/controllers/console/extension.py b/api/controllers/console/extension.py index 0c9a93c1cd..e53bb95c24 100644 --- a/api/controllers/console/extension.py +++ b/api/controllers/console/extension.py @@ -70,6 +70,21 @@ def _serialize_api_based_extension(extension: APIBasedExtension) -> dict[str, An return APIBasedExtensionResponse.model_validate(extension, from_attributes=True).model_dump(mode="json") +def _serialize_saved_api_based_extension(extension: APIBasedExtension, api_key: str) -> dict[str, Any]: + """Serialize a saved extension with the plaintext key used for response masking only. + + APIBasedExtensionService.save mutates the ORM object to hold the encrypted token before returning it. The response + contract, however, should match list/detail responses, where api_key is masked from the decrypted token. + """ + return APIBasedExtensionResponse( + id=extension.id, + name=extension.name, + api_endpoint=extension.api_endpoint, + api_key=api_key, + created_at=to_timestamp(extension.created_at), + ).model_dump(mode="json") + + @console_ns.route("/code-based-extension") class CodeBasedExtensionAPI(Resource): @console_ns.doc("get_code_based_extension") @@ -125,7 +140,7 @@ class APIBasedExtensionAPI(Resource): api_key=payload.api_key, ) - return _serialize_api_based_extension(APIBasedExtensionService.save(extension_data)) + return _serialize_saved_api_based_extension(APIBasedExtensionService.save(extension_data), payload.api_key), 201 @console_ns.route("/api-based-extension/") @@ -160,14 +175,19 @@ class APIBasedExtensionDetailAPI(Resource): extension_data_from_db = APIBasedExtensionService.get_with_tenant_id(current_tenant_id, api_based_extension_id) payload = APIBasedExtensionPayload.model_validate(console_ns.payload or {}) + api_key_for_response = extension_data_from_db.api_key extension_data_from_db.name = payload.name extension_data_from_db.api_endpoint = payload.api_endpoint if payload.api_key != HIDDEN_VALUE: extension_data_from_db.api_key = payload.api_key + api_key_for_response = payload.api_key - return _serialize_api_based_extension(APIBasedExtensionService.save(extension_data_from_db)) + return _serialize_saved_api_based_extension( + APIBasedExtensionService.save(extension_data_from_db), + api_key_for_response, + ) @console_ns.doc("delete_api_based_extension") @console_ns.doc(description="Delete API-based extension") diff --git a/api/tests/test_containers_integration_tests/controllers/console/test_api_based_extension.py b/api/tests/test_containers_integration_tests/controllers/console/test_api_based_extension.py new file mode 100644 index 0000000000..e7852b8fe1 --- /dev/null +++ b/api/tests/test_containers_integration_tests/controllers/console/test_api_based_extension.py @@ -0,0 +1,126 @@ +"""Integration tests for console API-based extension endpoints using testcontainers.""" + +from __future__ import annotations + +from unittest.mock import patch + +import pytest +from flask.testing import FlaskClient +from sqlalchemy.orm import Session + +from constants import HIDDEN_VALUE +from libs.rsa import generate_key_pair +from models import Tenant +from tests.test_containers_integration_tests.controllers.console.helpers import ( + authenticate_console_client, + create_console_account_and_tenant, +) + + +def _masked_api_key(api_key: str) -> str: + if len(api_key) <= 8: + return api_key[0] + "******" + api_key[-1] + return api_key[:3] + "******" + api_key[-3:] + + +@pytest.fixture +def api_extension_client( + db_session_with_containers: Session, + test_client_with_containers: FlaskClient, +) -> tuple[FlaskClient, dict[str, str], Tenant]: + account, tenant = create_console_account_and_tenant(db_session_with_containers) + tenant.encrypt_public_key = generate_key_pair(tenant.id) + db_session_with_containers.commit() + + headers = authenticate_console_client(test_client_with_containers, account) + return test_client_with_containers, headers, tenant + + +@pytest.fixture(autouse=True) +def mock_api_based_extension_ping(): + with patch("services.api_based_extension_service.APIBasedExtensionRequestor") as requestor: + requestor.return_value.request.return_value = {"result": "pong"} + yield requestor + + +def test_create_response_masks_plaintext_api_key( + api_extension_client: tuple[FlaskClient, dict[str, str], Tenant], +) -> None: + client, headers, _ = api_extension_client + api_key = "plain-secret-12345" + + response = client.post( + "/console/api/api-based-extension", + headers=headers, + json={ + "name": "Docs API", + "api_endpoint": "https://docs.example.com/hook", + "api_key": api_key, + }, + ) + + assert response.status_code == 201 + assert response.json is not None + assert response.json["api_key"] == _masked_api_key(api_key) + + +def test_update_response_masks_new_plaintext_api_key( + api_extension_client: tuple[FlaskClient, dict[str, str], Tenant], +) -> None: + client, headers, _ = api_extension_client + new_api_key = "new-secret-67890" + create_response = client.post( + "/console/api/api-based-extension", + headers=headers, + json={ + "name": "Docs API", + "api_endpoint": "https://docs.example.com/hook", + "api_key": "old-secret-12345", + }, + ) + assert create_response.json is not None + + update_response = client.post( + f"/console/api/api-based-extension/{create_response.json['id']}", + headers=headers, + json={ + "name": "Docs API Updated", + "api_endpoint": "https://docs.example.com/v2", + "api_key": new_api_key, + }, + ) + + assert update_response.status_code == 200 + assert update_response.json is not None + assert update_response.json["api_key"] == _masked_api_key(new_api_key) + + +def test_update_response_masks_existing_plaintext_api_key_when_hidden_value_is_submitted( + api_extension_client: tuple[FlaskClient, dict[str, str], Tenant], +) -> None: + client, headers, _ = api_extension_client + existing_api_key = "old-secret-12345" + create_response = client.post( + "/console/api/api-based-extension", + headers=headers, + json={ + "name": "Docs API", + "api_endpoint": "https://docs.example.com/hook", + "api_key": existing_api_key, + }, + ) + assert create_response.json is not None + + update_response = client.post( + f"/console/api/api-based-extension/{create_response.json['id']}", + headers=headers, + json={ + "name": "Docs API Updated", + "api_endpoint": "https://docs.example.com/v2", + "api_key": HIDDEN_VALUE, + }, + ) + + assert update_response.status_code == 200 + assert update_response.json is not None + assert update_response.json["api_key"] == _masked_api_key(existing_api_key) diff --git a/api/tests/unit_tests/controllers/console/test_extension.py b/api/tests/unit_tests/controllers/console/test_extension.py index 0d1fb39348..60a7ea5bb5 100644 --- a/api/tests/unit_tests/controllers/console/test_extension.py +++ b/api/tests/unit_tests/controllers/console/test_extension.py @@ -44,6 +44,12 @@ def _make_extension( return extension +def _masked_api_key(api_key: str) -> str: + if len(api_key) <= 8: + return api_key[0] + "******" + api_key[-1] + return api_key[:3] + "******" + api_key[-3:] + + @pytest.fixture(autouse=True) def _mock_console_guards(monkeypatch: pytest.MonkeyPatch) -> MagicMock: """Bypass console decorators so handlers can run in isolation.""" @@ -114,7 +120,7 @@ def test_api_based_extension_get_returns_tenant_extensions(app: Flask, monkeypat def test_api_based_extension_post_creates_extension(app: Flask, monkeypatch: pytest.MonkeyPatch): - saved_extension = _make_extension(name="Docs API", api_key="saved-secret") + saved_extension = _make_extension(name="Docs API", api_key="encrypted-token-from-save") save_mock = MagicMock(return_value=saved_extension) monkeypatch.setattr("controllers.console.extension.APIBasedExtensionService.save", save_mock) @@ -125,7 +131,7 @@ def test_api_based_extension_post_creates_extension(app: Flask, monkeypatch: pyt } with app.test_request_context("/console/api/api-based-extension", method="POST", json=payload): - response = APIBasedExtensionAPI().post() + response, status = APIBasedExtensionAPI().post() args, _ = save_mock.call_args created_extension: APIBasedExtension = args[0] @@ -133,7 +139,9 @@ def test_api_based_extension_post_creates_extension(app: Flask, monkeypatch: pyt assert created_extension.name == payload["name"] assert created_extension.api_endpoint == payload["api_endpoint"] assert created_extension.api_key == payload["api_key"] + assert status == 201 assert response["name"] == saved_extension.name + assert response["api_key"] == _masked_api_key(payload["api_key"]) save_mock.assert_called_once() @@ -183,6 +191,7 @@ def test_api_based_extension_detail_post_keeps_hidden_api_key(app: Flask, monkey assert existing_extension.api_key == "keep-me" save_mock.assert_called_once_with(existing_extension) assert response["name"] == payload["name"] + assert response["api_key"] == _masked_api_key("keep-me") def test_api_based_extension_detail_post_updates_api_key_when_provided(app: Flask, monkeypatch: pytest.MonkeyPatch): @@ -212,6 +221,7 @@ def test_api_based_extension_detail_post_updates_api_key_when_provided(app: Flas assert existing_extension.api_key == "new-secret" save_mock.assert_called_once_with(existing_extension) assert response["name"] == payload["name"] + assert response["api_key"] == _masked_api_key(payload["api_key"]) def test_api_based_extension_detail_delete_removes_extension(app: Flask, monkeypatch: pytest.MonkeyPatch): diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 07504d2754..800bbc746b 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -4642,11 +4642,6 @@ "count": 3 } }, - "web/service/client.spec.ts": { - "next/no-assign-module-variable": { - "count": 1 - } - }, "web/service/common.ts": { "ts/no-explicit-any": { "count": 29 diff --git a/packages/dify-ui/README.md b/packages/dify-ui/README.md index 010fb3e56d..8592622e6f 100644 --- a/packages/dify-ui/README.md +++ b/packages/dify-ui/README.md @@ -29,6 +29,8 @@ import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { Dialog, DialogContent, DialogTrigger } from '@langgenius/dify-ui/dialog' import { Drawer, DrawerPopup, DrawerTrigger } from '@langgenius/dify-ui/drawer' +import { FieldControl, FieldLabel, FieldRoot } from '@langgenius/dify-ui/field' +import { Form } from '@langgenius/dify-ui/form' import { Popover, PopoverContent, PopoverTrigger } from '@langgenius/dify-ui/popover' import '@langgenius/dify-ui/styles.css' // once, in the app root ``` @@ -37,18 +39,48 @@ Importing from `@langgenius/dify-ui` (no subpath) is intentionally not supported ## Primitives -| Category | Subpath | Notes | -| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | -| Overlay | `./alert-dialog`, `./autocomplete`, `./combobox`, `./context-menu`, `./dialog`, `./drawer`, `./dropdown-menu`, `./popover`, `./select`, `./toast`, `./tooltip` | Portalled. See [Overlay & portal contract] below. | -| Form | `./autocomplete`, `./combobox`, `./number-field`, `./slider`, `./switch` | Controlled / uncontrolled per Base UI defaults. | -| Layout | `./scroll-area` | Custom-styled scrollbar over the host viewport. | -| Media | `./avatar`, `./button` | Button exposes `cva` variants. | +| Category | Subpath | Notes | +| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | +| Overlay | `./alert-dialog`, `./autocomplete`, `./combobox`, `./context-menu`, `./dialog`, `./drawer`, `./dropdown-menu`, `./popover`, `./select`, `./toast`, `./tooltip` | Portalled. See [Overlay & portal contract] below. | +| Form | `./form`, `./field`, `./fieldset`, `./checkbox`, `./checkbox-group`, `./number-field`, `./select`, `./slider`, `./switch` | Native form boundary, field semantics, and controls. | +| Layout | `./scroll-area` | Custom-styled scrollbar over the host viewport. | +| Media | `./avatar`, `./button` | Button exposes `cva` variants. | Utilities: - `./cn` — `clsx` + `tailwind-merge` wrapper. Use this for conditional class composition. - `./styles.css` — the one CSS entry that ships the design tokens, theme variables, and project utilities/components. Import it once from the app root. +## Form contract + +Dify UI's form primitives are a Base UI composition layer for native form semantics, field accessibility, and design-system styling. They are intentionally not a form state-management framework. See the upstream [Base UI Form], [Base UI Field], and [Base UI Fieldset] docs for the underlying component contracts. + +Use `Form` for the submit boundary. It renders a native `
`, preserves Enter-to-submit and submit-button behavior, and adds Base UI's `onFormSubmit`, `errors`, `actionsRef`, and `validationMode` APIs for structured values and consolidated field validation. Prefer it over a bare `` when the form is composed with Dify UI fields. + +Use `FieldRoot` for each named field. A field must have a stable `name`, a visible `FieldLabel`, and either a `FieldControl` or another control that participates in the same Base UI field context. `FieldLabel`, `FieldDescription`, and `FieldError` provide the label and message relationships that screen readers need, while the Dify wrapper adds the default Form Input Set styling from the design system. + +Use `FieldsetRoot` and `FieldsetLegend` when one field is represented by a group of related controls, such as checkbox groups, radio groups, or multi-thumb sliders. Compose group controls with the Base UI pattern: + +```tsx + + }> + Allowed network protocols + + + + HTTPS + + + + +``` + +`FieldsetRoot` provides the group semantics and legend relationship. It does not own the interactive state of the grouped control. Pass `disabled`, `value`, `defaultValue`, and change handlers to the actual group primitive (`CheckboxGroup`, radio group, slider root, etc.) instead of relying on the fieldset wrapper to manage them. + +For complex business forms, keep state ownership outside these primitives. TanStack Form, zod, server validation, dialog reset behavior, and schema-driven rendering belong to the feature layer in `web/`; they should pass `name`, `invalid`, `dirty`, `touched`, `value`, `onValueChange`, and errors into these primitives rather than replacing the field semantics. + +Migration rule for `web/`: if a UI has a save/submit action, do not leave it as unrelated `Input` and `Button` pieces. Give it a real submit boundary with `Form` or a native ``, attach visible field names through `FieldLabel`, expose helper/error text through `FieldDescription` / `FieldError`, and keep non-submit buttons as `type="button"`. + ## Tailwind CSS v4 integration This package uses Tailwind CSS v4's CSS-first configuration model. Consumers should import Tailwind from their own root stylesheet, then import this package's CSS entry: @@ -138,6 +170,9 @@ See `[AGENTS.md](./AGENTS.md)` for: - Application state (`jotai`, `zustand`), data fetching (`ky`, `@tanstack/react-query`, `@orpc/*`), i18n (`next-i18next` / `react-i18next`), and routing (`next`) all live in `web/`. This package has zero dependencies on them and must stay that way so it can eventually be consumed by other apps or extracted. - Business components (chat, workflow, dataset views, etc.). Those belong in `web/app/components/...`. +[Base UI Field]: https://base-ui.com/react/components/field +[Base UI Fieldset]: https://base-ui.com/react/components/fieldset +[Base UI Form]: https://base-ui.com/react/components/form [Base UI Portal]: https://base-ui.com/react/overview/quick-start#portals [Base UI]: https://base-ui.com/react [Overlay & portal contract]: #overlay--portal-contract diff --git a/packages/dify-ui/package.json b/packages/dify-ui/package.json index ee20896570..d58fb954e0 100644 --- a/packages/dify-ui/package.json +++ b/packages/dify-ui/package.json @@ -53,6 +53,18 @@ "types": "./src/dropdown-menu/index.tsx", "import": "./src/dropdown-menu/index.tsx" }, + "./field": { + "types": "./src/field/index.tsx", + "import": "./src/field/index.tsx" + }, + "./fieldset": { + "types": "./src/fieldset/index.tsx", + "import": "./src/fieldset/index.tsx" + }, + "./form": { + "types": "./src/form/index.tsx", + "import": "./src/form/index.tsx" + }, "./meter": { "types": "./src/meter/index.tsx", "import": "./src/meter/index.tsx" diff --git a/packages/dify-ui/src/checkbox-group/__tests__/index.spec.tsx b/packages/dify-ui/src/checkbox-group/__tests__/index.spec.tsx index b5d8e65c99..4e98f42861 100644 --- a/packages/dify-ui/src/checkbox-group/__tests__/index.spec.tsx +++ b/packages/dify-ui/src/checkbox-group/__tests__/index.spec.tsx @@ -1,8 +1,8 @@ -import { Field } from '@base-ui/react/field' -import { Fieldset } from '@base-ui/react/fieldset' import { useState } from 'react' import { render } from 'vitest-browser-react' import { Checkbox } from '../../checkbox' +import { FieldItem, FieldLabel, FieldRoot } from '../../field' +import { FieldsetLegend, FieldsetRoot } from '../../fieldset' import { CheckboxGroup } from '../index' const asHTMLElement = (element: HTMLElement | SVGElement) => element as HTMLElement @@ -43,26 +43,26 @@ describe('CheckboxGroup', () => { }) }) - it('should compose with Base UI Field and Fieldset without losing labels', async () => { + it('should compose with Dify UI Field and Fieldset without losing labels', async () => { const onValueChange = vi.fn() const screen = await render( - - }> - Features - - + + }> + Features + + Search - - - - + + + + Analytics - - - - , + + + + , ) const analytics = screen.getByRole('checkbox', { name: 'Analytics' }) diff --git a/packages/dify-ui/src/checkbox-group/index.stories.tsx b/packages/dify-ui/src/checkbox-group/index.stories.tsx index 623ae62c98..ea4e638bab 100644 --- a/packages/dify-ui/src/checkbox-group/index.stories.tsx +++ b/packages/dify-ui/src/checkbox-group/index.stories.tsx @@ -1,12 +1,17 @@ import type { Meta, StoryObj } from '@storybook/react-vite' -import { Field } from '@base-ui/react/field' -import { Fieldset } from '@base-ui/react/fieldset' import { useId, useState } from 'react' import { CheckboxGroup } from '.' import { Checkbox } from '../checkbox' +import { + FieldDescription, + FieldItem, + FieldLabel, + FieldRoot, +} from '../field' +import { FieldsetLegend, FieldsetRoot } from '../fieldset' const meta = { - title: 'Base/UI/CheckboxGroup', + title: 'Base/Form/CheckboxGroup', component: CheckboxGroup, parameters: { layout: 'centered', @@ -75,11 +80,11 @@ function DynamicFormFieldDemo() { const [selected, setSelected] = useState(['markdown']) return ( - - + + This mirrors Dify dynamic form fields where checkbox options are controlled by schema and persisted as a string array. - - + )} > - + Allowed file types - + {options.map(option => ( - - + + {option.label} - - + + ))} - - + + ) } diff --git a/packages/dify-ui/src/checkbox/index.stories.tsx b/packages/dify-ui/src/checkbox/index.stories.tsx index 97cd1a1d60..adf4f28388 100644 --- a/packages/dify-ui/src/checkbox/index.stories.tsx +++ b/packages/dify-ui/src/checkbox/index.stories.tsx @@ -7,7 +7,7 @@ import { } from '.' const meta = { - title: 'Base/UI/Checkbox', + title: 'Base/Form/Checkbox', component: Checkbox, parameters: { layout: 'centered', diff --git a/packages/dify-ui/src/dialog/index.stories.tsx b/packages/dify-ui/src/dialog/index.stories.tsx index f9caa0d8c5..24556a11e7 100644 --- a/packages/dify-ui/src/dialog/index.stories.tsx +++ b/packages/dify-ui/src/dialog/index.stories.tsx @@ -9,6 +9,8 @@ import { DialogTrigger, } from '.' import { Button } from '../button' +import { FieldControl, FieldDescription, FieldError, FieldLabel, FieldRoot } from '../field' +import { Form } from '../form' const triggerButtonClassName = 'rounded-lg border border-divider-subtle bg-components-button-secondary-bg px-3 py-1.5 text-sm text-text-secondary shadow-xs hover:bg-state-base-hover' @@ -139,6 +141,89 @@ export const Controlled: Story = { render: () => , } +type ApiExtensionFormValues = { + name: string + endpoint: string + apiKey: string +} + +const FormDialogDemo = () => { + const [open, setOpen] = useState(false) + + return ( + + } + > + Configure API extension + + + +
+ + Configure API extension + + + Save the endpoint and credentials used by this workspace integration. + +
+ + className="grid gap-4 pt-5" + onFormSubmit={() => setOpen(false)} + > + + Name + + Name is required. + + + Endpoint + + + + View API extension docs + + + Endpoint is required. + Enter a valid URL. + + { + if (typeof value === 'string' && value.length > 0 && value.length < 5) + return 'API key must be at least 5 characters.' + + return null + }} + > + API key + + API key is required. + + +
+ + +
+ +
+
+ ) +} + +export const FormDialog: Story = { + render: () => , +} + export const ScrollingContent: Story = { render: () => ( diff --git a/packages/dify-ui/src/field/__tests__/index.spec.tsx b/packages/dify-ui/src/field/__tests__/index.spec.tsx new file mode 100644 index 0000000000..9569212360 --- /dev/null +++ b/packages/dify-ui/src/field/__tests__/index.spec.tsx @@ -0,0 +1,126 @@ +import { render } from 'vitest-browser-react' +import { Checkbox } from '../../checkbox' +import { CheckboxGroup } from '../../checkbox-group' +import { FieldsetLegend, FieldsetRoot } from '../../fieldset' +import { Form } from '../../form' +import { + FieldControl, + FieldDescription, + FieldError, + FieldItem, + FieldLabel, + FieldRoot, +} from '../index' + +const asHTMLElement = (element: HTMLElement | SVGElement) => element as HTMLElement + +describe('Field primitives', () => { + it('should associate label, description, and error with the control', async () => { + const onFormSubmit = vi.fn() + const screen = await render( +
+ + Email + + Used for account notifications. + Email is required. + + +
, + ) + + const input = screen.getByRole('textbox', { name: 'Email' }) + const label = asHTMLElement(screen.getByText('Email').element()) + const description = asHTMLElement(screen.getByText('Used for account notifications.').element()) + + await expect.element(input).toHaveAccessibleDescription('Used for account notifications.') + expect(label.tagName).toBe('LABEL') + expect(label).toHaveAttribute('for', asHTMLElement(input.element()).id) + expect(asHTMLElement(input.element()).getAttribute('aria-describedby')?.split(' ')).toContain(description.id) + await expect.element(input).toHaveClass('rounded-lg', 'system-sm-regular') + await expect.element(screen.getByText('Email')).toHaveClass('py-1', 'system-sm-medium') + await expect.element(screen.getByText('Used for account notifications.')).toHaveClass('py-0.5', 'body-xs-regular') + + asHTMLElement(screen.getByRole('button', { name: 'Save' }).element()).click() + + await vi.waitFor(async () => { + const error = asHTMLElement(screen.getByText('Email is required.').element()) + await expect.element(screen.getByText('Email is required.')).toBeInTheDocument() + await expect.element(input).toHaveAttribute('aria-invalid', 'true') + await expect.element(input).toHaveClass('data-invalid:border-components-input-border-destructive') + expect(asHTMLElement(input.element()).getAttribute('aria-describedby')?.split(' ')).toEqual( + expect.arrayContaining([description.id, error.id]), + ) + }) + expect(onFormSubmit).not.toHaveBeenCalled() + }) + + it('should submit valid field values through Base UI Form', async () => { + const onFormSubmit = vi.fn() + const screen = await render( +
+ + API key + + + +
, + ) + + asHTMLElement(screen.getByRole('button', { name: 'Save' }).element()).click() + + expect(onFormSubmit).toHaveBeenCalledTimes(1) + expect(onFormSubmit.mock.calls[0]?.[0]).toMatchObject({ apiKey: 'sk-test' }) + }) + + it('should support external invalid state without requiring FieldControl', async () => { + const screen = await render( + + }> + Features + + + + Search + + + Choose at least one feature. + + , + ) + + await expect.element(screen.getByRole('group', { name: 'Features' })).toBeInTheDocument() + await expect.element(screen.getByRole('checkbox', { name: 'Search' })).toHaveAttribute('aria-checked', 'true') + await expect.element(screen.getByText('Choose at least one feature.')).toHaveClass('text-text-destructive', 'body-xs-regular') + }) + + it('should apply design-system control sizes when requested', async () => { + const screen = await render( + <> + + Name + + + + Alias + + + , + ) + + await expect.element(screen.getByRole('textbox', { name: 'Name' })).toHaveClass('rounded-[10px]', 'py-[7px]', 'system-md-regular') + await expect.element(screen.getByRole('textbox', { name: 'Alias' })).toHaveClass('rounded-md', 'py-[3px]', 'system-xs-regular') + }) + + it('should expose the design-system read-only state', async () => { + const screen = await render( + + Token + + , + ) + + await expect.element(screen.getByRole('textbox', { name: 'Token' })).toHaveAttribute('readonly') + await expect.element(screen.getByRole('textbox', { name: 'Token' })).toHaveClass('read-only:cursor-default', 'read-only:focus:border-transparent') + }) +}) diff --git a/packages/dify-ui/src/field/index.stories.tsx b/packages/dify-ui/src/field/index.stories.tsx new file mode 100644 index 0000000000..84b6ac977d --- /dev/null +++ b/packages/dify-ui/src/field/index.stories.tsx @@ -0,0 +1,111 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Button } from '../button' +import { + FieldControl, + FieldDescription, + FieldError, + FieldLabel, + FieldRoot, +} from './index' + +const meta = { + title: 'Base/Form/Field', + component: FieldRoot, + parameters: { + layout: 'centered', + docs: { + description: { + component: 'Field primitives built on Base UI Field. Use FieldRoot with FieldLabel, FieldControl, FieldDescription, and FieldError for one named form field. External form libraries can control invalid, dirty, and touched on FieldRoot.', + }, + }, + }, + tags: ['autodocs'], +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const TextField: Story = { + render: () => ( +
+ + Endpoint + + Used as the base URL for extension requests. + Endpoint is required. + Enter a valid URL. + +
+ +
+
+ ), +} + +export const MultipleFields: Story = { + render: () => ( +
+ + Name + + Name is required. + + + Endpoint + + Used as the base URL for extension requests. + Endpoint is required. + Enter a valid URL. + + + API key + + Stored with the extension configuration. + API key is required. + +
+ +
+
+ ), +} + +export const ExternalInvalidState: Story = { + render: () => ( + + API key + + API key has expired. + + ), +} + +export const Sizes: Story = { + render: () => ( +
+ + Small + + + + Regular + + + + Large + + +
+ ), +} + +export const ReadOnly: Story = { + render: () => ( + + Endpoint + + This value is managed by the workspace owner. + + ), +} diff --git a/packages/dify-ui/src/field/index.tsx b/packages/dify-ui/src/field/index.tsx new file mode 100644 index 0000000000..12f0ba6ce8 --- /dev/null +++ b/packages/dify-ui/src/field/index.tsx @@ -0,0 +1,154 @@ +'use client' + +import type { Field as BaseFieldNS } from '@base-ui/react/field' +import type { VariantProps } from 'class-variance-authority' +import { Field as BaseField } from '@base-ui/react/field' +import { cva } from 'class-variance-authority' +import { cn } from '../cn' + +export type FieldRootProps + = Omit + & { + className?: string + } + +export type FieldRootActions = BaseFieldNS.Root.Actions + +export function FieldRoot({ + className, + ...props +}: FieldRootProps) { + return ( + + ) +} + +export type FieldItemProps + = Omit + & { + className?: string + } + +export function FieldItem({ + className, + ...props +}: FieldItemProps) { + return ( + + ) +} + +export type FieldLabelProps + = Omit + & { + className?: string + } + +export function FieldLabel({ + className, + ...props +}: FieldLabelProps) { + return ( + + ) +} + +const fieldControlVariants = cva( + [ + 'w-full appearance-none border border-transparent bg-components-input-bg-normal text-components-input-text-filled caret-primary-600 outline-hidden transition-[background-color,border-color,box-shadow]', + 'placeholder:text-components-input-text-placeholder', + 'hover:border-components-input-border-hover hover:bg-components-input-bg-hover', + 'focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs', + 'data-invalid:border-components-input-border-destructive data-invalid:bg-components-input-bg-destructive', + 'read-only:cursor-default read-only:shadow-none read-only:hover:border-transparent read-only:hover:bg-components-input-bg-normal read-only:focus:border-transparent read-only:focus:bg-components-input-bg-normal read-only:focus:shadow-none', + 'disabled:cursor-not-allowed disabled:border-transparent disabled:bg-components-input-bg-disabled disabled:text-components-input-text-filled-disabled', + 'disabled:hover:border-transparent disabled:hover:bg-components-input-bg-disabled', + 'motion-reduce:transition-none', + ], + { + variants: { + size: { + small: 'rounded-md px-2 py-[3px] system-xs-regular', + medium: 'rounded-lg px-3 py-[7px] system-sm-regular', + large: 'rounded-[10px] px-4 py-[7px] system-md-regular', + }, + }, + defaultVariants: { + size: 'medium', + }, + }, +) + +export type FieldControlSize = NonNullable['size']> + +export type FieldControlProps + = Omit + & VariantProps + & { + className?: string + } + +export type FieldControlChangeEventDetails = BaseFieldNS.Control.ChangeEventDetails + +export function FieldControl({ + className, + size = 'medium', + ...props +}: FieldControlProps) { + return ( + + ) +} + +export type FieldDescriptionProps + = Omit + & { + className?: string + } + +export function FieldDescription({ + className, + ...props +}: FieldDescriptionProps) { + return ( + + ) +} + +export type FieldErrorProps + = Omit + & { + className?: string + } + +export function FieldError({ + className, + ...props +}: FieldErrorProps) { + return ( + + ) +} + +export type FieldValidityProps = BaseFieldNS.Validity.Props +export type FieldValidityState = BaseFieldNS.Validity.State + +export const FieldValidity = BaseField.Validity diff --git a/packages/dify-ui/src/fieldset/__tests__/index.spec.tsx b/packages/dify-ui/src/fieldset/__tests__/index.spec.tsx new file mode 100644 index 0000000000..9ee90af306 --- /dev/null +++ b/packages/dify-ui/src/fieldset/__tests__/index.spec.tsx @@ -0,0 +1,21 @@ +import { render } from 'vitest-browser-react' +import { + FieldsetLegend, + FieldsetRoot, +} from '../index' + +describe('Fieldset primitives', () => { + it('should apply reset design-system classes', async () => { + const screen = await render( + + Permissions + , + ) + + const legend = screen.getByText('Permissions').element() as HTMLElement + const fieldset = legend.closest('fieldset') as HTMLElement + + await expect.element(fieldset).toHaveClass('m-0', 'min-w-0', 'border-0', 'p-0', 'custom-root') + await expect.element(legend).toHaveClass('mb-1', 'py-1', 'system-sm-medium', 'text-text-secondary', 'custom-legend') + }) +}) diff --git a/packages/dify-ui/src/fieldset/index.stories.tsx b/packages/dify-ui/src/fieldset/index.stories.tsx new file mode 100644 index 0000000000..51410ed24c --- /dev/null +++ b/packages/dify-ui/src/fieldset/index.stories.tsx @@ -0,0 +1,56 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Checkbox } from '../checkbox' +import { CheckboxGroup } from '../checkbox-group' +import { FieldItem, FieldLabel, FieldRoot } from '../field' +import { + FieldsetLegend, + FieldsetRoot, +} from './index' + +const meta = { + title: 'Base/Form/Fieldset', + component: FieldsetRoot, + parameters: { + layout: 'centered', + docs: { + description: { + component: 'Fieldset primitives built on Base UI Fieldset. Use FieldsetRoot and FieldsetLegend when one field is represented by a group of related controls such as checkbox groups, radio groups, or multi-thumb sliders. Fieldset provides group semantics and labeling; pass interactive state such as disabled and value to the actual group primitive.', + }, + }, + }, + tags: ['autodocs'], +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const CheckboxGroupField: Story = { + render: () => ( + + }> + Scopes +
+ + + + Read + + + + + + Write + + + + + + Admin + + +
+
+
+ ), +} diff --git a/packages/dify-ui/src/fieldset/index.tsx b/packages/dify-ui/src/fieldset/index.tsx new file mode 100644 index 0000000000..e51804509b --- /dev/null +++ b/packages/dify-ui/src/fieldset/index.tsx @@ -0,0 +1,41 @@ +'use client' + +import type { Fieldset as BaseFieldsetNS } from '@base-ui/react/fieldset' +import { Fieldset as BaseFieldset } from '@base-ui/react/fieldset' +import { cn } from '../cn' + +export type FieldsetRootProps + = Omit + & { + className?: string + } + +export function FieldsetRoot({ + className, + ...props +}: FieldsetRootProps) { + return ( + + ) +} + +export type FieldsetLegendProps + = Omit + & { + className?: string + } + +export function FieldsetLegend({ + className, + ...props +}: FieldsetLegendProps) { + return ( + + ) +} diff --git a/packages/dify-ui/src/form/__tests__/index.spec.tsx b/packages/dify-ui/src/form/__tests__/index.spec.tsx new file mode 100644 index 0000000000..6ce3f6b7e2 --- /dev/null +++ b/packages/dify-ui/src/form/__tests__/index.spec.tsx @@ -0,0 +1,53 @@ +import { render } from 'vitest-browser-react' +import { FieldControl, FieldLabel, FieldRoot } from '../../field' +import { Form } from '../index' + +const asHTMLElement = (element: HTMLElement | SVGElement) => element as HTMLElement + +describe('Form primitive', () => { + it('should render a native named form and merge custom class names', async () => { + const screen = await render( +
+ + Name + + +
, + ) + + await expect.element(screen.getByRole('form', { name: 'profile form' })).toHaveClass('custom-form') + }) + + it('should call onFormSubmit with submitted values', async () => { + const onFormSubmit = vi.fn() + const screen = await render( +
+ + Endpoint + + + +
, + ) + + asHTMLElement(screen.getByRole('button', { name: 'Save' }).element()).click() + + expect(onFormSubmit).toHaveBeenCalledTimes(1) + expect(onFormSubmit.mock.calls[0]?.[0]).toMatchObject({ + endpoint: 'https://api.example.com', + }) + }) + + it('should expose externally supplied errors through FieldError consumers', async () => { + const screen = await render( +
+ + Token + + +
, + ) + + await expect.element(screen.getByRole('textbox', { name: 'Token' })).toHaveAttribute('aria-invalid', 'true') + }) +}) diff --git a/packages/dify-ui/src/form/index.stories.tsx b/packages/dify-ui/src/form/index.stories.tsx new file mode 100644 index 0000000000..f1edac5e7c --- /dev/null +++ b/packages/dify-ui/src/form/index.stories.tsx @@ -0,0 +1,70 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Button } from '../button' +import { Checkbox } from '../checkbox' +import { CheckboxGroup } from '../checkbox-group' +import { + FieldControl, + FieldDescription, + FieldError, + FieldItem, + FieldLabel, + FieldRoot, +} from '../field' +import { FieldsetLegend, FieldsetRoot } from '../fieldset' +import { Form } from './index' + +const meta = { + title: 'Base/Form/Form', + component: Form, + parameters: { + layout: 'centered', + }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Basic: Story = { + render: () => ( +
undefined}> + + Name + + Name is required. + + + + Email + + Used for account notifications. + Email is required. + Enter a valid email address. + + + + }> + Features +
+ + + + Search + + + + + + Analytics + + +
+
+
+ +
+ +
+
+ ), +} diff --git a/packages/dify-ui/src/form/index.tsx b/packages/dify-ui/src/form/index.tsx new file mode 100644 index 0000000000..09cdc2a623 --- /dev/null +++ b/packages/dify-ui/src/form/index.tsx @@ -0,0 +1,11 @@ +'use client' + +import type { Form as BaseFormNS } from '@base-ui/react/form' +import { Form as BaseForm } from '@base-ui/react/form' + +export const Form = BaseForm + +export type FormProps = BaseFormNS.Props +export type FormActions = BaseFormNS.Actions +export type FormValidationMode = BaseFormNS.ValidationMode +export type FormSubmitEventDetails = BaseFormNS.SubmitEventDetails diff --git a/packages/dify-ui/src/number-field/index.stories.tsx b/packages/dify-ui/src/number-field/index.stories.tsx index a436d997e6..b9472943e0 100644 --- a/packages/dify-ui/src/number-field/index.stories.tsx +++ b/packages/dify-ui/src/number-field/index.stories.tsx @@ -108,7 +108,7 @@ const DemoField = ({ } const meta = { - title: 'Base/UI/NumberField', + title: 'Base/Form/NumberField', component: NumberField, parameters: { layout: 'centered', diff --git a/packages/dify-ui/src/select/index.stories.tsx b/packages/dify-ui/src/select/index.stories.tsx index 6dc832a291..697266dcec 100644 --- a/packages/dify-ui/src/select/index.stories.tsx +++ b/packages/dify-ui/src/select/index.stories.tsx @@ -16,7 +16,7 @@ import { const triggerWidth = 'w-64' const meta = { - title: 'Base/UI/Select', + title: 'Base/Form/Select', component: Select, parameters: { layout: 'centered', diff --git a/packages/dify-ui/src/slider/index.stories.tsx b/packages/dify-ui/src/slider/index.stories.tsx index a48e202142..844a984406 100644 --- a/packages/dify-ui/src/slider/index.stories.tsx +++ b/packages/dify-ui/src/slider/index.stories.tsx @@ -4,7 +4,7 @@ import { useState } from 'react' import { Slider } from '.' const meta = { - title: 'Base/UI/Slider', + title: 'Base/Form/Slider', component: Slider, parameters: { layout: 'centered', diff --git a/packages/dify-ui/src/switch/index.stories.tsx b/packages/dify-ui/src/switch/index.stories.tsx index f43b9ae154..4d47ef688e 100644 --- a/packages/dify-ui/src/switch/index.stories.tsx +++ b/packages/dify-ui/src/switch/index.stories.tsx @@ -4,7 +4,7 @@ import { useState, useTransition } from 'react' import { Switch, SwitchSkeleton } from '.' const meta = { - title: 'Base/UI/Switch', + title: 'Base/Form/Switch', component: Switch, parameters: { layout: 'centered', diff --git a/packages/dify-ui/vite.config.ts b/packages/dify-ui/vite.config.ts index f2a2d24e57..6a4c2f4286 100644 --- a/packages/dify-ui/vite.config.ts +++ b/packages/dify-ui/vite.config.ts @@ -9,6 +9,9 @@ export default defineConfig({ resolve: { tsconfigPaths: true, }, + optimizeDeps: { + include: ['@base-ui/react/form'], + }, test: { globals: true, setupFiles: ['./vitest.setup.ts'], diff --git a/web/app/components/app/configuration/tools/__tests__/external-data-tool-modal.spec.tsx b/web/app/components/app/configuration/tools/__tests__/external-data-tool-modal.spec.tsx index 2a725d88ca..fd87ab0aeb 100644 --- a/web/app/components/app/configuration/tools/__tests__/external-data-tool-modal.spec.tsx +++ b/web/app/components/app/configuration/tools/__tests__/external-data-tool-modal.spec.tsx @@ -84,7 +84,7 @@ vi.mock('@/app/components/base/features/new-feature-panel/moderation/form-genera })) vi.mock('@/app/components/header/account-setting/api-based-extension-page/selector', () => ({ - default: ({ + ApiBasedExtensionSelector: ({ onChange, value, }: { diff --git a/web/app/components/app/configuration/tools/external-data-tool-modal.tsx b/web/app/components/app/configuration/tools/external-data-tool-modal.tsx index b09b7b1c70..16e3633e3e 100644 --- a/web/app/components/app/configuration/tools/external-data-tool-modal.tsx +++ b/web/app/components/app/configuration/tools/external-data-tool-modal.tsx @@ -13,7 +13,7 @@ import AppIcon from '@/app/components/base/app-icon' import EmojiPicker from '@/app/components/base/emoji-picker' import FormGeneration from '@/app/components/base/features/new-feature-panel/moderation/form-generation' import { BookOpen01 } from '@/app/components/base/icons/src/vender/line/education' -import ApiBasedExtensionSelector from '@/app/components/header/account-setting/api-based-extension-page/selector' +import { ApiBasedExtensionSelector } from '@/app/components/header/account-setting/api-based-extension-page/selector' import { useDocLink, useLocale } from '@/context/i18n' import { useCodeBasedExtensions } from '@/service/use-common' import { diff --git a/web/app/components/base/checkbox-list/__tests__/index.spec.tsx b/web/app/components/base/checkbox-list/__tests__/index.spec.tsx index 7d536a766a..feccbd0b38 100644 --- a/web/app/components/base/checkbox-list/__tests__/index.spec.tsx +++ b/web/app/components/base/checkbox-list/__tests__/index.spec.tsx @@ -21,6 +21,7 @@ describe('checkbox list component', () => { ) expect(screen.getByText('Test Title'))!.toBeInTheDocument() expect(screen.getByText('Test Description'))!.toBeInTheDocument() + expect(screen.getByRole('group', { name: 'Test Title' }))!.toHaveAccessibleDescription('Test Description') options.forEach((option) => { expect(screen.getByText(option.label))!.toBeInTheDocument() }) @@ -231,6 +232,7 @@ describe('checkbox list component', () => { />, ) expect(screen.getByText('Test Label'))!.toBeInTheDocument() + expect(screen.getByRole('group', { name: 'Test Label' }))!.toBeInTheDocument() }) it('renders without showSelectAll, showCount, showSearch', () => { diff --git a/web/app/components/base/checkbox-list/index.tsx b/web/app/components/base/checkbox-list/index.tsx index 22cd1a5718..0b809e3792 100644 --- a/web/app/components/base/checkbox-list/index.tsx +++ b/web/app/components/base/checkbox-list/index.tsx @@ -3,7 +3,9 @@ import { Button } from '@langgenius/dify-ui/button' import { Checkbox } from '@langgenius/dify-ui/checkbox' import { CheckboxGroup } from '@langgenius/dify-ui/checkbox-group' import { cn } from '@langgenius/dify-ui/cn' -import { useId, useMemo, useState } from 'react' +import { FieldDescription, FieldItem, FieldLabel, FieldRoot } from '@langgenius/dify-ui/field' +import { FieldsetLegend, FieldsetRoot } from '@langgenius/dify-ui/fieldset' +import { useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import Badge from '@/app/components/base/badge' import SearchInput from '@/app/components/base/search-input' @@ -16,6 +18,7 @@ type CheckboxListOption = { } type CheckboxListProps = { + name?: string title?: string label?: string description?: string @@ -31,6 +34,7 @@ type CheckboxListProps = { } export const CheckboxList = ({ + name, title = '', label, description, @@ -45,7 +49,6 @@ export const CheckboxList = ({ maxHeight, }: CheckboxListProps) => { const { t } = useTranslation() - const groupLabelId = useId() const [searchQuery, setSearchQuery] = useState('') const filteredOptions = useMemo(() => { @@ -66,116 +69,129 @@ export const CheckboxList = ({ ) return ( -
- {label && ( -
- {label} -
- )} - {description && ( -
- {description} -
- )} - - onChange?.(nextValue)} - allValues={selectableOptionValues} - disabled={disabled} - className="rounded-lg border border-components-panel-border bg-components-panel-bg" + + onChange?.(nextValue)} + allValues={selectableOptionValues} + disabled={disabled} + className="flex flex-col gap-1" + /> + )} > - {(showSelectAll || title || showSearch) && ( -
- {!searchQuery && showSelectAll && ( -
) } -export default ApiBasedExtensionModal diff --git a/web/app/components/header/account-setting/api-based-extension-page/selector.tsx b/web/app/components/header/account-setting/api-based-extension-page/selector.tsx index e98ff593cf..e346c84261 100644 --- a/web/app/components/header/account-setting/api-based-extension-page/selector.tsx +++ b/web/app/components/header/account-setting/api-based-extension-page/selector.tsx @@ -1,36 +1,36 @@ import { Popover, PopoverContent, PopoverTrigger } from '@langgenius/dify-ui/popover' +import { useQuery } from '@tanstack/react-query' import { useState } from 'react' import { useTranslation } from 'react-i18next' import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/constants' import { useModalContext } from '@/context/modal-context' -import { useApiBasedExtensions } from '@/service/use-common' -import ApiBasedExtensionModal from './modal' +import { consoleQuery } from '@/service/client' +import { ApiBasedExtensionModal } from './modal' type ApiBasedExtensionSelectorProps = { value: string onChange: (value: string) => void } -const ApiBasedExtensionSelector = ({ +export function ApiBasedExtensionSelector({ value, onChange, -}: ApiBasedExtensionSelectorProps) => { +}: ApiBasedExtensionSelectorProps) { const { t } = useTranslation() const [open, setOpen] = useState(false) const [addModalOpen, setAddModalOpen] = useState(false) const { setShowAccountSettingModal, } = useModalContext() - const { data, refetch: mutate } = useApiBasedExtensions() + const { data: apiBasedExtensions = [] } = useQuery(consoleQuery.apiBasedExtension.get.queryOptions()) const handleSelect = (id: string) => { onChange(id) setOpen(false) } - const currentItem = data?.find(item => item.id === value) + const currentItem = apiBasedExtensions.find(item => item.id === value) - const handleSaveApiBasedExtension = () => { - mutate() + const handleApiBasedExtensionSaved = () => { setAddModalOpen(false) } const handleAddModalOpenChange = (nextOpen: boolean) => { @@ -96,12 +96,12 @@ const ApiBasedExtensionSelector = ({
{ - data?.map(item => ( + apiBasedExtensions.map(item => (
- + )} {state.step === InstallStepFromGitHub.selectPackage && ( = ({ return ( <> - - { + if (!value) + return + const selectedItem = versions.find(item => String(item.value) === value) + if (selectedItem) + onSelectVersion(selectedItem) + }} + > + +
+ + {selectedVersionOption?.name ?? t(`${i18nPrefix}.selectVersionPlaceholder`, { ns: 'plugin' }) ?? ''} + + {!!(updatePayload?.originalPackageInfo.version && selectedVersionOption && selectedVersionOption.value !== updatePayload.originalPackageInfo.version) && ( + + {updatePayload.originalPackageInfo.version} + {' '} + {'->'} + {' '} + {selectedVersionOption.value} + )} - - - ))} - - - - +
+
+ + {versions.map(item => ( + + {item.name} + {item.value === updatePayload?.originalPackageInfo.version && ( + INSTALLED + )} + + + ))} + + + + + + {t(`${i18nPrefix}.selectPackage`, { ns: 'plugin' })} + + +
{!isEdit && ( diff --git a/web/app/components/workflow/nodes/_base/components/form-input-item.tsx b/web/app/components/workflow/nodes/_base/components/form-input-item.tsx index 88b65f3ab9..9c3c50bba2 100644 --- a/web/app/components/workflow/nodes/_base/components/form-input-item.tsx +++ b/web/app/components/workflow/nodes/_base/components/form-input-item.tsx @@ -305,6 +305,7 @@ const FormInputItem: FC = ({ )} {isCheckbox && isConstant && ( { vi.resetModules() vi.doMock('@/utils/client', () => ({ isClient: isClientValue, isServer: !isClientValue })) const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}) - // eslint-disable-next-line next/no-assign-module-variable const module = await import('./client') warnSpy.mockClear() return { getBaseURL: module.getBaseURL, warnSpy } @@ -35,6 +35,14 @@ const createTag = (overrides: Partial = {}): Tag => ({ ...overrides, }) +const createApiBasedExtension = (overrides: Partial = {}): ApiBasedExtensionResponse => ({ + id: 'extension-1', + name: 'Weather', + api_endpoint: 'https://api.example.com/weather', + api_key: 'secret-key', + ...overrides, +}) + // Scenario: base URL selection and warnings. describe('getBaseURL', () => { beforeEach(() => { @@ -258,3 +266,94 @@ describe('consoleQuery tag mutation defaults', () => { expect(queryClient.getQueryData(knowledgeListKey)).toEqual([knowledgeTag]) }) }) + +// Scenario: oRPC mutation defaults own shared API Extension cache behavior. +describe('consoleQuery apiBasedExtension mutation defaults', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it('should add created API Extension to the list query cache', async () => { + const consoleQuery = await loadConsoleQuery() + const queryClient = new QueryClient() + const listKey = consoleQuery.apiBasedExtension.get.queryKey() + const existingExtension = createApiBasedExtension({ id: 'extension-1', name: 'Existing' }) + const createdExtension = createApiBasedExtension({ id: 'extension-2', name: 'Created' }) + + queryClient.setQueryData(listKey, [existingExtension]) + + const mutationOptions = consoleQuery.apiBasedExtension.post.mutationOptions() + await mutationOptions.onSuccess?.( + createdExtension, + { + body: { + name: createdExtension.name, + api_endpoint: createdExtension.api_endpoint, + api_key: createdExtension.api_key, + }, + }, + undefined, + createMutationContext(queryClient), + ) + + expect(queryClient.getQueryData(listKey)).toEqual([createdExtension, existingExtension]) + }) + + it('should update matching API Extension in the list query cache', async () => { + const consoleQuery = await loadConsoleQuery() + const queryClient = new QueryClient() + const listKey = consoleQuery.apiBasedExtension.get.queryKey() + const targetExtension = createApiBasedExtension({ id: 'extension-1', name: 'Before' }) + const otherExtension = createApiBasedExtension({ id: 'extension-2', name: 'Other' }) + const updatedExtension = createApiBasedExtension({ ...targetExtension, name: 'After' }) + + queryClient.setQueryData(listKey, [targetExtension, otherExtension]) + + const mutationOptions = consoleQuery.apiBasedExtension.byId.post.mutationOptions() + await mutationOptions.onSuccess?.( + updatedExtension, + { + params: { + id: targetExtension.id, + }, + body: { + name: 'Ignored Client Name', + api_endpoint: targetExtension.api_endpoint, + api_key: '[__HIDDEN__]', + }, + }, + undefined, + createMutationContext(queryClient), + ) + + expect(queryClient.getQueryData(listKey)).toEqual([updatedExtension, otherExtension]) + }) + + it('should remove deleted API Extension from the list query cache', async () => { + const consoleQuery = await loadConsoleQuery() + const queryClient = new QueryClient() + const listKey = consoleQuery.apiBasedExtension.get.queryKey() + const deletedExtension = createApiBasedExtension({ id: 'extension-1', name: 'Delete me' }) + const remainingExtension = createApiBasedExtension({ id: 'extension-2', name: 'Keep me' }) + + queryClient.setQueryData(listKey, [deletedExtension, remainingExtension]) + + const mutationOptions = consoleQuery.apiBasedExtension.byId.delete.mutationOptions() + await mutationOptions.onSuccess?.( + {}, + { + params: { + id: deletedExtension.id, + }, + }, + undefined, + createMutationContext(queryClient), + ) + + expect(queryClient.getQueryData(listKey)).toEqual([remainingExtension]) + }) +}) diff --git a/web/service/client.ts b/web/service/client.ts index 984779e2b2..84a8c7a43d 100644 --- a/web/service/client.ts +++ b/web/service/client.ts @@ -1,3 +1,4 @@ +import type { ApiBasedExtensionResponse } from '@dify/contracts/api/console/api-based-extension/types.gen' import type { ContractRouterClient } from '@orpc/contract' import type { JsonifiedClient } from '@orpc/openapi-client' import type { Tag } from '@/contract/console/tags' @@ -89,6 +90,45 @@ export const consoleClient: JsonifiedClient { + context.client.setQueryData( + consoleQuery.apiBasedExtension.get.queryKey(), + (oldExtensions: ApiBasedExtensionResponse[] | undefined) => + oldExtensions ? [createdExtension, ...oldExtensions] : oldExtensions, + ) + }, + }, + }, + byId: { + post: { + mutationOptions: { + onSuccess: (updatedExtension, variables, _onMutateResult, context) => { + context.client.setQueryData( + consoleQuery.apiBasedExtension.get.queryKey(), + (oldExtensions: ApiBasedExtensionResponse[] | undefined) => + oldExtensions?.map(extension => extension.id === variables.params.id + ? updatedExtension + : extension), + ) + }, + }, + }, + delete: { + mutationOptions: { + onSuccess: (_data, variables, _onMutateResult, context) => { + context.client.setQueryData( + consoleQuery.apiBasedExtension.get.queryKey(), + (oldExtensions: ApiBasedExtensionResponse[] | undefined) => + oldExtensions?.filter(extension => extension.id !== variables.params.id), + ) + }, + }, + }, + }, + }, tags: { create: { mutationOptions: { diff --git a/web/service/common.ts b/web/service/common.ts index 57304712dd..3f0ae66a9b 100644 --- a/web/service/common.ts +++ b/web/service/common.ts @@ -1,8 +1,3 @@ -import type { - ApiBasedExtensionListResponse, - ApiBasedExtensionPayload, - ApiBasedExtensionResponse, -} from '@dify/contracts/api/console/api-based-extension/types.gen' import type { DefaultModelResponse, Model, @@ -275,26 +270,6 @@ export const fetchDataSourceNotionBinding = (url: string): Promise<{ result: str return get<{ result: string }>(url) } -export const fetchApiBasedExtensionList = (url: string): Promise => { - return get(url) -} - -export const fetchApiBasedExtensionDetail = (url: string): Promise => { - return get(url) -} - -export const addApiBasedExtension = ({ url, body }: { url: string, body: ApiBasedExtensionPayload }): Promise => { - return post(url, { body }) -} - -export const updateApiBasedExtension = ({ url, body }: { url: string, body: ApiBasedExtensionPayload }): Promise => { - return post(url, { body }) -} - -export const deleteApiBasedExtension = (url: string): Promise<{ result: string }> => { - return del<{ result: string }>(url) -} - export const fetchCodeBasedExtensionList = (url: string): Promise => { return get(url) } diff --git a/web/service/use-common.ts b/web/service/use-common.ts index 9e39d090b5..2fb0a8cbda 100644 --- a/web/service/use-common.ts +++ b/web/service/use-common.ts @@ -23,7 +23,6 @@ import type { RETRIEVE_METHOD } from '@/types/app' import { queryOptions, useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { IS_DEV } from '@/config' import { get, post } from './base' -import { consoleClient } from './client' /** * True iff `err` is a 401 Response thrown by `service/base.ts`. @@ -52,7 +51,6 @@ export const commonQueryKeys = { accountIntegrates: [NAME_SPACE, 'account-integrates'] as const, pluginProviders: [NAME_SPACE, 'plugin-providers'] as const, notionConnection: [NAME_SPACE, 'notion-connection'] as const, - apiBasedExtensions: [NAME_SPACE, 'api-based-extensions'] as const, codeBasedExtensions: (module?: string) => [NAME_SPACE, 'code-based-extensions', module] as const, invitationCheck: (params?: { workspace_id?: string, email?: string, token?: string }) => [ NAME_SPACE, @@ -319,13 +317,6 @@ export const useCodeBasedExtensions = (module: string) => { }) } -export const useApiBasedExtensions = () => { - return useQuery({ - queryKey: commonQueryKeys.apiBasedExtensions, - queryFn: () => consoleClient.apiBasedExtension.get(), - }) -} - export const useInvitationCheck = (params?: { workspace_id?: string, email?: string, token?: string }, enabled?: boolean) => { return useQuery({ queryKey: commonQueryKeys.invitationCheck(params), From 2031d31ee8a9a05a6a492bfc4b6ec8be87edd6bb Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Tue, 19 May 2026 13:40:24 +0800 Subject: [PATCH 4/7] refactor(web): migrate annotation selection to checkbox group (#36370) --- .../__tests__/batch-action.spec.tsx | 6 +- .../app/annotation/__tests__/index.spec.tsx | 4 +- .../app/annotation/__tests__/list.spec.tsx | 12 +- .../app/annotation/batch-action.tsx | 39 ++-- web/app/components/app/annotation/index.tsx | 5 +- web/app/components/app/annotation/list.tsx | 205 +++++++++--------- 6 files changed, 134 insertions(+), 137 deletions(-) diff --git a/web/app/components/app/annotation/__tests__/batch-action.spec.tsx b/web/app/components/app/annotation/__tests__/batch-action.spec.tsx index 102465e116..95342615d1 100644 --- a/web/app/components/app/annotation/__tests__/batch-action.spec.tsx +++ b/web/app/components/app/annotation/__tests__/batch-action.spec.tsx @@ -6,14 +6,14 @@ describe('BatchAction', () => { const baseProps = { selectedIds: ['1', '2', '3'], onBatchDelete: vi.fn(), - onCancel: vi.fn(), + onSelectedIdsChange: vi.fn(), } beforeEach(() => { vi.clearAllMocks() }) - it('should show the selected count and trigger cancel action', () => { + it('should show the selected count and clear selection through selection change', () => { render() expect(screen.getByText('3')).toBeInTheDocument() @@ -21,7 +21,7 @@ describe('BatchAction', () => { fireEvent.click(screen.getByRole('button', { name: 'common.operation.cancel' })) - expect(baseProps.onCancel).toHaveBeenCalledTimes(1) + expect(baseProps.onSelectedIdsChange).toHaveBeenCalledWith([]) }) it('should confirm before running batch delete', async () => { diff --git a/web/app/components/app/annotation/__tests__/index.spec.tsx b/web/app/components/app/annotation/__tests__/index.spec.tsx index 2bd94d03b0..f0928ba2d3 100644 --- a/web/app/components/app/annotation/__tests__/index.spec.tsx +++ b/web/app/components/app/annotation/__tests__/index.spec.tsx @@ -67,7 +67,7 @@ vi.mock('../header-opts', () => ({ let latestListProps: any vi.mock('../list', () => ({ - default: (props: any) => { + List: (props: any) => { latestListProps = props if (!props.list.length) return
@@ -440,7 +440,7 @@ describe('Annotation', () => { latestListProps.onSelectedIdsChange([annotation.id]) }) await act(async () => { - latestListProps.onCancel() + latestListProps.onSelectedIdsChange([]) }) expect(latestListProps.selectedIds).toEqual([]) diff --git a/web/app/components/app/annotation/__tests__/list.spec.tsx b/web/app/components/app/annotation/__tests__/list.spec.tsx index 883c1adfe0..1116725fb2 100644 --- a/web/app/components/app/annotation/__tests__/list.spec.tsx +++ b/web/app/components/app/annotation/__tests__/list.spec.tsx @@ -1,7 +1,7 @@ import type { AnnotationItem } from '../type' import { fireEvent, render, screen, within } from '@testing-library/react' import * as React from 'react' -import List from '../list' +import { List } from '../list' const mockFormatTime = vi.fn(() => 'formatted-time') @@ -36,7 +36,6 @@ describe('List', () => { selectedIds={[]} onSelectedIdsChange={vi.fn()} onBatchDelete={vi.fn()} - onCancel={vi.fn()} />, ) @@ -57,12 +56,11 @@ describe('List', () => { selectedIds={[]} onSelectedIdsChange={onSelectedIdsChange} onBatchDelete={vi.fn()} - onCancel={vi.fn()} />, ) fireEvent.click(screen.getByRole('checkbox', { name: 'A' })) - expect(onSelectedIdsChange).toHaveBeenCalledWith(['a']) + expect(onSelectedIdsChange.mock.calls.at(-1)?.[0]).toEqual(['a']) rerender( { selectedIds={['a']} onSelectedIdsChange={onSelectedIdsChange} onBatchDelete={vi.fn()} - onCancel={vi.fn()} />, ) fireEvent.click(screen.getByRole('checkbox', { name: 'A' })) - expect(onSelectedIdsChange).toHaveBeenCalledWith([]) + expect(onSelectedIdsChange.mock.calls.at(-1)?.[0]).toEqual([]) fireEvent.click(screen.getByRole('checkbox', { name: 'common.operation.selectAll' })) - expect(onSelectedIdsChange).toHaveBeenCalledWith(['a', 'b']) + expect(onSelectedIdsChange.mock.calls.at(-1)?.[0]).toEqual(['a', 'b']) }) it('should confirm before removing an annotation and expose batch actions', async () => { @@ -93,7 +90,6 @@ describe('List', () => { selectedIds={[item.id]} onSelectedIdsChange={vi.fn()} onBatchDelete={vi.fn()} - onCancel={vi.fn()} />, ) diff --git a/web/app/components/app/annotation/batch-action.tsx b/web/app/components/app/annotation/batch-action.tsx index 961f313746..188dc46ce9 100644 --- a/web/app/components/app/annotation/batch-action.tsx +++ b/web/app/components/app/annotation/batch-action.tsx @@ -7,8 +7,8 @@ import { AlertDialogContent, AlertDialogTitle, } from '@langgenius/dify-ui/alert-dialog' +import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' -import { RiDeleteBinLine } from '@remixicon/react' import { useBoolean } from 'ahooks' import * as React from 'react' import { useTranslation } from 'react-i18next' @@ -20,14 +20,14 @@ type IBatchActionProps = { className?: string selectedIds: string[] onBatchDelete: () => Promise - onCancel: () => void + onSelectedIdsChange: (selectedIds: string[]) => void } const BatchAction: FC = ({ className, selectedIds, onBatchDelete, - onCancel, + onSelectedIdsChange, }) => { const { t } = useTranslation() const [isShowDeleteConfirm, { @@ -46,34 +46,35 @@ const BatchAction: FC = ({ setIsNotDeleting() } return ( -
-
+
+
- + {selectedIds.length} - {t(`${i18nPrefix}.selected`, { ns: 'appAnnotation' })} + {t(`${i18nPrefix}.selected`, { ns: 'appAnnotation' })}
- + - + {t('operation.cancel', { ns: 'common' })} +
!open && hideDeleteConfirm()}> diff --git a/web/app/components/app/annotation/index.tsx b/web/app/components/app/annotation/index.tsx index cbad5b40ea..fd8f75fefd 100644 --- a/web/app/components/app/annotation/index.tsx +++ b/web/app/components/app/annotation/index.tsx @@ -26,7 +26,7 @@ import { sleep } from '@/utils' import EmptyElement from './empty-element' import Filter from './filter' import HeaderOpts from './header-opts' -import List from './list' +import { List } from './list' import { AnnotationEnableStatus, JobStatus } from './type' import ViewAnnotationModal from './view-annotation-modal' @@ -176,7 +176,7 @@ const Annotation: FC = (props) => { > {annotationConfig?.enabled && ( -
+
setIsShowEdit(true)}> @@ -210,7 +210,6 @@ const Annotation: FC = (props) => { selectedIds={selectedIds} onSelectedIdsChange={setSelectedIds} onBatchDelete={handleBatchDelete} - onCancel={() => setSelectedIds([])} /> ) :
} diff --git a/web/app/components/app/annotation/list.tsx b/web/app/components/app/annotation/list.tsx index fa12c95ae3..361d410698 100644 --- a/web/app/components/app/annotation/list.tsx +++ b/web/app/components/app/annotation/list.tsx @@ -1,11 +1,8 @@ 'use client' -import type { FC } from 'react' import type { AnnotationItem } from './type' import { Checkbox } from '@langgenius/dify-ui/checkbox' -import { cn } from '@langgenius/dify-ui/cn' -import { RiDeleteBinLine, RiEditLine } from '@remixicon/react' +import { CheckboxGroup } from '@langgenius/dify-ui/checkbox-group' import * as React from 'react' -import { useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' import ActionButton from '@/app/components/base/action-button' import useTimestamp from '@/hooks/use-timestamp' @@ -19,121 +16,126 @@ type Props = { selectedIds: string[] onSelectedIdsChange: (selectedIds: string[]) => void onBatchDelete: () => Promise - onCancel: () => void } -const List: FC = ({ +type AnnotationTableRowProps = { + item: AnnotationItem + formattedCreatedAt: string + onView: (item: AnnotationItem) => void + onRemoveClick: (id: string) => void +} + +function AnnotationTableRow({ + item, + formattedCreatedAt, + onView, + onRemoveClick, +}: AnnotationTableRowProps) { + const { t } = useTranslation() + const questionId = React.useId() + + return ( + onView(item)} + > + e.stopPropagation()}> +
+ +
+ + + {item.question} + + + {item.answer} + + {formattedCreatedAt} + {item.hit_count} + e.stopPropagation()}> +
+ onView(item)}> + + + onRemoveClick(item.id)} + > + + +
+ + + ) +} + +export function List({ list, onView, onRemove, selectedIds, onSelectedIdsChange, onBatchDelete, - onCancel, -}) => { +}: Props) { const { t } = useTranslation() const { formatTime } = useTimestamp() const [currId, setCurrId] = React.useState(null) const [showConfirmDelete, setShowConfirmDelete] = React.useState(false) - - const isAllSelected = useMemo(() => { - return list.length > 0 && list.every(item => selectedIds.includes(item.id)) - }, [list, selectedIds]) - - const isSomeSelected = useMemo(() => { - return list.some(item => selectedIds.includes(item.id)) - }, [list, selectedIds]) - - const handleSelectAll = useCallback((checked: boolean) => { - const currentPageIds = list.map(item => item.id) - const otherPageIds = selectedIds.filter(id => !currentPageIds.includes(id)) - - if (checked) - onSelectedIdsChange([...otherPageIds, ...currentPageIds]) - else - onSelectedIdsChange(otherPageIds) - }, [list, selectedIds, onSelectedIdsChange]) + const annotationIds = list.map(item => item.id) return ( <>
- - - - - - - - - - - - - {list.map(item => ( - { - onView(item) - } - } - > - - - - - - + {list.map(item => ( + { + setCurrId(id) + setShowConfirmDelete(true) + }} + /> + ))} + +
- - {t('table.header.question', { ns: 'appAnnotation' })}{t('table.header.answer', { ns: 'appAnnotation' })}{t('table.header.createdAt', { ns: 'appAnnotation' })}{t('table.header.hits', { ns: 'appAnnotation' })}{t('table.header.actions', { ns: 'appAnnotation' })}
e.stopPropagation()}> - { - if (checked) - onSelectedIdsChange([...selectedIds, item.id]) - else - onSelectedIdsChange(selectedIds.filter(id => id !== item.id)) - }} - /> - - {item.question} - - {item.answer} - {formatTime(item.created_at, t('dateTimeFormat', { ns: 'appLog' }) as string)}{item.hit_count} e.stopPropagation()}> - {/* Actions */} -
- onView(item)}> - - - { - setCurrId(item.id) - setShowConfirmDelete(true) - }} - > - - + + + + + + + + + + - ))} - -
+
+
{t('table.header.question', { ns: 'appAnnotation' })}{t('table.header.answer', { ns: 'appAnnotation' })}{t('table.header.createdAt', { ns: 'appAnnotation' })}{t('table.header.hits', { ns: 'appAnnotation' })}{t('table.header.actions', { ns: 'appAnnotation' })}
+ +
+ setShowConfirmDelete(false)} @@ -148,10 +150,9 @@ const List: FC = ({ className="absolute bottom-20 left-0 z-20" selectedIds={selectedIds} onBatchDelete={onBatchDelete} - onCancel={onCancel} + onSelectedIdsChange={onSelectedIdsChange} /> )} ) } -export default React.memo(List) From 674cdc3521d93fc3ad996d4fb49f353f1ae5fe4e Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Tue, 19 May 2026 13:59:55 +0800 Subject: [PATCH 5/7] feat(dev-proxy): isolate local auth cookies by target (#36371) --- packages/dev-proxy/README.md | 16 ++++ packages/dev-proxy/src/cookies.spec.ts | 60 ++++++++++++- packages/dev-proxy/src/cookies.ts | 116 +++++++++++++++++++++---- packages/dev-proxy/src/server.spec.ts | 61 +++++++++++++ packages/dev-proxy/src/server.ts | 32 ++++++- packages/dev-proxy/src/types.ts | 7 ++ web/dev-proxy.config.ts | 5 ++ 7 files changed, 275 insertions(+), 22 deletions(-) diff --git a/packages/dev-proxy/README.md b/packages/dev-proxy/README.md index 6b9d7298c4..fff99a9123 100644 --- a/packages/dev-proxy/README.md +++ b/packages/dev-proxy/README.md @@ -187,6 +187,22 @@ export default defineDevProxyConfig({ Set `cookieRewrite: false` to disable cookie rewriting for a route. +When one local proxy can point to multiple online targets, use `localCookieScope: 'target-origin'` +for auth cookies. The proxy stores configured cookies under target-specific local names, +forwards only the active target's cookies upstream, and can override a stale frontend CSRF +header from the active scoped cookie: + +```ts +const cookieRewrite: CookieRewriteOptions = { + hostPrefixCookies: ['access_token', 'csrf_token', 'refresh_token'], + localCookieScope: 'target-origin', + csrfHeader: { + cookieName: 'csrf_token', + headerName: 'X-CSRF-Token', + }, +} +``` + ## Behavior - The proxy preserves the matched path prefix when forwarding requests. diff --git a/packages/dev-proxy/src/cookies.spec.ts b/packages/dev-proxy/src/cookies.spec.ts index 4a1b614eeb..02bce36eee 100644 --- a/packages/dev-proxy/src/cookies.spec.ts +++ b/packages/dev-proxy/src/cookies.spec.ts @@ -2,7 +2,12 @@ * @vitest-environment node */ import { describe, expect, it } from 'vitest' -import { rewriteCookieHeaderForUpstream, rewriteSetCookieHeadersForLocal } from './cookies' +import { + getCookieHeaderValue, + rewriteCookieHeaderForUpstream, + rewriteSetCookieHeadersForLocal, + toScopedLocalCookieName, +} from './cookies' describe('dev proxy cookies', () => { // Scenario: cookie names should only receive secure host prefixes when configured. @@ -41,4 +46,57 @@ describe('dev proxy cookies', () => { 'access_token=abc; Path=/; SameSite=Lax', ]) }) + + // Scenario: target-scoped cookies should isolate authentication state between upstream targets. + it('should only forward auth cookies from the active local scope', () => { + // Arrange + const activeAccessTokenName = toScopedLocalCookieName('access_token', 'active') + const otherAccessTokenName = toScopedLocalCookieName('access_token', 'other') + + // Act + const cookieHeader = rewriteCookieHeaderForUpstream([ + `${activeAccessTokenName}=active-token`, + 'access_token=legacy-token', + `${otherAccessTokenName}=other-token`, + 'theme=dark', + ].join('; '), { + hostPrefixCookies: ['access_token'], + localScopeKey: 'active', + useHostPrefix: true, + }) + + // Assert + expect(cookieHeader).toBe('__Host-access_token=active-token; theme=dark') + }) + + // Scenario: upstream auth set-cookie headers should be stored under scoped local names. + it('should rewrite upstream set-cookie headers into target-scoped local cookies', () => { + // Arrange + const scopedAccessTokenName = toScopedLocalCookieName('access_token', 'cloud') + + // Act + const cookies = rewriteSetCookieHeadersForLocal([ + '__Host-access_token=abc; Path=/console/api; Domain=cloud.example.com; Secure; SameSite=None; Partitioned', + ], { + hostPrefixCookies: ['access_token'], + localScopeKey: 'cloud', + }) + + // Assert + expect(cookies).toEqual([ + `${scopedAccessTokenName}=abc; Path=/; SameSite=Lax`, + ]) + }) + + // Scenario: request header helpers should read scoped CSRF cookies without exposing scope logic to callers. + it('should read scoped cookie values from cookie headers', () => { + // Arrange + const scopedCsrfCookieName = toScopedLocalCookieName('csrf_token', 'cloud') + + // Act + const csrfToken = getCookieHeaderValue(`${scopedCsrfCookieName}=csrf; csrf_token=legacy`, scopedCsrfCookieName) + + // Assert + expect(csrfToken).toBe('csrf') + }) }) diff --git a/packages/dev-proxy/src/cookies.ts b/packages/dev-proxy/src/cookies.ts index 61fdb6abd4..b9deb6d214 100644 --- a/packages/dev-proxy/src/cookies.ts +++ b/packages/dev-proxy/src/cookies.ts @@ -1,6 +1,7 @@ import type { CookieRewriteOptions } from './types' const SECURE_COOKIE_PREFIX_PATTERN = /^__(Host|Secure)-/ +const LOCAL_SCOPED_COOKIE_PREFIX = 'dev_proxy' const SAME_SITE_NONE_PATTERN = /^samesite=none$/i const COOKIE_PATH_PATTERN = /^path=/i const COOKIE_DOMAIN_PATTERN = /^domain=/i @@ -14,6 +15,17 @@ const matchesCookieName = (cookieName: string, matcher: string | RegExp) => ? matcher === cookieName : matcher.test(cookieName) +const hashScope = (scope: string) => { + let hash = 0x811C9DC5 + + for (let index = 0; index < scope.length; index += 1) { + hash ^= scope.charCodeAt(index) + hash = Math.imul(hash, 0x01000193) + } + + return (hash >>> 0).toString(36) +} + const shouldUseHostPrefix = (cookieName: string, options: CookieRewriteOptions) => { const normalizedCookieName = stripSecureCookiePrefix(cookieName) @@ -35,14 +47,29 @@ const toUpstreamCookieName = (cookieName: string, options: CookieRewriteOptions) export const toLocalCookieName = (cookieName: string) => stripSecureCookiePrefix(cookieName) -export const rewriteCookieHeaderForUpstream = ( - cookieHeader: string | undefined, - options: CookieRewriteOptions & { useHostPrefix?: boolean }, -) => { - if (!cookieHeader) - return cookieHeader +export const resolveCookieRewriteLocalScopeKey = (options: CookieRewriteOptions, targetUrl: URL) => { + if (options.localCookieScope === 'target-origin') + return hashScope(targetUrl.origin) - const { useHostPrefix = true } = options + return undefined +} + +export const toScopedLocalCookieName = (cookieName: string, localScopeKey: string) => + `${LOCAL_SCOPED_COOKIE_PREFIX}_${localScopeKey}_${toLocalCookieName(cookieName)}` + +const fromScopedLocalCookieName = (cookieName: string, localScopeKey: string) => { + const scopedPrefix = `${LOCAL_SCOPED_COOKIE_PREFIX}_${localScopeKey}_` + if (!cookieName.startsWith(scopedPrefix)) + return undefined + + return cookieName.slice(scopedPrefix.length) +} + +const isScopedLocalCookieName = (cookieName: string) => cookieName.startsWith(`${LOCAL_SCOPED_COOKIE_PREFIX}_`) + +const parseCookieHeader = (cookieHeader: string | undefined) => { + if (!cookieHeader) + return [] return cookieHeader .split(/;\s*/) @@ -50,20 +77,62 @@ export const rewriteCookieHeaderForUpstream = ( .map((cookie) => { const separatorIndex = cookie.indexOf('=') if (separatorIndex === -1) - return cookie + return { name: cookie, value: undefined } - const cookieName = cookie.slice(0, separatorIndex).trim() - const cookieValue = cookie.slice(separatorIndex + 1) - const upstreamCookieName = useHostPrefix - ? toUpstreamCookieName(cookieName, options) - : cookieName - - return `${upstreamCookieName}=${cookieValue}` + return { + name: cookie.slice(0, separatorIndex).trim(), + value: cookie.slice(separatorIndex + 1), + } }) +} + +export const getCookieHeaderValue = (cookieHeader: string | undefined, cookieName: string) => { + const cookie = parseCookieHeader(cookieHeader).find(cookie => cookie.name === cookieName) + return cookie?.value +} + +export const rewriteCookieHeaderForUpstream = ( + cookieHeader: string | undefined, + options: CookieRewriteOptions & { useHostPrefix?: boolean, localScopeKey?: string }, +) => { + if (!cookieHeader) + return cookieHeader + + const { useHostPrefix = true } = options + + return parseCookieHeader(cookieHeader) + .map((cookie) => { + if (cookie.value === undefined) + return cookie.name + + const scopedCookieName = options.localScopeKey + ? fromScopedLocalCookieName(cookie.name, options.localScopeKey) + : undefined + + if (scopedCookieName) { + const upstreamCookieName = useHostPrefix + ? toUpstreamCookieName(scopedCookieName, options) + : scopedCookieName + return `${upstreamCookieName}=${cookie.value}` + } + + if (options.localScopeKey && (isScopedLocalCookieName(cookie.name) || shouldUseHostPrefix(cookie.name, options))) + return undefined + + const upstreamCookieName = useHostPrefix + ? toUpstreamCookieName(cookie.name, options) + : cookie.name + + return `${upstreamCookieName}=${cookie.value}` + }) + .filter((cookie): cookie is string => Boolean(cookie)) .join('; ') } -const rewriteSetCookieValueForLocal = (setCookieValue: string) => { +const rewriteSetCookieValueForLocal = ( + setCookieValue: string, + options?: CookieRewriteOptions & { localScopeKey?: string }, +) => { const [rawCookiePair, ...rawAttributes] = setCookieValue.split(';') const separatorIndex = rawCookiePair!.indexOf('=') @@ -72,6 +141,13 @@ const rewriteSetCookieValueForLocal = (setCookieValue: string) => { const cookieName = rawCookiePair!.slice(0, separatorIndex).trim() const cookieValue = rawCookiePair!.slice(separatorIndex + 1) + const localCookieName = toLocalCookieName(cookieName) + const shouldScopeCookie = Boolean( + options?.localScopeKey && shouldUseHostPrefix(cookieName, options), + ) + const rewrittenCookieName = shouldScopeCookie + ? toScopedLocalCookieName(cookieName, options!.localScopeKey!) + : localCookieName const rewrittenAttributes = rawAttributes .map(attribute => attribute.trim()) .filter(attribute => @@ -89,8 +165,10 @@ const rewriteSetCookieValueForLocal = (setCookieValue: string) => { return attribute }) - return [`${toLocalCookieName(cookieName)}=${cookieValue}`, ...rewrittenAttributes].join('; ') + return [`${rewrittenCookieName}=${cookieValue}`, ...rewrittenAttributes].join('; ') } -export const rewriteSetCookieHeadersForLocal = (setCookieHeaders: readonly string[]) => - setCookieHeaders.map(rewriteSetCookieValueForLocal) +export const rewriteSetCookieHeadersForLocal = ( + setCookieHeaders: readonly string[], + options?: CookieRewriteOptions & { localScopeKey?: string }, +) => setCookieHeaders.map(cookie => rewriteSetCookieValueForLocal(cookie, options)) diff --git a/packages/dev-proxy/src/server.spec.ts b/packages/dev-proxy/src/server.spec.ts index 32c16a1807..1a60d44f9d 100644 --- a/packages/dev-proxy/src/server.spec.ts +++ b/packages/dev-proxy/src/server.spec.ts @@ -2,6 +2,7 @@ * @vitest-environment node */ import { beforeEach, describe, expect, it, vi } from 'vitest' +import { resolveCookieRewriteLocalScopeKey, toScopedLocalCookieName } from './cookies' import { buildUpstreamUrl, createDevProxyApp, isAllowedDevOrigin } from './server' describe('dev proxy server', () => { @@ -155,6 +156,66 @@ describe('dev proxy server', () => { expect(requestHeaders.get('cookie')).toBe('access_token=abc; refresh_token=def') }) + // Scenario: scoped Dify auth cookies should prevent stale local cookies from leaking across targets. + it('should proxy target-scoped auth cookies and override stale CSRF headers', async () => { + // Arrange + const cookieRewrite = { + hostPrefixCookies: ['access_token', 'csrf_token', 'refresh_token'], + localCookieScope: 'target-origin' as const, + csrfHeader: { + cookieName: 'csrf_token', + headerName: 'X-CSRF-Token', + }, + } + const targetUrl = new URL('https://cloud.example.com') + const localScopeKey = resolveCookieRewriteLocalScopeKey(cookieRewrite, targetUrl)! + const accessTokenCookieName = toScopedLocalCookieName('access_token', localScopeKey) + const csrfTokenCookieName = toScopedLocalCookieName('csrf_token', localScopeKey) + const otherScopeAccessTokenCookieName = toScopedLocalCookieName('access_token', 'other') + const fetchImpl = vi.fn().mockResolvedValue(new Response('ok', { + status: 200, + headers: [ + ['set-cookie', '__Host-access_token=next; Path=/console/api; Domain=cloud.example.com; Secure; SameSite=None'], + ], + })) + const app = createDevProxyApp({ + routes: [ + { + paths: '/console/api', + target: targetUrl.origin, + cookieRewrite, + }, + ], + fetchImpl, + }) + + // Act + const response = await app.request('http://127.0.0.1:5001/console/api/apps', { + headers: { + 'Cookie': [ + `${accessTokenCookieName}=current-access`, + `${csrfTokenCookieName}=current-csrf`, + 'access_token=legacy-access', + 'csrf_token=legacy-csrf', + `${otherScopeAccessTokenCookieName}=other-access`, + 'theme=dark', + ].join('; '), + 'X-CSRF-Token': 'legacy-csrf', + }, + }) + + // Assert + const requestHeaders = fetchImpl.mock.calls[0]?.[1]?.headers + if (!(requestHeaders instanceof Headers)) + throw new Error('Expected proxy request headers to be Headers') + + expect(requestHeaders.get('cookie')).toBe('__Host-access_token=current-access; __Host-csrf_token=current-csrf; theme=dark') + expect(requestHeaders.get('x-csrf-token')).toBe('current-csrf') + expect(response.headers.getSetCookie()).toEqual([ + `${accessTokenCookieName}=next; Path=/; SameSite=Lax`, + ]) + }) + // Scenario: custom route paths should support independent upstream targets. it('should proxy custom route paths to their configured targets', async () => { // Arrange diff --git a/packages/dev-proxy/src/server.ts b/packages/dev-proxy/src/server.ts index 79654750da..4719edfdfe 100644 --- a/packages/dev-proxy/src/server.ts +++ b/packages/dev-proxy/src/server.ts @@ -1,7 +1,13 @@ import type { Context, Hono } from 'hono' import type { CookieRewriteOptions, CreateDevProxyAppOptions, DevProxyCorsAllowedOrigins, DevProxyRoute } from './types' import { Hono as HonoApp } from 'hono' -import { rewriteCookieHeaderForUpstream, rewriteSetCookieHeadersForLocal } from './cookies' +import { + getCookieHeaderValue, + resolveCookieRewriteLocalScopeKey, + rewriteCookieHeaderForUpstream, + rewriteSetCookieHeadersForLocal, + toScopedLocalCookieName, +} from './cookies' const LOCAL_DEV_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]', '::1']) const ALLOW_METHODS = 'GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS' @@ -100,12 +106,26 @@ const createProxyRequestHeaders = ( headers.set('origin', targetUrl.origin) if (cookieRewrite) { + const originalCookieHeader = headers.get('cookie') || undefined + const localScopeKey = resolveCookieRewriteLocalScopeKey(cookieRewrite, targetUrl) const rewrittenCookieHeader = rewriteCookieHeaderForUpstream(headers.get('cookie') || undefined, { ...cookieRewrite, + localScopeKey, useHostPrefix: targetUrl.protocol === 'https:', }) if (rewrittenCookieHeader) headers.set('cookie', rewrittenCookieHeader) + else + headers.delete('cookie') + + if (localScopeKey && cookieRewrite.csrfHeader) { + const scopedCsrfCookieName = toScopedLocalCookieName(cookieRewrite.csrfHeader.cookieName, localScopeKey) + const scopedCsrfToken = getCookieHeaderValue(originalCookieHeader, scopedCsrfCookieName) + if (scopedCsrfToken) + headers.set(cookieRewrite.csrfHeader.headerName, scopedCsrfToken) + else + headers.delete(cookieRewrite.csrfHeader.headerName) + } } return headers @@ -123,6 +143,7 @@ const getSetCookieHeaders = (headers: Headers) => { const createUpstreamResponseHeaders = ( response: Response, + targetUrl: URL, requestOrigin: string | undefined | null, allowedOrigins: DevProxyCorsAllowedOrigins, cookieRewrite: CookieRewriteOptions | false | undefined, @@ -131,9 +152,15 @@ const createUpstreamResponseHeaders = ( RESPONSE_HEADERS_TO_DROP.forEach(header => headers.delete(header)) headers.delete('set-cookie') + const localScopeKey = cookieRewrite + ? resolveCookieRewriteLocalScopeKey(cookieRewrite, targetUrl) + : undefined const setCookieHeaders = getSetCookieHeaders(response.headers) const responseSetCookieHeaders = cookieRewrite - ? rewriteSetCookieHeadersForLocal(setCookieHeaders) + ? rewriteSetCookieHeadersForLocal(setCookieHeaders, { + ...cookieRewrite, + localScopeKey, + }) : setCookieHeaders responseSetCookieHeaders.forEach((cookie) => { @@ -167,6 +194,7 @@ const proxyRequest = async ( const upstreamResponse = await fetchImpl(targetUrl, requestInit) const responseHeaders = createUpstreamResponseHeaders( upstreamResponse, + targetUrl, context.req.header('origin'), allowedOrigins, route.cookieRewrite, diff --git a/packages/dev-proxy/src/types.ts b/packages/dev-proxy/src/types.ts index 2c42b2f7fb..5257ffaa50 100644 --- a/packages/dev-proxy/src/types.ts +++ b/packages/dev-proxy/src/types.ts @@ -11,8 +11,15 @@ export type DevProxyCorsConfig = { export type CookieNameMatcher = string | RegExp +export type CookieRewriteLocalScope = 'target-origin' + export type CookieRewriteOptions = { hostPrefixCookies?: readonly CookieNameMatcher[] + localCookieScope?: CookieRewriteLocalScope + csrfHeader?: { + cookieName: string + headerName: string + } } export type DevProxyRoute = { diff --git a/web/dev-proxy.config.ts b/web/dev-proxy.config.ts index d9787795b3..c3d1528fb0 100644 --- a/web/dev-proxy.config.ts +++ b/web/dev-proxy.config.ts @@ -14,6 +14,11 @@ const difyCookieRewrite: CookieRewriteOptions = { 'webapp_access_token', /^passport-/, ], + localCookieScope: 'target-origin', + csrfHeader: { + cookieName: 'csrf_token', + headerName: 'X-CSRF-Token', + }, } export default { From b04b4449db40f3a3e527e353767f38a7a5d5f3a3 Mon Sep 17 00:00:00 2001 From: Stephen Zhou Date: Tue, 19 May 2026 14:13:20 +0800 Subject: [PATCH 6/7] chore(api): annotate simple contract responses (#36331) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Asuka Minato --- api/controllers/common/fields.py | 110 +- api/controllers/console/app/app.py | 11 +- api/controllers/console/app/completion.py | 8 +- api/controllers/console/app/message.py | 6 +- api/controllers/console/app/workflow.py | 17 +- api/controllers/console/auth/activate.py | 27 +- .../console/auth/data_source_bearer_auth.py | 19 +- .../console/auth/email_register.py | 6 +- api/controllers/console/auth/login.py | 15 +- .../console/datasets/data_source.py | 8 +- api/controllers/console/datasets/datasets.py | 15 +- .../console/datasets/datasets_document.py | 30 +- .../console/datasets/datasets_segments.py | 16 +- api/controllers/console/datasets/external.py | 8 +- api/controllers/console/datasets/metadata.py | 7 +- .../datasets/rag_pipeline/datasource_auth.py | 8 +- .../datasets/rag_pipeline/rag_pipeline.py | 5 +- .../rag_pipeline/rag_pipeline_workflow.py | 21 + api/controllers/console/explore/completion.py | 6 +- .../console/explore/conversation.py | 6 +- .../console/explore/installed_app.py | 7 +- api/controllers/console/explore/message.py | 5 +- .../console/explore/saved_message.py | 5 +- api/controllers/console/explore/workflow.py | 5 +- api/controllers/console/feature.py | 13 +- api/controllers/console/files.py | 6 +- api/controllers/console/notification.py | 6 + api/controllers/console/remote_files.py | 8 + api/controllers/console/tag/tags.py | 9 +- api/controllers/console/workspace/account.py | 23 +- api/controllers/console/workspace/members.py | 6 +- .../console/workspace/model_providers.py | 7 +- api/controllers/console/workspace/models.py | 10 +- api/controllers/console/workspace/plugin.py | 17 +- .../console/workspace/tool_providers.py | 5 +- .../console/workspace/trigger_providers.py | 5 +- .../console/workspace/workspace.py | 10 +- api/controllers/service_api/app/app.py | 18 + api/controllers/service_api/app/completion.py | 6 +- api/controllers/service_api/app/message.py | 10 +- api/controllers/service_api/app/site.py | 8 + api/controllers/service_api/app/workflow.py | 5 +- .../service_api/dataset/dataset.py | 9 +- .../service_api/dataset/document.py | 9 +- .../service_api/dataset/metadata.py | 14 +- .../service_api/end_user/end_user.py | 4 + api/controllers/service_api/index.py | 5 + api/controllers/web/app.py | 9 +- api/controllers/web/completion.py | 6 +- api/controllers/web/conversation.py | 5 +- api/controllers/web/feature.py | 10 +- api/controllers/web/forgot_password.py | 12 +- api/controllers/web/login.py | 24 +- api/controllers/web/message.py | 5 +- api/controllers/web/remote_files.py | 5 +- api/controllers/web/saved_message.py | 4 +- api/controllers/web/workflow.py | 5 +- api/fields/file_fields.py | 4 +- api/openapi/markdown/console-swagger.md | 998 ++++++++++++------ api/openapi/markdown/service-swagger.md | 219 ++-- api/openapi/markdown/web-swagger.md | 415 +++++--- api/services/feature_service.py | 38 +- packages/contracts/README.md | 12 +- .../generated/api/console/account/orpc.gen.ts | 64 +- .../api/console/account/types.gen.ts | 51 +- .../generated/api/console/account/zod.gen.ts | 47 +- .../api/console/activate/orpc.gen.ts | 8 +- .../api/console/activate/types.gen.ts | 10 +- .../generated/api/console/activate/zod.gen.ts | 11 +- .../api/console/api-key-auth/orpc.gen.ts | 17 +- .../api/console/api-key-auth/types.gen.ts | 21 +- .../api/console/api-key-auth/zod.gen.ts | 25 +- .../generated/api/console/apps/orpc.gen.ts | 54 +- .../generated/api/console/apps/types.gen.ts | 44 +- .../generated/api/console/apps/zod.gen.ts | 43 +- .../generated/api/console/auth/orpc.gen.ts | 32 - .../generated/api/console/auth/types.gen.ts | 20 +- .../generated/api/console/auth/zod.gen.ts | 24 +- .../api/console/data-source/orpc.gen.ts | 16 - .../api/console/data-source/types.gen.ts | 12 +- .../api/console/data-source/zod.gen.ts | 14 +- .../api/console/datasets/orpc.gen.ts | 254 +---- .../api/console/datasets/types.gen.ts | 159 ++- .../generated/api/console/datasets/zod.gen.ts | 195 ++-- .../api/console/email-code-login/orpc.gen.ts | 16 - .../api/console/email-code-login/types.gen.ts | 17 +- .../api/console/email-code-login/zod.gen.ts | 19 +- .../api/console/email-register/types.gen.ts | 19 +- .../api/console/email-register/zod.gen.ts | 21 +- .../api/console/features/orpc.gen.ts | 8 +- .../api/console/features/types.gen.ts | 63 +- .../generated/api/console/features/zod.gen.ts | 89 +- .../generated/api/console/files/orpc.gen.ts | 16 - .../generated/api/console/files/types.gen.ts | 16 +- .../generated/api/console/files/zod.gen.ts | 18 +- .../api/console/installed-apps/orpc.gen.ts | 90 +- .../api/console/installed-apps/types.gen.ts | 73 +- .../api/console/installed-apps/zod.gen.ts | 95 +- .../generated/api/console/login/orpc.gen.ts | 7 - .../generated/api/console/login/types.gen.ts | 9 +- .../generated/api/console/login/zod.gen.ts | 10 +- .../generated/api/console/logout/orpc.gen.ts | 8 - .../generated/api/console/logout/types.gen.ts | 8 +- .../generated/api/console/logout/zod.gen.ts | 9 +- .../api/console/notification/types.gen.ts | 8 +- .../api/console/notification/zod.gen.ts | 9 +- .../generated/api/console/notion/orpc.gen.ts | 8 - .../generated/api/console/notion/types.gen.ts | 8 +- .../generated/api/console/notion/zod.gen.ts | 9 +- .../generated/api/console/rag/orpc.gen.ts | 38 +- .../generated/api/console/rag/types.gen.ts | 43 +- .../generated/api/console/rag/zod.gen.ts | 62 +- .../api/console/refresh-token/orpc.gen.ts | 8 - .../api/console/refresh-token/types.gen.ts | 8 +- .../api/console/refresh-token/zod.gen.ts | 9 +- .../api/console/remote-files/orpc.gen.ts | 19 +- .../api/console/remote-files/types.gen.ts | 30 +- .../api/console/remote-files/zod.gen.ts | 37 +- .../api/console/reset-password/orpc.gen.ts | 8 - .../api/console/reset-password/types.gen.ts | 9 +- .../api/console/reset-password/zod.gen.ts | 10 +- .../api/console/system-features/orpc.gen.ts | 7 +- .../api/console/system-features/types.gen.ts | 78 +- .../api/console/system-features/zod.gen.ts | 111 +- .../api/console/tag-bindings/orpc.gen.ts | 16 +- .../api/console/tag-bindings/types.gen.ts | 12 +- .../api/console/tag-bindings/zod.gen.ts | 11 +- .../generated/api/console/tags/orpc.gen.ts | 25 +- .../generated/api/console/tags/types.gen.ts | 12 +- .../generated/api/console/tags/zod.gen.ts | 8 +- .../api/console/workspaces/orpc.gen.ts | 161 +-- .../api/console/workspaces/types.gen.ts | 111 +- .../api/console/workspaces/zod.gen.ts | 127 ++- .../contracts/generated/api/readiness.json | 6 +- .../generated/api/service/orpc.gen.ts | 91 +- .../generated/api/service/types.gen.ts | 129 ++- .../generated/api/service/zod.gen.ts | 145 ++- .../contracts/generated/api/web/orpc.gen.ts | 142 +-- .../contracts/generated/api/web/types.gen.ts | 205 ++-- .../contracts/generated/api/web/zod.gen.ts | 232 +++- packages/contracts/openapi-ts.api.config.ts | 188 +++- .../scripts/generate-api-readiness-readme.mjs | 2 +- 142 files changed, 3830 insertions(+), 2399 deletions(-) diff --git a/api/controllers/common/fields.py b/api/controllers/common/fields.py index 8e665c1386..a90a26e730 100644 --- a/api/controllers/common/fields.py +++ b/api/controllers/common/fields.py @@ -2,8 +2,9 @@ from __future__ import annotations from typing import Any -from pydantic import BaseModel, ConfigDict, computed_field +from pydantic import BaseModel, ConfigDict, Field, computed_field +from fields.base import ResponseModel from graphon.file import helpers as file_helpers from models.model import IconType @@ -19,6 +20,113 @@ class SystemParameters(BaseModel): workflow_file_upload_limit: int +class SimpleResultResponse(ResponseModel): + result: str + + +class SimpleResultMessageResponse(ResponseModel): + result: str + message: str + + +class SimpleMessageResponse(ResponseModel): + message: str + + +class SimpleDataResponse(ResponseModel): + data: str + + +class SimpleResultDataResponse(ResponseModel): + result: str + data: str + + +class SimpleResultStringListResponse(ResponseModel): + result: str + data: list[str] + + +class SimpleResultOptionalDataResponse(ResponseModel): + result: str + data: str | None = None + + +class AccessTokenData(ResponseModel): + access_token: str + + +class AccessTokenResultResponse(ResponseModel): + result: str + data: AccessTokenData + + +class VerificationTokenResponse(ResponseModel): + is_valid: bool + email: str + token: str + + +class LoginStatusResponse(ResponseModel): + logged_in: bool + app_logged_in: bool + + +class AccessModeResponse(ResponseModel): + access_mode: str = Field(serialization_alias="accessMode", validation_alias="accessMode") + + +class BooleanResultResponse(ResponseModel): + result: bool + + +class SuccessResponse(ResponseModel): + success: bool + + +class UsageCheckResponse(ResponseModel): + is_using: bool + + +class UsageCountResponse(ResponseModel): + is_using: bool + count: int + + +class IndexInfoResponse(ResponseModel): + welcome: str + api_version: str + server_version: str + + +class AvatarUrlResponse(ResponseModel): + avatar_url: str + + +class TextContentResponse(ResponseModel): + content: str + + +class AllowedExtensionsResponse(ResponseModel): + allowed_extensions: list[str] + + +class UrlResponse(ResponseModel): + url: str + + +class RedirectUrlResponse(ResponseModel): + redirect_url: str + + +class ApiBaseUrlResponse(ResponseModel): + api_base_url: str + + +class NewAppResponse(ResponseModel): + new_app_id: str + + class Parameters(BaseModel): opening_statement: str | None = None suggested_questions: list[str] diff --git a/api/controllers/console/app/app.py b/api/controllers/console/app/app.py index 045325f283..28d16f852b 100644 --- a/api/controllers/console/app/app.py +++ b/api/controllers/console/app/app.py @@ -12,8 +12,9 @@ from sqlalchemy.orm import Session from werkzeug.datastructures import MultiDict from werkzeug.exceptions import BadRequest +from controllers.common.fields import RedirectUrlResponse, SimpleResultResponse from controllers.common.helpers import FileInfo -from controllers.common.schema import register_enum_models, register_schema_models +from controllers.common.schema import register_enum_models, register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.app.wraps import get_app_model from controllers.console.workspace.models import LoadBalancingPayload @@ -413,6 +414,7 @@ class AppExportResponse(ResponseModel): register_enum_models(console_ns, RetrievalMethod, WorkflowExecutionStatus, DatasetPermissionEnum) +register_response_schema_models(console_ns, RedirectUrlResponse, SimpleResultResponse) register_schema_models( console_ns, @@ -724,6 +726,7 @@ class AppExportApi(Resource): @console_ns.route("/apps//publish-to-creators-platform") class AppPublishToCreatorsPlatformApi(Resource): + @console_ns.response(200, "Success", console_ns.models[RedirectUrlResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -861,7 +864,11 @@ class AppTraceApi(Resource): @console_ns.doc(description="Update app tracing configuration") @console_ns.doc(params={"app_id": "Application ID"}) @console_ns.expect(console_ns.models[AppTracePayload.__name__]) - @console_ns.response(200, "Trace configuration updated successfully") + @console_ns.response( + 200, + "Trace configuration updated successfully", + console_ns.models[SimpleResultResponse.__name__], + ) @console_ns.response(403, "Insufficient permissions") @setup_required @login_required diff --git a/api/controllers/console/app/completion.py b/api/controllers/console/app/completion.py index 6a20296cff..817623bf7f 100644 --- a/api/controllers/console/app/completion.py +++ b/api/controllers/console/app/completion.py @@ -7,7 +7,8 @@ from pydantic import BaseModel, Field, field_validator from werkzeug.exceptions import InternalServerError, NotFound import services -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.app.error import ( AppUnavailableError, @@ -66,6 +67,7 @@ class ChatMessagePayload(BaseMessagePayload): register_schema_models(console_ns, CompletionMessagePayload, ChatMessagePayload) +register_response_schema_models(console_ns, SimpleResultResponse) # define completion message api for user @@ -124,7 +126,7 @@ class CompletionMessageStopApi(Resource): @console_ns.doc("stop_completion_message") @console_ns.doc(description="Stop a running completion message generation") @console_ns.doc(params={"app_id": "Application ID", "task_id": "Task ID to stop"}) - @console_ns.response(200, "Task stopped successfully") + @console_ns.response(200, "Task stopped successfully", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -205,7 +207,7 @@ class ChatMessageStopApi(Resource): @console_ns.doc("stop_chat_message") @console_ns.doc(description="Stop a running chat message generation") @console_ns.doc(params={"app_id": "Application ID", "task_id": "Task ID to stop"}) - @console_ns.response(200, "Task stopped successfully") + @console_ns.response(200, "Task stopped successfully", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/app/message.py b/api/controllers/console/app/message.py index 4b596b992f..06afe15548 100644 --- a/api/controllers/console/app/message.py +++ b/api/controllers/console/app/message.py @@ -9,7 +9,8 @@ from sqlalchemy import exists, func, select from werkzeug.exceptions import InternalServerError, NotFound from controllers.common.controller_schemas import MessageFeedbackPayload as _MessageFeedbackPayloadBase -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.app.error import ( CompletionRequestError, @@ -162,6 +163,7 @@ register_schema_models( MessageDetailResponse, MessageInfiniteScrollPaginationResponse, ) +register_response_schema_models(console_ns, SimpleResultResponse) @console_ns.route("/apps//chat-messages") @@ -247,7 +249,7 @@ class MessageFeedbackApi(Resource): @console_ns.doc(description="Create or update message feedback (like/dislike)") @console_ns.doc(params={"app_id": "Application ID"}) @console_ns.expect(console_ns.models[MessageFeedbackPayload.__name__]) - @console_ns.response(200, "Feedback updated successfully") + @console_ns.response(200, "Feedback updated successfully", console_ns.models[SimpleResultResponse.__name__]) @console_ns.response(404, "Message not found") @console_ns.response(403, "Insufficient permissions") @get_app_model diff --git a/api/controllers/console/app/workflow.py b/api/controllers/console/app/workflow.py index 8d065ece67..53744747d7 100644 --- a/api/controllers/console/app/workflow.py +++ b/api/controllers/console/app/workflow.py @@ -12,6 +12,7 @@ from werkzeug.exceptions import BadRequest, Forbidden, InternalServerError, NotF import services from controllers.common.controller_schemas import DefaultBlockConfigQuery, WorkflowListQuery, WorkflowUpdatePayload +from controllers.common.fields import NewAppResponse, SimpleResultResponse from controllers.common.schema import ( register_response_schema_model, register_response_schema_models, @@ -290,6 +291,8 @@ register_response_schema_models( WorkflowOnlineUser, WorkflowOnlineUsersByApp, WorkflowOnlineUsersResponse, + NewAppResponse, + SimpleResultResponse, ) @@ -869,7 +872,7 @@ class WorkflowTaskStopApi(Resource): @console_ns.doc("stop_workflow_task") @console_ns.doc(description="Stop running workflow task") @console_ns.doc(params={"app_id": "Application ID", "task_id": "Task ID"}) - @console_ns.response(200, "Task stopped successfully") + @console_ns.response(200, "Task stopped successfully", console_ns.models[SimpleResultResponse.__name__]) @console_ns.response(404, "Task not found") @console_ns.response(403, "Permission denied") @setup_required @@ -1069,7 +1072,11 @@ class ConvertToWorkflowApi(Resource): @console_ns.doc("convert_to_workflow") @console_ns.doc(description="Convert application to workflow mode") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.response(200, "Application converted to workflow successfully") + @console_ns.response( + 200, + "Application converted to workflow successfully", + console_ns.models[NewAppResponse.__name__], + ) @console_ns.response(400, "Application cannot be converted") @console_ns.response(403, "Permission denied") @setup_required @@ -1106,7 +1113,11 @@ class WorkflowFeaturesApi(Resource): @console_ns.doc("update_workflow_features") @console_ns.doc(description="Update draft workflow features") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.response(200, "Workflow features updated successfully") + @console_ns.response( + 200, + "Workflow features updated successfully", + console_ns.models[SimpleResultResponse.__name__], + ) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/auth/activate.py b/api/controllers/console/auth/activate.py index 0c05cf2fe3..eedb285434 100644 --- a/api/controllers/console/auth/activate.py +++ b/api/controllers/console/auth/activate.py @@ -1,5 +1,3 @@ -from typing import Any - from flask import request from flask_restx import Resource from pydantic import BaseModel, Field, field_validator @@ -40,16 +38,29 @@ class ActivatePayload(BaseModel): return timezone(value) -class ActivationCheckResponse(BaseModel): - is_valid: bool = Field(description="Whether token is valid") - data: dict[str, Any] | None = Field(default=None, description="Activation data if valid") - - class ActivationResponse(BaseModel): result: str = Field(description="Operation result") -register_schema_models(console_ns, ActivateCheckQuery, ActivatePayload, ActivationCheckResponse, ActivationResponse) +class ActivationCheckData(BaseModel): + workspace_name: str | None + workspace_id: str | None + email: str | None + + +class ActivationCheckResponse(BaseModel): + is_valid: bool = Field(description="Whether token is valid") + data: ActivationCheckData | None = Field(default=None, description="Activation data if valid") + + +register_schema_models( + console_ns, + ActivateCheckQuery, + ActivatePayload, + ActivationCheckData, + ActivationCheckResponse, + ActivationResponse, +) @console_ns.route("/activate/check") diff --git a/api/controllers/console/auth/data_source_bearer_auth.py b/api/controllers/console/auth/data_source_bearer_auth.py index db0d36af6e..2e3b8d2295 100644 --- a/api/controllers/console/auth/data_source_bearer_auth.py +++ b/api/controllers/console/auth/data_source_bearer_auth.py @@ -1,7 +1,8 @@ from flask_restx import Resource from pydantic import BaseModel, Field -from controllers.common.schema import register_schema_models +from controllers.common.schema import register_response_schema_models, register_schema_models +from fields.base import ResponseModel from libs.login import current_account_with_tenant, login_required from services.auth.api_key_auth_service import ApiKeyAuthService @@ -16,11 +17,26 @@ class ApiKeyAuthBindingPayload(BaseModel): credentials: dict = Field(...) +class ApiKeyAuthDataSourceItem(ResponseModel): + id: str + category: str + provider: str + disabled: bool + created_at: int + updated_at: int + + +class ApiKeyAuthDataSourceListResponse(ResponseModel): + sources: list[ApiKeyAuthDataSourceItem] + + register_schema_models(console_ns, ApiKeyAuthBindingPayload) +register_response_schema_models(console_ns, ApiKeyAuthDataSourceItem, ApiKeyAuthDataSourceListResponse) @console_ns.route("/api-key-auth/data-source") class ApiKeyAuthDataSource(Resource): + @console_ns.response(200, "Success", console_ns.models[ApiKeyAuthDataSourceListResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -70,6 +86,7 @@ class ApiKeyAuthDataSourceBindingDelete(Resource): @login_required @account_initialization_required @is_admin_or_owner_required + @console_ns.response(204, "Binding deleted successfully") def delete(self, binding_id): # The role of the current user in the table must be admin or owner _, current_tenant_id = current_account_with_tenant() diff --git a/api/controllers/console/auth/email_register.py b/api/controllers/console/auth/email_register.py index e1f3f0eaeb..15d8b2ccd2 100644 --- a/api/controllers/console/auth/email_register.py +++ b/api/controllers/console/auth/email_register.py @@ -4,7 +4,8 @@ from pydantic import BaseModel, Field, field_validator from configs import dify_config from constants.languages import get_valid_language, languages -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultDataResponse, VerificationTokenResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.auth.error import ( EmailAlreadyInUseError, @@ -58,6 +59,7 @@ class EmailRegisterResetPayload(BaseModel): register_schema_models(console_ns, EmailRegisterSendPayload, EmailRegisterValidityPayload, EmailRegisterResetPayload) +register_response_schema_models(console_ns, SimpleResultDataResponse, VerificationTokenResponse) @console_ns.route("/email-register/send-email") @@ -65,6 +67,7 @@ class EmailRegisterSendEmailApi(Resource): @setup_required @email_password_login_enabled @email_register_enabled + @console_ns.response(200, "Success", console_ns.models[SimpleResultDataResponse.__name__]) def post(self): args = EmailRegisterSendPayload.model_validate(console_ns.payload) normalized_email = args.email.lower() @@ -89,6 +92,7 @@ class EmailRegisterCheckApi(Resource): @setup_required @email_password_login_enabled @email_register_enabled + @console_ns.response(200, "Success", console_ns.models[VerificationTokenResponse.__name__]) def post(self): args = EmailRegisterValidityPayload.model_validate(console_ns.payload) diff --git a/api/controllers/console/auth/login.py b/api/controllers/console/auth/login.py index 3121470b84..712fce2aa9 100644 --- a/api/controllers/console/auth/login.py +++ b/api/controllers/console/auth/login.py @@ -9,7 +9,8 @@ from werkzeug.exceptions import Unauthorized import services from configs import dify_config from constants.languages import get_valid_language -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultDataResponse, SimpleResultOptionalDataResponse, SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.auth.error import ( AuthenticationFailedError, @@ -81,6 +82,12 @@ class EmailCodeLoginPayload(BaseModel): register_schema_models(console_ns, LoginPayload, EmailPayload, EmailCodeLoginPayload) +register_response_schema_models( + console_ns, + SimpleResultDataResponse, + SimpleResultOptionalDataResponse, + SimpleResultResponse, +) @console_ns.route("/login") @@ -90,6 +97,7 @@ class LoginApi(Resource): @setup_required @email_password_login_enabled @console_ns.expect(console_ns.models[LoginPayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultOptionalDataResponse.__name__]) @decrypt_password_field def post(self): """Authenticate user and login.""" @@ -163,6 +171,7 @@ class LoginApi(Resource): @console_ns.route("/logout") class LogoutApi(Resource): @setup_required + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def post(self): current_user, _ = current_account_with_tenant() account = current_user @@ -186,6 +195,7 @@ class ResetPasswordSendEmailApi(Resource): @setup_required @email_password_login_enabled @console_ns.expect(console_ns.models[EmailPayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultDataResponse.__name__]) def post(self): args = EmailPayload.model_validate(console_ns.payload) normalized_email = args.email.lower() @@ -213,6 +223,7 @@ class ResetPasswordSendEmailApi(Resource): class EmailCodeLoginSendEmailApi(Resource): @setup_required @console_ns.expect(console_ns.models[EmailPayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultDataResponse.__name__]) def post(self): args = EmailPayload.model_validate(console_ns.payload) normalized_email = args.email.lower() @@ -245,6 +256,7 @@ class EmailCodeLoginSendEmailApi(Resource): class EmailCodeLoginApi(Resource): @setup_required @console_ns.expect(console_ns.models[EmailCodeLoginPayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @decrypt_code_field def post(self): args = EmailCodeLoginPayload.model_validate(console_ns.payload) @@ -321,6 +333,7 @@ class EmailCodeLoginApi(Resource): @console_ns.route("/refresh-token") class RefreshTokenApi(Resource): + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def post(self): # Get refresh token from cookie instead of request body refresh_token = extract_refresh_token(request) diff --git a/api/controllers/console/datasets/data_source.py b/api/controllers/console/datasets/data_source.py index ed3c1a59d4..f81adb0313 100644 --- a/api/controllers/console/datasets/data_source.py +++ b/api/controllers/console/datasets/data_source.py @@ -9,7 +9,8 @@ from sqlalchemy import select from sqlalchemy.orm import sessionmaker from werkzeug.exceptions import NotFound -from controllers.common.schema import get_or_create_model, register_schema_model +from controllers.common.fields import SimpleResultResponse, TextContentResponse +from controllers.common.schema import get_or_create_model, register_response_schema_models, register_schema_model from core.datasource.entities.datasource_entities import DatasourceProviderType, OnlineDocumentPagesMessage from core.datasource.online_document.online_document_plugin import OnlineDocumentDatasourcePlugin from core.indexing_runner import IndexingRunner @@ -54,6 +55,7 @@ class DataSourceNotionPreviewQuery(BaseModel): register_schema_model(console_ns, NotionEstimatePayload) +register_response_schema_models(console_ns, SimpleResultResponse, TextContentResponse) integrate_icon_model = get_or_create_model("DataSourceIntegrateIcon", integrate_icon_fields) @@ -157,6 +159,7 @@ class DataSourceApi(Resource): @setup_required @login_required @account_initialization_required + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def patch(self, binding_id, action: Literal["enable", "disable"]): _, current_tenant_id = current_account_with_tenant() binding_id = str(binding_id) @@ -289,6 +292,7 @@ class DataSourceNotionApi(Resource): @setup_required @login_required @account_initialization_required + @console_ns.response(200, "Success", console_ns.models[TextContentResponse.__name__]) def get(self, page_id, page_type): _, current_tenant_id = current_account_with_tenant() @@ -362,6 +366,7 @@ class DataSourceNotionDatasetSyncApi(Resource): @setup_required @login_required @account_initialization_required + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def get(self, dataset_id): dataset_id_str = str(dataset_id) dataset = DatasetService.get_dataset(dataset_id_str) @@ -379,6 +384,7 @@ class DataSourceNotionDocumentSyncApi(Resource): @setup_required @login_required @account_initialization_required + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def get(self, dataset_id, document_id): dataset_id_str = str(dataset_id) document_id_str = str(document_id) diff --git a/api/controllers/console/datasets/datasets.py b/api/controllers/console/datasets/datasets.py index 0e91779b2c..0c5bf88a5a 100644 --- a/api/controllers/console/datasets/datasets.py +++ b/api/controllers/console/datasets/datasets.py @@ -8,7 +8,8 @@ from werkzeug.exceptions import Forbidden, NotFound import services from configs import dify_config -from controllers.common.schema import get_or_create_model, register_schema_models +from controllers.common.fields import ApiBaseUrlResponse, SimpleResultResponse, UsageCheckResponse +from controllers.common.schema import get_or_create_model, register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.apikey import ApiKeyItem, ApiKeyList from controllers.console.app.error import ProviderNotInitializeError @@ -58,6 +59,8 @@ from models.provider_ids import ModelProviderID from services.api_token_service import ApiTokenCache from services.dataset_service import DatasetPermissionService, DatasetService, DocumentService +register_response_schema_models(console_ns, ApiBaseUrlResponse, SimpleResultResponse, UsageCheckResponse) + # Register models for flask_restx to avoid dict type issues in Swagger dataset_base_model = get_or_create_model("DatasetBase", dataset_fields) @@ -521,6 +524,7 @@ class DatasetApi(Resource): @login_required @account_initialization_required @cloud_edition_billing_rate_limit_check("knowledge") + @console_ns.response(204, "Dataset deleted successfully") def delete(self, dataset_id): dataset_id_str = str(dataset_id) current_user, _ = current_account_with_tenant() @@ -543,7 +547,11 @@ class DatasetUseCheckApi(Resource): @console_ns.doc("check_dataset_use") @console_ns.doc(description="Check if dataset is in use") @console_ns.doc(params={"dataset_id": "Dataset ID"}) - @console_ns.response(200, "Dataset use status retrieved successfully") + @console_ns.response( + 200, + "Dataset use status retrieved successfully", + console_ns.models[UsageCheckResponse.__name__], + ) @setup_required @login_required @account_initialization_required @@ -873,6 +881,7 @@ class DatasetEnableApiApi(Resource): @setup_required @login_required @account_initialization_required + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def post(self, dataset_id, status): dataset_id_str = str(dataset_id) @@ -885,7 +894,7 @@ class DatasetEnableApiApi(Resource): class DatasetApiBaseUrlApi(Resource): @console_ns.doc("get_dataset_api_base_info") @console_ns.doc(description="Get dataset API base information") - @console_ns.response(200, "API base info retrieved successfully") + @console_ns.response(200, "API base info retrieved successfully", console_ns.models[ApiBaseUrlResponse.__name__]) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/datasets/datasets_document.py b/api/controllers/console/datasets/datasets_document.py index dfe8192b89..d98da48daa 100644 --- a/api/controllers/console/datasets/datasets_document.py +++ b/api/controllers/console/datasets/datasets_document.py @@ -15,7 +15,8 @@ from werkzeug.exceptions import Forbidden, NotFound import services from controllers.common.controller_schemas import DocumentBatchDownloadZipPayload -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultMessageResponse, SimpleResultResponse, UrlResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from core.errors.error import ( LLMBadRequestError, @@ -204,6 +205,7 @@ register_schema_models( DocumentWithSegmentsResponse, DatasetAndDocumentResponse, ) +register_response_schema_models(console_ns, SimpleResultMessageResponse, SimpleResultResponse, UrlResponse) class DocumentResource(Resource): @@ -487,6 +489,7 @@ class DatasetDocumentListApi(Resource): @login_required @account_initialization_required @cloud_edition_billing_rate_limit_check("knowledge") + @console_ns.response(204, "Documents deleted successfully") def delete(self, dataset_id): dataset_id = str(dataset_id) dataset = DatasetService.get_dataset(dataset_id) @@ -946,6 +949,7 @@ class DocumentApi(DocumentResource): @login_required @account_initialization_required @cloud_edition_billing_rate_limit_check("knowledge") + @console_ns.response(204, "Document deleted successfully") def delete(self, dataset_id, document_id): dataset_id = str(dataset_id) document_id = str(document_id) @@ -971,6 +975,7 @@ class DocumentDownloadApi(DocumentResource): @console_ns.doc("get_dataset_document_download_url") @console_ns.doc(description="Get a signed download URL for a dataset document's original uploaded file") + @console_ns.response(200, "Download URL generated successfully", console_ns.models[UrlResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -1028,7 +1033,11 @@ class DocumentProcessingApi(DocumentResource): @console_ns.doc( params={"dataset_id": "Dataset ID", "document_id": "Document ID", "action": "Action to perform (pause/resume)"} ) - @console_ns.response(200, "Processing status updated successfully") + @console_ns.response( + 200, + "Processing status updated successfully", + console_ns.models[SimpleResultResponse.__name__], + ) @console_ns.response(404, "Document not found") @console_ns.response(400, "Invalid action") @setup_required @@ -1073,7 +1082,11 @@ class DocumentMetadataApi(DocumentResource): @console_ns.doc(description="Update document metadata") @console_ns.doc(params={"dataset_id": "Dataset ID", "document_id": "Document ID"}) @console_ns.expect(console_ns.models[DocumentMetadataUpdatePayload.__name__]) - @console_ns.response(200, "Document metadata updated successfully") + @console_ns.response( + 200, + "Document metadata updated successfully", + console_ns.models[SimpleResultMessageResponse.__name__], + ) @console_ns.response(404, "Document not found") @console_ns.response(403, "Permission denied") @setup_required @@ -1127,6 +1140,7 @@ class DocumentStatusApi(DocumentResource): @account_initialization_required @cloud_edition_billing_resource_check("vector_space") @cloud_edition_billing_rate_limit_check("knowledge") + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def patch(self, dataset_id, action: Literal["enable", "disable", "archive", "un_archive"]): current_user, _ = current_account_with_tenant() dataset_id = str(dataset_id) @@ -1164,6 +1178,7 @@ class DocumentPauseApi(DocumentResource): @login_required @account_initialization_required @cloud_edition_billing_rate_limit_check("knowledge") + @console_ns.response(204, "Document paused successfully") def patch(self, dataset_id, document_id): """pause document.""" dataset_id = str(dataset_id) @@ -1198,6 +1213,7 @@ class DocumentRecoverApi(DocumentResource): @login_required @account_initialization_required @cloud_edition_billing_rate_limit_check("knowledge") + @console_ns.response(204, "Document resumed successfully") def patch(self, dataset_id, document_id): """recover document.""" dataset_id = str(dataset_id) @@ -1230,6 +1246,7 @@ class DocumentRetryApi(DocumentResource): @account_initialization_required @cloud_edition_billing_rate_limit_check("knowledge") @console_ns.expect(console_ns.models[DocumentRetryPayload.__name__]) + @console_ns.response(204, "Documents retry started successfully") def post(self, dataset_id): """retry document.""" payload = DocumentRetryPayload.model_validate(console_ns.payload or {}) @@ -1296,6 +1313,7 @@ class WebsiteDocumentSyncApi(DocumentResource): @setup_required @login_required @account_initialization_required + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def get(self, dataset_id, document_id): """sync website document.""" _, current_tenant_id = current_account_with_tenant() @@ -1362,7 +1380,11 @@ class DocumentGenerateSummaryApi(Resource): @console_ns.doc(description="Generate summary index for documents") @console_ns.doc(params={"dataset_id": "Dataset ID"}) @console_ns.expect(console_ns.models[GenerateSummaryPayload.__name__]) - @console_ns.response(200, "Summary generation started successfully") + @console_ns.response( + 200, + "Summary generation started successfully", + console_ns.models[SimpleResultResponse.__name__], + ) @console_ns.response(400, "Invalid request or dataset configuration") @console_ns.response(403, "Permission denied") @console_ns.response(404, "Dataset not found") diff --git a/api/controllers/console/datasets/datasets_segments.py b/api/controllers/console/datasets/datasets_segments.py index 2647bb1f5a..2eaa64994e 100644 --- a/api/controllers/console/datasets/datasets_segments.py +++ b/api/controllers/console/datasets/datasets_segments.py @@ -10,7 +10,8 @@ from werkzeug.exceptions import Forbidden, NotFound import services from configs import dify_config from controllers.common.controller_schemas import ChildChunkCreatePayload, ChildChunkUpdatePayload -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.app.error import ProviderNotInitializeError from controllers.console.datasets.error import ( @@ -30,6 +31,7 @@ from core.model_manager import ModelManager from core.rag.index_processor.constant.index_type import IndexTechniqueType from extensions.ext_database import db from extensions.ext_redis import redis_client +from fields.base import ResponseModel from fields.segment_fields import child_chunk_fields, segment_fields from graphon.model_runtime.entities.model_entities import ModelType from libs.helper import escape_like_pattern @@ -83,6 +85,11 @@ class BatchImportPayload(BaseModel): upload_file_id: str +class SegmentBatchImportStatusResponse(ResponseModel): + job_id: str + job_status: str + + class ChildChunkBatchUpdatePayload(BaseModel): chunks: list[ChildChunkUpdateArgs] @@ -98,6 +105,7 @@ register_schema_models( ChildChunkBatchUpdatePayload, ChildChunkUpdateArgs, ) +register_response_schema_models(console_ns, SegmentBatchImportStatusResponse, SimpleResultResponse) @console_ns.route("/datasets//documents//segments") @@ -217,6 +225,7 @@ class DatasetDocumentSegmentListApi(Resource): @login_required @account_initialization_required @cloud_edition_billing_rate_limit_check("knowledge") + @console_ns.response(204, "Segments deleted successfully") def delete(self, dataset_id, document_id): current_user, _ = current_account_with_tenant() @@ -252,6 +261,7 @@ class DatasetDocumentSegmentApi(Resource): @account_initialization_required @cloud_edition_billing_resource_check("vector_space") @cloud_edition_billing_rate_limit_check("knowledge") + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def patch(self, dataset_id, document_id, action): current_user, current_tenant_id = current_account_with_tenant() @@ -424,6 +434,7 @@ class DatasetDocumentSegmentUpdateApi(Resource): @login_required @account_initialization_required @cloud_edition_billing_rate_limit_check("knowledge") + @console_ns.response(204, "Segment deleted successfully") def delete(self, dataset_id, document_id, segment_id): current_user, current_tenant_id = current_account_with_tenant() @@ -464,6 +475,7 @@ class DatasetDocumentSegmentUpdateApi(Resource): "/datasets/batch_import_status/", ) class DatasetDocumentSegmentBatchImportApi(Resource): + @console_ns.response(200, "Batch import started", console_ns.models[SegmentBatchImportStatusResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -514,6 +526,7 @@ class DatasetDocumentSegmentBatchImportApi(Resource): return {"error": str(e)}, 500 return {"job_id": job_id, "job_status": "waiting"}, 200 + @console_ns.response(200, "Batch import status", console_ns.models[SegmentBatchImportStatusResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -691,6 +704,7 @@ class ChildChunkUpdateApi(Resource): @login_required @account_initialization_required @cloud_edition_billing_rate_limit_check("knowledge") + @console_ns.response(204, "Child chunk deleted successfully") def delete(self, dataset_id, document_id, segment_id, child_chunk_id): current_user, current_tenant_id = current_account_with_tenant() diff --git a/api/controllers/console/datasets/external.py b/api/controllers/console/datasets/external.py index e513e8c8f9..37cee1c17a 100644 --- a/api/controllers/console/datasets/external.py +++ b/api/controllers/console/datasets/external.py @@ -4,7 +4,8 @@ from pydantic import BaseModel, Field from werkzeug.exceptions import Forbidden, InternalServerError, NotFound import services -from controllers.common.schema import get_or_create_model, register_schema_models +from controllers.common.fields import UsageCountResponse +from controllers.common.schema import get_or_create_model, register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.datasets.error import DatasetNameDuplicateError from controllers.console.wraps import account_initialization_required, edit_permission_required, setup_required @@ -27,6 +28,8 @@ from services.external_knowledge_service import ExternalDatasetService from services.hit_testing_service import HitTestingService from services.knowledge_service import BedrockRetrievalSetting, ExternalDatasetTestService +register_response_schema_models(console_ns, UsageCountResponse) + def _build_dataset_detail_model(): keyword_setting_model = get_or_create_model("DatasetKeywordSetting", keyword_setting_fields) @@ -206,6 +209,7 @@ class ExternalApiTemplateApi(Resource): @setup_required @login_required @account_initialization_required + @console_ns.response(204, "External knowledge API deleted successfully") def delete(self, external_knowledge_api_id): current_user, current_tenant_id = current_account_with_tenant() external_knowledge_api_id = str(external_knowledge_api_id) @@ -222,7 +226,7 @@ class ExternalApiUseCheckApi(Resource): @console_ns.doc("check_external_api_usage") @console_ns.doc(description="Check if external knowledge API is being used") @console_ns.doc(params={"external_knowledge_api_id": "External knowledge API ID"}) - @console_ns.response(200, "Usage check completed successfully") + @console_ns.response(200, "Usage check completed successfully", console_ns.models[UsageCountResponse.__name__]) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/datasets/metadata.py b/api/controllers/console/datasets/metadata.py index d966e1629e..c6d041fc59 100644 --- a/api/controllers/console/datasets/metadata.py +++ b/api/controllers/console/datasets/metadata.py @@ -4,7 +4,8 @@ from flask_restx import Resource, marshal_with from werkzeug.exceptions import NotFound from controllers.common.controller_schemas import MetadataUpdatePayload -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.wraps import account_initialization_required, enterprise_license_required, setup_required from fields.dataset_fields import dataset_metadata_fields @@ -21,6 +22,7 @@ from services.metadata_service import MetadataService register_schema_models( console_ns, MetadataArgs, MetadataOperationData, MetadataUpdatePayload, DocumentMetadataOperation, MetadataDetail ) +register_response_schema_models(console_ns, SimpleResultResponse) @console_ns.route("/datasets//metadata") @@ -83,6 +85,7 @@ class DatasetMetadataApi(Resource): @login_required @account_initialization_required @enterprise_license_required + @console_ns.response(204, "Metadata deleted successfully") def delete(self, dataset_id, metadata_id): current_user, _ = current_account_with_tenant() dataset_id_str = str(dataset_id) @@ -113,6 +116,7 @@ class DatasetMetadataBuiltInFieldActionApi(Resource): @login_required @account_initialization_required @enterprise_license_required + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def post(self, dataset_id, action: Literal["enable", "disable"]): current_user, _ = current_account_with_tenant() dataset_id_str = str(dataset_id) @@ -136,6 +140,7 @@ class DocumentMetadataEditApi(Resource): @account_initialization_required @enterprise_license_required @console_ns.expect(console_ns.models[MetadataOperationData.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def post(self, dataset_id): current_user, _ = current_account_with_tenant() dataset_id_str = str(dataset_id) diff --git a/api/controllers/console/datasets/rag_pipeline/datasource_auth.py b/api/controllers/console/datasets/rag_pipeline/datasource_auth.py index fd0a8b33bc..f6dcd0e492 100644 --- a/api/controllers/console/datasets/rag_pipeline/datasource_auth.py +++ b/api/controllers/console/datasets/rag_pipeline/datasource_auth.py @@ -6,7 +6,8 @@ from pydantic import BaseModel, Field from werkzeug.exceptions import Forbidden, NotFound from configs import dify_config -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.wraps import account_initialization_required, edit_permission_required, setup_required from core.plugin.impl.oauth import OAuthHandler @@ -56,6 +57,7 @@ register_schema_models( DatasourceDefaultPayload, DatasourceUpdateNamePayload, ) +register_response_schema_models(console_ns, SimpleResultResponse) @console_ns.route("/oauth/plugin//datasource/get-authorization-url") @@ -209,6 +211,7 @@ class DatasourceAuth(Resource): @console_ns.route("/auth/plugin/datasource//delete") class DatasourceAuthDeleteApi(Resource): @console_ns.expect(console_ns.models[DatasourceCredentialDeletePayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -306,6 +309,7 @@ class DatasourceAuthOauthCustomClient(Resource): @setup_required @login_required @account_initialization_required + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def delete(self, provider_id: str): _, current_tenant_id = current_account_with_tenant() @@ -321,6 +325,7 @@ class DatasourceAuthOauthCustomClient(Resource): @console_ns.route("/auth/plugin/datasource//default") class DatasourceAuthDefaultApi(Resource): @console_ns.expect(console_ns.models[DatasourceDefaultPayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -342,6 +347,7 @@ class DatasourceAuthDefaultApi(Resource): @console_ns.route("/auth/plugin/datasource//update-name") class DatasourceUpdateProviderNameApi(Resource): @console_ns.expect(console_ns.models[DatasourceUpdateNamePayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/datasets/rag_pipeline/rag_pipeline.py b/api/controllers/console/datasets/rag_pipeline/rag_pipeline.py index 4fe9690257..ed19c327cd 100644 --- a/api/controllers/console/datasets/rag_pipeline/rag_pipeline.py +++ b/api/controllers/console/datasets/rag_pipeline/rag_pipeline.py @@ -6,7 +6,8 @@ from pydantic import BaseModel, Field from sqlalchemy import select from sqlalchemy.orm import sessionmaker -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleDataResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.wraps import ( account_initialization_required, @@ -59,6 +60,7 @@ class Payload(BaseModel): register_schema_models(console_ns, Payload) +register_response_schema_models(console_ns, SimpleDataResponse) @console_ns.route("/rag/pipeline/customized/templates/") @@ -85,6 +87,7 @@ class CustomizedPipelineTemplateApi(Resource): @login_required @account_initialization_required @enterprise_license_required + @console_ns.response(200, "Success", console_ns.models[SimpleDataResponse.__name__]) def post(self, template_id: str): with sessionmaker(db.engine, expire_on_commit=False).begin() as session: template = session.scalar( diff --git a/api/controllers/console/datasets/rag_pipeline/rag_pipeline_workflow.py b/api/controllers/console/datasets/rag_pipeline/rag_pipeline_workflow.py index 77dbf0be3f..25e8b060b8 100644 --- a/api/controllers/console/datasets/rag_pipeline/rag_pipeline_workflow.py +++ b/api/controllers/console/datasets/rag_pipeline/rag_pipeline_workflow.py @@ -10,6 +10,7 @@ from werkzeug.exceptions import BadRequest, Forbidden, InternalServerError, NotF import services from controllers.common.controller_schemas import DefaultBlockConfigQuery, WorkflowListQuery, WorkflowUpdatePayload +from controllers.common.fields import SimpleResultResponse from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.app.error import ( @@ -34,6 +35,7 @@ from core.app.apps.pipeline.pipeline_generator import PipelineGenerator from core.app.entities.app_invoke_entities import InvokeFrom from extensions.ext_database import db from factories import variable_factory +from fields.base import ResponseModel from fields.workflow_run_fields import ( WorkflowRunDetailResponse, WorkflowRunNodeExecutionListResponse, @@ -115,6 +117,17 @@ class RagPipelineRecommendedPluginQuery(BaseModel): type: str = "all" +class RagPipelineWorkflowSyncResponse(ResponseModel): + result: str + hash: str + updated_at: int + + +class RagPipelineWorkflowPublishResponse(ResponseModel): + result: str + created_at: int + + register_schema_models( console_ns, DraftWorkflowSyncPayload, @@ -133,6 +146,9 @@ register_schema_models( ) register_response_schema_models( console_ns, + RagPipelineWorkflowPublishResponse, + RagPipelineWorkflowSyncResponse, + SimpleResultResponse, WorkflowRunDetailResponse, WorkflowRunNodeExecutionListResponse, WorkflowRunNodeExecutionResponse, @@ -172,6 +188,7 @@ class DraftRagPipelineApi(Resource): @account_initialization_required @get_rag_pipeline @edit_permission_required + @console_ns.response(200, "Success", console_ns.models[RagPipelineWorkflowSyncResponse.__name__]) def post(self, pipeline: Pipeline): """ Sync draft workflow @@ -462,6 +479,7 @@ class RagPipelineDraftNodeRunApi(Resource): @console_ns.route("/rag/pipelines//workflow-runs/tasks//stop") class RagPipelineTaskStopApi(Resource): + @console_ns.response(200, "Task stopped successfully", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @edit_permission_required @@ -508,6 +526,7 @@ class PublishedRagPipelineApi(Resource): return dump_response(WorkflowResponse, workflow) + @console_ns.response(200, "Success", console_ns.models[RagPipelineWorkflowPublishResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -630,6 +649,7 @@ class PublishedAllRagPipelineApi(Resource): @console_ns.route("/rag/pipelines//workflows//restore") class RagPipelineDraftWorkflowRestoreApi(Resource): + @console_ns.response(200, "Success", console_ns.models[RagPipelineWorkflowSyncResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -699,6 +719,7 @@ class RagPipelineByIdApi(Resource): return dump_response(WorkflowResponse, workflow) + @console_ns.response(204, "Workflow deleted successfully") @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/explore/completion.py b/api/controllers/console/explore/completion.py index ccdccceaa6..2a699efb1d 100644 --- a/api/controllers/console/explore/completion.py +++ b/api/controllers/console/explore/completion.py @@ -6,7 +6,8 @@ from pydantic import BaseModel, Field, field_validator from werkzeug.exceptions import InternalServerError, NotFound import services -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console.app.error import ( AppUnavailableError, CompletionRequestError, @@ -72,6 +73,7 @@ class ChatMessagePayload(BaseModel): register_schema_models(console_ns, CompletionMessageExplorePayload, ChatMessagePayload) +register_response_schema_models(console_ns, SimpleResultResponse) # define completion api for user @@ -130,6 +132,7 @@ class CompletionApi(InstalledAppResource): endpoint="installed_app_stop_completion", ) class CompletionStopApi(InstalledAppResource): + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def post(self, installed_app, task_id): app_model = installed_app.app if app_model.mode != AppMode.COMPLETION: @@ -205,6 +208,7 @@ class ChatApi(InstalledAppResource): endpoint="installed_app_stop_chat_completion", ) class ChatStopApi(InstalledAppResource): + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def post(self, installed_app, task_id): app_model = installed_app.app app_mode = AppMode.value_of(app_model.mode) diff --git a/api/controllers/console/explore/conversation.py b/api/controllers/console/explore/conversation.py index 2eb2054e64..826610acda 100644 --- a/api/controllers/console/explore/conversation.py +++ b/api/controllers/console/explore/conversation.py @@ -6,7 +6,7 @@ from sqlalchemy.orm import sessionmaker from werkzeug.exceptions import NotFound from controllers.common.controller_schemas import ConversationRenamePayload -from controllers.common.schema import register_schema_models +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console.explore.error import NotChatAppError from controllers.console.explore.wraps import InstalledAppResource from core.app.entities.app_invoke_entities import InvokeFrom @@ -34,6 +34,7 @@ class ConversationListQuery(BaseModel): register_schema_models(console_ns, ConversationListQuery, ConversationRenamePayload) +register_response_schema_models(console_ns, ResultResponse) @console_ns.route( @@ -89,6 +90,7 @@ class ConversationListApi(InstalledAppResource): endpoint="installed_app_conversation", ) class ConversationApi(InstalledAppResource): + @console_ns.response(204, "Conversation deleted successfully") def delete(self, installed_app, c_id): app_model = installed_app.app app_mode = AppMode.value_of(app_model.mode) @@ -142,6 +144,7 @@ class ConversationRenameApi(InstalledAppResource): endpoint="installed_app_conversation_pin", ) class ConversationPinApi(InstalledAppResource): + @console_ns.response(200, "Success", console_ns.models[ResultResponse.__name__]) def patch(self, installed_app, c_id): app_model = installed_app.app app_mode = AppMode.value_of(app_model.mode) @@ -165,6 +168,7 @@ class ConversationPinApi(InstalledAppResource): endpoint="installed_app_conversation_unpin", ) class ConversationUnPinApi(InstalledAppResource): + @console_ns.response(200, "Success", console_ns.models[ResultResponse.__name__]) def patch(self, installed_app, c_id): app_model = installed_app.app app_mode = AppMode.value_of(app_model.mode) diff --git a/api/controllers/console/explore/installed_app.py b/api/controllers/console/explore/installed_app.py index 08c72e45d5..fb8d35013f 100644 --- a/api/controllers/console/explore/installed_app.py +++ b/api/controllers/console/explore/installed_app.py @@ -8,7 +8,8 @@ from pydantic import BaseModel, Field, computed_field, field_validator from sqlalchemy import and_, select from werkzeug.exceptions import BadRequest, Forbidden, NotFound -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleMessageResponse, SimpleResultMessageResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.explore.wraps import InstalledAppResource from controllers.console.wraps import account_initialization_required, cloud_edition_billing_resource_check @@ -122,6 +123,7 @@ register_schema_models( InstalledAppResponse, InstalledAppListResponse, ) +register_response_schema_models(console_ns, SimpleMessageResponse, SimpleResultMessageResponse) @console_ns.route("/installed-apps") @@ -209,6 +211,7 @@ class InstalledAppsListApi(Resource): @login_required @account_initialization_required @cloud_edition_billing_resource_check("apps") + @console_ns.response(200, "Success", console_ns.models[SimpleMessageResponse.__name__]) def post(self): payload = InstalledAppCreatePayload.model_validate(console_ns.payload or {}) @@ -258,6 +261,7 @@ class InstalledAppApi(InstalledAppResource): use InstalledAppResource to apply default decorators and get installed_app """ + @console_ns.response(204, "App uninstalled successfully") def delete(self, installed_app): _, current_tenant_id = current_account_with_tenant() if installed_app.app_owner_tenant_id == current_tenant_id: @@ -268,6 +272,7 @@ class InstalledAppApi(InstalledAppResource): return {"result": "success", "message": "App uninstalled successfully"}, 204 + @console_ns.response(200, "Success", console_ns.models[SimpleResultMessageResponse.__name__]) def patch(self, installed_app): payload = InstalledAppUpdatePayload.model_validate(console_ns.payload or {}) diff --git a/api/controllers/console/explore/message.py b/api/controllers/console/explore/message.py index 209667d1d0..0d25fbb66d 100644 --- a/api/controllers/console/explore/message.py +++ b/api/controllers/console/explore/message.py @@ -6,7 +6,7 @@ from pydantic import BaseModel, TypeAdapter from werkzeug.exceptions import InternalServerError, NotFound from controllers.common.controller_schemas import MessageFeedbackPayload, MessageListQuery -from controllers.common.schema import register_schema_models +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console.app.error import ( AppMoreLikeThisDisabledError, CompletionRequestError, @@ -49,6 +49,7 @@ class MoreLikeThisQuery(BaseModel): register_schema_models(console_ns, MessageListQuery, MessageFeedbackPayload, MoreLikeThisQuery) +register_response_schema_models(console_ns, ResultResponse, SuggestedQuestionsResponse) @console_ns.route( @@ -93,6 +94,7 @@ class MessageListApi(InstalledAppResource): ) class MessageFeedbackApi(InstalledAppResource): @console_ns.expect(console_ns.models[MessageFeedbackPayload.__name__]) + @console_ns.response(200, "Feedback submitted successfully", console_ns.models[ResultResponse.__name__]) def post(self, installed_app, message_id): current_user, _ = current_account_with_tenant() app_model = installed_app.app @@ -166,6 +168,7 @@ class MessageMoreLikeThisApi(InstalledAppResource): endpoint="installed_app_suggested_question", ) class MessageSuggestedQuestionApi(InstalledAppResource): + @console_ns.response(200, "Success", console_ns.models[SuggestedQuestionsResponse.__name__]) def get(self, installed_app, message_id): current_user, _ = current_account_with_tenant() app_model = installed_app.app diff --git a/api/controllers/console/explore/saved_message.py b/api/controllers/console/explore/saved_message.py index 9ec4e82324..51e73049a4 100644 --- a/api/controllers/console/explore/saved_message.py +++ b/api/controllers/console/explore/saved_message.py @@ -3,7 +3,7 @@ from pydantic import TypeAdapter from werkzeug.exceptions import NotFound from controllers.common.controller_schemas import SavedMessageCreatePayload, SavedMessageListQuery -from controllers.common.schema import register_schema_models +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.explore.error import NotCompletionAppError from controllers.console.explore.wraps import InstalledAppResource @@ -14,6 +14,7 @@ from services.errors.message import MessageNotExistsError from services.saved_message_service import SavedMessageService register_schema_models(console_ns, SavedMessageListQuery, SavedMessageCreatePayload) +register_response_schema_models(console_ns, ResultResponse) @console_ns.route("/installed-apps//saved-messages", endpoint="installed_app_saved_messages") @@ -42,6 +43,7 @@ class SavedMessageListApi(InstalledAppResource): ).model_dump(mode="json") @console_ns.expect(console_ns.models[SavedMessageCreatePayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[ResultResponse.__name__]) def post(self, installed_app): current_user, _ = current_account_with_tenant() app_model = installed_app.app @@ -62,6 +64,7 @@ class SavedMessageListApi(InstalledAppResource): "/installed-apps//saved-messages/", endpoint="installed_app_saved_message" ) class SavedMessageApi(InstalledAppResource): + @console_ns.response(204, "Saved message deleted successfully") def delete(self, installed_app, message_id): current_user, _ = current_account_with_tenant() app_model = installed_app.app diff --git a/api/controllers/console/explore/workflow.py b/api/controllers/console/explore/workflow.py index 438cce4fd8..bed8425c35 100644 --- a/api/controllers/console/explore/workflow.py +++ b/api/controllers/console/explore/workflow.py @@ -3,7 +3,8 @@ import logging from werkzeug.exceptions import InternalServerError from controllers.common.controller_schemas import WorkflowRunPayload -from controllers.common.schema import register_schema_model +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_model from controllers.console.app.error import ( CompletionRequestError, ProviderModelCurrentlyNotSupportError, @@ -34,6 +35,7 @@ from .. import console_ns logger = logging.getLogger(__name__) register_schema_model(console_ns, WorkflowRunPayload) +register_response_schema_models(console_ns, SimpleResultResponse) @console_ns.route("/installed-apps//workflows/run") @@ -78,6 +80,7 @@ class InstalledAppWorkflowRunApi(InstalledAppResource): @console_ns.route("/installed-apps//workflows/tasks//stop") class InstalledAppWorkflowTaskStopApi(InstalledAppResource): + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def post(self, installed_app: InstalledApp, task_id: str): """ Stop workflow task diff --git a/api/controllers/console/feature.py b/api/controllers/console/feature.py index d3811e2d1b..0e9a66c579 100644 --- a/api/controllers/console/feature.py +++ b/api/controllers/console/feature.py @@ -1,12 +1,15 @@ -from flask_restx import Resource, fields +from flask_restx import Resource from werkzeug.exceptions import Unauthorized +from controllers.common.schema import register_response_schema_models from libs.login import current_account_with_tenant, current_user, login_required -from services.feature_service import FeatureService +from services.feature_service import FeatureModel, FeatureService, SystemFeatureModel from . import console_ns from .wraps import account_initialization_required, cloud_utm_record, setup_required +register_response_schema_models(console_ns, FeatureModel, SystemFeatureModel) + @console_ns.route("/features") class FeatureApi(Resource): @@ -15,7 +18,7 @@ class FeatureApi(Resource): @console_ns.response( 200, "Success", - console_ns.model("FeatureResponse", {"features": fields.Raw(description="Feature configuration object")}), + console_ns.models[FeatureModel.__name__], ) @setup_required @login_required @@ -35,9 +38,7 @@ class SystemFeatureApi(Resource): @console_ns.response( 200, "Success", - console_ns.model( - "SystemFeatureResponse", {"features": fields.Raw(description="System feature configuration object")} - ), + console_ns.models[SystemFeatureModel.__name__], ) def get(self): """Get system-wide feature configuration diff --git a/api/controllers/console/files.py b/api/controllers/console/files.py index 5751026040..6811c8ce77 100644 --- a/api/controllers/console/files.py +++ b/api/controllers/console/files.py @@ -15,7 +15,8 @@ from controllers.common.errors import ( TooManyFilesError, UnsupportedFileTypeError, ) -from controllers.common.schema import register_schema_models +from controllers.common.fields import AllowedExtensionsResponse, TextContentResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console.wraps import ( account_initialization_required, cloud_edition_billing_resource_check, @@ -29,6 +30,7 @@ from services.file_service import FileService from . import console_ns register_schema_models(console_ns, UploadConfig, FileResponse) +register_response_schema_models(console_ns, AllowedExtensionsResponse, TextContentResponse) PREVIEW_WORDS_LIMIT = 3000 @@ -103,6 +105,7 @@ class FilePreviewApi(Resource): @setup_required @login_required @account_initialization_required + @console_ns.response(200, "Success", console_ns.models[TextContentResponse.__name__]) def get(self, file_id): file_id = str(file_id) _, tenant_id = current_account_with_tenant() @@ -115,5 +118,6 @@ class FileSupportTypeApi(Resource): @setup_required @login_required @account_initialization_required + @console_ns.response(200, "Success", console_ns.models[AllowedExtensionsResponse.__name__]) def get(self): return {"allowed_extensions": list(DOCUMENT_EXTENSIONS)} diff --git a/api/controllers/console/notification.py b/api/controllers/console/notification.py index 5d46470173..f54a6137b3 100644 --- a/api/controllers/console/notification.py +++ b/api/controllers/console/notification.py @@ -5,6 +5,8 @@ from flask import request from flask_restx import Resource from pydantic import BaseModel, Field +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models from controllers.console import console_ns from controllers.console.wraps import account_initialization_required, only_edition_cloud, setup_required from libs.login import current_account_with_tenant, login_required @@ -48,6 +50,9 @@ class DismissNotificationPayload(BaseModel): notification_id: str = Field(...) +register_response_schema_models(console_ns, SimpleResultResponse) + + @console_ns.route("/notification") class NotificationApi(Resource): @console_ns.doc("get_notification") @@ -110,6 +115,7 @@ class NotificationDismissApi(Resource): @login_required @account_initialization_required @only_edition_cloud + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) def post(self): current_user, _ = current_account_with_tenant() payload = DismissNotificationPayload.model_validate(request.get_json()) diff --git a/api/controllers/console/remote_files.py b/api/controllers/console/remote_files.py index 2a46d2250a..fd3ed78986 100644 --- a/api/controllers/console/remote_files.py +++ b/api/controllers/console/remote_files.py @@ -11,6 +11,7 @@ from controllers.common.errors import ( RemoteFileUploadError, UnsupportedFileTypeError, ) +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from core.helper import ssrf_proxy from extensions.ext_database import db @@ -24,8 +25,13 @@ class RemoteFileUploadPayload(BaseModel): url: str = Field(..., description="URL to fetch") +register_schema_models(console_ns, RemoteFileUploadPayload) +register_response_schema_models(console_ns, FileWithSignedUrl, RemoteFileInfo) + + @console_ns.route("/remote-files/") class GetRemoteFileInfo(Resource): + @console_ns.response(200, "Success", console_ns.models[RemoteFileInfo.__name__]) @login_required def get(self, url: str): decoded_url = urllib.parse.unquote(url) @@ -41,6 +47,8 @@ class GetRemoteFileInfo(Resource): @console_ns.route("/remote-files/upload") class RemoteFileUpload(Resource): + @console_ns.expect(console_ns.models[RemoteFileUploadPayload.__name__]) + @console_ns.response(201, "File uploaded successfully", console_ns.models[FileWithSignedUrl.__name__]) @login_required def post(self): payload = RemoteFileUploadPayload.model_validate(console_ns.payload) diff --git a/api/controllers/console/tag/tags.py b/api/controllers/console/tag/tags.py index 346f572ccc..199a05d9c2 100644 --- a/api/controllers/console/tag/tags.py +++ b/api/controllers/console/tag/tags.py @@ -5,7 +5,8 @@ from flask_restx import Resource from pydantic import BaseModel, Field, field_validator from werkzeug.exceptions import Forbidden -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.wraps import account_initialization_required, edit_permission_required, setup_required from fields.base import ResponseModel @@ -78,6 +79,7 @@ register_schema_models( TagListQueryParam, TagResponse, ) +register_response_schema_models(console_ns, SimpleResultResponse) @console_ns.route("/tags") @@ -102,6 +104,7 @@ class TagListApi(Resource): return serialized_tags, 200 @console_ns.expect(console_ns.models[TagBasePayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[TagResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -124,6 +127,7 @@ class TagListApi(Resource): @console_ns.route("/tags/") class TagUpdateDeleteApi(Resource): @console_ns.expect(console_ns.models[TagUpdateRequestPayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[TagResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -149,6 +153,7 @@ class TagUpdateDeleteApi(Resource): @login_required @account_initialization_required @edit_permission_required + @console_ns.response(204, "Tag deleted successfully") def delete(self, tag_id): tag_id = str(tag_id) @@ -203,6 +208,7 @@ class TagBindingCollectionApi(Resource): @console_ns.doc("create_tag_binding") @console_ns.expect(console_ns.models[TagBindingPayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -217,6 +223,7 @@ class TagBindingRemoveApi(Resource): @console_ns.doc("remove_tag_bindings") @console_ns.doc(description="Remove one or more tag bindings from a target.") @console_ns.expect(console_ns.models[TagBindingRemovePayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/workspace/account.py b/api/controllers/console/workspace/account.py index b1c363433a..74319d1336 100644 --- a/api/controllers/console/workspace/account.py +++ b/api/controllers/console/workspace/account.py @@ -12,7 +12,13 @@ from werkzeug.exceptions import NotFound from configs import dify_config from constants.languages import supported_language -from controllers.common.schema import register_schema_models +from controllers.common.fields import ( + AvatarUrlResponse, + SimpleResultDataResponse, + SimpleResultResponse, + VerificationTokenResponse, +) +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.auth.error import ( EmailAlreadyInUseError, @@ -231,11 +237,19 @@ register_schema_models( EducationStatusResponse, EducationAutocompleteResponse, ) +register_response_schema_models( + console_ns, + AvatarUrlResponse, + SimpleResultDataResponse, + SimpleResultResponse, + VerificationTokenResponse, +) @console_ns.route("/account/init") class AccountInitApi(Resource): @console_ns.expect(console_ns.models[AccountInitPayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required def post(self): @@ -312,6 +326,7 @@ class AccountAvatarApi(Resource): @console_ns.expect(console_ns.models[AccountAvatarQuery.__name__]) @console_ns.doc("get_account_avatar") @console_ns.doc(description="Get account avatar url") + @console_ns.response(200, "Success", console_ns.models[AvatarUrlResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -473,6 +488,7 @@ class AccountDeleteVerifyApi(Resource): @setup_required @login_required @account_initialization_required + @console_ns.response(200, "Success", console_ns.models[SimpleResultDataResponse.__name__]) def get(self): account, _ = current_account_with_tenant() @@ -485,6 +501,7 @@ class AccountDeleteVerifyApi(Resource): @console_ns.route("/account/delete") class AccountDeleteApi(Resource): @console_ns.expect(console_ns.models[AccountDeletePayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -505,6 +522,7 @@ class AccountDeleteApi(Resource): @console_ns.route("/account/delete/feedback") class AccountDeleteUpdateFeedbackApi(Resource): @console_ns.expect(console_ns.models[AccountDeletionFeedbackPayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required def post(self): payload = console_ns.payload or {} @@ -584,6 +602,7 @@ class EducationAutoCompleteApi(Resource): @console_ns.route("/account/change-email") class ChangeEmailSendEmailApi(Resource): @console_ns.expect(console_ns.models[ChangeEmailSendPayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultDataResponse.__name__]) @enable_change_email @setup_required @login_required @@ -649,6 +668,7 @@ class ChangeEmailSendEmailApi(Resource): @console_ns.route("/account/change-email/validity") class ChangeEmailCheckApi(Resource): @console_ns.expect(console_ns.models[ChangeEmailValidityPayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[VerificationTokenResponse.__name__]) @enable_change_email @setup_required @login_required @@ -765,6 +785,7 @@ class ChangeEmailResetApi(Resource): @console_ns.route("/account/change-email/check-email-unique") class CheckEmailUnique(Resource): @console_ns.expect(console_ns.models[CheckEmailUniquePayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required def post(self): payload = console_ns.payload or {} diff --git a/api/controllers/console/workspace/members.py b/api/controllers/console/workspace/members.py index dfc4142085..2be91626e7 100644 --- a/api/controllers/console/workspace/members.py +++ b/api/controllers/console/workspace/members.py @@ -6,7 +6,8 @@ from pydantic import BaseModel, Field, TypeAdapter import services from configs import dify_config -from controllers.common.schema import register_enum_models, register_schema_models +from controllers.common.fields import SimpleResultDataResponse, VerificationTokenResponse +from controllers.common.schema import register_enum_models, register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.auth.error import ( CannotTransferOwnerToSelfError, @@ -68,6 +69,7 @@ register_schema_models( OwnerTransferCheckPayload, OwnerTransferPayload, ) +register_response_schema_models(console_ns, SimpleResultDataResponse, VerificationTokenResponse) def _is_role_enabled(role: TenantAccountRole | str, tenant_id: str) -> bool: @@ -262,6 +264,7 @@ class SendOwnerTransferEmailApi(Resource): """Send owner transfer email.""" @console_ns.expect(console_ns.models[OwnerTransferEmailPayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultDataResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -299,6 +302,7 @@ class SendOwnerTransferEmailApi(Resource): @console_ns.route("/workspaces/current/members/owner-transfer-check") class OwnerTransferCheckApi(Resource): @console_ns.expect(console_ns.models[OwnerTransferCheckPayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[VerificationTokenResponse.__name__]) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/workspace/model_providers.py b/api/controllers/console/workspace/model_providers.py index 2f75218c0f..f00a7e5c79 100644 --- a/api/controllers/console/workspace/model_providers.py +++ b/api/controllers/console/workspace/model_providers.py @@ -5,7 +5,8 @@ from flask import request, send_file from flask_restx import Resource from pydantic import BaseModel, Field, field_validator -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.wraps import account_initialization_required, is_admin_or_owner_required, setup_required from graphon.model_runtime.entities.model_entities import ModelType @@ -85,6 +86,7 @@ register_schema_models( ParserCredentialValidate, ParserPreferredProviderType, ) +register_response_schema_models(console_ns, SimpleResultResponse) @console_ns.route("/workspaces/current/model-providers") @@ -177,6 +179,7 @@ class ModelProviderCredentialApi(Resource): return {"result": "success"} @console_ns.expect(console_ns.models[ParserCredentialDelete.__name__]) + @console_ns.response(204, "Credential deleted successfully") @setup_required @login_required @is_admin_or_owner_required @@ -197,6 +200,7 @@ class ModelProviderCredentialApi(Resource): @console_ns.route("/workspaces/current/model-providers//credentials/switch") class ModelProviderCredentialSwitchApi(Resource): @console_ns.expect(console_ns.models[ParserCredentialSwitch.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @is_admin_or_owner_required @@ -271,6 +275,7 @@ class ModelProviderIconApi(Resource): @console_ns.route("/workspaces/current/model-providers//preferred-provider-type") class PreferredProviderTypeUpdateApi(Resource): @console_ns.expect(console_ns.models[ParserPreferredProviderType.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @is_admin_or_owner_required diff --git a/api/controllers/console/workspace/models.py b/api/controllers/console/workspace/models.py index 7f7d6379c3..a24d6d0f7d 100644 --- a/api/controllers/console/workspace/models.py +++ b/api/controllers/console/workspace/models.py @@ -5,7 +5,8 @@ from flask import request from flask_restx import Resource from pydantic import BaseModel, Field, field_validator -from controllers.common.schema import register_enum_models, register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_enum_models, register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.wraps import account_initialization_required, is_admin_or_owner_required, setup_required from graphon.model_runtime.entities.model_entities import ModelType @@ -126,6 +127,7 @@ register_schema_models( Inner, ParserSwitch, ) +register_response_schema_models(console_ns, SimpleResultResponse) register_enum_models(console_ns, ModelType) @@ -149,6 +151,7 @@ class DefaultModelApi(Resource): return jsonable_encoder({"data": default_model_entity}) @console_ns.expect(console_ns.models[ParserPostDefault.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @is_admin_or_owner_required @@ -241,6 +244,7 @@ class ModelProviderModelApi(Resource): return {"result": "success"}, 200 @console_ns.expect(console_ns.models[ParserDeleteModels.__name__]) + @console_ns.response(204, "Model deleted successfully") @setup_required @login_required @is_admin_or_owner_required @@ -373,6 +377,7 @@ class ModelProviderModelCredentialApi(Resource): return {"result": "success"} @console_ns.expect(console_ns.models[ParserDeleteCredential.__name__]) + @console_ns.response(204, "Credential deleted successfully") @setup_required @login_required @is_admin_or_owner_required @@ -396,6 +401,7 @@ class ModelProviderModelCredentialApi(Resource): @console_ns.route("/workspaces/current/model-providers//models/credentials/switch") class ModelProviderModelCredentialSwitchApi(Resource): @console_ns.expect(console_ns.models[ParserSwitch.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @is_admin_or_owner_required @@ -420,6 +426,7 @@ class ModelProviderModelCredentialSwitchApi(Resource): ) class ModelProviderModelEnableApi(Resource): @console_ns.expect(console_ns.models[ParserDeleteModels.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -441,6 +448,7 @@ class ModelProviderModelEnableApi(Resource): ) class ModelProviderModelDisableApi(Resource): @console_ns.expect(console_ns.models[ParserDeleteModels.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/workspace/plugin.py b/api/controllers/console/workspace/plugin.py index a6d4a60beb..9e5e766f45 100644 --- a/api/controllers/console/workspace/plugin.py +++ b/api/controllers/console/workspace/plugin.py @@ -9,11 +9,13 @@ from werkzeug.datastructures import FileStorage from werkzeug.exceptions import Forbidden from configs import dify_config -from controllers.common.schema import register_enum_models, register_schema_models +from controllers.common.fields import SuccessResponse +from controllers.common.schema import register_enum_models, register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.workspace import plugin_permission_required from controllers.console.wraps import account_initialization_required, is_admin_or_owner_required, setup_required from core.plugin.impl.exc import PluginDaemonClientSideError +from fields.base import ResponseModel from graphon.model_runtime.utils.encoders import jsonable_encoder from libs.login import current_account_with_tenant, login_required from models.account import TenantPluginAutoUpgradeStrategy, TenantPluginPermission @@ -137,6 +139,12 @@ class ParserReadme(BaseModel): language: str = Field(default="en-US") +class PluginDebuggingKeyResponse(ResponseModel): + key: str + host: str + port: int + + register_schema_models( console_ns, ParserList, @@ -160,6 +168,7 @@ register_schema_models( ParserExcludePlugin, ParserReadme, ) +register_response_schema_models(console_ns, PluginDebuggingKeyResponse, SuccessResponse) register_enum_models( console_ns, @@ -186,6 +195,7 @@ def _read_upload_content(file: FileStorage, max_size: int) -> bytes: @console_ns.route("/workspaces/current/plugin/debugging-key") class PluginDebuggingKeyApi(Resource): + @console_ns.response(200, "Success", console_ns.models[PluginDebuggingKeyResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -491,6 +501,7 @@ class PluginFetchInstallTaskApi(Resource): @console_ns.route("/workspaces/current/plugin/tasks//delete") class PluginDeleteInstallTaskApi(Resource): + @console_ns.response(200, "Success", console_ns.models[SuccessResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -506,6 +517,7 @@ class PluginDeleteInstallTaskApi(Resource): @console_ns.route("/workspaces/current/plugin/tasks/delete_all") class PluginDeleteAllInstallTaskItemsApi(Resource): + @console_ns.response(200, "Success", console_ns.models[SuccessResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -521,6 +533,7 @@ class PluginDeleteAllInstallTaskItemsApi(Resource): @console_ns.route("/workspaces/current/plugin/tasks//delete/") class PluginDeleteInstallTaskItemApi(Resource): + @console_ns.response(200, "Success", console_ns.models[SuccessResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -586,6 +599,7 @@ class PluginUpgradeFromGithubApi(Resource): @console_ns.route("/workspaces/current/plugin/uninstall") class PluginUninstallApi(Resource): @console_ns.expect(console_ns.models[ParserUninstall.__name__]) + @console_ns.response(200, "Success", console_ns.models[SuccessResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -604,6 +618,7 @@ class PluginUninstallApi(Resource): @console_ns.route("/workspaces/current/plugin/permission/change") class PluginChangePermissionApi(Resource): @console_ns.expect(console_ns.models[ParserPermissionChange.__name__]) + @console_ns.response(200, "Success", console_ns.models[SuccessResponse.__name__]) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/workspace/tool_providers.py b/api/controllers/console/workspace/tool_providers.py index cb01a02318..4ef4b02118 100644 --- a/api/controllers/console/workspace/tool_providers.py +++ b/api/controllers/console/workspace/tool_providers.py @@ -10,7 +10,8 @@ from sqlalchemy.orm import sessionmaker from werkzeug.exceptions import Forbidden from configs import dify_config -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.wraps import ( account_initialization_required, @@ -252,6 +253,7 @@ register_schema_models( MCPProviderDeletePayload, MCPAuthPayload, ) +register_response_schema_models(console_ns, SimpleResultResponse) @console_ns.route("/workspaces/current/tool-providers") @@ -1055,6 +1057,7 @@ class ToolProviderMCPApi(Resource): return {"result": "success"} @console_ns.expect(console_ns.models[MCPProviderDeletePayload.__name__]) + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/workspace/trigger_providers.py b/api/controllers/console/workspace/trigger_providers.py index d11b66244f..ab44e46ed2 100644 --- a/api/controllers/console/workspace/trigger_providers.py +++ b/api/controllers/console/workspace/trigger_providers.py @@ -8,7 +8,8 @@ from sqlalchemy.orm import sessionmaker from werkzeug.exceptions import BadRequest, Forbidden from configs import dify_config -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.web.error import NotFoundError from core.plugin.entities.plugin_daemon import CredentialType from core.plugin.impl.oauth import OAuthHandler @@ -68,6 +69,7 @@ register_schema_models( TriggerSubscriptionBuilderUpdatePayload, TriggerOAuthClientPayload, ) +register_response_schema_models(console_ns, SimpleResultResponse) @console_ns.route("/workspaces/current/trigger-provider//icon") @@ -365,6 +367,7 @@ class TriggerSubscriptionUpdateApi(Resource): "/workspaces/current/trigger-provider//subscriptions/delete", ) class TriggerSubscriptionDeleteApi(Resource): + @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @is_admin_or_owner_required diff --git a/api/controllers/console/workspace/workspace.py b/api/controllers/console/workspace/workspace.py index 1eb91c472e..77501eed72 100644 --- a/api/controllers/console/workspace/workspace.py +++ b/api/controllers/console/workspace/workspace.py @@ -16,7 +16,7 @@ from controllers.common.errors import ( TooManyFilesError, UnsupportedFileTypeError, ) -from controllers.common.schema import register_schema_models +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.admin import admin_required from controllers.console.error import AccountNotLinkTenantError @@ -89,6 +89,12 @@ class TenantInfoResponse(ResponseModel): return to_timestamp(value) +class WorkspacePermissionResponse(ResponseModel): + workspace_id: str + allow_member_invite: bool + allow_owner_transfer: bool + + register_schema_models( console_ns, WorkspaceListQuery, @@ -97,6 +103,7 @@ register_schema_models( WorkspaceInfoPayload, TenantInfoResponse, ) +register_response_schema_models(console_ns, WorkspacePermissionResponse) provider_fields = { "provider_name": fields.String, @@ -357,6 +364,7 @@ class WorkspaceInfoApi(Resource): class WorkspacePermissionApi(Resource): """Get workspace permissions for the current workspace.""" + @console_ns.response(200, "Success", console_ns.models[WorkspacePermissionResponse.__name__]) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/service_api/app/app.py b/api/controllers/service_api/app/app.py index abcaa0e240..27b0d8753d 100644 --- a/api/controllers/service_api/app/app.py +++ b/api/controllers/service_api/app/app.py @@ -3,14 +3,27 @@ from typing import Any, cast from flask_restx import Resource from controllers.common.fields import Parameters +from controllers.common.schema import register_response_schema_models from controllers.service_api import service_api_ns from controllers.service_api.app.error import AppUnavailableError from controllers.service_api.wraps import validate_app_token from core.app.app_config.common.parameters_mapping import get_parameters_from_feature_dict +from fields.base import ResponseModel from models.model import App, AppMode from services.app_service import AppService +class AppInfoResponse(ResponseModel): + name: str + description: str | None + tags: list[str] + mode: str + author_name: str | None + + +register_response_schema_models(service_api_ns, AppInfoResponse) + + @service_api_ns.route("/parameters") class AppParameterApi(Resource): """Resource for app variables.""" @@ -81,6 +94,11 @@ class AppInfoApi(Resource): 404: "Application not found", } ) + @service_api_ns.response( + 200, + "Application info retrieved successfully", + service_api_ns.models[AppInfoResponse.__name__], + ) @validate_app_token def get(self, app_model: App): """Get app information. diff --git a/api/controllers/service_api/app/completion.py b/api/controllers/service_api/app/completion.py index 31f2797d66..dea54a11d9 100644 --- a/api/controllers/service_api/app/completion.py +++ b/api/controllers/service_api/app/completion.py @@ -8,7 +8,8 @@ from pydantic import BaseModel, Field, field_validator from werkzeug.exceptions import BadRequest, InternalServerError, NotFound import services -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.service_api import service_api_ns from controllers.service_api.app.error import ( AppUnavailableError, @@ -75,6 +76,7 @@ class ChatRequestPayload(BaseModel): register_schema_models(service_api_ns, CompletionRequestPayload, ChatRequestPayload) +register_response_schema_models(service_api_ns, SimpleResultResponse) @service_api_ns.route("/completion-messages") @@ -155,6 +157,7 @@ class CompletionStopApi(Resource): 404: "Task not found", } ) + @service_api_ns.response(200, "Task stopped successfully", service_api_ns.models[SimpleResultResponse.__name__]) @validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON, required=True)) def post(self, app_model: App, end_user: EndUser, task_id: str): """Stop a running completion task.""" @@ -254,6 +257,7 @@ class ChatStopApi(Resource): 404: "Task not found", } ) + @service_api_ns.response(200, "Task stopped successfully", service_api_ns.models[SimpleResultResponse.__name__]) @validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON, required=True)) def post(self, app_model: App, end_user: EndUser, task_id: str): """Stop a running chat message generation.""" diff --git a/api/controllers/service_api/app/message.py b/api/controllers/service_api/app/message.py index b75b299f6f..0ff0ae5104 100644 --- a/api/controllers/service_api/app/message.py +++ b/api/controllers/service_api/app/message.py @@ -7,7 +7,8 @@ from werkzeug.exceptions import BadRequest, InternalServerError, NotFound import services from controllers.common.controller_schemas import MessageFeedbackPayload, MessageListQuery -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultStringListResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.service_api import service_api_ns from controllers.service_api.app.error import NotChatAppError from controllers.service_api.wraps import FetchUserArg, WhereisUserArg, validate_app_token @@ -32,6 +33,7 @@ class FeedbackListQuery(BaseModel): register_schema_models(service_api_ns, MessageListQuery, MessageFeedbackPayload, FeedbackListQuery) +register_response_schema_models(service_api_ns, ResultResponse, SimpleResultStringListResponse) @service_api_ns.route("/messages") @@ -80,6 +82,7 @@ class MessageListApi(Resource): @service_api_ns.route("/messages//feedbacks") class MessageFeedbackApi(Resource): @service_api_ns.expect(service_api_ns.models[MessageFeedbackPayload.__name__]) + @service_api_ns.response(200, "Feedback submitted successfully", service_api_ns.models[ResultResponse.__name__]) @service_api_ns.doc("create_message_feedback") @service_api_ns.doc(description="Submit feedback for a message") @service_api_ns.doc(params={"message_id": "Message ID"}) @@ -138,6 +141,11 @@ class AppGetFeedbacksApi(Resource): @service_api_ns.route("/messages//suggested") class MessageSuggestedApi(Resource): + @service_api_ns.response( + 200, + "Suggested questions retrieved successfully", + service_api_ns.models[SimpleResultStringListResponse.__name__], + ) @service_api_ns.doc("get_suggested_questions") @service_api_ns.doc(description="Get suggested follow-up questions for a message") @service_api_ns.doc(params={"message_id": "Message ID"}) diff --git a/api/controllers/service_api/app/site.py b/api/controllers/service_api/app/site.py index bc06e8f386..f5d1dcd283 100644 --- a/api/controllers/service_api/app/site.py +++ b/api/controllers/service_api/app/site.py @@ -3,12 +3,15 @@ from sqlalchemy import select from werkzeug.exceptions import Forbidden from controllers.common.fields import Site as SiteResponse +from controllers.common.schema import register_response_schema_models from controllers.service_api import service_api_ns from controllers.service_api.wraps import validate_app_token from extensions.ext_database import db from models.account import TenantStatus from models.model import App, Site +register_response_schema_models(service_api_ns, SiteResponse) + @service_api_ns.route("/site") class AppSiteApi(Resource): @@ -23,6 +26,11 @@ class AppSiteApi(Resource): 403: "Forbidden - site not found or tenant archived", } ) + @service_api_ns.response( + 200, + "Site configuration retrieved successfully", + service_api_ns.models[SiteResponse.__name__], + ) @validate_app_token def get(self, app_model: App): """Retrieve app site info. diff --git a/api/controllers/service_api/app/workflow.py b/api/controllers/service_api/app/workflow.py index 45d2dda858..3f5331a443 100644 --- a/api/controllers/service_api/app/workflow.py +++ b/api/controllers/service_api/app/workflow.py @@ -11,7 +11,8 @@ from sqlalchemy.orm import sessionmaker from werkzeug.exceptions import BadRequest, InternalServerError, NotFound from controllers.common.controller_schemas import WorkflowRunPayload as WorkflowRunPayloadBase -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.service_api import service_api_ns from controllers.service_api.app.error import ( CompletionRequestError, @@ -67,6 +68,7 @@ class WorkflowLogQuery(BaseModel): register_schema_models(service_api_ns, WorkflowRunPayload, WorkflowLogQuery) +register_response_schema_models(service_api_ns, SimpleResultResponse) def _enum_value(value): @@ -376,6 +378,7 @@ class WorkflowTaskStopApi(Resource): 404: "Task not found", } ) + @service_api_ns.response(200, "Task stopped successfully", service_api_ns.models[SimpleResultResponse.__name__]) @validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON, required=True)) def post(self, app_model: App, end_user: EndUser, task_id: str): """Stop a running workflow task.""" diff --git a/api/controllers/service_api/dataset/dataset.py b/api/controllers/service_api/dataset/dataset.py index d85e46498d..8c8acc8d0a 100644 --- a/api/controllers/service_api/dataset/dataset.py +++ b/api/controllers/service_api/dataset/dataset.py @@ -6,7 +6,8 @@ from pydantic import BaseModel, Field, TypeAdapter, field_validator, model_valid from werkzeug.exceptions import Forbidden, NotFound import services -from controllers.common.schema import register_enum_models, register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_enum_models, register_response_schema_models, register_schema_models from controllers.console.wraps import edit_permission_required from controllers.service_api import service_api_ns from controllers.service_api.dataset.error import DatasetInUseError, DatasetNameDuplicateError, InvalidActionError @@ -138,6 +139,7 @@ register_schema_models( DatasetListQuery, DataSetTag, ) +register_response_schema_models(service_api_ns, SimpleResultResponse) @service_api_ns.route("/datasets") @@ -434,6 +436,11 @@ class DatasetApi(DatasetApiResource): class DocumentStatusApi(DatasetApiResource): """Resource for batch document status operations.""" + @service_api_ns.response( + 200, + "Document status updated successfully", + service_api_ns.models[SimpleResultResponse.__name__], + ) @service_api_ns.doc("update_document_status") @service_api_ns.doc(description="Batch update document status") @service_api_ns.doc( diff --git a/api/controllers/service_api/dataset/document.py b/api/controllers/service_api/dataset/document.py index e68eeeca25..1b9b9d40db 100644 --- a/api/controllers/service_api/dataset/document.py +++ b/api/controllers/service_api/dataset/document.py @@ -26,7 +26,8 @@ from controllers.common.errors import ( TooManyFilesError, UnsupportedFileTypeError, ) -from controllers.common.schema import register_enum_models, register_schema_models +from controllers.common.fields import UrlResponse +from controllers.common.schema import register_enum_models, register_response_schema_models, register_schema_models from controllers.service_api import service_api_ns from controllers.service_api.app.error import ProviderNotInitializeError from controllers.service_api.dataset.error import ( @@ -120,6 +121,7 @@ register_schema_models( PreProcessingRule, Segmentation, ) +register_response_schema_models(service_api_ns, UrlResponse) def _create_document_by_text(tenant_id: str, dataset_id: UUID) -> tuple[Mapping[str, object], int]: @@ -749,6 +751,11 @@ class DocumentDownloadApi(DatasetApiResource): 404: "Document or upload file not found", } ) + @service_api_ns.response( + 200, + "Download URL generated successfully", + service_api_ns.models[UrlResponse.__name__], + ) @cloud_edition_billing_rate_limit_check("knowledge", "dataset") def get(self, tenant_id, dataset_id, document_id): dataset = self.get_dataset(str(dataset_id), str(tenant_id)) diff --git a/api/controllers/service_api/dataset/metadata.py b/api/controllers/service_api/dataset/metadata.py index 21db7d0cb8..afab582bf2 100644 --- a/api/controllers/service_api/dataset/metadata.py +++ b/api/controllers/service_api/dataset/metadata.py @@ -5,7 +5,8 @@ from flask_restx import marshal from werkzeug.exceptions import NotFound from controllers.common.controller_schemas import MetadataUpdatePayload -from controllers.common.schema import register_schema_model, register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_model, register_schema_models from controllers.service_api import service_api_ns from controllers.service_api.wraps import DatasetApiResource, cloud_edition_billing_rate_limit_check from fields.dataset_fields import dataset_metadata_fields @@ -26,6 +27,7 @@ register_schema_models( DocumentMetadataOperation, MetadataOperationData, ) +register_response_schema_models(service_api_ns, SimpleResultResponse) @service_api_ns.route("/datasets//metadata") @@ -154,6 +156,11 @@ class DatasetMetadataBuiltInFieldActionServiceApi(DatasetApiResource): 404: "Dataset not found", } ) + @service_api_ns.response( + 200, + "Action completed successfully", + service_api_ns.models[SimpleResultResponse.__name__], + ) @cloud_edition_billing_rate_limit_check("knowledge", "dataset") def post(self, tenant_id, dataset_id, action: Literal["enable", "disable"]): """Enable or disable built-in metadata field.""" @@ -184,6 +191,11 @@ class DocumentMetadataEditServiceApi(DatasetApiResource): 404: "Dataset not found", } ) + @service_api_ns.response( + 200, + "Documents metadata updated successfully", + service_api_ns.models[SimpleResultResponse.__name__], + ) @cloud_edition_billing_rate_limit_check("knowledge", "dataset") def post(self, tenant_id, dataset_id): """Update metadata for multiple documents.""" diff --git a/api/controllers/service_api/end_user/end_user.py b/api/controllers/service_api/end_user/end_user.py index fbeb96f446..d2d018492a 100644 --- a/api/controllers/service_api/end_user/end_user.py +++ b/api/controllers/service_api/end_user/end_user.py @@ -2,6 +2,7 @@ from uuid import UUID from flask_restx import Resource +from controllers.common.schema import register_response_schema_models from controllers.service_api import service_api_ns from controllers.service_api.end_user.error import EndUserNotFoundError from controllers.service_api.wraps import validate_app_token @@ -9,6 +10,8 @@ from fields.end_user_fields import EndUserDetail from models.model import App from services.end_user_service import EndUserService +register_response_schema_models(service_api_ns, EndUserDetail) + @service_api_ns.route("/end-users/") class EndUserApi(Resource): @@ -24,6 +27,7 @@ class EndUserApi(Resource): 404: "End user not found", }, ) + @service_api_ns.response(200, "End user retrieved successfully", service_api_ns.models[EndUserDetail.__name__]) @validate_app_token def get(self, app_model: App, end_user_id: UUID): """Get end user detail. diff --git a/api/controllers/service_api/index.py b/api/controllers/service_api/index.py index a9d2d6fadc..31151b5f9f 100644 --- a/api/controllers/service_api/index.py +++ b/api/controllers/service_api/index.py @@ -1,11 +1,16 @@ from flask_restx import Resource from configs import dify_config +from controllers.common.fields import IndexInfoResponse +from controllers.common.schema import register_response_schema_models from controllers.service_api import service_api_ns +register_response_schema_models(service_api_ns, IndexInfoResponse) + @service_api_ns.route("/") class IndexApi(Resource): + @service_api_ns.response(200, "Success", service_api_ns.models[IndexInfoResponse.__name__]) def get(self): return { "welcome": "Dify OpenAPI", diff --git a/api/controllers/web/app.py b/api/controllers/web/app.py index 25bbedce54..e3d87549bb 100644 --- a/api/controllers/web/app.py +++ b/api/controllers/web/app.py @@ -8,7 +8,7 @@ from werkzeug.exceptions import Unauthorized from constants import HEADER_NAME_APP_CODE from controllers.common import fields -from controllers.common.schema import register_schema_models +from controllers.common.schema import register_response_schema_models, register_schema_models from core.app.app_config.common.parameters_mapping import get_parameters_from_feature_dict from libs.passport import PassportService from libs.token import extract_webapp_passport @@ -33,6 +33,11 @@ class AppAccessModeQuery(BaseModel): register_schema_models(web_ns, AppAccessModeQuery) +register_response_schema_models( + web_ns, + fields.AccessModeResponse, + fields.BooleanResultResponse, +) @web_ns.route("/parameters") @@ -109,6 +114,7 @@ class AppAccessMode(Resource): 500: "Internal Server Error", } ) + @web_ns.response(200, "Success", web_ns.models[fields.AccessModeResponse.__name__]) def get(self): raw_args = request.args.to_dict() args = AppAccessModeQuery.model_validate(raw_args) @@ -142,6 +148,7 @@ class AppWebAuthPermission(Resource): 500: "Internal Server Error", } ) + @web_ns.response(200, "Success", web_ns.models[fields.BooleanResultResponse.__name__]) def get(self): user_id = "visitor" app_code = request.headers.get(HEADER_NAME_APP_CODE) diff --git a/api/controllers/web/completion.py b/api/controllers/web/completion.py index 0528184d79..8f52988ef9 100644 --- a/api/controllers/web/completion.py +++ b/api/controllers/web/completion.py @@ -5,7 +5,8 @@ from pydantic import BaseModel, Field, field_validator from werkzeug.exceptions import InternalServerError, NotFound import services -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.web import web_ns from controllers.web.error import ( AppUnavailableError, @@ -66,6 +67,7 @@ class ChatMessagePayload(BaseModel): register_schema_models(web_ns, CompletionMessagePayload, ChatMessagePayload) +register_response_schema_models(web_ns, SimpleResultResponse) # define completion api for user @@ -137,6 +139,7 @@ class CompletionStopApi(WebApiResource): 500: "Internal Server Error", } ) + @web_ns.response(200, "Success", web_ns.models[SimpleResultResponse.__name__]) def post(self, app_model, end_user, task_id): if app_model.mode != AppMode.COMPLETION: raise NotCompletionAppError() @@ -222,6 +225,7 @@ class ChatStopApi(WebApiResource): 500: "Internal Server Error", } ) + @web_ns.response(200, "Success", web_ns.models[SimpleResultResponse.__name__]) def post(self, app_model, end_user, task_id): app_mode = AppMode.value_of(app_model.mode) if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}: diff --git a/api/controllers/web/conversation.py b/api/controllers/web/conversation.py index 3975dd85c8..6afa00c727 100644 --- a/api/controllers/web/conversation.py +++ b/api/controllers/web/conversation.py @@ -6,7 +6,7 @@ from sqlalchemy.orm import sessionmaker from werkzeug.exceptions import NotFound from controllers.common.controller_schemas import ConversationRenamePayload -from controllers.common.schema import register_schema_models +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.web import web_ns from controllers.web.error import NotChatAppError from controllers.web.wraps import WebApiResource @@ -39,6 +39,7 @@ class ConversationListQuery(BaseModel): register_schema_models(web_ns, ConversationListQuery, ConversationRenamePayload) +register_response_schema_models(web_ns, ResultResponse) @web_ns.route("/conversations") @@ -201,6 +202,7 @@ class ConversationPinApi(WebApiResource): 500: "Internal Server Error", } ) + @web_ns.response(200, "Conversation pinned successfully", web_ns.models[ResultResponse.__name__]) def patch(self, app_model, end_user, c_id): app_mode = AppMode.value_of(app_model.mode) if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}: @@ -231,6 +233,7 @@ class ConversationUnPinApi(WebApiResource): 500: "Internal Server Error", } ) + @web_ns.response(200, "Conversation unpinned successfully", web_ns.models[ResultResponse.__name__]) def patch(self, app_model, end_user, c_id): app_mode = AppMode.value_of(app_model.mode) if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}: diff --git a/api/controllers/web/feature.py b/api/controllers/web/feature.py index 2540bf02f4..2a600f445a 100644 --- a/api/controllers/web/feature.py +++ b/api/controllers/web/feature.py @@ -1,7 +1,10 @@ from flask_restx import Resource +from controllers.common.schema import register_response_schema_models from controllers.web import web_ns -from services.feature_service import FeatureService +from services.feature_service import FeatureService, SystemFeatureModel + +register_response_schema_models(web_ns, SystemFeatureModel) @web_ns.route("/system-features") @@ -9,6 +12,11 @@ class SystemFeatureApi(Resource): @web_ns.doc("get_system_features") @web_ns.doc(description="Get system feature flags and configuration") @web_ns.doc(responses={200: "System features retrieved successfully", 500: "Internal server error"}) + @web_ns.response( + 200, + "System features retrieved successfully", + web_ns.models[SystemFeatureModel.__name__], + ) def get(self): """Get system feature flags and configuration. diff --git a/api/controllers/web/forgot_password.py b/api/controllers/web/forgot_password.py index 61fd794c22..d0e023e40e 100644 --- a/api/controllers/web/forgot_password.py +++ b/api/controllers/web/forgot_password.py @@ -4,7 +4,8 @@ import secrets from flask import request from flask_restx import Resource -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultDataResponse, SimpleResultResponse, VerificationTokenResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console.auth.error import ( AuthenticationFailedError, EmailCodeError, @@ -28,6 +29,12 @@ from services.entities.auth_entities import ( ) register_schema_models(web_ns, ForgotPasswordSendPayload, ForgotPasswordCheckPayload, ForgotPasswordResetPayload) +register_response_schema_models( + web_ns, + SimpleResultDataResponse, + SimpleResultResponse, + VerificationTokenResponse, +) @web_ns.route("/forgot-password") @@ -46,6 +53,7 @@ class ForgotPasswordSendEmailApi(Resource): 429: "Too many requests - rate limit exceeded", } ) + @web_ns.response(200, "Password reset email sent successfully", web_ns.models[SimpleResultDataResponse.__name__]) def post(self): payload = ForgotPasswordSendPayload.model_validate(web_ns.payload or {}) @@ -81,6 +89,7 @@ class ForgotPasswordCheckApi(Resource): @web_ns.doc( responses={200: "Token is valid", 400: "Bad request - invalid token format", 401: "Invalid or expired token"} ) + @web_ns.response(200, "Token is valid", web_ns.models[VerificationTokenResponse.__name__]) def post(self): payload = ForgotPasswordCheckPayload.model_validate(web_ns.payload or {}) @@ -134,6 +143,7 @@ class ForgotPasswordResetApi(Resource): 404: "Account not found", } ) + @web_ns.response(200, "Password reset successfully", web_ns.models[SimpleResultResponse.__name__]) def post(self): payload = ForgotPasswordResetPayload.model_validate(web_ns.payload or {}) diff --git a/api/controllers/web/login.py b/api/controllers/web/login.py index 2255dd0332..2b9f8eac0f 100644 --- a/api/controllers/web/login.py +++ b/api/controllers/web/login.py @@ -8,7 +8,13 @@ from werkzeug.exceptions import Unauthorized import services from configs import dify_config -from controllers.common.schema import register_schema_models +from controllers.common.fields import ( + AccessTokenResultResponse, + LoginStatusResponse, + SimpleResultDataResponse, + SimpleResultResponse, +) +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.console.auth.error import ( AuthenticationFailedError, EmailCodeError, @@ -57,6 +63,13 @@ class EmailCodeLoginVerifyPayload(BaseModel): register_schema_models(web_ns, LoginPayload, EmailCodeLoginSendPayload, EmailCodeLoginVerifyPayload) +register_response_schema_models( + web_ns, + AccessTokenResultResponse, + LoginStatusResponse, + SimpleResultDataResponse, + SimpleResultResponse, +) @web_ns.route("/login") @@ -77,6 +90,7 @@ class LoginApi(Resource): 404: "Account not found", } ) + @web_ns.response(200, "Authentication successful", web_ns.models[AccessTokenResultResponse.__name__]) @decrypt_password_field def post(self): """Authenticate user and login.""" @@ -114,6 +128,7 @@ class LoginStatusApi(Resource): 401: "Login status", } ) + @web_ns.response(200, "Login status", web_ns.models[LoginStatusResponse.__name__]) def get(self): app_code = request.args.get("app_code") user_id = request.args.get("user_id") @@ -160,6 +175,7 @@ class LogoutApi(Resource): 200: "Logout successful", } ) + @web_ns.response(200, "Logout successful", web_ns.models[SimpleResultResponse.__name__]) def post(self): response = make_response({"result": "success"}) # enterprise SSO sets same site to None in https deployment @@ -182,6 +198,7 @@ class EmailCodeLoginSendEmailApi(Resource): 404: "Account not found", } ) + @web_ns.response(200, "Email code sent successfully", web_ns.models[SimpleResultDataResponse.__name__]) def post(self): payload = EmailCodeLoginSendPayload.model_validate(web_ns.payload or {}) @@ -213,6 +230,11 @@ class EmailCodeLoginApi(Resource): 404: "Account not found", } ) + @web_ns.response( + 200, + "Email code verified and login successful", + web_ns.models[AccessTokenResultResponse.__name__], + ) @decrypt_code_field def post(self): payload = EmailCodeLoginVerifyPayload.model_validate(web_ns.payload or {}) diff --git a/api/controllers/web/message.py b/api/controllers/web/message.py index 07ecf8035b..fc5e266c5c 100644 --- a/api/controllers/web/message.py +++ b/api/controllers/web/message.py @@ -6,7 +6,7 @@ from pydantic import BaseModel, Field, TypeAdapter from werkzeug.exceptions import InternalServerError, NotFound from controllers.common.controller_schemas import MessageFeedbackPayload, MessageListQuery -from controllers.common.schema import register_schema_models +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.web import web_ns from controllers.web.error import ( AppMoreLikeThisDisabledError, @@ -47,6 +47,7 @@ class MessageMoreLikeThisQuery(BaseModel): register_schema_models(web_ns, MessageListQuery, MessageFeedbackPayload, MessageMoreLikeThisQuery) +register_response_schema_models(web_ns, ResultResponse, SuggestedQuestionsResponse) @web_ns.route("/messages") @@ -130,6 +131,7 @@ class MessageFeedbackApi(WebApiResource): 500: "Internal Server Error", } ) + @web_ns.response(200, "Feedback submitted successfully", web_ns.models[ResultResponse.__name__]) def post(self, app_model, end_user, message_id): message_id = str(message_id) @@ -206,6 +208,7 @@ class MessageMoreLikeThisApi(WebApiResource): @web_ns.route("/messages//suggested-questions") class MessageSuggestedQuestionApi(WebApiResource): + @web_ns.response(200, "Success", web_ns.models[SuggestedQuestionsResponse.__name__]) @web_ns.doc("Get Suggested Questions") @web_ns.doc(description="Get suggested follow-up questions after a message (chat apps only).") @web_ns.doc(params={"message_id": {"description": "Message UUID", "type": "string", "required": True}}) diff --git a/api/controllers/web/remote_files.py b/api/controllers/web/remote_files.py index fe31e9d4ac..ff583acd5c 100644 --- a/api/controllers/web/remote_files.py +++ b/api/controllers/web/remote_files.py @@ -16,7 +16,7 @@ from fields.file_fields import FileWithSignedUrl, RemoteFileInfo from graphon.file import helpers as file_helpers from services.file_service import FileService -from ..common.schema import register_schema_models +from ..common.schema import register_response_schema_models, register_schema_models from . import web_ns from .wraps import WebApiResource @@ -25,7 +25,8 @@ class RemoteFileUploadPayload(BaseModel): url: HttpUrl = Field(description="Remote file URL") -register_schema_models(web_ns, RemoteFileUploadPayload, RemoteFileInfo, FileWithSignedUrl) +register_schema_models(web_ns, RemoteFileUploadPayload) +register_response_schema_models(web_ns, RemoteFileInfo, FileWithSignedUrl) @web_ns.route("/remote-files/") diff --git a/api/controllers/web/saved_message.py b/api/controllers/web/saved_message.py index 5b206f9a98..b1382efbd8 100644 --- a/api/controllers/web/saved_message.py +++ b/api/controllers/web/saved_message.py @@ -3,7 +3,7 @@ from pydantic import TypeAdapter from werkzeug.exceptions import NotFound from controllers.common.controller_schemas import SavedMessageCreatePayload, SavedMessageListQuery -from controllers.common.schema import register_schema_models +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.web import web_ns from controllers.web.error import NotCompletionAppError from controllers.web.wraps import WebApiResource @@ -13,6 +13,7 @@ from services.errors.message import MessageNotExistsError from services.saved_message_service import SavedMessageService register_schema_models(web_ns, SavedMessageListQuery, SavedMessageCreatePayload) +register_response_schema_models(web_ns, ResultResponse) @web_ns.route("/saved-messages") @@ -73,6 +74,7 @@ class SavedMessageListApi(WebApiResource): 500: "Internal Server Error", } ) + @web_ns.response(200, "Message saved successfully", web_ns.models[ResultResponse.__name__]) def post(self, app_model, end_user): if app_model.mode != "completion": raise NotCompletionAppError() diff --git a/api/controllers/web/workflow.py b/api/controllers/web/workflow.py index 98211193a0..00b3434922 100644 --- a/api/controllers/web/workflow.py +++ b/api/controllers/web/workflow.py @@ -3,7 +3,8 @@ import logging from werkzeug.exceptions import InternalServerError from controllers.common.controller_schemas import WorkflowRunPayload -from controllers.common.schema import register_schema_models +from controllers.common.fields import SimpleResultResponse +from controllers.common.schema import register_response_schema_models, register_schema_models from controllers.web import web_ns from controllers.web.error import ( CompletionRequestError, @@ -32,6 +33,7 @@ from services.errors.llm import InvokeRateLimitError logger = logging.getLogger(__name__) register_schema_models(web_ns, WorkflowRunPayload) +register_response_schema_models(web_ns, SimpleResultResponse) @web_ns.route("/workflows/run") @@ -102,6 +104,7 @@ class WorkflowTaskStopApi(WebApiResource): 500: "Internal Server Error", } ) + @web_ns.response(200, "Success", web_ns.models[SimpleResultResponse.__name__]) def post(self, app_model: App, end_user: EndUser, task_id: str): """ Stop workflow task diff --git a/api/fields/file_fields.py b/api/fields/file_fields.py index a3987a7e40..eb10308851 100644 --- a/api/fields/file_fields.py +++ b/api/fields/file_fields.py @@ -2,7 +2,7 @@ from __future__ import annotations from datetime import datetime -from pydantic import field_validator +from pydantic import ConfigDict, field_validator from fields.base import ResponseModel from libs.helper import to_timestamp @@ -49,6 +49,8 @@ class RemoteFileInfo(ResponseModel): class FileWithSignedUrl(ResponseModel): + model_config = ConfigDict(json_schema_serialization_defaults_required=True) + id: str name: str size: int diff --git a/api/openapi/markdown/console-swagger.md b/api/openapi/markdown/console-swagger.md index dc055c5823..2c8f0bd169 100644 --- a/api/openapi/markdown/console-swagger.md +++ b/api/openapi/markdown/console-swagger.md @@ -31,9 +31,9 @@ Get account avatar url ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [AvatarUrlResponse](#avatarurlresponse) | #### POST ##### Parameters @@ -59,9 +59,9 @@ Get account avatar url ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultDataResponse](#simpleresultdataresponse) | ### /account/change-email/check-email-unique @@ -74,9 +74,9 @@ Get account avatar url ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /account/change-email/reset @@ -104,9 +104,9 @@ Get account avatar url ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [VerificationTokenResponse](#verificationtokenresponse) | ### /account/delete @@ -119,9 +119,9 @@ Get account avatar url ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /account/delete/feedback @@ -134,18 +134,18 @@ Get account avatar url ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /account/delete/verify #### GET ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultDataResponse](#simpleresultdataresponse) | ### /account/education @@ -204,9 +204,9 @@ Get account avatar url ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /account/integrates @@ -444,9 +444,9 @@ Update API-based extension #### GET ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [ApiKeyAuthDataSourceListResponse](#apikeyauthdatasourcelistresponse) | ### /api-key-auth/data-source/binding @@ -476,7 +476,7 @@ Update API-based extension | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Binding deleted successfully | ### /app/prompt-templates @@ -1333,9 +1333,9 @@ Stop a running chat message generation ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Task stopped successfully | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Task stopped successfully | [SimpleResultResponse](#simpleresultresponse) | ### /apps/{app_id}/completion-conversations @@ -1438,9 +1438,9 @@ Stop a running completion message generation ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Task stopped successfully | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Task stopped successfully | [SimpleResultResponse](#simpleresultresponse) | ### /apps/{app_id}/conversation-variables @@ -1484,11 +1484,11 @@ Convert Completion App to Workflow App ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Application converted to workflow successfully | -| 400 | Application cannot be converted | -| 403 | Permission denied | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Application converted to workflow successfully | [NewAppResponse](#newappresponse) | +| 400 | Application cannot be converted | | +| 403 | Permission denied | | ### /apps/{app_id}/copy @@ -1556,11 +1556,11 @@ Create or update message feedback (like/dislike) ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Feedback updated successfully | -| 403 | Insufficient permissions | -| 404 | Message not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Feedback updated successfully | [SimpleResultResponse](#simpleresultresponse) | +| 403 | Insufficient permissions | | +| 404 | Message not found | | ### /apps/{app_id}/feedbacks/export @@ -1687,9 +1687,9 @@ Publish app to Creators Platform ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [RedirectUrlResponse](#redirecturlresponse) | ### /apps/{app_id}/server @@ -2052,10 +2052,10 @@ Update app tracing configuration ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Trace configuration updated successfully | -| 403 | Insufficient permissions | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Trace configuration updated successfully | [SimpleResultResponse](#simpleresultresponse) | +| 403 | Insufficient permissions | | ### /apps/{app_id}/trace-config @@ -2307,11 +2307,11 @@ Stop running workflow task ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Task stopped successfully | -| 403 | Permission denied | -| 404 | Task not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Task stopped successfully | [SimpleResultResponse](#simpleresultresponse) | +| 403 | Permission denied | | +| 404 | Task not found | | ### /apps/{app_id}/workflow-runs/{run_id} @@ -2915,9 +2915,9 @@ Update draft workflow features ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Workflow features updated successfully | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Workflow features updated successfully | [SimpleResultResponse](#simpleresultresponse) | ### /apps/{app_id}/workflows/draft/human-input/nodes/{node_id}/delivery-test @@ -3658,9 +3658,9 @@ Refresh MCP server configuration and regenerate server code ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | #### POST ##### Parameters @@ -3688,9 +3688,9 @@ Refresh MCP server configuration and regenerate server code ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /auth/plugin/datasource/{provider_id}/delete @@ -3704,9 +3704,9 @@ Refresh MCP server configuration and regenerate server code ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /auth/plugin/datasource/{provider_id}/update @@ -3736,9 +3736,9 @@ Refresh MCP server configuration and regenerate server code ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /billing/invoices @@ -3829,9 +3829,9 @@ Get compliance document download link #### PATCH ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /data-source/integrates/{binding_id}/{action} @@ -3859,9 +3859,9 @@ Get compliance document download link ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /datasets @@ -3914,9 +3914,9 @@ Get dataset API base information ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | API base info retrieved successfully | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | API base info retrieved successfully | [ApiBaseUrlResponse](#apibaseurlresponse) | ### /datasets/api-keys @@ -3969,9 +3969,9 @@ Delete dataset API key ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Batch import status | [SegmentBatchImportStatusResponse](#segmentbatchimportstatusresponse) | #### POST ##### Parameters @@ -3983,9 +3983,9 @@ Delete dataset API key ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Batch import started | [SegmentBatchImportStatusResponse](#segmentbatchimportstatusresponse) | ### /datasets/external @@ -4055,7 +4055,7 @@ Get external knowledge API templates | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | External knowledge API deleted successfully | #### GET ##### Description @@ -4104,9 +4104,9 @@ Check if external knowledge API is being used ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Usage check completed successfully | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Usage check completed successfully | [UsageCountResponse](#usagecountresponse) | ### /datasets/indexing-estimate @@ -4161,9 +4161,9 @@ Initialize dataset with documents #### GET ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [TextContentResponse](#textcontentresponse) | #### POST ##### Parameters @@ -4242,7 +4242,7 @@ Get mock dataset retrieval settings by vector type | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Dataset deleted successfully | #### GET ##### Description @@ -4295,9 +4295,9 @@ Update dataset details ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /datasets/{dataset_id}/auto-disable-logs @@ -4364,7 +4364,7 @@ Get dataset auto disable logs | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Documents deleted successfully | #### GET ##### Description @@ -4450,12 +4450,12 @@ then asynchronously generates summary indexes for the provided documents. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Summary generation started successfully | -| 400 | Invalid request or dataset configuration | -| 403 | Permission denied | -| 404 | Dataset not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Summary generation started successfully | [SimpleResultResponse](#simpleresultresponse) | +| 400 | Invalid request or dataset configuration | | +| 403 | Permission denied | | +| 404 | Dataset not found | | ### /datasets/{dataset_id}/documents/metadata @@ -4469,9 +4469,9 @@ then asynchronously generates summary indexes for the provided documents. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /datasets/{dataset_id}/documents/status/{action}/batch @@ -4485,9 +4485,9 @@ then asynchronously generates summary indexes for the provided documents. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /datasets/{dataset_id}/documents/{document_id} @@ -4503,7 +4503,7 @@ then asynchronously generates summary indexes for the provided documents. | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Document deleted successfully | #### GET ##### Description @@ -4541,9 +4541,9 @@ Get a signed download URL for a dataset document's original uploaded file ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Download URL generated successfully | [UrlResponse](#urlresponse) | ### /datasets/{dataset_id}/documents/{document_id}/indexing-estimate @@ -4605,11 +4605,11 @@ Update document metadata ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Document metadata updated successfully | -| 403 | Permission denied | -| 404 | Document not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Document metadata updated successfully | [SimpleResultMessageResponse](#simpleresultmessageresponse) | +| 403 | Permission denied | | +| 404 | Document not found | | ### /datasets/{dataset_id}/documents/{document_id}/notion/sync @@ -4623,9 +4623,9 @@ Update document metadata ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /datasets/{dataset_id}/documents/{document_id}/pipeline-execution-log @@ -4661,7 +4661,7 @@ pause document | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Document paused successfully | ### /datasets/{dataset_id}/documents/{document_id}/processing/resume @@ -4681,7 +4681,7 @@ recover document | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Document resumed successfully | ### /datasets/{dataset_id}/documents/{document_id}/processing/{action} @@ -4700,11 +4700,11 @@ Update document processing status (pause/resume) ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Processing status updated successfully | -| 400 | Invalid action | -| 404 | Document not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Processing status updated successfully | [SimpleResultResponse](#simpleresultresponse) | +| 400 | Invalid action | | +| 404 | Document not found | | ### /datasets/{dataset_id}/documents/{document_id}/rename @@ -4753,9 +4753,9 @@ Update document processing status (pause/resume) ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /datasets/{dataset_id}/documents/{document_id}/segments @@ -4771,7 +4771,7 @@ Update document processing status (pause/resume) | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Segments deleted successfully | #### GET ##### Parameters @@ -4799,9 +4799,9 @@ Update document processing status (pause/resume) ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Batch import status | [SegmentBatchImportStatusResponse](#segmentbatchimportstatusresponse) | #### POST ##### Parameters @@ -4814,9 +4814,9 @@ Update document processing status (pause/resume) ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Batch import started | [SegmentBatchImportStatusResponse](#segmentbatchimportstatusresponse) | ### /datasets/{dataset_id}/documents/{document_id}/segments/{segment_id} @@ -4833,7 +4833,7 @@ Update document processing status (pause/resume) | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Segment deleted successfully | #### PATCH ##### Parameters @@ -4915,7 +4915,7 @@ Update document processing status (pause/resume) | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Child chunk deleted successfully | #### PATCH ##### Parameters @@ -4983,9 +4983,9 @@ sync website document ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /datasets/{dataset_id}/error-docs @@ -5111,9 +5111,9 @@ Get dataset indexing status ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /datasets/{dataset_id}/metadata/{metadata_id} @@ -5129,7 +5129,7 @@ Get dataset indexing status | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Metadata deleted successfully | #### PATCH ##### Parameters @@ -5157,9 +5157,9 @@ Get dataset indexing status ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /datasets/{dataset_id}/permission-part-users @@ -5238,7 +5238,7 @@ retry document | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Documents retry started successfully | ### /datasets/{dataset_id}/use-check @@ -5255,9 +5255,9 @@ Check if dataset is in use ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Dataset use status retrieved successfully | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Dataset use status retrieved successfully | [UsageCheckResponse](#usagecheckresponse) | ### /datasets/{resource_id}/api-keys @@ -5339,9 +5339,9 @@ Delete an API key for a dataset ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultDataResponse](#simpleresultdataresponse) | ### /email-code-login/validity @@ -5354,9 +5354,9 @@ Delete an API key for a dataset ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /email-register @@ -5372,18 +5372,18 @@ Delete an API key for a dataset #### POST ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultDataResponse](#simpleresultdataresponse) | ### /email-register/validity #### POST ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [VerificationTokenResponse](#verificationtokenresponse) | ### /explore/apps @@ -5430,16 +5430,16 @@ Get feature configuration for current tenant | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | [FeatureResponse](#featureresponse) | +| 200 | Success | [FeatureModel](#featuremodel) | ### /files/support-type #### GET ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [AllowedExtensionsResponse](#allowedextensionsresponse) | ### /files/upload @@ -5468,9 +5468,9 @@ Get feature configuration for current tenant ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [TextContentResponse](#textcontentresponse) | ### /forgot-password @@ -5605,9 +5605,9 @@ Request body: #### POST ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleMessageResponse](#simplemessageresponse) | ### /installed-apps/{installed_app_id} @@ -5622,7 +5622,7 @@ Request body: | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | App uninstalled successfully | #### PATCH ##### Parameters @@ -5633,9 +5633,9 @@ Request body: ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultMessageResponse](#simpleresultmessageresponse) | ### /installed-apps/{installed_app_id}/audio-to-text @@ -5680,9 +5680,9 @@ Request body: ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /installed-apps/{installed_app_id}/completion-messages @@ -5712,9 +5712,9 @@ Request body: ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /installed-apps/{installed_app_id}/conversations @@ -5746,7 +5746,7 @@ Request body: | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Conversation deleted successfully | ### /installed-apps/{installed_app_id}/conversations/{c_id}/name @@ -5777,9 +5777,9 @@ Request body: ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [ResultResponse](#resultresponse) | ### /installed-apps/{installed_app_id}/conversations/{c_id}/unpin @@ -5793,9 +5793,9 @@ Request body: ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [ResultResponse](#resultresponse) | ### /installed-apps/{installed_app_id}/messages @@ -5826,9 +5826,9 @@ Request body: ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Feedback submitted successfully | [ResultResponse](#resultresponse) | ### /installed-apps/{installed_app_id}/messages/{message_id}/more-like-this @@ -5859,9 +5859,9 @@ Request body: ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SuggestedQuestionsResponse](#suggestedquestionsresponse) | ### /installed-apps/{installed_app_id}/meta @@ -5927,9 +5927,9 @@ Retrieve app parameters ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [ResultResponse](#resultresponse) | ### /installed-apps/{installed_app_id}/saved-messages/{message_id} @@ -5945,7 +5945,7 @@ Retrieve app parameters | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Saved message deleted successfully | ### /installed-apps/{installed_app_id}/text-to-audio @@ -5999,9 +5999,9 @@ Stop workflow task ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /instruction-generate @@ -6059,18 +6059,18 @@ Authenticate user and login ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultOptionalDataResponse](#simpleresultoptionaldataresponse) | ### /logout #### POST ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /mcp/oauth/callback @@ -6104,10 +6104,10 @@ Mark a notification as dismissed for the current user. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | -| 401 | Unauthorized | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | +| 401 | Unauthorized | | ### /notion/pages/{page_id}/{page_type}/preview @@ -6121,9 +6121,9 @@ Mark a notification as dismissed for the current user. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [TextContentResponse](#textcontentresponse) | #### POST ##### Parameters @@ -6429,9 +6429,9 @@ Handle OAuth callback for trigger provider ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleDataResponse](#simpledataresponse) | ### /rag/pipeline/dataset @@ -6625,9 +6625,9 @@ Stop workflow task ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Task stopped successfully | [SimpleResultResponse](#simpleresultresponse) | ### /rag/pipelines/{pipeline_id}/workflow-runs/{run_id} @@ -6761,9 +6761,9 @@ Sync draft workflow ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [RagPipelineWorkflowSyncResponse](#ragpipelineworkflowsyncresponse) | ### /rag/pipelines/{pipeline_id}/workflows/draft/datasource/nodes/{node_id}/run @@ -7123,9 +7123,9 @@ Publish workflow ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [RagPipelineWorkflowPublishResponse](#ragpipelineworkflowpublishresponse) | ### /rag/pipelines/{pipeline_id}/workflows/published/datasource/nodes/{node_id}/preview @@ -7245,7 +7245,7 @@ Delete a published workflow version that is not currently active on the pipeline | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Workflow deleted successfully | #### PATCH ##### Summary @@ -7280,27 +7280,33 @@ Update workflow attributes ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [RagPipelineWorkflowSyncResponse](#ragpipelineworkflowsyncresponse) | ### /refresh-token #### POST ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /remote-files/upload #### POST +##### Parameters + +| Name | Located in | Description | Required | Schema | +| ---- | ---------- | ----------- | -------- | ------ | +| payload | body | | Yes | [RemoteFileUploadPayload](#remotefileuploadpayload) | + ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 201 | File uploaded successfully | [FileWithSignedUrl](#filewithsignedurl) | ### /remote-files/{url} @@ -7313,9 +7319,9 @@ Update workflow attributes ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [RemoteFileInfo](#remotefileinfo) | ### /reset-password @@ -7328,9 +7334,9 @@ Update workflow attributes ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultDataResponse](#simpleresultdataresponse) | ### /rule-code-generate @@ -7433,7 +7439,7 @@ Only non-sensitive configuration data should be returned by this endpoint. | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | [SystemFeatureResponse](#systemfeatureresponse) | +| 200 | Success | [SystemFeatureModel](#systemfeaturemodel) | ### /tag-bindings @@ -7446,9 +7452,9 @@ Only non-sensitive configuration data should be returned by this endpoint. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /tag-bindings/remove @@ -7465,9 +7471,9 @@ Remove one or more tag bindings from a target. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /tags @@ -7494,9 +7500,9 @@ Remove one or more tag bindings from a target. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [TagResponse](#tagresponse) | ### /tags/{tag_id} @@ -7511,7 +7517,7 @@ Remove one or more tag bindings from a target. | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Tag deleted successfully | #### PATCH ##### Parameters @@ -7523,9 +7529,9 @@ Remove one or more tag bindings from a target. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [TagResponse](#tagresponse) | ### /test/retrieval @@ -7938,9 +7944,9 @@ Get list of available agent providers ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /workspaces/current/endpoints @@ -8177,9 +8183,9 @@ Update a plugin endpoint ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [VerificationTokenResponse](#verificationtokenresponse) | ### /workspaces/current/members/send-owner-transfer-confirm-email @@ -8192,9 +8198,9 @@ Update a plugin endpoint ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultDataResponse](#simpleresultdataresponse) | ### /workspaces/current/members/{member_id} @@ -8287,7 +8293,7 @@ Update a plugin endpoint | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Credential deleted successfully | #### GET ##### Parameters @@ -8343,9 +8349,9 @@ Update a plugin endpoint ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /workspaces/current/model-providers/{provider}/credentials/validate @@ -8377,7 +8383,7 @@ Update a plugin endpoint | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Model deleted successfully | #### GET ##### Parameters @@ -8420,7 +8426,7 @@ Update a plugin endpoint | Code | Description | | ---- | ----------- | -| 200 | Success | +| 204 | Credential deleted successfully | #### GET ##### Parameters @@ -8476,9 +8482,9 @@ Update a plugin endpoint ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /workspaces/current/model-providers/{provider}/models/credentials/validate @@ -8508,9 +8514,9 @@ Update a plugin endpoint ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /workspaces/current/model-providers/{provider}/models/enable @@ -8524,9 +8530,9 @@ Update a plugin endpoint ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /workspaces/current/model-providers/{provider}/models/load-balancing-configs/credentials-validate @@ -8589,9 +8595,9 @@ Update a plugin endpoint ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /workspaces/current/models/model-types/{model_type} @@ -8621,9 +8627,9 @@ Returns permission flags that control workspace features like member invitations ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [WorkspacePermissionResponse](#workspacepermissionresponse) | ### /workspaces/current/plugin/asset @@ -8645,9 +8651,9 @@ Returns permission flags that control workspace features like member invitations #### GET ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [PluginDebuggingKeyResponse](#plugindebuggingkeyresponse) | ### /workspaces/current/plugin/fetch-manifest @@ -8829,9 +8835,9 @@ Fetch dynamic options using credentials directly (for edit mode) ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SuccessResponse](#successresponse) | ### /workspaces/current/plugin/permission/fetch @@ -8916,9 +8922,9 @@ Fetch dynamic options using credentials directly (for edit mode) #### POST ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SuccessResponse](#successresponse) | ### /workspaces/current/plugin/tasks/{task_id} @@ -8946,9 +8952,9 @@ Fetch dynamic options using credentials directly (for edit mode) ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SuccessResponse](#successresponse) | ### /workspaces/current/plugin/tasks/{task_id}/delete/{identifier} @@ -8962,9 +8968,9 @@ Fetch dynamic options using credentials directly (for edit mode) ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SuccessResponse](#successresponse) | ### /workspaces/current/plugin/uninstall @@ -8977,9 +8983,9 @@ Fetch dynamic options using credentials directly (for edit mode) ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SuccessResponse](#successresponse) | ### /workspaces/current/plugin/upgrade/github @@ -9378,9 +9384,9 @@ Fetch dynamic options using credentials directly (for edit mode) ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | #### POST ##### Parameters @@ -9846,9 +9852,9 @@ Delete a subscription instance ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | ### /workspaces/current/trigger-provider/{subscription_id}/subscriptions/update @@ -10135,11 +10141,19 @@ Get banner list | token | string | | Yes | | workspace_id | string | | No | +#### ActivationCheckData + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| email | string | | Yes | +| workspace_id | string | | Yes | +| workspace_name | string | | Yes | + #### ActivationCheckResponse | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| data | object | Activation data if valid | No | +| data | [ActivationCheckData](#activationcheckdata) | Activation data if valid | No | | is_valid | boolean | Whether token is valid | Yes | #### ActivationResponse @@ -10217,6 +10231,12 @@ Get banner list | tool_input | string | | No | | tool_labels | [JSONValue](#jsonvalue) | | Yes | +#### AllowedExtensionsResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| allowed_extensions | [ string ] | | Yes | + #### Annotation | Name | Type | Description | Required | @@ -10305,6 +10325,12 @@ Get banner list | ---- | ---- | ----------- | -------- | | score_threshold | number | Score threshold | Yes | +#### ApiBaseUrlResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| api_base_url | string | | Yes | + #### ApiKeyAuthBindingPayload | Name | Type | Description | Required | @@ -10313,6 +10339,23 @@ Get banner list | credentials | object | | Yes | | provider | string | | Yes | +#### ApiKeyAuthDataSourceItem + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| category | string | | Yes | +| created_at | integer | | Yes | +| disabled | boolean | | Yes | +| id | string | | Yes | +| provider | string | | Yes | +| updated_at | integer | | Yes | + +#### ApiKeyAuthDataSourceListResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| sources | [ [ApiKeyAuthDataSourceItem](#apikeyauthdatasourceitem) ] | | Yes | + #### ApiKeyItem | Name | Type | Description | Required | @@ -10625,6 +10668,12 @@ AppMCPServer Status Enum | ---- | ---- | ----------- | -------- | | text | string | Transcribed text from audio | Yes | +#### AvatarUrlResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| avatar_url | string | | Yes | + #### BatchImportPayload | Name | Type | Description | Required | @@ -10648,6 +10697,23 @@ Retrieval settings for Amazon Bedrock knowledge base queries. | score_threshold | number | Minimum relevance score threshold | No | | top_k | integer | Maximum number of results to retrieve | No | +#### BillingModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| enabled | boolean | | Yes | +| subscription | [SubscriptionModel](#subscriptionmodel) | | Yes | + +#### BrandingModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| application_title | string | | Yes | +| enabled | boolean | | Yes | +| favicon | string | | Yes | +| login_page_logo | string | | Yes | +| workspace_logo | string | | Yes | + #### BuiltinProviderDefaultCredentialPayload | Name | Type | Description | Required | @@ -11568,6 +11634,13 @@ Request payload for bulk downloading documents as a zip archive. | data | [ string ] | | No | | has_next | boolean | | No | +#### EducationModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| activated | boolean | | Yes | +| enabled | boolean | | Yes | + #### EducationStatusResponse | Name | Type | Description | Required | @@ -11759,11 +11832,30 @@ Request payload for bulk downloading documents as a zip archive. | score_threshold_enabled | boolean | | No | | top_k | integer | | No | -#### FeatureResponse +#### FeatureModel | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| features | object | Feature configuration object | No | +| annotation_quota_limit | [LimitationModel](#limitationmodel) | | Yes | +| api_rate_limit | [Quota](#quota) | | Yes | +| apps | [LimitationModel](#limitationmodel) | | Yes | +| billing | [BillingModel](#billingmodel) | | Yes | +| can_replace_logo | boolean | | Yes | +| dataset_operator_enabled | boolean | | Yes | +| docs_processing | string | | Yes | +| documents_upload_quota | [LimitationModel](#limitationmodel) | | Yes | +| education | [EducationModel](#educationmodel) | | Yes | +| human_input_email_delivery_enabled | boolean | | Yes | +| is_allow_transfer_workspace | boolean | | Yes | +| knowledge_pipeline | [KnowledgePipeline](#knowledgepipeline) | | Yes | +| knowledge_rate_limit | integer | | Yes | +| members | [LimitationModel](#limitationmodel) | | Yes | +| model_load_balancing_enabled | boolean | | Yes | +| next_credit_reset_date | integer | | Yes | +| trigger_event | [Quota](#quota) | | Yes | +| vector_space | [LimitationModel](#limitationmodel) | | Yes | +| webapp_copyright_enabled | boolean | | Yes | +| workspace_members | [LicenseLimitationModel](#licenselimitationmodel) | | Yes | #### Feedback @@ -11851,6 +11943,19 @@ Request payload for bulk downloading documents as a zip archive. | ---- | ---- | ----------- | -------- | | FileType | string | | | +#### FileWithSignedUrl + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| created_at | integer | | Yes | +| created_by | string | | Yes | +| extension | string | | Yes | +| id | string | | Yes | +| mime_type | string | | Yes | +| name | string | | Yes | +| size | integer | | Yes | +| url | string | | Yes | + #### ForgotPasswordCheckPayload | Name | Type | Description | Required | @@ -12226,6 +12331,12 @@ Request payload for bulk downloading documents as a zip archive. | retrieval_model | [RetrievalModel](#retrievalmodel) | | No | | summary_index_setting | object | | No | +#### KnowledgePipeline + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| publish_enabled | boolean | | Yes | + #### LLMMode Enum class for large language model mode. @@ -12242,6 +12353,39 @@ Enum class for large language model mode. | name | string | | Yes | | settings | object | | Yes | +#### LicenseLimitationModel + +- enabled: whether this limit is enforced +- size: current usage count +- limit: maximum allowed count; 0 means unlimited + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| enabled | boolean | Whether this limit is currently active | Yes | +| limit | integer | Maximum number of resources allowed; 0 means no limit | Yes | +| size | integer | Number of resources already consumed | Yes | + +#### LicenseModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| expired_at | string | | Yes | +| status | [LicenseStatus](#licensestatus) | | Yes | +| workspaces | [LicenseLimitationModel](#licenselimitationmodel) | | Yes | + +#### LicenseStatus + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| LicenseStatus | string | | | + +#### LimitationModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| limit | integer | | Yes | +| size | integer | | Yes | + #### LoadBalancingCredentialPayload | Name | Type | Description | Required | @@ -12535,6 +12679,12 @@ Enum class for model type. | ---- | ---- | ----------- | -------- | | response_mode | string | *Enum:* `"blocking"`, `"streaming"` | Yes | +#### NewAppResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| new_app_id | string | | Yes | + #### NodeIdQuery | Name | Type | Description | Required | @@ -13016,6 +13166,14 @@ Form input definition. | upgrade_mode | [UpgradeMode](#upgrademode) | | No | | upgrade_time_of_day | integer | | No | +#### PluginDebuggingKeyResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| host | string | | Yes | +| key | string | | Yes | +| port | integer | | Yes | + #### PluginDependency | Name | Type | Description | Required | @@ -13030,6 +13188,25 @@ Form input definition. | ---- | ---- | ----------- | -------- | | endpoints | [ object ] | Endpoint information | Yes | +#### PluginInstallationPermissionModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| plugin_installation_scope | [PluginInstallationScope](#plugininstallationscope) | | Yes | +| restrict_to_marketplace_only | boolean | | Yes | + +#### PluginInstallationScope + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| PluginInstallationScope | string | | | + +#### PluginManagerModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| enabled | boolean | | Yes | + #### PluginPermissionSettingsPayload | Name | Type | Description | Required | @@ -13070,6 +13247,14 @@ Form input definition. | response_mode | string | *Enum:* `"blocking"`, `"streaming"` | No | | start_node_id | string | | Yes | +#### Quota + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| limit | integer | | Yes | +| reset_date | integer | | Yes | +| usage | integer | | Yes | + #### RagPipelineDatasetImportPayload | Name | Type | Description | Required | @@ -13122,6 +13307,21 @@ Form input definition. | ---- | ---- | ----------- | -------- | | type | string | | No | +#### RagPipelineWorkflowPublishResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| created_at | integer | | Yes | +| result | string | | Yes | + +#### RagPipelineWorkflowSyncResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| hash | string | | Yes | +| result | string | | Yes | +| updated_at | integer | | Yes | + #### RecommendedAppInfoResponse | Name | Type | Description | Required | @@ -13161,6 +13361,12 @@ Form input definition. | ---- | ---- | ----------- | -------- | | language | string | Language code for recommended app localization | No | +#### RedirectUrlResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| redirect_url | string | | Yes | + #### RelatedAppList | Name | Type | Description | Required | @@ -13168,6 +13374,19 @@ Form input definition. | data | [ [AppDetailKernel](#appdetailkernel) ] | | No | | total | integer | | No | +#### RemoteFileInfo + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| file_length | integer | | Yes | +| file_type | string | | Yes | + +#### RemoteFileUploadPayload + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| url | string | URL to fetch | Yes | + #### RerankingModel | Name | Type | Description | Required | @@ -13247,6 +13466,13 @@ Form input definition. | last_id | string | | No | | limit | integer | | No | +#### SegmentBatchImportStatusResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| job_id | string | | Yes | +| job_status | string | | Yes | + #### SegmentCreatePayload | Name | Type | Description | Required | @@ -13302,6 +13528,12 @@ Form input definition. | id | string | | Yes | | name | string | | Yes | +#### SimpleDataResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| data | string | | Yes | + #### SimpleEndUser | Name | Type | Description | Required | @@ -13320,6 +13552,12 @@ Form input definition. | message | string | | Yes | | query | string | | Yes | +#### SimpleMessageResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| message | string | | Yes | + #### SimpleModelConfig | Name | Type | Description | Required | @@ -13327,6 +13565,33 @@ Form input definition. | model_dict | [JSONValue](#jsonvalue) | | No | | pre_prompt | string | | No | +#### SimpleResultDataResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| data | string | | Yes | +| result | string | | Yes | + +#### SimpleResultMessageResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| message | string | | Yes | +| result | string | | Yes | + +#### SimpleResultOptionalDataResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| data | string | | No | +| result | string | | Yes | + +#### SimpleResultResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| result | string | | Yes | + #### Site | Name | Type | Description | Required | @@ -13394,6 +13659,13 @@ Default configuration for form inputs. | type | [ValueSourceType](#valuesourcetype) | | Yes | | value | string | | No | +#### SubscriptionModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| interval | string | | Yes | +| plan | string | | Yes | + #### SubscriptionQuery | Name | Type | Description | Required | @@ -13401,6 +13673,12 @@ Default configuration for form inputs. | interval | string | Billing interval
*Enum:* `"month"`, `"year"` | Yes | | plan | string | Subscription plan
*Enum:* `"professional"`, `"team"` | Yes | +#### SuccessResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| success | boolean | | Yes | + #### SuggestedQuestionsResponse | Name | Type | Description | Required | @@ -13431,11 +13709,32 @@ Default configuration for form inputs. | result | string | | No | | updated_at | string | | No | -#### SystemFeatureResponse +#### SystemFeatureModel | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| features | object | System feature configuration object | No | +| app_dsl_version | string | | Yes | +| branding | [BrandingModel](#brandingmodel) | | Yes | +| enable_change_email | boolean | | Yes | +| enable_collaboration_mode | boolean | | Yes | +| enable_creators_platform | boolean | | Yes | +| enable_email_code_login | boolean | | Yes | +| enable_email_password_login | boolean | | Yes | +| enable_explore_banner | boolean | | Yes | +| enable_marketplace | boolean | | Yes | +| enable_social_oauth_login | boolean | | Yes | +| enable_trial_app | boolean | | Yes | +| is_allow_create_workspace | boolean | | Yes | +| is_allow_register | boolean | | Yes | +| is_email_setup | boolean | | Yes | +| license | [LicenseModel](#licensemodel) | | Yes | +| max_plugin_package_size | integer | | Yes | +| plugin_installation_permission | [PluginInstallationPermissionModel](#plugininstallationpermissionmodel) | | Yes | +| plugin_manager | [PluginManagerModel](#pluginmanagermodel) | | Yes | +| sso_enforced_for_signin | boolean | | Yes | +| sso_enforced_for_signin_protocol | string | | Yes | +| trial_models | [ string ] | | Yes | +| webapp_auth | [WebAppAuthModel](#webappauthmodel) | | Yes | #### Tag @@ -13521,6 +13820,12 @@ Tag type | trial_credits_used | integer | | No | | trial_end_reason | string | | No | +#### TextContentResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| content | string | | Yes | + #### TextToAudioPayload | Name | Type | Description | Required | @@ -13825,6 +14130,25 @@ Tag type | video_file_size_limit | integer | | Yes | | workflow_file_upload_limit | integer | | Yes | +#### UrlResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| url | string | | Yes | + +#### UsageCheckResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| is_using | boolean | | Yes | + +#### UsageCountResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| count | integer | | Yes | +| is_using | boolean | | Yes | + #### UserActionConfig User action configuration. @@ -13844,6 +14168,30 @@ in form definiton, or a variable while the workflow is running. | ---- | ---- | ----------- | -------- | | ValueSourceType | string | ValueSourceType records whether the value comes from a static setting in form definiton, or a variable while the workflow is running. | | +#### VerificationTokenResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| email | string | | Yes | +| is_valid | boolean | | Yes | +| token | string | | Yes | + +#### WebAppAuthModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| allow_email_code_login | boolean | | Yes | +| allow_email_password_login | boolean | | Yes | +| allow_sso | boolean | | Yes | +| enabled | boolean | | Yes | +| sso_config | [WebAppAuthSSOModel](#webappauthssomodel) | | Yes | + +#### WebAppAuthSSOModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| protocol | string | | Yes | + #### WebhookTriggerResponse | Name | Type | Description | Required | @@ -14552,6 +14900,14 @@ Workflow tool configuration | limit | integer | | No | | page | integer | | No | +#### WorkspacePermissionResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| allow_member_invite | boolean | | Yes | +| allow_owner_transfer | boolean | | Yes | +| workspace_id | string | | Yes | + #### _AnonymousInlineModel_b1954337d565 | Name | Type | Description | Required | diff --git a/api/openapi/markdown/service-swagger.md b/api/openapi/markdown/service-swagger.md index 72bea2a1aa..87dbe8c1ba 100644 --- a/api/openapi/markdown/service-swagger.md +++ b/api/openapi/markdown/service-swagger.md @@ -21,9 +21,9 @@ Service operations #### GET ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [IndexInfoResponse](#indexinforesponse) | ### /app/feedbacks @@ -264,11 +264,11 @@ Stop a running chat message generation ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Task stopped successfully | -| 401 | Unauthorized - invalid API token | -| 404 | Task not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Task stopped successfully | [SimpleResultResponse](#simpleresultresponse) | +| 401 | Unauthorized - invalid API token | | +| 404 | Task not found | | ### /completion-messages @@ -318,11 +318,11 @@ Stop a running completion task ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Task stopped successfully | -| 401 | Unauthorized - invalid API token | -| 404 | Task not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Task stopped successfully | [SimpleResultResponse](#simpleresultresponse) | +| 401 | Unauthorized - invalid API token | | +| 404 | Task not found | | ### /conversations @@ -875,11 +875,11 @@ Update metadata for multiple documents ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Documents metadata updated successfully | -| 401 | Unauthorized - invalid API token | -| 404 | Dataset not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Documents metadata updated successfully | [SimpleResultResponse](#simpleresultresponse) | +| 401 | Unauthorized - invalid API token | | +| 404 | Dataset not found | | ### /datasets/{dataset_id}/documents/status/{action} @@ -914,13 +914,13 @@ Raises: ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Document status updated successfully | -| 400 | Bad request - invalid action | -| 401 | Unauthorized - invalid API token | -| 403 | Forbidden - insufficient permissions | -| 404 | Dataset not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Document status updated successfully | [SimpleResultResponse](#simpleresultresponse) | +| 400 | Bad request - invalid action | | +| 401 | Unauthorized - invalid API token | | +| 403 | Forbidden - insufficient permissions | | +| 404 | Dataset not found | | ### /datasets/{dataset_id}/documents/{batch}/indexing-status @@ -1028,12 +1028,12 @@ Get a signed download URL for a document's original uploaded file ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Download URL generated successfully | -| 401 | Unauthorized - invalid API token | -| 403 | Forbidden - insufficient permissions | -| 404 | Document or upload file not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Download URL generated successfully | [UrlResponse](#urlresponse) | +| 401 | Unauthorized - invalid API token | | +| 403 | Forbidden - insufficient permissions | | +| 404 | Document or upload file not found | | ### /datasets/{dataset_id}/documents/{document_id}/segments @@ -1452,11 +1452,11 @@ Enable or disable built-in metadata field ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Action completed successfully | -| 401 | Unauthorized - invalid API token | -| 404 | Dataset not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Action completed successfully | [SimpleResultResponse](#simpleresultresponse) | +| 401 | Unauthorized - invalid API token | | +| 404 | Dataset not found | | ### /datasets/{dataset_id}/metadata/{metadata_id} @@ -1655,11 +1655,11 @@ cross-tenant/app access when an end-user ID is known. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | End user retrieved successfully | -| 401 | Unauthorized - invalid API token | -| 404 | End user not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | End user retrieved successfully | [EndUserDetail](#enduserdetail) | +| 401 | Unauthorized - invalid API token | | +| 404 | End user not found | | ### /files/upload @@ -1770,11 +1770,11 @@ Returns basic information about the application including name, description, tag ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Application info retrieved successfully | -| 401 | Unauthorized - invalid API token | -| 404 | Application not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Application info retrieved successfully | [AppInfoResponse](#appinforesponse) | +| 401 | Unauthorized - invalid API token | | +| 404 | Application not found | | ### /messages @@ -1823,11 +1823,11 @@ Allows users to rate messages as like/dislike and provide optional feedback cont ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Feedback submitted successfully | -| 401 | Unauthorized - invalid API token | -| 404 | Message not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Feedback submitted successfully | [ResultResponse](#resultresponse) | +| 401 | Unauthorized - invalid API token | | +| 404 | Message not found | | ### /messages/{message_id}/suggested @@ -1849,13 +1849,13 @@ Returns AI-generated follow-up questions based on the message content. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Suggested questions retrieved successfully | -| 400 | Suggested questions feature is disabled | -| 401 | Unauthorized - invalid API token | -| 404 | Message not found | -| 500 | Internal server error | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Suggested questions retrieved successfully | [SimpleResultStringListResponse](#simpleresultstringlistresponse) | +| 400 | Suggested questions feature is disabled | | +| 401 | Unauthorized - invalid API token | | +| 404 | Message not found | | +| 500 | Internal server error | | ### /meta @@ -1911,11 +1911,11 @@ Returns the site configuration for the application including theme, icons, and t ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Site configuration retrieved successfully | -| 401 | Unauthorized - invalid API token | -| 403 | Forbidden - site not found or tenant archived | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Site configuration retrieved successfully | [Site](#site) | +| 401 | Unauthorized - invalid API token | | +| 403 | Forbidden - site not found or tenant archived | | ### /text-to-audio @@ -2068,11 +2068,11 @@ Stop a running workflow task ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Task stopped successfully | -| 401 | Unauthorized - invalid API token | -| 404 | Task not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Task stopped successfully | [SimpleResultResponse](#simpleresultresponse) | +| 401 | Unauthorized - invalid API token | | +| 404 | Task not found | | ### /workflows/{workflow_id}/run @@ -2167,6 +2167,16 @@ Returns a list of available models for the specified model type. | embedding_provider_name | string | Embedding provider name | Yes | | score_threshold | number | Score threshold for annotation matching | Yes | +#### AppInfoResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| author_name | string | | Yes | +| description | string | | Yes | +| mode | string | | Yes | +| name | string | | Yes | +| tags | [ string ] | | Yes | + #### ChatRequestPayload | Name | Type | Description | Required | @@ -2386,6 +2396,27 @@ Request payload for bulk downloading documents as a zip archive. | retrieval_model | [RetrievalModel](#retrievalmodel) | | No | | text | string | | No | +#### EndUserDetail + +Full EndUser record for API responses. + +Note: The SQLAlchemy model defines an `is_anonymous` property for Flask-Login semantics +(always False). The database column is exposed as `_is_anonymous`, so this DTO maps +`is_anonymous` from `_is_anonymous` to return the stored value. + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| app_id | string | | No | +| created_at | dateTime | | Yes | +| external_user_id | string | | No | +| id | string | | Yes | +| is_anonymous | boolean | | Yes | +| name | string | | No | +| session_id | string | | Yes | +| tenant_id | string | | Yes | +| type | string | | Yes | +| updated_at | dateTime | | Yes | + #### FeedbackListQuery | Name | Type | Description | Required | @@ -2434,6 +2465,14 @@ Request payload for bulk downloading documents as a zip archive. | action | string | | Yes | | inputs | object | | Yes | +#### IndexInfoResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| api_version | string | | Yes | +| server_version | string | | Yes | +| welcome | string | | Yes | + #### JsonValue | Name | Type | Description | Required | @@ -2525,6 +2564,12 @@ Metadata operation data | reranking_model_name | string | | No | | reranking_provider_name | string | | No | +#### ResultResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| result | string | | Yes | + #### RetrievalMethod | Name | Type | Description | Required | @@ -2610,6 +2655,38 @@ Metadata operation data | session_id | string | | No | | type | string | | Yes | +#### SimpleResultResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| result | string | | Yes | + +#### SimpleResultStringListResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| data | [ string ] | | Yes | +| result | string | | Yes | + +#### Site + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| chat_color_theme | string | | No | +| chat_color_theme_inverted | boolean | | Yes | +| copyright | string | | No | +| custom_disclaimer | string | | No | +| default_language | string | | Yes | +| description | string | | No | +| icon | string | | No | +| icon_background | string | | No | +| icon_type | string | | No | +| icon_url | string | | Yes | +| privacy_policy | string | | No | +| show_workflow_steps | boolean | | Yes | +| title | string | | Yes | +| use_icon_as_answer_icon | boolean | | Yes | + #### TagBindingPayload | Name | Type | Description | Required | @@ -2655,6 +2732,12 @@ Accept the legacy single-tag Service API payload while exposing a normalized tag | text | string | Text to convert to audio | No | | voice | string | Voice to use for TTS | No | +#### UrlResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| url | string | | Yes | + #### WeightKeywordSetting | Name | Type | Description | Required | diff --git a/api/openapi/markdown/web-swagger.md b/api/openapi/markdown/web-swagger.md index f8745d3135..3676169d59 100644 --- a/api/openapi/markdown/web-swagger.md +++ b/api/openapi/markdown/web-swagger.md @@ -78,14 +78,14 @@ Stop a running chat message task. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | -| 400 | Bad Request | -| 401 | Unauthorized | -| 403 | Forbidden | -| 404 | Task Not Found | -| 500 | Internal Server Error | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | +| 400 | Bad Request | | +| 401 | Unauthorized | | +| 403 | Forbidden | | +| 404 | Task Not Found | | +| 500 | Internal Server Error | | ### /completion-messages @@ -126,14 +126,14 @@ Stop a running completion message task. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | -| 400 | Bad Request | -| 401 | Unauthorized | -| 403 | Forbidden | -| 404 | Task Not Found | -| 500 | Internal Server Error | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | +| 400 | Bad Request | | +| 401 | Unauthorized | | +| 403 | Forbidden | | +| 404 | Task Not Found | | +| 500 | Internal Server Error | | ### /conversations @@ -227,14 +227,14 @@ Pin a specific conversation to keep it at the top of the list. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Conversation pinned successfully | -| 400 | Bad Request | -| 401 | Unauthorized | -| 403 | Forbidden | -| 404 | Conversation Not Found or Not a Chat App | -| 500 | Internal Server Error | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Conversation pinned successfully | [ResultResponse](#resultresponse) | +| 400 | Bad Request | | +| 401 | Unauthorized | | +| 403 | Forbidden | | +| 404 | Conversation Not Found or Not a Chat App | | +| 500 | Internal Server Error | | ### /conversations/{c_id}/unpin @@ -251,14 +251,14 @@ Unpin a specific conversation to remove it from the top of the list. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Conversation unpinned successfully | -| 400 | Bad Request | -| 401 | Unauthorized | -| 403 | Forbidden | -| 404 | Conversation Not Found or Not a Chat App | -| 500 | Internal Server Error | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Conversation unpinned successfully | [ResultResponse](#resultresponse) | +| 400 | Bad Request | | +| 401 | Unauthorized | | +| 403 | Forbidden | | +| 404 | Conversation Not Found or Not a Chat App | | +| 500 | Internal Server Error | | ### /email-code-login @@ -275,11 +275,11 @@ Send email verification code for login ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Email code sent successfully | -| 400 | Bad request - invalid email format | -| 404 | Account not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Email code sent successfully | [SimpleResultDataResponse](#simpleresultdataresponse) | +| 400 | Bad request - invalid email format | | +| 404 | Account not found | | ### /email-code-login/validity @@ -296,12 +296,12 @@ Verify email code and complete login ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Email code verified and login successful | -| 400 | Bad request - invalid code or token | -| 401 | Invalid token or expired code | -| 404 | Account not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Email code verified and login successful | [AccessTokenResultResponse](#accesstokenresultresponse) | +| 400 | Bad request - invalid code or token | | +| 401 | Invalid token or expired code | | +| 404 | Account not found | | ### /files/upload @@ -359,12 +359,12 @@ Send password reset email ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Password reset email sent successfully | -| 400 | Bad request - invalid email format | -| 404 | Account not found | -| 429 | Too many requests - rate limit exceeded | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Password reset email sent successfully | [SimpleResultDataResponse](#simpleresultdataresponse) | +| 400 | Bad request - invalid email format | | +| 404 | Account not found | | +| 429 | Too many requests - rate limit exceeded | | ### /forgot-password/resets @@ -381,12 +381,12 @@ Reset user password with verification token ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Password reset successfully | -| 400 | Bad request - invalid parameters or password mismatch | -| 401 | Invalid or expired token | -| 404 | Account not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Password reset successfully | [SimpleResultResponse](#simpleresultresponse) | +| 400 | Bad request - invalid parameters or password mismatch | | +| 401 | Invalid or expired token | | +| 404 | Account not found | | ### /forgot-password/validity @@ -403,11 +403,11 @@ Verify password reset token validity ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Token is valid | -| 400 | Bad request - invalid token format | -| 401 | Invalid or expired token | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Token is valid | [VerificationTokenResponse](#verificationtokenresponse) | +| 400 | Bad request - invalid token format | | +| 401 | Invalid or expired token | | ### /form/human_input/{form_token} @@ -480,13 +480,13 @@ Authenticate user for web application access ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Authentication successful | -| 400 | Bad request - invalid email or password format | -| 401 | Authentication failed - email or password mismatch | -| 403 | Account banned or login disabled | -| 404 | Account not found | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Authentication successful | [AccessTokenResultResponse](#accesstokenresultresponse) | +| 400 | Bad request - invalid email or password format | | +| 401 | Authentication failed - email or password mismatch | | +| 403 | Account banned or login disabled | | +| 404 | Account not found | | ### /login/status @@ -497,10 +497,10 @@ Check login status ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Login status | -| 401 | Login status | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Login status | [LoginStatusResponse](#loginstatusresponse) | +| 401 | Login status | | ### /logout @@ -511,9 +511,9 @@ Logout user from web application ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Logout successful | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Logout successful | [SimpleResultResponse](#simpleresultresponse) | ### /messages @@ -558,14 +558,14 @@ Submit feedback (like/dislike) for a specific message. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Feedback submitted successfully | -| 400 | Bad Request | -| 401 | Unauthorized | -| 403 | Forbidden | -| 404 | Message Not Found | -| 500 | Internal Server Error | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Feedback submitted successfully | [ResultResponse](#resultresponse) | +| 400 | Bad Request | | +| 401 | Unauthorized | | +| 403 | Forbidden | | +| 404 | Message Not Found | | +| 500 | Internal Server Error | | ### /messages/{message_id}/more-like-this @@ -607,14 +607,14 @@ Get suggested follow-up questions after a message (chat apps only). ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | -| 400 | Bad Request - Not a chat app or feature disabled | -| 401 | Unauthorized | -| 403 | Forbidden | -| 404 | Message Not Found or Conversation Not Found | -| 500 | Internal Server Error | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SuggestedQuestionsResponse](#suggestedquestionsresponse) | +| 400 | Bad Request - Not a chat app or feature disabled | | +| 401 | Unauthorized | | +| 403 | Forbidden | | +| 404 | Message Not Found or Conversation Not Found | | +| 500 | Internal Server Error | | ### /meta @@ -791,14 +791,14 @@ Save a specific message for later reference. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Message saved successfully | -| 400 | Bad Request - Not a completion app | -| 401 | Unauthorized | -| 403 | Forbidden | -| 404 | Message Not Found | -| 500 | Internal Server Error | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Message saved successfully | [ResultResponse](#resultresponse) | +| 400 | Bad Request - Not a completion app | | +| 401 | Unauthorized | | +| 403 | Forbidden | | +| 404 | Message Not Found | | +| 500 | Internal Server Error | | ### /saved-messages/{message_id} @@ -874,10 +874,10 @@ Only non-sensitive configuration data should be returned by this endpoint. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | System features retrieved successfully | -| 500 | Internal server error | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | System features retrieved successfully | [SystemFeatureModel](#systemfeaturemodel) | +| 500 | Internal server error | | ### /text-to-audio @@ -922,11 +922,11 @@ Retrieve the access mode for a web application (public or restricted). ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | -| 400 | Bad Request | -| 500 | Internal Server Error | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [AccessModeResponse](#accessmoderesponse) | +| 400 | Bad Request | | +| 500 | Internal Server Error | | ### /webapp/permission @@ -943,12 +943,12 @@ Check if user has permission to access a web application. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | -| 400 | Bad Request | -| 401 | Unauthorized | -| 500 | Internal Server Error | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [BooleanResultResponse](#booleanresultresponse) | +| 400 | Bad Request | | +| 401 | Unauthorized | | +| 500 | Internal Server Error | | ### /workflows/run @@ -997,14 +997,14 @@ Stop a running workflow task. ##### Responses -| Code | Description | -| ---- | ----------- | -| 200 | Success | -| 400 | Bad Request | -| 401 | Unauthorized | -| 403 | Forbidden | -| 404 | Task Not Found | -| 500 | Internal Server Error | +| Code | Description | Schema | +| ---- | ----------- | ------ | +| 200 | Success | [SimpleResultResponse](#simpleresultresponse) | +| 400 | Bad Request | | +| 401 | Unauthorized | | +| 403 | Forbidden | | +| 404 | Task Not Found | | +| 500 | Internal Server Error | | --- ## default @@ -1038,6 +1038,25 @@ Returns Server-Sent Events stream. --- ### Models +#### AccessModeResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| accessMode | string | | Yes | + +#### AccessTokenData + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| access_token | string | | Yes | + +#### AccessTokenResultResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| data | [AccessTokenData](#accesstokendata) | | Yes | +| result | string | | Yes | + #### AppAccessModeQuery | Name | Type | Description | Required | @@ -1045,6 +1064,22 @@ Returns Server-Sent Events stream. | appCode | string | Application code | No | | appId | string | Application ID | No | +#### BooleanResultResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| result | boolean | | Yes | + +#### BrandingModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| application_title | string | | Yes | +| enabled | boolean | | Yes | +| favicon | string | | Yes | +| login_page_logo | string | | Yes | +| workspace_logo | string | | Yes | + #### ChatMessagePayload | Name | Type | Description | Required | @@ -1121,14 +1156,14 @@ Returns Server-Sent Events stream. | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| created_at | integer | | No | -| created_by | string | | No | -| extension | string | | No | +| created_at | integer | | Yes | +| created_by | string | | Yes | +| extension | string | | Yes | | id | string | | Yes | -| mime_type | string | | No | +| mime_type | string | | Yes | | name | string | | Yes | | size | integer | | Yes | -| url | string | | No | +| url | string | | Yes | #### ForgotPasswordCheckPayload @@ -1153,6 +1188,32 @@ Returns Server-Sent Events stream. | email | string | | Yes | | language | string | | No | +#### LicenseLimitationModel + +- enabled: whether this limit is enforced +- size: current usage count +- limit: maximum allowed count; 0 means unlimited + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| enabled | boolean | Whether this limit is currently active | Yes | +| limit | integer | Maximum number of resources allowed; 0 means no limit | Yes | +| size | integer | Number of resources already consumed | Yes | + +#### LicenseModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| expired_at | string | | Yes | +| status | [LicenseStatus](#licensestatus) | | Yes | +| workspaces | [LicenseLimitationModel](#licenselimitationmodel) | | Yes | + +#### LicenseStatus + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| LicenseStatus | string | | | + #### LoginPayload | Name | Type | Description | Required | @@ -1160,6 +1221,13 @@ Returns Server-Sent Events stream. | email | string | | Yes | | password | string | | Yes | +#### LoginStatusResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| app_logged_in | boolean | | Yes | +| logged_in | boolean | | Yes | + #### MessageFeedbackPayload | Name | Type | Description | Required | @@ -1181,6 +1249,25 @@ Returns Server-Sent Events stream. | ---- | ---- | ----------- | -------- | | response_mode | string | Response mode
*Enum:* `"blocking"`, `"streaming"` | Yes | +#### PluginInstallationPermissionModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| plugin_installation_scope | [PluginInstallationScope](#plugininstallationscope) | | Yes | +| restrict_to_marketplace_only | boolean | | Yes | + +#### PluginInstallationScope + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| PluginInstallationScope | string | | | + +#### PluginManagerModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| enabled | boolean | | Yes | + #### RemoteFileInfo | Name | Type | Description | Required | @@ -1194,6 +1281,12 @@ Returns Server-Sent Events stream. | ---- | ---- | ----------- | -------- | | url | string (uri) | Remote file URL | Yes | +#### ResultResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| result | string | | Yes | + #### SavedMessageCreatePayload | Name | Type | Description | Required | @@ -1207,6 +1300,52 @@ Returns Server-Sent Events stream. | last_id | string | | No | | limit | integer | | No | +#### SimpleResultDataResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| data | string | | Yes | +| result | string | | Yes | + +#### SimpleResultResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| result | string | | Yes | + +#### SuggestedQuestionsResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| data | [ string ] | | Yes | + +#### SystemFeatureModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| app_dsl_version | string | | Yes | +| branding | [BrandingModel](#brandingmodel) | | Yes | +| enable_change_email | boolean | | Yes | +| enable_collaboration_mode | boolean | | Yes | +| enable_creators_platform | boolean | | Yes | +| enable_email_code_login | boolean | | Yes | +| enable_email_password_login | boolean | | Yes | +| enable_explore_banner | boolean | | Yes | +| enable_marketplace | boolean | | Yes | +| enable_social_oauth_login | boolean | | Yes | +| enable_trial_app | boolean | | Yes | +| is_allow_create_workspace | boolean | | Yes | +| is_allow_register | boolean | | Yes | +| is_email_setup | boolean | | Yes | +| license | [LicenseModel](#licensemodel) | | Yes | +| max_plugin_package_size | integer | | Yes | +| plugin_installation_permission | [PluginInstallationPermissionModel](#plugininstallationpermissionmodel) | | Yes | +| plugin_manager | [PluginManagerModel](#pluginmanagermodel) | | Yes | +| sso_enforced_for_signin | boolean | | Yes | +| sso_enforced_for_signin_protocol | string | | Yes | +| trial_models | [ string ] | | Yes | +| webapp_auth | [WebAppAuthModel](#webappauthmodel) | | Yes | + #### TextToAudioPayload | Name | Type | Description | Required | @@ -1216,6 +1355,30 @@ Returns Server-Sent Events stream. | text | string | Text to convert to audio | No | | voice | string | Voice to use for TTS | No | +#### VerificationTokenResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| email | string | | Yes | +| is_valid | boolean | | Yes | +| token | string | | Yes | + +#### WebAppAuthModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| allow_email_code_login | boolean | | Yes | +| allow_email_password_login | boolean | | Yes | +| allow_sso | boolean | | Yes | +| enabled | boolean | | Yes | +| sso_config | [WebAppAuthSSOModel](#webappauthssomodel) | | Yes | + +#### WebAppAuthSSOModel + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| protocol | string | | Yes | + #### WorkflowRunPayload | Name | Type | Description | Required | diff --git a/api/services/feature_service.py b/api/services/feature_service.py index 257c4bea9a..461cc8b30c 100644 --- a/api/services/feature_service.py +++ b/api/services/feature_service.py @@ -10,27 +10,31 @@ from services.billing_service import BillingService from services.enterprise.enterprise_service import EnterpriseService -class SubscriptionModel(BaseModel): +class FeatureResponseModel(BaseModel): + model_config = ConfigDict(json_schema_serialization_defaults_required=True, protected_namespaces=()) + + +class SubscriptionModel(FeatureResponseModel): plan: str = CloudPlan.SANDBOX interval: str = "" -class BillingModel(BaseModel): +class BillingModel(FeatureResponseModel): enabled: bool = False subscription: SubscriptionModel = SubscriptionModel() -class EducationModel(BaseModel): +class EducationModel(FeatureResponseModel): enabled: bool = False activated: bool = False -class LimitationModel(BaseModel): +class LimitationModel(FeatureResponseModel): size: int = 0 limit: int = 0 -class LicenseLimitationModel(BaseModel): +class LicenseLimitationModel(FeatureResponseModel): """ - enabled: whether this limit is enforced - size: current usage count @@ -56,7 +60,7 @@ class LicenseLimitationModel(BaseModel): return (self.limit - self.size) >= required -class Quota(BaseModel): +class Quota(FeatureResponseModel): usage: int = 0 limit: int = 0 reset_date: int = -1 @@ -71,13 +75,13 @@ class LicenseStatus(StrEnum): LOST = "lost" -class LicenseModel(BaseModel): +class LicenseModel(FeatureResponseModel): status: LicenseStatus = LicenseStatus.NONE expired_at: str = "" workspaces: LicenseLimitationModel = LicenseLimitationModel(enabled=False, size=0, limit=0) -class BrandingModel(BaseModel): +class BrandingModel(FeatureResponseModel): enabled: bool = False application_title: str = "" login_page_logo: str = "" @@ -85,11 +89,11 @@ class BrandingModel(BaseModel): favicon: str = "" -class WebAppAuthSSOModel(BaseModel): +class WebAppAuthSSOModel(FeatureResponseModel): protocol: str = "" -class WebAppAuthModel(BaseModel): +class WebAppAuthModel(FeatureResponseModel): enabled: bool = False allow_sso: bool = False sso_config: WebAppAuthSSOModel = WebAppAuthSSOModel() @@ -97,7 +101,7 @@ class WebAppAuthModel(BaseModel): allow_email_password_login: bool = False -class KnowledgePipeline(BaseModel): +class KnowledgePipeline(FeatureResponseModel): publish_enabled: bool = False @@ -108,7 +112,7 @@ class PluginInstallationScope(StrEnum): ALL = "all" -class PluginInstallationPermissionModel(BaseModel): +class PluginInstallationPermissionModel(FeatureResponseModel): # Plugin installation scope – possible values: # none: prohibit all plugin installations # official_only: allow only Dify official plugins @@ -121,7 +125,7 @@ class PluginInstallationPermissionModel(BaseModel): restrict_to_marketplace_only: bool = False -class FeatureModel(BaseModel): +class FeatureModel(FeatureResponseModel): billing: BillingModel = BillingModel() education: EducationModel = EducationModel() members: LimitationModel = LimitationModel(size=0, limit=1) @@ -141,23 +145,21 @@ class FeatureModel(BaseModel): api_rate_limit: Quota = Quota(usage=0, limit=5000, reset_date=0) # Controls whether email delivery is allowed for HumanInput nodes. human_input_email_delivery_enabled: bool = False - # pydantic configs - model_config = ConfigDict(protected_namespaces=()) knowledge_pipeline: KnowledgePipeline = KnowledgePipeline() next_credit_reset_date: int = 0 -class KnowledgeRateLimitModel(BaseModel): +class KnowledgeRateLimitModel(FeatureResponseModel): enabled: bool = False limit: int = 10 subscription_plan: str = "" -class PluginManagerModel(BaseModel): +class PluginManagerModel(FeatureResponseModel): enabled: bool = False -class SystemFeatureModel(BaseModel): +class SystemFeatureModel(FeatureResponseModel): app_dsl_version: str = "" sso_enforced_for_signin: bool = False sso_enforced_for_signin_protocol: str = "" diff --git a/packages/contracts/README.md b/packages/contracts/README.md index e9320c921d..57ccc78cce 100644 --- a/packages/contracts/README.md +++ b/packages/contracts/README.md @@ -8,14 +8,14 @@ Snapshot generated from `packages/contracts/generated/api/readiness.json` after running `pnpm -C packages/contracts gen-api-contract-from-openapi`. -Are we OpenAPI ready? **No.** Current generated API contracts are **16.7% ready**. +Are we OpenAPI ready? **No.** Current generated API contracts are **36.3% ready**. | Surface | Ready | Not ready | Total | Ready % | | --------- | ------: | --------: | ------: | --------: | -| console | 96 | 474 | 570 | 16.8% | -| service | 16 | 72 | 88 | 18.2% | -| web | 5 | 36 | 41 | 12.2% | -| **total** | **117** | **582** | **699** | **16.7%** | +| console | 205 | 365 | 570 | 36.0% | +| service | 28 | 60 | 88 | 31.8% | +| web | 21 | 20 | 41 | 51.2% | +| **total** | **254** | **445** | **699** | **36.3%** | Readiness here means the generated contract operation is not marked with: @@ -23,7 +23,7 @@ Readiness here means the generated contract operation is not marked with: Operations marked with that warning should not be migrated to blindly. Prefer fixing backend OpenAPI annotations first so the generated contract has accurate request and response types, then migrate callers endpoint by endpoint. -The current heuristic marks an operation as not ready when a request body or success response that should have a body contains a loose object type, or when an operation has no documented 2xx response. 204, 205, and 304 responses are treated as bodyless when the request type is otherwise accurate. +The current heuristic marks an operation as not ready when a request body or success response that should have a body contains a loose object type, when a mutating controller reads a JSON body that is not documented as a request body, or when an operation has no documented 2xx response. 204, 205, and 304 responses are treated as bodyless when the request type is otherwise accurate. diff --git a/packages/contracts/generated/api/console/account/orpc.gen.ts b/packages/contracts/generated/api/console/account/orpc.gen.ts index 7308733a12..e963f9cd3c 100644 --- a/packages/contracts/generated/api/console/account/orpc.gen.ts +++ b/packages/contracts/generated/api/console/account/orpc.gen.ts @@ -45,16 +45,10 @@ import { /** * Get account avatar url - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get = oc .route({ - deprecated: true, - description: - 'Get account avatar url\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Get account avatar url', inputStructure: 'detailed', method: 'GET', operationId: 'getAccountAvatar', @@ -80,16 +74,8 @@ export const avatar = { post, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post2 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postAccountChangeEmailCheckEmailUnique', @@ -118,16 +104,8 @@ export const reset = { post: post3, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post4 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postAccountChangeEmailValidity', @@ -141,16 +119,8 @@ export const validity = { post: post4, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post5 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postAccountChangeEmail', @@ -167,16 +137,8 @@ export const changeEmail = { validity, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post6 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postAccountDeleteFeedback', @@ -190,16 +152,8 @@ export const feedback = { post: post6, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get2 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getAccountDeleteVerify', @@ -212,16 +166,8 @@ export const verify = { get: get2, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post7 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postAccountDelete', @@ -302,16 +248,8 @@ export const education = { verify: verify2, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post9 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postAccountInit', diff --git a/packages/contracts/generated/api/console/account/types.gen.ts b/packages/contracts/generated/api/console/account/types.gen.ts index 6ccac5f94a..19de4e5c52 100644 --- a/packages/contracts/generated/api/console/account/types.gen.ts +++ b/packages/contracts/generated/api/console/account/types.gen.ts @@ -4,6 +4,10 @@ export type ClientOptions = { baseUrl: `${string}://${string}/console/api` | (string & {}) } +export type AvatarUrlResponse = { + avatar_url: string +} + export type AccountAvatarPayload = { avatar: string } @@ -29,10 +33,19 @@ export type ChangeEmailSendPayload = { token?: string | null } +export type SimpleResultDataResponse = { + data: string + result: string +} + export type CheckEmailUniquePayload = { email: string } +export type SimpleResultResponse = { + result: string +} + export type ChangeEmailResetPayload = { new_email: string token: string @@ -44,6 +57,12 @@ export type ChangeEmailValidityPayload = { token: string } +export type VerificationTokenResponse = { + email: string + is_valid: boolean + token: string +} + export type AccountDeletePayload = { code: string token: string @@ -126,9 +145,7 @@ export type GetAccountAvatarData = { } export type GetAccountAvatarResponses = { - 200: { - [key: string]: unknown - } + 200: AvatarUrlResponse } export type GetAccountAvatarResponse = GetAccountAvatarResponses[keyof GetAccountAvatarResponses] @@ -154,9 +171,7 @@ export type PostAccountChangeEmailData = { } export type PostAccountChangeEmailResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultDataResponse } export type PostAccountChangeEmailResponse @@ -170,9 +185,7 @@ export type PostAccountChangeEmailCheckEmailUniqueData = { } export type PostAccountChangeEmailCheckEmailUniqueResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostAccountChangeEmailCheckEmailUniqueResponse @@ -200,9 +213,7 @@ export type PostAccountChangeEmailValidityData = { } export type PostAccountChangeEmailValidityResponses = { - 200: { - [key: string]: unknown - } + 200: VerificationTokenResponse } export type PostAccountChangeEmailValidityResponse @@ -216,9 +227,7 @@ export type PostAccountDeleteData = { } export type PostAccountDeleteResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostAccountDeleteResponse = PostAccountDeleteResponses[keyof PostAccountDeleteResponses] @@ -231,9 +240,7 @@ export type PostAccountDeleteFeedbackData = { } export type PostAccountDeleteFeedbackResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostAccountDeleteFeedbackResponse @@ -247,9 +254,7 @@ export type GetAccountDeleteVerifyData = { } export type GetAccountDeleteVerifyResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultDataResponse } export type GetAccountDeleteVerifyResponse @@ -325,9 +330,7 @@ export type PostAccountInitData = { } export type PostAccountInitResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostAccountInitResponse = PostAccountInitResponses[keyof PostAccountInitResponses] diff --git a/packages/contracts/generated/api/console/account/zod.gen.ts b/packages/contracts/generated/api/console/account/zod.gen.ts index 18afef9541..fd62c919f3 100644 --- a/packages/contracts/generated/api/console/account/zod.gen.ts +++ b/packages/contracts/generated/api/console/account/zod.gen.ts @@ -2,6 +2,13 @@ import * as z from 'zod' +/** + * AvatarUrlResponse + */ +export const zAvatarUrlResponse = z.object({ + avatar_url: z.string(), +}) + /** * AccountAvatarPayload */ @@ -36,6 +43,14 @@ export const zChangeEmailSendPayload = z.object({ token: z.string().nullish(), }) +/** + * SimpleResultDataResponse + */ +export const zSimpleResultDataResponse = z.object({ + data: z.string(), + result: z.string(), +}) + /** * CheckEmailUniquePayload */ @@ -43,6 +58,13 @@ export const zCheckEmailUniquePayload = z.object({ email: z.string(), }) +/** + * SimpleResultResponse + */ +export const zSimpleResultResponse = z.object({ + result: z.string(), +}) + /** * ChangeEmailResetPayload */ @@ -60,6 +82,15 @@ export const zChangeEmailValidityPayload = z.object({ token: z.string(), }) +/** + * VerificationTokenResponse + */ +export const zVerificationTokenResponse = z.object({ + email: z.string(), + is_valid: z.boolean(), + token: z.string(), +}) + /** * AccountDeletePayload */ @@ -181,7 +212,7 @@ export const zGetAccountAvatarQuery = z.object({ /** * Success */ -export const zGetAccountAvatarResponse = z.record(z.string(), z.unknown()) +export const zGetAccountAvatarResponse = zAvatarUrlResponse export const zPostAccountAvatarBody = zAccountAvatarPayload @@ -195,14 +226,14 @@ export const zPostAccountChangeEmailBody = zChangeEmailSendPayload /** * Success */ -export const zPostAccountChangeEmailResponse = z.record(z.string(), z.unknown()) +export const zPostAccountChangeEmailResponse = zSimpleResultDataResponse export const zPostAccountChangeEmailCheckEmailUniqueBody = zCheckEmailUniquePayload /** * Success */ -export const zPostAccountChangeEmailCheckEmailUniqueResponse = z.record(z.string(), z.unknown()) +export const zPostAccountChangeEmailCheckEmailUniqueResponse = zSimpleResultResponse export const zPostAccountChangeEmailResetBody = zChangeEmailResetPayload @@ -216,26 +247,26 @@ export const zPostAccountChangeEmailValidityBody = zChangeEmailValidityPayload /** * Success */ -export const zPostAccountChangeEmailValidityResponse = z.record(z.string(), z.unknown()) +export const zPostAccountChangeEmailValidityResponse = zVerificationTokenResponse export const zPostAccountDeleteBody = zAccountDeletePayload /** * Success */ -export const zPostAccountDeleteResponse = z.record(z.string(), z.unknown()) +export const zPostAccountDeleteResponse = zSimpleResultResponse export const zPostAccountDeleteFeedbackBody = zAccountDeletionFeedbackPayload /** * Success */ -export const zPostAccountDeleteFeedbackResponse = z.record(z.string(), z.unknown()) +export const zPostAccountDeleteFeedbackResponse = zSimpleResultResponse /** * Success */ -export const zGetAccountDeleteVerifyResponse = z.record(z.string(), z.unknown()) +export const zGetAccountDeleteVerifyResponse = zSimpleResultDataResponse /** * Success @@ -270,7 +301,7 @@ export const zPostAccountInitBody = zAccountInitPayload /** * Success */ -export const zPostAccountInitResponse = z.record(z.string(), z.unknown()) +export const zPostAccountInitResponse = zSimpleResultResponse /** * Success diff --git a/packages/contracts/generated/api/console/activate/orpc.gen.ts b/packages/contracts/generated/api/console/activate/orpc.gen.ts index 3e74dd841b..870f45bd2e 100644 --- a/packages/contracts/generated/api/console/activate/orpc.gen.ts +++ b/packages/contracts/generated/api/console/activate/orpc.gen.ts @@ -12,16 +12,10 @@ import { /** * Check if activation token is valid - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get = oc .route({ - deprecated: true, - description: - 'Check if activation token is valid\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Check if activation token is valid', inputStructure: 'detailed', method: 'GET', operationId: 'getActivateCheck', diff --git a/packages/contracts/generated/api/console/activate/types.gen.ts b/packages/contracts/generated/api/console/activate/types.gen.ts index 97a16c6861..ae12c3e461 100644 --- a/packages/contracts/generated/api/console/activate/types.gen.ts +++ b/packages/contracts/generated/api/console/activate/types.gen.ts @@ -18,12 +18,16 @@ export type ActivationResponse = { } export type ActivationCheckResponse = { - data?: { - [key: string]: unknown - } | null + data?: ActivationCheckData is_valid: boolean } +export type ActivationCheckData = { + email: string | null + workspace_id: string | null + workspace_name: string | null +} + export type PostActivateData = { body: ActivatePayload path?: never diff --git a/packages/contracts/generated/api/console/activate/zod.gen.ts b/packages/contracts/generated/api/console/activate/zod.gen.ts index 30897b6666..573c2d5f4c 100644 --- a/packages/contracts/generated/api/console/activate/zod.gen.ts +++ b/packages/contracts/generated/api/console/activate/zod.gen.ts @@ -21,11 +21,20 @@ export const zActivationResponse = z.object({ result: z.string(), }) +/** + * ActivationCheckData + */ +export const zActivationCheckData = z.object({ + email: z.string().nullable(), + workspace_id: z.string().nullable(), + workspace_name: z.string().nullable(), +}) + /** * ActivationCheckResponse */ export const zActivationCheckResponse = z.object({ - data: z.record(z.string(), z.unknown()).nullish(), + data: zActivationCheckData.optional(), is_valid: z.boolean(), }) diff --git a/packages/contracts/generated/api/console/api-key-auth/orpc.gen.ts b/packages/contracts/generated/api/console/api-key-auth/orpc.gen.ts index 48f5f69624..38714ef745 100644 --- a/packages/contracts/generated/api/console/api-key-auth/orpc.gen.ts +++ b/packages/contracts/generated/api/console/api-key-auth/orpc.gen.ts @@ -34,20 +34,13 @@ export const binding = { post, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete_ = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteApiKeyAuthDataSourceByBindingId', path: '/api-key-auth/data-source/{binding_id}', + successStatus: 204, tags: ['console'], }) .input(z.object({ params: zDeleteApiKeyAuthDataSourceByBindingIdPath })) @@ -57,16 +50,8 @@ export const byBindingId = { delete: delete_, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getApiKeyAuthDataSource', diff --git a/packages/contracts/generated/api/console/api-key-auth/types.gen.ts b/packages/contracts/generated/api/console/api-key-auth/types.gen.ts index 970b3a44e9..a519481a73 100644 --- a/packages/contracts/generated/api/console/api-key-auth/types.gen.ts +++ b/packages/contracts/generated/api/console/api-key-auth/types.gen.ts @@ -4,6 +4,10 @@ export type ClientOptions = { baseUrl: `${string}://${string}/console/api` | (string & {}) } +export type ApiKeyAuthDataSourceListResponse = { + sources: Array +} + export type ApiKeyAuthBindingPayload = { category: string credentials: { @@ -12,6 +16,15 @@ export type ApiKeyAuthBindingPayload = { provider: string } +export type ApiKeyAuthDataSourceItem = { + category: string + created_at: number + disabled: boolean + id: string + provider: string + updated_at: number +} + export type GetApiKeyAuthDataSourceData = { body?: never path?: never @@ -20,9 +33,7 @@ export type GetApiKeyAuthDataSourceData = { } export type GetApiKeyAuthDataSourceResponses = { - 200: { - [key: string]: unknown - } + 200: ApiKeyAuthDataSourceListResponse } export type GetApiKeyAuthDataSourceResponse @@ -54,8 +65,8 @@ export type DeleteApiKeyAuthDataSourceByBindingIdData = { } export type DeleteApiKeyAuthDataSourceByBindingIdResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } diff --git a/packages/contracts/generated/api/console/api-key-auth/zod.gen.ts b/packages/contracts/generated/api/console/api-key-auth/zod.gen.ts index 6c7f5ad19b..65c3c92f5c 100644 --- a/packages/contracts/generated/api/console/api-key-auth/zod.gen.ts +++ b/packages/contracts/generated/api/console/api-key-auth/zod.gen.ts @@ -11,10 +11,29 @@ export const zApiKeyAuthBindingPayload = z.object({ provider: z.string(), }) +/** + * ApiKeyAuthDataSourceItem + */ +export const zApiKeyAuthDataSourceItem = z.object({ + category: z.string(), + created_at: z.int(), + disabled: z.boolean(), + id: z.string(), + provider: z.string(), + updated_at: z.int(), +}) + +/** + * ApiKeyAuthDataSourceListResponse + */ +export const zApiKeyAuthDataSourceListResponse = z.object({ + sources: z.array(zApiKeyAuthDataSourceItem), +}) + /** * Success */ -export const zGetApiKeyAuthDataSourceResponse = z.record(z.string(), z.unknown()) +export const zGetApiKeyAuthDataSourceResponse = zApiKeyAuthDataSourceListResponse export const zPostApiKeyAuthDataSourceBindingBody = zApiKeyAuthBindingPayload @@ -28,6 +47,6 @@ export const zDeleteApiKeyAuthDataSourceByBindingIdPath = z.object({ }) /** - * Success + * Binding deleted successfully */ -export const zDeleteApiKeyAuthDataSourceByBindingIdResponse = z.record(z.string(), z.unknown()) +export const zDeleteApiKeyAuthDataSourceByBindingIdResponse = z.record(z.string(), z.never()) diff --git a/packages/contracts/generated/api/console/apps/orpc.gen.ts b/packages/contracts/generated/api/console/apps/orpc.gen.ts index a1a0faaefd..3e8bd4a6bb 100644 --- a/packages/contracts/generated/api/console/apps/orpc.gen.ts +++ b/packages/contracts/generated/api/console/apps/orpc.gen.ts @@ -1262,16 +1262,10 @@ export const byMessageId = { /** * Stop a running chat message generation - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post16 = oc .route({ - deprecated: true, - description: - 'Stop a running chat message generation\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Stop a running chat message generation', inputStructure: 'detailed', method: 'POST', operationId: 'postAppsByAppIdChatMessagesByTaskIdStop', @@ -1387,16 +1381,10 @@ export const completionConversations = { /** * Stop a running completion message generation - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post17 = oc .route({ - deprecated: true, - description: - 'Stop a running completion message generation\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Stop a running completion message generation', inputStructure: 'detailed', method: 'POST', operationId: 'postAppsByAppIdCompletionMessagesByTaskIdStop', @@ -1475,16 +1463,11 @@ export const conversationVariables = { * Convert application to workflow mode * Convert expert mode of chatbot app to workflow mode * Convert Completion App to Workflow App - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post19 = oc .route({ - deprecated: true, description: - 'Convert application to workflow mode\nConvert expert mode of chatbot app to workflow mode\nConvert Completion App to Workflow App\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + 'Convert application to workflow mode\nConvert expert mode of chatbot app to workflow mode\nConvert Completion App to Workflow App', inputStructure: 'detailed', method: 'POST', operationId: 'postAppsByAppIdConvertToWorkflow', @@ -1589,16 +1572,10 @@ export const export3 = { /** * Create or update message feedback (like/dislike) - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post21 = oc .route({ - deprecated: true, - description: - 'Create or update message feedback (like/dislike)\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Create or update message feedback (like/dislike)', inputStructure: 'detailed', method: 'POST', operationId: 'postAppsByAppIdFeedbacks', @@ -1724,16 +1701,9 @@ export const name = { /** * Publish app to Creators Platform - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post25 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postAppsByAppIdPublishToCreatorsPlatform', @@ -2217,16 +2187,10 @@ export const get32 = oc /** * Update app tracing configuration - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post31 = oc .route({ - deprecated: true, - description: - 'Update app tracing configuration\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Update app tracing configuration', inputStructure: 'detailed', method: 'POST', operationId: 'postAppsByAppIdTrace', @@ -2476,16 +2440,10 @@ export const count3 = { * Stop workflow task * * Stop running workflow task - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post34 = oc .route({ - deprecated: true, - description: - 'Stop running workflow task\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Stop running workflow task', inputStructure: 'detailed', method: 'POST', operationId: 'postAppsByAppIdWorkflowRunsTasksByTaskIdStop', diff --git a/packages/contracts/generated/api/console/apps/types.gen.ts b/packages/contracts/generated/api/console/apps/types.gen.ts index a4e3c97a0a..69435e357e 100644 --- a/packages/contracts/generated/api/console/apps/types.gen.ts +++ b/packages/contracts/generated/api/console/apps/types.gen.ts @@ -262,6 +262,10 @@ export type SuggestedQuestionsResponse = { data: Array } +export type SimpleResultResponse = { + result: string +} + export type ConversationPagination = { has_next: boolean items: Array @@ -309,6 +313,10 @@ export type ConvertToWorkflowPayload = { name?: string | null } +export type NewAppResponse = { + new_app_id: string +} + export type CopyAppPayload = { description?: string | null icon?: string | null @@ -397,6 +405,10 @@ export type AppNamePayload = { name: string } +export type RedirectUrlResponse = { + redirect_url: string +} + export type AppMcpServerResponse = { created_at?: number | null description: string @@ -2420,9 +2432,7 @@ export type PostAppsByAppIdChatMessagesByTaskIdStopData = { } export type PostAppsByAppIdChatMessagesByTaskIdStopResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostAppsByAppIdChatMessagesByTaskIdStopResponse @@ -2561,9 +2571,7 @@ export type PostAppsByAppIdCompletionMessagesByTaskIdStopData = { } export type PostAppsByAppIdCompletionMessagesByTaskIdStopResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostAppsByAppIdCompletionMessagesByTaskIdStopResponse @@ -2609,9 +2617,7 @@ export type PostAppsByAppIdConvertToWorkflowError = PostAppsByAppIdConvertToWorkflowErrors[keyof PostAppsByAppIdConvertToWorkflowErrors] export type PostAppsByAppIdConvertToWorkflowResponses = { - 200: { - [key: string]: unknown - } + 200: NewAppResponse } export type PostAppsByAppIdConvertToWorkflowResponse @@ -2690,9 +2696,7 @@ export type PostAppsByAppIdFeedbacksError = PostAppsByAppIdFeedbacksErrors[keyof PostAppsByAppIdFeedbacksErrors] export type PostAppsByAppIdFeedbacksResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostAppsByAppIdFeedbacksResponse @@ -2843,9 +2847,7 @@ export type PostAppsByAppIdPublishToCreatorsPlatformData = { } export type PostAppsByAppIdPublishToCreatorsPlatformResponses = { - 200: { - [key: string]: unknown - } + 200: RedirectUrlResponse } export type PostAppsByAppIdPublishToCreatorsPlatformResponse @@ -3259,9 +3261,7 @@ export type PostAppsByAppIdTraceErrors = { export type PostAppsByAppIdTraceError = PostAppsByAppIdTraceErrors[keyof PostAppsByAppIdTraceErrors] export type PostAppsByAppIdTraceResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostAppsByAppIdTraceResponse @@ -3525,9 +3525,7 @@ export type PostAppsByAppIdWorkflowRunsTasksByTaskIdStopError = PostAppsByAppIdWorkflowRunsTasksByTaskIdStopErrors[keyof PostAppsByAppIdWorkflowRunsTasksByTaskIdStopErrors] export type PostAppsByAppIdWorkflowRunsTasksByTaskIdStopResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostAppsByAppIdWorkflowRunsTasksByTaskIdStopResponse @@ -4079,9 +4077,7 @@ export type PostAppsByAppIdWorkflowsDraftFeaturesData = { } export type PostAppsByAppIdWorkflowsDraftFeaturesResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostAppsByAppIdWorkflowsDraftFeaturesResponse diff --git a/packages/contracts/generated/api/console/apps/zod.gen.ts b/packages/contracts/generated/api/console/apps/zod.gen.ts index 1f8ea393c7..152296eec1 100644 --- a/packages/contracts/generated/api/console/apps/zod.gen.ts +++ b/packages/contracts/generated/api/console/apps/zod.gen.ts @@ -160,6 +160,13 @@ export const zSuggestedQuestionsResponse = z.object({ data: z.array(z.string()), }) +/** + * SimpleResultResponse + */ +export const zSimpleResultResponse = z.object({ + result: z.string(), +}) + /** * CompletionMessagePayload */ @@ -182,6 +189,13 @@ export const zConvertToWorkflowPayload = z.object({ name: z.string().nullish(), }) +/** + * NewAppResponse + */ +export const zNewAppResponse = z.object({ + new_app_id: z.string(), +}) + /** * AppExportResponse */ @@ -223,6 +237,13 @@ export const zAppNamePayload = z.object({ name: z.string().min(1), }) +/** + * RedirectUrlResponse + */ +export const zRedirectUrlResponse = z.object({ + redirect_url: z.string(), +}) + /** * MCPServerCreatePayload */ @@ -2327,7 +2348,7 @@ export const zPostAppsByAppIdChatMessagesByTaskIdStopPath = z.object({ /** * Task stopped successfully */ -export const zPostAppsByAppIdChatMessagesByTaskIdStopResponse = z.record(z.string(), z.unknown()) +export const zPostAppsByAppIdChatMessagesByTaskIdStopResponse = zSimpleResultResponse export const zGetAppsByAppIdCompletionConversationsPath = z.object({ app_id: z.string(), @@ -2390,10 +2411,7 @@ export const zPostAppsByAppIdCompletionMessagesByTaskIdStopPath = z.object({ /** * Task stopped successfully */ -export const zPostAppsByAppIdCompletionMessagesByTaskIdStopResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostAppsByAppIdCompletionMessagesByTaskIdStopResponse = zSimpleResultResponse export const zGetAppsByAppIdConversationVariablesPath = z.object({ app_id: z.string(), @@ -2417,7 +2435,7 @@ export const zPostAppsByAppIdConvertToWorkflowPath = z.object({ /** * Application converted to workflow successfully */ -export const zPostAppsByAppIdConvertToWorkflowResponse = z.record(z.string(), z.unknown()) +export const zPostAppsByAppIdConvertToWorkflowResponse = zNewAppResponse export const zPostAppsByAppIdCopyBody = zCopyAppPayload @@ -2453,7 +2471,7 @@ export const zPostAppsByAppIdFeedbacksPath = z.object({ /** * Feedback updated successfully */ -export const zPostAppsByAppIdFeedbacksResponse = z.record(z.string(), z.unknown()) +export const zPostAppsByAppIdFeedbacksResponse = zSimpleResultResponse export const zGetAppsByAppIdFeedbacksExportPath = z.object({ app_id: z.string(), @@ -2523,7 +2541,7 @@ export const zPostAppsByAppIdPublishToCreatorsPlatformPath = z.object({ /** * Success */ -export const zPostAppsByAppIdPublishToCreatorsPlatformResponse = z.record(z.string(), z.unknown()) +export const zPostAppsByAppIdPublishToCreatorsPlatformResponse = zRedirectUrlResponse export const zGetAppsByAppIdServerPath = z.object({ app_id: z.string(), @@ -2757,7 +2775,7 @@ export const zPostAppsByAppIdTracePath = z.object({ /** * Trace configuration updated successfully */ -export const zPostAppsByAppIdTraceResponse = z.record(z.string(), z.unknown()) +export const zPostAppsByAppIdTraceResponse = zSimpleResultResponse export const zDeleteAppsByAppIdTraceConfigBody = zTraceProviderQuery @@ -2906,10 +2924,7 @@ export const zPostAppsByAppIdWorkflowRunsTasksByTaskIdStopPath = z.object({ /** * Task stopped successfully */ -export const zPostAppsByAppIdWorkflowRunsTasksByTaskIdStopResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostAppsByAppIdWorkflowRunsTasksByTaskIdStopResponse = zSimpleResultResponse export const zGetAppsByAppIdWorkflowRunsByRunIdPath = z.object({ app_id: z.string(), @@ -3246,7 +3261,7 @@ export const zPostAppsByAppIdWorkflowsDraftFeaturesPath = z.object({ /** * Workflow features updated successfully */ -export const zPostAppsByAppIdWorkflowsDraftFeaturesResponse = z.record(z.string(), z.unknown()) +export const zPostAppsByAppIdWorkflowsDraftFeaturesResponse = zSimpleResultResponse export const zPostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdDeliveryTestBody = zHumanInputDeliveryTestPayload diff --git a/packages/contracts/generated/api/console/auth/orpc.gen.ts b/packages/contracts/generated/api/console/auth/orpc.gen.ts index a17a733d82..bc2f9fc410 100644 --- a/packages/contracts/generated/api/console/auth/orpc.gen.ts +++ b/packages/contracts/generated/api/console/auth/orpc.gen.ts @@ -74,16 +74,8 @@ export const list = { get: get2, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete_ = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteAuthPluginDatasourceByProviderIdCustomClient', @@ -122,16 +114,8 @@ export const customClient = { post, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post2 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postAuthPluginDatasourceByProviderIdDefault', @@ -150,16 +134,8 @@ export const default_ = { post: post2, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post3 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postAuthPluginDatasourceByProviderIdDelete', @@ -206,16 +182,8 @@ export const update = { post: post4, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post5 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postAuthPluginDatasourceByProviderIdUpdateName', diff --git a/packages/contracts/generated/api/console/auth/types.gen.ts b/packages/contracts/generated/api/console/auth/types.gen.ts index 1a974f626b..73b5064fa9 100644 --- a/packages/contracts/generated/api/console/auth/types.gen.ts +++ b/packages/contracts/generated/api/console/auth/types.gen.ts @@ -11,6 +11,10 @@ export type DatasourceCredentialPayload = { name?: string | null } +export type SimpleResultResponse = { + result: string +} + export type DatasourceCustomClientPayload = { client_params?: { [key: string]: unknown @@ -117,9 +121,7 @@ export type DeleteAuthPluginDatasourceByProviderIdCustomClientData = { } export type DeleteAuthPluginDatasourceByProviderIdCustomClientResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type DeleteAuthPluginDatasourceByProviderIdCustomClientResponse @@ -153,9 +155,7 @@ export type PostAuthPluginDatasourceByProviderIdDefaultData = { } export type PostAuthPluginDatasourceByProviderIdDefaultResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostAuthPluginDatasourceByProviderIdDefaultResponse @@ -171,9 +171,7 @@ export type PostAuthPluginDatasourceByProviderIdDeleteData = { } export type PostAuthPluginDatasourceByProviderIdDeleteResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostAuthPluginDatasourceByProviderIdDeleteResponse @@ -207,9 +205,7 @@ export type PostAuthPluginDatasourceByProviderIdUpdateNameData = { } export type PostAuthPluginDatasourceByProviderIdUpdateNameResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostAuthPluginDatasourceByProviderIdUpdateNameResponse diff --git a/packages/contracts/generated/api/console/auth/zod.gen.ts b/packages/contracts/generated/api/console/auth/zod.gen.ts index 3d183e09cd..8248a9d858 100644 --- a/packages/contracts/generated/api/console/auth/zod.gen.ts +++ b/packages/contracts/generated/api/console/auth/zod.gen.ts @@ -10,6 +10,13 @@ export const zDatasourceCredentialPayload = z.object({ name: z.string().max(100).nullish(), }) +/** + * SimpleResultResponse + */ +export const zSimpleResultResponse = z.object({ + result: z.string(), +}) + /** * DatasourceCustomClientPayload */ @@ -86,10 +93,7 @@ export const zDeleteAuthPluginDatasourceByProviderIdCustomClientPath = z.object( /** * Success */ -export const zDeleteAuthPluginDatasourceByProviderIdCustomClientResponse = z.record( - z.string(), - z.unknown(), -) +export const zDeleteAuthPluginDatasourceByProviderIdCustomClientResponse = zSimpleResultResponse export const zPostAuthPluginDatasourceByProviderIdCustomClientBody = zDatasourceCustomClientPayload @@ -114,10 +118,7 @@ export const zPostAuthPluginDatasourceByProviderIdDefaultPath = z.object({ /** * Success */ -export const zPostAuthPluginDatasourceByProviderIdDefaultResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostAuthPluginDatasourceByProviderIdDefaultResponse = zSimpleResultResponse export const zPostAuthPluginDatasourceByProviderIdDeleteBody = zDatasourceCredentialDeletePayload @@ -128,7 +129,7 @@ export const zPostAuthPluginDatasourceByProviderIdDeletePath = z.object({ /** * Success */ -export const zPostAuthPluginDatasourceByProviderIdDeleteResponse = z.record(z.string(), z.unknown()) +export const zPostAuthPluginDatasourceByProviderIdDeleteResponse = zSimpleResultResponse export const zPostAuthPluginDatasourceByProviderIdUpdateBody = zDatasourceCredentialUpdatePayload @@ -150,7 +151,4 @@ export const zPostAuthPluginDatasourceByProviderIdUpdateNamePath = z.object({ /** * Success */ -export const zPostAuthPluginDatasourceByProviderIdUpdateNameResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostAuthPluginDatasourceByProviderIdUpdateNameResponse = zSimpleResultResponse diff --git a/packages/contracts/generated/api/console/data-source/orpc.gen.ts b/packages/contracts/generated/api/console/data-source/orpc.gen.ts index dceb32433d..51c86e86bb 100644 --- a/packages/contracts/generated/api/console/data-source/orpc.gen.ts +++ b/packages/contracts/generated/api/console/data-source/orpc.gen.ts @@ -31,16 +31,8 @@ export const get = oc .input(z.object({ params: zGetDataSourceIntegratesByBindingIdByActionPath })) .output(zGetDataSourceIntegratesByBindingIdByActionResponse) -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const patch = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'PATCH', operationId: 'patchDataSourceIntegratesByBindingIdByAction', @@ -77,16 +69,8 @@ export const get2 = oc }) .output(zGetDataSourceIntegratesResponse) -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const patch2 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'PATCH', operationId: 'patchDataSourceIntegrates', diff --git a/packages/contracts/generated/api/console/data-source/types.gen.ts b/packages/contracts/generated/api/console/data-source/types.gen.ts index b8e57e212a..eb68f30bd5 100644 --- a/packages/contracts/generated/api/console/data-source/types.gen.ts +++ b/packages/contracts/generated/api/console/data-source/types.gen.ts @@ -4,6 +4,10 @@ export type ClientOptions = { baseUrl: `${string}://${string}/console/api` | (string & {}) } +export type SimpleResultResponse = { + result: string +} + export type GetDataSourceIntegratesData = { body?: never path?: never @@ -28,9 +32,7 @@ export type PatchDataSourceIntegratesData = { } export type PatchDataSourceIntegratesResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PatchDataSourceIntegratesResponse @@ -66,9 +68,7 @@ export type PatchDataSourceIntegratesByBindingIdByActionData = { } export type PatchDataSourceIntegratesByBindingIdByActionResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PatchDataSourceIntegratesByBindingIdByActionResponse diff --git a/packages/contracts/generated/api/console/data-source/zod.gen.ts b/packages/contracts/generated/api/console/data-source/zod.gen.ts index b98caa256c..f1bd5c652f 100644 --- a/packages/contracts/generated/api/console/data-source/zod.gen.ts +++ b/packages/contracts/generated/api/console/data-source/zod.gen.ts @@ -2,6 +2,13 @@ import * as z from 'zod' +/** + * SimpleResultResponse + */ +export const zSimpleResultResponse = z.object({ + result: z.string(), +}) + /** * Success */ @@ -10,7 +17,7 @@ export const zGetDataSourceIntegratesResponse = z.record(z.string(), z.unknown() /** * Success */ -export const zPatchDataSourceIntegratesResponse = z.record(z.string(), z.unknown()) +export const zPatchDataSourceIntegratesResponse = zSimpleResultResponse export const zGetDataSourceIntegratesByBindingIdByActionPath = z.object({ action: z.string(), @@ -30,7 +37,4 @@ export const zPatchDataSourceIntegratesByBindingIdByActionPath = z.object({ /** * Success */ -export const zPatchDataSourceIntegratesByBindingIdByActionResponse = z.record( - z.string(), - z.unknown(), -) +export const zPatchDataSourceIntegratesByBindingIdByActionResponse = zSimpleResultResponse diff --git a/packages/contracts/generated/api/console/datasets/orpc.gen.ts b/packages/contracts/generated/api/console/datasets/orpc.gen.ts index 6a2bcb7720..4623d369c8 100644 --- a/packages/contracts/generated/api/console/datasets/orpc.gen.ts +++ b/packages/contracts/generated/api/console/datasets/orpc.gen.ts @@ -187,16 +187,10 @@ import { /** * Get dataset API base information - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get = oc .route({ - deprecated: true, - description: - 'Get dataset API base information\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Get dataset API base information', inputStructure: 'detailed', method: 'GET', operationId: 'getDatasetsApiBaseInfo', @@ -259,16 +253,8 @@ export const apiKeys = { byApiKeyId, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get3 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getDatasetsBatchImportStatusByJobId', @@ -278,16 +264,8 @@ export const get3 = oc .input(z.object({ params: zGetDatasetsBatchImportStatusByJobIdPath })) .output(zGetDatasetsBatchImportStatusByJobIdResponse) -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post2 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postDatasetsBatchImportStatusByJobId', @@ -339,16 +317,10 @@ export const external = { /** * Check if external knowledge API is being used - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get4 = oc .route({ - deprecated: true, - description: - 'Check if external knowledge API is being used\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Check if external knowledge API is being used', inputStructure: 'detailed', method: 'GET', operationId: 'getDatasetsExternalKnowledgeApiByExternalKnowledgeApiIdUseCheck', @@ -362,20 +334,13 @@ export const useCheck = { get: get4, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete2 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteDatasetsExternalKnowledgeApiByExternalKnowledgeApiId', path: '/datasets/external-knowledge-api/{external_knowledge_api_id}', + successStatus: 204, tags: ['console'], }) .input(z.object({ params: zDeleteDatasetsExternalKnowledgeApiByExternalKnowledgeApiIdPath })) @@ -556,16 +521,8 @@ export const metadata = { builtIn, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get8 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getDatasetsNotionIndexingEstimate', @@ -673,16 +630,8 @@ export const retrievalSetting = { byVectorType, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post8 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postDatasetsByDatasetIdApiKeysByStatus', @@ -820,16 +769,11 @@ export const downloadZip = { * This endpoint checks if the dataset configuration supports summary generation * (indexing_technique must be 'high_quality' and summary_index_setting.enable must be true), * then asynchronously generates summary indexes for the provided documents. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post10 = oc .route({ - deprecated: true, description: - 'Generate summary index for documents\nThis endpoint checks if the dataset configuration supports summary generation\n(indexing_technique must be \'high_quality\' and summary_index_setting.enable must be true),\nthen asynchronously generates summary indexes for the provided documents.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + 'Generate summary index for documents\nThis endpoint checks if the dataset configuration supports summary generation\n(indexing_technique must be \'high_quality\' and summary_index_setting.enable must be true),\nthen asynchronously generates summary indexes for the provided documents.', inputStructure: 'detailed', method: 'POST', operationId: 'postDatasetsByDatasetIdDocumentsGenerateSummary', @@ -849,16 +793,8 @@ export const generateSummary = { post: post10, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post11 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postDatasetsByDatasetIdDocumentsMetadata', @@ -877,16 +813,8 @@ export const metadata2 = { post: post11, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const patch2 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'PATCH', operationId: 'patchDatasetsByDatasetIdDocumentsStatusByActionBatch', @@ -910,16 +838,10 @@ export const status = { /** * Get a signed download URL for a dataset document's original uploaded file - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get15 = oc .route({ - deprecated: true, - description: - 'Get a signed download URL for a dataset document\'s original uploaded file\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Get a signed download URL for a dataset document\'s original uploaded file', inputStructure: 'detailed', method: 'GET', operationId: 'getDatasetsByDatasetIdDocumentsByDocumentIdDownload', @@ -985,16 +907,10 @@ export const indexingStatus2 = { /** * Update document metadata - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const put = oc .route({ - deprecated: true, - description: - 'Update document metadata\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Update document metadata', inputStructure: 'detailed', method: 'PUT', operationId: 'putDatasetsByDatasetIdDocumentsByDocumentIdMetadata', @@ -1013,16 +929,8 @@ export const metadata3 = { put, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get18 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getDatasetsByDatasetIdDocumentsByDocumentIdNotionSync', @@ -1065,20 +973,14 @@ export const pipelineExecutionLog = { /** * pause document - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const patch3 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'PATCH', operationId: 'patchDatasetsByDatasetIdDocumentsByDocumentIdProcessingPause', path: '/datasets/{dataset_id}/documents/{document_id}/processing/pause', + successStatus: 204, summary: 'pause document', tags: ['console'], }) @@ -1091,20 +993,14 @@ export const pause = { /** * recover document - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const patch4 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'PATCH', operationId: 'patchDatasetsByDatasetIdDocumentsByDocumentIdProcessingResume', path: '/datasets/{dataset_id}/documents/{document_id}/processing/resume', + successStatus: 204, summary: 'recover document', tags: ['console'], }) @@ -1117,16 +1013,10 @@ export const resume = { /** * Update document processing status (pause/resume) - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const patch5 = oc .route({ - deprecated: true, - description: - 'Update document processing status (pause/resume)\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Update document processing status (pause/resume)', inputStructure: 'detailed', method: 'PATCH', operationId: 'patchDatasetsByDatasetIdDocumentsByDocumentIdProcessingByAction', @@ -1166,16 +1056,8 @@ export const rename = { post: post12, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const patch6 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'PATCH', operationId: 'patchDatasetsByDatasetIdDocumentsByDocumentIdSegmentByAction', @@ -1218,16 +1100,8 @@ export const segment = { byAction: byAction3, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get20 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImport', @@ -1237,16 +1111,8 @@ export const get20 = oc .input(z.object({ params: zGetDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImportPath })) .output(zGetDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImportResponse) -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post14 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImport', @@ -1266,21 +1132,14 @@ export const batchImport = { post: post14, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete3 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBySegmentIdChildChunksByChildChunkId', path: '/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}', + successStatus: 204, tags: ['console'], }) .input( @@ -1403,20 +1262,13 @@ export const childChunks = { byChildChunkId, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete4 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBySegmentId', path: '/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}', + successStatus: 204, tags: ['console'], }) .input( @@ -1454,20 +1306,13 @@ export const bySegmentId = { childChunks, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete5 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteDatasetsByDatasetIdDocumentsByDocumentIdSegments', path: '/datasets/{dataset_id}/documents/{document_id}/segments', + successStatus: 204, tags: ['console'], }) .input(z.object({ params: zDeleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsPath })) @@ -1537,16 +1382,9 @@ export const summaryStatus = { /** * sync website document - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get24 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getDatasetsByDatasetIdDocumentsByDocumentIdWebsiteSync', @@ -1561,20 +1399,13 @@ export const websiteSync = { get: get24, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete6 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteDatasetsByDatasetIdDocumentsByDocumentId', path: '/datasets/{dataset_id}/documents/{document_id}', + successStatus: 204, tags: ['console'], }) .input(z.object({ params: zDeleteDatasetsByDatasetIdDocumentsByDocumentIdPath })) @@ -1623,20 +1454,13 @@ export const byDocumentId = { websiteSync, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete7 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteDatasetsByDatasetIdDocuments', path: '/datasets/{dataset_id}/documents', + successStatus: 204, tags: ['console'], }) .input(z.object({ params: zDeleteDatasetsByDatasetIdDocumentsPath })) @@ -1813,16 +1637,8 @@ export const indexingStatus3 = { get: get28, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post19 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postDatasetsByDatasetIdMetadataBuiltInByAction', @@ -1840,20 +1656,13 @@ export const builtIn2 = { byAction: byAction4, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete8 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteDatasetsByDatasetIdMetadataByMetadataId', path: '/datasets/{dataset_id}/metadata/{metadata_id}', + successStatus: 204, tags: ['console'], }) .input(z.object({ params: zDeleteDatasetsByDatasetIdMetadataByMetadataIdPath })) @@ -1938,16 +1747,8 @@ export const metadata4 = { byMetadataId, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get30 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getDatasetsByDatasetIdNotionSync', @@ -2042,20 +1843,14 @@ export const relatedApps = { /** * retry document - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post21 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postDatasetsByDatasetIdRetry', path: '/datasets/{dataset_id}/retry', + successStatus: 204, summary: 'retry document', tags: ['console'], }) @@ -2073,16 +1868,10 @@ export const retry = { /** * Check if dataset is in use - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get34 = oc .route({ - deprecated: true, - description: - 'Check if dataset is in use\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Check if dataset is in use', inputStructure: 'detailed', method: 'GET', operationId: 'getDatasetsByDatasetIdUseCheck', @@ -2096,20 +1885,13 @@ export const useCheck2 = { get: get34, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete9 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteDatasetsByDatasetId', path: '/datasets/{dataset_id}', + successStatus: 204, tags: ['console'], }) .input(z.object({ params: zDeleteDatasetsByDatasetIdPath })) diff --git a/packages/contracts/generated/api/console/datasets/types.gen.ts b/packages/contracts/generated/api/console/datasets/types.gen.ts index 4b1ff07660..2d9f494515 100644 --- a/packages/contracts/generated/api/console/datasets/types.gen.ts +++ b/packages/contracts/generated/api/console/datasets/types.gen.ts @@ -14,6 +14,10 @@ export type DatasetCreatePayload = { provider?: string } +export type ApiBaseUrlResponse = { + api_base_url: string +} + export type ApiKeyList = { data: Array } @@ -26,6 +30,11 @@ export type ApiKeyItem = { type: string } +export type SegmentBatchImportStatusResponse = { + job_id: string + job_status: string +} + export type BatchImportPayload = { upload_file_id: string } @@ -89,6 +98,11 @@ export type ExternalKnowledgeApiPayload = { } } +export type UsageCountResponse = { + count: number + is_using: boolean +} + export type IndexingEstimatePayload = { dataset_id?: string | null doc_form?: string @@ -126,6 +140,10 @@ export type DatasetAndDocumentResponse = { documents: Array } +export type TextContentResponse = { + content: string +} + export type NotionEstimatePayload = { doc_form?: string doc_language?: string @@ -164,6 +182,10 @@ export type DatasetUpdatePayload = { } | null } +export type SimpleResultResponse = { + result: string +} + export type DocumentBatchDownloadZipPayload = { document_ids: Array } @@ -176,11 +198,20 @@ export type MetadataOperationData = { operation_data: Array } +export type UrlResponse = { + url: string +} + export type DocumentMetadataUpdatePayload = { doc_metadata?: unknown doc_type?: string | null } +export type SimpleResultMessageResponse = { + message: string + result: string +} + export type DocumentRenamePayload = { name: string } @@ -290,6 +321,10 @@ export type DocumentRetryPayload = { document_ids: Array } +export type UsageCheckResponse = { + is_using: boolean +} + export type DatasetPermissionEnum = 'all_team_members' | 'only_me' | 'partial_members' export type DatasetDocMetadata = { @@ -665,9 +700,7 @@ export type GetDatasetsApiBaseInfoData = { } export type GetDatasetsApiBaseInfoResponses = { - 200: { - [key: string]: unknown - } + 200: ApiBaseUrlResponse } export type GetDatasetsApiBaseInfoResponse @@ -737,9 +770,7 @@ export type GetDatasetsBatchImportStatusByJobIdData = { } export type GetDatasetsBatchImportStatusByJobIdResponses = { - 200: { - [key: string]: unknown - } + 200: SegmentBatchImportStatusResponse } export type GetDatasetsBatchImportStatusByJobIdResponse @@ -755,9 +786,7 @@ export type PostDatasetsBatchImportStatusByJobIdData = { } export type PostDatasetsBatchImportStatusByJobIdResponses = { - 200: { - [key: string]: unknown - } + 200: SegmentBatchImportStatusResponse } export type PostDatasetsBatchImportStatusByJobIdResponse @@ -834,8 +863,8 @@ export type DeleteDatasetsExternalKnowledgeApiByExternalKnowledgeApiIdData = { } export type DeleteDatasetsExternalKnowledgeApiByExternalKnowledgeApiIdResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -897,9 +926,7 @@ export type GetDatasetsExternalKnowledgeApiByExternalKnowledgeApiIdUseCheckData } export type GetDatasetsExternalKnowledgeApiByExternalKnowledgeApiIdUseCheckResponses = { - 200: { - [key: string]: unknown - } + 200: UsageCountResponse } export type GetDatasetsExternalKnowledgeApiByExternalKnowledgeApiIdUseCheckResponse @@ -966,9 +993,7 @@ export type GetDatasetsNotionIndexingEstimateData = { } export type GetDatasetsNotionIndexingEstimateResponses = { - 200: { - [key: string]: unknown - } + 200: TextContentResponse } export type GetDatasetsNotionIndexingEstimateResponse @@ -1052,8 +1077,8 @@ export type DeleteDatasetsByDatasetIdData = { } export type DeleteDatasetsByDatasetIdResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -1127,9 +1152,7 @@ export type PostDatasetsByDatasetIdApiKeysByStatusData = { } export type PostDatasetsByDatasetIdApiKeysByStatusResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostDatasetsByDatasetIdApiKeysByStatusResponse @@ -1210,8 +1233,8 @@ export type DeleteDatasetsByDatasetIdDocumentsData = { } export type DeleteDatasetsByDatasetIdDocumentsResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -1302,9 +1325,7 @@ export type PostDatasetsByDatasetIdDocumentsGenerateSummaryError = PostDatasetsByDatasetIdDocumentsGenerateSummaryErrors[keyof PostDatasetsByDatasetIdDocumentsGenerateSummaryErrors] export type PostDatasetsByDatasetIdDocumentsGenerateSummaryResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostDatasetsByDatasetIdDocumentsGenerateSummaryResponse @@ -1320,9 +1341,7 @@ export type PostDatasetsByDatasetIdDocumentsMetadataData = { } export type PostDatasetsByDatasetIdDocumentsMetadataResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostDatasetsByDatasetIdDocumentsMetadataResponse @@ -1339,9 +1358,7 @@ export type PatchDatasetsByDatasetIdDocumentsStatusByActionBatchData = { } export type PatchDatasetsByDatasetIdDocumentsStatusByActionBatchResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PatchDatasetsByDatasetIdDocumentsStatusByActionBatchResponse @@ -1358,8 +1375,8 @@ export type DeleteDatasetsByDatasetIdDocumentsByDocumentIdData = { } export type DeleteDatasetsByDatasetIdDocumentsByDocumentIdResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -1407,9 +1424,7 @@ export type GetDatasetsByDatasetIdDocumentsByDocumentIdDownloadData = { } export type GetDatasetsByDatasetIdDocumentsByDocumentIdDownloadResponses = { - 200: { - [key: string]: unknown - } + 200: UrlResponse } export type GetDatasetsByDatasetIdDocumentsByDocumentIdDownloadResponse @@ -1497,9 +1512,7 @@ export type PutDatasetsByDatasetIdDocumentsByDocumentIdMetadataError = PutDatasetsByDatasetIdDocumentsByDocumentIdMetadataErrors[keyof PutDatasetsByDatasetIdDocumentsByDocumentIdMetadataErrors] export type PutDatasetsByDatasetIdDocumentsByDocumentIdMetadataResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultMessageResponse } export type PutDatasetsByDatasetIdDocumentsByDocumentIdMetadataResponse @@ -1516,9 +1529,7 @@ export type GetDatasetsByDatasetIdDocumentsByDocumentIdNotionSyncData = { } export type GetDatasetsByDatasetIdDocumentsByDocumentIdNotionSyncResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type GetDatasetsByDatasetIdDocumentsByDocumentIdNotionSyncResponse @@ -1554,8 +1565,8 @@ export type PatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingPauseData = { } export type PatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingPauseResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -1573,8 +1584,8 @@ export type PatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingResumeData = } export type PatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingResumeResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -1605,9 +1616,7 @@ export type PatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingByActionError = PatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingByActionErrors[keyof PatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingByActionErrors] export type PatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingByActionResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingByActionResponse @@ -1661,9 +1670,7 @@ export type PatchDatasetsByDatasetIdDocumentsByDocumentIdSegmentByActionData = { } export type PatchDatasetsByDatasetIdDocumentsByDocumentIdSegmentByActionResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PatchDatasetsByDatasetIdDocumentsByDocumentIdSegmentByActionResponse @@ -1680,8 +1687,8 @@ export type DeleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsData = { } export type DeleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -1718,9 +1725,7 @@ export type GetDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImportData = } export type GetDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImportResponses = { - 200: { - [key: string]: unknown - } + 200: SegmentBatchImportStatusResponse } export type GetDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImportResponse @@ -1737,9 +1742,7 @@ export type PostDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImportData } export type PostDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImportResponses = { - 200: { - [key: string]: unknown - } + 200: SegmentBatchImportStatusResponse } export type PostDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImportResponse @@ -1757,8 +1760,8 @@ export type DeleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBySegmentIdDat } export type DeleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBySegmentIdResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -1860,8 +1863,8 @@ export type DeleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBySegmentIdChi export type DeleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBySegmentIdChildChunksByChildChunkIdResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -1930,9 +1933,7 @@ export type GetDatasetsByDatasetIdDocumentsByDocumentIdWebsiteSyncData = { } export type GetDatasetsByDatasetIdDocumentsByDocumentIdWebsiteSyncResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type GetDatasetsByDatasetIdDocumentsByDocumentIdWebsiteSyncResponse @@ -2088,9 +2089,7 @@ export type PostDatasetsByDatasetIdMetadataBuiltInByActionData = { } export type PostDatasetsByDatasetIdMetadataBuiltInByActionResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostDatasetsByDatasetIdMetadataBuiltInByActionResponse @@ -2107,8 +2106,8 @@ export type DeleteDatasetsByDatasetIdMetadataByMetadataIdData = { } export type DeleteDatasetsByDatasetIdMetadataByMetadataIdResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -2144,9 +2143,7 @@ export type GetDatasetsByDatasetIdNotionSyncData = { } export type GetDatasetsByDatasetIdNotionSyncResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type GetDatasetsByDatasetIdNotionSyncResponse @@ -2224,8 +2221,8 @@ export type PostDatasetsByDatasetIdRetryData = { } export type PostDatasetsByDatasetIdRetryResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -2242,9 +2239,7 @@ export type GetDatasetsByDatasetIdUseCheckData = { } export type GetDatasetsByDatasetIdUseCheckResponses = { - 200: { - [key: string]: unknown - } + 200: UsageCheckResponse } export type GetDatasetsByDatasetIdUseCheckResponse diff --git a/packages/contracts/generated/api/console/datasets/zod.gen.ts b/packages/contracts/generated/api/console/datasets/zod.gen.ts index e26f412da9..18d585a247 100644 --- a/packages/contracts/generated/api/console/datasets/zod.gen.ts +++ b/packages/contracts/generated/api/console/datasets/zod.gen.ts @@ -2,6 +2,13 @@ import * as z from 'zod' +/** + * ApiBaseUrlResponse + */ +export const zApiBaseUrlResponse = z.object({ + api_base_url: z.string(), +}) + /** * ApiKeyItem */ @@ -20,6 +27,14 @@ export const zApiKeyList = z.object({ data: z.array(zApiKeyItem), }) +/** + * SegmentBatchImportStatusResponse + */ +export const zSegmentBatchImportStatusResponse = z.object({ + job_id: z.string(), + job_status: z.string(), +}) + /** * BatchImportPayload */ @@ -46,6 +61,14 @@ export const zExternalKnowledgeApiPayload = z.object({ settings: z.record(z.string(), z.unknown()), }) +/** + * UsageCountResponse + */ +export const zUsageCountResponse = z.object({ + count: z.int(), + is_using: z.boolean(), +}) + /** * IndexingEstimatePayload */ @@ -58,6 +81,13 @@ export const zIndexingEstimatePayload = z.object({ process_rule: z.record(z.string(), z.unknown()), }) +/** + * TextContentResponse + */ +export const zTextContentResponse = z.object({ + content: z.string(), +}) + /** * NotionEstimatePayload */ @@ -68,6 +98,13 @@ export const zNotionEstimatePayload = z.object({ process_rule: z.record(z.string(), z.unknown()), }) +/** + * SimpleResultResponse + */ +export const zSimpleResultResponse = z.object({ + result: z.string(), +}) + /** * DocumentBatchDownloadZipPayload * @@ -84,6 +121,13 @@ export const zGenerateSummaryPayload = z.object({ document_list: z.array(z.string()), }) +/** + * UrlResponse + */ +export const zUrlResponse = z.object({ + url: z.string(), +}) + /** * DocumentMetadataUpdatePayload */ @@ -92,6 +136,14 @@ export const zDocumentMetadataUpdatePayload = z.object({ doc_type: z.string().nullish(), }) +/** + * SimpleResultMessageResponse + */ +export const zSimpleResultMessageResponse = z.object({ + message: z.string(), + result: z.string(), +}) + /** * DocumentRenamePayload */ @@ -166,6 +218,13 @@ export const zDocumentRetryPayload = z.object({ document_ids: z.array(z.string()), }) +/** + * UsageCheckResponse + */ +export const zUsageCheckResponse = z.object({ + is_using: z.boolean(), +}) + /** * DatasetPermissionEnum */ @@ -777,7 +836,7 @@ export const zPostDatasetsResponse = z.record(z.string(), z.unknown()) /** * API base info retrieved successfully */ -export const zGetDatasetsApiBaseInfoResponse = z.record(z.string(), z.unknown()) +export const zGetDatasetsApiBaseInfoResponse = zApiBaseUrlResponse /** * API keys retrieved successfully @@ -803,9 +862,9 @@ export const zGetDatasetsBatchImportStatusByJobIdPath = z.object({ }) /** - * Success + * Batch import status */ -export const zGetDatasetsBatchImportStatusByJobIdResponse = z.record(z.string(), z.unknown()) +export const zGetDatasetsBatchImportStatusByJobIdResponse = zSegmentBatchImportStatusResponse export const zPostDatasetsBatchImportStatusByJobIdBody = zBatchImportPayload @@ -814,9 +873,9 @@ export const zPostDatasetsBatchImportStatusByJobIdPath = z.object({ }) /** - * Success + * Batch import started */ -export const zPostDatasetsBatchImportStatusByJobIdResponse = z.record(z.string(), z.unknown()) +export const zPostDatasetsBatchImportStatusByJobIdResponse = zSegmentBatchImportStatusResponse export const zPostDatasetsExternalBody = zExternalDatasetCreatePayload @@ -848,11 +907,11 @@ export const zDeleteDatasetsExternalKnowledgeApiByExternalKnowledgeApiIdPath = z }) /** - * Success + * External knowledge API deleted successfully */ export const zDeleteDatasetsExternalKnowledgeApiByExternalKnowledgeApiIdResponse = z.record( z.string(), - z.unknown(), + z.never(), ) export const zGetDatasetsExternalKnowledgeApiByExternalKnowledgeApiIdPath = z.object({ @@ -889,10 +948,8 @@ export const zGetDatasetsExternalKnowledgeApiByExternalKnowledgeApiIdUseCheckPat /** * Usage check completed successfully */ -export const zGetDatasetsExternalKnowledgeApiByExternalKnowledgeApiIdUseCheckResponse = z.record( - z.string(), - z.unknown(), -) +export const zGetDatasetsExternalKnowledgeApiByExternalKnowledgeApiIdUseCheckResponse + = zUsageCountResponse export const zPostDatasetsIndexingEstimateBody = zIndexingEstimatePayload @@ -916,7 +973,7 @@ export const zGetDatasetsMetadataBuiltInResponse = z.record(z.string(), z.unknow /** * Success */ -export const zGetDatasetsNotionIndexingEstimateResponse = z.record(z.string(), z.unknown()) +export const zGetDatasetsNotionIndexingEstimateResponse = zTextContentResponse export const zPostDatasetsNotionIndexingEstimateBody = zNotionEstimatePayload @@ -953,9 +1010,9 @@ export const zDeleteDatasetsByDatasetIdPath = z.object({ }) /** - * Success + * Dataset deleted successfully */ -export const zDeleteDatasetsByDatasetIdResponse = z.record(z.string(), z.unknown()) +export const zDeleteDatasetsByDatasetIdResponse = z.record(z.string(), z.never()) export const zGetDatasetsByDatasetIdPath = z.object({ dataset_id: z.string(), @@ -985,7 +1042,7 @@ export const zPostDatasetsByDatasetIdApiKeysByStatusPath = z.object({ /** * Success */ -export const zPostDatasetsByDatasetIdApiKeysByStatusResponse = z.record(z.string(), z.unknown()) +export const zPostDatasetsByDatasetIdApiKeysByStatusResponse = zSimpleResultResponse export const zGetDatasetsByDatasetIdAutoDisableLogsPath = z.object({ dataset_id: z.string(), @@ -1027,9 +1084,9 @@ export const zDeleteDatasetsByDatasetIdDocumentsPath = z.object({ }) /** - * Success + * Documents deleted successfully */ -export const zDeleteDatasetsByDatasetIdDocumentsResponse = z.record(z.string(), z.unknown()) +export const zDeleteDatasetsByDatasetIdDocumentsResponse = z.record(z.string(), z.never()) export const zGetDatasetsByDatasetIdDocumentsPath = z.object({ dataset_id: z.string(), @@ -1083,10 +1140,7 @@ export const zPostDatasetsByDatasetIdDocumentsGenerateSummaryPath = z.object({ /** * Summary generation started successfully */ -export const zPostDatasetsByDatasetIdDocumentsGenerateSummaryResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostDatasetsByDatasetIdDocumentsGenerateSummaryResponse = zSimpleResultResponse export const zPostDatasetsByDatasetIdDocumentsMetadataBody = zMetadataOperationData @@ -1097,7 +1151,7 @@ export const zPostDatasetsByDatasetIdDocumentsMetadataPath = z.object({ /** * Success */ -export const zPostDatasetsByDatasetIdDocumentsMetadataResponse = z.record(z.string(), z.unknown()) +export const zPostDatasetsByDatasetIdDocumentsMetadataResponse = zSimpleResultResponse export const zPatchDatasetsByDatasetIdDocumentsStatusByActionBatchPath = z.object({ action: z.string(), @@ -1107,10 +1161,7 @@ export const zPatchDatasetsByDatasetIdDocumentsStatusByActionBatchPath = z.objec /** * Success */ -export const zPatchDatasetsByDatasetIdDocumentsStatusByActionBatchResponse = z.record( - z.string(), - z.unknown(), -) +export const zPatchDatasetsByDatasetIdDocumentsStatusByActionBatchResponse = zSimpleResultResponse export const zDeleteDatasetsByDatasetIdDocumentsByDocumentIdPath = z.object({ dataset_id: z.string(), @@ -1118,11 +1169,11 @@ export const zDeleteDatasetsByDatasetIdDocumentsByDocumentIdPath = z.object({ }) /** - * Success + * Document deleted successfully */ export const zDeleteDatasetsByDatasetIdDocumentsByDocumentIdResponse = z.record( z.string(), - z.unknown(), + z.never(), ) export const zGetDatasetsByDatasetIdDocumentsByDocumentIdPath = z.object({ @@ -1148,12 +1199,9 @@ export const zGetDatasetsByDatasetIdDocumentsByDocumentIdDownloadPath = z.object }) /** - * Success + * Download URL generated successfully */ -export const zGetDatasetsByDatasetIdDocumentsByDocumentIdDownloadResponse = z.record( - z.string(), - z.unknown(), -) +export const zGetDatasetsByDatasetIdDocumentsByDocumentIdDownloadResponse = zUrlResponse export const zGetDatasetsByDatasetIdDocumentsByDocumentIdIndexingEstimatePath = z.object({ dataset_id: z.string(), @@ -1192,10 +1240,8 @@ export const zPutDatasetsByDatasetIdDocumentsByDocumentIdMetadataPath = z.object /** * Document metadata updated successfully */ -export const zPutDatasetsByDatasetIdDocumentsByDocumentIdMetadataResponse = z.record( - z.string(), - z.unknown(), -) +export const zPutDatasetsByDatasetIdDocumentsByDocumentIdMetadataResponse + = zSimpleResultMessageResponse export const zGetDatasetsByDatasetIdDocumentsByDocumentIdNotionSyncPath = z.object({ dataset_id: z.string(), @@ -1205,10 +1251,7 @@ export const zGetDatasetsByDatasetIdDocumentsByDocumentIdNotionSyncPath = z.obje /** * Success */ -export const zGetDatasetsByDatasetIdDocumentsByDocumentIdNotionSyncResponse = z.record( - z.string(), - z.unknown(), -) +export const zGetDatasetsByDatasetIdDocumentsByDocumentIdNotionSyncResponse = zSimpleResultResponse export const zGetDatasetsByDatasetIdDocumentsByDocumentIdPipelineExecutionLogPath = z.object({ dataset_id: z.string(), @@ -1229,11 +1272,11 @@ export const zPatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingPausePath = }) /** - * Success + * Document paused successfully */ export const zPatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingPauseResponse = z.record( z.string(), - z.unknown(), + z.never(), ) export const zPatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingResumePath = z.object({ @@ -1242,11 +1285,11 @@ export const zPatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingResumePath }) /** - * Success + * Document resumed successfully */ export const zPatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingResumeResponse = z.record( z.string(), - z.unknown(), + z.never(), ) export const zPatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingByActionPath = z.object({ @@ -1258,10 +1301,8 @@ export const zPatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingByActionPat /** * Processing status updated successfully */ -export const zPatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingByActionResponse = z.record( - z.string(), - z.unknown(), -) +export const zPatchDatasetsByDatasetIdDocumentsByDocumentIdProcessingByActionResponse + = zSimpleResultResponse export const zPostDatasetsByDatasetIdDocumentsByDocumentIdRenameBody = zDocumentRenamePayload @@ -1299,10 +1340,8 @@ export const zPatchDatasetsByDatasetIdDocumentsByDocumentIdSegmentByActionPath = /** * Success */ -export const zPatchDatasetsByDatasetIdDocumentsByDocumentIdSegmentByActionResponse = z.record( - z.string(), - z.unknown(), -) +export const zPatchDatasetsByDatasetIdDocumentsByDocumentIdSegmentByActionResponse + = zSimpleResultResponse export const zDeleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsPath = z.object({ dataset_id: z.string(), @@ -1310,11 +1349,11 @@ export const zDeleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsPath = z.obj }) /** - * Success + * Segments deleted successfully */ export const zDeleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsResponse = z.record( z.string(), - z.unknown(), + z.never(), ) export const zGetDatasetsByDatasetIdDocumentsByDocumentIdSegmentsPath = z.object({ @@ -1336,12 +1375,10 @@ export const zGetDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImportPath }) /** - * Success + * Batch import status */ -export const zGetDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImportResponse = z.record( - z.string(), - z.unknown(), -) +export const zGetDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImportResponse + = zSegmentBatchImportStatusResponse export const zPostDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImportBody = zBatchImportPayload @@ -1352,12 +1389,10 @@ export const zPostDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImportPat }) /** - * Success + * Batch import started */ -export const zPostDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImportResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBatchImportResponse + = zSegmentBatchImportStatusResponse export const zDeleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBySegmentIdPath = z.object({ dataset_id: z.string(), @@ -1366,11 +1401,11 @@ export const zDeleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBySegmentIdP }) /** - * Success + * Segment deleted successfully */ export const zDeleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBySegmentIdResponse = z.record( z.string(), - z.unknown(), + z.never(), ) export const zPatchDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBySegmentIdBody @@ -1441,10 +1476,10 @@ export const zDeleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBySegmentIdC }) /** - * Success + * Child chunk deleted successfully */ export const zDeleteDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBySegmentIdChildChunksByChildChunkIdResponse - = z.record(z.string(), z.unknown()) + = z.record(z.string(), z.never()) export const zPatchDatasetsByDatasetIdDocumentsByDocumentIdSegmentsBySegmentIdChildChunksByChildChunkIdBody = zChildChunkUpdatePayload @@ -1484,10 +1519,7 @@ export const zGetDatasetsByDatasetIdDocumentsByDocumentIdWebsiteSyncPath = z.obj /** * Success */ -export const zGetDatasetsByDatasetIdDocumentsByDocumentIdWebsiteSyncResponse = z.record( - z.string(), - z.unknown(), -) +export const zGetDatasetsByDatasetIdDocumentsByDocumentIdWebsiteSyncResponse = zSimpleResultResponse export const zGetDatasetsByDatasetIdErrorDocsPath = z.object({ dataset_id: z.string(), @@ -1557,10 +1589,7 @@ export const zPostDatasetsByDatasetIdMetadataBuiltInByActionPath = z.object({ /** * Success */ -export const zPostDatasetsByDatasetIdMetadataBuiltInByActionResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostDatasetsByDatasetIdMetadataBuiltInByActionResponse = zSimpleResultResponse export const zDeleteDatasetsByDatasetIdMetadataByMetadataIdPath = z.object({ dataset_id: z.string(), @@ -1568,11 +1597,11 @@ export const zDeleteDatasetsByDatasetIdMetadataByMetadataIdPath = z.object({ }) /** - * Success + * Metadata deleted successfully */ export const zDeleteDatasetsByDatasetIdMetadataByMetadataIdResponse = z.record( z.string(), - z.unknown(), + z.never(), ) export const zPatchDatasetsByDatasetIdMetadataByMetadataIdBody = zMetadataUpdatePayload @@ -1597,7 +1626,7 @@ export const zGetDatasetsByDatasetIdNotionSyncPath = z.object({ /** * Success */ -export const zGetDatasetsByDatasetIdNotionSyncResponse = z.record(z.string(), z.unknown()) +export const zGetDatasetsByDatasetIdNotionSyncResponse = zSimpleResultResponse export const zGetDatasetsByDatasetIdPermissionPartUsersPath = z.object({ dataset_id: z.string(), @@ -1633,9 +1662,9 @@ export const zPostDatasetsByDatasetIdRetryPath = z.object({ }) /** - * Success + * Documents retry started successfully */ -export const zPostDatasetsByDatasetIdRetryResponse = z.record(z.string(), z.unknown()) +export const zPostDatasetsByDatasetIdRetryResponse = z.record(z.string(), z.never()) export const zGetDatasetsByDatasetIdUseCheckPath = z.object({ dataset_id: z.string(), @@ -1644,7 +1673,7 @@ export const zGetDatasetsByDatasetIdUseCheckPath = z.object({ /** * Dataset use status retrieved successfully */ -export const zGetDatasetsByDatasetIdUseCheckResponse = z.record(z.string(), z.unknown()) +export const zGetDatasetsByDatasetIdUseCheckResponse = zUsageCheckResponse export const zGetDatasetsByResourceIdApiKeysPath = z.object({ resource_id: z.string(), diff --git a/packages/contracts/generated/api/console/email-code-login/orpc.gen.ts b/packages/contracts/generated/api/console/email-code-login/orpc.gen.ts index e1d0c2c319..54edabc29f 100644 --- a/packages/contracts/generated/api/console/email-code-login/orpc.gen.ts +++ b/packages/contracts/generated/api/console/email-code-login/orpc.gen.ts @@ -10,16 +10,8 @@ import { zPostEmailCodeLoginValidityResponse, } from './zod.gen' -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postEmailCodeLoginValidity', @@ -33,16 +25,8 @@ export const validity = { post, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post2 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postEmailCodeLogin', diff --git a/packages/contracts/generated/api/console/email-code-login/types.gen.ts b/packages/contracts/generated/api/console/email-code-login/types.gen.ts index f1413a611d..8a41589ef5 100644 --- a/packages/contracts/generated/api/console/email-code-login/types.gen.ts +++ b/packages/contracts/generated/api/console/email-code-login/types.gen.ts @@ -9,6 +9,11 @@ export type EmailPayload = { language?: string | null } +export type SimpleResultDataResponse = { + data: string + result: string +} + export type EmailCodeLoginPayload = { code: string email: string @@ -17,6 +22,10 @@ export type EmailCodeLoginPayload = { token: string } +export type SimpleResultResponse = { + result: string +} + export type PostEmailCodeLoginData = { body: EmailPayload path?: never @@ -25,9 +34,7 @@ export type PostEmailCodeLoginData = { } export type PostEmailCodeLoginResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultDataResponse } export type PostEmailCodeLoginResponse @@ -41,9 +48,7 @@ export type PostEmailCodeLoginValidityData = { } export type PostEmailCodeLoginValidityResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostEmailCodeLoginValidityResponse diff --git a/packages/contracts/generated/api/console/email-code-login/zod.gen.ts b/packages/contracts/generated/api/console/email-code-login/zod.gen.ts index 83f1abed45..af72ec3386 100644 --- a/packages/contracts/generated/api/console/email-code-login/zod.gen.ts +++ b/packages/contracts/generated/api/console/email-code-login/zod.gen.ts @@ -10,6 +10,14 @@ export const zEmailPayload = z.object({ language: z.string().nullish(), }) +/** + * SimpleResultDataResponse + */ +export const zSimpleResultDataResponse = z.object({ + data: z.string(), + result: z.string(), +}) + /** * EmailCodeLoginPayload */ @@ -21,16 +29,23 @@ export const zEmailCodeLoginPayload = z.object({ token: z.string(), }) +/** + * SimpleResultResponse + */ +export const zSimpleResultResponse = z.object({ + result: z.string(), +}) + export const zPostEmailCodeLoginBody = zEmailPayload /** * Success */ -export const zPostEmailCodeLoginResponse = z.record(z.string(), z.unknown()) +export const zPostEmailCodeLoginResponse = zSimpleResultDataResponse export const zPostEmailCodeLoginValidityBody = zEmailCodeLoginPayload /** * Success */ -export const zPostEmailCodeLoginValidityResponse = z.record(z.string(), z.unknown()) +export const zPostEmailCodeLoginValidityResponse = zSimpleResultResponse diff --git a/packages/contracts/generated/api/console/email-register/types.gen.ts b/packages/contracts/generated/api/console/email-register/types.gen.ts index 3fe5129fbf..cca4d75415 100644 --- a/packages/contracts/generated/api/console/email-register/types.gen.ts +++ b/packages/contracts/generated/api/console/email-register/types.gen.ts @@ -4,6 +4,17 @@ export type ClientOptions = { baseUrl: `${string}://${string}/console/api` | (string & {}) } +export type SimpleResultDataResponse = { + data: string + result: string +} + +export type VerificationTokenResponse = { + email: string + is_valid: boolean + token: string +} + export type PostEmailRegisterData = { body?: never path?: never @@ -27,9 +38,7 @@ export type PostEmailRegisterSendEmailData = { } export type PostEmailRegisterSendEmailResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultDataResponse } export type PostEmailRegisterSendEmailResponse @@ -43,9 +52,7 @@ export type PostEmailRegisterValidityData = { } export type PostEmailRegisterValidityResponses = { - 200: { - [key: string]: unknown - } + 200: VerificationTokenResponse } export type PostEmailRegisterValidityResponse diff --git a/packages/contracts/generated/api/console/email-register/zod.gen.ts b/packages/contracts/generated/api/console/email-register/zod.gen.ts index 11720317f2..490777db90 100644 --- a/packages/contracts/generated/api/console/email-register/zod.gen.ts +++ b/packages/contracts/generated/api/console/email-register/zod.gen.ts @@ -2,6 +2,23 @@ import * as z from 'zod' +/** + * SimpleResultDataResponse + */ +export const zSimpleResultDataResponse = z.object({ + data: z.string(), + result: z.string(), +}) + +/** + * VerificationTokenResponse + */ +export const zVerificationTokenResponse = z.object({ + email: z.string(), + is_valid: z.boolean(), + token: z.string(), +}) + /** * Success */ @@ -10,9 +27,9 @@ export const zPostEmailRegisterResponse = z.record(z.string(), z.unknown()) /** * Success */ -export const zPostEmailRegisterSendEmailResponse = z.record(z.string(), z.unknown()) +export const zPostEmailRegisterSendEmailResponse = zSimpleResultDataResponse /** * Success */ -export const zPostEmailRegisterValidityResponse = z.record(z.string(), z.unknown()) +export const zPostEmailRegisterValidityResponse = zVerificationTokenResponse diff --git a/packages/contracts/generated/api/console/features/orpc.gen.ts b/packages/contracts/generated/api/console/features/orpc.gen.ts index e859a3c684..e24ec3d964 100644 --- a/packages/contracts/generated/api/console/features/orpc.gen.ts +++ b/packages/contracts/generated/api/console/features/orpc.gen.ts @@ -8,16 +8,10 @@ import { zGetFeaturesResponse } from './zod.gen' * Get feature configuration for current tenant * * Get feature configuration for current tenant - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get = oc .route({ - deprecated: true, - description: - 'Get feature configuration for current tenant\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Get feature configuration for current tenant', inputStructure: 'detailed', method: 'GET', operationId: 'getFeatures', diff --git a/packages/contracts/generated/api/console/features/types.gen.ts b/packages/contracts/generated/api/console/features/types.gen.ts index 4c3ba1c00f..411e062afb 100644 --- a/packages/contracts/generated/api/console/features/types.gen.ts +++ b/packages/contracts/generated/api/console/features/types.gen.ts @@ -4,10 +4,63 @@ export type ClientOptions = { baseUrl: `${string}://${string}/console/api` | (string & {}) } -export type FeatureResponse = { - features?: { - [key: string]: unknown - } +export type FeatureModel = { + annotation_quota_limit: LimitationModel + api_rate_limit: Quota + apps: LimitationModel + billing: BillingModel + can_replace_logo: boolean + dataset_operator_enabled: boolean + docs_processing: string + documents_upload_quota: LimitationModel + education: EducationModel + human_input_email_delivery_enabled: boolean + is_allow_transfer_workspace: boolean + knowledge_pipeline: KnowledgePipeline + knowledge_rate_limit: number + members: LimitationModel + model_load_balancing_enabled: boolean + next_credit_reset_date: number + trigger_event: Quota + vector_space: LimitationModel + webapp_copyright_enabled: boolean + workspace_members: LicenseLimitationModel +} + +export type LimitationModel = { + limit: number + size: number +} + +export type Quota = { + limit: number + reset_date: number + usage: number +} + +export type BillingModel = { + enabled: boolean + subscription: SubscriptionModel +} + +export type EducationModel = { + activated: boolean + enabled: boolean +} + +export type KnowledgePipeline = { + publish_enabled: boolean +} + +export type LicenseLimitationModel = { + enabled: boolean + limit: number + size: number +} + +export type SubscriptionModel = { + interval: string + plan: string } export type GetFeaturesData = { @@ -18,7 +71,7 @@ export type GetFeaturesData = { } export type GetFeaturesResponses = { - 200: FeatureResponse + 200: FeatureModel } export type GetFeaturesResponse = GetFeaturesResponses[keyof GetFeaturesResponses] diff --git a/packages/contracts/generated/api/console/features/zod.gen.ts b/packages/contracts/generated/api/console/features/zod.gen.ts index 7bfc4debdd..9ace83a433 100644 --- a/packages/contracts/generated/api/console/features/zod.gen.ts +++ b/packages/contracts/generated/api/console/features/zod.gen.ts @@ -2,11 +2,94 @@ import * as z from 'zod' -export const zFeatureResponse = z.object({ - features: z.record(z.string(), z.unknown()).optional(), +/** + * LimitationModel + */ +export const zLimitationModel = z.object({ + limit: z.int().default(0), + size: z.int().default(0), +}) + +/** + * Quota + */ +export const zQuota = z.object({ + limit: z.int().default(0), + reset_date: z.int().default(-1), + usage: z.int().default(0), +}) + +/** + * EducationModel + */ +export const zEducationModel = z.object({ + activated: z.boolean().default(false), + enabled: z.boolean().default(false), +}) + +/** + * KnowledgePipeline + */ +export const zKnowledgePipeline = z.object({ + publish_enabled: z.boolean().default(false), +}) + +/** + * LicenseLimitationModel + * + * - enabled: whether this limit is enforced + * - size: current usage count + * - limit: maximum allowed count; 0 means unlimited + */ +export const zLicenseLimitationModel = z.object({ + enabled: z.boolean().default(false), + limit: z.int().default(0), + size: z.int().default(0), +}) + +/** + * SubscriptionModel + */ +export const zSubscriptionModel = z.object({ + interval: z.string().default(''), + plan: z.string().default('sandbox'), +}) + +/** + * BillingModel + */ +export const zBillingModel = z.object({ + enabled: z.boolean().default(false), + subscription: zSubscriptionModel, +}) + +/** + * FeatureModel + */ +export const zFeatureModel = z.object({ + annotation_quota_limit: zLimitationModel, + api_rate_limit: zQuota, + apps: zLimitationModel, + billing: zBillingModel, + can_replace_logo: z.boolean().default(false), + dataset_operator_enabled: z.boolean().default(false), + docs_processing: z.string().default('standard'), + documents_upload_quota: zLimitationModel, + education: zEducationModel, + human_input_email_delivery_enabled: z.boolean().default(false), + is_allow_transfer_workspace: z.boolean().default(true), + knowledge_pipeline: zKnowledgePipeline, + knowledge_rate_limit: z.int().default(10), + members: zLimitationModel, + model_load_balancing_enabled: z.boolean().default(false), + next_credit_reset_date: z.int().default(0), + trigger_event: zQuota, + vector_space: zLimitationModel, + webapp_copyright_enabled: z.boolean().default(false), + workspace_members: zLicenseLimitationModel, }) /** * Success */ -export const zGetFeaturesResponse = zFeatureResponse +export const zGetFeaturesResponse = zFeatureModel diff --git a/packages/contracts/generated/api/console/files/orpc.gen.ts b/packages/contracts/generated/api/console/files/orpc.gen.ts index a46dcca46e..2ee949edc2 100644 --- a/packages/contracts/generated/api/console/files/orpc.gen.ts +++ b/packages/contracts/generated/api/console/files/orpc.gen.ts @@ -11,16 +11,8 @@ import { zPostFilesUploadResponse, } from './zod.gen' -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getFilesSupportType', @@ -59,16 +51,8 @@ export const upload = { post, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get3 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getFilesByFileIdPreview', diff --git a/packages/contracts/generated/api/console/files/types.gen.ts b/packages/contracts/generated/api/console/files/types.gen.ts index 5620235461..e2ce3cf501 100644 --- a/packages/contracts/generated/api/console/files/types.gen.ts +++ b/packages/contracts/generated/api/console/files/types.gen.ts @@ -4,6 +4,10 @@ export type ClientOptions = { baseUrl: `${string}://${string}/console/api` | (string & {}) } +export type AllowedExtensionsResponse = { + allowed_extensions: Array +} + export type UploadConfig = { attachment_image_file_size_limit?: number | null audio_file_size_limit: number @@ -34,6 +38,10 @@ export type FileResponse = { user_id?: string | null } +export type TextContentResponse = { + content: string +} + export type GetFilesSupportTypeData = { body?: never path?: never @@ -42,9 +50,7 @@ export type GetFilesSupportTypeData = { } export type GetFilesSupportTypeResponses = { - 200: { - [key: string]: unknown - } + 200: AllowedExtensionsResponse } export type GetFilesSupportTypeResponse @@ -86,9 +92,7 @@ export type GetFilesByFileIdPreviewData = { } export type GetFilesByFileIdPreviewResponses = { - 200: { - [key: string]: unknown - } + 200: TextContentResponse } export type GetFilesByFileIdPreviewResponse diff --git a/packages/contracts/generated/api/console/files/zod.gen.ts b/packages/contracts/generated/api/console/files/zod.gen.ts index d61e7795ce..1886afe790 100644 --- a/packages/contracts/generated/api/console/files/zod.gen.ts +++ b/packages/contracts/generated/api/console/files/zod.gen.ts @@ -2,6 +2,13 @@ import * as z from 'zod' +/** + * AllowedExtensionsResponse + */ +export const zAllowedExtensionsResponse = z.object({ + allowed_extensions: z.array(z.string()), +}) + /** * UploadConfig */ @@ -38,10 +45,17 @@ export const zFileResponse = z.object({ user_id: z.string().nullish(), }) +/** + * TextContentResponse + */ +export const zTextContentResponse = z.object({ + content: z.string(), +}) + /** * Success */ -export const zGetFilesSupportTypeResponse = z.record(z.string(), z.unknown()) +export const zGetFilesSupportTypeResponse = zAllowedExtensionsResponse /** * Success @@ -60,4 +74,4 @@ export const zGetFilesByFileIdPreviewPath = z.object({ /** * Success */ -export const zGetFilesByFileIdPreviewResponse = z.record(z.string(), z.unknown()) +export const zGetFilesByFileIdPreviewResponse = zTextContentResponse diff --git a/packages/contracts/generated/api/console/installed-apps/orpc.gen.ts b/packages/contracts/generated/api/console/installed-apps/orpc.gen.ts index f0efa7abbc..414e72dcb2 100644 --- a/packages/contracts/generated/api/console/installed-apps/orpc.gen.ts +++ b/packages/contracts/generated/api/console/installed-apps/orpc.gen.ts @@ -90,16 +90,8 @@ export const audioToText = { post, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post2 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postInstalledAppsByInstalledAppIdChatMessagesByTaskIdStop', @@ -146,16 +138,8 @@ export const chatMessages = { byTaskId, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post4 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postInstalledAppsByInstalledAppIdCompletionMessagesByTaskIdStop', @@ -230,16 +214,8 @@ export const name = { post: post6, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const patch = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'PATCH', operationId: 'patchInstalledAppsByInstalledAppIdConversationsByCIdPin', @@ -253,16 +229,8 @@ export const pin = { patch, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const patch2 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'PATCH', operationId: 'patchInstalledAppsByInstalledAppIdConversationsByCIdUnpin', @@ -276,20 +244,13 @@ export const unpin = { patch: patch2, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete_ = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteInstalledAppsByInstalledAppIdConversationsByCId', path: '/installed-apps/{installed_app_id}/conversations/{c_id}', + successStatus: 204, tags: ['console'], }) .input(z.object({ params: zDeleteInstalledAppsByInstalledAppIdConversationsByCIdPath })) @@ -331,16 +292,8 @@ export const conversations = { byCId, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post7 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postInstalledAppsByInstalledAppIdMessagesByMessageIdFeedbacks', @@ -387,16 +340,8 @@ export const moreLikeThis = { get: get2, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get3 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getInstalledAppsByInstalledAppIdMessagesByMessageIdSuggestedQuestions', @@ -501,20 +446,13 @@ export const parameters = { get: get6, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete2 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteInstalledAppsByInstalledAppIdSavedMessagesByMessageId', path: '/installed-apps/{installed_app_id}/saved-messages/{message_id}', + successStatus: 204, tags: ['console'], }) .input(z.object({ params: zDeleteInstalledAppsByInstalledAppIdSavedMessagesByMessageIdPath })) @@ -548,16 +486,8 @@ export const get7 = oc ) .output(zGetInstalledAppsByInstalledAppIdSavedMessagesResponse) -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post8 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postInstalledAppsByInstalledAppIdSavedMessages', @@ -639,16 +569,9 @@ export const run = { /** * Stop workflow task - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post11 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postInstalledAppsByInstalledAppIdWorkflowsTasksByTaskIdStop', @@ -676,20 +599,13 @@ export const workflows = { tasks, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete3 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteInstalledAppsByInstalledAppId', path: '/installed-apps/{installed_app_id}', + successStatus: 204, tags: ['console'], }) .input(z.object({ params: zDeleteInstalledAppsByInstalledAppIdPath })) diff --git a/packages/contracts/generated/api/console/installed-apps/types.gen.ts b/packages/contracts/generated/api/console/installed-apps/types.gen.ts index 22f9903bc8..59120100bf 100644 --- a/packages/contracts/generated/api/console/installed-apps/types.gen.ts +++ b/packages/contracts/generated/api/console/installed-apps/types.gen.ts @@ -8,6 +8,15 @@ export type InstalledAppListResponse = { installed_apps: Array } +export type SimpleMessageResponse = { + message: string +} + +export type SimpleResultMessageResponse = { + message: string + result: string +} + export type ChatMessagePayload = { conversation_id?: string | null files?: Array | null @@ -23,6 +32,10 @@ export type ChatMessagePayload = { retriever_from?: string } +export type SimpleResultResponse = { + result: string +} + export type CompletionMessageExplorePayload = { files?: Array<{ [key: string]: unknown @@ -40,12 +53,20 @@ export type ConversationRenamePayload = { name?: string | null } +export type ResultResponse = { + result: string +} + export type MessageFeedbackPayload = { content?: string | null message_id: string rating?: 'dislike' | 'like' | null } +export type SuggestedQuestionsResponse = { + data: Array +} + export type SavedMessageCreatePayload = { message_id: string } @@ -107,9 +128,7 @@ export type PostInstalledAppsData = { } export type PostInstalledAppsResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleMessageResponse } export type PostInstalledAppsResponse = PostInstalledAppsResponses[keyof PostInstalledAppsResponses] @@ -124,8 +143,8 @@ export type DeleteInstalledAppsByInstalledAppIdData = { } export type DeleteInstalledAppsByInstalledAppIdResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -142,9 +161,7 @@ export type PatchInstalledAppsByInstalledAppIdData = { } export type PatchInstalledAppsByInstalledAppIdResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultMessageResponse } export type PatchInstalledAppsByInstalledAppIdResponse @@ -197,9 +214,7 @@ export type PostInstalledAppsByInstalledAppIdChatMessagesByTaskIdStopData = { } export type PostInstalledAppsByInstalledAppIdChatMessagesByTaskIdStopResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostInstalledAppsByInstalledAppIdChatMessagesByTaskIdStopResponse @@ -234,9 +249,7 @@ export type PostInstalledAppsByInstalledAppIdCompletionMessagesByTaskIdStopData } export type PostInstalledAppsByInstalledAppIdCompletionMessagesByTaskIdStopResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostInstalledAppsByInstalledAppIdCompletionMessagesByTaskIdStopResponse @@ -275,8 +288,8 @@ export type DeleteInstalledAppsByInstalledAppIdConversationsByCIdData = { } export type DeleteInstalledAppsByInstalledAppIdConversationsByCIdResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -313,9 +326,7 @@ export type PatchInstalledAppsByInstalledAppIdConversationsByCIdPinData = { } export type PatchInstalledAppsByInstalledAppIdConversationsByCIdPinResponses = { - 200: { - [key: string]: unknown - } + 200: ResultResponse } export type PatchInstalledAppsByInstalledAppIdConversationsByCIdPinResponse @@ -332,9 +343,7 @@ export type PatchInstalledAppsByInstalledAppIdConversationsByCIdUnpinData = { } export type PatchInstalledAppsByInstalledAppIdConversationsByCIdUnpinResponses = { - 200: { - [key: string]: unknown - } + 200: ResultResponse } export type PatchInstalledAppsByInstalledAppIdConversationsByCIdUnpinResponse @@ -373,9 +382,7 @@ export type PostInstalledAppsByInstalledAppIdMessagesByMessageIdFeedbacksData = } export type PostInstalledAppsByInstalledAppIdMessagesByMessageIdFeedbacksResponses = { - 200: { - [key: string]: unknown - } + 200: ResultResponse } export type PostInstalledAppsByInstalledAppIdMessagesByMessageIdFeedbacksResponse @@ -413,9 +420,7 @@ export type GetInstalledAppsByInstalledAppIdMessagesByMessageIdSuggestedQuestion } export type GetInstalledAppsByInstalledAppIdMessagesByMessageIdSuggestedQuestionsResponses = { - 200: { - [key: string]: unknown - } + 200: SuggestedQuestionsResponse } export type GetInstalledAppsByInstalledAppIdMessagesByMessageIdSuggestedQuestionsResponse @@ -488,9 +493,7 @@ export type PostInstalledAppsByInstalledAppIdSavedMessagesData = { } export type PostInstalledAppsByInstalledAppIdSavedMessagesResponses = { - 200: { - [key: string]: unknown - } + 200: ResultResponse } export type PostInstalledAppsByInstalledAppIdSavedMessagesResponse @@ -507,8 +510,8 @@ export type DeleteInstalledAppsByInstalledAppIdSavedMessagesByMessageIdData = { } export type DeleteInstalledAppsByInstalledAppIdSavedMessagesByMessageIdResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -562,9 +565,7 @@ export type PostInstalledAppsByInstalledAppIdWorkflowsTasksByTaskIdStopData = { } export type PostInstalledAppsByInstalledAppIdWorkflowsTasksByTaskIdStopResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostInstalledAppsByInstalledAppIdWorkflowsTasksByTaskIdStopResponse diff --git a/packages/contracts/generated/api/console/installed-apps/zod.gen.ts b/packages/contracts/generated/api/console/installed-apps/zod.gen.ts index d688bba246..aa5feb1650 100644 --- a/packages/contracts/generated/api/console/installed-apps/zod.gen.ts +++ b/packages/contracts/generated/api/console/installed-apps/zod.gen.ts @@ -2,6 +2,21 @@ import * as z from 'zod' +/** + * SimpleMessageResponse + */ +export const zSimpleMessageResponse = z.object({ + message: z.string(), +}) + +/** + * SimpleResultMessageResponse + */ +export const zSimpleResultMessageResponse = z.object({ + message: z.string(), + result: z.string(), +}) + /** * ChatMessagePayload */ @@ -16,6 +31,13 @@ export const zChatMessagePayload = z.object({ retriever_from: z.string().optional().default('dev'), }) +/** + * SimpleResultResponse + */ +export const zSimpleResultResponse = z.object({ + result: z.string(), +}) + /** * CompletionMessageExplorePayload */ @@ -35,6 +57,13 @@ export const zConversationRenamePayload = z.object({ name: z.string().nullish(), }) +/** + * ResultResponse + */ +export const zResultResponse = z.object({ + result: z.string(), +}) + /** * MessageFeedbackPayload */ @@ -44,6 +73,13 @@ export const zMessageFeedbackPayload = z.object({ rating: z.enum(['dislike', 'like']).nullish(), }) +/** + * SuggestedQuestionsResponse + */ +export const zSuggestedQuestionsResponse = z.object({ + data: z.array(z.string()), +}) + /** * SavedMessageCreatePayload */ @@ -110,16 +146,16 @@ export const zGetInstalledAppsResponse = zInstalledAppListResponse /** * Success */ -export const zPostInstalledAppsResponse = z.record(z.string(), z.unknown()) +export const zPostInstalledAppsResponse = zSimpleMessageResponse export const zDeleteInstalledAppsByInstalledAppIdPath = z.object({ installed_app_id: z.string(), }) /** - * Success + * App uninstalled successfully */ -export const zDeleteInstalledAppsByInstalledAppIdResponse = z.record(z.string(), z.unknown()) +export const zDeleteInstalledAppsByInstalledAppIdResponse = z.record(z.string(), z.never()) export const zPatchInstalledAppsByInstalledAppIdPath = z.object({ installed_app_id: z.string(), @@ -128,7 +164,7 @@ export const zPatchInstalledAppsByInstalledAppIdPath = z.object({ /** * Success */ -export const zPatchInstalledAppsByInstalledAppIdResponse = z.record(z.string(), z.unknown()) +export const zPatchInstalledAppsByInstalledAppIdResponse = zSimpleResultMessageResponse export const zPostInstalledAppsByInstalledAppIdAudioToTextPath = z.object({ installed_app_id: z.string(), @@ -164,10 +200,8 @@ export const zPostInstalledAppsByInstalledAppIdChatMessagesByTaskIdStopPath = z. /** * Success */ -export const zPostInstalledAppsByInstalledAppIdChatMessagesByTaskIdStopResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostInstalledAppsByInstalledAppIdChatMessagesByTaskIdStopResponse + = zSimpleResultResponse export const zPostInstalledAppsByInstalledAppIdCompletionMessagesBody = zCompletionMessageExplorePayload @@ -192,10 +226,8 @@ export const zPostInstalledAppsByInstalledAppIdCompletionMessagesByTaskIdStopPat /** * Success */ -export const zPostInstalledAppsByInstalledAppIdCompletionMessagesByTaskIdStopResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostInstalledAppsByInstalledAppIdCompletionMessagesByTaskIdStopResponse + = zSimpleResultResponse export const zGetInstalledAppsByInstalledAppIdConversationsPath = z.object({ installed_app_id: z.string(), @@ -221,11 +253,11 @@ export const zDeleteInstalledAppsByInstalledAppIdConversationsByCIdPath = z.obje }) /** - * Success + * Conversation deleted successfully */ export const zDeleteInstalledAppsByInstalledAppIdConversationsByCIdResponse = z.record( z.string(), - z.unknown(), + z.never(), ) export const zPostInstalledAppsByInstalledAppIdConversationsByCIdNameBody @@ -252,10 +284,7 @@ export const zPatchInstalledAppsByInstalledAppIdConversationsByCIdPinPath = z.ob /** * Success */ -export const zPatchInstalledAppsByInstalledAppIdConversationsByCIdPinResponse = z.record( - z.string(), - z.unknown(), -) +export const zPatchInstalledAppsByInstalledAppIdConversationsByCIdPinResponse = zResultResponse export const zPatchInstalledAppsByInstalledAppIdConversationsByCIdUnpinPath = z.object({ c_id: z.string(), @@ -265,10 +294,7 @@ export const zPatchInstalledAppsByInstalledAppIdConversationsByCIdUnpinPath = z. /** * Success */ -export const zPatchInstalledAppsByInstalledAppIdConversationsByCIdUnpinResponse = z.record( - z.string(), - z.unknown(), -) +export const zPatchInstalledAppsByInstalledAppIdConversationsByCIdUnpinResponse = zResultResponse export const zGetInstalledAppsByInstalledAppIdMessagesPath = z.object({ installed_app_id: z.string(), @@ -294,12 +320,10 @@ export const zPostInstalledAppsByInstalledAppIdMessagesByMessageIdFeedbacksPath }) /** - * Success + * Feedback submitted successfully */ -export const zPostInstalledAppsByInstalledAppIdMessagesByMessageIdFeedbacksResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostInstalledAppsByInstalledAppIdMessagesByMessageIdFeedbacksResponse + = zResultResponse export const zGetInstalledAppsByInstalledAppIdMessagesByMessageIdMoreLikeThisPath = z.object({ installed_app_id: z.string(), @@ -327,7 +351,7 @@ export const zGetInstalledAppsByInstalledAppIdMessagesByMessageIdSuggestedQuesti * Success */ export const zGetInstalledAppsByInstalledAppIdMessagesByMessageIdSuggestedQuestionsResponse - = z.record(z.string(), z.unknown()) + = zSuggestedQuestionsResponse export const zGetInstalledAppsByInstalledAppIdMetaPath = z.object({ installed_app_id: z.string(), @@ -373,10 +397,7 @@ export const zPostInstalledAppsByInstalledAppIdSavedMessagesPath = z.object({ /** * Success */ -export const zPostInstalledAppsByInstalledAppIdSavedMessagesResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostInstalledAppsByInstalledAppIdSavedMessagesResponse = zResultResponse export const zDeleteInstalledAppsByInstalledAppIdSavedMessagesByMessageIdPath = z.object({ installed_app_id: z.string(), @@ -384,11 +405,11 @@ export const zDeleteInstalledAppsByInstalledAppIdSavedMessagesByMessageIdPath = }) /** - * Success + * Saved message deleted successfully */ export const zDeleteInstalledAppsByInstalledAppIdSavedMessagesByMessageIdResponse = z.record( z.string(), - z.unknown(), + z.never(), ) export const zPostInstalledAppsByInstalledAppIdTextToAudioBody = zTextToAudioPayload @@ -427,7 +448,5 @@ export const zPostInstalledAppsByInstalledAppIdWorkflowsTasksByTaskIdStopPath = /** * Success */ -export const zPostInstalledAppsByInstalledAppIdWorkflowsTasksByTaskIdStopResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostInstalledAppsByInstalledAppIdWorkflowsTasksByTaskIdStopResponse + = zSimpleResultResponse diff --git a/packages/contracts/generated/api/console/login/orpc.gen.ts b/packages/contracts/generated/api/console/login/orpc.gen.ts index 0fb7cbf4bb..b8e647a11d 100644 --- a/packages/contracts/generated/api/console/login/orpc.gen.ts +++ b/packages/contracts/generated/api/console/login/orpc.gen.ts @@ -7,16 +7,9 @@ import { zPostLoginBody, zPostLoginResponse } from './zod.gen' /** * Authenticate user and login - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postLogin', diff --git a/packages/contracts/generated/api/console/login/types.gen.ts b/packages/contracts/generated/api/console/login/types.gen.ts index 8646c56c2a..a2db40bfcd 100644 --- a/packages/contracts/generated/api/console/login/types.gen.ts +++ b/packages/contracts/generated/api/console/login/types.gen.ts @@ -11,6 +11,11 @@ export type LoginPayload = { remember_me?: boolean } +export type SimpleResultOptionalDataResponse = { + data?: string | null + result: string +} + export type PostLoginData = { body: LoginPayload path?: never @@ -19,9 +24,7 @@ export type PostLoginData = { } export type PostLoginResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultOptionalDataResponse } export type PostLoginResponse = PostLoginResponses[keyof PostLoginResponses] diff --git a/packages/contracts/generated/api/console/login/zod.gen.ts b/packages/contracts/generated/api/console/login/zod.gen.ts index 612ab8d3be..aae456d854 100644 --- a/packages/contracts/generated/api/console/login/zod.gen.ts +++ b/packages/contracts/generated/api/console/login/zod.gen.ts @@ -12,9 +12,17 @@ export const zLoginPayload = z.object({ remember_me: z.boolean().optional().default(false), }) +/** + * SimpleResultOptionalDataResponse + */ +export const zSimpleResultOptionalDataResponse = z.object({ + data: z.string().nullish(), + result: z.string(), +}) + export const zPostLoginBody = zLoginPayload /** * Success */ -export const zPostLoginResponse = z.record(z.string(), z.unknown()) +export const zPostLoginResponse = zSimpleResultOptionalDataResponse diff --git a/packages/contracts/generated/api/console/logout/orpc.gen.ts b/packages/contracts/generated/api/console/logout/orpc.gen.ts index 0fe1f3b909..02ecd2c82d 100644 --- a/packages/contracts/generated/api/console/logout/orpc.gen.ts +++ b/packages/contracts/generated/api/console/logout/orpc.gen.ts @@ -4,16 +4,8 @@ import { oc } from '@orpc/contract' import { zPostLogoutResponse } from './zod.gen' -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postLogout', diff --git a/packages/contracts/generated/api/console/logout/types.gen.ts b/packages/contracts/generated/api/console/logout/types.gen.ts index 9834d78dc1..f8129e487c 100644 --- a/packages/contracts/generated/api/console/logout/types.gen.ts +++ b/packages/contracts/generated/api/console/logout/types.gen.ts @@ -4,6 +4,10 @@ export type ClientOptions = { baseUrl: `${string}://${string}/console/api` | (string & {}) } +export type SimpleResultResponse = { + result: string +} + export type PostLogoutData = { body?: never path?: never @@ -12,9 +16,7 @@ export type PostLogoutData = { } export type PostLogoutResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostLogoutResponse = PostLogoutResponses[keyof PostLogoutResponses] diff --git a/packages/contracts/generated/api/console/logout/zod.gen.ts b/packages/contracts/generated/api/console/logout/zod.gen.ts index 2e2be21264..eacb4072ac 100644 --- a/packages/contracts/generated/api/console/logout/zod.gen.ts +++ b/packages/contracts/generated/api/console/logout/zod.gen.ts @@ -2,7 +2,14 @@ import * as z from 'zod' +/** + * SimpleResultResponse + */ +export const zSimpleResultResponse = z.object({ + result: z.string(), +}) + /** * Success */ -export const zPostLogoutResponse = z.record(z.string(), z.unknown()) +export const zPostLogoutResponse = zSimpleResultResponse diff --git a/packages/contracts/generated/api/console/notification/types.gen.ts b/packages/contracts/generated/api/console/notification/types.gen.ts index 8fe661016b..eb068725f3 100644 --- a/packages/contracts/generated/api/console/notification/types.gen.ts +++ b/packages/contracts/generated/api/console/notification/types.gen.ts @@ -4,6 +4,10 @@ export type ClientOptions = { baseUrl: `${string}://${string}/console/api` | (string & {}) } +export type SimpleResultResponse = { + result: string +} + export type GetNotificationData = { body?: never path?: never @@ -44,9 +48,7 @@ export type PostNotificationDismissError = PostNotificationDismissErrors[keyof PostNotificationDismissErrors] export type PostNotificationDismissResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostNotificationDismissResponse diff --git a/packages/contracts/generated/api/console/notification/zod.gen.ts b/packages/contracts/generated/api/console/notification/zod.gen.ts index c17e436ed9..dcf4aaa56b 100644 --- a/packages/contracts/generated/api/console/notification/zod.gen.ts +++ b/packages/contracts/generated/api/console/notification/zod.gen.ts @@ -2,6 +2,13 @@ import * as z from 'zod' +/** + * SimpleResultResponse + */ +export const zSimpleResultResponse = z.object({ + result: z.string(), +}) + /** * Success — inspect should_show to decide whether to render the modal */ @@ -10,4 +17,4 @@ export const zGetNotificationResponse = z.record(z.string(), z.unknown()) /** * Success */ -export const zPostNotificationDismissResponse = z.record(z.string(), z.unknown()) +export const zPostNotificationDismissResponse = zSimpleResultResponse diff --git a/packages/contracts/generated/api/console/notion/orpc.gen.ts b/packages/contracts/generated/api/console/notion/orpc.gen.ts index 8c5dc03c9e..28b2704a4b 100644 --- a/packages/contracts/generated/api/console/notion/orpc.gen.ts +++ b/packages/contracts/generated/api/console/notion/orpc.gen.ts @@ -12,16 +12,8 @@ import { zPostNotionPagesByPageIdByPageTypePreviewResponse, } from './zod.gen' -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getNotionPagesByPageIdByPageTypePreview', diff --git a/packages/contracts/generated/api/console/notion/types.gen.ts b/packages/contracts/generated/api/console/notion/types.gen.ts index c616a22286..90c9f50894 100644 --- a/packages/contracts/generated/api/console/notion/types.gen.ts +++ b/packages/contracts/generated/api/console/notion/types.gen.ts @@ -4,6 +4,10 @@ export type ClientOptions = { baseUrl: `${string}://${string}/console/api` | (string & {}) } +export type TextContentResponse = { + content: string +} + export type NotionEstimatePayload = { doc_form?: string doc_language?: string @@ -26,9 +30,7 @@ export type GetNotionPagesByPageIdByPageTypePreviewData = { } export type GetNotionPagesByPageIdByPageTypePreviewResponses = { - 200: { - [key: string]: unknown - } + 200: TextContentResponse } export type GetNotionPagesByPageIdByPageTypePreviewResponse diff --git a/packages/contracts/generated/api/console/notion/zod.gen.ts b/packages/contracts/generated/api/console/notion/zod.gen.ts index 0aad7b682c..3362dd6b34 100644 --- a/packages/contracts/generated/api/console/notion/zod.gen.ts +++ b/packages/contracts/generated/api/console/notion/zod.gen.ts @@ -2,6 +2,13 @@ import * as z from 'zod' +/** + * TextContentResponse + */ +export const zTextContentResponse = z.object({ + content: z.string(), +}) + /** * NotionEstimatePayload */ @@ -20,7 +27,7 @@ export const zGetNotionPagesByPageIdByPageTypePreviewPath = z.object({ /** * Success */ -export const zGetNotionPagesByPageIdByPageTypePreviewResponse = z.record(z.string(), z.unknown()) +export const zGetNotionPagesByPageIdByPageTypePreviewResponse = zTextContentResponse export const zPostNotionPagesByPageIdByPageTypePreviewBody = zNotionEstimatePayload diff --git a/packages/contracts/generated/api/console/rag/orpc.gen.ts b/packages/contracts/generated/api/console/rag/orpc.gen.ts index c522f1d060..8faeec575d 100644 --- a/packages/contracts/generated/api/console/rag/orpc.gen.ts +++ b/packages/contracts/generated/api/console/rag/orpc.gen.ts @@ -156,16 +156,8 @@ export const patch = oc .input(z.object({ params: zPatchRagPipelineCustomizedTemplatesByTemplateIdPath })) .output(zPatchRagPipelineCustomizedTemplatesByTemplateIdResponse) -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postRagPipelineCustomizedTemplatesByTemplateId', @@ -498,16 +490,9 @@ export const exports_ = { /** * Stop workflow task - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post8 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postRagPipelinesByPipelineIdWorkflowRunsTasksByTaskIdStop', @@ -1268,16 +1253,9 @@ export const get21 = oc /** * Publish workflow - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post16 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postRagPipelinesByPipelineIdWorkflowsPublish', @@ -1470,16 +1448,8 @@ export const published = { run: run7, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post20 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postRagPipelinesByPipelineIdWorkflowsByWorkflowIdRestore', @@ -1495,20 +1465,14 @@ export const restore = { /** * Delete a published workflow version that is not currently active on the pipeline - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const delete5 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteRagPipelinesByPipelineIdWorkflowsByWorkflowId', path: '/rag/pipelines/{pipeline_id}/workflows/{workflow_id}', + successStatus: 204, summary: 'Delete a published workflow version that is not currently active on the pipeline', tags: ['console'], }) diff --git a/packages/contracts/generated/api/console/rag/types.gen.ts b/packages/contracts/generated/api/console/rag/types.gen.ts index b25272ed7a..8060243ad0 100644 --- a/packages/contracts/generated/api/console/rag/types.gen.ts +++ b/packages/contracts/generated/api/console/rag/types.gen.ts @@ -4,6 +4,10 @@ export type ClientOptions = { baseUrl: `${string}://${string}/console/api` | (string & {}) } +export type SimpleDataResponse = { + data: string +} + export type RagPipelineDatasetImportPayload = { yaml_content: string } @@ -34,6 +38,10 @@ export type WorkflowRunPaginationResponse = { limit: number } +export type SimpleResultResponse = { + result: string +} + export type WorkflowRunDetailResponse = { created_at?: number | null created_by_account?: SimpleAccount @@ -86,6 +94,12 @@ export type WorkflowResponse = { version: string } +export type RagPipelineWorkflowSyncResponse = { + hash: string + result: string + updated_at: number +} + export type DatasourceNodeRunPayload = { credential_id?: string | null datasource_type: string @@ -151,6 +165,11 @@ export type DraftWorkflowRunPayload = { start_node_id: string } +export type RagPipelineWorkflowPublishResponse = { + created_at: number + result: string +} + export type Parser = { credential_id?: string | null datasource_type: string @@ -285,9 +304,7 @@ export type PostRagPipelineCustomizedTemplatesByTemplateIdData = { } export type PostRagPipelineCustomizedTemplatesByTemplateIdResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleDataResponse } export type PostRagPipelineCustomizedTemplatesByTemplateIdResponse @@ -524,9 +541,7 @@ export type PostRagPipelinesByPipelineIdWorkflowRunsTasksByTaskIdStopData = { } export type PostRagPipelinesByPipelineIdWorkflowRunsTasksByTaskIdStopResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostRagPipelinesByPipelineIdWorkflowRunsTasksByTaskIdStopResponse @@ -663,9 +678,7 @@ export type PostRagPipelinesByPipelineIdWorkflowsDraftData = { } export type PostRagPipelinesByPipelineIdWorkflowsDraftResponses = { - 200: { - [key: string]: unknown - } + 200: RagPipelineWorkflowSyncResponse } export type PostRagPipelinesByPipelineIdWorkflowsDraftResponse @@ -1044,9 +1057,7 @@ export type PostRagPipelinesByPipelineIdWorkflowsPublishData = { } export type PostRagPipelinesByPipelineIdWorkflowsPublishResponses = { - 200: { - [key: string]: unknown - } + 200: RagPipelineWorkflowPublishResponse } export type PostRagPipelinesByPipelineIdWorkflowsPublishResponse @@ -1156,8 +1167,8 @@ export type DeleteRagPipelinesByPipelineIdWorkflowsByWorkflowIdData = { } export type DeleteRagPipelinesByPipelineIdWorkflowsByWorkflowIdResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -1207,9 +1218,7 @@ export type PostRagPipelinesByPipelineIdWorkflowsByWorkflowIdRestoreData = { } export type PostRagPipelinesByPipelineIdWorkflowsByWorkflowIdRestoreResponses = { - 200: { - [key: string]: unknown - } + 200: RagPipelineWorkflowSyncResponse } export type PostRagPipelinesByPipelineIdWorkflowsByWorkflowIdRestoreResponse diff --git a/packages/contracts/generated/api/console/rag/zod.gen.ts b/packages/contracts/generated/api/console/rag/zod.gen.ts index 6832c6eb09..276b6476ff 100644 --- a/packages/contracts/generated/api/console/rag/zod.gen.ts +++ b/packages/contracts/generated/api/console/rag/zod.gen.ts @@ -2,6 +2,13 @@ import * as z from 'zod' +/** + * SimpleDataResponse + */ +export const zSimpleDataResponse = z.object({ + data: z.string(), +}) + /** * RagPipelineDatasetImportPayload */ @@ -33,6 +40,22 @@ export const zPayload = z.object({ name: z.string().min(1).max(40), }) +/** + * SimpleResultResponse + */ +export const zSimpleResultResponse = z.object({ + result: z.string(), +}) + +/** + * RagPipelineWorkflowSyncResponse + */ +export const zRagPipelineWorkflowSyncResponse = z.object({ + hash: z.string(), + result: z.string(), + updated_at: z.int(), +}) + /** * DatasourceNodeRunPayload */ @@ -76,6 +99,14 @@ export const zDraftWorkflowRunPayload = z.object({ start_node_id: z.string(), }) +/** + * RagPipelineWorkflowPublishResponse + */ +export const zRagPipelineWorkflowPublishResponse = z.object({ + created_at: z.int(), + result: z.string(), +}) + /** * Parser */ @@ -304,10 +335,7 @@ export const zPostRagPipelineCustomizedTemplatesByTemplateIdPath = z.object({ /** * Success */ -export const zPostRagPipelineCustomizedTemplatesByTemplateIdResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostRagPipelineCustomizedTemplatesByTemplateIdResponse = zSimpleDataResponse export const zPostRagPipelineDatasetBody = zRagPipelineDatasetImportPayload @@ -423,12 +451,10 @@ export const zPostRagPipelinesByPipelineIdWorkflowRunsTasksByTaskIdStopPath = z. }) /** - * Success + * Task stopped successfully */ -export const zPostRagPipelinesByPipelineIdWorkflowRunsTasksByTaskIdStopResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostRagPipelinesByPipelineIdWorkflowRunsTasksByTaskIdStopResponse + = zSimpleResultResponse export const zGetRagPipelinesByPipelineIdWorkflowRunsByRunIdPath = z.object({ pipeline_id: z.string(), @@ -500,7 +526,7 @@ export const zPostRagPipelinesByPipelineIdWorkflowsDraftPath = z.object({ /** * Success */ -export const zPostRagPipelinesByPipelineIdWorkflowsDraftResponse = z.record(z.string(), z.unknown()) +export const zPostRagPipelinesByPipelineIdWorkflowsDraftResponse = zRagPipelineWorkflowSyncResponse export const zPostRagPipelinesByPipelineIdWorkflowsDraftDatasourceNodesByNodeIdRunBody = zDatasourceNodeRunPayload @@ -761,10 +787,8 @@ export const zPostRagPipelinesByPipelineIdWorkflowsPublishPath = z.object({ /** * Success */ -export const zPostRagPipelinesByPipelineIdWorkflowsPublishResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostRagPipelinesByPipelineIdWorkflowsPublishResponse + = zRagPipelineWorkflowPublishResponse export const zPostRagPipelinesByPipelineIdWorkflowsPublishedDatasourceNodesByNodeIdPreviewBody = zParser @@ -838,11 +862,11 @@ export const zDeleteRagPipelinesByPipelineIdWorkflowsByWorkflowIdPath = z.object }) /** - * Success + * Workflow deleted successfully */ export const zDeleteRagPipelinesByPipelineIdWorkflowsByWorkflowIdResponse = z.record( z.string(), - z.unknown(), + z.never(), ) export const zPatchRagPipelinesByPipelineIdWorkflowsByWorkflowIdPath = z.object({ @@ -863,7 +887,5 @@ export const zPostRagPipelinesByPipelineIdWorkflowsByWorkflowIdRestorePath = z.o /** * Success */ -export const zPostRagPipelinesByPipelineIdWorkflowsByWorkflowIdRestoreResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostRagPipelinesByPipelineIdWorkflowsByWorkflowIdRestoreResponse + = zRagPipelineWorkflowSyncResponse diff --git a/packages/contracts/generated/api/console/refresh-token/orpc.gen.ts b/packages/contracts/generated/api/console/refresh-token/orpc.gen.ts index 90d8aae968..4faa4d7d23 100644 --- a/packages/contracts/generated/api/console/refresh-token/orpc.gen.ts +++ b/packages/contracts/generated/api/console/refresh-token/orpc.gen.ts @@ -4,16 +4,8 @@ import { oc } from '@orpc/contract' import { zPostRefreshTokenResponse } from './zod.gen' -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postRefreshToken', diff --git a/packages/contracts/generated/api/console/refresh-token/types.gen.ts b/packages/contracts/generated/api/console/refresh-token/types.gen.ts index 15c939b947..81f76a749c 100644 --- a/packages/contracts/generated/api/console/refresh-token/types.gen.ts +++ b/packages/contracts/generated/api/console/refresh-token/types.gen.ts @@ -4,6 +4,10 @@ export type ClientOptions = { baseUrl: `${string}://${string}/console/api` | (string & {}) } +export type SimpleResultResponse = { + result: string +} + export type PostRefreshTokenData = { body?: never path?: never @@ -12,9 +16,7 @@ export type PostRefreshTokenData = { } export type PostRefreshTokenResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostRefreshTokenResponse = PostRefreshTokenResponses[keyof PostRefreshTokenResponses] diff --git a/packages/contracts/generated/api/console/refresh-token/zod.gen.ts b/packages/contracts/generated/api/console/refresh-token/zod.gen.ts index d76067552c..f10ac4c9e0 100644 --- a/packages/contracts/generated/api/console/refresh-token/zod.gen.ts +++ b/packages/contracts/generated/api/console/refresh-token/zod.gen.ts @@ -2,7 +2,14 @@ import * as z from 'zod' +/** + * SimpleResultResponse + */ +export const zSimpleResultResponse = z.object({ + result: z.string(), +}) + /** * Success */ -export const zPostRefreshTokenResponse = z.record(z.string(), z.unknown()) +export const zPostRefreshTokenResponse = zSimpleResultResponse diff --git a/packages/contracts/generated/api/console/remote-files/orpc.gen.ts b/packages/contracts/generated/api/console/remote-files/orpc.gen.ts index d8e493b759..afb26cd84a 100644 --- a/packages/contracts/generated/api/console/remote-files/orpc.gen.ts +++ b/packages/contracts/generated/api/console/remote-files/orpc.gen.ts @@ -6,41 +6,28 @@ import * as z from 'zod' import { zGetRemoteFilesByUrlPath, zGetRemoteFilesByUrlResponse, + zPostRemoteFilesUploadBody, zPostRemoteFilesUploadResponse, } from './zod.gen' -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postRemoteFilesUpload', path: '/remote-files/upload', + successStatus: 201, tags: ['console'], }) + .input(z.object({ body: zPostRemoteFilesUploadBody })) .output(zPostRemoteFilesUploadResponse) export const upload = { post, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getRemoteFilesByUrl', diff --git a/packages/contracts/generated/api/console/remote-files/types.gen.ts b/packages/contracts/generated/api/console/remote-files/types.gen.ts index ea61592a76..4162f98f93 100644 --- a/packages/contracts/generated/api/console/remote-files/types.gen.ts +++ b/packages/contracts/generated/api/console/remote-files/types.gen.ts @@ -4,17 +4,35 @@ export type ClientOptions = { baseUrl: `${string}://${string}/console/api` | (string & {}) } +export type RemoteFileUploadPayload = { + url: string +} + +export type FileWithSignedUrl = { + created_at: number | null + created_by: string | null + extension: string | null + id: string + mime_type: string | null + name: string + size: number + url: string | null +} + +export type RemoteFileInfo = { + file_length: number + file_type: string +} + export type PostRemoteFilesUploadData = { - body?: never + body: RemoteFileUploadPayload path?: never query?: never url: '/remote-files/upload' } export type PostRemoteFilesUploadResponses = { - 200: { - [key: string]: unknown - } + 201: FileWithSignedUrl } export type PostRemoteFilesUploadResponse @@ -30,9 +48,7 @@ export type GetRemoteFilesByUrlData = { } export type GetRemoteFilesByUrlResponses = { - 200: { - [key: string]: unknown - } + 200: RemoteFileInfo } export type GetRemoteFilesByUrlResponse diff --git a/packages/contracts/generated/api/console/remote-files/zod.gen.ts b/packages/contracts/generated/api/console/remote-files/zod.gen.ts index cee96cf65f..f389299059 100644 --- a/packages/contracts/generated/api/console/remote-files/zod.gen.ts +++ b/packages/contracts/generated/api/console/remote-files/zod.gen.ts @@ -3,9 +3,40 @@ import * as z from 'zod' /** - * Success + * RemoteFileUploadPayload */ -export const zPostRemoteFilesUploadResponse = z.record(z.string(), z.unknown()) +export const zRemoteFileUploadPayload = z.object({ + url: z.string(), +}) + +/** + * FileWithSignedUrl + */ +export const zFileWithSignedUrl = z.object({ + created_at: z.int().nullable(), + created_by: z.string().nullable(), + extension: z.string().nullable(), + id: z.string(), + mime_type: z.string().nullable(), + name: z.string(), + size: z.int(), + url: z.string().nullable(), +}) + +/** + * RemoteFileInfo + */ +export const zRemoteFileInfo = z.object({ + file_length: z.int(), + file_type: z.string(), +}) + +export const zPostRemoteFilesUploadBody = zRemoteFileUploadPayload + +/** + * File uploaded successfully + */ +export const zPostRemoteFilesUploadResponse = zFileWithSignedUrl export const zGetRemoteFilesByUrlPath = z.object({ url: z.string(), @@ -14,4 +45,4 @@ export const zGetRemoteFilesByUrlPath = z.object({ /** * Success */ -export const zGetRemoteFilesByUrlResponse = z.record(z.string(), z.unknown()) +export const zGetRemoteFilesByUrlResponse = zRemoteFileInfo diff --git a/packages/contracts/generated/api/console/reset-password/orpc.gen.ts b/packages/contracts/generated/api/console/reset-password/orpc.gen.ts index 2c049efb9d..93701280db 100644 --- a/packages/contracts/generated/api/console/reset-password/orpc.gen.ts +++ b/packages/contracts/generated/api/console/reset-password/orpc.gen.ts @@ -5,16 +5,8 @@ import * as z from 'zod' import { zPostResetPasswordBody, zPostResetPasswordResponse } from './zod.gen' -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postResetPassword', diff --git a/packages/contracts/generated/api/console/reset-password/types.gen.ts b/packages/contracts/generated/api/console/reset-password/types.gen.ts index 6c2467aab4..74e5d50ba6 100644 --- a/packages/contracts/generated/api/console/reset-password/types.gen.ts +++ b/packages/contracts/generated/api/console/reset-password/types.gen.ts @@ -9,6 +9,11 @@ export type EmailPayload = { language?: string | null } +export type SimpleResultDataResponse = { + data: string + result: string +} + export type PostResetPasswordData = { body: EmailPayload path?: never @@ -17,9 +22,7 @@ export type PostResetPasswordData = { } export type PostResetPasswordResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultDataResponse } export type PostResetPasswordResponse = PostResetPasswordResponses[keyof PostResetPasswordResponses] diff --git a/packages/contracts/generated/api/console/reset-password/zod.gen.ts b/packages/contracts/generated/api/console/reset-password/zod.gen.ts index 055ed9e127..707094ef8f 100644 --- a/packages/contracts/generated/api/console/reset-password/zod.gen.ts +++ b/packages/contracts/generated/api/console/reset-password/zod.gen.ts @@ -10,9 +10,17 @@ export const zEmailPayload = z.object({ language: z.string().nullish(), }) +/** + * SimpleResultDataResponse + */ +export const zSimpleResultDataResponse = z.object({ + data: z.string(), + result: z.string(), +}) + export const zPostResetPasswordBody = zEmailPayload /** * Success */ -export const zPostResetPasswordResponse = z.record(z.string(), z.unknown()) +export const zPostResetPasswordResponse = zSimpleResultDataResponse diff --git a/packages/contracts/generated/api/console/system-features/orpc.gen.ts b/packages/contracts/generated/api/console/system-features/orpc.gen.ts index a3667f791f..5c0a475585 100644 --- a/packages/contracts/generated/api/console/system-features/orpc.gen.ts +++ b/packages/contracts/generated/api/console/system-features/orpc.gen.ts @@ -14,16 +14,11 @@ import { zGetSystemFeaturesResponse } from './zod.gen' * Authentication would create circular dependency (can't login without dashboard loading). * * Only non-sensitive configuration data should be returned by this endpoint. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get = oc .route({ - deprecated: true, description: - 'Get system-wide feature configuration\nNOTE: This endpoint is unauthenticated by design, as it provides system features\ndata required for dashboard initialization.\n\nAuthentication would create circular dependency (can\'t login without dashboard loading).\n\nOnly non-sensitive configuration data should be returned by this endpoint.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + 'Get system-wide feature configuration\nNOTE: This endpoint is unauthenticated by design, as it provides system features\ndata required for dashboard initialization.\n\nAuthentication would create circular dependency (can\'t login without dashboard loading).\n\nOnly non-sensitive configuration data should be returned by this endpoint.', inputStructure: 'detailed', method: 'GET', operationId: 'getSystemFeatures', diff --git a/packages/contracts/generated/api/console/system-features/types.gen.ts b/packages/contracts/generated/api/console/system-features/types.gen.ts index 1f14d19c51..3ef9c6e30e 100644 --- a/packages/contracts/generated/api/console/system-features/types.gen.ts +++ b/packages/contracts/generated/api/console/system-features/types.gen.ts @@ -4,10 +4,78 @@ export type ClientOptions = { baseUrl: `${string}://${string}/console/api` | (string & {}) } -export type SystemFeatureResponse = { - features?: { - [key: string]: unknown - } +export type SystemFeatureModel = { + app_dsl_version: string + branding: BrandingModel + enable_change_email: boolean + enable_collaboration_mode: boolean + enable_creators_platform: boolean + enable_email_code_login: boolean + enable_email_password_login: boolean + enable_explore_banner: boolean + enable_marketplace: boolean + enable_social_oauth_login: boolean + enable_trial_app: boolean + is_allow_create_workspace: boolean + is_allow_register: boolean + is_email_setup: boolean + license: LicenseModel + max_plugin_package_size: number + plugin_installation_permission: PluginInstallationPermissionModel + plugin_manager: PluginManagerModel + sso_enforced_for_signin: boolean + sso_enforced_for_signin_protocol: string + trial_models: Array + webapp_auth: WebAppAuthModel +} + +export type BrandingModel = { + application_title: string + enabled: boolean + favicon: string + login_page_logo: string + workspace_logo: string +} + +export type LicenseModel = { + expired_at: string + status: LicenseStatus + workspaces: LicenseLimitationModel +} + +export type PluginInstallationPermissionModel = { + plugin_installation_scope: PluginInstallationScope + restrict_to_marketplace_only: boolean +} + +export type PluginManagerModel = { + enabled: boolean +} + +export type WebAppAuthModel = { + allow_email_code_login: boolean + allow_email_password_login: boolean + allow_sso: boolean + enabled: boolean + sso_config: WebAppAuthSsoModel +} + +export type LicenseStatus = 'active' | 'expired' | 'expiring' | 'inactive' | 'lost' | 'none' + +export type LicenseLimitationModel = { + enabled: boolean + limit: number + size: number +} + +export type PluginInstallationScope + = | 'all' + | 'none' + | 'official_and_specific_partners' + | 'official_only' + +export type WebAppAuthSsoModel = { + protocol: string } export type GetSystemFeaturesData = { @@ -18,7 +86,7 @@ export type GetSystemFeaturesData = { } export type GetSystemFeaturesResponses = { - 200: SystemFeatureResponse + 200: SystemFeatureModel } export type GetSystemFeaturesResponse = GetSystemFeaturesResponses[keyof GetSystemFeaturesResponses] diff --git a/packages/contracts/generated/api/console/system-features/zod.gen.ts b/packages/contracts/generated/api/console/system-features/zod.gen.ts index 58f353b512..b3bba61c3f 100644 --- a/packages/contracts/generated/api/console/system-features/zod.gen.ts +++ b/packages/contracts/generated/api/console/system-features/zod.gen.ts @@ -2,11 +2,116 @@ import * as z from 'zod' -export const zSystemFeatureResponse = z.object({ - features: z.record(z.string(), z.unknown()).optional(), +/** + * BrandingModel + */ +export const zBrandingModel = z.object({ + application_title: z.string().default(''), + enabled: z.boolean().default(false), + favicon: z.string().default(''), + login_page_logo: z.string().default(''), + workspace_logo: z.string().default(''), +}) + +/** + * PluginManagerModel + */ +export const zPluginManagerModel = z.object({ + enabled: z.boolean().default(false), +}) + +/** + * LicenseStatus + */ +export const zLicenseStatus = z.enum(['active', 'expired', 'expiring', 'inactive', 'lost', 'none']) + +/** + * LicenseLimitationModel + * + * - enabled: whether this limit is enforced + * - size: current usage count + * - limit: maximum allowed count; 0 means unlimited + */ +export const zLicenseLimitationModel = z.object({ + enabled: z.boolean().default(false), + limit: z.int().default(0), + size: z.int().default(0), +}) + +/** + * LicenseModel + */ +export const zLicenseModel = z.object({ + expired_at: z.string().default(''), + status: zLicenseStatus, + workspaces: zLicenseLimitationModel, +}) + +/** + * PluginInstallationScope + */ +export const zPluginInstallationScope = z.enum([ + 'all', + 'none', + 'official_and_specific_partners', + 'official_only', +]) + +/** + * PluginInstallationPermissionModel + */ +export const zPluginInstallationPermissionModel = z.object({ + plugin_installation_scope: zPluginInstallationScope, + restrict_to_marketplace_only: z.boolean().default(false), +}) + +/** + * WebAppAuthSSOModel + */ +export const zWebAppAuthSsoModel = z.object({ + protocol: z.string().default(''), +}) + +/** + * WebAppAuthModel + */ +export const zWebAppAuthModel = z.object({ + allow_email_code_login: z.boolean().default(false), + allow_email_password_login: z.boolean().default(false), + allow_sso: z.boolean().default(false), + enabled: z.boolean().default(false), + sso_config: zWebAppAuthSsoModel, +}) + +/** + * SystemFeatureModel + */ +export const zSystemFeatureModel = z.object({ + app_dsl_version: z.string().default(''), + branding: zBrandingModel, + enable_change_email: z.boolean().default(true), + enable_collaboration_mode: z.boolean().default(true), + enable_creators_platform: z.boolean().default(false), + enable_email_code_login: z.boolean().default(false), + enable_email_password_login: z.boolean().default(true), + enable_explore_banner: z.boolean().default(false), + enable_marketplace: z.boolean().default(false), + enable_social_oauth_login: z.boolean().default(false), + enable_trial_app: z.boolean().default(false), + is_allow_create_workspace: z.boolean().default(false), + is_allow_register: z.boolean().default(false), + is_email_setup: z.boolean().default(false), + license: zLicenseModel, + max_plugin_package_size: z.int().default(15728640), + plugin_installation_permission: zPluginInstallationPermissionModel, + plugin_manager: zPluginManagerModel, + sso_enforced_for_signin: z.boolean().default(false), + sso_enforced_for_signin_protocol: z.string().default(''), + trial_models: z.array(z.string()).default([]), + webapp_auth: zWebAppAuthModel, }) /** * Success */ -export const zGetSystemFeaturesResponse = zSystemFeatureResponse +export const zGetSystemFeaturesResponse = zSystemFeatureModel diff --git a/packages/contracts/generated/api/console/tag-bindings/orpc.gen.ts b/packages/contracts/generated/api/console/tag-bindings/orpc.gen.ts index 154c75d917..a3c7f5ed88 100644 --- a/packages/contracts/generated/api/console/tag-bindings/orpc.gen.ts +++ b/packages/contracts/generated/api/console/tag-bindings/orpc.gen.ts @@ -12,16 +12,10 @@ import { /** * Remove one or more tag bindings from a target. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post = oc .route({ - deprecated: true, - description: - 'Remove one or more tag bindings from a target.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Remove one or more tag bindings from a target.', inputStructure: 'detailed', method: 'POST', operationId: 'postTagBindingsRemove', @@ -35,16 +29,8 @@ export const remove = { post, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post2 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postTagBindings', diff --git a/packages/contracts/generated/api/console/tag-bindings/types.gen.ts b/packages/contracts/generated/api/console/tag-bindings/types.gen.ts index 1896ccd366..98f7424449 100644 --- a/packages/contracts/generated/api/console/tag-bindings/types.gen.ts +++ b/packages/contracts/generated/api/console/tag-bindings/types.gen.ts @@ -10,6 +10,10 @@ export type TagBindingPayload = { type: TagType } +export type SimpleResultResponse = { + result: string +} + export type TagBindingRemovePayload = { tag_ids: Array target_id: string @@ -26,9 +30,7 @@ export type PostTagBindingsData = { } export type PostTagBindingsResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostTagBindingsResponse = PostTagBindingsResponses[keyof PostTagBindingsResponses] @@ -41,9 +43,7 @@ export type PostTagBindingsRemoveData = { } export type PostTagBindingsRemoveResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostTagBindingsRemoveResponse diff --git a/packages/contracts/generated/api/console/tag-bindings/zod.gen.ts b/packages/contracts/generated/api/console/tag-bindings/zod.gen.ts index 72e2608b95..a734d0874f 100644 --- a/packages/contracts/generated/api/console/tag-bindings/zod.gen.ts +++ b/packages/contracts/generated/api/console/tag-bindings/zod.gen.ts @@ -2,6 +2,13 @@ import * as z from 'zod' +/** + * SimpleResultResponse + */ +export const zSimpleResultResponse = z.object({ + result: z.string(), +}) + /** * TagType * @@ -32,11 +39,11 @@ export const zPostTagBindingsBody = zTagBindingPayload /** * Success */ -export const zPostTagBindingsResponse = z.record(z.string(), z.unknown()) +export const zPostTagBindingsResponse = zSimpleResultResponse export const zPostTagBindingsRemoveBody = zTagBindingRemovePayload /** * Success */ -export const zPostTagBindingsRemoveResponse = z.record(z.string(), z.unknown()) +export const zPostTagBindingsRemoveResponse = zSimpleResultResponse diff --git a/packages/contracts/generated/api/console/tags/orpc.gen.ts b/packages/contracts/generated/api/console/tags/orpc.gen.ts index bc2ac4ef5c..6e3fc681aa 100644 --- a/packages/contracts/generated/api/console/tags/orpc.gen.ts +++ b/packages/contracts/generated/api/console/tags/orpc.gen.ts @@ -15,35 +15,20 @@ import { zPostTagsResponse, } from './zod.gen' -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete_ = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteTagsByTagId', path: '/tags/{tag_id}', + successStatus: 204, tags: ['console'], }) .input(z.object({ params: zDeleteTagsByTagIdPath })) .output(zDeleteTagsByTagIdResponse) -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const patch = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'PATCH', operationId: 'patchTagsByTagId', @@ -69,16 +54,8 @@ export const get = oc .input(z.object({ query: zGetTagsQuery.optional() })) .output(zGetTagsResponse) -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postTags', diff --git a/packages/contracts/generated/api/console/tags/types.gen.ts b/packages/contracts/generated/api/console/tags/types.gen.ts index 3e1bac75c4..c43abdbb00 100644 --- a/packages/contracts/generated/api/console/tags/types.gen.ts +++ b/packages/contracts/generated/api/console/tags/types.gen.ts @@ -46,9 +46,7 @@ export type PostTagsData = { } export type PostTagsResponses = { - 200: { - [key: string]: unknown - } + 200: TagResponse } export type PostTagsResponse = PostTagsResponses[keyof PostTagsResponses] @@ -63,8 +61,8 @@ export type DeleteTagsByTagIdData = { } export type DeleteTagsByTagIdResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -80,9 +78,7 @@ export type PatchTagsByTagIdData = { } export type PatchTagsByTagIdResponses = { - 200: { - [key: string]: unknown - } + 200: TagResponse } export type PatchTagsByTagIdResponse = PatchTagsByTagIdResponses[keyof PatchTagsByTagIdResponses] diff --git a/packages/contracts/generated/api/console/tags/zod.gen.ts b/packages/contracts/generated/api/console/tags/zod.gen.ts index 65c5b06b63..263b67b083 100644 --- a/packages/contracts/generated/api/console/tags/zod.gen.ts +++ b/packages/contracts/generated/api/console/tags/zod.gen.ts @@ -49,16 +49,16 @@ export const zPostTagsBody = zTagBasePayload /** * Success */ -export const zPostTagsResponse = z.record(z.string(), z.unknown()) +export const zPostTagsResponse = zTagResponse export const zDeleteTagsByTagIdPath = z.object({ tag_id: z.string(), }) /** - * Success + * Tag deleted successfully */ -export const zDeleteTagsByTagIdResponse = z.record(z.string(), z.unknown()) +export const zDeleteTagsByTagIdResponse = z.record(z.string(), z.never()) export const zPatchTagsByTagIdBody = zTagUpdateRequestPayload @@ -69,4 +69,4 @@ export const zPatchTagsByTagIdPath = z.object({ /** * Success */ -export const zPatchTagsByTagIdResponse = z.record(z.string(), z.unknown()) +export const zPatchTagsByTagIdResponse = zTagResponse diff --git a/packages/contracts/generated/api/console/workspaces/orpc.gen.ts b/packages/contracts/generated/api/console/workspaces/orpc.gen.ts index f4460bb181..242c2ccfa8 100644 --- a/packages/contracts/generated/api/console/workspaces/orpc.gen.ts +++ b/packages/contracts/generated/api/console/workspaces/orpc.gen.ts @@ -382,16 +382,8 @@ export const get4 = oc .input(z.object({ query: zGetWorkspacesCurrentDefaultModelQuery })) .output(zGetWorkspacesCurrentDefaultModelResponse) -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postWorkspacesCurrentDefaultModel', @@ -669,16 +661,8 @@ export const inviteEmail = { post: post8, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post9 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postWorkspacesCurrentMembersOwnerTransferCheck', @@ -692,16 +676,8 @@ export const ownerTransferCheck = { post: post9, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post10 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postWorkspacesCurrentMembersSendOwnerTransferConfirmEmail', @@ -837,16 +813,8 @@ export const checkoutUrl = { get: get8, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post12 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postWorkspacesCurrentModelProvidersByProviderCredentialsSwitch', @@ -893,20 +861,13 @@ export const validate = { post: post13, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete4 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteWorkspacesCurrentModelProvidersByProviderCredentials', path: '/workspaces/current/model-providers/{provider}/credentials', + successStatus: 204, tags: ['console'], }) .input( @@ -998,16 +959,8 @@ export const credentials = { validate, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post15 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postWorkspacesCurrentModelProvidersByProviderModelsCredentialsSwitch', @@ -1054,20 +1007,13 @@ export const validate2 = { post: post16, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete5 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteWorkspacesCurrentModelProvidersByProviderModelsCredentials', path: '/workspaces/current/model-providers/{provider}/models/credentials', + successStatus: 204, tags: ['console'], }) .input( @@ -1159,16 +1105,8 @@ export const credentials2 = { validate: validate2, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const patch2 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'PATCH', operationId: 'patchWorkspacesCurrentModelProvidersByProviderModelsDisable', @@ -1187,16 +1125,8 @@ export const disable2 = { patch: patch2, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const patch3 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'PATCH', operationId: 'patchWorkspacesCurrentModelProvidersByProviderModelsEnable', @@ -1316,20 +1246,13 @@ export const parameterRules = { get: get11, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete6 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteWorkspacesCurrentModelProvidersByProviderModels', path: '/workspaces/current/model-providers/{provider}/models', + successStatus: 204, tags: ['console'], }) .input( @@ -1394,16 +1317,8 @@ export const models = { parameterRules, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post21 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postWorkspacesCurrentModelProvidersByProviderPreferredProviderType', @@ -1488,16 +1403,11 @@ export const models2 = { * Get workspace permission settings * * Returns permission flags that control workspace features like member invitations and owner transfer. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get15 = oc .route({ - deprecated: true, description: - 'Returns permission flags that control workspace features like member invitations and owner transfer.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + 'Returns permission flags that control workspace features like member invitations and owner transfer.', inputStructure: 'detailed', method: 'GET', operationId: 'getWorkspacesCurrentPermission', @@ -1534,16 +1444,8 @@ export const asset = { get: get16, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get17 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getWorkspacesCurrentPluginDebuggingKey', @@ -1835,16 +1737,8 @@ export const parameters = { dynamicOptionsWithCredentials, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post28 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postWorkspacesCurrentPluginPermissionChange', @@ -1986,16 +1880,8 @@ export const readme = { get: get25, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post31 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postWorkspacesCurrentPluginTasksDeleteAll', @@ -2008,16 +1894,8 @@ export const deleteAll = { post: post31, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post32 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postWorkspacesCurrentPluginTasksByTaskIdDeleteByIdentifier', @@ -2031,16 +1909,8 @@ export const byIdentifier = { post: post32, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post33 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postWorkspacesCurrentPluginTasksByTaskIdDelete', @@ -2104,16 +1974,8 @@ export const tasks = { byTaskId, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const post34 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postWorkspacesCurrentPluginUninstall', @@ -2952,16 +2814,8 @@ export const update4 = { byProviderId: byProviderId2, } -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const delete11 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'DELETE', operationId: 'deleteWorkspacesCurrentToolProviderMcp', @@ -3737,16 +3591,9 @@ export const byProvider3 = { /** * Delete a subscription instance - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post61 = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postWorkspacesCurrentTriggerProviderBySubscriptionIdSubscriptionsDelete', diff --git a/packages/contracts/generated/api/console/workspaces/types.gen.ts b/packages/contracts/generated/api/console/workspaces/types.gen.ts index 3d2dde4482..cecf1f1284 100644 --- a/packages/contracts/generated/api/console/workspaces/types.gen.ts +++ b/packages/contracts/generated/api/console/workspaces/types.gen.ts @@ -29,6 +29,10 @@ export type ParserPostDefault = { model_settings: Array } +export type SimpleResultResponse = { + result: string +} + export type EndpointCreatePayload = { name: string plugin_unique_identifier: string @@ -99,10 +103,21 @@ export type OwnerTransferCheckPayload = { token: string } +export type VerificationTokenResponse = { + email: string + is_valid: boolean + token: string +} + export type OwnerTransferEmailPayload = { language?: string | null } +export type SimpleResultDataResponse = { + data: string + result: string +} + export type OwnerTransferPayload = { token: string } @@ -204,6 +219,18 @@ export type ParserPreferredProviderType = { preferred_provider_type: 'custom' | 'system' } +export type WorkspacePermissionResponse = { + allow_member_invite: boolean + allow_owner_transfer: boolean + workspace_id: string +} + +export type PluginDebuggingKeyResponse = { + host: string + key: string + port: number +} + export type ParserGithubInstall = { package: string plugin_unique_identifier: string @@ -235,6 +262,10 @@ export type ParserPermissionChange = { install_permission: InstallPermission } +export type SuccessResponse = { + success: boolean +} + export type ParserExcludePlugin = { plugin_id: string } @@ -634,9 +665,7 @@ export type PostWorkspacesCurrentDefaultModelData = { } export type PostWorkspacesCurrentDefaultModelResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostWorkspacesCurrentDefaultModelResponse @@ -903,9 +932,7 @@ export type PostWorkspacesCurrentMembersOwnerTransferCheckData = { } export type PostWorkspacesCurrentMembersOwnerTransferCheckResponses = { - 200: { - [key: string]: unknown - } + 200: VerificationTokenResponse } export type PostWorkspacesCurrentMembersOwnerTransferCheckResponse @@ -919,9 +946,7 @@ export type PostWorkspacesCurrentMembersSendOwnerTransferConfirmEmailData = { } export type PostWorkspacesCurrentMembersSendOwnerTransferConfirmEmailResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultDataResponse } export type PostWorkspacesCurrentMembersSendOwnerTransferConfirmEmailResponse @@ -1027,8 +1052,8 @@ export type DeleteWorkspacesCurrentModelProvidersByProviderCredentialsData = { } export type DeleteWorkspacesCurrentModelProvidersByProviderCredentialsResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -1101,9 +1126,7 @@ export type PostWorkspacesCurrentModelProvidersByProviderCredentialsSwitchData = } export type PostWorkspacesCurrentModelProvidersByProviderCredentialsSwitchResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostWorkspacesCurrentModelProvidersByProviderCredentialsSwitchResponse @@ -1137,8 +1160,8 @@ export type DeleteWorkspacesCurrentModelProvidersByProviderModelsData = { } export type DeleteWorkspacesCurrentModelProvidersByProviderModelsResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -1191,8 +1214,8 @@ export type DeleteWorkspacesCurrentModelProvidersByProviderModelsCredentialsData } export type DeleteWorkspacesCurrentModelProvidersByProviderModelsCredentialsResponses = { - 200: { - [key: string]: unknown + 204: { + [key: string]: never } } @@ -1268,9 +1291,7 @@ export type PostWorkspacesCurrentModelProvidersByProviderModelsCredentialsSwitch } export type PostWorkspacesCurrentModelProvidersByProviderModelsCredentialsSwitchResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostWorkspacesCurrentModelProvidersByProviderModelsCredentialsSwitchResponse @@ -1304,9 +1325,7 @@ export type PatchWorkspacesCurrentModelProvidersByProviderModelsDisableData = { } export type PatchWorkspacesCurrentModelProvidersByProviderModelsDisableResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PatchWorkspacesCurrentModelProvidersByProviderModelsDisableResponse @@ -1322,9 +1341,7 @@ export type PatchWorkspacesCurrentModelProvidersByProviderModelsEnableData = { } export type PatchWorkspacesCurrentModelProvidersByProviderModelsEnableResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PatchWorkspacesCurrentModelProvidersByProviderModelsEnableResponse @@ -1401,9 +1418,7 @@ export type PostWorkspacesCurrentModelProvidersByProviderPreferredProviderTypeDa } export type PostWorkspacesCurrentModelProvidersByProviderPreferredProviderTypeResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostWorkspacesCurrentModelProvidersByProviderPreferredProviderTypeResponse @@ -1435,9 +1450,7 @@ export type GetWorkspacesCurrentPermissionData = { } export type GetWorkspacesCurrentPermissionResponses = { - 200: { - [key: string]: unknown - } + 200: WorkspacePermissionResponse } export type GetWorkspacesCurrentPermissionResponse @@ -1470,9 +1483,7 @@ export type GetWorkspacesCurrentPluginDebuggingKeyData = { } export type GetWorkspacesCurrentPluginDebuggingKeyResponses = { - 200: { - [key: string]: unknown - } + 200: PluginDebuggingKeyResponse } export type GetWorkspacesCurrentPluginDebuggingKeyResponse @@ -1679,9 +1690,7 @@ export type PostWorkspacesCurrentPluginPermissionChangeData = { } export type PostWorkspacesCurrentPluginPermissionChangeResponses = { - 200: { - [key: string]: unknown - } + 200: SuccessResponse } export type PostWorkspacesCurrentPluginPermissionChangeResponse @@ -1797,9 +1806,7 @@ export type PostWorkspacesCurrentPluginTasksDeleteAllData = { } export type PostWorkspacesCurrentPluginTasksDeleteAllResponses = { - 200: { - [key: string]: unknown - } + 200: SuccessResponse } export type PostWorkspacesCurrentPluginTasksDeleteAllResponse @@ -1833,9 +1840,7 @@ export type PostWorkspacesCurrentPluginTasksByTaskIdDeleteData = { } export type PostWorkspacesCurrentPluginTasksByTaskIdDeleteResponses = { - 200: { - [key: string]: unknown - } + 200: SuccessResponse } export type PostWorkspacesCurrentPluginTasksByTaskIdDeleteResponse @@ -1852,9 +1857,7 @@ export type PostWorkspacesCurrentPluginTasksByTaskIdDeleteByIdentifierData = { } export type PostWorkspacesCurrentPluginTasksByTaskIdDeleteByIdentifierResponses = { - 200: { - [key: string]: unknown - } + 200: SuccessResponse } export type PostWorkspacesCurrentPluginTasksByTaskIdDeleteByIdentifierResponse @@ -1868,9 +1871,7 @@ export type PostWorkspacesCurrentPluginUninstallData = { } export type PostWorkspacesCurrentPluginUninstallResponses = { - 200: { - [key: string]: unknown - } + 200: SuccessResponse } export type PostWorkspacesCurrentPluginUninstallResponse @@ -2363,9 +2364,7 @@ export type DeleteWorkspacesCurrentToolProviderMcpData = { } export type DeleteWorkspacesCurrentToolProviderMcpResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type DeleteWorkspacesCurrentToolProviderMcpResponse @@ -2895,9 +2894,7 @@ export type PostWorkspacesCurrentTriggerProviderBySubscriptionIdSubscriptionsDel } export type PostWorkspacesCurrentTriggerProviderBySubscriptionIdSubscriptionsDeleteResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostWorkspacesCurrentTriggerProviderBySubscriptionIdSubscriptionsDeleteResponse diff --git a/packages/contracts/generated/api/console/workspaces/zod.gen.ts b/packages/contracts/generated/api/console/workspaces/zod.gen.ts index cf7a3d97c5..a27fc4f5b3 100644 --- a/packages/contracts/generated/api/console/workspaces/zod.gen.ts +++ b/packages/contracts/generated/api/console/workspaces/zod.gen.ts @@ -20,6 +20,13 @@ export const zTenantInfoResponse = z.object({ trial_end_reason: z.string().nullish(), }) +/** + * SimpleResultResponse + */ +export const zSimpleResultResponse = z.object({ + result: z.string(), +}) + /** * EndpointCreatePayload */ @@ -110,6 +117,15 @@ export const zOwnerTransferCheckPayload = z.object({ token: z.string(), }) +/** + * VerificationTokenResponse + */ +export const zVerificationTokenResponse = z.object({ + email: z.string(), + is_valid: z.boolean(), + token: z.string(), +}) + /** * OwnerTransferEmailPayload */ @@ -117,6 +133,14 @@ export const zOwnerTransferEmailPayload = z.object({ language: z.string().nullish(), }) +/** + * SimpleResultDataResponse + */ +export const zSimpleResultDataResponse = z.object({ + data: z.string(), + result: z.string(), +}) + /** * OwnerTransferPayload */ @@ -176,6 +200,24 @@ export const zParserPreferredProviderType = z.object({ preferred_provider_type: z.enum(['custom', 'system']), }) +/** + * WorkspacePermissionResponse + */ +export const zWorkspacePermissionResponse = z.object({ + allow_member_invite: z.boolean(), + allow_owner_transfer: z.boolean(), + workspace_id: z.string(), +}) + +/** + * PluginDebuggingKeyResponse + */ +export const zPluginDebuggingKeyResponse = z.object({ + host: z.string(), + key: z.string(), + port: z.int(), +}) + /** * ParserGithubInstall */ @@ -212,6 +254,13 @@ export const zParserDynamicOptionsWithCredentials = z.object({ provider: z.string(), }) +/** + * SuccessResponse + */ +export const zSuccessResponse = z.object({ + success: z.boolean(), +}) + /** * ParserExcludePlugin */ @@ -770,7 +819,7 @@ export const zPostWorkspacesCurrentDefaultModelBody = zParserPostDefault /** * Success */ -export const zPostWorkspacesCurrentDefaultModelResponse = z.record(z.string(), z.unknown()) +export const zPostWorkspacesCurrentDefaultModelResponse = zSimpleResultResponse export const zPostWorkspacesCurrentEndpointsBody = zEndpointCreatePayload @@ -872,10 +921,7 @@ export const zPostWorkspacesCurrentMembersOwnerTransferCheckBody = zOwnerTransfe /** * Success */ -export const zPostWorkspacesCurrentMembersOwnerTransferCheckResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostWorkspacesCurrentMembersOwnerTransferCheckResponse = zVerificationTokenResponse export const zPostWorkspacesCurrentMembersSendOwnerTransferConfirmEmailBody = zOwnerTransferEmailPayload @@ -883,10 +929,8 @@ export const zPostWorkspacesCurrentMembersSendOwnerTransferConfirmEmailBody /** * Success */ -export const zPostWorkspacesCurrentMembersSendOwnerTransferConfirmEmailResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostWorkspacesCurrentMembersSendOwnerTransferConfirmEmailResponse + = zSimpleResultDataResponse export const zDeleteWorkspacesCurrentMembersByMemberIdPath = z.object({ member_id: z.string(), @@ -954,11 +998,11 @@ export const zDeleteWorkspacesCurrentModelProvidersByProviderCredentialsPath = z }) /** - * Success + * Credential deleted successfully */ export const zDeleteWorkspacesCurrentModelProvidersByProviderCredentialsResponse = z.record( z.string(), - z.unknown(), + z.never(), ) export const zGetWorkspacesCurrentModelProvidersByProviderCredentialsPath = z.object({ @@ -1015,10 +1059,8 @@ export const zPostWorkspacesCurrentModelProvidersByProviderCredentialsSwitchPath /** * Success */ -export const zPostWorkspacesCurrentModelProvidersByProviderCredentialsSwitchResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostWorkspacesCurrentModelProvidersByProviderCredentialsSwitchResponse + = zSimpleResultResponse export const zPostWorkspacesCurrentModelProvidersByProviderCredentialsValidateBody = zParserCredentialValidate @@ -1042,11 +1084,11 @@ export const zDeleteWorkspacesCurrentModelProvidersByProviderModelsPath = z.obje }) /** - * Success + * Model deleted successfully */ export const zDeleteWorkspacesCurrentModelProvidersByProviderModelsResponse = z.record( z.string(), - z.unknown(), + z.never(), ) export const zGetWorkspacesCurrentModelProvidersByProviderModelsPath = z.object({ @@ -1083,11 +1125,11 @@ export const zDeleteWorkspacesCurrentModelProvidersByProviderModelsCredentialsPa }) /** - * Success + * Credential deleted successfully */ export const zDeleteWorkspacesCurrentModelProvidersByProviderModelsCredentialsResponse = z.record( z.string(), - z.unknown(), + z.never(), ) export const zGetWorkspacesCurrentModelProvidersByProviderModelsCredentialsPath = z.object({ @@ -1150,7 +1192,7 @@ export const zPostWorkspacesCurrentModelProvidersByProviderModelsCredentialsSwit * Success */ export const zPostWorkspacesCurrentModelProvidersByProviderModelsCredentialsSwitchResponse - = z.record(z.string(), z.unknown()) + = zSimpleResultResponse export const zPostWorkspacesCurrentModelProvidersByProviderModelsCredentialsValidateBody = zParserValidate @@ -1176,10 +1218,8 @@ export const zPatchWorkspacesCurrentModelProvidersByProviderModelsDisablePath = /** * Success */ -export const zPatchWorkspacesCurrentModelProvidersByProviderModelsDisableResponse = z.record( - z.string(), - z.unknown(), -) +export const zPatchWorkspacesCurrentModelProvidersByProviderModelsDisableResponse + = zSimpleResultResponse export const zPatchWorkspacesCurrentModelProvidersByProviderModelsEnableBody = zParserDeleteModels @@ -1190,10 +1230,8 @@ export const zPatchWorkspacesCurrentModelProvidersByProviderModelsEnablePath = z /** * Success */ -export const zPatchWorkspacesCurrentModelProvidersByProviderModelsEnableResponse = z.record( - z.string(), - z.unknown(), -) +export const zPatchWorkspacesCurrentModelProvidersByProviderModelsEnableResponse + = zSimpleResultResponse export const zPostWorkspacesCurrentModelProvidersByProviderModelsLoadBalancingConfigsCredentialsValidateBody = zLoadBalancingCredentialPayload @@ -1250,10 +1288,8 @@ export const zPostWorkspacesCurrentModelProvidersByProviderPreferredProviderType /** * Success */ -export const zPostWorkspacesCurrentModelProvidersByProviderPreferredProviderTypeResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostWorkspacesCurrentModelProvidersByProviderPreferredProviderTypeResponse + = zSimpleResultResponse export const zGetWorkspacesCurrentModelsModelTypesByModelTypePath = z.object({ model_type: z.string(), @@ -1270,7 +1306,7 @@ export const zGetWorkspacesCurrentModelsModelTypesByModelTypeResponse = z.record /** * Success */ -export const zGetWorkspacesCurrentPermissionResponse = z.record(z.string(), z.unknown()) +export const zGetWorkspacesCurrentPermissionResponse = zWorkspacePermissionResponse export const zGetWorkspacesCurrentPluginAssetQuery = z.object({ file_name: z.string(), @@ -1285,7 +1321,7 @@ export const zGetWorkspacesCurrentPluginAssetResponse = z.record(z.string(), z.u /** * Success */ -export const zGetWorkspacesCurrentPluginDebuggingKeyResponse = z.record(z.string(), z.unknown()) +export const zGetWorkspacesCurrentPluginDebuggingKeyResponse = zPluginDebuggingKeyResponse export const zGetWorkspacesCurrentPluginFetchManifestQuery = z.object({ plugin_unique_identifier: z.string(), @@ -1402,10 +1438,7 @@ export const zPostWorkspacesCurrentPluginPermissionChangeBody = zParserPermissio /** * Success */ -export const zPostWorkspacesCurrentPluginPermissionChangeResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostWorkspacesCurrentPluginPermissionChangeResponse = zSuccessResponse /** * Success @@ -1460,7 +1493,7 @@ export const zGetWorkspacesCurrentPluginTasksResponse = z.record(z.string(), z.u /** * Success */ -export const zPostWorkspacesCurrentPluginTasksDeleteAllResponse = z.record(z.string(), z.unknown()) +export const zPostWorkspacesCurrentPluginTasksDeleteAllResponse = zSuccessResponse export const zGetWorkspacesCurrentPluginTasksByTaskIdPath = z.object({ task_id: z.string(), @@ -1478,10 +1511,7 @@ export const zPostWorkspacesCurrentPluginTasksByTaskIdDeletePath = z.object({ /** * Success */ -export const zPostWorkspacesCurrentPluginTasksByTaskIdDeleteResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostWorkspacesCurrentPluginTasksByTaskIdDeleteResponse = zSuccessResponse export const zPostWorkspacesCurrentPluginTasksByTaskIdDeleteByIdentifierPath = z.object({ identifier: z.string(), @@ -1491,17 +1521,14 @@ export const zPostWorkspacesCurrentPluginTasksByTaskIdDeleteByIdentifierPath = z /** * Success */ -export const zPostWorkspacesCurrentPluginTasksByTaskIdDeleteByIdentifierResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostWorkspacesCurrentPluginTasksByTaskIdDeleteByIdentifierResponse = zSuccessResponse export const zPostWorkspacesCurrentPluginUninstallBody = zParserUninstall /** * Success */ -export const zPostWorkspacesCurrentPluginUninstallResponse = z.record(z.string(), z.unknown()) +export const zPostWorkspacesCurrentPluginUninstallResponse = zSuccessResponse export const zPostWorkspacesCurrentPluginUpgradeGithubBody = zParserGithubUpgrade @@ -1776,7 +1803,7 @@ export const zDeleteWorkspacesCurrentToolProviderMcpBody = zMcpProviderDeletePay /** * Success */ -export const zDeleteWorkspacesCurrentToolProviderMcpResponse = z.record(z.string(), z.unknown()) +export const zDeleteWorkspacesCurrentToolProviderMcpResponse = zSimpleResultResponse export const zPostWorkspacesCurrentToolProviderMcpBody = zMcpProviderCreatePayload @@ -2087,7 +2114,7 @@ export const zPostWorkspacesCurrentTriggerProviderBySubscriptionIdSubscriptionsD * Success */ export const zPostWorkspacesCurrentTriggerProviderBySubscriptionIdSubscriptionsDeleteResponse - = z.record(z.string(), z.unknown()) + = zSimpleResultResponse export const zPostWorkspacesCurrentTriggerProviderBySubscriptionIdSubscriptionsUpdateBody = zTriggerSubscriptionBuilderUpdatePayload diff --git a/packages/contracts/generated/api/readiness.json b/packages/contracts/generated/api/readiness.json index 78fed3ccfa..d0c14d3df2 100644 --- a/packages/contracts/generated/api/readiness.json +++ b/packages/contracts/generated/api/readiness.json @@ -1,15 +1,15 @@ { "surfaces": { "console": { - "notReady": 474, + "notReady": 365, "total": 570 }, "service": { - "notReady": 72, + "notReady": 60, "total": 88 }, "web": { - "notReady": 36, + "notReady": 20, "total": 41 } }, diff --git a/packages/contracts/generated/api/service/orpc.gen.ts b/packages/contracts/generated/api/service/orpc.gen.ts index 647cdd87b5..56471b73b9 100644 --- a/packages/contracts/generated/api/service/orpc.gen.ts +++ b/packages/contracts/generated/api/service/orpc.gen.ts @@ -199,16 +199,8 @@ import { zPutConversationsByCIdVariablesByVariableIdResponse, } from './zod.gen' -/** - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated - */ export const get = oc .route({ - deprecated: true, - description: - 'Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'GET', operationId: 'getRoot', @@ -450,16 +442,10 @@ export const audioToText = { * Stop a running chat message generation * * Stop a running chat message generation - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post4 = oc .route({ - deprecated: true, - description: - 'Stop a running chat message generation\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Stop a running chat message generation', inputStructure: 'detailed', method: 'POST', operationId: 'postChatMessagesByTaskIdStop', @@ -513,16 +499,10 @@ export const chatMessages = { * Stop a running completion task * * Stop a running completion task - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post6 = oc .route({ - deprecated: true, - description: - 'Stop a running completion task\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Stop a running completion task', inputStructure: 'detailed', method: 'POST', operationId: 'postCompletionMessagesByTaskIdStop', @@ -1027,16 +1007,10 @@ export const downloadZip = { * Update metadata for multiple documents * * Update metadata for multiple documents - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post18 = oc .route({ - deprecated: true, - description: - 'Update metadata for multiple documents\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Update metadata for multiple documents', inputStructure: 'detailed', method: 'POST', operationId: 'postDatasetsByDatasetIdDocumentsMetadata', @@ -1132,16 +1106,10 @@ export const byBatch = { /** * Get a signed download URL for a document's original uploaded file - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get9 = oc .route({ - deprecated: true, - description: - 'Get a signed download URL for a document\'s original uploaded file\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Get a signed download URL for a document\'s original uploaded file', inputStructure: 'detailed', method: 'GET', operationId: 'getDatasetsByDatasetIdDocumentsByDocumentIdDownload', @@ -1644,16 +1612,10 @@ export const hitTesting = { * Enable or disable built-in metadata field * * Enable or disable built-in metadata field - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post27 = oc .route({ - deprecated: true, - description: - 'Enable or disable built-in metadata field\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Enable or disable built-in metadata field', inputStructure: 'detailed', method: 'POST', operationId: 'postDatasetsByDatasetIdMetadataBuiltInByAction', @@ -2127,16 +2089,11 @@ export const datasets = { * Get an end user by ID * This endpoint is scoped to the current app token's tenant/app to prevent * cross-tenant/app access when an end-user ID is known. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get21 = oc .route({ - deprecated: true, description: - 'Get an end user by ID\nThis endpoint is scoped to the current app token\'s tenant/app to prevent\ncross-tenant/app access when an end-user ID is known.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + 'Get an end user by ID\nThis endpoint is scoped to the current app token\'s tenant/app to prevent\ncross-tenant/app access when an end-user ID is known.', inputStructure: 'detailed', method: 'GET', operationId: 'getEndUsersByEndUserId', @@ -2288,16 +2245,11 @@ export const form = { * * Get basic application information * Returns basic information about the application including name, description, tags, and mode. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get24 = oc .route({ - deprecated: true, description: - 'Get basic application information\nReturns basic information about the application including name, description, tags, and mode.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + 'Get basic application information\nReturns basic information about the application including name, description, tags, and mode.', inputStructure: 'detailed', method: 'GET', operationId: 'getInfo', @@ -2316,16 +2268,11 @@ export const info = { * * Submit feedback for a message * Allows users to rate messages as like/dislike and provide optional feedback content. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post35 = oc .route({ - deprecated: true, description: - 'Submit feedback for a message\nAllows users to rate messages as like/dislike and provide optional feedback content.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + 'Submit feedback for a message\nAllows users to rate messages as like/dislike and provide optional feedback content.', inputStructure: 'detailed', method: 'POST', operationId: 'postMessagesByMessageIdFeedbacks', @@ -2350,16 +2297,11 @@ export const feedbacks2 = { * * Get suggested follow-up questions for a message * Returns AI-generated follow-up questions based on the message content. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get25 = oc .route({ - deprecated: true, description: - 'Get suggested follow-up questions for a message\nReturns AI-generated follow-up questions based on the message content.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + 'Get suggested follow-up questions for a message\nReturns AI-generated follow-up questions based on the message content.', inputStructure: 'detailed', method: 'GET', operationId: 'getMessagesByMessageIdSuggested', @@ -2470,16 +2412,11 @@ export const parameters = { * * Get application site configuration * Returns the site configuration for the application including theme, icons, and text. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get29 = oc .route({ - deprecated: true, description: - 'Get application site configuration\nReturns the site configuration for the application including theme, icons, and text.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + 'Get application site configuration\nReturns the site configuration for the application including theme, icons, and text.', inputStructure: 'detailed', method: 'GET', operationId: 'getSite', @@ -2653,16 +2590,10 @@ export const run3 = { * Stop a running workflow task * * Stop a running workflow task - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post38 = oc .route({ - deprecated: true, - description: - 'Stop a running workflow task\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Stop a running workflow task', inputStructure: 'detailed', method: 'POST', operationId: 'postWorkflowsTasksByTaskIdStop', diff --git a/packages/contracts/generated/api/service/types.gen.ts b/packages/contracts/generated/api/service/types.gen.ts index ba6f822087..9918edcb2a 100644 --- a/packages/contracts/generated/api/service/types.gen.ts +++ b/packages/contracts/generated/api/service/types.gen.ts @@ -31,6 +31,14 @@ export type AnnotationReplyActionPayload = { score_threshold: number } +export type AppInfoResponse = { + author_name: string | null + description: string | null + mode: string + name: string + tags: Array +} + export type ChatRequestPayload = { auto_generate_name?: boolean conversation_id?: string | null @@ -232,6 +240,19 @@ export type DocumentTextUpdate = { text?: string | null } +export type EndUserDetail = { + app_id?: string | null + created_at: string + external_user_id?: string | null + id: string + is_anonymous: boolean + name?: string | null + session_id: string + tenant_id: string + type: string + updated_at: string +} + export type FeedbackListQuery = { limit?: number page?: number @@ -274,6 +295,12 @@ export type HumanInputFormSubmitPayload = { } } +export type IndexInfoResponse = { + api_version: string + server_version: string + welcome: string +} + export type JsonValue = unknown export type MessageFeedbackPayload = { @@ -339,6 +366,10 @@ export type RerankingModel = { reranking_provider_name?: string | null } +export type ResultResponse = { + result: string +} + export type RetrievalMethod = | 'full_text_search' | 'hybrid_search' @@ -408,6 +439,32 @@ export type SimpleEndUser = { type: string } +export type SimpleResultResponse = { + result: string +} + +export type SimpleResultStringListResponse = { + data: Array + result: string +} + +export type Site = { + chat_color_theme?: string | null + chat_color_theme_inverted: boolean + copyright?: string | null + custom_disclaimer?: string | null + default_language: string + description?: string | null + icon?: string | null + icon_background?: string | null + icon_type?: string | null + readonly icon_url: string | null + privacy_policy?: string | null + show_workflow_steps: boolean + title: string + use_icon_as_answer_icon: boolean +} + export type TagBindingPayload = { tag_ids: Array target_id: string @@ -439,6 +496,10 @@ export type TextToAudioPayload = { voice?: string | null } +export type UrlResponse = { + url: string +} + export type WeightKeywordSetting = { keyword_weight: number } @@ -525,6 +586,22 @@ export type WorkflowRunResponse = { workflow_id: string } +export type SiteWritable = { + chat_color_theme?: string | null + chat_color_theme_inverted: boolean + copyright?: string | null + custom_disclaimer?: string | null + default_language: string + description?: string | null + icon?: string | null + icon_background?: string | null + icon_type?: string | null + privacy_policy?: string | null + show_workflow_steps: boolean + title: string + use_icon_as_answer_icon: boolean +} + export type GetRootData = { body?: never path?: never @@ -533,9 +610,7 @@ export type GetRootData = { } export type GetRootResponses = { - 200: { - [key: string]: unknown - } + 200: IndexInfoResponse } export type GetRootResponse = GetRootResponses[keyof GetRootResponses] @@ -824,9 +899,7 @@ export type PostChatMessagesByTaskIdStopError = PostChatMessagesByTaskIdStopErrors[keyof PostChatMessagesByTaskIdStopErrors] export type PostChatMessagesByTaskIdStopResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostChatMessagesByTaskIdStopResponse @@ -888,9 +961,7 @@ export type PostCompletionMessagesByTaskIdStopError = PostCompletionMessagesByTaskIdStopErrors[keyof PostCompletionMessagesByTaskIdStopErrors] export type PostCompletionMessagesByTaskIdStopResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostCompletionMessagesByTaskIdStopResponse @@ -1595,9 +1666,7 @@ export type PostDatasetsByDatasetIdDocumentsMetadataError = PostDatasetsByDatasetIdDocumentsMetadataErrors[keyof PostDatasetsByDatasetIdDocumentsMetadataErrors] export type PostDatasetsByDatasetIdDocumentsMetadataResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostDatasetsByDatasetIdDocumentsMetadataResponse @@ -1632,9 +1701,7 @@ export type PatchDatasetsByDatasetIdDocumentsStatusByActionError = PatchDatasetsByDatasetIdDocumentsStatusByActionErrors[keyof PatchDatasetsByDatasetIdDocumentsStatusByActionErrors] export type PatchDatasetsByDatasetIdDocumentsStatusByActionResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PatchDatasetsByDatasetIdDocumentsStatusByActionResponse @@ -1796,9 +1863,7 @@ export type GetDatasetsByDatasetIdDocumentsByDocumentIdDownloadError = GetDatasetsByDatasetIdDocumentsByDocumentIdDownloadErrors[keyof GetDatasetsByDatasetIdDocumentsByDocumentIdDownloadErrors] export type GetDatasetsByDatasetIdDocumentsByDocumentIdDownloadResponses = { - 200: { - [key: string]: unknown - } + 200: UrlResponse } export type GetDatasetsByDatasetIdDocumentsByDocumentIdDownloadResponse @@ -2372,9 +2437,7 @@ export type PostDatasetsByDatasetIdMetadataBuiltInByActionError = PostDatasetsByDatasetIdMetadataBuiltInByActionErrors[keyof PostDatasetsByDatasetIdMetadataBuiltInByActionErrors] export type PostDatasetsByDatasetIdMetadataBuiltInByActionResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostDatasetsByDatasetIdMetadataBuiltInByActionResponse @@ -2605,9 +2668,7 @@ export type GetEndUsersByEndUserIdError = GetEndUsersByEndUserIdErrors[keyof GetEndUsersByEndUserIdErrors] export type GetEndUsersByEndUserIdResponses = { - 200: { - [key: string]: unknown - } + 200: EndUserDetail } export type GetEndUsersByEndUserIdResponse @@ -2766,9 +2827,7 @@ export type GetInfoErrors = { export type GetInfoError = GetInfoErrors[keyof GetInfoErrors] export type GetInfoResponses = { - 200: { - [key: string]: unknown - } + 200: AppInfoResponse } export type GetInfoResponse = GetInfoResponses[keyof GetInfoResponses] @@ -2825,9 +2884,7 @@ export type PostMessagesByMessageIdFeedbacksError = PostMessagesByMessageIdFeedbacksErrors[keyof PostMessagesByMessageIdFeedbacksErrors] export type PostMessagesByMessageIdFeedbacksResponses = { - 200: { - [key: string]: unknown - } + 200: ResultResponse } export type PostMessagesByMessageIdFeedbacksResponse @@ -2861,9 +2918,7 @@ export type GetMessagesByMessageIdSuggestedError = GetMessagesByMessageIdSuggestedErrors[keyof GetMessagesByMessageIdSuggestedErrors] export type GetMessagesByMessageIdSuggestedResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultStringListResponse } export type GetMessagesByMessageIdSuggestedResponse @@ -2940,9 +2995,7 @@ export type GetSiteErrors = { export type GetSiteError = GetSiteErrors[keyof GetSiteErrors] export type GetSiteResponses = { - 200: { - [key: string]: unknown - } + 200: Site } export type GetSiteResponse = GetSiteResponses[keyof GetSiteResponses] @@ -3125,9 +3178,7 @@ export type PostWorkflowsTasksByTaskIdStopError = PostWorkflowsTasksByTaskIdStopErrors[keyof PostWorkflowsTasksByTaskIdStopErrors] export type PostWorkflowsTasksByTaskIdStopResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostWorkflowsTasksByTaskIdStopResponse diff --git a/packages/contracts/generated/api/service/zod.gen.ts b/packages/contracts/generated/api/service/zod.gen.ts index 8a1b7c5a3d..f99d3f08a1 100644 --- a/packages/contracts/generated/api/service/zod.gen.ts +++ b/packages/contracts/generated/api/service/zod.gen.ts @@ -41,6 +41,17 @@ export const zAnnotationReplyActionPayload = z.object({ score_threshold: z.number(), }) +/** + * AppInfoResponse + */ +export const zAppInfoResponse = z.object({ + author_name: z.string().nullable(), + description: z.string().nullable(), + mode: z.string(), + name: z.string(), + tags: z.array(z.string()), +}) + /** * ChatRequestPayload */ @@ -232,6 +243,28 @@ export const zDocumentListQuery = z.object({ status: z.string().nullish(), }) +/** + * EndUserDetail + * + * Full EndUser record for API responses. + * + * Note: The SQLAlchemy model defines an `is_anonymous` property for Flask-Login semantics + * (always False). The database column is exposed as `_is_anonymous`, so this DTO maps + * `is_anonymous` from `_is_anonymous` to return the stored value. + */ +export const zEndUserDetail = z.object({ + app_id: z.string().nullish(), + created_at: z.iso.datetime(), + external_user_id: z.string().nullish(), + id: z.string(), + is_anonymous: z.boolean(), + name: z.string().nullish(), + session_id: z.string(), + tenant_id: z.string(), + type: z.string(), + updated_at: z.iso.datetime(), +}) + /** * FeedbackListQuery */ @@ -267,6 +300,15 @@ export const zFileResponse = z.object({ user_id: z.string().nullish(), }) +/** + * IndexInfoResponse + */ +export const zIndexInfoResponse = z.object({ + api_version: z.string(), + server_version: z.string(), + welcome: z.string(), +}) + export const zJsonValue = z.unknown() /** @@ -374,6 +416,13 @@ export const zRerankingModel = z.object({ reranking_provider_name: z.string().nullish(), }) +/** + * ResultResponse + */ +export const zResultResponse = z.object({ + result: z.string(), +}) + /** * RetrievalMethod */ @@ -465,6 +514,41 @@ export const zSimpleEndUser = z.object({ type: z.string(), }) +/** + * SimpleResultResponse + */ +export const zSimpleResultResponse = z.object({ + result: z.string(), +}) + +/** + * SimpleResultStringListResponse + */ +export const zSimpleResultStringListResponse = z.object({ + data: z.array(z.string()), + result: z.string(), +}) + +/** + * Site + */ +export const zSite = z.object({ + chat_color_theme: z.string().nullish(), + chat_color_theme_inverted: z.boolean(), + copyright: z.string().nullish(), + custom_disclaimer: z.string().nullish(), + default_language: z.string(), + description: z.string().nullish(), + icon: z.string().nullish(), + icon_background: z.string().nullish(), + icon_type: z.string().nullish(), + icon_url: z.string().readonly().nullable(), + privacy_policy: z.string().nullish(), + show_workflow_steps: z.boolean(), + title: z.string(), + use_icon_as_answer_icon: z.boolean(), +}) + /** * TagBindingPayload */ @@ -516,6 +600,13 @@ export const zTextToAudioPayload = z.object({ voice: z.string().nullish(), }) +/** + * UrlResponse + */ +export const zUrlResponse = z.object({ + url: z.string(), +}) + /** * WeightKeywordSetting */ @@ -710,10 +801,29 @@ export const zWorkflowRunResponse = z.object({ workflow_id: z.string(), }) +/** + * Site + */ +export const zSiteWritable = z.object({ + chat_color_theme: z.string().nullish(), + chat_color_theme_inverted: z.boolean(), + copyright: z.string().nullish(), + custom_disclaimer: z.string().nullish(), + default_language: z.string(), + description: z.string().nullish(), + icon: z.string().nullish(), + icon_background: z.string().nullish(), + icon_type: z.string().nullish(), + privacy_policy: z.string().nullish(), + show_workflow_steps: z.boolean(), + title: z.string(), + use_icon_as_answer_icon: z.boolean(), +}) + /** * Success */ -export const zGetRootResponse = z.record(z.string(), z.unknown()) +export const zGetRootResponse = zIndexInfoResponse export const zGetAppFeedbacksQuery = z.object({ limit: z.int().gte(1).lte(101).optional().default(20), @@ -800,7 +910,7 @@ export const zPostChatMessagesByTaskIdStopPath = z.object({ /** * Task stopped successfully */ -export const zPostChatMessagesByTaskIdStopResponse = z.record(z.string(), z.unknown()) +export const zPostChatMessagesByTaskIdStopResponse = zSimpleResultResponse export const zPostCompletionMessagesBody = zCompletionRequestPayload @@ -816,7 +926,7 @@ export const zPostCompletionMessagesByTaskIdStopPath = z.object({ /** * Task stopped successfully */ -export const zPostCompletionMessagesByTaskIdStopResponse = z.record(z.string(), z.unknown()) +export const zPostCompletionMessagesByTaskIdStopResponse = zSimpleResultResponse export const zGetConversationsQuery = z.object({ last_id: z.string().nullish(), @@ -1050,7 +1160,7 @@ export const zPostDatasetsByDatasetIdDocumentsMetadataPath = z.object({ /** * Documents metadata updated successfully */ -export const zPostDatasetsByDatasetIdDocumentsMetadataResponse = z.record(z.string(), z.unknown()) +export const zPostDatasetsByDatasetIdDocumentsMetadataResponse = zSimpleResultResponse export const zPatchDatasetsByDatasetIdDocumentsStatusByActionPath = z.object({ action: z.string(), @@ -1060,10 +1170,7 @@ export const zPatchDatasetsByDatasetIdDocumentsStatusByActionPath = z.object({ /** * Document status updated successfully */ -export const zPatchDatasetsByDatasetIdDocumentsStatusByActionResponse = z.record( - z.string(), - z.unknown(), -) +export const zPatchDatasetsByDatasetIdDocumentsStatusByActionResponse = zSimpleResultResponse export const zGetDatasetsByDatasetIdDocumentsByBatchIndexingStatusPath = z.object({ batch: z.string(), @@ -1125,10 +1232,7 @@ export const zGetDatasetsByDatasetIdDocumentsByDocumentIdDownloadPath = z.object /** * Download URL generated successfully */ -export const zGetDatasetsByDatasetIdDocumentsByDocumentIdDownloadResponse = z.record( - z.string(), - z.unknown(), -) +export const zGetDatasetsByDatasetIdDocumentsByDocumentIdDownloadResponse = zUrlResponse export const zGetDatasetsByDatasetIdDocumentsByDocumentIdSegmentsPath = z.object({ dataset_id: z.string(), @@ -1379,10 +1483,7 @@ export const zPostDatasetsByDatasetIdMetadataBuiltInByActionPath = z.object({ /** * Action completed successfully */ -export const zPostDatasetsByDatasetIdMetadataBuiltInByActionResponse = z.record( - z.string(), - z.unknown(), -) +export const zPostDatasetsByDatasetIdMetadataBuiltInByActionResponse = zSimpleResultResponse export const zDeleteDatasetsByDatasetIdMetadataByMetadataIdPath = z.object({ dataset_id: z.string(), @@ -1477,7 +1578,7 @@ export const zGetEndUsersByEndUserIdPath = z.object({ /** * End user retrieved successfully */ -export const zGetEndUsersByEndUserIdResponse = z.record(z.string(), z.unknown()) +export const zGetEndUsersByEndUserIdResponse = zEndUserDetail /** * File uploaded successfully @@ -1520,7 +1621,7 @@ export const zPostFormHumanInputByFormTokenResponse = z.record(z.string(), z.unk /** * Application info retrieved successfully */ -export const zGetInfoResponse = z.record(z.string(), z.unknown()) +export const zGetInfoResponse = zAppInfoResponse export const zGetMessagesQuery = z.object({ conversation_id: z.string(), @@ -1542,7 +1643,7 @@ export const zPostMessagesByMessageIdFeedbacksPath = z.object({ /** * Feedback submitted successfully */ -export const zPostMessagesByMessageIdFeedbacksResponse = z.record(z.string(), z.unknown()) +export const zPostMessagesByMessageIdFeedbacksResponse = zResultResponse export const zGetMessagesByMessageIdSuggestedPath = z.object({ message_id: z.string(), @@ -1551,7 +1652,7 @@ export const zGetMessagesByMessageIdSuggestedPath = z.object({ /** * Suggested questions retrieved successfully */ -export const zGetMessagesByMessageIdSuggestedResponse = z.record(z.string(), z.unknown()) +export const zGetMessagesByMessageIdSuggestedResponse = zSimpleResultStringListResponse /** * Metadata retrieved successfully @@ -1566,7 +1667,7 @@ export const zGetParametersResponse = z.record(z.string(), z.unknown()) /** * Site configuration retrieved successfully */ -export const zGetSiteResponse = z.record(z.string(), z.unknown()) +export const zGetSiteResponse = zSite export const zPostTextToAudioBody = zTextToAudioPayload @@ -1629,7 +1730,7 @@ export const zPostWorkflowsTasksByTaskIdStopPath = z.object({ /** * Task stopped successfully */ -export const zPostWorkflowsTasksByTaskIdStopResponse = z.record(z.string(), z.unknown()) +export const zPostWorkflowsTasksByTaskIdStopResponse = zSimpleResultResponse export const zPostWorkflowsByWorkflowIdRunBody = zWorkflowRunPayload diff --git a/packages/contracts/generated/api/web/orpc.gen.ts b/packages/contracts/generated/api/web/orpc.gen.ts index eea2efcb7c..4e7c949bdb 100644 --- a/packages/contracts/generated/api/web/orpc.gen.ts +++ b/packages/contracts/generated/api/web/orpc.gen.ts @@ -110,16 +110,10 @@ export const audioToText = { /** * Stop a running chat message task. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post2 = oc .route({ - deprecated: true, - description: - 'Stop a running chat message task.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Stop a running chat message task.', inputStructure: 'detailed', method: 'POST', operationId: 'postChatMessagesByTaskIdStop', @@ -165,16 +159,10 @@ export const chatMessages = { /** * Stop a running completion message task. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post4 = oc .route({ - deprecated: true, - description: - 'Stop a running completion message task.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Stop a running completion message task.', inputStructure: 'detailed', method: 'POST', operationId: 'postCompletionMessagesByTaskIdStop', @@ -250,16 +238,10 @@ export const name = { /** * Pin a specific conversation to keep it at the top of the list. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const patch = oc .route({ - deprecated: true, - description: - 'Pin a specific conversation to keep it at the top of the list.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Pin a specific conversation to keep it at the top of the list.', inputStructure: 'detailed', method: 'PATCH', operationId: 'patchConversationsByCIdPin', @@ -275,16 +257,10 @@ export const pin = { /** * Unpin a specific conversation to remove it from the top of the list. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const patch2 = oc .route({ - deprecated: true, - description: - 'Unpin a specific conversation to remove it from the top of the list.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Unpin a specific conversation to remove it from the top of the list.', inputStructure: 'detailed', method: 'PATCH', operationId: 'patchConversationsByCIdUnpin', @@ -349,16 +325,10 @@ export const conversations = { /** * Verify email code and complete login - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post7 = oc .route({ - deprecated: true, - description: - 'Verify email code and complete login\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Verify email code and complete login', inputStructure: 'detailed', method: 'POST', operationId: 'postEmailCodeLoginValidity', @@ -374,16 +344,10 @@ export const validity = { /** * Send email verification code for login - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post8 = oc .route({ - deprecated: true, - description: - 'Send email verification code for login\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Send email verification code for login', inputStructure: 'detailed', method: 'POST', operationId: 'postEmailCodeLogin', @@ -448,16 +412,10 @@ export const files = { /** * Reset user password with verification token - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post10 = oc .route({ - deprecated: true, - description: - 'Reset user password with verification token\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Reset user password with verification token', inputStructure: 'detailed', method: 'POST', operationId: 'postForgotPasswordResets', @@ -473,16 +431,10 @@ export const resets = { /** * Verify password reset token validity - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post11 = oc .route({ - deprecated: true, - description: - 'Verify password reset token validity\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Verify password reset token validity', inputStructure: 'detailed', method: 'POST', operationId: 'postForgotPasswordValidity', @@ -498,16 +450,10 @@ export const validity2 = { /** * Send password reset email - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post12 = oc .route({ - deprecated: true, - description: - 'Send password reset email\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Send password reset email', inputStructure: 'detailed', method: 'POST', operationId: 'postForgotPassword', @@ -594,16 +540,10 @@ export const form = { /** * Check login status - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get3 = oc .route({ - deprecated: true, - description: - 'Check login status\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Check login status', inputStructure: 'detailed', method: 'GET', operationId: 'getLoginStatus', @@ -620,16 +560,10 @@ export const status = { * Authenticate user and login * * Authenticate user for web application access - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post14 = oc .route({ - deprecated: true, - description: - 'Authenticate user for web application access\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Authenticate user for web application access', inputStructure: 'detailed', method: 'POST', operationId: 'postLogin', @@ -647,16 +581,10 @@ export const login = { /** * Logout user from web application - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post15 = oc .route({ - deprecated: true, - description: - 'Logout user from web application\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Logout user from web application', inputStructure: 'detailed', method: 'POST', operationId: 'postLogout', @@ -731,16 +659,10 @@ export const moreLikeThis = { /** * Get suggested follow-up questions after a message (chat apps only). - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get5 = oc .route({ - deprecated: true, - description: - 'Get suggested follow-up questions after a message (chat apps only).\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Get suggested follow-up questions after a message (chat apps only).', inputStructure: 'detailed', method: 'GET', operationId: 'getMessagesByMessageIdSuggestedQuestions', @@ -886,11 +808,16 @@ export const passport = { * RemoteFileUploadError: Failed to fetch file from remote URL * FileTooLargeError: File exceeds size limit * UnsupportedFileTypeError: File type not supported + * + * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. + * + * @deprecated */ export const post17 = oc .route({ + deprecated: true, description: - 'Upload a file from a remote URL\nDownloads a file from the provided remote URL and uploads it\nto the platform storage for use in web applications.\n\nArgs:\n app_model: The associated application model\n end_user: The end user making the request\n\nJSON Parameters:\n url: The remote URL to download the file from (required)\n\nReturns:\n dict: File information including ID, signed URL, and metadata\n int: HTTP status code 201 for success\n\nRaises:\n RemoteFileUploadError: Failed to fetch file from remote URL\n FileTooLargeError: File exceeds size limit\n UnsupportedFileTypeError: File type not supported', + 'Upload a file from a remote URL\nDownloads a file from the provided remote URL and uploads it\nto the platform storage for use in web applications.\n\nArgs:\n app_model: The associated application model\n end_user: The end user making the request\n\nJSON Parameters:\n url: The remote URL to download the file from (required)\n\nReturns:\n dict: File information including ID, signed URL, and metadata\n int: HTTP status code 201 for success\n\nRaises:\n RemoteFileUploadError: Failed to fetch file from remote URL\n FileTooLargeError: File exceeds size limit\n UnsupportedFileTypeError: File type not supported\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', inputStructure: 'detailed', method: 'POST', operationId: 'postRemoteFilesUpload', @@ -1060,16 +987,11 @@ export const site = { * Authentication would create circular dependency (can't authenticate without webapp loading). * * Only non-sensitive configuration data should be returned by this endpoint. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get13 = oc .route({ - deprecated: true, description: - 'Get system feature flags and configuration\nReturns the current system feature flags and configuration\nthat control various functionalities across the platform.\n\nReturns:\n dict: System feature configuration object\n\nThis endpoint is akin to the `SystemFeatureApi` endpoint in api/controllers/console/feature.py,\nexcept it is intended for use by the web app, instead of the console dashboard.\n\nNOTE: This endpoint is unauthenticated by design, as it provides system features\ndata required for webapp initialization.\n\nAuthentication would create circular dependency (can\'t authenticate without webapp loading).\n\nOnly non-sensitive configuration data should be returned by this endpoint.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + 'Get system feature flags and configuration\nReturns the current system feature flags and configuration\nthat control various functionalities across the platform.\n\nReturns:\n dict: System feature configuration object\n\nThis endpoint is akin to the `SystemFeatureApi` endpoint in api/controllers/console/feature.py,\nexcept it is intended for use by the web app, instead of the console dashboard.\n\nNOTE: This endpoint is unauthenticated by design, as it provides system features\ndata required for webapp initialization.\n\nAuthentication would create circular dependency (can\'t authenticate without webapp loading).\n\nOnly non-sensitive configuration data should be returned by this endpoint.', inputStructure: 'detailed', method: 'GET', operationId: 'getSystemFeatures', @@ -1113,16 +1035,10 @@ export const textToAudio = { /** * Retrieve the access mode for a web application (public or restricted). - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get14 = oc .route({ - deprecated: true, - description: - 'Retrieve the access mode for a web application (public or restricted).\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Retrieve the access mode for a web application (public or restricted).', inputStructure: 'detailed', method: 'GET', operationId: 'getWebappAccessMode', @@ -1138,16 +1054,10 @@ export const accessMode = { /** * Check if user has permission to access a web application. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const get15 = oc .route({ - deprecated: true, - description: - 'Check if user has permission to access a web application.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Check if user has permission to access a web application.', inputStructure: 'detailed', method: 'GET', operationId: 'getWebappPermission', @@ -1236,16 +1146,10 @@ export const run = { * Stop workflow task * * Stop a running workflow task. - * - * Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate. - * - * @deprecated */ export const post21 = oc .route({ - deprecated: true, - description: - 'Stop a running workflow task.\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.', + description: 'Stop a running workflow task.', inputStructure: 'detailed', method: 'POST', operationId: 'postWorkflowsTasksByTaskIdStop', diff --git a/packages/contracts/generated/api/web/types.gen.ts b/packages/contracts/generated/api/web/types.gen.ts index fed7ed8452..b08f372208 100644 --- a/packages/contracts/generated/api/web/types.gen.ts +++ b/packages/contracts/generated/api/web/types.gen.ts @@ -4,11 +4,36 @@ export type ClientOptions = { baseUrl: `${string}://${string}/api` | (string & {}) } +export type AccessModeResponse = { + accessMode: string +} + +export type AccessTokenData = { + access_token: string +} + +export type AccessTokenResultResponse = { + data: AccessTokenData + result: string +} + export type AppAccessModeQuery = { appCode?: string | null appId?: string | null } +export type BooleanResultResponse = { + result: boolean +} + +export type BrandingModel = { + application_title: string + enabled: boolean + favicon: string + login_page_logo: string + workspace_logo: string +} + export type ChatMessagePayload = { conversation_id?: string | null files?: Array<{ @@ -76,14 +101,14 @@ export type FileResponse = { } export type FileWithSignedUrl = { - created_at?: number | null - created_by?: string | null - extension?: string | null + created_at: number | null + created_by: string | null + extension: string | null id: string - mime_type?: string | null + mime_type: string | null name: string size: number - url?: string | null + url: string | null } export type ForgotPasswordCheckPayload = { @@ -103,11 +128,30 @@ export type ForgotPasswordSendPayload = { language?: string | null } +export type LicenseLimitationModel = { + enabled: boolean + limit: number + size: number +} + +export type LicenseModel = { + expired_at: string + status: LicenseStatus + workspaces: LicenseLimitationModel +} + +export type LicenseStatus = 'active' | 'expired' | 'expiring' | 'inactive' | 'lost' | 'none' + export type LoginPayload = { email: string password: string } +export type LoginStatusResponse = { + app_logged_in: boolean + logged_in: boolean +} + export type MessageFeedbackPayload = { content?: string | null rating?: 'dislike' | 'like' | null @@ -123,6 +167,21 @@ export type MessageMoreLikeThisQuery = { response_mode: 'blocking' | 'streaming' } +export type PluginInstallationPermissionModel = { + plugin_installation_scope: PluginInstallationScope + restrict_to_marketplace_only: boolean +} + +export type PluginInstallationScope + = | 'all' + | 'none' + | 'official_and_specific_partners' + | 'official_only' + +export type PluginManagerModel = { + enabled: boolean +} + export type RemoteFileInfo = { file_length: number file_type: string @@ -132,6 +191,10 @@ export type RemoteFileUploadPayload = { url: string } +export type ResultResponse = { + result: string +} + export type SavedMessageCreatePayload = { message_id: string } @@ -141,6 +204,44 @@ export type SavedMessageListQuery = { limit?: number } +export type SimpleResultDataResponse = { + data: string + result: string +} + +export type SimpleResultResponse = { + result: string +} + +export type SuggestedQuestionsResponse = { + data: Array +} + +export type SystemFeatureModel = { + app_dsl_version: string + branding: BrandingModel + enable_change_email: boolean + enable_collaboration_mode: boolean + enable_creators_platform: boolean + enable_email_code_login: boolean + enable_email_password_login: boolean + enable_explore_banner: boolean + enable_marketplace: boolean + enable_social_oauth_login: boolean + enable_trial_app: boolean + is_allow_create_workspace: boolean + is_allow_register: boolean + is_email_setup: boolean + license: LicenseModel + max_plugin_package_size: number + plugin_installation_permission: PluginInstallationPermissionModel + plugin_manager: PluginManagerModel + sso_enforced_for_signin: boolean + sso_enforced_for_signin_protocol: string + trial_models: Array + webapp_auth: WebAppAuthModel +} + export type TextToAudioPayload = { message_id?: string | null streaming?: boolean | null @@ -148,6 +249,24 @@ export type TextToAudioPayload = { voice?: string | null } +export type VerificationTokenResponse = { + email: string + is_valid: boolean + token: string +} + +export type WebAppAuthModel = { + allow_email_code_login: boolean + allow_email_password_login: boolean + allow_sso: boolean + enabled: boolean + sso_config: WebAppAuthSsoModel +} + +export type WebAppAuthSsoModel = { + protocol: string +} + export type WorkflowRunPayload = { files?: Array<{ [key: string]: unknown @@ -261,9 +380,7 @@ export type PostChatMessagesByTaskIdStopError = PostChatMessagesByTaskIdStopErrors[keyof PostChatMessagesByTaskIdStopErrors] export type PostChatMessagesByTaskIdStopResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostChatMessagesByTaskIdStopResponse @@ -337,9 +454,7 @@ export type PostCompletionMessagesByTaskIdStopError = PostCompletionMessagesByTaskIdStopErrors[keyof PostCompletionMessagesByTaskIdStopErrors] export type PostCompletionMessagesByTaskIdStopResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostCompletionMessagesByTaskIdStopResponse @@ -497,9 +612,7 @@ export type PatchConversationsByCIdPinError = PatchConversationsByCIdPinErrors[keyof PatchConversationsByCIdPinErrors] export type PatchConversationsByCIdPinResponses = { - 200: { - [key: string]: unknown - } + 200: ResultResponse } export type PatchConversationsByCIdPinResponse @@ -536,9 +649,7 @@ export type PatchConversationsByCIdUnpinError = PatchConversationsByCIdUnpinErrors[keyof PatchConversationsByCIdUnpinErrors] export type PatchConversationsByCIdUnpinResponses = { - 200: { - [key: string]: unknown - } + 200: ResultResponse } export type PatchConversationsByCIdUnpinResponse @@ -563,9 +674,7 @@ export type PostEmailCodeLoginErrors = { export type PostEmailCodeLoginError = PostEmailCodeLoginErrors[keyof PostEmailCodeLoginErrors] export type PostEmailCodeLoginResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultDataResponse } export type PostEmailCodeLoginResponse @@ -594,9 +703,7 @@ export type PostEmailCodeLoginValidityError = PostEmailCodeLoginValidityErrors[keyof PostEmailCodeLoginValidityErrors] export type PostEmailCodeLoginValidityResponses = { - 200: { - [key: string]: unknown - } + 200: AccessTokenResultResponse } export type PostEmailCodeLoginValidityResponse @@ -651,9 +758,7 @@ export type PostForgotPasswordErrors = { export type PostForgotPasswordError = PostForgotPasswordErrors[keyof PostForgotPasswordErrors] export type PostForgotPasswordResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultDataResponse } export type PostForgotPasswordResponse @@ -682,9 +787,7 @@ export type PostForgotPasswordResetsError = PostForgotPasswordResetsErrors[keyof PostForgotPasswordResetsErrors] export type PostForgotPasswordResetsResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostForgotPasswordResetsResponse @@ -710,9 +813,7 @@ export type PostForgotPasswordValidityError = PostForgotPasswordValidityErrors[keyof PostForgotPasswordValidityErrors] export type PostForgotPasswordValidityResponses = { - 200: { - [key: string]: unknown - } + 200: VerificationTokenResponse } export type PostForgotPasswordValidityResponse @@ -779,9 +880,7 @@ export type PostLoginErrors = { export type PostLoginError = PostLoginErrors[keyof PostLoginErrors] export type PostLoginResponses = { - 200: { - [key: string]: unknown - } + 200: AccessTokenResultResponse } export type PostLoginResponse = PostLoginResponses[keyof PostLoginResponses] @@ -802,9 +901,7 @@ export type GetLoginStatusErrors = { export type GetLoginStatusError = GetLoginStatusErrors[keyof GetLoginStatusErrors] export type GetLoginStatusResponses = { - 200: { - [key: string]: unknown - } + 200: LoginStatusResponse } export type GetLoginStatusResponse = GetLoginStatusResponses[keyof GetLoginStatusResponses] @@ -817,9 +914,7 @@ export type PostLogoutData = { } export type PostLogoutResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostLogoutResponse = PostLogoutResponses[keyof PostLogoutResponses] @@ -897,9 +992,7 @@ export type PostMessagesByMessageIdFeedbacksError = PostMessagesByMessageIdFeedbacksErrors[keyof PostMessagesByMessageIdFeedbacksErrors] export type PostMessagesByMessageIdFeedbacksResponses = { - 200: { - [key: string]: unknown - } + 200: ResultResponse } export type PostMessagesByMessageIdFeedbacksResponse @@ -977,9 +1070,7 @@ export type GetMessagesByMessageIdSuggestedQuestionsError = GetMessagesByMessageIdSuggestedQuestionsErrors[keyof GetMessagesByMessageIdSuggestedQuestionsErrors] export type GetMessagesByMessageIdSuggestedQuestionsResponses = { - 200: { - [key: string]: unknown - } + 200: SuggestedQuestionsResponse } export type GetMessagesByMessageIdSuggestedQuestionsResponse @@ -1211,9 +1302,7 @@ export type PostSavedMessagesErrors = { export type PostSavedMessagesError = PostSavedMessagesErrors[keyof PostSavedMessagesErrors] export type PostSavedMessagesResponses = { - 200: { - [key: string]: unknown - } + 200: ResultResponse } export type PostSavedMessagesResponse = PostSavedMessagesResponses[keyof PostSavedMessagesResponses] @@ -1308,9 +1397,7 @@ export type GetSystemFeaturesErrors = { export type GetSystemFeaturesError = GetSystemFeaturesErrors[keyof GetSystemFeaturesErrors] export type GetSystemFeaturesResponses = { - 200: { - [key: string]: unknown - } + 200: SystemFeatureModel } export type GetSystemFeaturesResponse = GetSystemFeaturesResponses[keyof GetSystemFeaturesResponses] @@ -1369,9 +1456,7 @@ export type GetWebappAccessModeErrors = { export type GetWebappAccessModeError = GetWebappAccessModeErrors[keyof GetWebappAccessModeErrors] export type GetWebappAccessModeResponses = { - 200: { - [key: string]: unknown - } + 200: AccessModeResponse } export type GetWebappAccessModeResponse @@ -1401,9 +1486,7 @@ export type GetWebappPermissionErrors = { export type GetWebappPermissionError = GetWebappPermissionErrors[keyof GetWebappPermissionErrors] export type GetWebappPermissionResponses = { - 200: { - [key: string]: unknown - } + 200: BooleanResultResponse } export type GetWebappPermissionResponse @@ -1493,9 +1576,7 @@ export type PostWorkflowsTasksByTaskIdStopError = PostWorkflowsTasksByTaskIdStopErrors[keyof PostWorkflowsTasksByTaskIdStopErrors] export type PostWorkflowsTasksByTaskIdStopResponses = { - 200: { - [key: string]: unknown - } + 200: SimpleResultResponse } export type PostWorkflowsTasksByTaskIdStopResponse diff --git a/packages/contracts/generated/api/web/zod.gen.ts b/packages/contracts/generated/api/web/zod.gen.ts index 3d4785891f..d1e8ab7600 100644 --- a/packages/contracts/generated/api/web/zod.gen.ts +++ b/packages/contracts/generated/api/web/zod.gen.ts @@ -2,6 +2,28 @@ import * as z from 'zod' +/** + * AccessModeResponse + */ +export const zAccessModeResponse = z.object({ + accessMode: z.string(), +}) + +/** + * AccessTokenData + */ +export const zAccessTokenData = z.object({ + access_token: z.string(), +}) + +/** + * AccessTokenResultResponse + */ +export const zAccessTokenResultResponse = z.object({ + data: zAccessTokenData, + result: z.string(), +}) + /** * AppAccessModeQuery */ @@ -10,6 +32,24 @@ export const zAppAccessModeQuery = z.object({ appId: z.string().nullish(), }) +/** + * BooleanResultResponse + */ +export const zBooleanResultResponse = z.object({ + result: z.boolean(), +}) + +/** + * BrandingModel + */ +export const zBrandingModel = z.object({ + application_title: z.string().default(''), + enabled: z.boolean().default(false), + favicon: z.string().default(''), + login_page_logo: z.string().default(''), + workspace_logo: z.string().default(''), +}) + /** * ChatMessagePayload */ @@ -96,14 +136,14 @@ export const zFileResponse = z.object({ * FileWithSignedUrl */ export const zFileWithSignedUrl = z.object({ - created_at: z.int().nullish(), - created_by: z.string().nullish(), - extension: z.string().nullish(), + created_at: z.int().nullable(), + created_by: z.string().nullable(), + extension: z.string().nullable(), id: z.string(), - mime_type: z.string().nullish(), + mime_type: z.string().nullable(), name: z.string(), size: z.int(), - url: z.string().nullish(), + url: z.string().nullable(), }) /** @@ -132,6 +172,33 @@ export const zForgotPasswordSendPayload = z.object({ language: z.string().nullish(), }) +/** + * LicenseLimitationModel + * + * - enabled: whether this limit is enforced + * - size: current usage count + * - limit: maximum allowed count; 0 means unlimited + */ +export const zLicenseLimitationModel = z.object({ + enabled: z.boolean().default(false), + limit: z.int().default(0), + size: z.int().default(0), +}) + +/** + * LicenseStatus + */ +export const zLicenseStatus = z.enum(['active', 'expired', 'expiring', 'inactive', 'lost', 'none']) + +/** + * LicenseModel + */ +export const zLicenseModel = z.object({ + expired_at: z.string().default(''), + status: zLicenseStatus, + workspaces: zLicenseLimitationModel, +}) + /** * LoginPayload */ @@ -140,6 +207,14 @@ export const zLoginPayload = z.object({ password: z.string(), }) +/** + * LoginStatusResponse + */ +export const zLoginStatusResponse = z.object({ + app_logged_in: z.boolean(), + logged_in: z.boolean(), +}) + /** * MessageFeedbackPayload */ @@ -164,6 +239,31 @@ export const zMessageMoreLikeThisQuery = z.object({ response_mode: z.enum(['blocking', 'streaming']), }) +/** + * PluginInstallationScope + */ +export const zPluginInstallationScope = z.enum([ + 'all', + 'none', + 'official_and_specific_partners', + 'official_only', +]) + +/** + * PluginInstallationPermissionModel + */ +export const zPluginInstallationPermissionModel = z.object({ + plugin_installation_scope: zPluginInstallationScope, + restrict_to_marketplace_only: z.boolean().default(false), +}) + +/** + * PluginManagerModel + */ +export const zPluginManagerModel = z.object({ + enabled: z.boolean().default(false), +}) + /** * RemoteFileInfo */ @@ -179,6 +279,13 @@ export const zRemoteFileUploadPayload = z.object({ url: z.url().min(1).max(2083), }) +/** + * ResultResponse + */ +export const zResultResponse = z.object({ + result: z.string(), +}) + /** * SavedMessageCreatePayload */ @@ -194,6 +301,28 @@ export const zSavedMessageListQuery = z.object({ limit: z.int().gte(1).lte(100).optional().default(20), }) +/** + * SimpleResultDataResponse + */ +export const zSimpleResultDataResponse = z.object({ + data: z.string(), + result: z.string(), +}) + +/** + * SimpleResultResponse + */ +export const zSimpleResultResponse = z.object({ + result: z.string(), +}) + +/** + * SuggestedQuestionsResponse + */ +export const zSuggestedQuestionsResponse = z.object({ + data: z.array(z.string()), +}) + /** * TextToAudioPayload */ @@ -204,6 +333,61 @@ export const zTextToAudioPayload = z.object({ voice: z.string().nullish(), }) +/** + * VerificationTokenResponse + */ +export const zVerificationTokenResponse = z.object({ + email: z.string(), + is_valid: z.boolean(), + token: z.string(), +}) + +/** + * WebAppAuthSSOModel + */ +export const zWebAppAuthSsoModel = z.object({ + protocol: z.string().default(''), +}) + +/** + * WebAppAuthModel + */ +export const zWebAppAuthModel = z.object({ + allow_email_code_login: z.boolean().default(false), + allow_email_password_login: z.boolean().default(false), + allow_sso: z.boolean().default(false), + enabled: z.boolean().default(false), + sso_config: zWebAppAuthSsoModel, +}) + +/** + * SystemFeatureModel + */ +export const zSystemFeatureModel = z.object({ + app_dsl_version: z.string().default(''), + branding: zBrandingModel, + enable_change_email: z.boolean().default(true), + enable_collaboration_mode: z.boolean().default(true), + enable_creators_platform: z.boolean().default(false), + enable_email_code_login: z.boolean().default(false), + enable_email_password_login: z.boolean().default(true), + enable_explore_banner: z.boolean().default(false), + enable_marketplace: z.boolean().default(false), + enable_social_oauth_login: z.boolean().default(false), + enable_trial_app: z.boolean().default(false), + is_allow_create_workspace: z.boolean().default(false), + is_allow_register: z.boolean().default(false), + is_email_setup: z.boolean().default(false), + license: zLicenseModel, + max_plugin_package_size: z.int().default(15728640), + plugin_installation_permission: zPluginInstallationPermissionModel, + plugin_manager: zPluginManagerModel, + sso_enforced_for_signin: z.boolean().default(false), + sso_enforced_for_signin_protocol: z.string().default(''), + trial_models: z.array(z.string()).default([]), + webapp_auth: zWebAppAuthModel, +}) + /** * WorkflowRunPayload */ @@ -231,7 +415,7 @@ export const zPostChatMessagesByTaskIdStopPath = z.object({ /** * Success */ -export const zPostChatMessagesByTaskIdStopResponse = z.record(z.string(), z.unknown()) +export const zPostChatMessagesByTaskIdStopResponse = zSimpleResultResponse export const zPostCompletionMessagesBody = zCompletionMessagePayload @@ -247,7 +431,7 @@ export const zPostCompletionMessagesByTaskIdStopPath = z.object({ /** * Success */ -export const zPostCompletionMessagesByTaskIdStopResponse = z.record(z.string(), z.unknown()) +export const zPostCompletionMessagesByTaskIdStopResponse = zSimpleResultResponse export const zGetConversationsQuery = z.object({ last_id: z.string().optional(), @@ -294,7 +478,7 @@ export const zPatchConversationsByCIdPinPath = z.object({ /** * Conversation pinned successfully */ -export const zPatchConversationsByCIdPinResponse = z.record(z.string(), z.unknown()) +export const zPatchConversationsByCIdPinResponse = zResultResponse export const zPatchConversationsByCIdUnpinPath = z.object({ c_id: z.string(), @@ -303,21 +487,21 @@ export const zPatchConversationsByCIdUnpinPath = z.object({ /** * Conversation unpinned successfully */ -export const zPatchConversationsByCIdUnpinResponse = z.record(z.string(), z.unknown()) +export const zPatchConversationsByCIdUnpinResponse = zResultResponse export const zPostEmailCodeLoginBody = zEmailCodeLoginSendPayload /** * Email code sent successfully */ -export const zPostEmailCodeLoginResponse = z.record(z.string(), z.unknown()) +export const zPostEmailCodeLoginResponse = zSimpleResultDataResponse export const zPostEmailCodeLoginValidityBody = zEmailCodeLoginVerifyPayload /** * Email code verified and login successful */ -export const zPostEmailCodeLoginValidityResponse = z.record(z.string(), z.unknown()) +export const zPostEmailCodeLoginValidityResponse = zAccessTokenResultResponse /** * File uploaded successfully @@ -329,21 +513,21 @@ export const zPostForgotPasswordBody = zForgotPasswordSendPayload /** * Password reset email sent successfully */ -export const zPostForgotPasswordResponse = z.record(z.string(), z.unknown()) +export const zPostForgotPasswordResponse = zSimpleResultDataResponse export const zPostForgotPasswordResetsBody = zForgotPasswordResetPayload /** * Password reset successfully */ -export const zPostForgotPasswordResetsResponse = z.record(z.string(), z.unknown()) +export const zPostForgotPasswordResetsResponse = zSimpleResultResponse export const zPostForgotPasswordValidityBody = zForgotPasswordCheckPayload /** * Token is valid */ -export const zPostForgotPasswordValidityResponse = z.record(z.string(), z.unknown()) +export const zPostForgotPasswordValidityResponse = zVerificationTokenResponse export const zGetFormHumanInputByFormTokenPath = z.object({ form_token: z.string(), @@ -368,17 +552,17 @@ export const zPostLoginBody = zLoginPayload /** * Authentication successful */ -export const zPostLoginResponse = z.record(z.string(), z.unknown()) +export const zPostLoginResponse = zAccessTokenResultResponse /** * Login status */ -export const zGetLoginStatusResponse = z.record(z.string(), z.unknown()) +export const zGetLoginStatusResponse = zLoginStatusResponse /** * Logout successful */ -export const zPostLogoutResponse = z.record(z.string(), z.unknown()) +export const zPostLogoutResponse = zSimpleResultResponse export const zGetMessagesQuery = z.object({ conversation_id: z.string(), @@ -403,7 +587,7 @@ export const zPostMessagesByMessageIdFeedbacksQuery = z.object({ /** * Feedback submitted successfully */ -export const zPostMessagesByMessageIdFeedbacksResponse = z.record(z.string(), z.unknown()) +export const zPostMessagesByMessageIdFeedbacksResponse = zResultResponse export const zGetMessagesByMessageIdMoreLikeThisPath = z.object({ message_id: z.string(), @@ -425,7 +609,7 @@ export const zGetMessagesByMessageIdSuggestedQuestionsPath = z.object({ /** * Success */ -export const zGetMessagesByMessageIdSuggestedQuestionsResponse = z.record(z.string(), z.unknown()) +export const zGetMessagesByMessageIdSuggestedQuestionsResponse = zSuggestedQuestionsResponse /** * Success @@ -473,7 +657,7 @@ export const zPostSavedMessagesQuery = z.object({ /** * Message saved successfully */ -export const zPostSavedMessagesResponse = z.record(z.string(), z.unknown()) +export const zPostSavedMessagesResponse = zResultResponse export const zDeleteSavedMessagesByMessageIdPath = z.object({ message_id: z.string(), @@ -492,7 +676,7 @@ export const zGetSiteResponse = z.record(z.string(), z.unknown()) /** * System features retrieved successfully */ -export const zGetSystemFeaturesResponse = z.record(z.string(), z.unknown()) +export const zGetSystemFeaturesResponse = zSystemFeatureModel export const zPostTextToAudioBody = zTextToAudioPayload @@ -509,7 +693,7 @@ export const zGetWebappAccessModeQuery = z.object({ /** * Success */ -export const zGetWebappAccessModeResponse = z.record(z.string(), z.unknown()) +export const zGetWebappAccessModeResponse = zAccessModeResponse export const zGetWebappPermissionQuery = z.object({ appId: z.string(), @@ -518,7 +702,7 @@ export const zGetWebappPermissionQuery = z.object({ /** * Success */ -export const zGetWebappPermissionResponse = z.record(z.string(), z.unknown()) +export const zGetWebappPermissionResponse = zBooleanResultResponse export const zGetWorkflowByTaskIdEventsPath = z.object({ task_id: z.string(), @@ -543,4 +727,4 @@ export const zPostWorkflowsTasksByTaskIdStopPath = z.object({ /** * Success */ -export const zPostWorkflowsTasksByTaskIdStopResponse = z.record(z.string(), z.unknown()) +export const zPostWorkflowsTasksByTaskIdStopResponse = zSimpleResultResponse diff --git a/packages/contracts/openapi-ts.api.config.ts b/packages/contracts/openapi-ts.api.config.ts index d17b5dcbc3..5cb46dd496 100644 --- a/packages/contracts/openapi-ts.api.config.ts +++ b/packages/contracts/openapi-ts.api.config.ts @@ -80,11 +80,21 @@ type ApiReadinessSurfaceStats = { total: number } +type ApiSurface = 'console' | 'service' | 'web' + +type ApiOperationContext = { + method: string + routePath: string + runtimeBodyRequired: boolean +} + const currentDir = path.dirname(fileURLToPath(import.meta.url)) const apiOpenApiDir = path.resolve(currentDir, 'openapi') const apiReadinessStatsPath = path.resolve(currentDir, 'generated/api/readiness.json') +const apiControllersDir = path.resolve(currentDir, '../../api/controllers') const operationMethods = new Set(['delete', 'get', 'patch', 'post', 'put']) +const requestBodyMethods = new Set(['delete', 'patch', 'post', 'put']) const noBodyResponseStatuses = new Set(['204', '205', '304']) const apiSpecs: ApiSpec[] = [ @@ -180,6 +190,174 @@ const clone = (value: T): T => { return JSON.parse(JSON.stringify(value)) as T } +const apiOperationKey = (surface: string, method: string, routePath: string) => { + return `${surface}:${method.toLowerCase()}:${routePath}` +} + +// Swagger cannot tell whether an undocumented POST/PATCH/PUT/DELETE body is truly absent or +// just missing @expect(). Scan controllers so readiness stays conservative for those routes. +const listPythonFiles = (directory: string): string[] => { + if (!fs.existsSync(directory)) + return [] + + return fs.readdirSync(directory, { withFileTypes: true }).flatMap((entry) => { + const entryPath = path.join(directory, entry.name) + if (entry.isDirectory()) + return listPythonFiles(entryPath) + if (entry.isFile() && entry.name.endsWith('.py')) + return [entryPath] + return [] + }) +} + +const leadingWhitespaceLength = (value: string) => { + return value.length - value.trimStart().length +} + +const parenthesesDelta = (value: string) => { + return [...value].reduce((total, char) => { + if (char === '(') + return total + 1 + if (char === ')') + return total - 1 + return total + }, 0) +} + +const collectDecorator = (lines: string[], startIndex: number) => { + const decoratorLines = [lines[startIndex] ?? ''] + let index = startIndex + let balance = parenthesesDelta(decoratorLines[0] ?? '') + + while (balance > 0 && index + 1 < lines.length) { + index += 1 + const line = lines[index] ?? '' + decoratorLines.push(line) + balance += parenthesesDelta(line) + } + + return { + decorator: decoratorLines.join('\n'), + endIndex: index, + } +} + +const routePathFromControllerPath = (controllerPath: string) => { + return controllerPath + .replace(/<(?:[^:<>]+:)?([^<>]+)>/g, '{$1}') + .replace(/\/+/g, '/') +} + +const routePathsFromDecorator = (decorator: string) => { + if (!decorator.includes('.route(')) + return [] + + return [...decorator.matchAll(/(['"])(.*?)\1/g)] + .map(([, , routePath]) => routePath) + .filter((routePath): routePath is string => typeof routePath === 'string' && routePath.startsWith('/')) + .map(routePathFromControllerPath) +} + +const methodBodyFrom = (lines: string[], methodLineIndex: number, methodIndent: number) => { + const bodyLines: string[] = [] + + for (let index = methodLineIndex + 1; index < lines.length; index += 1) { + const line = lines[index] ?? '' + if (line.trim() && leadingWhitespaceLength(line) <= methodIndent) + break + + bodyLines.push(line) + } + + return bodyLines.join('\n') +} + +const usesRuntimeJsonBody = (body: string) => { + return /\b(?:console_ns|service_api_ns|web_ns)\.payload\b/.test(body) + || /\brequest\.get_json\s*\(/.test(body) + || /\brequest\.json\b/.test(body) +} + +const collectRuntimeBodyOperationKeysFromFile = (surface: ApiSurface, filePath: string) => { + const operationKeys = new Set() + const lines = fs.readFileSync(filePath, 'utf8').split(/\r?\n/) + let pendingDecorators: string[] = [] + let currentRoutes: string[] = [] + let currentClassIndent: number | undefined + + for (let index = 0; index < lines.length; index += 1) { + const line = lines[index] ?? '' + const trimmed = line.trim() + + if (!trimmed) + continue + + if (trimmed.startsWith('@')) { + const { decorator, endIndex } = collectDecorator(lines, index) + pendingDecorators.push(decorator) + index = endIndex + continue + } + + const indent = leadingWhitespaceLength(line) + const classMatch = line.match(/^(\s*)class\s+\w+/) + if (classMatch) { + currentClassIndent = indent + currentRoutes = pendingDecorators.flatMap(routePathsFromDecorator) + pendingDecorators = [] + continue + } + + if (currentClassIndent !== undefined && indent <= currentClassIndent) + currentRoutes = [] + + const methodMatch = line.match(/^\s*def\s+(delete|get|patch|post|put)\s*\(/) + if (!methodMatch) { + pendingDecorators = [] + continue + } + + pendingDecorators = [] + + const method = methodMatch[1] + if (!method || !requestBodyMethods.has(method)) + continue + + if (currentRoutes.length === 0) + continue + + const body = methodBodyFrom(lines, index, indent) + if (!usesRuntimeJsonBody(body)) + continue + + for (const routePath of currentRoutes) + operationKeys.add(apiOperationKey(surface, method, routePath)) + } + + return operationKeys +} + +const collectRuntimeBodyOperationKeys = () => { + const surfaces = { + console: path.join(apiControllersDir, 'console'), + service: path.join(apiControllersDir, 'service_api'), + web: path.join(apiControllersDir, 'web'), + } satisfies Record + + const operationKeys = new Set() + + for (const [surface, directory] of Object.entries(surfaces) as [ApiSurface, string][]) { + for (const filePath of listPythonFiles(directory)) { + for (const operationKey of collectRuntimeBodyOperationKeysFromFile(surface, filePath)) + operationKeys.add(operationKey) + } + } + + return operationKeys +} + +const runtimeBodyOperationKeys = collectRuntimeBodyOperationKeys() + const collectDefinitionRefs = (value: unknown, refs: Set, visited = new WeakSet()) => { if (!value || typeof value !== 'object') return @@ -530,6 +708,7 @@ const hasLooseSchema = ( const hasPossiblyInaccurateGeneratedContractTypes = ( operation: SwaggerOperation, definitions: Record, + context: ApiOperationContext, ) => { const successResponses = Object.entries(operation.responses ?? {}) .filter(([status]) => /^2\d\d$/.test(status)) @@ -541,6 +720,9 @@ const hasPossiblyInaccurateGeneratedContractTypes = ( if (successResponsesWithBody.some(([, response]) => hasLooseSchema(response.schema, definitions))) return true + if (context.runtimeBodyRequired && !operation.parameters?.some(parameter => parameter.in === 'body')) + return true + return operation.parameters?.some((parameter) => { return parameter.in === 'body' && hasLooseSchema(parameter.schema, definitions) }) ?? false @@ -580,7 +762,11 @@ const normalizeOperations = (document: SwaggerDocument, surface: string) => { swaggerOperation.operationId = operationId(method, routePath) normalizeResponses(swaggerOperation) - const hasPossiblyInaccurateTypes = hasPossiblyInaccurateGeneratedContractTypes(swaggerOperation, definitions) + const hasPossiblyInaccurateTypes = hasPossiblyInaccurateGeneratedContractTypes(swaggerOperation, definitions, { + method, + routePath, + runtimeBodyRequired: runtimeBodyOperationKeys.has(apiOperationKey(surface, method, routePath)), + }) recordApiReadiness(surface, !hasPossiblyInaccurateTypes) if (method === 'get') diff --git a/packages/contracts/scripts/generate-api-readiness-readme.mjs b/packages/contracts/scripts/generate-api-readiness-readme.mjs index c75b944e2a..d063565aed 100644 --- a/packages/contracts/scripts/generate-api-readiness-readme.mjs +++ b/packages/contracts/scripts/generate-api-readiness-readme.mjs @@ -65,7 +65,7 @@ Readiness here means the generated contract operation is not marked with: Operations marked with that warning should not be migrated to blindly. Prefer fixing backend OpenAPI annotations first so the generated contract has accurate request and response types, then migrate callers endpoint by endpoint. -The current heuristic marks an operation as not ready when a request body or success response that should have a body contains a loose object type, or when an operation has no documented 2xx response. 204, 205, and 304 responses are treated as bodyless when the request type is otherwise accurate. +The current heuristic marks an operation as not ready when a request body or success response that should have a body contains a loose object type, when a mutating controller reads a JSON body that is not documented as a request body, or when an operation has no documented 2xx response. 204, 205, and 304 responses are treated as bodyless when the request type is otherwise accurate. ${readinessEndMarker} ` From a13ab760027a8acb6961a5c6bc7d0fe4b73fb109 Mon Sep 17 00:00:00 2001 From: arya rizky Date: Tue, 19 May 2026 13:19:35 +0700 Subject: [PATCH 7/7] fix(agenton): use AsyncGenerator return annotation for asynccontextmanager (#36361) Co-authored-by: Arya Rizky --- dify-agent/src/agenton/compositor/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dify-agent/src/agenton/compositor/core.py b/dify-agent/src/agenton/compositor/core.py index 355b143356..4e77e9c1e0 100644 --- a/dify-agent/src/agenton/compositor/core.py +++ b/dify-agent/src/agenton/compositor/core.py @@ -14,7 +14,7 @@ hydrated deterministically. """ from collections import OrderedDict -from collections.abc import AsyncIterator, Mapping, Sequence +from collections.abc import AsyncGenerator, Mapping, Sequence from contextlib import asynccontextmanager from dataclasses import dataclass from typing import Any, Generic, cast @@ -178,7 +178,7 @@ class Compositor(Generic[PromptT, ToolT, LayerPromptT, LayerToolT, UserPromptT, *, configs: Mapping[str, LayerConfigInput] | None = None, session_snapshot: CompositorSessionSnapshotValue | None = None, - ) -> AsyncIterator[CompositorRun[PromptT, ToolT, LayerPromptT, LayerToolT, UserPromptT, LayerUserPromptT]]: + ) -> AsyncGenerator[CompositorRun[PromptT, ToolT, LayerPromptT, LayerToolT, UserPromptT, LayerUserPromptT]]: """Create a fresh run, enter layers in graph order, and yield it. Configs are keyed by layer node name and validated before factories run.