1use serde_json::{json, Value};
9
10pub const CATALOG_PATH: &str = "/v1/palette/catalog";
11pub const SEARCH_PATH: &str = "/v1/palette/search";
12pub const SCHEMA_PATH: &str = "/v1/palette/schema";
13pub const EXECUTE_PATH: &str = "/v1/palette/execute";
14
15pub fn augment_with_palette_routes(value: &mut Value) {
19 let Some(paths) = value.get_mut("paths").and_then(Value::as_object_mut) else {
20 return;
21 };
22 paths
23 .entry(CATALOG_PATH.to_owned())
24 .or_insert_with(catalog_path_item);
25 paths
26 .entry(SEARCH_PATH.to_owned())
27 .or_insert_with(search_path_item);
28 paths
29 .entry(SCHEMA_PATH.to_owned())
30 .or_insert_with(schema_path_item);
31 paths
32 .entry(EXECUTE_PATH.to_owned())
33 .or_insert_with(execute_path_item);
34}
35
36fn catalog_path_item() -> Value {
37 json!({
38 "get": {
39 "summary": "List palette-exposed launcher entries",
40 "description": "Every provider tool whose palette overlay exposes it (default: exposed).",
41 "responses": {
42 "200": {"description": "Launcher catalog"}
43 }
44 }
45 })
46}
47
48fn search_path_item() -> Value {
49 json!({
50 "get": {
51 "summary": "Search palette-exposed launcher entries",
52 "parameters": [
53 {"name": "q", "in": "query", "required": false, "schema": {"type": "string"}},
54 {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer"}}
55 ],
56 "responses": {
57 "200": {"description": "Matching launcher entries"}
58 }
59 }
60 })
61}
62
63fn schema_path_item() -> Value {
64 json!({
65 "get": {
66 "summary": "Get a launcher entry's input/output schema",
67 "parameters": [
68 {"name": "id", "in": "query", "required": true, "schema": {"type": "string"}}
69 ],
70 "responses": {
71 "200": {"description": "Launcher schema"},
72 "404": {"description": "Unknown or no longer palette-exposed launcher id"}
73 }
74 }
75 })
76}
77
78fn execute_path_item() -> Value {
79 json!({
80 "post": {
81 "summary": "Execute a palette launcher action",
82 "description": "Read/write scope, admin, and destructive-confirmation policy are enforced by the underlying provider dispatch.",
83 "requestBody": {
84 "required": true,
85 "content": {
86 "application/json": {
87 "schema": {
88 "type": "object",
89 "required": ["id"],
90 "properties": {
91 "id": {"type": "string"},
92 "params": {"type": "object"},
93 "confirmDestructive": {"type": "boolean"}
94 }
95 }
96 }
97 }
98 },
99 "responses": {
100 "200": {"description": "Launcher execution result"},
101 "400": {"description": "Invalid params or missing destructive confirmation"},
102 "403": {"description": "Insufficient scope or admin required"},
103 "404": {"description": "Unknown or no longer palette-exposed launcher id"}
104 }
105 }
106 })
107}
108
109#[cfg(test)]
110#[path = "openapi_tests.rs"]
111mod tests;