feat: simplify marketplace plugin identifier format

- Drop checksum from marketplace_plugin_unique_identifier
- Use simpler org/name:version format instead of org/name:version@checksum
- Update download endpoint to /api/v1/plugins/{org}/{name}/{version}/download
- Maintain backward compatibility by stripping checksums when present
This commit is contained in:
-LAN- 2025-08-08 19:45:05 +08:00
parent 56afb3fd64
commit e5ad372df9
No known key found for this signature in database
GPG Key ID: 6BA0D108DED011FF
4 changed files with 32 additions and 4 deletions

View File

@ -11,6 +11,20 @@ marketplace_api_url = URL(str(dify_config.MARKETPLACE_API_URL))
def get_plugin_pkg_url(plugin_unique_identifier: str) -> str:
# Parse org/name:version format (without checksum)
if "/" in plugin_unique_identifier and ":" in plugin_unique_identifier:
# Remove checksum if present (format: org/name:version@checksum)
if "@" in plugin_unique_identifier:
plugin_unique_identifier = plugin_unique_identifier.split("@")[0]
# Parse org/name:version
org_and_name, version = plugin_unique_identifier.rsplit(":", 1)
org, name = org_and_name.split("/", 1)
# Use new endpoint format
return str(marketplace_api_url / f"api/v1/plugins/{org}/{name}/{version}/download")
# Fallback to old format with query param
return str((marketplace_api_url / "api/v1/plugins/download").with_query(unique_identifier=plugin_unique_identifier))

View File

@ -205,6 +205,9 @@ class PluginDependency(BaseModel):
@property
def plugin_unique_identifier(self) -> str:
# Strip checksum if present (format: org/name:version@checksum -> org/name:version)
if "@" in self.marketplace_plugin_unique_identifier:
return self.marketplace_plugin_unique_identifier.split("@")[0]
return self.marketplace_plugin_unique_identifier
class Package(BaseModel):

View File

@ -41,9 +41,11 @@ const InstallByDSLList: ForwardRefRenderFunction<ExposeRefs, Props> = ({
// DSL has id, to get plugin info to show more info
const { isLoading: isFetchingMarketplaceDataById, data: infoGetById, error: infoByIdError } = useFetchPluginsInMarketPlaceByInfo(allPlugins.filter(d => d.type === 'marketplace').map((d) => {
const dependecy = (d as GitHubItemAndMarketPlaceDependency).value
// split org, name, version by / and :
// and remove @ and its suffix
const [orgPart, nameAndVersionPart] = dependecy.marketplace_plugin_unique_identifier!.split('@')[0].split('/')
// Parse org/name:version format (checksum already removed by backend)
const identifier = dependecy.marketplace_plugin_unique_identifier!
// Remove checksum if still present (for backward compatibility)
const cleanIdentifier = identifier.includes('@') ? identifier.split('@')[0] : identifier
const [orgPart, nameAndVersionPart] = cleanIdentifier.split('/')
const [name, version] = nameAndVersionPart.split(':')
return {
organization: orgPart,
@ -109,7 +111,13 @@ const InstallByDSLList: ForwardRefRenderFunction<ExposeRefs, Props> = ({
if (!isFetchingMarketplaceDataById && infoGetById?.data.list) {
const sortedList = allPlugins.filter(d => d.type === 'marketplace').map((d) => {
const p = d as GitHubItemAndMarketPlaceDependency
const id = p.value.marketplace_plugin_unique_identifier?.split(':')[0]
// Parse org/name from org/name:version format
let identifier = p.value.marketplace_plugin_unique_identifier || ''
// Remove checksum if present
if (identifier.includes('@'))
identifier = identifier.split('@')[0]
// Get org/name part (without version)
const id = identifier.split(':')[0]
const retPluginInfo = infoGetById.data.list.find(item => item.plugin.plugin_id === id)?.plugin
return { ...retPluginInfo, from: d.type } as Plugin
})

View File

@ -286,6 +286,9 @@ export const useInstallOrUpdate = ({
if (item.type === 'marketplace') {
const data = item as GitHubItemAndMarketPlaceDependency
uniqueIdentifier = data.value.marketplace_plugin_unique_identifier! || plugin[i]?.plugin_id
// Strip checksum if present (for backward compatibility)
if (uniqueIdentifier.includes('@'))
uniqueIdentifier = uniqueIdentifier.split('@')[0]
if (uniqueIdentifier === installedPayload?.uniqueIdentifier) {
return {
success: true,