Implementation:Langgenius Dify Marketplace Contracts
| Knowledge Sources | Dify |
|---|---|
| Domains | Plugin_System, Marketplace, Frontend |
| Last Updated | 2026-02-12 00:00 GMT |
Overview
Description
The Marketplace Contracts module defines three oRPC typed contracts that form the complete API surface for plugin and bundle discovery against the Dify Marketplace. Each contract specifies its HTTP route, method, input type, and output type using the @orpc/contract library's type<T>() utility, producing zero-runtime-overhead type constraints that are enforced at compile time.
The three contracts are:
- collectionsContract -- Lists marketplace collections with optional search and pagination.
- collectionPluginsContract -- Retrieves plugins within a specific collection by
collectionId. - searchAdvancedContract -- Performs advanced search across plugins or bundles with full filtering capabilities.
All contracts extend a shared base contract imported from web/contract/base.ts, which provides the marketplace base URL and common configuration.
Usage
These contracts are consumed by the React Query hooks in web/service/use-plugins.ts and by direct marketplace API calls. The contracts serve as the type-safe interface layer between the frontend and the marketplace backend.
Code Reference
Source Location
web/contract/marketplace.ts (Lines 6--56)
Signature
export const collectionsContract = base
.route({ path: '/collections', method: 'GET' })
.input(
type<{
query?: CollectionsAndPluginsSearchParams & { page?: number; page_size?: number }
}>(),
)
.output(
type<{
data?: { collections?: MarketplaceCollection[] }
}>(),
)
export const collectionPluginsContract = base
.route({ path: '/collections/{collectionId}/plugins', method: 'POST' })
.input(
type<{
params: { collectionId: string }
body?: CollectionsAndPluginsSearchParams
}>(),
)
.output(
type<{
data?: { plugins?: Plugin[] }
}>(),
)
export const searchAdvancedContract = base
.route({ path: '/{kind}/search/advanced', method: 'POST' })
.input(
type<{
params: { kind: 'plugins' | 'bundles' }
body: Omit<PluginsSearchParams, 'type'>
}>(),
)
.output(type<{ data: PluginsFromMarketplaceResponse }>())
Import
import { collectionsContract, collectionPluginsContract, searchAdvancedContract } from '@/contract/marketplace'
I/O Contract
collectionsContract
| Direction | Field | Type | Description |
|---|---|---|---|
| Input | query | CollectionsAndPluginsSearchParams & { page?: number; page_size?: number } |
Optional search parameters and pagination |
| Output | data.collections | MarketplaceCollection[] |
Array of curated marketplace collections |
collectionPluginsContract
| Direction | Field | Type | Description |
|---|---|---|---|
| Input | params.collectionId | string |
The unique identifier of the collection |
| Input | body | CollectionsAndPluginsSearchParams |
Optional search/filter parameters |
| Output | data.plugins | Plugin[] |
Array of plugins belonging to the collection |
searchAdvancedContract
| Direction | Field | Type | Description |
|---|---|---|---|
| Input | params.kind | 'bundles' | The type of resource to search |
| Input | body | Omit<PluginsSearchParams, 'type'> |
Search parameters (query, sort_by, sort_order, category, tags, exclude, page, page_size) |
| Output | data | PluginsFromMarketplaceResponse |
Search results with plugins/bundles and pagination metadata |
Usage Examples
Browsing marketplace collections
// The collectionsContract is consumed by hooks that fetch paginated collections
const { data } = useQuery({
queryKey: ['marketplace', 'collections'],
queryFn: () => getMarketplace<{ data: { collections: MarketplaceCollection[] } }>(
'/collections',
{ params: { page: 1, page_size: 20 } }
),
})
Searching for plugins with advanced filters
// The searchAdvancedContract types the advanced search mutation
const { mutateAsync } = useMutationPluginsFromMarketplace()
const results = await mutateAsync({
query: 'openai',
sort_by: 'install_count',
sort_order: 'desc',
category: 'model',
tags: ['llm'],
page: 1,
page_size: 40,
type: 'plugin',
})
Fetching plugins in a specific collection
// The collectionPluginsContract types the collection plugins endpoint
const response = await postMarketplace<{ data: { plugins: Plugin[] } }>(
`/collections/${collectionId}/plugins`,
{ body: { limit: 15 } }
)