systemprompt_extension/
traits.rs1use std::sync::Arc;
2
3use serde_json::Value as JsonValue;
4use systemprompt_provider_contracts::{
5 ComponentRenderer, ContentDataProvider, FrontmatterProcessor, Job, LlmProvider,
6 PageDataProvider, PagePrerenderer, RssFeedProvider, SitemapProvider, TemplateDataExtender,
7 TemplateProvider, ToolProvider,
8};
9
10use crate::asset::{AssetDefinition, AssetPaths};
11use crate::context::ExtensionContext;
12use crate::error::ConfigError;
13use crate::metadata::{ExtensionMetadata, ExtensionRole, SchemaDefinition};
14use crate::migration::Migration;
15#[cfg(feature = "web")]
16use crate::router::ExtensionRouter;
17use crate::router::{ExtensionRouterConfig, SiteAuthConfig};
18
19pub trait Extension: Send + Sync + 'static {
20 fn metadata(&self) -> ExtensionMetadata;
21
22 fn schemas(&self) -> Vec<SchemaDefinition> {
23 vec![]
24 }
25
26 fn migration_weight(&self) -> u32 {
27 100
28 }
29
30 #[cfg(feature = "web")]
31 fn router(&self, ctx: &dyn ExtensionContext) -> Option<ExtensionRouter> {
32 let _ = ctx;
33 None
34 }
35
36 fn router_config(&self) -> Option<ExtensionRouterConfig> {
37 None
38 }
39
40 fn site_auth(&self) -> Option<SiteAuthConfig> {
41 None
42 }
43
44 fn jobs(&self) -> Vec<Arc<dyn Job>> {
45 vec![]
46 }
47
48 fn config_prefix(&self) -> Option<&str> {
49 None
50 }
51
52 fn config_schema(&self) -> Option<JsonValue> {
53 None
54 }
55
56 fn validate_config(&self, config: &JsonValue) -> Result<(), ConfigError> {
57 let _ = config;
58 Ok(())
59 }
60
61 fn llm_providers(&self) -> Vec<Arc<dyn LlmProvider>> {
62 vec![]
63 }
64
65 fn tool_providers(&self) -> Vec<Arc<dyn ToolProvider>> {
66 vec![]
67 }
68
69 fn template_providers(&self) -> Vec<Arc<dyn TemplateProvider>> {
70 vec![]
71 }
72
73 fn component_renderers(&self) -> Vec<Arc<dyn ComponentRenderer>> {
74 vec![]
75 }
76
77 fn template_data_extenders(&self) -> Vec<Arc<dyn TemplateDataExtender>> {
78 vec![]
79 }
80
81 fn page_data_providers(&self) -> Vec<Arc<dyn PageDataProvider>> {
82 vec![]
83 }
84
85 fn page_prerenderers(&self) -> Vec<Arc<dyn PagePrerenderer>> {
86 vec![]
87 }
88
89 fn frontmatter_processors(&self) -> Vec<Arc<dyn FrontmatterProcessor>> {
90 vec![]
91 }
92
93 fn content_data_providers(&self) -> Vec<Arc<dyn ContentDataProvider>> {
94 vec![]
95 }
96
97 fn rss_feed_providers(&self) -> Vec<Arc<dyn RssFeedProvider>> {
98 vec![]
99 }
100
101 fn sitemap_providers(&self) -> Vec<Arc<dyn SitemapProvider>> {
102 vec![]
103 }
104
105 fn required_storage_paths(&self) -> Vec<&'static str> {
106 vec![]
107 }
108
109 fn dependencies(&self) -> Vec<&'static str> {
110 vec![]
111 }
112
113 fn is_required(&self) -> bool {
114 false
115 }
116
117 fn migrations(&self) -> Vec<Migration> {
118 vec![]
119 }
120
121 fn roles(&self) -> Vec<ExtensionRole> {
122 vec![]
123 }
124
125 fn priority(&self) -> u32 {
126 100
127 }
128
129 fn id(&self) -> &'static str {
130 self.metadata().id
131 }
132
133 fn name(&self) -> &'static str {
134 self.metadata().name
135 }
136
137 fn version(&self) -> &'static str {
138 self.metadata().version
139 }
140
141 fn has_schemas(&self) -> bool {
142 !self.schemas().is_empty()
143 }
144
145 #[cfg(feature = "web")]
146 fn has_router(&self, ctx: &dyn ExtensionContext) -> bool {
147 self.router(ctx).is_some()
148 }
149
150 #[cfg(not(feature = "web"))]
151 fn has_router(&self, _ctx: &dyn ExtensionContext) -> bool {
152 false
153 }
154
155 fn has_jobs(&self) -> bool {
156 !self.jobs().is_empty()
157 }
158
159 fn has_config(&self) -> bool {
160 self.config_prefix().is_some()
161 }
162
163 fn has_llm_providers(&self) -> bool {
164 !self.llm_providers().is_empty()
165 }
166
167 fn has_tool_providers(&self) -> bool {
168 !self.tool_providers().is_empty()
169 }
170
171 fn has_template_providers(&self) -> bool {
172 !self.template_providers().is_empty()
173 }
174
175 fn has_component_renderers(&self) -> bool {
176 !self.component_renderers().is_empty()
177 }
178
179 fn has_template_data_extenders(&self) -> bool {
180 !self.template_data_extenders().is_empty()
181 }
182
183 fn has_page_data_providers(&self) -> bool {
184 !self.page_data_providers().is_empty()
185 }
186
187 fn has_page_prerenderers(&self) -> bool {
188 !self.page_prerenderers().is_empty()
189 }
190
191 fn has_frontmatter_processors(&self) -> bool {
192 !self.frontmatter_processors().is_empty()
193 }
194
195 fn has_content_data_providers(&self) -> bool {
196 !self.content_data_providers().is_empty()
197 }
198
199 fn has_rss_feed_providers(&self) -> bool {
200 !self.rss_feed_providers().is_empty()
201 }
202
203 fn has_sitemap_providers(&self) -> bool {
204 !self.sitemap_providers().is_empty()
205 }
206
207 fn has_site_auth(&self) -> bool {
208 self.site_auth().is_some()
209 }
210
211 fn has_storage_paths(&self) -> bool {
212 !self.required_storage_paths().is_empty()
213 }
214
215 fn has_roles(&self) -> bool {
216 !self.roles().is_empty()
217 }
218
219 fn has_migrations(&self) -> bool {
220 !self.migrations().is_empty()
221 }
222
223 fn declares_assets(&self) -> bool {
224 false
225 }
226
227 fn required_assets(&self, _paths: &dyn AssetPaths) -> Vec<AssetDefinition> {
228 vec![]
229 }
230}
231
232#[macro_export]
233macro_rules! register_extension {
234 ($ext_type:ty) => {
235 ::inventory::submit! {
236 $crate::ExtensionRegistration {
237 factory: || ::std::sync::Arc::new(<$ext_type>::default()) as ::std::sync::Arc<dyn $crate::Extension>,
238 }
239 }
240 };
241 ($ext_expr:expr) => {
242 ::inventory::submit! {
243 $crate::ExtensionRegistration {
244 factory: || ::std::sync::Arc::new($ext_expr) as ::std::sync::Arc<dyn $crate::Extension>,
245 }
246 }
247 };
248}