Skip to main content

lenso_contracts/
console.rs

1//! Lenso Console Module declarations and the framework-owned ESM contract.
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use utoipa::ToSchema;
6
7/// The versioned manifest consumed by the Console ESM loader.
8pub const CONSOLE_MODULE_PROTOCOL: &str = "lenso.console-module.v1";
9/// The major protocol understood by the current Console ESM loader.
10pub const CONSOLE_MODULE_PROTOCOL_MAJOR: u32 = 1;
11/// The only executable Console artifact format supported by the framework.
12pub const CONSOLE_UI_ESM_FORMAT: &str = "console_ui_esm";
13/// Retired bridge identifier retained only so older published authoring crates
14/// can be rebuilt while their releases are rejected by contract validation.
15pub const CONSOLE_BRIDGE_PROTOCOL: &str = "lenso.console-bridge.v1";
16
17#[derive(
18    Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema,
19)]
20#[serde(rename_all = "snake_case")]
21#[non_exhaustive]
22pub enum ConsoleSurfaceArea {
23    Runtime,
24    Operations,
25    Data,
26    Configuration,
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
30pub struct ConsoleSurface {
31    pub name: String,
32    pub label: String,
33    pub route: String,
34    pub presentation: ConsoleSurfacePresentation,
35    #[serde(default, skip_serializing_if = "Option::is_none")]
36    pub icon: Option<String>,
37    #[serde(default)]
38    pub required_capabilities: Vec<String>,
39    #[serde(default, skip_serializing_if = "Option::is_none")]
40    pub navigation: Option<ConsoleNavigation>,
41}
42
43#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
44#[serde(tag = "kind", rename_all = "snake_case")]
45#[non_exhaustive]
46pub enum ConsoleSurfacePresentation {
47    Declarative {
48        schema: Value,
49    },
50    /// A same-realm ESM surface loaded from the owning Module Release.
51    Esm {
52        entry: String,
53    },
54    /// Retired compatibility authoring shape. Module Releases reject it.
55    #[schemars(skip)]
56    Isolated {
57        entry: String,
58        bridge_protocol: String,
59    },
60}
61
62#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
63#[serde(rename_all = "camelCase", deny_unknown_fields)]
64pub struct ConsoleModuleSurface {
65    pub id: String,
66    pub path: String,
67    pub label: String,
68    pub area: ConsoleSurfaceArea,
69    #[serde(default, skip_serializing_if = "Vec::is_empty")]
70    pub required_capabilities: Vec<String>,
71    #[serde(default, skip_serializing_if = "Option::is_none")]
72    pub icon: Option<String>,
73    #[serde(default, skip_serializing_if = "Option::is_none")]
74    pub navigation: Option<ConsoleNavigation>,
75}
76
77/// The immutable presentation manifest embedded in a `console_ui_esm`
78/// artifact. Its field names intentionally match the public Console SDK.
79#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
80#[serde(rename_all = "camelCase", deny_unknown_fields)]
81pub struct ConsoleModuleManifest {
82    pub protocol: String,
83    pub module_id: String,
84    pub host_api: String,
85    pub console_ui: String,
86    pub surfaces: Vec<ConsoleModuleSurface>,
87}
88
89#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
90#[serde(rename_all = "camelCase", deny_unknown_fields)]
91pub struct ConsoleUiArtifactStyleAsset {
92    pub path: String,
93    #[serde(default, skip_serializing_if = "Option::is_none")]
94    pub order: Option<i32>,
95    #[serde(default, skip_serializing_if = "Option::is_none")]
96    pub media: Option<String>,
97}
98
99#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
100#[serde(rename_all = "camelCase")]
101pub struct ConsolePermissionRequest {
102    pub permission_id: String,
103    #[serde(default)]
104    pub operations: Vec<String>,
105    #[serde(default)]
106    pub resources: Vec<String>,
107    #[serde(default)]
108    pub outbound_destinations: Vec<String>,
109    #[serde(default)]
110    pub secret_references: Vec<String>,
111}
112
113#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
114pub struct ConsolePermissionGrant {
115    pub module_id: String,
116    pub module_release_digest: String,
117    #[serde(default, skip_serializing_if = "Option::is_none")]
118    pub ui_artifact_digest: Option<String>,
119    #[serde(default)]
120    pub granted_permissions: Vec<String>,
121}
122
123#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
124pub struct ConsoleContribution {
125    pub target: String,
126    pub target_version: u32,
127    pub label: String,
128    pub action: ConsoleContributionAction,
129    #[serde(default, skip_serializing_if = "Option::is_none")]
130    pub icon: Option<String>,
131    #[serde(default)]
132    pub required_capabilities: Vec<String>,
133}
134
135#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
136pub struct ConsoleSlot {
137    pub id: String,
138    pub version: u32,
139    pub label: String,
140    #[serde(default)]
141    pub accepts: Vec<ConsoleContributionKind>,
142    #[serde(default)]
143    pub context: Vec<ConsoleSlotContext>,
144}
145
146#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
147#[serde(rename_all = "snake_case")]
148#[non_exhaustive]
149pub enum ConsoleContributionKind {
150    AdminAction,
151}
152
153#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
154pub struct ConsoleSlotContext {
155    pub name: String,
156    #[serde(default)]
157    pub fields: Vec<ConsoleSlotContextField>,
158}
159
160#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
161pub struct ConsoleSlotContextField {
162    pub name: String,
163    pub field_type: ConsoleSlotContextFieldType,
164    #[serde(default)]
165    pub required: bool,
166}
167
168#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
169#[serde(rename_all = "snake_case")]
170#[non_exhaustive]
171pub enum ConsoleSlotContextFieldType {
172    String,
173    Boolean,
174    Number,
175    Timestamp,
176}
177
178#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
179#[serde(tag = "kind", rename_all = "snake_case")]
180#[non_exhaustive]
181pub enum ConsoleContributionAction {
182    AdminAction {
183        module: String,
184        name: String,
185        #[serde(default)]
186        input_bindings: Vec<ConsoleActionInputBinding>,
187    },
188}
189
190#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
191pub struct ConsoleActionInputBinding {
192    pub input: String,
193    pub value: ConsoleActionInputValue,
194}
195
196#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
197#[serde(tag = "kind", rename_all = "snake_case")]
198#[non_exhaustive]
199pub enum ConsoleActionInputValue {
200    SlotContext { path: String },
201}
202
203#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
204#[serde(rename_all = "camelCase")]
205pub struct ConsoleNavigation {
206    pub workspace: ConsoleWorkspaceRef,
207    #[serde(default, skip_serializing_if = "Option::is_none")]
208    pub group: Option<ConsoleNavigationGroup>,
209    #[serde(default, skip_serializing_if = "Option::is_none")]
210    pub order: Option<i32>,
211}
212
213#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
214#[serde(rename_all = "camelCase")]
215pub struct ConsoleWorkspaceRef {
216    pub id: String,
217    pub label: String,
218    #[serde(default, skip_serializing_if = "Option::is_none")]
219    pub icon: Option<String>,
220}
221
222#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, schemars::JsonSchema)]
223#[serde(rename_all = "camelCase")]
224pub struct ConsoleNavigationGroup {
225    pub id: String,
226    pub label: String,
227    #[serde(default, skip_serializing_if = "Option::is_none")]
228    pub icon: Option<String>,
229    #[serde(default, skip_serializing_if = "Option::is_none")]
230    pub order: Option<i32>,
231}