@@ -7,23 +7,28 @@ use crate::common::document::ExtensionOnOpenedType;
77use crate :: common:: document:: OnOpened ;
88use crate :: common:: register:: SearchSourceRegistry ;
99use crate :: util:: platform:: Platform ;
10+ use crate :: util:: version:: COCO_VERSION ;
11+ use crate :: util:: version:: parse_coco_semver;
1012use anyhow:: Context ;
1113use bitflags:: bitflags;
1214use borrowme:: { Borrow , ToOwned } ;
1315use derive_more:: Display ;
1416use indexmap:: IndexMap ;
17+ use semver:: Version as SemVer ;
1518use serde:: Deserialize ;
1619use serde:: Serialize ;
1720use serde_json:: Value as Json ;
1821use std:: collections:: HashMap ;
1922use std:: collections:: HashSet ;
23+ use std:: ops:: Deref ;
2024use std:: path:: Path ;
2125use tauri:: { AppHandle , Manager } ;
2226use third_party:: THIRD_PARTY_EXTENSIONS_SEARCH_SOURCE ;
2327
2428pub const LOCAL_QUERY_SOURCE_TYPE : & str = "local" ;
2529const PLUGIN_JSON_FILE_NAME : & str = "plugin.json" ;
2630const ASSETS_DIRECTORY_FILE_NAME : & str = "assets" ;
31+ const PLUGIN_JSON_FIELD_MINIMUM_COCO_VERSION : & str = "minimum_coco_version" ;
2732
2833fn default_true ( ) -> bool {
2934 true
@@ -119,6 +124,16 @@ pub struct Extension {
119124 /// Permission that this extension requires.
120125 permission : Option < ExtensionPermission > ,
121126
127+ /// The version of Coco app that this extension requires.
128+ ///
129+ /// If not set, then this extension is compatible with all versions of Coco app.
130+ ///
131+ /// It is only for third-party extensions. Built-in extensions should always
132+ /// set this field to `None`.
133+ #[ serde( deserialize_with = "deserialize_coco_semver" ) ]
134+ #[ serde( default ) ] // None if this field is missing
135+ minimum_coco_version : Option < SemVer > ,
136+
122137 /*
123138 * The following fields are currently useless to us but are needed by our
124139 * extension store.
@@ -292,6 +307,9 @@ impl Extension {
292307
293308 Some ( on_opened)
294309 }
310+ ExtensionType :: Unknown => {
311+ unreachable ! ( "Extensions of type [Unknown] should never be opened" )
312+ }
295313 }
296314 }
297315
@@ -366,6 +384,26 @@ impl Extension {
366384 }
367385}
368386
387+ /// Deserialize Coco SemVer from a string.
388+ ///
389+ /// This function adapts `parse_coco_semver` to work with serde's `deserialize_with`
390+ /// attribute.
391+ fn deserialize_coco_semver < ' de , D > ( deserializer : D ) -> Result < Option < SemVer > , D :: Error >
392+ where
393+ D : serde:: Deserializer < ' de > ,
394+ {
395+ let version_str: Option < String > = Option :: deserialize ( deserializer) ?;
396+ let Some ( version_str) = version_str else {
397+ return Ok ( None ) ;
398+ } ;
399+
400+ let Some ( semver) = parse_coco_semver ( & version_str) else {
401+ return Err ( serde:: de:: Error :: custom ( "version string format is invalid" ) ) ;
402+ } ;
403+
404+ Ok ( Some ( semver) )
405+ }
406+
369407#[ derive( Debug , Deserialize , Serialize , Clone , PartialEq ) ]
370408pub ( crate ) struct CommandAction {
371409 pub ( crate ) exec : String ,
@@ -569,6 +607,10 @@ pub enum ExtensionType {
569607 AiExtension ,
570608 #[ display( "View" ) ]
571609 View ,
610+ /// Add this variant for better compatibility: Future versions of Coco may
611+ /// add new extension types that older versions of Coco are not aware of.
612+ #[ display( "Unknown" ) ]
613+ Unknown ,
572614}
573615
574616impl ExtensionType {
@@ -816,6 +858,22 @@ pub(crate) async fn init_extensions(tauri_app_handle: &AppHandle) -> Result<(),
816858 Ok ( ( ) )
817859}
818860
861+ /// Is `extension` compatible with the current running Coco app?
862+ ///
863+ /// It is defined as a tauri command rather than an associated function because
864+ /// it will be used in frontend code as well.
865+ ///
866+ /// Async tauri commands are required to return `Result<T, E>`, this function
867+ /// only needs to return a boolean, so it is not marked async.
868+ #[ tauri:: command]
869+ pub ( crate ) fn is_extension_compatible ( extension : Extension ) -> bool {
870+ let Some ( ref minimum_coco_version) = extension. minimum_coco_version else {
871+ return true ;
872+ } ;
873+
874+ COCO_VERSION . deref ( ) >= minimum_coco_version
875+ }
876+
819877#[ tauri:: command]
820878pub ( crate ) async fn enable_extension (
821879 tauri_app_handle : AppHandle ,
0 commit comments