mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-05-18 05:37:09 +02:00
Track HTTP setting sources in timeline
This commit is contained in:
@@ -1,10 +1,15 @@
|
|||||||
import type {
|
import type {
|
||||||
|
AnyModel,
|
||||||
HttpResponse,
|
HttpResponse,
|
||||||
HttpResponseEvent,
|
HttpResponseEvent,
|
||||||
HttpResponseEventData,
|
HttpResponseEventData,
|
||||||
} from "@yaakapp-internal/models";
|
} from "@yaakapp-internal/models";
|
||||||
|
import { foldersAtom, workspacesAtom } from "@yaakapp-internal/models";
|
||||||
|
import { useAtomValue } from "jotai";
|
||||||
import { type ReactNode, useMemo, useState } from "react";
|
import { type ReactNode, useMemo, useState } from "react";
|
||||||
import { useHttpResponseEvents } from "../hooks/useHttpResponseEvents";
|
import { useHttpResponseEvents } from "../hooks/useHttpResponseEvents";
|
||||||
|
import { useAllRequests } from "../hooks/useAllRequests";
|
||||||
|
import { resolvedModelName } from "../lib/resolvedModelName";
|
||||||
import { Editor } from "./core/Editor/LazyEditor";
|
import { Editor } from "./core/Editor/LazyEditor";
|
||||||
import { type EventDetailAction, EventDetailHeader, EventViewer } from "./core/EventViewer";
|
import { type EventDetailAction, EventDetailHeader, EventViewer } from "./core/EventViewer";
|
||||||
import { EventViewerRow } from "./core/EventViewerRow";
|
import { EventViewerRow } from "./core/EventViewerRow";
|
||||||
@@ -95,6 +100,7 @@ function EventDetails({
|
|||||||
}) {
|
}) {
|
||||||
const { label } = getEventDisplay(event.event);
|
const { label } = getEventDisplay(event.event);
|
||||||
const e = event.event;
|
const e = event.event;
|
||||||
|
const settingSourceModels = useSettingSourceModels();
|
||||||
|
|
||||||
const actions: EventDetailAction[] = [
|
const actions: EventDetailAction[] = [
|
||||||
{
|
{
|
||||||
@@ -211,6 +217,9 @@ function EventDetails({
|
|||||||
<KeyValueRows>
|
<KeyValueRows>
|
||||||
<KeyValueRow label="Setting">{e.name}</KeyValueRow>
|
<KeyValueRow label="Setting">{e.name}</KeyValueRow>
|
||||||
<KeyValueRow label="Value">{e.value}</KeyValueRow>
|
<KeyValueRow label="Value">{e.value}</KeyValueRow>
|
||||||
|
{e.source_model != null ? (
|
||||||
|
<KeyValueRow label="Source">{formatSettingSource(e, settingSourceModels)}</KeyValueRow>
|
||||||
|
) : null}
|
||||||
</KeyValueRows>
|
</KeyValueRows>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -315,6 +324,35 @@ function formatEventText(event: HttpResponseEventData, includePrefix: boolean):
|
|||||||
return includePrefix ? `${prefix} ${text}` : text;
|
return includePrefix ? `${prefix} ${text}` : text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function useSettingSourceModels() {
|
||||||
|
const requests = useAllRequests();
|
||||||
|
const folders = useAtomValue(foldersAtom);
|
||||||
|
const workspaces = useAtomValue(workspacesAtom);
|
||||||
|
|
||||||
|
return useMemo<AnyModel[]>(
|
||||||
|
() => [...requests, ...folders, ...workspaces],
|
||||||
|
[requests, folders, workspaces],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatSettingSource(
|
||||||
|
event: Extract<HttpResponseEventData, { type: "setting" }>,
|
||||||
|
models: AnyModel[],
|
||||||
|
): string {
|
||||||
|
const sourceModel = event.source_model;
|
||||||
|
if (sourceModel == null || sourceModel === "default") {
|
||||||
|
return "Default";
|
||||||
|
}
|
||||||
|
|
||||||
|
const model =
|
||||||
|
event.source_id == null
|
||||||
|
? null
|
||||||
|
: (models.find((m) => m.model === sourceModel && m.id === event.source_id) ?? null);
|
||||||
|
const name = model == null ? event.source_name : resolvedModelName(model);
|
||||||
|
const label = sourceModel.replaceAll("_", " ");
|
||||||
|
return name == null || name.length === 0 ? label : `${name} (${label})`;
|
||||||
|
}
|
||||||
|
|
||||||
type EventDisplay = {
|
type EventDisplay = {
|
||||||
icon: IconProps["icon"];
|
icon: IconProps["icon"];
|
||||||
color: IconProps["color"];
|
color: IconProps["color"];
|
||||||
|
|||||||
@@ -248,16 +248,18 @@ pub async fn cmd_ws_connect<R: Runtime>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cookie_jar =
|
let mut cookie_jar = match (
|
||||||
match (resolved_settings.send_cookies || resolved_settings.store_cookies, cookie_jar_id) {
|
resolved_settings.send_cookies.value || resolved_settings.store_cookies.value,
|
||||||
(true, Some(id)) => Some(app_handle.db().get_cookie_jar(id)?),
|
cookie_jar_id,
|
||||||
_ => None,
|
) {
|
||||||
};
|
(true, Some(id)) => Some(app_handle.db().get_cookie_jar(id)?),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
let cookie_store =
|
let cookie_store =
|
||||||
cookie_jar.as_ref().map(|jar| CookieStore::from_cookies(jar.cookies.clone()));
|
cookie_jar.as_ref().map(|jar| CookieStore::from_cookies(jar.cookies.clone()));
|
||||||
|
|
||||||
// Add cookies to WS HTTP Upgrade
|
// Add cookies to WS HTTP Upgrade
|
||||||
if let (true, Some(store)) = (resolved_settings.send_cookies, cookie_store.as_ref()) {
|
if let (true, Some(store)) = (resolved_settings.send_cookies.value, cookie_store.as_ref()) {
|
||||||
// Convert WS URL -> HTTP URL because our cookie store matches based on
|
// Convert WS URL -> HTTP URL because our cookie store matches based on
|
||||||
// Path/HttpOnly/Secure attributes even though WS upgrades are HTTP requests
|
// Path/HttpOnly/Secure attributes even though WS upgrades are HTTP requests
|
||||||
let http_url = convert_ws_url_to_http(&url);
|
let http_url = convert_ws_url_to_http(&url);
|
||||||
@@ -295,7 +297,7 @@ pub async fn cmd_ws_connect<R: Runtime>(
|
|||||||
url.as_str(),
|
url.as_str(),
|
||||||
headers,
|
headers,
|
||||||
receive_tx,
|
receive_tx,
|
||||||
resolved_settings.validate_certificates,
|
resolved_settings.validate_certificates.value,
|
||||||
client_cert,
|
client_cert,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@@ -335,7 +337,7 @@ pub async fn cmd_ws_connect<R: Runtime>(
|
|||||||
.collect::<Vec<HttpResponseHeader>>();
|
.collect::<Vec<HttpResponseHeader>>();
|
||||||
|
|
||||||
if let (true, Some(cookie_jar), Some(store)) =
|
if let (true, Some(cookie_jar), Some(store)) =
|
||||||
(resolved_settings.store_cookies, cookie_jar.as_mut(), cookie_store.as_ref())
|
(resolved_settings.store_cookies.value, cookie_jar.as_mut(), cookie_store.as_ref())
|
||||||
{
|
{
|
||||||
let set_cookie_headers = response
|
let set_cookie_headers = response
|
||||||
.headers()
|
.headers()
|
||||||
|
|||||||
@@ -24,7 +24,13 @@ pub enum RedirectBehavior {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum HttpResponseEvent {
|
pub enum HttpResponseEvent {
|
||||||
Setting(String, String),
|
Setting {
|
||||||
|
name: String,
|
||||||
|
value: String,
|
||||||
|
source_model: Option<String>,
|
||||||
|
source_id: Option<String>,
|
||||||
|
source_name: Option<String>,
|
||||||
|
},
|
||||||
Info(String),
|
Info(String),
|
||||||
Redirect {
|
Redirect {
|
||||||
url: String,
|
url: String,
|
||||||
@@ -67,7 +73,9 @@ pub enum HttpResponseEvent {
|
|||||||
impl Display for HttpResponseEvent {
|
impl Display for HttpResponseEvent {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
HttpResponseEvent::Setting(name, value) => write!(f, "* Setting {}={}", name, value),
|
HttpResponseEvent::Setting { name, value, .. } => {
|
||||||
|
write!(f, "* Setting {}={}", name, value)
|
||||||
|
}
|
||||||
HttpResponseEvent::Info(s) => write!(f, "* {}", s),
|
HttpResponseEvent::Info(s) => write!(f, "* {}", s),
|
||||||
HttpResponseEvent::Redirect {
|
HttpResponseEvent::Redirect {
|
||||||
url,
|
url,
|
||||||
@@ -146,7 +154,9 @@ impl From<HttpResponseEvent> for yaak_models::models::HttpResponseEventData {
|
|||||||
fn from(event: HttpResponseEvent) -> Self {
|
fn from(event: HttpResponseEvent) -> Self {
|
||||||
use yaak_models::models::HttpResponseEventData as D;
|
use yaak_models::models::HttpResponseEventData as D;
|
||||||
match event {
|
match event {
|
||||||
HttpResponseEvent::Setting(name, value) => D::Setting { name, value },
|
HttpResponseEvent::Setting { name, value, source_model, source_id, source_name } => {
|
||||||
|
D::Setting { name, value, source_model, source_id, source_name }
|
||||||
|
}
|
||||||
HttpResponseEvent::Info(message) => D::Info { message },
|
HttpResponseEvent::Info(message) => D::Info { message },
|
||||||
HttpResponseEvent::Redirect {
|
HttpResponseEvent::Redirect {
|
||||||
url,
|
url,
|
||||||
@@ -483,15 +493,6 @@ impl HttpSender for ReqwestSender {
|
|||||||
|
|
||||||
// Send the request
|
// Send the request
|
||||||
let sendable_req = req_builder.build()?;
|
let sendable_req = req_builder.build()?;
|
||||||
send_event(HttpResponseEvent::Setting(
|
|
||||||
"timeout".to_string(),
|
|
||||||
if request.options.timeout.unwrap_or_default().is_zero() {
|
|
||||||
"Infinity".to_string()
|
|
||||||
} else {
|
|
||||||
format!("{:?}", request.options.timeout)
|
|
||||||
},
|
|
||||||
));
|
|
||||||
|
|
||||||
send_event(HttpResponseEvent::SendUrl {
|
send_event(HttpResponseEvent::SendUrl {
|
||||||
method: sendable_req.method().to_string(),
|
method: sendable_req.method().to_string(),
|
||||||
scheme: sendable_req.url().scheme().to_string(),
|
scheme: sendable_req.url().scheme().to_string(),
|
||||||
|
|||||||
@@ -144,12 +144,6 @@ impl<S: HttpSender> HttpTransaction<S> {
|
|||||||
options: request.options.clone(),
|
options: request.options.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Send the request
|
|
||||||
send_event(HttpResponseEvent::Setting(
|
|
||||||
"redirects".to_string(),
|
|
||||||
request.options.follow_redirects.to_string(),
|
|
||||||
));
|
|
||||||
|
|
||||||
// Execute with cancellation support
|
// Execute with cancellation support
|
||||||
let response = tokio::select! {
|
let response = tokio::select! {
|
||||||
result = self.sender.send(req, event_tx.clone()) => result?,
|
result = self.sender.send(req, event_tx.clone()) => result?,
|
||||||
|
|||||||
+8
-1
@@ -258,7 +258,14 @@ export type HttpResponseEvent = {
|
|||||||
* The `From` impl is in yaak-http to avoid circular dependencies.
|
* The `From` impl is in yaak-http to avoid circular dependencies.
|
||||||
*/
|
*/
|
||||||
export type HttpResponseEventData =
|
export type HttpResponseEventData =
|
||||||
| { type: "setting"; name: string; value: string }
|
| {
|
||||||
|
type: "setting";
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
source_model?: string;
|
||||||
|
source_id?: string;
|
||||||
|
source_name?: string;
|
||||||
|
}
|
||||||
| { type: "info"; message: string }
|
| { type: "info"; message: string }
|
||||||
| {
|
| {
|
||||||
type: "redirect";
|
type: "redirect";
|
||||||
|
|||||||
@@ -92,23 +92,46 @@ pub struct DnsOverride {
|
|||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Default)]
|
||||||
|
pub struct ResolvedSetting<T> {
|
||||||
|
pub value: T,
|
||||||
|
pub source_model: String,
|
||||||
|
pub source_id: Option<String>,
|
||||||
|
pub source_name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ResolvedSetting<T> {
|
||||||
|
pub fn from_model(value: T, model: AnyModel) -> Self {
|
||||||
|
Self {
|
||||||
|
value,
|
||||||
|
source_model: model.model().to_string(),
|
||||||
|
source_id: Some(model.id().to_string()),
|
||||||
|
source_name: Some(model.resolved_name()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_source(value: T) -> Self {
|
||||||
|
Self { value, source_model: "default".to_string(), source_id: None, source_name: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ResolvedHttpRequestSettings {
|
pub struct ResolvedHttpRequestSettings {
|
||||||
pub validate_certificates: bool,
|
pub validate_certificates: ResolvedSetting<bool>,
|
||||||
pub follow_redirects: bool,
|
pub follow_redirects: ResolvedSetting<bool>,
|
||||||
pub request_timeout: i32,
|
pub request_timeout: ResolvedSetting<i32>,
|
||||||
pub send_cookies: bool,
|
pub send_cookies: ResolvedSetting<bool>,
|
||||||
pub store_cookies: bool,
|
pub store_cookies: ResolvedSetting<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ResolvedHttpRequestSettings {
|
impl Default for ResolvedHttpRequestSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
validate_certificates: true,
|
validate_certificates: ResolvedSetting::default_source(true),
|
||||||
follow_redirects: true,
|
follow_redirects: ResolvedSetting::default_source(true),
|
||||||
request_timeout: 0,
|
request_timeout: ResolvedSetting::default_source(0),
|
||||||
send_cookies: true,
|
send_cookies: ResolvedSetting::default_source(true),
|
||||||
store_cookies: true,
|
store_cookies: ResolvedSetting::default_source(true),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1748,6 +1771,15 @@ pub enum HttpResponseEventData {
|
|||||||
Setting {
|
Setting {
|
||||||
name: String,
|
name: String,
|
||||||
value: String,
|
value: String,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
#[ts(optional, as = "Option<String>")]
|
||||||
|
source_model: Option<String>,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
#[ts(optional, as = "Option<String>")]
|
||||||
|
source_id: Option<String>,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
#[ts(optional, as = "Option<String>")]
|
||||||
|
source_name: Option<String>,
|
||||||
},
|
},
|
||||||
Info {
|
Info {
|
||||||
message: String,
|
message: String,
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ use crate::client_db::ClientDb;
|
|||||||
use crate::connection_or_tx::ConnectionOrTx;
|
use crate::connection_or_tx::ConnectionOrTx;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
Environment, EnvironmentIden, Folder, FolderIden, GrpcRequest, GrpcRequestIden, HttpRequest,
|
AnyModel, Environment, EnvironmentIden, Folder, FolderIden, GrpcRequest, GrpcRequestIden,
|
||||||
HttpRequestHeader, HttpRequestIden, ResolvedHttpRequestSettings, WebsocketRequest,
|
HttpRequest, HttpRequestHeader, HttpRequestIden, ResolvedHttpRequestSettings, ResolvedSetting,
|
||||||
WebsocketRequestIden,
|
WebsocketRequest, WebsocketRequestIden,
|
||||||
};
|
};
|
||||||
use crate::util::UpdateSource;
|
use crate::util::UpdateSource;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
@@ -157,27 +157,42 @@ impl<'a> ClientDb<'a> {
|
|||||||
|
|
||||||
Ok(ResolvedHttpRequestSettings {
|
Ok(ResolvedHttpRequestSettings {
|
||||||
validate_certificates: if folder.setting_validate_certificates.enabled {
|
validate_certificates: if folder.setting_validate_certificates.enabled {
|
||||||
folder.setting_validate_certificates.value
|
ResolvedSetting::from_model(
|
||||||
|
folder.setting_validate_certificates.value,
|
||||||
|
AnyModel::Folder(folder.clone()),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
parent.validate_certificates
|
parent.validate_certificates
|
||||||
},
|
},
|
||||||
follow_redirects: if folder.setting_follow_redirects.enabled {
|
follow_redirects: if folder.setting_follow_redirects.enabled {
|
||||||
folder.setting_follow_redirects.value
|
ResolvedSetting::from_model(
|
||||||
|
folder.setting_follow_redirects.value,
|
||||||
|
AnyModel::Folder(folder.clone()),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
parent.follow_redirects
|
parent.follow_redirects
|
||||||
},
|
},
|
||||||
request_timeout: if folder.setting_request_timeout.enabled {
|
request_timeout: if folder.setting_request_timeout.enabled {
|
||||||
folder.setting_request_timeout.value
|
ResolvedSetting::from_model(
|
||||||
|
folder.setting_request_timeout.value,
|
||||||
|
AnyModel::Folder(folder.clone()),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
parent.request_timeout
|
parent.request_timeout
|
||||||
},
|
},
|
||||||
send_cookies: if folder.setting_send_cookies.enabled {
|
send_cookies: if folder.setting_send_cookies.enabled {
|
||||||
folder.setting_send_cookies.value
|
ResolvedSetting::from_model(
|
||||||
|
folder.setting_send_cookies.value,
|
||||||
|
AnyModel::Folder(folder.clone()),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
parent.send_cookies
|
parent.send_cookies
|
||||||
},
|
},
|
||||||
store_cookies: if folder.setting_store_cookies.enabled {
|
store_cookies: if folder.setting_store_cookies.enabled {
|
||||||
folder.setting_store_cookies.value
|
ResolvedSetting::from_model(
|
||||||
|
folder.setting_store_cookies.value,
|
||||||
|
AnyModel::Folder(folder.clone()),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
parent.store_cookies
|
parent.store_cookies
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ use super::dedupe_headers;
|
|||||||
use crate::client_db::ClientDb;
|
use crate::client_db::ClientDb;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
Folder, FolderIden, HttpRequest, HttpRequestHeader, HttpRequestIden,
|
AnyModel, Folder, FolderIden, HttpRequest, HttpRequestHeader, HttpRequestIden,
|
||||||
ResolvedHttpRequestSettings,
|
ResolvedHttpRequestSettings, ResolvedSetting,
|
||||||
};
|
};
|
||||||
use crate::util::UpdateSource;
|
use crate::util::UpdateSource;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
@@ -108,27 +108,42 @@ impl<'a> ClientDb<'a> {
|
|||||||
|
|
||||||
Ok(ResolvedHttpRequestSettings {
|
Ok(ResolvedHttpRequestSettings {
|
||||||
validate_certificates: if http_request.setting_validate_certificates.enabled {
|
validate_certificates: if http_request.setting_validate_certificates.enabled {
|
||||||
http_request.setting_validate_certificates.value
|
ResolvedSetting::from_model(
|
||||||
|
http_request.setting_validate_certificates.value,
|
||||||
|
AnyModel::HttpRequest(http_request.clone()),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
parent.validate_certificates
|
parent.validate_certificates
|
||||||
},
|
},
|
||||||
follow_redirects: if http_request.setting_follow_redirects.enabled {
|
follow_redirects: if http_request.setting_follow_redirects.enabled {
|
||||||
http_request.setting_follow_redirects.value
|
ResolvedSetting::from_model(
|
||||||
|
http_request.setting_follow_redirects.value,
|
||||||
|
AnyModel::HttpRequest(http_request.clone()),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
parent.follow_redirects
|
parent.follow_redirects
|
||||||
},
|
},
|
||||||
request_timeout: if http_request.setting_request_timeout.enabled {
|
request_timeout: if http_request.setting_request_timeout.enabled {
|
||||||
http_request.setting_request_timeout.value
|
ResolvedSetting::from_model(
|
||||||
|
http_request.setting_request_timeout.value,
|
||||||
|
AnyModel::HttpRequest(http_request.clone()),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
parent.request_timeout
|
parent.request_timeout
|
||||||
},
|
},
|
||||||
send_cookies: if http_request.setting_send_cookies.enabled {
|
send_cookies: if http_request.setting_send_cookies.enabled {
|
||||||
http_request.setting_send_cookies.value
|
ResolvedSetting::from_model(
|
||||||
|
http_request.setting_send_cookies.value,
|
||||||
|
AnyModel::HttpRequest(http_request.clone()),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
parent.send_cookies
|
parent.send_cookies
|
||||||
},
|
},
|
||||||
store_cookies: if http_request.setting_store_cookies.enabled {
|
store_cookies: if http_request.setting_store_cookies.enabled {
|
||||||
http_request.setting_store_cookies.value
|
ResolvedSetting::from_model(
|
||||||
|
http_request.setting_store_cookies.value,
|
||||||
|
AnyModel::HttpRequest(http_request.clone()),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
parent.store_cookies
|
parent.store_cookies
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ use super::dedupe_headers;
|
|||||||
use crate::client_db::ClientDb;
|
use crate::client_db::ClientDb;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
Folder, FolderIden, HttpRequestHeader, ResolvedHttpRequestSettings, WebsocketRequest,
|
AnyModel, Folder, FolderIden, HttpRequestHeader, ResolvedHttpRequestSettings, ResolvedSetting,
|
||||||
WebsocketRequestIden,
|
WebsocketRequest, WebsocketRequestIden,
|
||||||
};
|
};
|
||||||
use crate::util::UpdateSource;
|
use crate::util::UpdateSource;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
@@ -132,12 +132,18 @@ impl<'a> ClientDb<'a> {
|
|||||||
|
|
||||||
Ok(ResolvedHttpRequestSettings {
|
Ok(ResolvedHttpRequestSettings {
|
||||||
send_cookies: if websocket_request.setting_send_cookies.enabled {
|
send_cookies: if websocket_request.setting_send_cookies.enabled {
|
||||||
websocket_request.setting_send_cookies.value
|
ResolvedSetting::from_model(
|
||||||
|
websocket_request.setting_send_cookies.value,
|
||||||
|
AnyModel::WebsocketRequest(websocket_request.clone()),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
parent.send_cookies
|
parent.send_cookies
|
||||||
},
|
},
|
||||||
store_cookies: if websocket_request.setting_store_cookies.enabled {
|
store_cookies: if websocket_request.setting_store_cookies.enabled {
|
||||||
websocket_request.setting_store_cookies.value
|
ResolvedSetting::from_model(
|
||||||
|
websocket_request.setting_store_cookies.value,
|
||||||
|
AnyModel::WebsocketRequest(websocket_request.clone()),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
parent.store_cookies
|
parent.store_cookies
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::client_db::ClientDb;
|
use crate::client_db::ClientDb;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
EnvironmentIden, FolderIden, GrpcRequestIden, HttpRequestHeader, HttpRequestIden,
|
AnyModel, EnvironmentIden, FolderIden, GrpcRequestIden, HttpRequestHeader, HttpRequestIden,
|
||||||
ResolvedHttpRequestSettings, WebsocketRequestIden, Workspace, WorkspaceIden,
|
ResolvedHttpRequestSettings, ResolvedSetting, WebsocketRequestIden, Workspace, WorkspaceIden,
|
||||||
};
|
};
|
||||||
use crate::util::UpdateSource;
|
use crate::util::UpdateSource;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
@@ -90,11 +90,26 @@ impl<'a> ClientDb<'a> {
|
|||||||
workspace: &Workspace,
|
workspace: &Workspace,
|
||||||
) -> ResolvedHttpRequestSettings {
|
) -> ResolvedHttpRequestSettings {
|
||||||
ResolvedHttpRequestSettings {
|
ResolvedHttpRequestSettings {
|
||||||
validate_certificates: workspace.setting_validate_certificates,
|
validate_certificates: ResolvedSetting::from_model(
|
||||||
follow_redirects: workspace.setting_follow_redirects,
|
workspace.setting_validate_certificates,
|
||||||
request_timeout: workspace.setting_request_timeout,
|
AnyModel::Workspace(workspace.clone()),
|
||||||
send_cookies: workspace.setting_send_cookies,
|
),
|
||||||
store_cookies: workspace.setting_store_cookies,
|
follow_redirects: ResolvedSetting::from_model(
|
||||||
|
workspace.setting_follow_redirects,
|
||||||
|
AnyModel::Workspace(workspace.clone()),
|
||||||
|
),
|
||||||
|
request_timeout: ResolvedSetting::from_model(
|
||||||
|
workspace.setting_request_timeout,
|
||||||
|
AnyModel::Workspace(workspace.clone()),
|
||||||
|
),
|
||||||
|
send_cookies: ResolvedSetting::from_model(
|
||||||
|
workspace.setting_send_cookies,
|
||||||
|
AnyModel::Workspace(workspace.clone()),
|
||||||
|
),
|
||||||
|
store_cookies: ResolvedSetting::from_model(
|
||||||
|
workspace.setting_store_cookies,
|
||||||
|
AnyModel::Workspace(workspace.clone()),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+430
-56
@@ -1,108 +1,482 @@
|
|||||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
// 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 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 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 Cookie = {
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
domain: CookieDomain;
|
||||||
|
expires: CookieExpires;
|
||||||
|
path: string;
|
||||||
|
secure: boolean;
|
||||||
|
httpOnly: boolean;
|
||||||
|
sameSite: CookieSameSite | null;
|
||||||
|
};
|
||||||
|
|
||||||
export type CookieDomain = { "HostOnly": string } | { "Suffix": string } | "NotPresent" | "Empty";
|
export type CookieDomain = { HostOnly: string } | { Suffix: string } | "NotPresent" | "Empty";
|
||||||
|
|
||||||
export type CookieExpires = { "AtUtc": string } | "SessionEnd";
|
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 CookieJar = {
|
||||||
|
model: "cookie_jar";
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
workspaceId: string;
|
||||||
|
cookies: Array<Cookie>;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type DnsOverride = { hostname: string, ipv4: Array<string>, ipv6: Array<string>, enabled?: boolean, };
|
export type CookieSameSite = "Strict" | "Lax" | "None";
|
||||||
|
|
||||||
|
export type DnsOverride = {
|
||||||
|
hostname: string;
|
||||||
|
ipv4: Array<string>;
|
||||||
|
ipv6: Array<string>;
|
||||||
|
enabled?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type EditorKeymap = "default" | "vim" | "vscode" | "emacs";
|
export type EditorKeymap = "default" | "vim" | "vscode" | "emacs";
|
||||||
|
|
||||||
export type EncryptedKey = { encryptedKey: string, };
|
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,
|
export type Environment = {
|
||||||
/**
|
model: "environment";
|
||||||
* Variables defined in this environment scope.
|
id: string;
|
||||||
* Child environments override parent variables by name.
|
workspaceId: string;
|
||||||
*/
|
createdAt: string;
|
||||||
variables: Array<EnvironmentVariable>, color: string | null, sortPriority: number, };
|
updatedAt: string;
|
||||||
|
name: string;
|
||||||
|
public: boolean;
|
||||||
|
parentModel: string;
|
||||||
|
parentId: string | null;
|
||||||
|
/**
|
||||||
|
* Variables defined in this environment scope.
|
||||||
|
* Child environments override parent variables by name.
|
||||||
|
*/
|
||||||
|
variables: Array<EnvironmentVariable>;
|
||||||
|
color: string | null;
|
||||||
|
sortPriority: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type EnvironmentVariable = { enabled?: boolean, name: string, value: string, id?: string, };
|
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 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;
|
||||||
|
settingSendCookies: InheritedBoolSetting;
|
||||||
|
settingStoreCookies: InheritedBoolSetting;
|
||||||
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
|
settingFollowRedirects: InheritedBoolSetting;
|
||||||
|
settingRequestTimeout: InheritedIntSetting;
|
||||||
|
};
|
||||||
|
|
||||||
export type GraphQlIntrospection = { model: "graphql_introspection", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, content: string | null, };
|
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 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 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 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 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,
|
export type GrpcRequest = {
|
||||||
/**
|
model: "grpc_request";
|
||||||
* Server URL (http for plaintext or https for secure)
|
id: string;
|
||||||
*/
|
createdAt: string;
|
||||||
url: 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;
|
||||||
|
/**
|
||||||
|
* Server URL (http for plaintext or https for secure)
|
||||||
|
*/
|
||||||
|
url: string;
|
||||||
|
settingSendCookies: InheritedBoolSetting;
|
||||||
|
settingStoreCookies: InheritedBoolSetting;
|
||||||
|
};
|
||||||
|
|
||||||
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,
|
export type HttpRequest = {
|
||||||
/**
|
model: "http_request";
|
||||||
* URL parameters used for both path placeholders (`:id`) and query string entries.
|
id: string;
|
||||||
*/
|
createdAt: string;
|
||||||
urlParameters: Array<HttpUrlParameter>, };
|
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;
|
||||||
|
/**
|
||||||
|
* URL parameters used for both path placeholders (`:id`) and query string entries.
|
||||||
|
*/
|
||||||
|
urlParameters: Array<HttpUrlParameter>;
|
||||||
|
settingSendCookies: InheritedBoolSetting;
|
||||||
|
settingStoreCookies: InheritedBoolSetting;
|
||||||
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
|
settingFollowRedirects: InheritedBoolSetting;
|
||||||
|
settingRequestTimeout: InheritedIntSetting;
|
||||||
|
};
|
||||||
|
|
||||||
export type HttpRequestHeader = { enabled?: boolean, name: string, value: string, id?: string, };
|
export type HttpRequestHeader = { enabled?: boolean; name: string; value: string; id?: 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, elapsedDns: 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 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;
|
||||||
|
elapsedDns: 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, };
|
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.
|
* Serializable representation of HTTP response events for DB storage.
|
||||||
* This mirrors `yaak_http::sender::HttpResponseEvent` but with serde support.
|
* This mirrors `yaak_http::sender::HttpResponseEvent` but with serde support.
|
||||||
* The `From` impl is in yaak-http to avoid circular dependencies.
|
* 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, dropped_body: boolean, dropped_headers: Array<string>, } | { "type": "send_url", method: string, scheme: string, username: string, password: string, host: string, port: number, path: string, query: string, fragment: 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, } | { "type": "dns_resolved", hostname: string, addresses: Array<string>, duration: bigint, overridden: boolean, };
|
export type HttpResponseEventData =
|
||||||
|
| {
|
||||||
|
type: "setting";
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
source_model?: string;
|
||||||
|
source_id?: string;
|
||||||
|
source_name?: string;
|
||||||
|
}
|
||||||
|
| { type: "info"; message: string }
|
||||||
|
| {
|
||||||
|
type: "redirect";
|
||||||
|
url: string;
|
||||||
|
status: number;
|
||||||
|
behavior: string;
|
||||||
|
dropped_body: boolean;
|
||||||
|
dropped_headers: Array<string>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "send_url";
|
||||||
|
method: string;
|
||||||
|
scheme: string;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
path: string;
|
||||||
|
query: string;
|
||||||
|
fragment: 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 }
|
||||||
|
| {
|
||||||
|
type: "dns_resolved";
|
||||||
|
hostname: string;
|
||||||
|
addresses: Array<string>;
|
||||||
|
duration: bigint;
|
||||||
|
overridden: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type HttpResponseHeader = { name: string, value: string, };
|
export type HttpResponseHeader = { name: string; value: string };
|
||||||
|
|
||||||
export type HttpResponseState = "initialized" | "connected" | "closed";
|
export type HttpResponseState = "initialized" | "connected" | "closed";
|
||||||
|
|
||||||
export type HttpUrlParameter = { enabled?: boolean,
|
export type HttpUrlParameter = {
|
||||||
/**
|
enabled?: boolean;
|
||||||
* Colon-prefixed parameters are treated as path parameters if they match, like `/users/:id`
|
/**
|
||||||
* Other entries are appended as query parameters
|
* Colon-prefixed parameters are treated as path parameters if they match, like `/users/:id`
|
||||||
*/
|
* Other entries are appended as query parameters
|
||||||
name: string, value: string, id?: string, };
|
*/
|
||||||
|
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 InheritedBoolSetting = { enabled?: boolean; value: boolean };
|
||||||
|
|
||||||
export type Plugin = { model: "plugin", id: string, createdAt: string, updatedAt: string, checkedAt: string | null, directory: string, enabled: boolean, url: string | null, source: PluginSource, };
|
export type InheritedIntSetting = { enabled?: boolean; value: number };
|
||||||
|
|
||||||
|
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;
|
||||||
|
source: PluginSource;
|
||||||
|
};
|
||||||
|
|
||||||
export type PluginSource = "bundled" | "filesystem" | "registry";
|
export type PluginSource = "bundled" | "filesystem" | "registry";
|
||||||
|
|
||||||
export type ProxySetting = { "type": "enabled", http: string, https: string, auth: ProxySettingAuth | null, bypass: string, disabled: boolean, } | { "type": "disabled" };
|
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 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, hotkeys: { [key in string]?: Array<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;
|
||||||
|
hotkeys: { [key in string]?: Array<string> };
|
||||||
|
};
|
||||||
|
|
||||||
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 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 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 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 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 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,
|
export type WebsocketRequest = {
|
||||||
/**
|
model: "websocket_request";
|
||||||
* URL parameters used for both path placeholders (`:id`) and query string entries.
|
id: string;
|
||||||
*/
|
createdAt: string;
|
||||||
urlParameters: Array<HttpUrlParameter>, };
|
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;
|
||||||
|
/**
|
||||||
|
* URL parameters used for both path placeholders (`:id`) and query string entries.
|
||||||
|
*/
|
||||||
|
urlParameters: Array<HttpUrlParameter>;
|
||||||
|
settingSendCookies: InheritedBoolSetting;
|
||||||
|
settingStoreCookies: InheritedBoolSetting;
|
||||||
|
};
|
||||||
|
|
||||||
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, settingDnsOverrides: Array<DnsOverride>, };
|
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;
|
||||||
|
settingDnsOverrides: Array<DnsOverride>;
|
||||||
|
settingSendCookies: boolean;
|
||||||
|
settingStoreCookies: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type WorkspaceMeta = { model: "workspace_meta", id: string, workspaceId: string, createdAt: string, updatedAt: string, encryptionKey: EncryptedKey | null, settingSyncDir: string | null, };
|
export type WorkspaceMeta = {
|
||||||
|
model: "workspace_meta";
|
||||||
|
id: string;
|
||||||
|
workspaceId: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
encryptionKey: EncryptedKey | null;
|
||||||
|
settingSyncDir: string | null;
|
||||||
|
};
|
||||||
|
|||||||
+61
-7
@@ -4,7 +4,7 @@ use log::warn;
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicI32, Ordering};
|
use std::sync::atomic::{AtomicI32, Ordering};
|
||||||
use std::time::Instant;
|
use std::time::{Duration, Instant};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::fs::File;
|
use tokio::fs::File;
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
@@ -26,6 +26,7 @@ use yaak_models::blob_manager::{BlobManager, BodyChunk};
|
|||||||
use yaak_models::models::{
|
use yaak_models::models::{
|
||||||
ClientCertificate, CookieJar, DnsOverride, Environment, HttpRequest, HttpResponse,
|
ClientCertificate, CookieJar, DnsOverride, Environment, HttpRequest, HttpResponse,
|
||||||
HttpResponseEvent, HttpResponseHeader, HttpResponseState, ProxySetting, ProxySettingAuth,
|
HttpResponseEvent, HttpResponseHeader, HttpResponseState, ProxySetting, ProxySettingAuth,
|
||||||
|
ResolvedSetting,
|
||||||
};
|
};
|
||||||
use yaak_models::query_manager::QueryManager;
|
use yaak_models::query_manager::QueryManager;
|
||||||
use yaak_models::util::{UpdateSource, generate_prefixed_id};
|
use yaak_models::util::{UpdateSource, generate_prefixed_id};
|
||||||
@@ -343,16 +344,16 @@ pub fn resolve_http_send_runtime_config(
|
|||||||
|
|
||||||
Ok(HttpSendRuntimeConfig {
|
Ok(HttpSendRuntimeConfig {
|
||||||
send_options: SendableHttpRequestOptions {
|
send_options: SendableHttpRequestOptions {
|
||||||
follow_redirects: resolved_settings.follow_redirects,
|
follow_redirects: resolved_settings.follow_redirects.value,
|
||||||
timeout: if resolved_settings.request_timeout > 0 {
|
timeout: if resolved_settings.request_timeout.value > 0 {
|
||||||
Some(std::time::Duration::from_millis(
|
Some(std::time::Duration::from_millis(
|
||||||
resolved_settings.request_timeout.unsigned_abs() as u64,
|
resolved_settings.request_timeout.value.unsigned_abs() as u64,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
validate_certificates: resolved_settings.validate_certificates,
|
validate_certificates: resolved_settings.validate_certificates.value,
|
||||||
proxy: proxy_setting_from_settings(settings.proxy),
|
proxy: proxy_setting_from_settings(settings.proxy),
|
||||||
dns_overrides: workspace.setting_dns_overrides,
|
dns_overrides: workspace.setting_dns_overrides,
|
||||||
client_certificates: settings.client_certificates,
|
client_certificates: settings.client_certificates,
|
||||||
@@ -486,8 +487,8 @@ pub async fn send_http_request<T: TemplateCallback>(
|
|||||||
cookie_jar.as_ref().map(|jar| CookieStore::from_cookies(jar.cookies.clone()));
|
cookie_jar.as_ref().map(|jar| CookieStore::from_cookies(jar.cookies.clone()));
|
||||||
let cookie_behavior = CookieBehavior {
|
let cookie_behavior = CookieBehavior {
|
||||||
store: cookie_store,
|
store: cookie_store,
|
||||||
send_cookies: resolved_settings.send_cookies,
|
send_cookies: resolved_settings.send_cookies.value,
|
||||||
store_cookies: resolved_settings.store_cookies,
|
store_cookies: resolved_settings.store_cookies.value,
|
||||||
};
|
};
|
||||||
|
|
||||||
let rendered_request = render_http_request(
|
let rendered_request = render_http_request(
|
||||||
@@ -614,6 +615,37 @@ pub async fn send_http_request<T: TemplateCallback>(
|
|||||||
let started_at = Instant::now();
|
let started_at = Instant::now();
|
||||||
let request_started_url = sendable_request.url.clone();
|
let request_started_url = sendable_request.url.clone();
|
||||||
|
|
||||||
|
send_setting_event(
|
||||||
|
&event_tx,
|
||||||
|
"validate_certificates",
|
||||||
|
runtime_config.validate_certificates.to_string(),
|
||||||
|
&resolved_settings.validate_certificates,
|
||||||
|
);
|
||||||
|
send_setting_event(
|
||||||
|
&event_tx,
|
||||||
|
"redirects",
|
||||||
|
sendable_request.options.follow_redirects.to_string(),
|
||||||
|
&resolved_settings.follow_redirects,
|
||||||
|
);
|
||||||
|
send_setting_event(
|
||||||
|
&event_tx,
|
||||||
|
"timeout",
|
||||||
|
timeout_setting_value(sendable_request.options.timeout),
|
||||||
|
&resolved_settings.request_timeout,
|
||||||
|
);
|
||||||
|
send_setting_event(
|
||||||
|
&event_tx,
|
||||||
|
"send_cookies",
|
||||||
|
cookie_behavior.send_cookies.to_string(),
|
||||||
|
&resolved_settings.send_cookies,
|
||||||
|
);
|
||||||
|
send_setting_event(
|
||||||
|
&event_tx,
|
||||||
|
"store_cookies",
|
||||||
|
cookie_behavior.store_cookies.to_string(),
|
||||||
|
&resolved_settings.store_cookies,
|
||||||
|
);
|
||||||
|
|
||||||
let mut http_response =
|
let mut http_response =
|
||||||
match executor.send(sendable_request, event_tx, cookie_behavior.clone()).await {
|
match executor.send(sendable_request, event_tx, cookie_behavior.clone()).await {
|
||||||
Ok(response) => response,
|
Ok(response) => response,
|
||||||
@@ -958,6 +990,28 @@ fn persist_cookie_jar(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn send_setting_event<T>(
|
||||||
|
event_tx: &mpsc::Sender<SenderHttpResponseEvent>,
|
||||||
|
name: impl Into<String>,
|
||||||
|
value: impl Into<String>,
|
||||||
|
setting: &ResolvedSetting<T>,
|
||||||
|
) {
|
||||||
|
let _ = event_tx.try_send(SenderHttpResponseEvent::Setting {
|
||||||
|
name: name.into(),
|
||||||
|
value: value.into(),
|
||||||
|
source_model: Some(setting.source_model.clone()),
|
||||||
|
source_id: setting.source_id.clone(),
|
||||||
|
source_name: setting.source_name.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timeout_setting_value(timeout: Option<Duration>) -> String {
|
||||||
|
match timeout {
|
||||||
|
Some(timeout) if !timeout.is_zero() => format!("{timeout:?}"),
|
||||||
|
_ => "Infinity".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn proxy_setting_from_settings(proxy: Option<ProxySetting>) -> HttpConnectionProxySetting {
|
fn proxy_setting_from_settings(proxy: Option<ProxySetting>) -> HttpConnectionProxySetting {
|
||||||
match proxy {
|
match proxy {
|
||||||
None => HttpConnectionProxySetting::System,
|
None => HttpConnectionProxySetting::System,
|
||||||
|
|||||||
+430
-56
@@ -1,108 +1,482 @@
|
|||||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
// 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 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 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 Cookie = {
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
domain: CookieDomain;
|
||||||
|
expires: CookieExpires;
|
||||||
|
path: string;
|
||||||
|
secure: boolean;
|
||||||
|
httpOnly: boolean;
|
||||||
|
sameSite: CookieSameSite | null;
|
||||||
|
};
|
||||||
|
|
||||||
export type CookieDomain = { "HostOnly": string } | { "Suffix": string } | "NotPresent" | "Empty";
|
export type CookieDomain = { HostOnly: string } | { Suffix: string } | "NotPresent" | "Empty";
|
||||||
|
|
||||||
export type CookieExpires = { "AtUtc": string } | "SessionEnd";
|
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 CookieJar = {
|
||||||
|
model: "cookie_jar";
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
workspaceId: string;
|
||||||
|
cookies: Array<Cookie>;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type DnsOverride = { hostname: string, ipv4: Array<string>, ipv6: Array<string>, enabled?: boolean, };
|
export type CookieSameSite = "Strict" | "Lax" | "None";
|
||||||
|
|
||||||
|
export type DnsOverride = {
|
||||||
|
hostname: string;
|
||||||
|
ipv4: Array<string>;
|
||||||
|
ipv6: Array<string>;
|
||||||
|
enabled?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type EditorKeymap = "default" | "vim" | "vscode" | "emacs";
|
export type EditorKeymap = "default" | "vim" | "vscode" | "emacs";
|
||||||
|
|
||||||
export type EncryptedKey = { encryptedKey: string, };
|
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,
|
export type Environment = {
|
||||||
/**
|
model: "environment";
|
||||||
* Variables defined in this environment scope.
|
id: string;
|
||||||
* Child environments override parent variables by name.
|
workspaceId: string;
|
||||||
*/
|
createdAt: string;
|
||||||
variables: Array<EnvironmentVariable>, color: string | null, sortPriority: number, };
|
updatedAt: string;
|
||||||
|
name: string;
|
||||||
|
public: boolean;
|
||||||
|
parentModel: string;
|
||||||
|
parentId: string | null;
|
||||||
|
/**
|
||||||
|
* Variables defined in this environment scope.
|
||||||
|
* Child environments override parent variables by name.
|
||||||
|
*/
|
||||||
|
variables: Array<EnvironmentVariable>;
|
||||||
|
color: string | null;
|
||||||
|
sortPriority: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type EnvironmentVariable = { enabled?: boolean, name: string, value: string, id?: string, };
|
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 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;
|
||||||
|
settingSendCookies: InheritedBoolSetting;
|
||||||
|
settingStoreCookies: InheritedBoolSetting;
|
||||||
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
|
settingFollowRedirects: InheritedBoolSetting;
|
||||||
|
settingRequestTimeout: InheritedIntSetting;
|
||||||
|
};
|
||||||
|
|
||||||
export type GraphQlIntrospection = { model: "graphql_introspection", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, content: string | null, };
|
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 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 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 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 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,
|
export type GrpcRequest = {
|
||||||
/**
|
model: "grpc_request";
|
||||||
* Server URL (http for plaintext or https for secure)
|
id: string;
|
||||||
*/
|
createdAt: string;
|
||||||
url: 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;
|
||||||
|
/**
|
||||||
|
* Server URL (http for plaintext or https for secure)
|
||||||
|
*/
|
||||||
|
url: string;
|
||||||
|
settingSendCookies: InheritedBoolSetting;
|
||||||
|
settingStoreCookies: InheritedBoolSetting;
|
||||||
|
};
|
||||||
|
|
||||||
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,
|
export type HttpRequest = {
|
||||||
/**
|
model: "http_request";
|
||||||
* URL parameters used for both path placeholders (`:id`) and query string entries.
|
id: string;
|
||||||
*/
|
createdAt: string;
|
||||||
urlParameters: Array<HttpUrlParameter>, };
|
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;
|
||||||
|
/**
|
||||||
|
* URL parameters used for both path placeholders (`:id`) and query string entries.
|
||||||
|
*/
|
||||||
|
urlParameters: Array<HttpUrlParameter>;
|
||||||
|
settingSendCookies: InheritedBoolSetting;
|
||||||
|
settingStoreCookies: InheritedBoolSetting;
|
||||||
|
settingValidateCertificates: InheritedBoolSetting;
|
||||||
|
settingFollowRedirects: InheritedBoolSetting;
|
||||||
|
settingRequestTimeout: InheritedIntSetting;
|
||||||
|
};
|
||||||
|
|
||||||
export type HttpRequestHeader = { enabled?: boolean, name: string, value: string, id?: string, };
|
export type HttpRequestHeader = { enabled?: boolean; name: string; value: string; id?: 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, elapsedDns: 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 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;
|
||||||
|
elapsedDns: 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, };
|
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.
|
* Serializable representation of HTTP response events for DB storage.
|
||||||
* This mirrors `yaak_http::sender::HttpResponseEvent` but with serde support.
|
* This mirrors `yaak_http::sender::HttpResponseEvent` but with serde support.
|
||||||
* The `From` impl is in yaak-http to avoid circular dependencies.
|
* 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, dropped_body: boolean, dropped_headers: Array<string>, } | { "type": "send_url", method: string, scheme: string, username: string, password: string, host: string, port: number, path: string, query: string, fragment: 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, } | { "type": "dns_resolved", hostname: string, addresses: Array<string>, duration: bigint, overridden: boolean, };
|
export type HttpResponseEventData =
|
||||||
|
| {
|
||||||
|
type: "setting";
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
source_model?: string;
|
||||||
|
source_id?: string;
|
||||||
|
source_name?: string;
|
||||||
|
}
|
||||||
|
| { type: "info"; message: string }
|
||||||
|
| {
|
||||||
|
type: "redirect";
|
||||||
|
url: string;
|
||||||
|
status: number;
|
||||||
|
behavior: string;
|
||||||
|
dropped_body: boolean;
|
||||||
|
dropped_headers: Array<string>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "send_url";
|
||||||
|
method: string;
|
||||||
|
scheme: string;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
path: string;
|
||||||
|
query: string;
|
||||||
|
fragment: 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 }
|
||||||
|
| {
|
||||||
|
type: "dns_resolved";
|
||||||
|
hostname: string;
|
||||||
|
addresses: Array<string>;
|
||||||
|
duration: bigint;
|
||||||
|
overridden: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type HttpResponseHeader = { name: string, value: string, };
|
export type HttpResponseHeader = { name: string; value: string };
|
||||||
|
|
||||||
export type HttpResponseState = "initialized" | "connected" | "closed";
|
export type HttpResponseState = "initialized" | "connected" | "closed";
|
||||||
|
|
||||||
export type HttpUrlParameter = { enabled?: boolean,
|
export type HttpUrlParameter = {
|
||||||
/**
|
enabled?: boolean;
|
||||||
* Colon-prefixed parameters are treated as path parameters if they match, like `/users/:id`
|
/**
|
||||||
* Other entries are appended as query parameters
|
* Colon-prefixed parameters are treated as path parameters if they match, like `/users/:id`
|
||||||
*/
|
* Other entries are appended as query parameters
|
||||||
name: string, value: string, id?: string, };
|
*/
|
||||||
|
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 InheritedBoolSetting = { enabled?: boolean; value: boolean };
|
||||||
|
|
||||||
export type Plugin = { model: "plugin", id: string, createdAt: string, updatedAt: string, checkedAt: string | null, directory: string, enabled: boolean, url: string | null, source: PluginSource, };
|
export type InheritedIntSetting = { enabled?: boolean; value: number };
|
||||||
|
|
||||||
|
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;
|
||||||
|
source: PluginSource;
|
||||||
|
};
|
||||||
|
|
||||||
export type PluginSource = "bundled" | "filesystem" | "registry";
|
export type PluginSource = "bundled" | "filesystem" | "registry";
|
||||||
|
|
||||||
export type ProxySetting = { "type": "enabled", http: string, https: string, auth: ProxySettingAuth | null, bypass: string, disabled: boolean, } | { "type": "disabled" };
|
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 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, hotkeys: { [key in string]?: Array<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;
|
||||||
|
hotkeys: { [key in string]?: Array<string> };
|
||||||
|
};
|
||||||
|
|
||||||
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 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 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 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 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 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,
|
export type WebsocketRequest = {
|
||||||
/**
|
model: "websocket_request";
|
||||||
* URL parameters used for both path placeholders (`:id`) and query string entries.
|
id: string;
|
||||||
*/
|
createdAt: string;
|
||||||
urlParameters: Array<HttpUrlParameter>, };
|
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;
|
||||||
|
/**
|
||||||
|
* URL parameters used for both path placeholders (`:id`) and query string entries.
|
||||||
|
*/
|
||||||
|
urlParameters: Array<HttpUrlParameter>;
|
||||||
|
settingSendCookies: InheritedBoolSetting;
|
||||||
|
settingStoreCookies: InheritedBoolSetting;
|
||||||
|
};
|
||||||
|
|
||||||
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, settingDnsOverrides: Array<DnsOverride>, };
|
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;
|
||||||
|
settingDnsOverrides: Array<DnsOverride>;
|
||||||
|
settingSendCookies: boolean;
|
||||||
|
settingStoreCookies: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type WorkspaceMeta = { model: "workspace_meta", id: string, workspaceId: string, createdAt: string, updatedAt: string, encryptionKey: EncryptedKey | null, settingSyncDir: string | null, };
|
export type WorkspaceMeta = {
|
||||||
|
model: "workspace_meta";
|
||||||
|
id: string;
|
||||||
|
workspaceId: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
encryptionKey: EncryptedKey | null;
|
||||||
|
settingSyncDir: string | null;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user