1mod admin_data;
17mod binding;
18mod host;
19mod linked;
20mod module;
21mod source;
22
23pub use admin_data::{
24 AdminActionSource, AdminDataSource, AdminListQuery, AdminPage, AdminQuerySource,
25};
26pub use binding::{EventHandlerRegistrationContext, EventHandlerRuntimeContext, ModuleBinding};
27pub use host::{HostContribution, HostLinkedModule};
28pub use lenso_contracts::{
29 AdminAction, AdminActionConfirmation, AdminActionDangerLevel, AdminActionInputField,
30 AdminActionInputSchema, AdminDeclarativeComponent, AdminDeclarativePage,
31 AdminDeclarativeSection, AdminDeclarativeSurface, AdminEmbeddedEntry, AdminEmbeddedRuntime,
32 AdminEmbeddedSurface, AdminMetricBinding, AdminPermission, AdminSandboxPolicy, AdminSchema,
33 AdminSurface, CONSOLE_BRIDGE_PROTOCOL, CONSOLE_MODULE_PROTOCOL, CONSOLE_MODULE_PROTOCOL_MAJOR,
34 CONSOLE_UI_ESM_FORMAT, ConsoleActionInputBinding, ConsoleActionInputValue, ConsoleContribution,
35 ConsoleContributionAction, ConsoleContributionKind, ConsoleModuleManifest,
36 ConsoleModuleSurface, ConsoleNavigation, ConsoleNavigationGroup, ConsolePermissionGrant,
37 ConsolePermissionRequest, ConsoleSlot, ConsoleSlotContext, ConsoleSlotContextField,
38 ConsoleSlotContextFieldType, ConsoleSurface, ConsoleSurfaceArea, ConsoleSurfacePresentation,
39 ConsoleUiArtifact, ConsoleUiArtifactEntry, ConsoleUiArtifactFormat,
40 ConsoleUiArtifactStyleAsset, ConsoleWorkspaceRef, CronParseError, CronSchedule, EntitySchema,
41 EventHandlerDeclaration, EventSurface, FieldSchema, FieldType,
42 LifecycleActivationJobDeclaration, LifecycleActivationRunPolicy,
43 LifecycleStartupCheckDeclaration, LifecycleStartupCheckKind, LifecycleSurface,
44 ModuleCapabilityReference, ModuleHttpMethod, ModuleHttpRoute, ModuleManifest,
45 ModuleManifestBuilder, ModuleManifestLint, ModuleManifestLintSeverity, ModuleRequirement,
46 ModuleRouteLint, ModuleRouteLintSeverity, RuntimeFunctionDeclaration,
47 RuntimeRetryPolicyDeclaration, RuntimeSurface, StoryDisplayDescriptor, StoryDisplaySource,
48 lint_module_http_routes, lint_module_manifest, lint_module_manifest_parts,
49 module_capability_references, validate_cron_expression,
50};
51pub use linked::{
52 LinkedBinding, LinkedBindingBuilder, LinkedHttpContribution, LinkedHttpRouteMerger,
53};
54pub use module::{Module, ModuleLoadStatus};
55pub use source::ModuleSource;
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60 use platform_core::{
61 AppConfig, AppContext, AppError, AuthConfig, DatabaseConfig, ErrorCode, HttpConfig,
62 LoggingEventPublisher, Migration, ModuleSourcesConfig, RedisConfig, ServiceConfig,
63 TelemetryConfig,
64 };
65 use std::collections::BTreeMap;
66 use std::sync::Arc;
67
68 #[derive(Debug, Clone, PartialEq, Eq)]
69 struct TestContribution(&'static str);
70
71 const TEST_MIGRATIONS: &[Migration] = &[Migration {
72 name: "test/0001_init",
73 sql: "select 1;",
74 }];
75
76 fn manifest() -> ModuleManifest {
77 ModuleManifest::builder("fixture/test").build()
78 }
79
80 fn module(_ctx: &AppContext) -> Module {
81 Module::linked(manifest(), LinkedBinding::builder().build())
82 }
83
84 fn fallible_module(_ctx: &AppContext) -> platform_core::AppResult<Module> {
85 Err(AppError::new(
86 ErrorCode::ExternalDependency,
87 "object storage configuration is invalid",
88 ))
89 }
90
91 #[test]
92 fn host_linked_module_keeps_typed_contributions() {
93 let linked_module = HostLinkedModule::linked("test", manifest, module, TEST_MIGRATIONS)
94 .with_contribution(TestContribution("wired"));
95
96 let contributions = linked_module
97 .contributions::<TestContribution>()
98 .collect::<Vec<_>>();
99
100 assert_eq!(contributions, vec![&TestContribution("wired")]);
101 }
102
103 #[tokio::test]
104 async fn fallible_host_linked_module_preserves_structured_loader_error() {
105 let linked_module =
106 HostLinkedModule::try_linked("test", manifest, fallible_module, TEST_MIGRATIONS);
107 let db = platform_core::DbPool::connect_lazy("postgres://localhost/lenso_test")
108 .expect("lazy pool should build");
109 let ctx = AppContext::new(
110 AppConfig {
111 service: ServiceConfig::default(),
112 database: DatabaseConfig {
113 url: "postgres://localhost/lenso_test".to_owned(),
114 max_connections: 1,
115 },
116 redis: RedisConfig::default(),
117 http: HttpConfig::default(),
118 telemetry: TelemetryConfig::default(),
119 auth: AuthConfig::default(),
120 module_sources: ModuleSourcesConfig {
121 linked_profile: "core".to_owned(),
122 },
123 modules: BTreeMap::new(),
124 },
125 db,
126 Arc::new(LoggingEventPublisher),
127 );
128
129 let error = linked_module
130 .try_load_module(&ctx)
131 .expect_err("fallible loader error must remain structured");
132
133 assert_eq!(error.code, ErrorCode::ExternalDependency);
134 assert_eq!(
135 error.public_message,
136 "object storage configuration is invalid"
137 );
138 }
139}