mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-20 08:33:52 +01:00
MCP Server Plugin (#335)
This commit is contained in:
@@ -22,8 +22,8 @@ use yaak_http::types::{
|
||||
};
|
||||
use yaak_models::blob_manager::{BlobManagerExt, BodyChunk};
|
||||
use yaak_models::models::{
|
||||
Cookie, CookieJar, Environment, HttpRequest, HttpResponse, HttpResponseEvent,
|
||||
HttpResponseHeader, HttpResponseState, ProxySetting, ProxySettingAuth,
|
||||
CookieJar, Environment, HttpRequest, HttpResponse, HttpResponseEvent, HttpResponseHeader,
|
||||
HttpResponseState, ProxySetting, ProxySettingAuth,
|
||||
};
|
||||
use yaak_models::query_manager::QueryManagerExt;
|
||||
use yaak_models::util::UpdateSource;
|
||||
|
||||
@@ -13,7 +13,7 @@ use tauri::{AppHandle, Emitter, Manager, Runtime};
|
||||
use tauri_plugin_clipboard_manager::ClipboardExt;
|
||||
use yaak_common::window::WorkspaceWindowTrait;
|
||||
use yaak_models::blob_manager::BlobManagerExt;
|
||||
use yaak_models::models::{HttpResponse, Plugin};
|
||||
use yaak_models::models::{AnyModel, HttpResponse, Plugin};
|
||||
use yaak_models::queries::any_request::AnyRequest;
|
||||
use yaak_models::query_manager::QueryManagerExt;
|
||||
use yaak_models::util::UpdateSource;
|
||||
@@ -21,10 +21,10 @@ use yaak_plugins::error::Error::PluginErr;
|
||||
use yaak_plugins::events::{
|
||||
Color, DeleteKeyValueResponse, EmptyPayload, ErrorResponse, FindHttpResponsesResponse,
|
||||
GetCookieValueResponse, GetHttpRequestByIdResponse, GetKeyValueResponse, Icon, InternalEvent,
|
||||
InternalEventPayload, ListCookieNamesResponse, ListHttpRequestsResponse,
|
||||
InternalEventPayload, ListCookieNamesResponse, ListHttpRequestsResponse, ListWorkspacesResponse,
|
||||
RenderGrpcRequestResponse, RenderHttpRequestResponse, SendHttpRequestResponse,
|
||||
SetKeyValueResponse, ShowToastRequest, TemplateRenderResponse, WindowInfoResponse,
|
||||
WindowNavigateEvent,
|
||||
WindowNavigateEvent, WorkspaceInfo,
|
||||
};
|
||||
use yaak_plugins::plugin_handle::PluginHandle;
|
||||
use yaak_plugins::template_callback::PluginTemplateCallback;
|
||||
@@ -87,6 +87,70 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
|
||||
yaak_plugins::events::ListFoldersResponse { folders },
|
||||
)))
|
||||
}
|
||||
InternalEventPayload::UpsertModelRequest(req) => {
|
||||
use AnyModel::*;
|
||||
let model = match &req.model {
|
||||
HttpRequest(m) => {
|
||||
HttpRequest(app_handle.db().upsert_http_request(m, &UpdateSource::Plugin)?)
|
||||
}
|
||||
GrpcRequest(m) => {
|
||||
GrpcRequest(app_handle.db().upsert_grpc_request(m, &UpdateSource::Plugin)?)
|
||||
}
|
||||
WebsocketRequest(m) => WebsocketRequest(
|
||||
app_handle.db().upsert_websocket_request(m, &UpdateSource::Plugin)?,
|
||||
),
|
||||
Folder(m) => Folder(app_handle.db().upsert_folder(m, &UpdateSource::Plugin)?),
|
||||
Environment(m) => {
|
||||
Environment(app_handle.db().upsert_environment(m, &UpdateSource::Plugin)?)
|
||||
}
|
||||
Workspace(m) => {
|
||||
Workspace(app_handle.db().upsert_workspace(m, &UpdateSource::Plugin)?)
|
||||
}
|
||||
_ => {
|
||||
return Err(PluginErr("Upsert not supported for this model type".into()).into())
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Some(InternalEventPayload::UpsertModelResponse(
|
||||
yaak_plugins::events::UpsertModelResponse { model },
|
||||
)))
|
||||
}
|
||||
InternalEventPayload::DeleteModelRequest(req) => {
|
||||
let model = match req.model.as_str() {
|
||||
"http_request" => AnyModel::HttpRequest(
|
||||
app_handle
|
||||
.db()
|
||||
.delete_http_request_by_id(&req.id, &UpdateSource::Plugin)?,
|
||||
),
|
||||
"grpc_request" => AnyModel::GrpcRequest(
|
||||
app_handle
|
||||
.db()
|
||||
.delete_grpc_request_by_id(&req.id, &UpdateSource::Plugin)?,
|
||||
),
|
||||
"websocket_request" => AnyModel::WebsocketRequest(
|
||||
app_handle
|
||||
.db()
|
||||
.delete_websocket_request_by_id(&req.id, &UpdateSource::Plugin)?,
|
||||
),
|
||||
"folder" => AnyModel::Folder(
|
||||
app_handle
|
||||
.db()
|
||||
.delete_folder_by_id(&req.id, &UpdateSource::Plugin)?,
|
||||
),
|
||||
"environment" => AnyModel::Environment(
|
||||
app_handle
|
||||
.db()
|
||||
.delete_environment_by_id(&req.id, &UpdateSource::Plugin)?,
|
||||
),
|
||||
_ => {
|
||||
return Err(PluginErr("Delete not supported for this model type".into()).into())
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Some(InternalEventPayload::DeleteModelResponse(
|
||||
yaak_plugins::events::DeleteModelResponse { model },
|
||||
)))
|
||||
}
|
||||
InternalEventPayload::GetHttpRequestByIdRequest(req) => {
|
||||
let http_request = app_handle.db().get_http_request(&req.id).ok();
|
||||
Ok(Some(InternalEventPayload::GetHttpRequestByIdResponse(GetHttpRequestByIdResponse {
|
||||
@@ -382,6 +446,24 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
|
||||
})))
|
||||
}
|
||||
|
||||
InternalEventPayload::ListWorkspacesRequest(_) => {
|
||||
let mut workspaces = Vec::new();
|
||||
|
||||
for (_, window) in app_handle.webview_windows() {
|
||||
if let Some(workspace) = workspace_from_window(&window) {
|
||||
workspaces.push(WorkspaceInfo {
|
||||
id: workspace.id.clone(),
|
||||
name: workspace.name.clone(),
|
||||
label: window.label().to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Some(InternalEventPayload::ListWorkspacesResponse(ListWorkspacesResponse {
|
||||
workspaces,
|
||||
})))
|
||||
}
|
||||
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
18
src-tauri/yaak-plugins/bindings/gen_events.ts
generated
18
src-tauri/yaak-plugins/bindings/gen_events.ts
generated
File diff suppressed because one or more lines are too long
57
src-tauri/yaak-plugins/bindings/gen_models.ts
generated
57
src-tauri/yaak-plugins/bindings/gen_models.ts
generated
@@ -1,11 +1,37 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type AnyModel = CookieJar | Environment | Folder | GraphQlIntrospection | GrpcConnection | GrpcEvent | GrpcRequest | HttpRequest | HttpResponse | HttpResponseEvent | KeyValue | Plugin | Settings | SyncState | WebsocketConnection | WebsocketEvent | WebsocketRequest | Workspace | WorkspaceMeta;
|
||||
|
||||
export type ClientCertificate = { host: string, port: number | null, crtFile: string | null, keyFile: string | null, pfxFile: string | null, passphrase: string | null, enabled?: boolean, };
|
||||
|
||||
export type Cookie = { raw_cookie: string, domain: CookieDomain, expires: CookieExpires, path: [string, boolean], };
|
||||
|
||||
export type CookieDomain = { "HostOnly": string } | { "Suffix": string } | "NotPresent" | "Empty";
|
||||
|
||||
export type CookieExpires = { "AtUtc": string } | "SessionEnd";
|
||||
|
||||
export type CookieJar = { model: "cookie_jar", id: string, createdAt: string, updatedAt: string, workspaceId: string, cookies: Array<Cookie>, name: string, };
|
||||
|
||||
export type EditorKeymap = "default" | "vim" | "vscode" | "emacs";
|
||||
|
||||
export type EncryptedKey = { encryptedKey: string, };
|
||||
|
||||
export type Environment = { model: "environment", id: string, workspaceId: string, createdAt: string, updatedAt: string, name: string, public: boolean, parentModel: string, parentId: string | null, variables: Array<EnvironmentVariable>, color: string | null, sortPriority: number, };
|
||||
|
||||
export type EnvironmentVariable = { enabled?: boolean, name: string, value: string, id?: string, };
|
||||
|
||||
export type Folder = { model: "folder", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record<string, any>, authenticationType: string | null, description: string, headers: Array<HttpRequestHeader>, name: string, sortPriority: number, };
|
||||
|
||||
export type GraphQlIntrospection = { model: "graphql_introspection", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, content: string | null, };
|
||||
|
||||
export type GrpcConnection = { model: "grpc_connection", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, elapsed: number, error: string | null, method: string, service: string, status: number, state: GrpcConnectionState, trailers: { [key in string]?: string }, url: string, };
|
||||
|
||||
export type GrpcConnectionState = "initialized" | "connected" | "closed";
|
||||
|
||||
export type GrpcEvent = { model: "grpc_event", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, connectionId: string, content: string, error: string | null, eventType: GrpcEventType, metadata: { [key in string]?: string }, status: number | null, };
|
||||
|
||||
export type GrpcEventType = "info" | "error" | "client_message" | "server_message" | "connection_start" | "connection_end";
|
||||
|
||||
export type GrpcRequest = { model: "grpc_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authenticationType: string | null, authentication: Record<string, any>, description: string, message: string, metadata: Array<HttpRequestHeader>, method: string | null, name: string, service: string | null, sortPriority: number, url: string, };
|
||||
|
||||
export type HttpRequest = { model: "http_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record<string, any>, authenticationType: string | null, body: Record<string, any>, bodyType: string | null, description: string, headers: Array<HttpRequestHeader>, method: string, name: string, sortPriority: number, url: string, urlParameters: Array<HttpUrlParameter>, };
|
||||
@@ -14,12 +40,43 @@ export type HttpRequestHeader = { enabled?: boolean, name: string, value: string
|
||||
|
||||
export type HttpResponse = { model: "http_response", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, bodyPath: string | null, contentLength: number | null, contentLengthCompressed: number | null, elapsed: number, elapsedHeaders: number, error: string | null, headers: Array<HttpResponseHeader>, remoteAddr: string | null, requestContentLength: number | null, requestHeaders: Array<HttpResponseHeader>, status: number, statusReason: string | null, state: HttpResponseState, url: string, version: string | null, };
|
||||
|
||||
export type HttpResponseEvent = { model: "http_response_event", id: string, createdAt: string, updatedAt: string, workspaceId: string, responseId: string, event: HttpResponseEventData, };
|
||||
|
||||
/**
|
||||
* Serializable representation of HTTP response events for DB storage.
|
||||
* This mirrors `yaak_http::sender::HttpResponseEvent` but with serde support.
|
||||
* The `From` impl is in yaak-http to avoid circular dependencies.
|
||||
*/
|
||||
export type HttpResponseEventData = { "type": "setting", name: string, value: string, } | { "type": "info", message: string, } | { "type": "redirect", url: string, status: number, behavior: string, } | { "type": "send_url", method: string, path: string, } | { "type": "receive_url", version: string, status: string, } | { "type": "header_up", name: string, value: string, } | { "type": "header_down", name: string, value: string, } | { "type": "chunk_sent", bytes: number, } | { "type": "chunk_received", bytes: number, };
|
||||
|
||||
export type HttpResponseHeader = { name: string, value: string, };
|
||||
|
||||
export type HttpResponseState = "initialized" | "connected" | "closed";
|
||||
|
||||
export type HttpUrlParameter = { enabled?: boolean, name: string, value: string, id?: string, };
|
||||
|
||||
export type KeyValue = { model: "key_value", id: string, createdAt: string, updatedAt: string, key: string, namespace: string, value: string, };
|
||||
|
||||
export type Plugin = { model: "plugin", id: string, createdAt: string, updatedAt: string, checkedAt: string | null, directory: string, enabled: boolean, url: string | null, };
|
||||
|
||||
export type ProxySetting = { "type": "enabled", http: string, https: string, auth: ProxySettingAuth | null, bypass: string, disabled: boolean, } | { "type": "disabled" };
|
||||
|
||||
export type ProxySettingAuth = { user: string, password: string, };
|
||||
|
||||
export type Settings = { model: "settings", id: string, createdAt: string, updatedAt: string, appearance: string, clientCertificates: Array<ClientCertificate>, coloredMethods: boolean, editorFont: string | null, editorFontSize: number, editorKeymap: EditorKeymap, editorSoftWrap: boolean, hideWindowControls: boolean, useNativeTitlebar: boolean, interfaceFont: string | null, interfaceFontSize: number, interfaceScale: number, openWorkspaceNewWindow: boolean | null, proxy: ProxySetting | null, themeDark: string, themeLight: string, updateChannel: string, hideLicenseBadge: boolean, autoupdate: boolean, autoDownloadUpdates: boolean, checkNotifications: boolean, };
|
||||
|
||||
export type SyncState = { model: "sync_state", id: string, workspaceId: string, createdAt: string, updatedAt: string, flushedAt: string, modelId: string, checksum: string, relPath: string, syncDir: string, };
|
||||
|
||||
export type WebsocketConnection = { model: "websocket_connection", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, elapsed: number, error: string | null, headers: Array<HttpResponseHeader>, state: WebsocketConnectionState, status: number, url: string, };
|
||||
|
||||
export type WebsocketConnectionState = "initialized" | "connected" | "closing" | "closed";
|
||||
|
||||
export type WebsocketEvent = { model: "websocket_event", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, connectionId: string, isServer: boolean, message: Array<number>, messageType: WebsocketEventType, };
|
||||
|
||||
export type WebsocketEventType = "binary" | "close" | "frame" | "open" | "ping" | "pong" | "text";
|
||||
|
||||
export type WebsocketRequest = { model: "websocket_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record<string, any>, authenticationType: string | null, description: string, headers: Array<HttpRequestHeader>, message: string, name: string, sortPriority: number, url: string, urlParameters: Array<HttpUrlParameter>, };
|
||||
|
||||
export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, authentication: Record<string, any>, authenticationType: string | null, description: string, headers: Array<HttpRequestHeader>, name: string, encryptionKeyChallenge: string | null, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, };
|
||||
|
||||
export type WorkspaceMeta = { model: "workspace_meta", id: string, workspaceId: string, createdAt: string, updatedAt: string, encryptionKey: EncryptedKey | null, settingSyncDir: string | null, };
|
||||
|
||||
@@ -4,7 +4,8 @@ use tauri::{Runtime, WebviewWindow};
|
||||
use ts_rs::TS;
|
||||
use yaak_common::window::WorkspaceWindowTrait;
|
||||
use yaak_models::models::{
|
||||
Environment, Folder, GrpcRequest, HttpRequest, HttpResponse, WebsocketRequest, Workspace,
|
||||
AnyModel, Environment, Folder, GrpcRequest, HttpRequest, HttpResponse, WebsocketRequest,
|
||||
Workspace,
|
||||
};
|
||||
use yaak_models::util::generate_prefixed_id;
|
||||
|
||||
@@ -161,6 +162,9 @@ pub enum InternalEventPayload {
|
||||
WindowInfoRequest(WindowInfoRequest),
|
||||
WindowInfoResponse(WindowInfoResponse),
|
||||
|
||||
ListWorkspacesRequest(ListWorkspacesRequest),
|
||||
ListWorkspacesResponse(ListWorkspacesResponse),
|
||||
|
||||
GetHttpRequestByIdRequest(GetHttpRequestByIdRequest),
|
||||
GetHttpRequestByIdResponse(GetHttpRequestByIdResponse),
|
||||
|
||||
@@ -171,6 +175,12 @@ pub enum InternalEventPayload {
|
||||
ListFoldersRequest(ListFoldersRequest),
|
||||
ListFoldersResponse(ListFoldersResponse),
|
||||
|
||||
UpsertModelRequest(UpsertModelRequest),
|
||||
UpsertModelResponse(UpsertModelResponse),
|
||||
|
||||
DeleteModelRequest(DeleteModelRequest),
|
||||
DeleteModelResponse(DeleteModelResponse),
|
||||
|
||||
GetThemesRequest(GetThemesRequest),
|
||||
GetThemesResponse(GetThemesResponse),
|
||||
|
||||
@@ -573,6 +583,28 @@ pub struct WindowInfoResponse {
|
||||
pub label: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||
#[serde(default, rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "gen_events.ts")]
|
||||
pub struct ListWorkspacesRequest {}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||
#[serde(default, rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "gen_events.ts")]
|
||||
pub struct ListWorkspacesResponse {
|
||||
pub workspaces: Vec<WorkspaceInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "gen_events.ts")]
|
||||
pub struct WorkspaceInfo {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
#[ts(skip)]
|
||||
pub label: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export, export_to = "gen_events.ts")]
|
||||
@@ -1330,6 +1362,35 @@ pub struct ListFoldersResponse {
|
||||
pub folders: Vec<Folder>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "gen_events.ts")]
|
||||
pub struct UpsertModelRequest {
|
||||
pub model: AnyModel,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "gen_events.ts")]
|
||||
pub struct UpsertModelResponse {
|
||||
pub model: AnyModel,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "gen_events.ts")]
|
||||
pub struct DeleteModelRequest {
|
||||
pub model: String,
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "gen_events.ts")]
|
||||
pub struct DeleteModelResponse {
|
||||
pub model: AnyModel,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||
#[serde(default, rename_all = "camelCase")]
|
||||
#[ts(export, export_to = "gen_events.ts")]
|
||||
|
||||
BIN
src-tauri/yaak-templates/pkg/yaak_templates_bg.wasm
generated
BIN
src-tauri/yaak-templates/pkg/yaak_templates_bg.wasm
generated
Binary file not shown.
@@ -248,7 +248,6 @@ pub fn find_client_certificate(
|
||||
|
||||
// Match host (case-insensitive)
|
||||
if !cert.host.eq_ignore_ascii_case(host) {
|
||||
debug!("Client certificate host does not match {} != {} (cert)", host, cert.host);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user