perf(web): lazy load console contract shards (#38230)

This commit is contained in:
Stephen Zhou 2026-06-30 22:15:29 +08:00 committed by GitHub
parent baf2191ee3
commit 4b17f968a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 484 additions and 396 deletions

View File

@ -1,103 +1,54 @@
// This file is auto-generated by @hey-api/openapi-ts // This file is auto-generated by @hey-api/openapi-ts
import { account } from './account/orpc.gen' export const contractLoaders = {
import { activate } from './activate/orpc.gen' account: () => import('./account/orpc.gen').then(({ account }) => ({ account })),
import { agent } from './agent/orpc.gen' activate: () => import('./activate/orpc.gen').then(({ activate }) => ({ activate })),
import { allWorkspaces } from './all-workspaces/orpc.gen' agent: () => import('./agent/orpc.gen').then(({ agent }) => ({ agent })),
import { apiBasedExtension } from './api-based-extension/orpc.gen' allWorkspaces: () => import('./all-workspaces/orpc.gen').then(({ allWorkspaces }) => ({ allWorkspaces })),
import { apiKeyAuth } from './api-key-auth/orpc.gen' apiBasedExtension: () => import('./api-based-extension/orpc.gen').then(({ apiBasedExtension }) => ({ apiBasedExtension })),
import { appDslVersion } from './app-dsl-version/orpc.gen' apiKeyAuth: () => import('./api-key-auth/orpc.gen').then(({ apiKeyAuth }) => ({ apiKeyAuth })),
import { app } from './app/orpc.gen' app: () => import('./app/orpc.gen').then(({ app }) => ({ app })),
import { apps } from './apps/orpc.gen' appDslVersion: () => import('./app-dsl-version/orpc.gen').then(({ appDslVersion }) => ({ appDslVersion })),
import { auth } from './auth/orpc.gen' apps: () => import('./apps/orpc.gen').then(({ apps }) => ({ apps })),
import { billing } from './billing/orpc.gen' auth: () => import('./auth/orpc.gen').then(({ auth }) => ({ auth })),
import { codeBasedExtension } from './code-based-extension/orpc.gen' billing: () => import('./billing/orpc.gen').then(({ billing }) => ({ billing })),
import { compliance } from './compliance/orpc.gen' codeBasedExtension: () => import('./code-based-extension/orpc.gen').then(({ codeBasedExtension }) => ({ codeBasedExtension })),
import { dataSource } from './data-source/orpc.gen' compliance: () => import('./compliance/orpc.gen').then(({ compliance }) => ({ compliance })),
import { datasets } from './datasets/orpc.gen' dataSource: () => import('./data-source/orpc.gen').then(({ dataSource }) => ({ dataSource })),
import { emailCodeLogin } from './email-code-login/orpc.gen' datasets: () => import('./datasets/orpc.gen').then(({ datasets }) => ({ datasets })),
import { emailRegister } from './email-register/orpc.gen' emailCodeLogin: () => import('./email-code-login/orpc.gen').then(({ emailCodeLogin }) => ({ emailCodeLogin })),
import { explore } from './explore/orpc.gen' emailRegister: () => import('./email-register/orpc.gen').then(({ emailRegister }) => ({ emailRegister })),
import { features } from './features/orpc.gen' explore: () => import('./explore/orpc.gen').then(({ explore }) => ({ explore })),
import { files } from './files/orpc.gen' features: () => import('./features/orpc.gen').then(({ features }) => ({ features })),
import { forgotPassword } from './forgot-password/orpc.gen' files: () => import('./files/orpc.gen').then(({ files }) => ({ files })),
import { form } from './form/orpc.gen' forgotPassword: () => import('./forgot-password/orpc.gen').then(({ forgotPassword }) => ({ forgotPassword })),
import { info } from './info/orpc.gen' form: () => import('./form/orpc.gen').then(({ form }) => ({ form })),
import { installedApps } from './installed-apps/orpc.gen' info: () => import('./info/orpc.gen').then(({ info }) => ({ info })),
import { instructionGenerate } from './instruction-generate/orpc.gen' installedApps: () => import('./installed-apps/orpc.gen').then(({ installedApps }) => ({ installedApps })),
import { login } from './login/orpc.gen' instructionGenerate: () => import('./instruction-generate/orpc.gen').then(({ instructionGenerate }) => ({ instructionGenerate })),
import { logout } from './logout/orpc.gen' login: () => import('./login/orpc.gen').then(({ login }) => ({ login })),
import { notification } from './notification/orpc.gen' logout: () => import('./logout/orpc.gen').then(({ logout }) => ({ logout })),
import { notion } from './notion/orpc.gen' notification: () => import('./notification/orpc.gen').then(({ notification }) => ({ notification })),
import { oauth } from './oauth/orpc.gen' notion: () => import('./notion/orpc.gen').then(({ notion }) => ({ notion })),
import { rag } from './rag/orpc.gen' oauth: () => import('./oauth/orpc.gen').then(({ oauth }) => ({ oauth })),
import { refreshToken } from './refresh-token/orpc.gen' rag: () => import('./rag/orpc.gen').then(({ rag }) => ({ rag })),
import { remoteFiles } from './remote-files/orpc.gen' refreshToken: () => import('./refresh-token/orpc.gen').then(({ refreshToken }) => ({ refreshToken })),
import { resetPassword } from './reset-password/orpc.gen' remoteFiles: () => import('./remote-files/orpc.gen').then(({ remoteFiles }) => ({ remoteFiles })),
import { ruleCodeGenerate } from './rule-code-generate/orpc.gen' resetPassword: () => import('./reset-password/orpc.gen').then(({ resetPassword }) => ({ resetPassword })),
import { ruleGenerate } from './rule-generate/orpc.gen' ruleCodeGenerate: () => import('./rule-code-generate/orpc.gen').then(({ ruleCodeGenerate }) => ({ ruleCodeGenerate })),
import { ruleStructuredOutputGenerate } from './rule-structured-output-generate/orpc.gen' ruleGenerate: () => import('./rule-generate/orpc.gen').then(({ ruleGenerate }) => ({ ruleGenerate })),
import { snippets } from './snippets/orpc.gen' ruleStructuredOutputGenerate: () =>
import { spec } from './spec/orpc.gen' import('./rule-structured-output-generate/orpc.gen').then(({ ruleStructuredOutputGenerate }) => ({ ruleStructuredOutputGenerate })),
import { systemFeatures } from './system-features/orpc.gen' snippets: () => import('./snippets/orpc.gen').then(({ snippets }) => ({ snippets })),
import { tagBindings } from './tag-bindings/orpc.gen' spec: () => import('./spec/orpc.gen').then(({ spec }) => ({ spec })),
import { tags } from './tags/orpc.gen' systemFeatures: () => import('./system-features/orpc.gen').then(({ systemFeatures }) => ({ systemFeatures })),
import { test } from './test/orpc.gen' tagBindings: () => import('./tag-bindings/orpc.gen').then(({ tagBindings }) => ({ tagBindings })),
import { trialApps } from './trial-apps/orpc.gen' tags: () => import('./tags/orpc.gen').then(({ tags }) => ({ tags })),
import { trialModels } from './trial-models/orpc.gen' test: () => import('./test/orpc.gen').then(({ test }) => ({ test })),
import { website } from './website/orpc.gen' trialApps: () => import('./trial-apps/orpc.gen').then(({ trialApps }) => ({ trialApps })),
import { workflowGenerate } from './workflow-generate/orpc.gen' trialModels: () => import('./trial-models/orpc.gen').then(({ trialModels }) => ({ trialModels })),
import { workflow } from './workflow/orpc.gen' website: () => import('./website/orpc.gen').then(({ website }) => ({ website })),
import { workspaces } from './workspaces/orpc.gen' workflow: () => import('./workflow/orpc.gen').then(({ workflow }) => ({ workflow })),
workflowGenerate: () => import('./workflow-generate/orpc.gen').then(({ workflowGenerate }) => ({ workflowGenerate })),
export const contract = { workspaces: () => import('./workspaces/orpc.gen').then(({ workspaces }) => ({ workspaces })),
account,
activate,
agent,
allWorkspaces,
apiBasedExtension,
apiKeyAuth,
app,
appDslVersion,
apps,
auth,
billing,
codeBasedExtension,
compliance,
dataSource,
datasets,
emailCodeLogin,
emailRegister,
explore,
features,
files,
forgotPassword,
form,
info,
installedApps,
instructionGenerate,
login,
logout,
notification,
notion,
oauth,
rag,
refreshToken,
remoteFiles,
resetPassword,
ruleCodeGenerate,
ruleGenerate,
ruleStructuredOutputGenerate,
snippets,
spec,
systemFeatures,
tagBindings,
tags,
test,
trialApps,
trialModels,
website,
workflow,
workflowGenerate,
workspaces,
} }

View File

@ -344,16 +344,13 @@ const consoleContractEntryContent = (segments: string[]) => {
} }
}) })
const imports = contracts const contractEntries = contracts
.map(contract => `import { ${contract.name} } from './${contract.importPath}/orpc.gen'`) .map(contract => ` ${contract.name}: () => import('./${contract.importPath}/orpc.gen').then(({ ${contract.name} }) => ({ ${contract.name} })),`)
.join('\n') .join('\n')
const contractEntries = contracts.map(contract => ` ${contract.name},`).join('\n')
return `// This file is auto-generated by @hey-api/openapi-ts return `// This file is auto-generated by @hey-api/openapi-ts
${imports} export const contractLoaders = {
export const contract = {
${contractEntries} ${contractEntries}
} }
` `

View File

@ -1,5 +1,5 @@
import type { PluginsSearchParams } from './types' import type { PluginsSearchParams } from './types'
import type { MarketPlaceInputs } from '@/contract/router' import type { MarketPlaceInputs } from '@/contract/marketplace'
import { useInfiniteQuery, useQuery } from '@tanstack/react-query' import { useInfiniteQuery, useQuery } from '@tanstack/react-query'
import { marketplaceQuery } from '@/service/client' import { marketplaceQuery } from '@/service/client'
import { getMarketplaceCollectionsAndPlugins, getMarketplacePlugins } from './utils' import { getMarketplaceCollectionsAndPlugins, getMarketplacePlugins } from './utils'

View File

@ -0,0 +1,13 @@
import { agent } from '@dify/contracts/api/console/agent/orpc.gen'
import { agentDriveContracts } from './agent-drive'
export const agentRouterContract = {
...agent,
byAgentId: {
...agent.byAgentId,
drive: {
...agent.byAgentId.drive,
...agentDriveContracts.byAgentId.drive,
},
},
}

View File

@ -1,8 +1,10 @@
import type { AppListResponse, WorkflowOnlineUsersResponse } from '@/models/app' import type { AppListResponse, WorkflowOnlineUsersResponse } from '@/models/app'
import type { CommonResponse } from '@/models/common' import type { CommonResponse } from '@/models/common'
import type { AppModeEnum } from '@/types/app' import type { AppModeEnum } from '@/types/app'
import { apps } from '@dify/contracts/api/console/apps/orpc.gen'
import { type } from '@orpc/contract' import { type } from '@orpc/contract'
import { base } from '../base' import { base } from '../base'
import { agentDriveContracts } from './agent-drive'
export type AppListSortBy = 'last_modified' | 'recently_created' | 'earliest_created' export type AppListSortBy = 'last_modified' | 'recently_created' | 'earliest_created'
type AppListMode = AppModeEnum | 'agent' | 'channel' | 'all' type AppListMode = AppModeEnum | 'agent' | 'channel' | 'all'
@ -85,3 +87,24 @@ export const workflowOnlineUsersContract = base
} }
}>()) }>())
.output(type<WorkflowOnlineUsersResponse>()) .output(type<WorkflowOnlineUsersResponse>())
export const appsRouterContract = {
...apps,
list: appListContract,
deleteApp: appDeleteContract,
starredList: appStarredListContract,
star: appStarContract,
unstar: appUnstarContract,
workflowOnlineUsers: workflowOnlineUsersContract,
byAppId: {
...apps.byAppId,
agent: {
...apps.byAppId.agent,
...agentDriveContracts.byAppId.agent,
drive: {
...apps.byAppId.agent.drive,
...agentDriveContracts.byAppId.agent.drive,
},
},
},
}

View File

@ -1,3 +1,4 @@
import { billing } from '@dify/contracts/api/console/billing/orpc.gen'
import { type } from '@orpc/contract' import { type } from '@orpc/contract'
import { base } from '../base' import { base } from '../base'
@ -23,3 +24,9 @@ export const bindPartnerStackContract = base
} }
}>()) }>())
.output(type<unknown>()) .output(type<unknown>())
export const billingRouterContract = {
...billing,
invoices: invoicesContract,
bindPartnerStack: bindPartnerStackContract,
}

View File

@ -5,6 +5,7 @@ import type { Banner } from '@/models/app'
import type { App, AppCategory, InstalledApp } from '@/models/explore' import type { App, AppCategory, InstalledApp } from '@/models/explore'
import type { AppMeta } from '@/models/share' import type { AppMeta } from '@/models/share'
import type { AppModeEnum } from '@/types/app' import type { AppModeEnum } from '@/types/app'
import { explore } from '@dify/contracts/api/console/explore/orpc.gen'
import { type } from '@orpc/contract' import { type } from '@orpc/contract'
import { base } from '../base' import { base } from '../base'
@ -142,3 +143,18 @@ export const exploreBannersContract = base
}) })
.input(type<{ query?: { language?: string } }>()) .input(type<{ query?: { language?: string } }>())
.output(type<Banner[]>()) .output(type<Banner[]>())
export const exploreRouterContract = {
...explore,
apps: exploreAppsContract,
learnDifyApps: learnDifyAppsContract,
appDetail: exploreAppDetailContract,
installedApps: exploreInstalledAppsContract,
uninstallInstalledApp: exploreInstalledAppUninstallContract,
updateInstalledApp: exploreInstalledAppPinContract,
appAccessMode: exploreInstalledAppAccessModeContract,
updateAppAccessMode: exploreInstalledAppAccessModeUpdateContract,
installedAppParameters: exploreInstalledAppParametersContract,
installedAppMeta: exploreInstalledAppMetaContract,
banners: exploreBannersContract,
}

View File

@ -1,4 +1,5 @@
import type { PostFilesUploadResponse } from '@dify/contracts/api/console/files/types.gen' import type { PostFilesUploadResponse } from '@dify/contracts/api/console/files/types.gen'
import { files } from '@dify/contracts/api/console/files/orpc.gen'
import { type } from '@orpc/contract' import { type } from '@orpc/contract'
import { base } from '../base' import { base } from '../base'
@ -14,3 +15,11 @@ export const fileUploadContract = base
} }
}>()) }>())
.output(type<PostFilesUploadResponse>()) .output(type<PostFilesUploadResponse>())
export const filesRouterContract = {
...files,
upload: {
...files.upload,
post: fileUploadContract,
},
}

View File

@ -31,3 +31,8 @@ export const changePreferredProviderTypeContract = base
} }
}>()) }>())
.output(type<CommonResponse>()) .output(type<CommonResponse>())
export const modelProvidersRouterContract = {
models: modelProvidersModelsContract,
changePreferredProviderType: changePreferredProviderTypeContract,
}

View File

@ -25,3 +25,8 @@ export const pluginLatestVersionsContract = base
} }
}>()) }>())
.output(type<InstalledLatestVersionResponse>()) .output(type<InstalledLatestVersionResponse>())
export const pluginsRouterContract = {
checkInstalled: pluginCheckInstalledContract,
latestVersions: pluginLatestVersionsContract,
}

View File

@ -342,3 +342,31 @@ export const stopSnippetWorkflowTaskContract = base
} }
}>()) }>())
.output(type<unknown>()) .output(type<unknown>())
export const snippetsRouterContract = {
list: listCustomizedSnippetsContract,
create: createCustomizedSnippetContract,
detail: getCustomizedSnippetContract,
update: updateCustomizedSnippetContract,
delete: deleteCustomizedSnippetContract,
export: exportCustomizedSnippetContract,
import: importCustomizedSnippetContract,
confirmImport: confirmSnippetImportContract,
checkDependencies: checkSnippetDependenciesContract,
incrementUseCount: incrementSnippetUseCountContract,
draftWorkflow: getSnippetDraftWorkflowContract,
syncDraftWorkflow: syncSnippetDraftWorkflowContract,
draftConfig: getSnippetDraftConfigContract,
publishedWorkflow: getSnippetPublishedWorkflowContract,
publishWorkflow: publishSnippetWorkflowContract,
defaultBlockConfigs: getSnippetDefaultBlockConfigsContract,
workflowRuns: listSnippetWorkflowRunsContract,
workflowRunDetail: getSnippetWorkflowRunDetailContract,
workflowRunNodeExecutions: listSnippetWorkflowRunNodeExecutionsContract,
runDraftNode: runSnippetDraftNodeContract,
lastDraftNodeRun: getSnippetDraftNodeLastRunContract,
runDraftIterationNode: runSnippetDraftIterationNodeContract,
runDraftLoopNode: runSnippetDraftLoopNodeContract,
runDraftWorkflow: runSnippetDraftWorkflowContract,
stopWorkflowTask: stopSnippetWorkflowTaskContract,
}

View File

@ -1,3 +1,4 @@
import { tags } from '@dify/contracts/api/console/tags/orpc.gen'
import { type } from '@orpc/contract' import { type } from '@orpc/contract'
import { base } from '../base' import { base } from '../base'
@ -89,3 +90,13 @@ export const tagBindingRemoveContract = base
} }
}>()) }>())
.output(type<unknown>()) .output(type<unknown>())
export const tagsRouterContract = {
...tags,
list: tagListContract,
create: tagCreateContract,
update: tagUpdateContract,
delete: tagDeleteContract,
bind: tagBindingCreateContract,
unbind: tagBindingRemoveContract,
}

View File

@ -117,3 +117,21 @@ export const triggerOAuthInitiateContract = base
.route({ path: '/workspaces/current/trigger-provider/{provider}/subscriptions/oauth/authorize', method: 'GET' }) .route({ path: '/workspaces/current/trigger-provider/{provider}/subscriptions/oauth/authorize', method: 'GET' })
.input(type<{ params: { provider: string } }>()) .input(type<{ params: { provider: string } }>())
.output(type<{ authorization_url: string, subscription_builder: TriggerSubscriptionBuilder }>()) .output(type<{ authorization_url: string, subscription_builder: TriggerSubscriptionBuilder }>())
export const triggersRouterContract = {
list: triggersContract,
providerInfo: triggerProviderInfoContract,
subscriptions: triggerSubscriptionsContract,
subscriptionBuilderCreate: triggerSubscriptionBuilderCreateContract,
subscriptionBuilderUpdate: triggerSubscriptionBuilderUpdateContract,
subscriptionBuilderVerifyUpdate: triggerSubscriptionBuilderVerifyUpdateContract,
subscriptionVerify: triggerSubscriptionVerifyContract,
subscriptionBuild: triggerSubscriptionBuildContract,
subscriptionDelete: triggerSubscriptionDeleteContract,
subscriptionUpdate: triggerSubscriptionUpdateContract,
subscriptionBuilderLogs: triggerSubscriptionBuilderLogsContract,
oauthConfig: triggerOAuthConfigContract,
oauthConfigure: triggerOAuthConfigureContract,
oauthDelete: triggerOAuthDeleteContract,
oauthInitiate: triggerOAuthInitiateContract,
}

View File

@ -1,6 +1,7 @@
import type { ChatConfig } from '@/app/components/base/chat/types' import type { ChatConfig } from '@/app/components/base/chat/types'
import type { DataSetListResponse } from '@/models/datasets' import type { DataSetListResponse } from '@/models/datasets'
import type { TryAppFlowPreview, TryAppInfo } from '@/models/try-app' import type { TryAppFlowPreview, TryAppInfo } from '@/models/try-app'
import { trialApps } from '@dify/contracts/api/console/trial-apps/orpc.gen'
import { type } from '@orpc/contract' import { type } from '@orpc/contract'
import { base } from '../base' import { base } from '../base'
@ -54,3 +55,11 @@ export const trialAppParametersContract = base
} }
}>()) }>())
.output(type<ChatConfig>()) .output(type<ChatConfig>())
export const trialAppsRouterContract = {
...trialApps,
info: trialAppInfoContract,
datasets: trialAppDatasetsContract,
parameters: trialAppParametersContract,
workflows: trialAppWorkflowsContract,
}

View File

@ -78,3 +78,10 @@ export const workflowDraftUpdateFeaturesContract = base
} }
}>()) }>())
.output(type<CommonResponse>()) .output(type<CommonResponse>())
export const workflowDraftRouterContract = {
environmentVariables: workflowDraftEnvironmentVariablesContract,
updateEnvironmentVariables: workflowDraftUpdateEnvironmentVariablesContract,
updateConversationVariables: workflowDraftUpdateConversationVariablesContract,
updateFeatures: workflowDraftUpdateFeaturesContract,
}

View File

@ -1,3 +1,4 @@
import { workspaces } from '@dify/contracts/api/console/workspaces/orpc.gen'
import { type } from '@orpc/contract' import { type } from '@orpc/contract'
import { base } from '../base' import { base } from '../base'
@ -54,3 +55,11 @@ export const workspaceSwitchContract = base
body: SwitchWorkspaceRequest body: SwitchWorkspaceRequest
}>()) }>())
.output(type<SwitchWorkspaceResponse>()) .output(type<SwitchWorkspaceResponse>())
export const workspacesRouterContract = {
...workspaces,
get: workspacesGetContract,
switch: {
post: workspaceSwitchContract,
},
}

View File

@ -1,10 +1,11 @@
import type { InferContractRouterInputs } from '@orpc/contract'
import type { CollectionsAndPluginsSearchParams, MarketplaceCollection, PluginsSearchParams } from '@/app/components/plugins/marketplace/types' import type { CollectionsAndPluginsSearchParams, MarketplaceCollection, PluginsSearchParams } from '@/app/components/plugins/marketplace/types'
import type { Plugin, PluginsFromMarketplaceResponse } from '@/app/components/plugins/types' import type { Plugin, PluginsFromMarketplaceResponse } from '@/app/components/plugins/types'
import type { MarketplaceTemplate } from '@/types/marketplace-template' import type { MarketplaceTemplate } from '@/types/marketplace-template'
import { type } from '@orpc/contract' import { type } from '@orpc/contract'
import { base } from './base' import { base } from './base'
export const collectionsContract = base const collectionsContract = base
.route({ .route({
path: '/collections', path: '/collections',
method: 'GET', method: 'GET',
@ -22,7 +23,7 @@ export const collectionsContract = base
}>(), }>(),
) )
export const collectionPluginsContract = base const collectionPluginsContract = base
.route({ .route({
path: '/collections/{collectionId}/plugins', path: '/collections/{collectionId}/plugins',
method: 'POST', method: 'POST',
@ -43,7 +44,7 @@ export const collectionPluginsContract = base
}>(), }>(),
) )
export const searchAdvancedContract = base const searchAdvancedContract = base
.route({ .route({
path: '/{kind}/search/advanced', path: '/{kind}/search/advanced',
method: 'POST', method: 'POST',
@ -56,7 +57,7 @@ export const searchAdvancedContract = base
}>()) }>())
.output(type<{ data: PluginsFromMarketplaceResponse }>()) .output(type<{ data: PluginsFromMarketplaceResponse }>())
export const templateDetailContract = base const templateDetailContract = base
.route({ .route({
path: '/templates/{templateId}', path: '/templates/{templateId}',
method: 'GET', method: 'GET',
@ -68,7 +69,7 @@ export const templateDetailContract = base
}>()) }>())
.output(type<{ data: MarketplaceTemplate }>()) .output(type<{ data: MarketplaceTemplate }>())
export const downloadPluginContract = base const downloadPluginContract = base
.route({ .route({
path: '/plugins/{organization}/{pluginName}/{version}/download', path: '/plugins/{organization}/{pluginName}/{version}/download',
method: 'GET', method: 'GET',
@ -81,3 +82,13 @@ export const downloadPluginContract = base
} }
}>()) }>())
.output(type<Blob>()) .output(type<Blob>())
export const marketplaceRouterContract = {
collections: collectionsContract,
collectionPlugins: collectionPluginsContract,
searchAdvanced: searchAdvancedContract,
templateDetail: templateDetailContract,
downloadPlugin: downloadPluginContract,
}
export type MarketPlaceInputs = InferContractRouterInputs<typeof marketplaceRouterContract>

View File

@ -1,249 +1,120 @@
import type { InferContractRouterInputs } from '@orpc/contract' import { account } from '@dify/contracts/api/console/account/orpc.gen'
import { contract as communityContract } from '@dify/contracts/api/console/orpc.gen' import { activate } from '@dify/contracts/api/console/activate/orpc.gen'
import { allWorkspaces } from '@dify/contracts/api/console/all-workspaces/orpc.gen'
import { apiBasedExtension } from '@dify/contracts/api/console/api-based-extension/orpc.gen'
import { apiKeyAuth } from '@dify/contracts/api/console/api-key-auth/orpc.gen'
import { appDslVersion } from '@dify/contracts/api/console/app-dsl-version/orpc.gen'
import { app } from '@dify/contracts/api/console/app/orpc.gen'
import { auth } from '@dify/contracts/api/console/auth/orpc.gen'
import { codeBasedExtension } from '@dify/contracts/api/console/code-based-extension/orpc.gen'
import { compliance } from '@dify/contracts/api/console/compliance/orpc.gen'
import { dataSource } from '@dify/contracts/api/console/data-source/orpc.gen'
import { datasets } from '@dify/contracts/api/console/datasets/orpc.gen'
import { emailCodeLogin } from '@dify/contracts/api/console/email-code-login/orpc.gen'
import { emailRegister } from '@dify/contracts/api/console/email-register/orpc.gen'
import { features } from '@dify/contracts/api/console/features/orpc.gen'
import { forgotPassword } from '@dify/contracts/api/console/forgot-password/orpc.gen'
import { form } from '@dify/contracts/api/console/form/orpc.gen'
import { info } from '@dify/contracts/api/console/info/orpc.gen'
import { installedApps } from '@dify/contracts/api/console/installed-apps/orpc.gen'
import { instructionGenerate } from '@dify/contracts/api/console/instruction-generate/orpc.gen'
import { login } from '@dify/contracts/api/console/login/orpc.gen'
import { logout } from '@dify/contracts/api/console/logout/orpc.gen'
import { notion } from '@dify/contracts/api/console/notion/orpc.gen'
import { oauth } from '@dify/contracts/api/console/oauth/orpc.gen'
import { rag } from '@dify/contracts/api/console/rag/orpc.gen'
import { refreshToken } from '@dify/contracts/api/console/refresh-token/orpc.gen'
import { remoteFiles } from '@dify/contracts/api/console/remote-files/orpc.gen'
import { resetPassword } from '@dify/contracts/api/console/reset-password/orpc.gen'
import { ruleCodeGenerate } from '@dify/contracts/api/console/rule-code-generate/orpc.gen'
import { ruleGenerate } from '@dify/contracts/api/console/rule-generate/orpc.gen'
import { ruleStructuredOutputGenerate } from '@dify/contracts/api/console/rule-structured-output-generate/orpc.gen'
import { spec } from '@dify/contracts/api/console/spec/orpc.gen'
import { systemFeatures } from '@dify/contracts/api/console/system-features/orpc.gen'
import { tagBindings } from '@dify/contracts/api/console/tag-bindings/orpc.gen'
import { test } from '@dify/contracts/api/console/test/orpc.gen'
import { trialModels } from '@dify/contracts/api/console/trial-models/orpc.gen'
import { website } from '@dify/contracts/api/console/website/orpc.gen'
import { workflowGenerate } from '@dify/contracts/api/console/workflow-generate/orpc.gen'
import { workflow } from '@dify/contracts/api/console/workflow/orpc.gen'
import { contract as enterpriseContract } from '@dify/contracts/enterprise/orpc.gen' import { contract as enterpriseContract } from '@dify/contracts/enterprise/orpc.gen'
import { rbacAccessConfigContract } from './console/access-control' import { rbacAccessConfigContract } from './console/access-control'
import { agentDriveContracts } from './console/agent-drive' import { agentRouterContract } from './console/agent'
import { import { appsRouterContract } from './console/apps'
appDeleteContract, import { billingRouterContract } from './console/billing'
appListContract, import { exploreRouterContract } from './console/explore'
appStarContract, import { filesRouterContract } from './console/files'
appStarredListContract, import { modelProvidersRouterContract } from './console/model-providers'
appUnstarContract,
workflowOnlineUsersContract,
} from './console/apps'
import { bindPartnerStackContract, invoicesContract } from './console/billing'
import {
exploreAppDetailContract,
exploreAppsContract,
exploreBannersContract,
exploreInstalledAppAccessModeContract,
exploreInstalledAppAccessModeUpdateContract,
exploreInstalledAppMetaContract,
exploreInstalledAppParametersContract,
exploreInstalledAppPinContract,
exploreInstalledAppsContract,
exploreInstalledAppUninstallContract,
learnDifyAppsContract,
} from './console/explore'
import { fileUploadContract } from './console/files'
import { changePreferredProviderTypeContract, modelProvidersModelsContract } from './console/model-providers'
import { notificationContract, notificationDismissContract } from './console/notification' import { notificationContract, notificationDismissContract } from './console/notification'
import { pluginCheckInstalledContract, pluginLatestVersionsContract } from './console/plugins' import { pluginsRouterContract } from './console/plugins'
import { import { snippetsRouterContract } from './console/snippets'
checkSnippetDependenciesContract, import { tagsRouterContract } from './console/tags'
confirmSnippetImportContract, import { triggersRouterContract } from './console/trigger'
createCustomizedSnippetContract, import { trialAppsRouterContract } from './console/try-app'
deleteCustomizedSnippetContract, import { workflowDraftRouterContract } from './console/workflow'
exportCustomizedSnippetContract,
getCustomizedSnippetContract,
getSnippetDefaultBlockConfigsContract,
getSnippetDraftConfigContract,
getSnippetDraftNodeLastRunContract,
getSnippetDraftWorkflowContract,
getSnippetPublishedWorkflowContract,
getSnippetWorkflowRunDetailContract,
importCustomizedSnippetContract,
incrementSnippetUseCountContract,
listCustomizedSnippetsContract,
listSnippetWorkflowRunNodeExecutionsContract,
listSnippetWorkflowRunsContract,
publishSnippetWorkflowContract,
runSnippetDraftIterationNodeContract,
runSnippetDraftLoopNodeContract,
runSnippetDraftNodeContract,
runSnippetDraftWorkflowContract,
stopSnippetWorkflowTaskContract,
syncSnippetDraftWorkflowContract,
updateCustomizedSnippetContract,
} from './console/snippets'
import {
tagBindingCreateContract,
tagBindingRemoveContract,
tagCreateContract,
tagDeleteContract,
tagListContract,
tagUpdateContract,
} from './console/tags'
import {
triggerOAuthConfigContract,
triggerOAuthConfigureContract,
triggerOAuthDeleteContract,
triggerOAuthInitiateContract,
triggerProviderInfoContract,
triggersContract,
triggerSubscriptionBuildContract,
triggerSubscriptionBuilderCreateContract,
triggerSubscriptionBuilderLogsContract,
triggerSubscriptionBuilderUpdateContract,
triggerSubscriptionBuilderVerifyUpdateContract,
triggerSubscriptionDeleteContract,
triggerSubscriptionsContract,
triggerSubscriptionUpdateContract,
triggerSubscriptionVerifyContract,
} from './console/trigger'
import { trialAppDatasetsContract, trialAppInfoContract, trialAppParametersContract, trialAppWorkflowsContract } from './console/try-app'
import {
workflowDraftEnvironmentVariablesContract,
workflowDraftUpdateConversationVariablesContract,
workflowDraftUpdateEnvironmentVariablesContract,
workflowDraftUpdateFeaturesContract,
} from './console/workflow'
import { workflowCommentContracts } from './console/workflow-comment' import { workflowCommentContracts } from './console/workflow-comment'
import { workspacesGetContract, workspaceSwitchContract } from './console/workspaces' import { workspacesRouterContract } from './console/workspaces'
import { collectionPluginsContract, collectionsContract, downloadPluginContract, searchAdvancedContract, templateDetailContract } from './marketplace'
export const marketplaceRouterContract = { const communityContract = {
collections: collectionsContract, account,
collectionPlugins: collectionPluginsContract, activate,
searchAdvanced: searchAdvancedContract, allWorkspaces,
templateDetail: templateDetailContract, apiBasedExtension,
downloadPlugin: downloadPluginContract, apiKeyAuth,
app,
appDslVersion,
auth,
codeBasedExtension,
compliance,
dataSource,
datasets,
emailCodeLogin,
emailRegister,
features,
forgotPassword,
form,
info,
installedApps,
instructionGenerate,
login,
logout,
notion,
oauth,
rag,
refreshToken,
remoteFiles,
resetPassword,
ruleCodeGenerate,
ruleGenerate,
ruleStructuredOutputGenerate,
spec,
systemFeatures,
tagBindings,
test,
trialModels,
website,
workflow,
workflowGenerate,
} }
export type MarketPlaceInputs = InferContractRouterInputs<typeof marketplaceRouterContract>
export const consoleRouterContract = { export const consoleRouterContract = {
enterprise: enterpriseContract, enterprise: enterpriseContract,
...communityContract, ...communityContract,
apps: { agent: agentRouterContract,
...communityContract.apps, apps: appsRouterContract,
list: appListContract, billing: billingRouterContract,
deleteApp: appDeleteContract, explore: exploreRouterContract,
starredList: appStarredListContract, files: filesRouterContract,
star: appStarContract, modelProviders: modelProvidersRouterContract,
unstar: appUnstarContract,
workflowOnlineUsers: workflowOnlineUsersContract,
byAppId: {
...communityContract.apps.byAppId,
agent: {
...communityContract.apps.byAppId.agent,
...agentDriveContracts.byAppId.agent,
drive: {
...communityContract.apps.byAppId.agent.drive,
...agentDriveContracts.byAppId.agent.drive,
},
},
},
},
agent: {
...communityContract.agent,
byAgentId: {
...communityContract.agent.byAgentId,
drive: {
...communityContract.agent.byAgentId.drive,
...agentDriveContracts.byAgentId.drive,
},
},
},
explore: {
...communityContract.explore,
apps: exploreAppsContract,
learnDifyApps: learnDifyAppsContract,
appDetail: exploreAppDetailContract,
installedApps: exploreInstalledAppsContract,
uninstallInstalledApp: exploreInstalledAppUninstallContract,
updateInstalledApp: exploreInstalledAppPinContract,
appAccessMode: exploreInstalledAppAccessModeContract,
updateAppAccessMode: exploreInstalledAppAccessModeUpdateContract,
installedAppParameters: exploreInstalledAppParametersContract,
installedAppMeta: exploreInstalledAppMetaContract,
banners: exploreBannersContract,
},
trialApps: {
...communityContract.trialApps,
info: trialAppInfoContract,
datasets: trialAppDatasetsContract,
parameters: trialAppParametersContract,
workflows: trialAppWorkflowsContract,
},
files: {
...communityContract.files,
upload: {
...communityContract.files.upload,
post: fileUploadContract,
},
},
modelProviders: {
models: modelProvidersModelsContract,
changePreferredProviderType: changePreferredProviderTypeContract,
},
plugins: {
checkInstalled: pluginCheckInstalledContract,
latestVersions: pluginLatestVersionsContract,
},
rbacAccessConfig: rbacAccessConfigContract,
snippets: {
list: listCustomizedSnippetsContract,
create: createCustomizedSnippetContract,
detail: getCustomizedSnippetContract,
update: updateCustomizedSnippetContract,
delete: deleteCustomizedSnippetContract,
export: exportCustomizedSnippetContract,
import: importCustomizedSnippetContract,
confirmImport: confirmSnippetImportContract,
checkDependencies: checkSnippetDependenciesContract,
incrementUseCount: incrementSnippetUseCountContract,
draftWorkflow: getSnippetDraftWorkflowContract,
syncDraftWorkflow: syncSnippetDraftWorkflowContract,
draftConfig: getSnippetDraftConfigContract,
publishedWorkflow: getSnippetPublishedWorkflowContract,
publishWorkflow: publishSnippetWorkflowContract,
defaultBlockConfigs: getSnippetDefaultBlockConfigsContract,
workflowRuns: listSnippetWorkflowRunsContract,
workflowRunDetail: getSnippetWorkflowRunDetailContract,
workflowRunNodeExecutions: listSnippetWorkflowRunNodeExecutionsContract,
runDraftNode: runSnippetDraftNodeContract,
lastDraftNodeRun: getSnippetDraftNodeLastRunContract,
runDraftIterationNode: runSnippetDraftIterationNodeContract,
runDraftLoopNode: runSnippetDraftLoopNodeContract,
runDraftWorkflow: runSnippetDraftWorkflowContract,
stopWorkflowTask: stopSnippetWorkflowTaskContract,
},
billing: {
...communityContract.billing,
invoices: invoicesContract,
bindPartnerStack: bindPartnerStackContract,
},
workflowDraft: {
environmentVariables: workflowDraftEnvironmentVariablesContract,
updateEnvironmentVariables: workflowDraftUpdateEnvironmentVariablesContract,
updateConversationVariables: workflowDraftUpdateConversationVariablesContract,
updateFeatures: workflowDraftUpdateFeaturesContract,
},
workflowComments: workflowCommentContracts,
notification: notificationContract, notification: notificationContract,
notificationDismiss: notificationDismissContract, notificationDismiss: notificationDismissContract,
tags: { plugins: pluginsRouterContract,
...communityContract.tags, rbacAccessConfig: rbacAccessConfigContract,
list: tagListContract, snippets: snippetsRouterContract,
create: tagCreateContract, tags: tagsRouterContract,
update: tagUpdateContract, triggers: triggersRouterContract,
delete: tagDeleteContract, trialApps: trialAppsRouterContract,
bind: tagBindingCreateContract, workflowComments: workflowCommentContracts,
unbind: tagBindingRemoveContract, workflowDraft: workflowDraftRouterContract,
}, workspaces: workspacesRouterContract,
triggers: {
list: triggersContract,
providerInfo: triggerProviderInfoContract,
subscriptions: triggerSubscriptionsContract,
subscriptionBuilderCreate: triggerSubscriptionBuilderCreateContract,
subscriptionBuilderUpdate: triggerSubscriptionBuilderUpdateContract,
subscriptionBuilderVerifyUpdate: triggerSubscriptionBuilderVerifyUpdateContract,
subscriptionVerify: triggerSubscriptionVerifyContract,
subscriptionBuild: triggerSubscriptionBuildContract,
subscriptionDelete: triggerSubscriptionDeleteContract,
subscriptionUpdate: triggerSubscriptionUpdateContract,
subscriptionBuilderLogs: triggerSubscriptionBuilderLogsContract,
oauthConfig: triggerOAuthConfigContract,
oauthConfigure: triggerOAuthConfigureContract,
oauthDelete: triggerOAuthDeleteContract,
oauthInitiate: triggerOAuthInitiateContract,
},
workspaces: {
...communityContract.workspaces,
get: workspacesGetContract,
switch: {
post: workspaceSwitchContract,
},
},
} }

View File

@ -2,20 +2,21 @@
import type { ContractRouterClient } from '@orpc/contract' import type { ContractRouterClient } from '@orpc/contract'
import type { JsonifiedClient } from '@orpc/openapi-client' import type { JsonifiedClient } from '@orpc/openapi-client'
import type { ConsoleRouterContract } from '@/service/console-link'
import { createORPCClient } from '@orpc/client' import { createORPCClient } from '@orpc/client'
import { OpenAPILink } from '@orpc/openapi-client/fetch' import { OpenAPILink } from '@orpc/openapi-client/fetch'
import { createTanstackQueryUtils } from '@orpc/tanstack-query' import { createTanstackQueryUtils } from '@orpc/tanstack-query'
import { API_PREFIX } from '@/config' import { API_PREFIX } from '@/config'
import { consoleRouterContract } from '@/contract/router'
// eslint-disable-next-line no-restricted-imports // eslint-disable-next-line no-restricted-imports
import { request } from '@/service/base' import { request } from '@/service/base'
import { getBaseURL } from '@/service/client' import { getBaseURL } from '@/service/client'
import { createConsoleDynamicLink } from '@/service/console-link'
type AgentConfigureConsoleClientContext = { type AgentConfigureConsoleClientContext = {
silent?: boolean silent?: boolean
} }
const agentConfigureConsoleLink = new OpenAPILink<AgentConfigureConsoleClientContext>(consoleRouterContract, { const agentConfigureConsoleLink = createConsoleDynamicLink<AgentConfigureConsoleClientContext>(contract => new OpenAPILink<AgentConfigureConsoleClientContext>(contract, {
url: getBaseURL(API_PREFIX), url: getBaseURL(API_PREFIX),
fetch: (input, init, options) => { fetch: (input, init, options) => {
return request( return request(
@ -28,9 +29,9 @@ const agentConfigureConsoleLink = new OpenAPILink<AgentConfigureConsoleClientCon
}, },
) )
}, },
}) }))
const agentConfigureConsoleClient: JsonifiedClient<ContractRouterClient<typeof consoleRouterContract, AgentConfigureConsoleClientContext>> const agentConfigureConsoleClient: JsonifiedClient<ContractRouterClient<ConsoleRouterContract, AgentConfigureConsoleClientContext>>
= createORPCClient(agentConfigureConsoleLink) = createORPCClient(agentConfigureConsoleLink)
export const agentConfigureConsoleQuery = createTanstackQueryUtils(agentConfigureConsoleClient, { export const agentConfigureConsoleQuery = createTanstackQueryUtils(agentConfigureConsoleClient, {

View File

@ -38,7 +38,6 @@ const config: KnipConfig = {
'i18n-config/locale-resources/*.ts', 'i18n-config/locale-resources/*.ts',
], ],
ignoreBinaries: [ ignoreBinaries: [
'only-allow',
'pbcopy', 'pbcopy',
'which', 'which',
], ],

View File

@ -5,11 +5,13 @@ import type {
ListReleasesResponse, ListReleasesResponse,
PrecheckReleaseRequest, PrecheckReleaseRequest,
} from '@dify/contracts/enterprise/types.gen' } from '@dify/contracts/enterprise/types.gen'
import type { ContractRouterClient } from '@orpc/contract' import type { ClientLink } from '@orpc/client'
import type { AnyContractRouter, ContractRouterClient } from '@orpc/contract'
import type { JsonifiedClient } from '@orpc/openapi-client' import type { JsonifiedClient } from '@orpc/openapi-client'
import type { RouterUtils } from '@orpc/tanstack-query' import type { RouterUtils } from '@orpc/tanstack-query'
import type { InfiniteData, QueryClient, QueryKey } from '@tanstack/react-query' import type { InfiniteData, QueryClient, QueryKey } from '@tanstack/react-query'
import type { Tag } from '@/contract/console/tags' import type { Tag } from '@/contract/console/tags'
import type { consoleRouterContract } from '@/contract/router'
import { createORPCClient, onError } from '@orpc/client' import { createORPCClient, onError } from '@orpc/client'
import { OpenAPILink } from '@orpc/openapi-client/fetch' import { OpenAPILink } from '@orpc/openapi-client/fetch'
import { createTanstackQueryUtils } from '@orpc/tanstack-query' import { createTanstackQueryUtils } from '@orpc/tanstack-query'
@ -19,13 +21,11 @@ import {
IS_MARKETPLACE, IS_MARKETPLACE,
MARKETPLACE_API_PREFIX, MARKETPLACE_API_PREFIX,
} from '@/config' } from '@/config'
import { import { marketplaceRouterContract } from '@/contract/marketplace'
consoleRouterContract,
marketplaceRouterContract,
} from '@/contract/router'
import { isClient } from '@/utils/client' import { isClient } from '@/utils/client'
// eslint-disable-next-line no-restricted-imports // eslint-disable-next-line no-restricted-imports
import { request } from './base' import { request } from './base'
import { createConsoleDynamicLink } from './console-link'
function getMarketplaceHeaders() { function getMarketplaceHeaders() {
return new Headers({ return new Headers({
@ -58,6 +58,30 @@ export function getBaseURL(path: string) {
return url return url
} }
type ConsoleClientContext = Record<never, never>
type ConsoleClientLink = ClientLink<ConsoleClientContext>
function createConsoleOpenAPILink(contract: AnyContractRouter): ConsoleClientLink {
return new OpenAPILink<ConsoleClientContext>(contract, {
url: getBaseURL(API_PREFIX),
fetch: (input, init) => {
return request(
input.url,
init,
{
fetchCompat: true,
request: input,
},
)
},
interceptors: [
onError((error) => {
console.error(error)
}),
],
})
}
const marketplaceLink = new OpenAPILink(marketplaceRouterContract, { const marketplaceLink = new OpenAPILink(marketplaceRouterContract, {
url: MARKETPLACE_API_PREFIX, url: MARKETPLACE_API_PREFIX,
headers: () => (getMarketplaceHeaders()), headers: () => (getMarketplaceHeaders()),
@ -323,24 +347,7 @@ async function invalidateReleaseMutationQueries(
]) ])
} }
const consoleLink = new OpenAPILink(consoleRouterContract, { const consoleLink = createConsoleDynamicLink<ConsoleClientContext>(createConsoleOpenAPILink)
url: getBaseURL(API_PREFIX),
fetch: (input, init) => {
return request(
input.url,
init,
{
fetchCompat: true,
request: input,
},
)
},
interceptors: [
onError((error) => {
console.error(error)
}),
],
})
export const consoleClient: JsonifiedClient<ContractRouterClient<typeof consoleRouterContract>> = createORPCClient(consoleLink) export const consoleClient: JsonifiedClient<ContractRouterClient<typeof consoleRouterContract>> = createORPCClient(consoleLink)

View File

@ -0,0 +1,32 @@
import type { ClientContext, ClientLink } from '@orpc/client'
import type { AnyContractRouter } from '@orpc/contract'
import type { consoleRouterContract } from '@/contract/router'
import { DynamicLink } from '@orpc/client'
import { loadConsoleContractForSegment } from './console-router-loader'
export type ConsoleRouterContract = typeof consoleRouterContract
export function createConsoleDynamicLink<TContext extends ClientContext>(
createLink: (contract: AnyContractRouter) => ClientLink<TContext>,
) {
const routerLinkPromises = new Map<string, Promise<ClientLink<TContext>>>()
function getRouterLink(path: readonly string[]) {
const segment = path[0]
if (!segment)
throw new Error('Console contract path is empty.')
let routerLinkPromise = routerLinkPromises.get(segment)
if (!routerLinkPromise) {
routerLinkPromise = loadConsoleContractForSegment(segment).then(createLink).catch((error) => {
routerLinkPromises.delete(segment)
throw error
})
routerLinkPromises.set(segment, routerLinkPromise)
}
return routerLinkPromise
}
return new DynamicLink<TContext>((_options, path) => getRouterLink(path))
}

View File

@ -0,0 +1,51 @@
import type { AnyContractRouter } from '@orpc/contract'
import { contractLoaders } from '@dify/contracts/api/console/orpc.gen'
const wrapConsoleContract = (segment: string, contract: unknown) => ({ [segment]: contract }) as AnyContractRouter
async function loadGeneratedConsoleContract(segment: string) {
const loader = contractLoaders[segment as keyof typeof contractLoaders]
if (!loader)
return null
return loader() as Promise<AnyContractRouter>
}
const customConsoleContractLoaders: Record<string, () => Promise<AnyContractRouter>> = {
agent: () => import('@/contract/console/agent').then(({ agentRouterContract }) => wrapConsoleContract('agent', agentRouterContract)),
apps: () => import('@/contract/console/apps').then(({ appsRouterContract }) => wrapConsoleContract('apps', appsRouterContract)),
billing: () => import('@/contract/console/billing').then(({ billingRouterContract }) => wrapConsoleContract('billing', billingRouterContract)),
enterprise: () => import('@dify/contracts/enterprise/orpc.gen').then(({ contract }) => wrapConsoleContract('enterprise', contract)),
explore: () => import('@/contract/console/explore').then(({ exploreRouterContract }) => wrapConsoleContract('explore', exploreRouterContract)),
files: () => import('@/contract/console/files').then(({ filesRouterContract }) => wrapConsoleContract('files', filesRouterContract)),
modelProviders: () =>
import('@/contract/console/model-providers').then(({ modelProvidersRouterContract }) => wrapConsoleContract('modelProviders', modelProvidersRouterContract)),
notification: () =>
import('@/contract/console/notification').then(({ notificationContract }) => wrapConsoleContract('notification', notificationContract)),
notificationDismiss: () =>
import('@/contract/console/notification').then(({ notificationDismissContract }) => wrapConsoleContract('notificationDismiss', notificationDismissContract)),
plugins: () => import('@/contract/console/plugins').then(({ pluginsRouterContract }) => wrapConsoleContract('plugins', pluginsRouterContract)),
rbacAccessConfig: () =>
import('@/contract/console/access-control').then(({ rbacAccessConfigContract }) => wrapConsoleContract('rbacAccessConfig', rbacAccessConfigContract)),
snippets: () => import('@/contract/console/snippets').then(({ snippetsRouterContract }) => wrapConsoleContract('snippets', snippetsRouterContract)),
tags: () => import('@/contract/console/tags').then(({ tagsRouterContract }) => wrapConsoleContract('tags', tagsRouterContract)),
triggers: () => import('@/contract/console/trigger').then(({ triggersRouterContract }) => wrapConsoleContract('triggers', triggersRouterContract)),
trialApps: () => import('@/contract/console/try-app').then(({ trialAppsRouterContract }) => wrapConsoleContract('trialApps', trialAppsRouterContract)),
workflowComments: () =>
import('@/contract/console/workflow-comment').then(({ workflowCommentContracts }) => wrapConsoleContract('workflowComments', workflowCommentContracts)),
workflowDraft: () =>
import('@/contract/console/workflow').then(({ workflowDraftRouterContract }) => wrapConsoleContract('workflowDraft', workflowDraftRouterContract)),
workspaces: () => import('@/contract/console/workspaces').then(({ workspacesRouterContract }) => wrapConsoleContract('workspaces', workspacesRouterContract)),
}
export async function loadConsoleContractForSegment(segment: string) {
const customContractLoader = customConsoleContractLoaders[segment]
if (customContractLoader)
return customContractLoader()
const generatedContract = await loadGeneratedConsoleContract(segment)
if (generatedContract)
return generatedContract
throw new Error(`Console contract segment "${segment}" is not configured.`)
}

View File

@ -1,5 +1,7 @@
import type { ContractRouterClient } from '@orpc/contract' import type { ClientLink } from '@orpc/client'
import type { AnyContractRouter, ContractRouterClient } from '@orpc/contract'
import type { JsonifiedClient } from '@orpc/openapi-client' import type { JsonifiedClient } from '@orpc/openapi-client'
import type { consoleRouterContract } from '@/contract/router'
import { createORPCClient, onError } from '@orpc/client' import { createORPCClient, onError } from '@orpc/client'
import { OpenAPILink } from '@orpc/openapi-client/fetch' import { OpenAPILink } from '@orpc/openapi-client/fetch'
import { createTanstackQueryUtils } from '@orpc/tanstack-query' import { createTanstackQueryUtils } from '@orpc/tanstack-query'
@ -9,7 +11,7 @@ import {
CSRF_HEADER_NAME, CSRF_HEADER_NAME,
} from '@/config' } from '@/config'
import { SERVER_CONSOLE_API_PREFIX } from '@/config/server' import { SERVER_CONSOLE_API_PREFIX } from '@/config/server'
import { consoleRouterContract } from '@/contract/router' import { createConsoleDynamicLink } from './console-link'
import 'server-only' import 'server-only'
@ -68,6 +70,29 @@ const createServerConsoleRequestHeaders = (context: ServerConsoleClientContext |
return requestHeaders return requestHeaders
} }
type ServerConsoleClientLink = ClientLink<ServerConsoleClientContext>
function createServerConsoleOpenAPILink(contract: AnyContractRouter): ServerConsoleClientLink {
return new OpenAPILink<ServerConsoleClientContext>(contract, {
url: getServerConsoleApiPrefix,
headers: ({ context }) => createServerConsoleRequestHeaders(context),
fetch: (request, init) => {
if (request.body && !request.headers.has('content-type'))
request.headers.set('Content-Type', 'application/json')
return globalThis.fetch(request, {
...init,
cache: 'no-store',
})
},
interceptors: [
onError((error) => {
console.error(error)
}),
],
})
}
export const getServerConsoleClientContext = async (): Promise<ServerConsoleClientContext> => { export const getServerConsoleClientContext = async (): Promise<ServerConsoleClientContext> => {
const { cookies, headers } = await import('@/next/headers') const { cookies, headers } = await import('@/next/headers')
const requestHeaders = await headers() const requestHeaders = await headers()
@ -82,24 +107,7 @@ export const getServerConsoleClientContext = async (): Promise<ServerConsoleClie
export const getServerConsoleRequestHeaders = async () => export const getServerConsoleRequestHeaders = async () =>
createServerConsoleRequestHeaders(await getServerConsoleClientContext()) createServerConsoleRequestHeaders(await getServerConsoleClientContext())
const serverConsoleLink = new OpenAPILink<ServerConsoleClientContext>(consoleRouterContract, { const serverConsoleLink = createConsoleDynamicLink<ServerConsoleClientContext>(createServerConsoleOpenAPILink)
url: getServerConsoleApiPrefix,
headers: ({ context }) => createServerConsoleRequestHeaders(context),
fetch: (request, init) => {
if (request.body && !request.headers.has('content-type'))
request.headers.set('Content-Type', 'application/json')
return globalThis.fetch(request, {
...init,
cache: 'no-store',
})
},
interceptors: [
onError((error) => {
console.error(error)
}),
],
})
export const serverConsoleClient: JsonifiedClient<ContractRouterClient<typeof consoleRouterContract, ServerConsoleClientContext>> = createORPCClient(serverConsoleLink) export const serverConsoleClient: JsonifiedClient<ContractRouterClient<typeof consoleRouterContract, ServerConsoleClientContext>> = createORPCClient(serverConsoleLink)