feat: migrate repository and workdir domains to ServerApi
This commit is contained in:
Generated
+2
@@ -1447,6 +1447,7 @@ dependencies = [
|
|||||||
"grep-searcher",
|
"grep-searcher",
|
||||||
"ignore",
|
"ignore",
|
||||||
"libc",
|
"libc",
|
||||||
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2 0.10.9",
|
"sha2 0.10.9",
|
||||||
@@ -6104,6 +6105,7 @@ dependencies = [
|
|||||||
"fs-operation",
|
"fs-operation",
|
||||||
"manifest",
|
"manifest",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2 0.11.0",
|
"sha2 0.11.0",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ grep-regex = "0.1.14"
|
|||||||
grep-searcher = "0.1.16"
|
grep-searcher = "0.1.16"
|
||||||
ignore = "0.4.25"
|
ignore = "0.4.25"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
schemars.workspace = true
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
sha2 = "0.10.9"
|
sha2 = "0.10.9"
|
||||||
tempfile.workspace = true
|
tempfile.workspace = true
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::path::{Component, Path, PathBuf};
|
use std::path::{Component, Path, PathBuf};
|
||||||
|
|
||||||
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::FsError;
|
use crate::FsError;
|
||||||
@@ -11,9 +12,11 @@ use crate::FsError;
|
|||||||
/// while computing line and content metadata. `max_response_bytes` limits the
|
/// while computing line and content metadata. `max_response_bytes` limits the
|
||||||
/// bytes retained for the response independently of the caller's requested
|
/// bytes retained for the response independently of the caller's requested
|
||||||
/// `ReadRequest::max_bytes`.
|
/// `ReadRequest::max_bytes`.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, JsonSchema)]
|
||||||
pub struct BoundedReadLimits {
|
pub struct BoundedReadLimits {
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub max_source_bytes: u64,
|
pub max_source_bytes: u64,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub max_response_bytes: usize,
|
pub max_response_bytes: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +75,7 @@ impl<'de> Deserialize<'de> for BoundedReadLimits {
|
|||||||
|
|
||||||
/// Scope-checked filesystem path. Relative paths resolve below the bound
|
/// Scope-checked filesystem path. Relative paths resolve below the bound
|
||||||
/// Workdir root; absolute paths require an explicit matching scope rule.
|
/// Workdir root; absolute paths require an explicit matching scope rule.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, JsonSchema)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct FsPath(String);
|
pub struct FsPath(String);
|
||||||
|
|
||||||
@@ -153,21 +156,22 @@ impl fmt::Display for FsPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct StatRequest {
|
pub struct StatRequest {
|
||||||
pub path: FsPath,
|
pub path: FsPath,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct StatResult {
|
pub struct StatResult {
|
||||||
pub path: FsPath,
|
pub path: FsPath,
|
||||||
pub kind: EntryKind,
|
pub kind: EntryKind,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub size: u64,
|
pub size: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum EntryKind {
|
pub enum EntryKind {
|
||||||
File,
|
File,
|
||||||
@@ -178,27 +182,32 @@ pub enum EntryKind {
|
|||||||
|
|
||||||
pub type ContentHash = [u8; 32];
|
pub type ContentHash = [u8; 32];
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct ReadRequest {
|
pub struct ReadRequest {
|
||||||
pub path: FsPath,
|
pub path: FsPath,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub offset: usize,
|
pub offset: usize,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub limit: usize,
|
pub limit: usize,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub max_bytes: usize,
|
pub max_bytes: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct ReadResult {
|
pub struct ReadResult {
|
||||||
pub path: FsPath,
|
pub path: FsPath,
|
||||||
pub bytes: Vec<u8>,
|
pub bytes: Vec<u8>,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub start_line: usize,
|
pub start_line: usize,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub total_lines: usize,
|
pub total_lines: usize,
|
||||||
pub content_hash: ContentHash,
|
pub content_hash: ContentHash,
|
||||||
pub truncated: bool,
|
pub truncated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WriteRequest {
|
pub struct WriteRequest {
|
||||||
pub path: FsPath,
|
pub path: FsPath,
|
||||||
@@ -206,13 +215,14 @@ pub struct WriteRequest {
|
|||||||
pub expected_hash: Option<ContentHash>,
|
pub expected_hash: Option<ContentHash>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct WriteResult {
|
pub struct WriteResult {
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub bytes_written: usize,
|
pub bytes_written: usize,
|
||||||
pub created: bool,
|
pub created: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct EditRequest {
|
pub struct EditRequest {
|
||||||
pub path: FsPath,
|
pub path: FsPath,
|
||||||
@@ -222,54 +232,61 @@ pub struct EditRequest {
|
|||||||
pub expected_hash: ContentHash,
|
pub expected_hash: ContentHash,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct EditResult {
|
pub struct EditResult {
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub replacements: usize,
|
pub replacements: usize,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub bytes_written: usize,
|
pub bytes_written: usize,
|
||||||
pub content_hash: ContentHash,
|
pub content_hash: ContentHash,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct ListRequest {
|
pub struct ListRequest {
|
||||||
pub path: FsPath,
|
pub path: FsPath,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub limit: usize,
|
pub limit: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct ListEntry {
|
pub struct ListEntry {
|
||||||
pub path: FsPath,
|
pub path: FsPath,
|
||||||
pub kind: EntryKind,
|
pub kind: EntryKind,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub size: u64,
|
pub size: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct ListResult {
|
pub struct ListResult {
|
||||||
pub entries: Vec<ListEntry>,
|
pub entries: Vec<ListEntry>,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub total_entries: usize,
|
pub total_entries: usize,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub total_bytes: u64,
|
pub total_bytes: u64,
|
||||||
pub truncated: bool,
|
pub truncated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct GlobRequest {
|
pub struct GlobRequest {
|
||||||
pub pattern: String,
|
pub pattern: String,
|
||||||
pub path: FsPath,
|
pub path: FsPath,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub limit: usize,
|
pub limit: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct GlobResult {
|
pub struct GlobResult {
|
||||||
pub paths: Vec<FsPath>,
|
pub paths: Vec<FsPath>,
|
||||||
pub truncated: bool,
|
pub truncated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum GrepOutputMode {
|
pub enum GrepOutputMode {
|
||||||
Content,
|
Content,
|
||||||
@@ -283,7 +300,7 @@ impl Default for GrepOutputMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct GrepRequest {
|
pub struct GrepRequest {
|
||||||
pub pattern: String,
|
pub pattern: String,
|
||||||
@@ -291,21 +308,27 @@ pub struct GrepRequest {
|
|||||||
pub glob: Option<String>,
|
pub glob: Option<String>,
|
||||||
pub file_type: Option<String>,
|
pub file_type: Option<String>,
|
||||||
pub case_insensitive: bool,
|
pub case_insensitive: bool,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub before_context: usize,
|
pub before_context: usize,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub after_context: usize,
|
pub after_context: usize,
|
||||||
pub multiline: bool,
|
pub multiline: bool,
|
||||||
pub output_mode: GrepOutputMode,
|
pub output_mode: GrepOutputMode,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub limit: usize,
|
pub limit: usize,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub offset: usize,
|
pub offset: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct GrepResult {
|
pub struct GrepResult {
|
||||||
/// Provider-rendered bounded grep report. Keeping rendering here avoids
|
/// Provider-rendered bounded grep report. Keeping rendering here avoids
|
||||||
/// transferring candidate files across a remote provider boundary.
|
/// transferring candidate files across a remote provider boundary.
|
||||||
pub output: String,
|
pub output: String,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub match_count: usize,
|
pub match_count: usize,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub matched_files: usize,
|
pub matched_files: usize,
|
||||||
pub truncated: bool,
|
pub truncated: bool,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ required-features = ["typescript"]
|
|||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "generate_workdir_api_types"
|
name = "generate_workdir_api_types"
|
||||||
required-features = ["typescript"]
|
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "generate_worker_launch_api_types"
|
name = "generate_worker_launch_api_types"
|
||||||
|
|||||||
@@ -1,6 +1,59 @@
|
|||||||
|
use std::fs;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use server_api::repository_openapi_typescript::{
|
||||||
|
INPUT_PATH, WORKDIR_OUTPUT_PATH, generate_workdir_typescript,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
print!(
|
if let Err(error) = run() {
|
||||||
"{}",
|
eprintln!("{error}");
|
||||||
server_api::normalized_typescript(server_api::workdir_api_typescript())
|
std::process::exit(1);
|
||||||
);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run() -> Result<(), String> {
|
||||||
|
let mut check = false;
|
||||||
|
for argument in std::env::args().skip(1) {
|
||||||
|
match argument.as_str() {
|
||||||
|
"--check" => check = true,
|
||||||
|
"--help" | "-h" => {
|
||||||
|
println!(
|
||||||
|
"Generate the bounded Workdir API TypeScript artifact.\n\n\
|
||||||
|
Usage: cargo run -q -p server-api --example generate_workdir_api_types -- [--check]"
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
other => return Err(format!("unknown argument `{other}`")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
|
||||||
|
let input_path = root.join(INPUT_PATH);
|
||||||
|
let output_path = root.join(WORKDIR_OUTPUT_PATH);
|
||||||
|
let input = fs::read_to_string(&input_path)
|
||||||
|
.map_err(|error| format!("failed to read {}: {error}", input_path.display()))?;
|
||||||
|
let generated = generate_workdir_typescript(&input)
|
||||||
|
.map_err(|error| format!("failed to generate Workdir API types: {error}"))?;
|
||||||
|
|
||||||
|
if check {
|
||||||
|
let checked_in = fs::read_to_string(&output_path)
|
||||||
|
.map_err(|error| format!("failed to read {}: {error}", output_path.display()))?;
|
||||||
|
if checked_in != generated {
|
||||||
|
return Err(format!(
|
||||||
|
"{} is stale; regenerate it without --check",
|
||||||
|
output_path.display()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
println!("{} is current", output_path.display());
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let temporary_path = output_path.with_extension("ts.tmp");
|
||||||
|
fs::write(&temporary_path, generated)
|
||||||
|
.map_err(|error| format!("failed to write {}: {error}", temporary_path.display()))?;
|
||||||
|
fs::rename(&temporary_path, &output_path)
|
||||||
|
.map_err(|error| format!("failed to replace {}: {error}", output_path.display()))?;
|
||||||
|
println!("generated {}", output_path.display());
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+528
-29
@@ -77,6 +77,64 @@ impl api_macros::HttpRequestError for RepositoryApiError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Error body for current-Worker Workdir operations.
|
||||||
|
///
|
||||||
|
/// Domain/service failures preserve the existing Repository-style API envelope,
|
||||||
|
/// while provider failures preserve the established typed Workdir transport
|
||||||
|
/// envelope and HTTP status classification.
|
||||||
|
#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct WorkdirOperationApiError {
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub error: Option<String>,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub code: Option<workdir::http::WorkdirTransportErrorCode>,
|
||||||
|
pub message: String,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub diagnostics: Option<Vec<Diagnostic>>,
|
||||||
|
#[serde(skip, default = "default_repository_error_status")]
|
||||||
|
status: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WorkdirOperationApiError {
|
||||||
|
pub fn api(error: RepositoryApiError) -> Self {
|
||||||
|
Self {
|
||||||
|
error: Some(error.error),
|
||||||
|
code: None,
|
||||||
|
message: error.message,
|
||||||
|
diagnostics: Some(error.diagnostics),
|
||||||
|
status: error.status,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn provider(error: workdir::http::WorkdirTransportError) -> Self {
|
||||||
|
let status = error.code.http_status();
|
||||||
|
Self {
|
||||||
|
error: None,
|
||||||
|
code: Some(error.code),
|
||||||
|
message: error.message,
|
||||||
|
diagnostics: None,
|
||||||
|
status,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl api_macros::HttpError for WorkdirOperationApiError {
|
||||||
|
fn status_code(&self) -> u16 {
|
||||||
|
self.code.map_or(self.status, |code| code.http_status())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl api_macros::HttpRequestError for WorkdirOperationApiError {
|
||||||
|
fn from_request_rejection(status: u16, message: String) -> Self {
|
||||||
|
Self::api(
|
||||||
|
<RepositoryApiError as api_macros::HttpRequestError>::from_request_rejection(
|
||||||
|
status, message,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! impl_openapi_schema {
|
macro_rules! impl_openapi_schema {
|
||||||
($($ty:ty),+ $(,)?) => {
|
($($ty:ty),+ $(,)?) => {
|
||||||
$(impl api_macros::openapi::OpenApiSchema for $ty {})+
|
$(impl api_macros::openapi::OpenApiSchema for $ty {})+
|
||||||
@@ -109,8 +167,29 @@ impl_openapi_schema!(
|
|||||||
CreateWorkspaceRepositoryRequest,
|
CreateWorkspaceRepositoryRequest,
|
||||||
CreateWorkspaceRepositoryResponse,
|
CreateWorkspaceRepositoryResponse,
|
||||||
RepositoryApiError,
|
RepositoryApiError,
|
||||||
|
WorkdirOperationApiError,
|
||||||
RepositoryListResponse,
|
RepositoryListResponse,
|
||||||
RepositoryDetailResponse,
|
RepositoryDetailResponse,
|
||||||
|
RepositorySshConnectionProbeRequest,
|
||||||
|
RepositorySshConnectionProbeResponse,
|
||||||
|
ConfirmRepositorySshHostTrustRequest,
|
||||||
|
RepositoryLogQuery,
|
||||||
|
RepositoryLogResponse,
|
||||||
|
HostListResponse,
|
||||||
|
HostWorkerListResponse,
|
||||||
|
HostSummary,
|
||||||
|
WorkingDirectoryRemovalRequest,
|
||||||
|
WorkingDirectoryRemovalResponse,
|
||||||
|
WorkingDirectoryCreateRequest,
|
||||||
|
WorkingDirectoryListResponse,
|
||||||
|
WorkingDirectoryDetailResponse,
|
||||||
|
WorkingDirectoryCreateResponse,
|
||||||
|
CurrentWorkerWorkdirAttachRequest,
|
||||||
|
CurrentWorkerWorkdirAttachmentResponse,
|
||||||
|
CurrentWorkerWorkdirOperationRequest,
|
||||||
|
CurrentWorkerWorkdirOperationResponse,
|
||||||
|
ExternalWorkdirGrantCreateRequest,
|
||||||
|
ExternalWorkdirGrantResponse,
|
||||||
WorkspaceResponse,
|
WorkspaceResponse,
|
||||||
WorkspaceMetadataSettingsResponse,
|
WorkspaceMetadataSettingsResponse,
|
||||||
UpdateWorkspaceMetadataRequest,
|
UpdateWorkspaceMetadataRequest,
|
||||||
@@ -980,6 +1059,324 @@ pub trait ServerApi {
|
|||||||
#[body] request: CreateWorkspaceRepositoryRequest,
|
#[body] request: CreateWorkspaceRepositoryRequest,
|
||||||
) -> Result<CreateWorkspaceRepositoryResponse, RepositoryApiError>;
|
) -> Result<CreateWorkspaceRepositoryResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[post(
|
||||||
|
"/api/w/{workspace_id}/repositories/{repository_key}/ssh-connection-test",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 409, 500, 502, 503],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn repository_ssh_connection_probe(
|
||||||
|
&self,
|
||||||
|
#[extension] actor: RequestActor,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[path] repository_key: String,
|
||||||
|
#[body] request: RepositorySshConnectionProbeRequest,
|
||||||
|
) -> Result<RepositorySshConnectionProbeResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[put(
|
||||||
|
"/api/w/{workspace_id}/repositories/{repository_key}/ssh-connection-test",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 409, 500, 502, 503],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn repository_ssh_host_trust_confirm(
|
||||||
|
&self,
|
||||||
|
#[extension] actor: RequestActor,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[path] repository_key: String,
|
||||||
|
#[body] request: ConfirmRepositorySshHostTrustRequest,
|
||||||
|
) -> Result<RepositorySshHostTrust, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[get(
|
||||||
|
"/api/w/{workspace_id}/repositories/{repository_key}/log",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 500],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn repository_log(
|
||||||
|
&self,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[path] repository_key: String,
|
||||||
|
#[query] query: RepositoryLogQuery,
|
||||||
|
) -> Result<RepositoryLogResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[get(
|
||||||
|
"/api/repositories/{repository_key}/log",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 500],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn repository_log_alias(
|
||||||
|
&self,
|
||||||
|
#[path] repository_key: String,
|
||||||
|
#[query] query: RepositoryLogQuery,
|
||||||
|
) -> Result<RepositoryLogResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[get(
|
||||||
|
"/api/w/{workspace_id}/hosts",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 500],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn host_list(
|
||||||
|
&self,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
) -> Result<HostListResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[get(
|
||||||
|
"/api/hosts",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 500],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn host_list_alias(&self) -> Result<HostListResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[get(
|
||||||
|
"/api/w/{workspace_id}/hosts/{host_id}/workers",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 500, 502, 503],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn host_worker_list(
|
||||||
|
&self,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[path] host_id: String,
|
||||||
|
) -> Result<HostWorkerListResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[get(
|
||||||
|
"/api/hosts/{host_id}/workers",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 500, 502, 503],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn host_worker_list_alias(
|
||||||
|
&self,
|
||||||
|
#[path] host_id: String,
|
||||||
|
) -> Result<HostWorkerListResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[get(
|
||||||
|
"/api/w/{workspace_id}/runtimes/{runtime_id}/working-directories",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 500, 502, 503],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn runtime_workdir_list(
|
||||||
|
&self,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[path] runtime_id: String,
|
||||||
|
) -> Result<WorkingDirectoryListResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[post(
|
||||||
|
"/api/w/{workspace_id}/runtimes/{runtime_id}/working-directories",
|
||||||
|
status = 201,
|
||||||
|
alternate_status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 409, 500, 502, 503],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn runtime_workdir_create(
|
||||||
|
&self,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[path] runtime_id: String,
|
||||||
|
#[body] request: WorkingDirectoryCreateRequest,
|
||||||
|
) -> Result<WorkingDirectoryCreateResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[get(
|
||||||
|
"/api/w/{workspace_id}/runtimes/{runtime_id}/working-directories/{working_directory_id}",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 500, 502, 503],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn runtime_workdir_detail(
|
||||||
|
&self,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[path] runtime_id: String,
|
||||||
|
#[path] working_directory_id: String,
|
||||||
|
) -> Result<WorkingDirectoryDetailResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[delete(
|
||||||
|
"/api/w/{workspace_id}/runtimes/{runtime_id}/working-directories/{working_directory_id}",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 409, 500, 502, 503],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn runtime_workdir_cleanup(
|
||||||
|
&self,
|
||||||
|
#[extension] context: ServerRequestContext,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[path] runtime_id: String,
|
||||||
|
#[path] working_directory_id: String,
|
||||||
|
#[body] request: WorkingDirectoryRemovalRequest,
|
||||||
|
) -> Result<WorkingDirectoryRemovalResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[post(
|
||||||
|
"/api/w/{workspace_id}/workers/self/workdir-attachments",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 409, 500, 502, 503],
|
||||||
|
bearer_auth = true
|
||||||
|
)]
|
||||||
|
async fn current_worker_workdir_attach(
|
||||||
|
&self,
|
||||||
|
#[extension] context: ServerRequestContext,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[body] request: CurrentWorkerWorkdirAttachRequest,
|
||||||
|
) -> Result<CurrentWorkerWorkdirAttachmentResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[delete(
|
||||||
|
"/api/w/{workspace_id}/workers/self/workdir-attachments/{alias}",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 409, 500, 502, 503],
|
||||||
|
bearer_auth = true
|
||||||
|
)]
|
||||||
|
async fn current_worker_workdir_detach(
|
||||||
|
&self,
|
||||||
|
#[extension] context: ServerRequestContext,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[path] alias: String,
|
||||||
|
) -> Result<CurrentWorkerWorkdirAttachmentResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[post(
|
||||||
|
"/api/w/{workspace_id}/workers/self/workdir-session/operations",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 409, 500, 502, 503],
|
||||||
|
bearer_auth = true
|
||||||
|
)]
|
||||||
|
async fn current_worker_workdir_operation(
|
||||||
|
&self,
|
||||||
|
#[extension] context: ServerRequestContext,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[body] request: CurrentWorkerWorkdirOperationRequest,
|
||||||
|
) -> Result<CurrentWorkerWorkdirOperationResponse, WorkdirOperationApiError>;
|
||||||
|
|
||||||
|
#[post(
|
||||||
|
"/api/w/{workspace_id}/external-workdir-grants",
|
||||||
|
status = 201,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 409, 500],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn external_workdir_grant_create(
|
||||||
|
&self,
|
||||||
|
#[extension] actor: RequestActor,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[body] request: ExternalWorkdirGrantCreateRequest,
|
||||||
|
) -> Result<ExternalWorkdirGrantResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[get(
|
||||||
|
"/api/w/{workspace_id}/external-workdir-grants/{grant_id}",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 500],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn external_workdir_grant_get(
|
||||||
|
&self,
|
||||||
|
#[extension] actor: RequestActor,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[path] grant_id: String,
|
||||||
|
) -> Result<ExternalWorkdirGrantResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[delete(
|
||||||
|
"/api/w/{workspace_id}/external-workdir-grants/{grant_id}",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 409, 500],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn external_workdir_grant_revoke(
|
||||||
|
&self,
|
||||||
|
#[extension] actor: RequestActor,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[path] grant_id: String,
|
||||||
|
) -> Result<ExternalWorkdirGrantResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[get(
|
||||||
|
"/api/w/{workspace_id}/working-directories",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 500, 502, 503],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn workspace_workdir_list(
|
||||||
|
&self,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
) -> Result<WorkingDirectoryListResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[post(
|
||||||
|
"/api/w/{workspace_id}/working-directories",
|
||||||
|
status = 201,
|
||||||
|
alternate_status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 409, 500, 502, 503],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn workspace_workdir_create(
|
||||||
|
&self,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[body] request: WorkingDirectoryCreateRequest,
|
||||||
|
) -> Result<WorkingDirectoryCreateResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[get(
|
||||||
|
"/api/w/{workspace_id}/working-directories/{working_directory_id}",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 500, 502, 503],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn workspace_workdir_detail(
|
||||||
|
&self,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[path] working_directory_id: String,
|
||||||
|
) -> Result<WorkingDirectoryDetailResponse, RepositoryApiError>;
|
||||||
|
|
||||||
|
#[delete(
|
||||||
|
"/api/w/{workspace_id}/working-directories/{working_directory_id}",
|
||||||
|
status = 200,
|
||||||
|
error_status = 400,
|
||||||
|
additional_error_statuses = [401, 403, 404, 409, 500, 502, 503],
|
||||||
|
bearer_auth = true,
|
||||||
|
browser_auth = true
|
||||||
|
)]
|
||||||
|
async fn workspace_workdir_cleanup(
|
||||||
|
&self,
|
||||||
|
#[extension] context: ServerRequestContext,
|
||||||
|
#[path] workspace_id: String,
|
||||||
|
#[path] working_directory_id: String,
|
||||||
|
#[body] request: WorkingDirectoryRemovalRequest,
|
||||||
|
) -> Result<WorkingDirectoryRemovalResponse, RepositoryApiError>;
|
||||||
|
|
||||||
#[get("/api/tickets", status = 200, error_status = 400, additional_error_statuses = [500])]
|
#[get("/api/tickets", status = 200, error_status = 400, additional_error_statuses = [500])]
|
||||||
async fn ticket_list_alias(
|
async fn ticket_list_alias(
|
||||||
&self,
|
&self,
|
||||||
@@ -1488,9 +1885,16 @@ pub fn canonical_openapi_document()
|
|||||||
///
|
///
|
||||||
/// Generated clients and OpenAPI omit extension parameters; operation implementations use this
|
/// Generated clients and OpenAPI omit extension parameters; operation implementations use this
|
||||||
/// value instead of re-parsing transport headers inside domain handlers.
|
/// value instead of re-parsing transport headers inside domain handlers.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct ServerWorkerSource {
|
||||||
|
pub runtime_id: String,
|
||||||
|
pub worker_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ServerRequestContext {
|
pub struct ServerRequestContext {
|
||||||
pub actor: Option<RequestActor>,
|
pub actor: Option<RequestActor>,
|
||||||
|
pub worker_source: Option<ServerWorkerSource>,
|
||||||
pub origin: Option<String>,
|
pub origin: Option<String>,
|
||||||
/// Transport headers retained for Server-side authentication adapters.
|
/// Transport headers retained for Server-side authentication adapters.
|
||||||
///
|
///
|
||||||
@@ -2991,7 +3395,7 @@ pub struct RepositorySummary {
|
|||||||
pub diagnostics: Option<Vec<RepositoryDiagnostic>>,
|
pub diagnostics: Option<Vec<RepositoryDiagnostic>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct GitCommitSummary {
|
pub struct GitCommitSummary {
|
||||||
@@ -3024,14 +3428,14 @@ pub struct RepositoryDetailResponse {
|
|||||||
pub source: String,
|
pub source: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct RepositorySshConnectionProbeRequest {
|
pub struct RepositorySshConnectionProbeRequest {
|
||||||
pub runtime_id: String,
|
pub runtime_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct RepositorySshHostKeyCandidate {
|
pub struct RepositorySshHostKeyCandidate {
|
||||||
@@ -3040,7 +3444,7 @@ pub struct RepositorySshHostKeyCandidate {
|
|||||||
pub fingerprint: String,
|
pub fingerprint: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum RepositorySshConnectionTrustState {
|
pub enum RepositorySshConnectionTrustState {
|
||||||
@@ -3049,7 +3453,7 @@ pub enum RepositorySshConnectionTrustState {
|
|||||||
Changed,
|
Changed,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct RepositorySshConnectionProbeResponse {
|
pub struct RepositorySshConnectionProbeResponse {
|
||||||
@@ -3061,11 +3465,12 @@ pub struct RepositorySshConnectionProbeResponse {
|
|||||||
pub trust_state: RepositorySshConnectionTrustState,
|
pub trust_state: RepositorySshConnectionTrustState,
|
||||||
pub host_trust_id: String,
|
pub host_trust_id: String,
|
||||||
#[cfg_attr(feature = "typescript", ts(type = "number | null"))]
|
#[cfg_attr(feature = "typescript", ts(type = "number | null"))]
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub expected_host_trust_revision: Option<u64>,
|
pub expected_host_trust_revision: Option<u64>,
|
||||||
pub candidates: Vec<RepositorySshHostKeyCandidate>,
|
pub candidates: Vec<RepositorySshHostKeyCandidate>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct ConfirmRepositorySshHostTrustRequest {
|
pub struct ConfirmRepositorySshHostTrustRequest {
|
||||||
@@ -3073,10 +3478,19 @@ pub struct ConfirmRepositorySshHostTrustRequest {
|
|||||||
pub runtime_id: String,
|
pub runtime_id: String,
|
||||||
pub host_key: String,
|
pub host_key: String,
|
||||||
#[cfg_attr(feature = "typescript", ts(type = "number | null"))]
|
#[cfg_attr(feature = "typescript", ts(type = "number | null"))]
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub expected_host_trust_revision: Option<u64>,
|
pub expected_host_trust_revision: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct RepositoryLogQuery {
|
||||||
|
#[serde(default)]
|
||||||
|
#[schemars(range(min = 1, max = 200))]
|
||||||
|
pub limit: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct RepositoryLogResponse {
|
pub struct RepositoryLogResponse {
|
||||||
@@ -3085,6 +3499,7 @@ pub struct RepositoryLogResponse {
|
|||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
#[cfg_attr(feature = "typescript", ts(optional = nullable))]
|
#[cfg_attr(feature = "typescript", ts(optional = nullable))]
|
||||||
pub default_selector: Option<String>,
|
pub default_selector: Option<String>,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub limit: usize,
|
pub limit: usize,
|
||||||
pub items: Vec<GitCommitSummary>,
|
pub items: Vec<GitCommitSummary>,
|
||||||
pub diagnostics: Vec<Diagnostic>,
|
pub diagnostics: Vec<Diagnostic>,
|
||||||
@@ -3115,7 +3530,7 @@ pub struct Diagnostic {
|
|||||||
///
|
///
|
||||||
/// The value identifies stable materialization provenance without exposing a
|
/// The value identifies stable materialization provenance without exposing a
|
||||||
/// provider path, Runtime handle, or session identity.
|
/// provider path, Runtime handle, or session identity.
|
||||||
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum WorkingDirectoryMaterializerKind {
|
pub enum WorkingDirectoryMaterializerKind {
|
||||||
@@ -3124,7 +3539,7 @@ pub enum WorkingDirectoryMaterializerKind {
|
|||||||
ClientHostedExternal,
|
ClientHostedExternal,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum WorkingDirectoryStatusKind {
|
pub enum WorkingDirectoryStatusKind {
|
||||||
@@ -3153,7 +3568,7 @@ impl std::fmt::Display for WorkingDirectoryStatusKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkingDirectoryCleanupTarget {
|
pub struct WorkingDirectoryCleanupTarget {
|
||||||
@@ -3162,14 +3577,14 @@ pub struct WorkingDirectoryCleanupTarget {
|
|||||||
pub repository_key: String,
|
pub repository_key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkingDirectoryRemovalRequest {
|
pub struct WorkingDirectoryRemovalRequest {
|
||||||
pub reason: String,
|
pub reason: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum WorkingDirectoryRemovalDisposition {
|
pub enum WorkingDirectoryRemovalDisposition {
|
||||||
@@ -3178,7 +3593,7 @@ pub enum WorkingDirectoryRemovalDisposition {
|
|||||||
AttentionRequired,
|
AttentionRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[cfg_attr(feature = "typescript", ts(optional_fields = nullable))]
|
#[cfg_attr(feature = "typescript", ts(optional_fields = nullable))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
@@ -3191,7 +3606,7 @@ pub struct WorkingDirectoryRemovalResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Durable Workspace occupancy projection for one Workdir.
|
/// Durable Workspace occupancy projection for one Workdir.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkingDirectoryOccupancy {
|
pub struct WorkingDirectoryOccupancy {
|
||||||
@@ -3204,7 +3619,7 @@ pub struct WorkingDirectoryOccupancy {
|
|||||||
/// Runtime-internal Workdir cleanup authority. This transport intentionally
|
/// Runtime-internal Workdir cleanup authority. This transport intentionally
|
||||||
/// retains the Backend-generated Repository id and is never a Workspace public
|
/// retains the Backend-generated Repository id and is never a Workspace public
|
||||||
/// projection.
|
/// projection.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[cfg_attr(feature = "typescript", ts(optional_fields = nullable))]
|
#[cfg_attr(feature = "typescript", ts(optional_fields = nullable))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
@@ -3217,7 +3632,7 @@ pub struct RuntimeWorkingDirectoryCleanupTarget {
|
|||||||
/// Runtime-internal Workdir inventory transport. Workspace REST and model-facing
|
/// Runtime-internal Workdir inventory transport. Workspace REST and model-facing
|
||||||
/// surfaces must project this through [`WorkingDirectorySummary`] so the UUID is
|
/// surfaces must project this through [`WorkingDirectorySummary`] so the UUID is
|
||||||
/// replaced with `repository_key`.
|
/// replaced with `repository_key`.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[cfg_attr(feature = "typescript", ts(optional_fields = nullable))]
|
#[cfg_attr(feature = "typescript", ts(optional_fields = nullable))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
@@ -3241,6 +3656,7 @@ pub struct RuntimeWorkingDirectorySummary {
|
|||||||
pub current_tree: Option<String>,
|
pub current_tree: Option<String>,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
#[cfg_attr(feature = "typescript", ts(type = "number | null"))]
|
#[cfg_attr(feature = "typescript", ts(type = "number | null"))]
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub observed_at_epoch_seconds: Option<u64>,
|
pub observed_at_epoch_seconds: Option<u64>,
|
||||||
pub materializer_kind: WorkingDirectoryMaterializerKind,
|
pub materializer_kind: WorkingDirectoryMaterializerKind,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
@@ -3253,7 +3669,7 @@ pub struct RuntimeWorkingDirectorySummary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Public Workdir source identity. Provider routing details and host paths are intentionally absent.
|
/// Public Workdir source identity. Provider routing details and host paths are intentionally absent.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
|
#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
|
||||||
pub enum WorkingDirectorySource {
|
pub enum WorkingDirectorySource {
|
||||||
@@ -3262,7 +3678,7 @@ pub enum WorkingDirectorySource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Public, provider-neutral Workdir inventory projection.
|
/// Public, provider-neutral Workdir inventory projection.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[cfg_attr(feature = "typescript", ts(optional_fields = nullable))]
|
#[cfg_attr(feature = "typescript", ts(optional_fields = nullable))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
@@ -3286,6 +3702,7 @@ pub struct WorkingDirectorySummary {
|
|||||||
pub current_tree: Option<String>,
|
pub current_tree: Option<String>,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
#[cfg_attr(feature = "typescript", ts(optional, type = "number | null"))]
|
#[cfg_attr(feature = "typescript", ts(optional, type = "number | null"))]
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub observed_at_epoch_seconds: Option<u64>,
|
pub observed_at_epoch_seconds: Option<u64>,
|
||||||
pub materializer_kind: WorkingDirectoryMaterializerKind,
|
pub materializer_kind: WorkingDirectoryMaterializerKind,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
@@ -3414,17 +3831,18 @@ impl From<workdir::workspace::WorkingDirectorySummary> for WorkingDirectorySumma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct ExternalWorkdirGrantCreateRequest {
|
pub struct ExternalWorkdirGrantCreateRequest {
|
||||||
pub provider_instance_id: String,
|
pub provider_instance_id: String,
|
||||||
pub display_name: String,
|
pub display_name: String,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub ttl_seconds: u64,
|
pub ttl_seconds: u64,
|
||||||
pub read_only: bool,
|
pub read_only: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct ExternalWorkdirGrantResponse {
|
pub struct ExternalWorkdirGrantResponse {
|
||||||
@@ -3435,6 +3853,7 @@ pub struct ExternalWorkdirGrantResponse {
|
|||||||
pub display_name: String,
|
pub display_name: String,
|
||||||
pub permissions: String,
|
pub permissions: String,
|
||||||
pub expires_at: String,
|
pub expires_at: String,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub generation: u64,
|
pub generation: u64,
|
||||||
pub status: String,
|
pub status: String,
|
||||||
}
|
}
|
||||||
@@ -3444,7 +3863,7 @@ pub struct ExternalWorkdirGrantResponse {
|
|||||||
/// `runtime_id = None` requests Workspace default Runtime resolution and
|
/// `runtime_id = None` requests Workspace default Runtime resolution and
|
||||||
/// `operation_id = Some(_)` fences exact replay. All four fields deliberately
|
/// `operation_id = Some(_)` fences exact replay. All four fields deliberately
|
||||||
/// preserve the Server's existing optionality.
|
/// preserve the Server's existing optionality.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[cfg_attr(feature = "typescript", ts(optional_fields = nullable))]
|
#[cfg_attr(feature = "typescript", ts(optional_fields = nullable))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
@@ -3461,7 +3880,7 @@ pub struct WorkingDirectoryCreateRequest {
|
|||||||
pub operation_id: Option<String>,
|
pub operation_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkingDirectoryListResponse {
|
pub struct WorkingDirectoryListResponse {
|
||||||
@@ -3470,7 +3889,7 @@ pub struct WorkingDirectoryListResponse {
|
|||||||
pub diagnostics: Vec<Diagnostic>,
|
pub diagnostics: Vec<Diagnostic>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkingDirectoryDetailResponse {
|
pub struct WorkingDirectoryDetailResponse {
|
||||||
@@ -3481,7 +3900,72 @@ pub struct WorkingDirectoryDetailResponse {
|
|||||||
pub diagnostics: Vec<Diagnostic>,
|
pub diagnostics: Vec<Diagnostic>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct HostSummary {
|
||||||
|
pub runtime_id: String,
|
||||||
|
pub host_id: String,
|
||||||
|
pub label: String,
|
||||||
|
pub kind: String,
|
||||||
|
pub status: String,
|
||||||
|
pub observed_at: String,
|
||||||
|
pub last_seen_at: Option<String>,
|
||||||
|
pub os: String,
|
||||||
|
pub arch: String,
|
||||||
|
pub diagnostics: Vec<Diagnostic>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct HostListResponse {
|
||||||
|
pub workspace_id: String,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
|
pub limit: usize,
|
||||||
|
pub items: Vec<HostSummary>,
|
||||||
|
pub source: String,
|
||||||
|
pub diagnostics: Vec<Diagnostic>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct HostWorkerListResponse {
|
||||||
|
pub workspace_id: String,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
|
pub limit: usize,
|
||||||
|
pub items: Vec<WorkerSummary>,
|
||||||
|
pub source: String,
|
||||||
|
pub diagnostics: Vec<Diagnostic>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct CurrentWorkerWorkdirAttachRequest {
|
||||||
|
pub alias: String,
|
||||||
|
pub working_directory_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct CurrentWorkerWorkdirAttachmentResponse {
|
||||||
|
pub workspace_id: String,
|
||||||
|
pub alias: String,
|
||||||
|
pub working_directory_id: String,
|
||||||
|
pub capabilities: workdir::WorkdirSessionCapabilities,
|
||||||
|
pub attached: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct CurrentWorkerWorkdirOperationRequest {
|
||||||
|
pub target_workdir: String,
|
||||||
|
pub operation: workdir::http::WorkdirSessionOperation,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub struct CurrentWorkerWorkdirOperationResponse(pub workdir::http::WorkdirSessionOperationResult);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkingDirectoryCreateResponse {
|
pub struct WorkingDirectoryCreateResponse {
|
||||||
@@ -3489,6 +3973,20 @@ pub struct WorkingDirectoryCreateResponse {
|
|||||||
pub runtime_id: String,
|
pub runtime_id: String,
|
||||||
pub item: WorkingDirectorySummary,
|
pub item: WorkingDirectorySummary,
|
||||||
pub diagnostics: Vec<Diagnostic>,
|
pub diagnostics: Vec<Diagnostic>,
|
||||||
|
#[serde(skip, default = "default_workdir_create_status")]
|
||||||
|
#[cfg_attr(feature = "typescript", ts(skip))]
|
||||||
|
#[schemars(skip)]
|
||||||
|
pub http_status: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn default_workdir_create_status() -> u16 {
|
||||||
|
201
|
||||||
|
}
|
||||||
|
|
||||||
|
impl api_macros::HttpSuccess for WorkingDirectoryCreateResponse {
|
||||||
|
fn status_code(&self) -> u16 {
|
||||||
|
self.http_status
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
@@ -4962,7 +5460,7 @@ pub struct RuntimeConnectionTestResponse {
|
|||||||
pub diagnostics: Vec<Diagnostic>,
|
pub diagnostics: Vec<Diagnostic>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
pub struct WorkerWorkspaceSummary {
|
pub struct WorkerWorkspaceSummary {
|
||||||
pub visibility: String,
|
pub visibility: String,
|
||||||
@@ -4971,14 +5469,14 @@ pub struct WorkerWorkspaceSummary {
|
|||||||
pub workspace_id: Option<String>,
|
pub workspace_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
pub struct WorkerImplementationSummary {
|
pub struct WorkerImplementationSummary {
|
||||||
pub kind: String,
|
pub kind: String,
|
||||||
pub display_hint: String,
|
pub display_hint: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
pub struct WorkerCapabilitySummary {
|
pub struct WorkerCapabilitySummary {
|
||||||
pub can_stop: bool,
|
pub can_stop: bool,
|
||||||
@@ -5149,7 +5647,7 @@ pub struct WorkspaceWorkerDiscoveryPage {
|
|||||||
|
|
||||||
/// One Workspace Worker Workdir attachment. `alias` is the stable Worker-local
|
/// One Workspace Worker Workdir attachment. `alias` is the stable Worker-local
|
||||||
/// routing key; the nested Workdir id and display name are inventory metadata.
|
/// routing key; the nested Workdir id and display name are inventory metadata.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkerWorkdirAttachmentSummary {
|
pub struct WorkerWorkdirAttachmentSummary {
|
||||||
@@ -5170,7 +5668,7 @@ pub struct RuntimeWorkerWorkdirAttachmentSummary {
|
|||||||
/// `resource_key` is required here even though Runtime-internal Worker summaries
|
/// `resource_key` is required here even though Runtime-internal Worker summaries
|
||||||
/// do not carry one. The Workspace Server must resolve it from Workspace
|
/// do not carry one. The Workspace Server must resolve it from Workspace
|
||||||
/// authority before constructing this response.
|
/// authority before constructing this response.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
pub struct WorkerSummary {
|
pub struct WorkerSummary {
|
||||||
pub runtime_id: String,
|
pub runtime_id: String,
|
||||||
@@ -5190,6 +5688,7 @@ pub struct WorkerSummary {
|
|||||||
pub state: String,
|
pub state: String,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
#[cfg_attr(feature = "typescript", ts(optional))]
|
#[cfg_attr(feature = "typescript", ts(optional))]
|
||||||
|
#[schemars(with = "Option<serde_json::Value>")]
|
||||||
pub worker_state: Option<protocol::WorkerStateSnapshot>,
|
pub worker_state: Option<protocol::WorkerStateSnapshot>,
|
||||||
pub last_seen_at: Option<String>,
|
pub last_seen_at: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ pub const GENERATOR_VERSION: &str = "1";
|
|||||||
pub const GENERATOR_OPTIONS: &str = "repository-operation-schema-closure,openapi-3.1,format:uint64=safe-number,strict-safe-integers,sorted-output";
|
pub const GENERATOR_OPTIONS: &str = "repository-operation-schema-closure,openapi-3.1,format:uint64=safe-number,strict-safe-integers,sorted-output";
|
||||||
pub const INPUT_PATH: &str = "openapi/server-api.json";
|
pub const INPUT_PATH: &str = "openapi/server-api.json";
|
||||||
pub const OUTPUT_PATH: &str = "web/workspace/src/lib/generated/repository-api.ts";
|
pub const OUTPUT_PATH: &str = "web/workspace/src/lib/generated/repository-api.ts";
|
||||||
|
pub const WORKDIR_GENERATOR_NAME: &str = "yoi-workdir-openapi-typescript";
|
||||||
|
pub const WORKDIR_GENERATOR_VERSION: &str = "1";
|
||||||
|
pub const WORKDIR_GENERATOR_OPTIONS: &str =
|
||||||
|
"workdir-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output";
|
||||||
|
pub const WORKDIR_OUTPUT_PATH: &str = "web/workspace/src/lib/generated/workdir-api.ts";
|
||||||
|
|
||||||
const MAX_SAFE_INTEGER: f64 = 9_007_199_254_740_991.0;
|
const MAX_SAFE_INTEGER: f64 = 9_007_199_254_740_991.0;
|
||||||
const MIN_SAFE_INTEGER: f64 = -9_007_199_254_740_991.0;
|
const MIN_SAFE_INTEGER: f64 = -9_007_199_254_740_991.0;
|
||||||
@@ -72,6 +77,48 @@ pub fn generate_repository_typescript(input: &str) -> Result<String, GenerationE
|
|||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generate_workdir_typescript(input: &str) -> Result<String, GenerationError> {
|
||||||
|
let document: Value = serde_json::from_str(input)
|
||||||
|
.map_err(|error| GenerationError::invalid(format!("invalid OpenAPI JSON: {error}")))?;
|
||||||
|
let root = object(&document, "OpenAPI document")?;
|
||||||
|
if root.get("openapi").and_then(Value::as_str) != Some("3.1.0") {
|
||||||
|
return Err(GenerationError::invalid(
|
||||||
|
"Workdir TypeScript generation requires OpenAPI 3.1.0",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let info = object_field(root, "info", "OpenAPI document")?;
|
||||||
|
let contract_version = required_string(info, "version", "OpenAPI info")?;
|
||||||
|
let contract_digest = required_string(info, "x-yoi-source-digest", "OpenAPI info")?;
|
||||||
|
validate_contract_digest(contract_digest)?;
|
||||||
|
let schemas = object_field(
|
||||||
|
object_field(root, "components", "OpenAPI document")?,
|
||||||
|
"schemas",
|
||||||
|
"OpenAPI components",
|
||||||
|
)?;
|
||||||
|
let paths = object_field(root, "paths", "OpenAPI document")?;
|
||||||
|
let roots = validate_workdir_operations(paths)?;
|
||||||
|
let closure = schema_closure(schemas, &roots)?;
|
||||||
|
|
||||||
|
let mut output = format!(
|
||||||
|
"// @generated by {WORKDIR_GENERATOR_NAME}@{WORKDIR_GENERATOR_VERSION}. Do not edit.\n\
|
||||||
|
// Input: {INPUT_PATH}\n\
|
||||||
|
// Input contract: {contract_version} ({contract_digest})\n\
|
||||||
|
// Options: {WORKDIR_GENERATOR_OPTIONS}\n\
|
||||||
|
// Output: {WORKDIR_OUTPUT_PATH}\n\
|
||||||
|
// Regenerate/check: cargo run -q -p server-api --example generate_workdir_api_types -- --check\n\n"
|
||||||
|
);
|
||||||
|
for name in closure {
|
||||||
|
let schema = schemas
|
||||||
|
.get(&name)
|
||||||
|
.ok_or_else(|| GenerationError::invalid(format!("missing schema `{name}`")))?;
|
||||||
|
let declaration = render_schema(schema, &format!("schema `{name}`"))?;
|
||||||
|
output.push_str(&format!("export type {name} = {declaration};\n\n"));
|
||||||
|
}
|
||||||
|
output.pop();
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
|
||||||
fn validate_contract_digest(digest: &str) -> Result<(), GenerationError> {
|
fn validate_contract_digest(digest: &str) -> Result<(), GenerationError> {
|
||||||
let Some(hex) = digest.strip_prefix("sha256:") else {
|
let Some(hex) = digest.strip_prefix("sha256:") else {
|
||||||
return Err(GenerationError::invalid(
|
return Err(GenerationError::invalid(
|
||||||
@@ -89,8 +136,7 @@ fn validate_contract_digest(digest: &str) -> Result<(), GenerationError> {
|
|||||||
fn validate_repository_operations(
|
fn validate_repository_operations(
|
||||||
paths: &Map<String, Value>,
|
paths: &Map<String, Value>,
|
||||||
) -> Result<BTreeSet<String>, GenerationError> {
|
) -> Result<BTreeSet<String>, GenerationError> {
|
||||||
let mut roots = BTreeSet::new();
|
let operations = [
|
||||||
for operation in [
|
|
||||||
OperationContract {
|
OperationContract {
|
||||||
path: "/api/repositories",
|
path: "/api/repositories",
|
||||||
method: "get",
|
method: "get",
|
||||||
@@ -129,7 +175,184 @@ fn validate_repository_operations(
|
|||||||
request: None,
|
request: None,
|
||||||
successes: &[("200", "RepositoryDetailResponse")],
|
successes: &[("200", "RepositoryDetailResponse")],
|
||||||
},
|
},
|
||||||
] {
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/repositories/{repository_key}/ssh-connection-test",
|
||||||
|
method: "post",
|
||||||
|
operation_id: "repository_ssh_connection_probe",
|
||||||
|
request: Some("RepositorySshConnectionProbeRequest"),
|
||||||
|
successes: &[("200", "RepositorySshConnectionProbeResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/repositories/{repository_key}/ssh-connection-test",
|
||||||
|
method: "put",
|
||||||
|
operation_id: "repository_ssh_host_trust_confirm",
|
||||||
|
request: Some("ConfirmRepositorySshHostTrustRequest"),
|
||||||
|
successes: &[("200", "RepositorySshHostTrust")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/repositories/{repository_key}/log",
|
||||||
|
method: "get",
|
||||||
|
operation_id: "repository_log",
|
||||||
|
request: None,
|
||||||
|
successes: &[("200", "RepositoryLogResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/repositories/{repository_key}/log",
|
||||||
|
method: "get",
|
||||||
|
operation_id: "repository_log_alias",
|
||||||
|
request: None,
|
||||||
|
successes: &[("200", "RepositoryLogResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/hosts",
|
||||||
|
method: "get",
|
||||||
|
operation_id: "host_list",
|
||||||
|
request: None,
|
||||||
|
successes: &[("200", "HostListResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/hosts",
|
||||||
|
method: "get",
|
||||||
|
operation_id: "host_list_alias",
|
||||||
|
request: None,
|
||||||
|
successes: &[("200", "HostListResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/hosts/{host_id}/workers",
|
||||||
|
method: "get",
|
||||||
|
operation_id: "host_worker_list",
|
||||||
|
request: None,
|
||||||
|
successes: &[("200", "HostWorkerListResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/hosts/{host_id}/workers",
|
||||||
|
method: "get",
|
||||||
|
operation_id: "host_worker_list_alias",
|
||||||
|
request: None,
|
||||||
|
successes: &[("200", "HostWorkerListResponse")],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
validate_operation_contracts(paths, &operations)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_workdir_operations(
|
||||||
|
paths: &Map<String, Value>,
|
||||||
|
) -> Result<BTreeSet<String>, GenerationError> {
|
||||||
|
let operations = [
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/runtimes/{runtime_id}/working-directories",
|
||||||
|
method: "get",
|
||||||
|
operation_id: "runtime_workdir_list",
|
||||||
|
request: None,
|
||||||
|
successes: &[("200", "WorkingDirectoryListResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/runtimes/{runtime_id}/working-directories",
|
||||||
|
method: "post",
|
||||||
|
operation_id: "runtime_workdir_create",
|
||||||
|
request: Some("WorkingDirectoryCreateRequest"),
|
||||||
|
successes: &[
|
||||||
|
("200", "WorkingDirectoryCreateResponse"),
|
||||||
|
("201", "WorkingDirectoryCreateResponse"),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/runtimes/{runtime_id}/working-directories/{working_directory_id}",
|
||||||
|
method: "get",
|
||||||
|
operation_id: "runtime_workdir_detail",
|
||||||
|
request: None,
|
||||||
|
successes: &[("200", "WorkingDirectoryDetailResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/runtimes/{runtime_id}/working-directories/{working_directory_id}",
|
||||||
|
method: "delete",
|
||||||
|
operation_id: "runtime_workdir_cleanup",
|
||||||
|
request: Some("WorkingDirectoryRemovalRequest"),
|
||||||
|
successes: &[("200", "WorkingDirectoryRemovalResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/workers/self/workdir-attachments",
|
||||||
|
method: "post",
|
||||||
|
operation_id: "current_worker_workdir_attach",
|
||||||
|
request: Some("CurrentWorkerWorkdirAttachRequest"),
|
||||||
|
successes: &[("200", "CurrentWorkerWorkdirAttachmentResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/workers/self/workdir-attachments/{alias}",
|
||||||
|
method: "delete",
|
||||||
|
operation_id: "current_worker_workdir_detach",
|
||||||
|
request: None,
|
||||||
|
successes: &[("200", "CurrentWorkerWorkdirAttachmentResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/workers/self/workdir-session/operations",
|
||||||
|
method: "post",
|
||||||
|
operation_id: "current_worker_workdir_operation",
|
||||||
|
request: Some("CurrentWorkerWorkdirOperationRequest"),
|
||||||
|
successes: &[("200", "WorkdirSessionOperationResult")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/external-workdir-grants",
|
||||||
|
method: "post",
|
||||||
|
operation_id: "external_workdir_grant_create",
|
||||||
|
request: Some("ExternalWorkdirGrantCreateRequest"),
|
||||||
|
successes: &[("201", "ExternalWorkdirGrantResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/external-workdir-grants/{grant_id}",
|
||||||
|
method: "get",
|
||||||
|
operation_id: "external_workdir_grant_get",
|
||||||
|
request: None,
|
||||||
|
successes: &[("200", "ExternalWorkdirGrantResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/external-workdir-grants/{grant_id}",
|
||||||
|
method: "delete",
|
||||||
|
operation_id: "external_workdir_grant_revoke",
|
||||||
|
request: None,
|
||||||
|
successes: &[("200", "ExternalWorkdirGrantResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/working-directories",
|
||||||
|
method: "get",
|
||||||
|
operation_id: "workspace_workdir_list",
|
||||||
|
request: None,
|
||||||
|
successes: &[("200", "WorkingDirectoryListResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/working-directories",
|
||||||
|
method: "post",
|
||||||
|
operation_id: "workspace_workdir_create",
|
||||||
|
request: Some("WorkingDirectoryCreateRequest"),
|
||||||
|
successes: &[
|
||||||
|
("200", "WorkingDirectoryCreateResponse"),
|
||||||
|
("201", "WorkingDirectoryCreateResponse"),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/working-directories/{working_directory_id}",
|
||||||
|
method: "get",
|
||||||
|
operation_id: "workspace_workdir_detail",
|
||||||
|
request: None,
|
||||||
|
successes: &[("200", "WorkingDirectoryDetailResponse")],
|
||||||
|
},
|
||||||
|
OperationContract {
|
||||||
|
path: "/api/w/{workspace_id}/working-directories/{working_directory_id}",
|
||||||
|
method: "delete",
|
||||||
|
operation_id: "workspace_workdir_cleanup",
|
||||||
|
request: Some("WorkingDirectoryRemovalRequest"),
|
||||||
|
successes: &[("200", "WorkingDirectoryRemovalResponse")],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
validate_operation_contracts(paths, &operations)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_operation_contracts(
|
||||||
|
paths: &Map<String, Value>,
|
||||||
|
operations: &[OperationContract],
|
||||||
|
) -> Result<BTreeSet<String>, GenerationError> {
|
||||||
|
let mut roots = BTreeSet::new();
|
||||||
|
for operation in operations {
|
||||||
let path = object_field(paths, operation.path, "OpenAPI paths")?;
|
let path = object_field(paths, operation.path, "OpenAPI paths")?;
|
||||||
let value = object_field(path, operation.method, operation.path)?;
|
let value = object_field(path, operation.method, operation.path)?;
|
||||||
if value.get("operationId").and_then(Value::as_str) != Some(operation.operation_id) {
|
if value.get("operationId").and_then(Value::as_str) != Some(operation.operation_id) {
|
||||||
@@ -167,10 +390,13 @@ fn validate_repository_operations(
|
|||||||
&format!("{} response {status}", operation.operation_id),
|
&format!("{} response {status}", operation.operation_id),
|
||||||
)?;
|
)?;
|
||||||
let schema = json_content_schema(response, operation.operation_id)?;
|
let schema = json_content_schema(response, operation.operation_id)?;
|
||||||
let expected = successes
|
let expected = successes.get(status.as_str()).copied().unwrap_or_else(|| {
|
||||||
.get(status.as_str())
|
if operation.operation_id == "current_worker_workdir_operation" {
|
||||||
.copied()
|
"WorkdirOperationApiError"
|
||||||
.unwrap_or("RepositoryApiError");
|
} else {
|
||||||
|
"RepositoryApiError"
|
||||||
|
}
|
||||||
|
});
|
||||||
require_schema_ref(schema, expected, operation.operation_id)?;
|
require_schema_ref(schema, expected, operation.operation_id)?;
|
||||||
roots.insert(expected.to_owned());
|
roots.insert(expected.to_owned());
|
||||||
}
|
}
|
||||||
@@ -315,6 +541,27 @@ fn literal_matches_type(kind: &str, value: &Value) -> bool {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tagged_object_discriminator(value: &Value) -> Option<(String, String)> {
|
||||||
|
let schema = value.as_object()?;
|
||||||
|
if schema.get("type")?.as_str()? != "object"
|
||||||
|
|| schema.get("additionalProperties") != Some(&Value::Bool(false))
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let required = schema.get("required")?.as_array()?;
|
||||||
|
let properties = schema.get("properties")?.as_object()?;
|
||||||
|
properties.iter().find_map(|(name, property)| {
|
||||||
|
if !required
|
||||||
|
.iter()
|
||||||
|
.any(|required| required.as_str() == Some(name))
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let literal = property.as_object()?.get("const")?.as_str()?;
|
||||||
|
Some((name.clone(), literal.to_owned()))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn literal_schema_matches_type(schema: &Map<String, Value>, kind: &str) -> bool {
|
fn literal_schema_matches_type(schema: &Map<String, Value>, kind: &str) -> bool {
|
||||||
if let Some(constant) = schema.get("const") {
|
if let Some(constant) = schema.get("const") {
|
||||||
return literal_matches_type(kind, constant);
|
return literal_matches_type(kind, constant);
|
||||||
@@ -328,6 +575,14 @@ fn literal_schema_matches_type(schema: &Map<String, Value>, kind: &str) -> bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render_schema(value: &Value, context: &str) -> Result<String, GenerationError> {
|
fn render_schema(value: &Value, context: &str) -> Result<String, GenerationError> {
|
||||||
|
if value == &Value::Bool(true) {
|
||||||
|
return Ok("unknown".to_owned());
|
||||||
|
}
|
||||||
|
if value == &Value::Bool(false) {
|
||||||
|
return Err(GenerationError::invalid(format!(
|
||||||
|
"{context} rejects every value"
|
||||||
|
)));
|
||||||
|
}
|
||||||
let schema = object(value, context)?;
|
let schema = object(value, context)?;
|
||||||
if schema.contains_key("$ref") {
|
if schema.contains_key("$ref") {
|
||||||
let reference = schema_reference(value, context)?;
|
let reference = schema_reference(value, context)?;
|
||||||
@@ -403,6 +658,34 @@ fn render_schema(value: &Value, context: &str) -> Result<String, GenerationError
|
|||||||
"{context} contains an empty oneOf"
|
"{context} contains an empty oneOf"
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
let tagged_discriminators = branches
|
||||||
|
.iter()
|
||||||
|
.map(tagged_object_discriminator)
|
||||||
|
.collect::<Option<Vec<_>>>();
|
||||||
|
if let Some(discriminators) = tagged_discriminators {
|
||||||
|
if outer_type.is_some() {
|
||||||
|
return Err(GenerationError::invalid(format!(
|
||||||
|
"{context} combines a tagged object union with an outer type"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let Some((discriminator_name, _)) = discriminators.first() else {
|
||||||
|
unreachable!("empty oneOf rejected above");
|
||||||
|
};
|
||||||
|
let mut seen = BTreeSet::new();
|
||||||
|
for (name, literal) in &discriminators {
|
||||||
|
if name != discriminator_name || !seen.insert(literal.clone()) {
|
||||||
|
return Err(GenerationError::invalid(format!(
|
||||||
|
"{context} contains overlapping tagged oneOf branches"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return branches
|
||||||
|
.iter()
|
||||||
|
.map(|branch| render_schema(branch, context))
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
.map(|branches| branches.join(" | "));
|
||||||
|
}
|
||||||
|
|
||||||
let mut rendered = Vec::with_capacity(branches.len());
|
let mut rendered = Vec::with_capacity(branches.len());
|
||||||
let mut seen_literals = BTreeSet::new();
|
let mut seen_literals = BTreeSet::new();
|
||||||
for branch in branches {
|
for branch in branches {
|
||||||
@@ -438,12 +721,12 @@ fn render_schema(value: &Value, context: &str) -> Result<String, GenerationError
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(kind) = outer_type {
|
if let Some(kind) = outer_type
|
||||||
if !literal_schema_matches_type(branch_object, kind) {
|
&& !literal_schema_matches_type(branch_object, kind)
|
||||||
return Err(GenerationError::invalid(format!(
|
{
|
||||||
"{context} oneOf branch does not match outer type `{kind}`"
|
return Err(GenerationError::invalid(format!(
|
||||||
)));
|
"{context} oneOf branch does not match outer type `{kind}`"
|
||||||
}
|
)));
|
||||||
}
|
}
|
||||||
rendered.push(render_schema(branch, context)?);
|
rendered.push(render_schema(branch, context)?);
|
||||||
}
|
}
|
||||||
@@ -530,7 +813,14 @@ fn render_typed_schema(
|
|||||||
"integer" => {
|
"integer" => {
|
||||||
ensure_schema_keywords(schema, &["format", "maximum", "minimum", "type"], context)?;
|
ensure_schema_keywords(schema, &["format", "maximum", "minimum", "type"], context)?;
|
||||||
let format = match schema.get("format") {
|
let format = match schema.get("format") {
|
||||||
Some(Value::String(format)) if format == "uint64" => Some(format.as_str()),
|
Some(Value::String(format))
|
||||||
|
if matches!(
|
||||||
|
format.as_str(),
|
||||||
|
"uint" | "uint8" | "uint16" | "uint32" | "uint64" | "int32"
|
||||||
|
) =>
|
||||||
|
{
|
||||||
|
Some(format.as_str())
|
||||||
|
}
|
||||||
Some(Value::String(format)) => {
|
Some(Value::String(format)) => {
|
||||||
return Err(GenerationError::invalid(format!(
|
return Err(GenerationError::invalid(format!(
|
||||||
"{context} uses unsupported integer format `{format}`"
|
"{context} uses unsupported integer format `{format}`"
|
||||||
@@ -545,12 +835,16 @@ fn render_typed_schema(
|
|||||||
};
|
};
|
||||||
let minimum = schema.get("minimum").and_then(Value::as_f64);
|
let minimum = schema.get("minimum").and_then(Value::as_f64);
|
||||||
let maximum = schema.get("maximum").and_then(Value::as_f64);
|
let maximum = schema.get("maximum").and_then(Value::as_f64);
|
||||||
let expected_minimum = if format == Some("uint64") {
|
let (expected_minimum, expected_maximum) = match format {
|
||||||
0.0
|
Some("uint") | Some("uint64") => (0.0, MAX_SAFE_INTEGER),
|
||||||
} else {
|
Some("uint8") => (0.0, u8::MAX as f64),
|
||||||
MIN_SAFE_INTEGER
|
Some("uint16") => (0.0, u16::MAX as f64),
|
||||||
|
Some("uint32") => (0.0, u32::MAX as f64),
|
||||||
|
Some("int32") => (i32::MIN as f64, i32::MAX as f64),
|
||||||
|
None => (MIN_SAFE_INTEGER, MAX_SAFE_INTEGER),
|
||||||
|
Some(_) => unreachable!("integer format validated above"),
|
||||||
};
|
};
|
||||||
if minimum != Some(expected_minimum) || maximum != Some(MAX_SAFE_INTEGER) {
|
if minimum != Some(expected_minimum) || maximum != Some(expected_maximum) {
|
||||||
return Err(GenerationError::invalid(format!(
|
return Err(GenerationError::invalid(format!(
|
||||||
"{context} integer range does not match its JavaScript safe-number mapping"
|
"{context} integer range does not match its JavaScript safe-number mapping"
|
||||||
)));
|
)));
|
||||||
@@ -558,11 +852,35 @@ fn render_typed_schema(
|
|||||||
Ok("number".to_owned())
|
Ok("number".to_owned())
|
||||||
}
|
}
|
||||||
"array" => {
|
"array" => {
|
||||||
ensure_schema_keywords(schema, &["items", "type"], context)?;
|
ensure_schema_keywords(schema, &["items", "maxItems", "minItems", "type"], context)?;
|
||||||
let items = schema.get("items").ok_or_else(|| {
|
let items = schema.get("items").ok_or_else(|| {
|
||||||
GenerationError::invalid(format!("{context} array has no item schema"))
|
GenerationError::invalid(format!("{context} array has no item schema"))
|
||||||
})?;
|
})?;
|
||||||
Ok(format!("Array<{}>", render_schema(items, context)?))
|
let item = render_schema(items, context)?;
|
||||||
|
match (schema.get("minItems"), schema.get("maxItems")) {
|
||||||
|
(None, None) => Ok(format!("Array<{item}>")),
|
||||||
|
(Some(minimum), Some(maximum)) if minimum == maximum => {
|
||||||
|
let length = minimum.as_u64().ok_or_else(|| {
|
||||||
|
GenerationError::invalid(format!(
|
||||||
|
"{context} fixed array length must be a non-negative integer"
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
if length > 64 {
|
||||||
|
return Err(GenerationError::invalid(format!(
|
||||||
|
"{context} fixed array length exceeds the generator limit"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
Ok(format!(
|
||||||
|
"[{}]",
|
||||||
|
std::iter::repeat_n(item, length as usize)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => Err(GenerationError::invalid(format!(
|
||||||
|
"{context} contains unsupported variable array bounds"
|
||||||
|
))),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"object" => {
|
"object" => {
|
||||||
ensure_schema_keywords(
|
ensure_schema_keywords(
|
||||||
@@ -778,13 +1096,13 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let mut document: Value = serde_json::from_str(OPENAPI).unwrap();
|
let mut document: Value = serde_json::from_str(OPENAPI).unwrap();
|
||||||
document["components"]["schemas"]["RepositoryListResponse"]["properties"]["items"]["maxItems"] =
|
document["components"]["schemas"]["RepositoryListResponse"]["properties"]["items"]["uniqueItems"] =
|
||||||
serde_json::json!(1);
|
serde_json::json!(true);
|
||||||
let error = generate_repository_typescript(&document.to_string()).unwrap_err();
|
let error = generate_repository_typescript(&document.to_string()).unwrap_err();
|
||||||
assert!(
|
assert!(
|
||||||
error
|
error
|
||||||
.to_string()
|
.to_string()
|
||||||
.contains("unsupported schema keyword `maxItems`")
|
.contains("unsupported schema keyword `uniqueItems`")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ async-trait.workspace = true
|
|||||||
fs-operation.workspace = true
|
fs-operation.workspace = true
|
||||||
manifest.workspace = true
|
manifest.workspace = true
|
||||||
reqwest = { version = "0.13", default-features = false, features = ["json", "rustls"], optional = true }
|
reqwest = { version = "0.13", default-features = false, features = ["json", "rustls"], optional = true }
|
||||||
|
schemars.workspace = true
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
sha2.workspace = true
|
sha2.workspace = true
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
//! optional so Runtime servers can share these DTOs without depending on a
|
//! optional so Runtime servers can share these DTOs without depending on a
|
||||||
//! client stack.
|
//! client stack.
|
||||||
|
|
||||||
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -16,7 +17,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Opaque Runtime-owned identifier for one ephemeral Workdir session.
|
/// Opaque Runtime-owned identifier for one ephemeral Workdir session.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct WorkdirSessionId(String);
|
pub struct WorkdirSessionId(String);
|
||||||
|
|
||||||
@@ -37,7 +38,7 @@ impl WorkdirSessionId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Open a fresh session for a persisted Workdir identity.
|
/// Open a fresh session for a persisted Workdir identity.
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct OpenWorkdirSessionRequest {
|
pub struct OpenWorkdirSessionRequest {
|
||||||
/// Optional Runtime Worker whose persisted binding establishes workspace
|
/// Optional Runtime Worker whose persisted binding establishes workspace
|
||||||
/// ownership of the Workdir. Runtime servers reject cross-workspace owners.
|
/// ownership of the Workdir. Runtime servers reject cross-workspace owners.
|
||||||
@@ -45,7 +46,7 @@ pub struct OpenWorkdirSessionRequest {
|
|||||||
pub owner_worker_id: Option<String>,
|
pub owner_worker_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct OpenWorkdirSessionResponse {
|
pub struct OpenWorkdirSessionResponse {
|
||||||
pub session_id: WorkdirSessionId,
|
pub session_id: WorkdirSessionId,
|
||||||
pub workdir_id: WorkdirId,
|
pub workdir_id: WorkdirId,
|
||||||
@@ -53,7 +54,7 @@ pub struct OpenWorkdirSessionResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// One provider-side Workdir operation.
|
/// One provider-side Workdir operation.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(
|
#[serde(
|
||||||
tag = "operation",
|
tag = "operation",
|
||||||
content = "request",
|
content = "request",
|
||||||
@@ -77,14 +78,14 @@ pub enum WorkdirSessionOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Wire envelope for one provider operation.
|
/// Wire envelope for one provider operation.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkdirSessionOperationRequest {
|
pub struct WorkdirSessionOperationRequest {
|
||||||
pub operation: WorkdirSessionOperation,
|
pub operation: WorkdirSessionOperation,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Typed result paired with [`WorkdirSessionOperation`].
|
/// Typed result paired with [`WorkdirSessionOperation`].
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(
|
#[serde(
|
||||||
tag = "operation",
|
tag = "operation",
|
||||||
content = "result",
|
content = "result",
|
||||||
@@ -174,7 +175,7 @@ pub async fn dispatch_workdir_session_operation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Stable, host-path-free error code crossing the Runtime boundary.
|
/// Stable, host-path-free error code crossing the Runtime boundary.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum WorkdirTransportErrorCode {
|
pub enum WorkdirTransportErrorCode {
|
||||||
NotFound,
|
NotFound,
|
||||||
@@ -238,7 +239,7 @@ impl WorkdirTransportErrorCode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct WorkdirTransportError {
|
pub struct WorkdirTransportError {
|
||||||
pub code: WorkdirTransportErrorCode,
|
pub code: WorkdirTransportErrorCode,
|
||||||
pub message: String,
|
pub message: String,
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ use std::path::{Path, PathBuf};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::sync::broadcast;
|
use tokio::sync::broadcast;
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ pub use scope::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Persistent, opaque identity of one materialized Workdir.
|
/// Persistent, opaque identity of one materialized Workdir.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct Workdir {
|
pub struct Workdir {
|
||||||
id: WorkdirId,
|
id: WorkdirId,
|
||||||
}
|
}
|
||||||
@@ -63,7 +64,7 @@ impl Workdir {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Opaque Workdir identifier assigned by the materialization authority.
|
/// Opaque Workdir identifier assigned by the materialization authority.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct WorkdirId(String);
|
pub struct WorkdirId(String);
|
||||||
|
|
||||||
@@ -79,7 +80,7 @@ impl std::fmt::Display for WorkdirId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum WorkdirSessionCapability {
|
pub enum WorkdirSessionCapability {
|
||||||
Read,
|
Read,
|
||||||
@@ -90,7 +91,7 @@ pub enum WorkdirSessionCapability {
|
|||||||
Command,
|
Command,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct WorkdirSessionCapabilities {
|
pub struct WorkdirSessionCapabilities {
|
||||||
bits: u8,
|
bits: u8,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct CommandHandle(pub String);
|
pub struct CommandHandle(pub String);
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct CommandRequest {
|
pub struct CommandRequest {
|
||||||
pub command: String,
|
pub command: String,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub timeout_secs: u64,
|
pub timeout_secs: u64,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub output_limit: usize,
|
pub output_limit: usize,
|
||||||
/// Workdir-relative command directory. Providers validate it against the
|
/// Workdir-relative command directory. Providers validate it against the
|
||||||
/// active session before process start.
|
/// active session before process start.
|
||||||
@@ -25,15 +28,17 @@ pub struct CommandRequest {
|
|||||||
pub tool_call_id: Option<String>,
|
pub tool_call_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct CommandOutputRequest {
|
pub struct CommandOutputRequest {
|
||||||
pub handle: CommandHandle,
|
pub handle: CommandHandle,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub cursor: usize,
|
pub cursor: usize,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub limit: usize,
|
pub limit: usize,
|
||||||
pub wait: bool,
|
pub wait: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum CommandStatus {
|
pub enum CommandStatus {
|
||||||
Running,
|
Running,
|
||||||
@@ -43,35 +48,41 @@ pub enum CommandStatus {
|
|||||||
Cancelled,
|
Cancelled,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum CommandStream {
|
pub enum CommandStream {
|
||||||
Stdout,
|
Stdout,
|
||||||
Stderr,
|
Stderr,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
|
||||||
pub struct CommandStreamSlice {
|
pub struct CommandStreamSlice {
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub start_offset: u64,
|
pub start_offset: u64,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub end_offset: u64,
|
pub end_offset: u64,
|
||||||
pub content: String,
|
pub content: String,
|
||||||
pub truncated: bool,
|
pub truncated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct CommandSnapshot {
|
pub struct CommandSnapshot {
|
||||||
pub command_id: String,
|
pub command_id: String,
|
||||||
pub tool_call_id: Option<String>,
|
pub tool_call_id: Option<String>,
|
||||||
pub status: CommandStatus,
|
pub status: CommandStatus,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub started_at_ms: u64,
|
pub started_at_ms: u64,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub observed_at_ms: u64,
|
pub observed_at_ms: u64,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||||
pub last_output_at_ms: Option<u64>,
|
pub last_output_at_ms: Option<u64>,
|
||||||
pub stdout: CommandStreamSlice,
|
pub stdout: CommandStreamSlice,
|
||||||
pub stderr: CommandStreamSlice,
|
pub stderr: CommandStreamSlice,
|
||||||
|
#[schemars(range(min = -2147483648_i32, max = 2147483647_i32))]
|
||||||
pub exit_code: Option<i32>,
|
pub exit_code: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(tag = "kind", rename_all = "snake_case")]
|
#[serde(tag = "kind", rename_all = "snake_case")]
|
||||||
pub enum CommandEvent {
|
pub enum CommandEvent {
|
||||||
Started {
|
Started {
|
||||||
@@ -97,12 +108,14 @@ pub enum CommandEvent {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct CommandOutput {
|
pub struct CommandOutput {
|
||||||
pub status: CommandStatus,
|
pub status: CommandStatus,
|
||||||
|
#[schemars(range(min = -2147483648_i32, max = 2147483647_i32))]
|
||||||
pub exit_code: Option<i32>,
|
pub exit_code: Option<i32>,
|
||||||
pub timed_out: bool,
|
pub timed_out: bool,
|
||||||
pub content: String,
|
pub content: String,
|
||||||
|
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||||
pub next_cursor: Option<usize>,
|
pub next_cursor: Option<usize>,
|
||||||
pub truncated: bool,
|
pub truncated: bool,
|
||||||
/// Complete output retained by the provider when `truncated` is true.
|
/// Complete output retained by the provider when `truncated` is true.
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use fs_operation::{
|
|||||||
ListResult, ReadRequest, ReadResult, StatRequest, StatResult, WriteRequest, WriteResult,
|
ListResult, ReadRequest, ReadResult, StatRequest, StatResult, WriteRequest, WriteResult,
|
||||||
};
|
};
|
||||||
use manifest::SymlinkPolicy;
|
use manifest::SymlinkPolicy;
|
||||||
|
use schemars::JsonSchema;
|
||||||
use tokio::sync::broadcast;
|
use tokio::sync::broadcast;
|
||||||
|
|
||||||
const MAX_SCOPED_COMMANDS: usize = 16;
|
const MAX_SCOPED_COMMANDS: usize = 16;
|
||||||
@@ -19,25 +20,26 @@ use crate::{
|
|||||||
WorkdirSessionCapabilities, WorkdirSessionCapability, WorkdirSessionHandle,
|
WorkdirSessionCapabilities, WorkdirSessionCapability, WorkdirSessionHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum WorkdirToolScopePermission {
|
pub enum WorkdirToolScopePermission {
|
||||||
Read,
|
Read,
|
||||||
Write,
|
Write,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkdirToolScopeRule {
|
pub struct WorkdirToolScopeRule {
|
||||||
pub target: FsPath,
|
pub target: FsPath,
|
||||||
pub permission: WorkdirToolScopePermission,
|
pub permission: WorkdirToolScopePermission,
|
||||||
pub recursive: bool,
|
pub recursive: bool,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
#[schemars(with = "String")]
|
||||||
pub symlink_policy: SymlinkPolicy,
|
pub symlink_policy: SymlinkPolicy,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provider-side check for one operation under an attenuated tool scope.
|
/// Provider-side check for one operation under an attenuated tool scope.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkdirScopeAuthorizationRequest {
|
pub struct WorkdirScopeAuthorizationRequest {
|
||||||
pub rules: Vec<WorkdirToolScopeRule>,
|
pub rules: Vec<WorkdirToolScopeRule>,
|
||||||
@@ -46,14 +48,14 @@ pub struct WorkdirScopeAuthorizationRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Provider-side overlap comparison that keeps resolved host paths private.
|
/// Provider-side overlap comparison that keeps resolved host paths private.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkdirScopeOverlapRequest {
|
pub struct WorkdirScopeOverlapRequest {
|
||||||
pub left: WorkdirToolScopeRule,
|
pub left: WorkdirToolScopeRule,
|
||||||
pub right: WorkdirToolScopeRule,
|
pub right: WorkdirToolScopeRule,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkdirToolScope {
|
pub struct WorkdirToolScope {
|
||||||
pub rules: Vec<WorkdirToolScopeRule>,
|
pub rules: Vec<WorkdirToolScopeRule>,
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
//! transport projections. They intentionally do not expose provider/session
|
//! transport projections. They intentionally do not expose provider/session
|
||||||
//! handles, host paths, Runtime URLs, or credentials.
|
//! handles, host paths, Runtime URLs, or credentials.
|
||||||
|
|
||||||
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum WorkingDirectoryMaterializerKind {
|
pub enum WorkingDirectoryMaterializerKind {
|
||||||
#[default]
|
#[default]
|
||||||
@@ -14,7 +15,7 @@ pub enum WorkingDirectoryMaterializerKind {
|
|||||||
ClientHostedExternal,
|
ClientHostedExternal,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum WorkingDirectoryStatusKind {
|
pub enum WorkingDirectoryStatusKind {
|
||||||
Active,
|
Active,
|
||||||
@@ -42,7 +43,7 @@ impl std::fmt::Display for WorkingDirectoryStatusKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkingDirectoryCleanupTarget {
|
pub struct WorkingDirectoryCleanupTarget {
|
||||||
pub kind: String,
|
pub kind: String,
|
||||||
@@ -50,7 +51,7 @@ pub struct WorkingDirectoryCleanupTarget {
|
|||||||
pub repository_key: String,
|
pub repository_key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkingDirectoryOccupancy {
|
pub struct WorkingDirectoryOccupancy {
|
||||||
pub runtime_id: String,
|
pub runtime_id: String,
|
||||||
@@ -59,7 +60,7 @@ pub struct WorkingDirectoryOccupancy {
|
|||||||
pub linked_at: String,
|
pub linked_at: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct RuntimeWorkingDirectoryCleanupTarget {
|
pub struct RuntimeWorkingDirectoryCleanupTarget {
|
||||||
pub kind: String,
|
pub kind: String,
|
||||||
@@ -67,7 +68,7 @@ pub struct RuntimeWorkingDirectoryCleanupTarget {
|
|||||||
pub repository_id: String,
|
pub repository_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct RuntimeWorkingDirectorySummary {
|
pub struct RuntimeWorkingDirectorySummary {
|
||||||
pub working_directory_id: String,
|
pub working_directory_id: String,
|
||||||
@@ -99,14 +100,14 @@ pub struct RuntimeWorkingDirectorySummary {
|
|||||||
pub occupied_by: Option<WorkingDirectoryOccupancy>,
|
pub occupied_by: Option<WorkingDirectoryOccupancy>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||||
#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
|
#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
|
||||||
pub enum WorkingDirectorySource {
|
pub enum WorkingDirectorySource {
|
||||||
Repository { repository_key: String },
|
Repository { repository_key: String },
|
||||||
ExternalGrant { grant_id: String },
|
ExternalGrant { grant_id: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkingDirectorySummary {
|
pub struct WorkingDirectorySummary {
|
||||||
pub working_directory_id: String,
|
pub working_directory_id: String,
|
||||||
@@ -146,7 +147,9 @@ impl WorkingDirectorySummary {
|
|||||||
pub use WorkingDirectoryMaterializerKind as MaterializerKind;
|
pub use WorkingDirectoryMaterializerKind as MaterializerKind;
|
||||||
|
|
||||||
/// Stable Workspace identity for a Worker hosted by a Runtime.
|
/// Stable Workspace identity for a Worker hosted by a Runtime.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
#[derive(
|
||||||
|
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
|
||||||
|
)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct RuntimeWorkerRef {
|
pub struct RuntimeWorkerRef {
|
||||||
pub runtime_id: String,
|
pub runtime_id: String,
|
||||||
@@ -164,7 +167,7 @@ impl RuntimeWorkerRef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Immutable materialization provenance retained by Workspace inventory.
|
/// Immutable materialization provenance retained by Workspace inventory.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkingDirectoryProvenance {
|
pub struct WorkingDirectoryProvenance {
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
@@ -179,7 +182,7 @@ pub struct WorkingDirectoryProvenance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Latest provider-neutral observation attached to Workspace inventory.
|
/// Latest provider-neutral observation attached to Workspace inventory.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkingDirectoryCurrentObservation {
|
pub struct WorkingDirectoryCurrentObservation {
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
@@ -247,7 +250,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WorkspaceWorkdirSessionOperationRequest {
|
pub struct WorkspaceWorkdirSessionOperationRequest {
|
||||||
/// Worker-local attachment alias selected by the calling tool router.
|
/// Worker-local attachment alias selected by the calling tool router.
|
||||||
|
|||||||
@@ -291,6 +291,23 @@ impl From<RuntimeDiagnostic> for server_api::Diagnostic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<HostSummary> for server_api::HostSummary {
|
||||||
|
fn from(host: HostSummary) -> Self {
|
||||||
|
Self {
|
||||||
|
runtime_id: host.runtime_id,
|
||||||
|
host_id: host.host_id,
|
||||||
|
label: host.label,
|
||||||
|
kind: host.kind,
|
||||||
|
status: host.status,
|
||||||
|
observed_at: host.observed_at,
|
||||||
|
last_seen_at: host.last_seen_at,
|
||||||
|
os: host.os,
|
||||||
|
arch: host.arch,
|
||||||
|
diagnostics: host.diagnostics.into_iter().map(Into::into).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<RuntimeSourceSummary> for server_api::RuntimeSourceSummary {
|
impl From<RuntimeSourceSummary> for server_api::RuntimeSourceSummary {
|
||||||
fn from(source: RuntimeSourceSummary) -> Self {
|
fn from(source: RuntimeSourceSummary) -> Self {
|
||||||
let kind = match source.kind {
|
let kind = match source.kind {
|
||||||
|
|||||||
@@ -3641,11 +3641,13 @@ fn build_server_auth_router(api: ServerAuthApi) -> Router {
|
|||||||
|
|
||||||
fn server_request_context(
|
fn server_request_context(
|
||||||
actor: Option<RequestActor>,
|
actor: Option<RequestActor>,
|
||||||
|
worker_source: Option<server_api::ServerWorkerSource>,
|
||||||
origin: Option<String>,
|
origin: Option<String>,
|
||||||
headers: &HeaderMap,
|
headers: &HeaderMap,
|
||||||
) -> server_api::ServerRequestContext {
|
) -> server_api::ServerRequestContext {
|
||||||
server_api::ServerRequestContext {
|
server_api::ServerRequestContext {
|
||||||
actor,
|
actor,
|
||||||
|
worker_source,
|
||||||
origin,
|
origin,
|
||||||
transport_headers: headers
|
transport_headers: headers
|
||||||
.iter()
|
.iter()
|
||||||
@@ -3683,7 +3685,7 @@ fn contract_request_headers(
|
|||||||
async fn attach_server_origin_context(mut request: Request, next: Next) -> Response {
|
async fn attach_server_origin_context(mut request: Request, next: Next) -> Response {
|
||||||
let actor = request.extensions().get::<RequestActor>().cloned();
|
let actor = request.extensions().get::<RequestActor>().cloned();
|
||||||
let origin = request_origin(request.headers());
|
let origin = request_origin(request.headers());
|
||||||
let context = server_request_context(actor, origin, request.headers());
|
let context = server_request_context(actor, None, origin, request.headers());
|
||||||
request.extensions_mut().insert(context);
|
request.extensions_mut().insert(context);
|
||||||
next.run(request).await
|
next.run(request).await
|
||||||
}
|
}
|
||||||
@@ -3708,8 +3710,15 @@ async fn attach_server_request_context(
|
|||||||
Err(error) => return server_error_response(error),
|
Err(error) => return server_error_response(error),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let worker_source = request
|
||||||
|
.extensions()
|
||||||
|
.get::<crate::worker_source::VerifiedWorkerMutationSource>()
|
||||||
|
.map(|source| server_api::ServerWorkerSource {
|
||||||
|
runtime_id: source.runtime_id.clone(),
|
||||||
|
worker_id: source.worker_id.clone(),
|
||||||
|
});
|
||||||
let origin = request_origin(request.headers());
|
let origin = request_origin(request.headers());
|
||||||
let context = server_request_context(actor, origin, request.headers());
|
let context = server_request_context(actor, worker_source, origin, request.headers());
|
||||||
request.extensions_mut().insert(context);
|
request.extensions_mut().insert(context);
|
||||||
next.run(request).await
|
next.run(request).await
|
||||||
}
|
}
|
||||||
@@ -3865,6 +3874,62 @@ fn generated_workspace_contract_router(service: ServerApiContractService) -> Rou
|
|||||||
.merge(server_api::server_api_axum::repository_create(
|
.merge(server_api::server_api_axum::repository_create(
|
||||||
service.clone(),
|
service.clone(),
|
||||||
))
|
))
|
||||||
|
.merge(server_api::server_api_axum::repository_ssh_connection_probe(service.clone()))
|
||||||
|
.merge(server_api::server_api_axum::repository_ssh_host_trust_confirm(service.clone()))
|
||||||
|
.merge(server_api::server_api_axum::repository_log(service.clone()))
|
||||||
|
.merge(server_api::server_api_axum::repository_log_alias(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::host_list(service.clone()))
|
||||||
|
.merge(server_api::server_api_axum::host_list_alias(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::host_worker_list(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::host_worker_list_alias(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::runtime_workdir_list(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::runtime_workdir_create(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::runtime_workdir_detail(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::runtime_workdir_cleanup(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::current_worker_workdir_attach(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::current_worker_workdir_detach(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::current_worker_workdir_operation(service.clone()))
|
||||||
|
.merge(server_api::server_api_axum::external_workdir_grant_create(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::external_workdir_grant_get(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::external_workdir_grant_revoke(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::workspace_workdir_list(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::workspace_workdir_create(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::workspace_workdir_detail(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
|
.merge(server_api::server_api_axum::workspace_workdir_cleanup(
|
||||||
|
service.clone(),
|
||||||
|
))
|
||||||
.merge(server_api::server_api_axum::ticket_list_alias(
|
.merge(server_api::server_api_axum::ticket_list_alias(
|
||||||
service.clone(),
|
service.clone(),
|
||||||
))
|
))
|
||||||
@@ -6103,6 +6168,451 @@ impl server_api::ServerApi for ServerApiContractService {
|
|||||||
.map_err(ApiError::into_repository_api_error)?;
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
project_contract_dto(&response)
|
project_contract_dto(&response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn repository_ssh_connection_probe(
|
||||||
|
&self,
|
||||||
|
actor: RequestActor,
|
||||||
|
workspace_id: String,
|
||||||
|
repository_key: String,
|
||||||
|
request: server_api::RepositorySshConnectionProbeRequest,
|
||||||
|
) -> std::result::Result<
|
||||||
|
server_api::RepositorySshConnectionProbeResponse,
|
||||||
|
server_api::RepositoryApiError,
|
||||||
|
> {
|
||||||
|
let Json(response) = scoped_probe_repository_ssh_connection(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
AxumPath(ScopedRepositoryPath {
|
||||||
|
workspace_id,
|
||||||
|
repository_key,
|
||||||
|
}),
|
||||||
|
Extension(actor),
|
||||||
|
Json(request),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn repository_ssh_host_trust_confirm(
|
||||||
|
&self,
|
||||||
|
actor: RequestActor,
|
||||||
|
workspace_id: String,
|
||||||
|
repository_key: String,
|
||||||
|
request: server_api::ConfirmRepositorySshHostTrustRequest,
|
||||||
|
) -> std::result::Result<server_api::RepositorySshHostTrust, server_api::RepositoryApiError>
|
||||||
|
{
|
||||||
|
let Json(response) = scoped_confirm_repository_ssh_host_trust(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
AxumPath(ScopedRepositoryPath {
|
||||||
|
workspace_id,
|
||||||
|
repository_key,
|
||||||
|
}),
|
||||||
|
Extension(actor),
|
||||||
|
Json(request),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn repository_log(
|
||||||
|
&self,
|
||||||
|
workspace_id: String,
|
||||||
|
repository_key: String,
|
||||||
|
query: server_api::RepositoryLogQuery,
|
||||||
|
) -> std::result::Result<server_api::RepositoryLogResponse, server_api::RepositoryApiError>
|
||||||
|
{
|
||||||
|
let Json(response) = scoped_repository_log(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
AxumPath(ScopedRepositoryPath {
|
||||||
|
workspace_id,
|
||||||
|
repository_key,
|
||||||
|
}),
|
||||||
|
Query(LogQuery { limit: query.limit }),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn repository_log_alias(
|
||||||
|
&self,
|
||||||
|
repository_key: String,
|
||||||
|
query: server_api::RepositoryLogQuery,
|
||||||
|
) -> std::result::Result<server_api::RepositoryLogResponse, server_api::RepositoryApiError>
|
||||||
|
{
|
||||||
|
let Json(response) = repository_log(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
AxumPath(repository_key),
|
||||||
|
Query(LogQuery { limit: query.limit }),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn host_list(
|
||||||
|
&self,
|
||||||
|
workspace_id: String,
|
||||||
|
) -> std::result::Result<server_api::HostListResponse, server_api::RepositoryApiError> {
|
||||||
|
let Json(response) = scoped_list_hosts(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
AxumPath(ScopedWorkspacePath { workspace_id }),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(server_api::HostListResponse {
|
||||||
|
workspace_id: response.workspace_id,
|
||||||
|
limit: response.limit,
|
||||||
|
items: response.items.into_iter().map(Into::into).collect(),
|
||||||
|
source: response.source,
|
||||||
|
diagnostics: response.diagnostics.into_iter().map(Into::into).collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn host_list_alias(
|
||||||
|
&self,
|
||||||
|
) -> std::result::Result<server_api::HostListResponse, server_api::RepositoryApiError> {
|
||||||
|
let Json(response) = list_hosts(State(self.workspace_api()?.clone()))
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(server_api::HostListResponse {
|
||||||
|
workspace_id: response.workspace_id,
|
||||||
|
limit: response.limit,
|
||||||
|
items: response.items.into_iter().map(Into::into).collect(),
|
||||||
|
source: response.source,
|
||||||
|
diagnostics: response.diagnostics.into_iter().map(Into::into).collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn host_worker_list(
|
||||||
|
&self,
|
||||||
|
workspace_id: String,
|
||||||
|
host_id: String,
|
||||||
|
) -> std::result::Result<server_api::HostWorkerListResponse, server_api::RepositoryApiError>
|
||||||
|
{
|
||||||
|
let Json(response) = scoped_list_host_workers(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
AxumPath(ScopedHostPath {
|
||||||
|
workspace_id,
|
||||||
|
host_id,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn host_worker_list_alias(
|
||||||
|
&self,
|
||||||
|
host_id: String,
|
||||||
|
) -> std::result::Result<server_api::HostWorkerListResponse, server_api::RepositoryApiError>
|
||||||
|
{
|
||||||
|
let Json(response) =
|
||||||
|
list_host_workers(State(self.workspace_api()?.clone()), AxumPath(host_id))
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn runtime_workdir_list(
|
||||||
|
&self,
|
||||||
|
workspace_id: String,
|
||||||
|
runtime_id: String,
|
||||||
|
) -> std::result::Result<server_api::WorkingDirectoryListResponse, server_api::RepositoryApiError>
|
||||||
|
{
|
||||||
|
let Json(response) = scoped_list_runtime_working_directories(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
AxumPath(ScopedRuntimePath {
|
||||||
|
workspace_id,
|
||||||
|
runtime_id,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn runtime_workdir_create(
|
||||||
|
&self,
|
||||||
|
workspace_id: String,
|
||||||
|
runtime_id: String,
|
||||||
|
request: server_api::WorkingDirectoryCreateRequest,
|
||||||
|
) -> std::result::Result<
|
||||||
|
server_api::WorkingDirectoryCreateResponse,
|
||||||
|
server_api::RepositoryApiError,
|
||||||
|
> {
|
||||||
|
let (_, Json(response)) = scoped_create_runtime_working_directory(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
AxumPath(ScopedRuntimePath {
|
||||||
|
workspace_id,
|
||||||
|
runtime_id,
|
||||||
|
}),
|
||||||
|
Json(request),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn runtime_workdir_detail(
|
||||||
|
&self,
|
||||||
|
workspace_id: String,
|
||||||
|
runtime_id: String,
|
||||||
|
working_directory_id: String,
|
||||||
|
) -> std::result::Result<
|
||||||
|
server_api::WorkingDirectoryDetailResponse,
|
||||||
|
server_api::RepositoryApiError,
|
||||||
|
> {
|
||||||
|
let Json(response) = scoped_runtime_working_directory_detail(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
AxumPath(ScopedRuntimeWorkingDirectoryPath {
|
||||||
|
workspace_id,
|
||||||
|
runtime_id,
|
||||||
|
working_directory_id,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn runtime_workdir_cleanup(
|
||||||
|
&self,
|
||||||
|
context: server_api::ServerRequestContext,
|
||||||
|
workspace_id: String,
|
||||||
|
runtime_id: String,
|
||||||
|
working_directory_id: String,
|
||||||
|
request: server_api::WorkingDirectoryRemovalRequest,
|
||||||
|
) -> std::result::Result<
|
||||||
|
server_api::WorkingDirectoryRemovalResponse,
|
||||||
|
server_api::RepositoryApiError,
|
||||||
|
> {
|
||||||
|
cleanup_runtime_working_directory_contract(
|
||||||
|
self.workspace_api()?.clone(),
|
||||||
|
workspace_id,
|
||||||
|
runtime_id,
|
||||||
|
working_directory_id,
|
||||||
|
context,
|
||||||
|
request,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn current_worker_workdir_attach(
|
||||||
|
&self,
|
||||||
|
context: server_api::ServerRequestContext,
|
||||||
|
workspace_id: String,
|
||||||
|
request: server_api::CurrentWorkerWorkdirAttachRequest,
|
||||||
|
) -> std::result::Result<
|
||||||
|
server_api::CurrentWorkerWorkdirAttachmentResponse,
|
||||||
|
server_api::RepositoryApiError,
|
||||||
|
> {
|
||||||
|
let Json(response) = scoped_attach_current_worker_workdir(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
AxumPath(ScopedWorkspacePath { workspace_id }),
|
||||||
|
contract_request_headers(&context)?,
|
||||||
|
Json(AttachCurrentWorkerWorkdirRequest {
|
||||||
|
alias: request.alias,
|
||||||
|
working_directory_id: request.working_directory_id,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(server_api::CurrentWorkerWorkdirAttachmentResponse {
|
||||||
|
workspace_id: response.workspace_id,
|
||||||
|
alias: response.alias,
|
||||||
|
working_directory_id: response.working_directory_id,
|
||||||
|
capabilities: response.capabilities,
|
||||||
|
attached: response.attached,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn current_worker_workdir_detach(
|
||||||
|
&self,
|
||||||
|
context: server_api::ServerRequestContext,
|
||||||
|
workspace_id: String,
|
||||||
|
alias: String,
|
||||||
|
) -> std::result::Result<
|
||||||
|
server_api::CurrentWorkerWorkdirAttachmentResponse,
|
||||||
|
server_api::RepositoryApiError,
|
||||||
|
> {
|
||||||
|
let Json(response) = scoped_detach_current_worker_workdir(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
AxumPath((workspace_id, alias)),
|
||||||
|
contract_request_headers(&context)?,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(server_api::CurrentWorkerWorkdirAttachmentResponse {
|
||||||
|
workspace_id: response.workspace_id,
|
||||||
|
alias: response.alias,
|
||||||
|
working_directory_id: response.working_directory_id,
|
||||||
|
capabilities: response.capabilities,
|
||||||
|
attached: response.attached,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn current_worker_workdir_operation(
|
||||||
|
&self,
|
||||||
|
context: server_api::ServerRequestContext,
|
||||||
|
workspace_id: String,
|
||||||
|
request: server_api::CurrentWorkerWorkdirOperationRequest,
|
||||||
|
) -> std::result::Result<
|
||||||
|
server_api::CurrentWorkerWorkdirOperationResponse,
|
||||||
|
server_api::WorkdirOperationApiError,
|
||||||
|
> {
|
||||||
|
let Json(response) = scoped_execute_current_worker_workdir_operation(
|
||||||
|
State(
|
||||||
|
self.workspace_api()
|
||||||
|
.map_err(server_api::WorkdirOperationApiError::api)?
|
||||||
|
.clone(),
|
||||||
|
),
|
||||||
|
AxumPath(ScopedWorkspacePath { workspace_id }),
|
||||||
|
contract_request_headers(&context)
|
||||||
|
.map_err(server_api::WorkdirOperationApiError::api)?,
|
||||||
|
Json(WorkspaceWorkdirSessionOperationRequest {
|
||||||
|
target_workdir: request.target_workdir,
|
||||||
|
operation: request.operation,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|error| match error {
|
||||||
|
WorkdirOperationApiError::Api(error) => {
|
||||||
|
server_api::WorkdirOperationApiError::api(error.into_repository_api_error())
|
||||||
|
}
|
||||||
|
WorkdirOperationApiError::Provider(error) => {
|
||||||
|
server_api::WorkdirOperationApiError::provider(error)
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
Ok(server_api::CurrentWorkerWorkdirOperationResponse(response))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn external_workdir_grant_create(
|
||||||
|
&self,
|
||||||
|
actor: RequestActor,
|
||||||
|
workspace_id: String,
|
||||||
|
request: server_api::ExternalWorkdirGrantCreateRequest,
|
||||||
|
) -> std::result::Result<server_api::ExternalWorkdirGrantResponse, server_api::RepositoryApiError>
|
||||||
|
{
|
||||||
|
let (_, Json(response)) = scoped_create_external_workdir_grant(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
AxumPath(ScopedWorkspacePath { workspace_id }),
|
||||||
|
Extension(actor),
|
||||||
|
Json(request),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn external_workdir_grant_get(
|
||||||
|
&self,
|
||||||
|
actor: RequestActor,
|
||||||
|
workspace_id: String,
|
||||||
|
grant_id: String,
|
||||||
|
) -> std::result::Result<server_api::ExternalWorkdirGrantResponse, server_api::RepositoryApiError>
|
||||||
|
{
|
||||||
|
let Json(response) = scoped_get_external_workdir_grant(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
Extension(actor),
|
||||||
|
AxumPath((workspace_id, grant_id)),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn external_workdir_grant_revoke(
|
||||||
|
&self,
|
||||||
|
actor: RequestActor,
|
||||||
|
workspace_id: String,
|
||||||
|
grant_id: String,
|
||||||
|
) -> std::result::Result<server_api::ExternalWorkdirGrantResponse, server_api::RepositoryApiError>
|
||||||
|
{
|
||||||
|
let Json(response) = scoped_revoke_external_workdir_grant(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
Extension(actor),
|
||||||
|
AxumPath((workspace_id, grant_id)),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn workspace_workdir_list(
|
||||||
|
&self,
|
||||||
|
workspace_id: String,
|
||||||
|
) -> std::result::Result<server_api::WorkingDirectoryListResponse, server_api::RepositoryApiError>
|
||||||
|
{
|
||||||
|
let Json(response) = scoped_list_working_directories(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
AxumPath(ScopedWorkspacePath { workspace_id }),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn workspace_workdir_create(
|
||||||
|
&self,
|
||||||
|
workspace_id: String,
|
||||||
|
request: server_api::WorkingDirectoryCreateRequest,
|
||||||
|
) -> std::result::Result<
|
||||||
|
server_api::WorkingDirectoryCreateResponse,
|
||||||
|
server_api::RepositoryApiError,
|
||||||
|
> {
|
||||||
|
let (_, Json(response)) = scoped_create_working_directory(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
AxumPath(ScopedWorkspacePath { workspace_id }),
|
||||||
|
Json(request),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn workspace_workdir_detail(
|
||||||
|
&self,
|
||||||
|
workspace_id: String,
|
||||||
|
working_directory_id: String,
|
||||||
|
) -> std::result::Result<
|
||||||
|
server_api::WorkingDirectoryDetailResponse,
|
||||||
|
server_api::RepositoryApiError,
|
||||||
|
> {
|
||||||
|
let Json(response) = scoped_working_directory_detail(
|
||||||
|
State(self.workspace_api()?.clone()),
|
||||||
|
AxumPath(ScopedWorkingDirectoryPath {
|
||||||
|
workspace_id,
|
||||||
|
working_directory_id,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)?;
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn workspace_workdir_cleanup(
|
||||||
|
&self,
|
||||||
|
context: server_api::ServerRequestContext,
|
||||||
|
workspace_id: String,
|
||||||
|
working_directory_id: String,
|
||||||
|
request: server_api::WorkingDirectoryRemovalRequest,
|
||||||
|
) -> std::result::Result<
|
||||||
|
server_api::WorkingDirectoryRemovalResponse,
|
||||||
|
server_api::RepositoryApiError,
|
||||||
|
> {
|
||||||
|
cleanup_working_directory_contract(
|
||||||
|
self.workspace_api()?.clone(),
|
||||||
|
workspace_id,
|
||||||
|
working_directory_id,
|
||||||
|
context,
|
||||||
|
request,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::into_repository_api_error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_inner_router(api: WorkspaceApi) -> Router {
|
fn build_inner_router(api: WorkspaceApi) -> Router {
|
||||||
@@ -6110,62 +6620,15 @@ fn build_inner_router(api: WorkspaceApi) -> Router {
|
|||||||
let auth = build_server_auth_router(ServerAuthApi::from(&api))
|
let auth = build_server_auth_router(ServerAuthApi::from(&api))
|
||||||
.merge(generated_auth_contract_router(contract_service.clone()));
|
.merge(generated_auth_contract_router(contract_service.clone()));
|
||||||
let workspace = Router::new()
|
let workspace = Router::new()
|
||||||
.route(
|
// WebSocket provider transport is intentionally outside the generated
|
||||||
"/api/w/{workspace_id}/repositories/{repository_key}/ssh-connection-test",
|
// JSON REST contract.
|
||||||
post(scoped_probe_repository_ssh_connection)
|
|
||||||
.put(scoped_confirm_repository_ssh_host_trust),
|
|
||||||
)
|
|
||||||
.route("/api/repositories/{repository_key}/log", get(repository_log))
|
|
||||||
.route(
|
|
||||||
"/api/w/{workspace_id}/repositories/{repository_key}/log",
|
|
||||||
get(scoped_repository_log),
|
|
||||||
)
|
|
||||||
.route("/api/hosts", get(list_hosts))
|
|
||||||
.route("/api/w/{workspace_id}/hosts", get(scoped_list_hosts))
|
|
||||||
.route(
|
|
||||||
"/api/w/{workspace_id}/runtime-config",
|
|
||||||
get(get_latest_workspace_runtime_config),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/api/w/{workspace_id}/runtimes/{runtime_id}/working-directories",
|
|
||||||
get(scoped_list_runtime_working_directories).post(scoped_create_runtime_working_directory),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/api/w/{workspace_id}/runtimes/{runtime_id}/working-directories/{working_directory_id}",
|
|
||||||
get(scoped_runtime_working_directory_detail).delete(scoped_cleanup_runtime_working_directory),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/api/w/{workspace_id}/workers/self/workdir-attachments",
|
|
||||||
post(scoped_attach_current_worker_workdir),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/api/w/{workspace_id}/workers/self/workdir-attachments/{alias}",
|
|
||||||
delete(scoped_detach_current_worker_workdir),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/api/w/{workspace_id}/workers/self/workdir-session/operations",
|
|
||||||
post(scoped_execute_current_worker_workdir_operation),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/api/w/{workspace_id}/external-workdir-grants",
|
|
||||||
post(scoped_create_external_workdir_grant),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/api/w/{workspace_id}/external-workdir-grants/{grant_id}",
|
|
||||||
get(scoped_get_external_workdir_grant)
|
|
||||||
.delete(scoped_revoke_external_workdir_grant),
|
|
||||||
)
|
|
||||||
.route(
|
.route(
|
||||||
"/api/w/{workspace_id}/external-workdir-grants/{grant_id}/provider",
|
"/api/w/{workspace_id}/external-workdir-grants/{grant_id}/provider",
|
||||||
get(scoped_external_workdir_provider_ws),
|
get(scoped_external_workdir_provider_ws),
|
||||||
)
|
)
|
||||||
.route(
|
.route(
|
||||||
"/api/w/{workspace_id}/working-directories",
|
"/api/w/{workspace_id}/runtime-config",
|
||||||
get(scoped_list_working_directories).post(scoped_create_working_directory),
|
get(get_latest_workspace_runtime_config),
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/api/w/{workspace_id}/working-directories/{working_directory_id}",
|
|
||||||
get(scoped_working_directory_detail).delete(scoped_cleanup_working_directory),
|
|
||||||
)
|
)
|
||||||
.route("/api/runtimes", get(list_runtimes))
|
.route("/api/runtimes", get(list_runtimes))
|
||||||
.route(
|
.route(
|
||||||
@@ -6381,11 +6844,6 @@ fn build_inner_router(api: WorkspaceApi) -> Router {
|
|||||||
"/api/w/{workspace_id}/runtimes/{runtime_id}/workers/{worker_id}/protocol/ws",
|
"/api/w/{workspace_id}/runtimes/{runtime_id}/workers/{worker_id}/protocol/ws",
|
||||||
get(scoped_worker_protocol_ws),
|
get(scoped_worker_protocol_ws),
|
||||||
)
|
)
|
||||||
.route("/api/hosts/{host_id}/workers", get(list_host_workers))
|
|
||||||
.route(
|
|
||||||
"/api/w/{workspace_id}/hosts/{host_id}/workers",
|
|
||||||
get(scoped_list_host_workers),
|
|
||||||
)
|
|
||||||
.fallback(get(static_or_spa_fallback))
|
.fallback(get(static_or_spa_fallback))
|
||||||
.with_state(api)
|
.with_state(api)
|
||||||
.merge(generated_workspace_contract_router(contract_service));
|
.merge(generated_workspace_contract_router(contract_service));
|
||||||
@@ -13759,13 +14217,81 @@ async fn scoped_runtime_working_directory_detail(
|
|||||||
working_directory_detail_for_runtime(api, &path.runtime_id, &path.working_directory_id)
|
working_directory_detail_for_runtime(api, &path.runtime_id, &path.working_directory_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn scoped_cleanup_runtime_working_directory(
|
fn workdir_removal_source_actor(
|
||||||
State(api): State<WorkspaceApi>,
|
worker_source: Option<(&str, &str)>,
|
||||||
AxumPath(path): AxumPath<ScopedRuntimeWorkingDirectoryPath>,
|
request_actor: Option<&RequestActor>,
|
||||||
worker_source: Option<Extension<crate::worker_source::VerifiedWorkerMutationSource>>,
|
) -> ApiResult<String> {
|
||||||
request_actor: Option<Extension<RequestActor>>,
|
if let Some((runtime_id, worker_id)) = worker_source {
|
||||||
Json(request): Json<WorkingDirectoryRemovalRequest>,
|
Ok(format!("worker:{runtime_id}:{worker_id}"))
|
||||||
) -> ApiResult<Json<WorkingDirectoryRemovalResponse>> {
|
} else if let Some(actor) = request_actor {
|
||||||
|
Ok(format!("account:{}", actor.account_id))
|
||||||
|
} else {
|
||||||
|
Err(ApiError::from(Error::WorkspacePermissionDenied(
|
||||||
|
"Workdir removal requires authenticated source authority".to_string(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contract_workdir_removal_source_actor(
|
||||||
|
context: &server_api::ServerRequestContext,
|
||||||
|
) -> ApiResult<String> {
|
||||||
|
workdir_removal_source_actor(
|
||||||
|
context
|
||||||
|
.worker_source
|
||||||
|
.as_ref()
|
||||||
|
.map(|source| (source.runtime_id.as_str(), source.worker_id.as_str())),
|
||||||
|
context.actor.as_ref(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn cleanup_runtime_working_directory_contract(
|
||||||
|
api: WorkspaceApi,
|
||||||
|
workspace_id: String,
|
||||||
|
runtime_id: String,
|
||||||
|
working_directory_id: String,
|
||||||
|
context: server_api::ServerRequestContext,
|
||||||
|
request: WorkingDirectoryRemovalRequest,
|
||||||
|
) -> ApiResult<WorkingDirectoryRemovalResponse> {
|
||||||
|
let source_actor = contract_workdir_removal_source_actor(&context)?;
|
||||||
|
cleanup_runtime_working_directory(
|
||||||
|
api,
|
||||||
|
ScopedRuntimeWorkingDirectoryPath {
|
||||||
|
workspace_id,
|
||||||
|
runtime_id,
|
||||||
|
working_directory_id,
|
||||||
|
},
|
||||||
|
source_actor,
|
||||||
|
request,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn cleanup_working_directory_contract(
|
||||||
|
api: WorkspaceApi,
|
||||||
|
workspace_id: String,
|
||||||
|
working_directory_id: String,
|
||||||
|
context: server_api::ServerRequestContext,
|
||||||
|
request: WorkingDirectoryRemovalRequest,
|
||||||
|
) -> ApiResult<WorkingDirectoryRemovalResponse> {
|
||||||
|
let source_actor = contract_workdir_removal_source_actor(&context)?;
|
||||||
|
cleanup_working_directory(
|
||||||
|
api,
|
||||||
|
ScopedWorkingDirectoryPath {
|
||||||
|
workspace_id,
|
||||||
|
working_directory_id,
|
||||||
|
},
|
||||||
|
source_actor,
|
||||||
|
request,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn cleanup_runtime_working_directory(
|
||||||
|
api: WorkspaceApi,
|
||||||
|
path: ScopedRuntimeWorkingDirectoryPath,
|
||||||
|
source_actor: String,
|
||||||
|
request: WorkingDirectoryRemovalRequest,
|
||||||
|
) -> ApiResult<WorkingDirectoryRemovalResponse> {
|
||||||
validate_workspace_scope(&api, &path.workspace_id)?;
|
validate_workspace_scope(&api, &path.workspace_id)?;
|
||||||
require_active_workspace_runtime_binding(&api, &path.runtime_id).await?;
|
require_active_workspace_runtime_binding(&api, &path.runtime_id).await?;
|
||||||
let registered_runtime = registered_workdir_runtime_id(&api, &path.working_directory_id)?;
|
let registered_runtime = registered_workdir_runtime_id(&api, &path.working_directory_id)?;
|
||||||
@@ -13774,22 +14300,12 @@ async fn scoped_cleanup_runtime_working_directory(
|
|||||||
"Workdir does not belong to the requested Runtime".to_string(),
|
"Workdir does not belong to the requested Runtime".to_string(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
let source_actor = if let Some(Extension(source)) = worker_source {
|
|
||||||
format!("worker:{}:{}", source.runtime_id, source.worker_id)
|
|
||||||
} else if let Some(Extension(actor)) = request_actor {
|
|
||||||
format!("account:{}", actor.account_id)
|
|
||||||
} else {
|
|
||||||
return Err(ApiError::from(Error::WorkspacePermissionDenied(
|
|
||||||
"Workdir removal requires authenticated source authority".to_string(),
|
|
||||||
)));
|
|
||||||
};
|
|
||||||
execute_workdir_removal(
|
execute_workdir_removal(
|
||||||
&api,
|
&api,
|
||||||
&path.working_directory_id,
|
&path.working_directory_id,
|
||||||
&source_actor,
|
&source_actor,
|
||||||
&request.reason,
|
&request.reason,
|
||||||
)
|
)
|
||||||
.map(Json)
|
|
||||||
.map_err(ApiError::from)
|
.map_err(ApiError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14736,30 +15252,19 @@ async fn scoped_working_directory_detail(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn scoped_cleanup_working_directory(
|
async fn cleanup_working_directory(
|
||||||
State(api): State<WorkspaceApi>,
|
api: WorkspaceApi,
|
||||||
AxumPath(path): AxumPath<ScopedWorkingDirectoryPath>,
|
path: ScopedWorkingDirectoryPath,
|
||||||
worker_source: Option<Extension<crate::worker_source::VerifiedWorkerMutationSource>>,
|
source_actor: String,
|
||||||
request_actor: Option<Extension<RequestActor>>,
|
request: WorkingDirectoryRemovalRequest,
|
||||||
Json(request): Json<WorkingDirectoryRemovalRequest>,
|
) -> ApiResult<WorkingDirectoryRemovalResponse> {
|
||||||
) -> ApiResult<Json<WorkingDirectoryRemovalResponse>> {
|
|
||||||
validate_workspace_scope(&api, &path.workspace_id)?;
|
validate_workspace_scope(&api, &path.workspace_id)?;
|
||||||
let source_actor = if let Some(Extension(source)) = worker_source {
|
|
||||||
format!("worker:{}:{}", source.runtime_id, source.worker_id)
|
|
||||||
} else if let Some(Extension(actor)) = request_actor {
|
|
||||||
format!("account:{}", actor.account_id)
|
|
||||||
} else {
|
|
||||||
return Err(ApiError::from(Error::WorkspacePermissionDenied(
|
|
||||||
"Workdir removal requires authenticated source authority".to_string(),
|
|
||||||
)));
|
|
||||||
};
|
|
||||||
execute_workdir_removal(
|
execute_workdir_removal(
|
||||||
&api,
|
&api,
|
||||||
&path.working_directory_id,
|
&path.working_directory_id,
|
||||||
&source_actor,
|
&source_actor,
|
||||||
&request.reason,
|
&request.reason,
|
||||||
)
|
)
|
||||||
.map(Json)
|
|
||||||
.map_err(ApiError::from)
|
.map_err(ApiError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15022,6 +15527,7 @@ async fn create_workspace_working_directory(
|
|||||||
.expect("Repository Workdir detail has Runtime"),
|
.expect("Repository Workdir detail has Runtime"),
|
||||||
item: response.item,
|
item: response.item,
|
||||||
diagnostics: response.diagnostics,
|
diagnostics: response.diagnostics,
|
||||||
|
http_status: StatusCode::OK.as_u16(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
@@ -15217,6 +15723,7 @@ async fn create_workspace_working_directory(
|
|||||||
runtime_id: reserved.resolved_runtime_id,
|
runtime_id: reserved.resolved_runtime_id,
|
||||||
item: summary.into(),
|
item: summary.into(),
|
||||||
diagnostics: working_directory_diagnostics(result.diagnostics),
|
diagnostics: working_directory_diagnostics(result.diagnostics),
|
||||||
|
http_status: StatusCode::CREATED.as_u16(),
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -16894,7 +17401,7 @@ async fn scoped_worker_protocol_ws(
|
|||||||
async fn scoped_list_host_workers(
|
async fn scoped_list_host_workers(
|
||||||
State(api): State<WorkspaceApi>,
|
State(api): State<WorkspaceApi>,
|
||||||
AxumPath(path): AxumPath<ScopedHostPath>,
|
AxumPath(path): AxumPath<ScopedHostPath>,
|
||||||
) -> ApiResult<Json<server_api::ListResponse<server_api::WorkerSummary>>> {
|
) -> ApiResult<Json<server_api::HostWorkerListResponse>> {
|
||||||
validate_workspace_scope(&api, &path.workspace_id)?;
|
validate_workspace_scope(&api, &path.workspace_id)?;
|
||||||
list_host_workers(State(api), AxumPath(path.host_id)).await
|
list_host_workers(State(api), AxumPath(path.host_id)).await
|
||||||
}
|
}
|
||||||
@@ -20394,14 +20901,14 @@ fn protocol_error_event(message: impl Into<String>) -> protocol::Event {
|
|||||||
async fn list_host_workers(
|
async fn list_host_workers(
|
||||||
State(api): State<WorkspaceApi>,
|
State(api): State<WorkspaceApi>,
|
||||||
AxumPath(host_id): AxumPath<String>,
|
AxumPath(host_id): AxumPath<String>,
|
||||||
) -> ApiResult<Json<server_api::ListResponse<server_api::WorkerSummary>>> {
|
) -> ApiResult<Json<server_api::HostWorkerListResponse>> {
|
||||||
let limit = api.config.max_records.min(200);
|
let limit = api.config.max_records.min(200);
|
||||||
let runtime_workers = api
|
let runtime_workers = api
|
||||||
.runtime
|
.runtime
|
||||||
.list_workers_for_host(&host_id, limit)
|
.list_workers_for_host(&host_id, limit)
|
||||||
.map_err(|err| err.into_error())?;
|
.map_err(|err| err.into_error())?;
|
||||||
let items = project_observed_workspace_workers(&api, runtime_workers.items)?;
|
let items = project_observed_workspace_workers(&api, runtime_workers.items)?;
|
||||||
Ok(Json(server_api::ListResponse {
|
Ok(Json(server_api::HostWorkerListResponse {
|
||||||
workspace_id: api.workspace_id().to_string(),
|
workspace_id: api.workspace_id().to_string(),
|
||||||
limit,
|
limit,
|
||||||
items,
|
items,
|
||||||
|
|||||||
+4815
-1
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,12 @@
|
|||||||
// @generated by yoi-repository-openapi-typescript@1. Do not edit.
|
// @generated by yoi-repository-openapi-typescript@1. Do not edit.
|
||||||
// Input: openapi/server-api.json
|
// Input: openapi/server-api.json
|
||||||
// Input contract: 0.1.0 (sha256:0026ff3d0f1d267e4de3f154a14f4ef3f7554b603a376820f0775e5deb16a083)
|
// Input contract: 0.1.0 (sha256:e3f776a17079ce202725bb97de607426f4bfad9afe390ba7bbf76186e871be59)
|
||||||
// Options: repository-operation-schema-closure,openapi-3.1,format:uint64=safe-number,strict-safe-integers,sorted-output
|
// Options: repository-operation-schema-closure,openapi-3.1,format:uint64=safe-number,strict-safe-integers,sorted-output
|
||||||
// Output: web/workspace/src/lib/generated/repository-api.ts
|
// Output: web/workspace/src/lib/generated/repository-api.ts
|
||||||
// Regenerate/check: cargo run -q -p server-api --example generate_repository_openapi_types -- --check
|
// Regenerate/check: cargo run -q -p server-api --example generate_repository_openapi_types -- --check
|
||||||
|
|
||||||
|
export type ConfirmRepositorySshHostTrustRequest = { expected_host_trust_revision?: number | null; host_key: string; operation_id: string; runtime_id: string; };
|
||||||
|
|
||||||
export type CreateWorkspaceRepositoryRequest = { default_ref?: string | null; repository_key: string; source: string; };
|
export type CreateWorkspaceRepositoryRequest = { default_ref?: string | null; repository_key: string; source: string; };
|
||||||
|
|
||||||
export type CreateWorkspaceRepositoryResponse = { replayed: boolean; repository_key: string; workspace_id: string; };
|
export type CreateWorkspaceRepositoryResponse = { replayed: boolean; repository_key: string; workspace_id: string; };
|
||||||
@@ -13,10 +15,18 @@ export type Diagnostic = { code: string; message: string; severity: DiagnosticSe
|
|||||||
|
|
||||||
export type DiagnosticSeverity = "info" | "warning" | "error";
|
export type DiagnosticSeverity = "info" | "warning" | "error";
|
||||||
|
|
||||||
|
export type GitCommitSummary = { author_date: string; author_email: string; author_name: string; hash: string; parents: Array<string>; refs: Array<string>; short_hash: string; summary: string; };
|
||||||
|
|
||||||
export type GitRemoteSummary = { fetch_url: string; name: string; };
|
export type GitRemoteSummary = { fetch_url: string; name: string; };
|
||||||
|
|
||||||
export type GitRepositorySummary = { branch?: string | null; dirty: boolean; head?: string | null; remotes: Array<GitRemoteSummary>; status: string; };
|
export type GitRepositorySummary = { branch?: string | null; dirty: boolean; head?: string | null; remotes: Array<GitRemoteSummary>; status: string; };
|
||||||
|
|
||||||
|
export type HostListResponse = { diagnostics: Array<Diagnostic>; items: Array<HostSummary>; limit: number; source: string; workspace_id: string; };
|
||||||
|
|
||||||
|
export type HostSummary = { arch: string; diagnostics: Array<Diagnostic>; host_id: string; kind: string; label: string; last_seen_at?: string | null; observed_at: string; os: string; runtime_id: string; status: string; };
|
||||||
|
|
||||||
|
export type HostWorkerListResponse = { diagnostics: Array<Diagnostic>; items: Array<WorkerSummary>; limit: number; source: string; workspace_id: string; };
|
||||||
|
|
||||||
export type RepositoryApiError = { diagnostics?: Array<Diagnostic>; error: string; message: string; };
|
export type RepositoryApiError = { diagnostics?: Array<Diagnostic>; error: string; message: string; };
|
||||||
|
|
||||||
export type RepositoryDetailResponse = { item: RepositorySummary; source: string; workspace_id: string; };
|
export type RepositoryDetailResponse = { item: RepositorySummary; source: string; workspace_id: string; };
|
||||||
@@ -25,10 +35,44 @@ export type RepositoryDiagnostic = { code: string; message: string; severity: st
|
|||||||
|
|
||||||
export type RepositoryListResponse = { diagnostics: Array<Diagnostic>; items: Array<RepositorySummary>; source: string; workspace_id: string; };
|
export type RepositoryListResponse = { diagnostics: Array<Diagnostic>; items: Array<RepositorySummary>; source: string; workspace_id: string; };
|
||||||
|
|
||||||
|
export type RepositoryLogResponse = { default_selector?: string | null; diagnostics: Array<Diagnostic>; items: Array<GitCommitSummary>; limit: number; repository_key: string; workspace_id: string; };
|
||||||
|
|
||||||
export type RepositoryObservedStatus = "unverified" | "ready" | "invalid";
|
export type RepositoryObservedStatus = "unverified" | "ready" | "invalid";
|
||||||
|
|
||||||
export type RepositorySource = { kind: RepositorySourceKind; uri: string; };
|
export type RepositorySource = { kind: RepositorySourceKind; uri: string; };
|
||||||
|
|
||||||
export type RepositorySourceKind = "local_path" | "file" | "ssh" | "https" | "invalid";
|
export type RepositorySourceKind = "local_path" | "file" | "ssh" | "https" | "invalid";
|
||||||
|
|
||||||
|
export type RepositorySshConnectionProbeRequest = { runtime_id: string; };
|
||||||
|
|
||||||
|
export type RepositorySshConnectionProbeResponse = { candidates: Array<RepositorySshHostKeyCandidate>; expected_host_trust_revision?: number | null; host_trust_id: string; hostname: string; port: number; repository_key: string; runtime_id: string; trust_state: RepositorySshConnectionTrustState; workspace_id: string; };
|
||||||
|
|
||||||
|
export type RepositorySshConnectionTrustState = "untrusted" | "verified" | "changed";
|
||||||
|
|
||||||
|
export type RepositorySshHostKeyCandidate = { algorithm: string; fingerprint: string; host_key: string; };
|
||||||
|
|
||||||
|
export type RepositorySshHostTrust = { created_at: string; current_revision: number; fingerprint: string; host_key: string; host_trust_id: string; hostname: string; key_algorithm: string; port: number; referenced_repositories?: Array<string>; updated_at: string; workspace_id: string; };
|
||||||
|
|
||||||
export type RepositorySummary = { default_selector?: string | null; diagnostics?: Array<RepositoryDiagnostic> | null; git?: GitRepositorySummary | null; kind: string; observed_at?: string | null; observed_status: RepositoryObservedStatus; provider: string; record_authority: string; repository_key: string; source: RepositorySource; source_fingerprint: string; source_revision: number; };
|
export type RepositorySummary = { default_selector?: string | null; diagnostics?: Array<RepositoryDiagnostic> | null; git?: GitRepositorySummary | null; kind: string; observed_at?: string | null; observed_status: RepositoryObservedStatus; provider: string; record_authority: string; repository_key: string; source: RepositorySource; source_fingerprint: string; source_revision: number; };
|
||||||
|
|
||||||
|
export type WorkerCapabilitySummary = { can_spawn_followup: boolean; can_stop: boolean; };
|
||||||
|
|
||||||
|
export type WorkerImplementationSummary = { display_hint: string; kind: string; };
|
||||||
|
|
||||||
|
export type WorkerSummary = { capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: unknown; workspace: WorkerWorkspaceSummary; };
|
||||||
|
|
||||||
|
export type WorkerWorkdirAttachmentSummary = { alias: string; working_directory: WorkingDirectorySummary; };
|
||||||
|
|
||||||
|
export type WorkerWorkspaceSummary = { identity: string; visibility: string; workspace_id?: string | null; };
|
||||||
|
|
||||||
|
export type WorkingDirectoryCleanupTarget = { kind: string; repository_key: string; working_directory_id: string; };
|
||||||
|
|
||||||
|
export type WorkingDirectoryMaterializerKind = "runtime_git_clone" | "client_hosted_external";
|
||||||
|
|
||||||
|
export type WorkingDirectoryOccupancy = { display_name: string; linked_at: string; runtime_id: string; worker_id: string; };
|
||||||
|
|
||||||
|
export type WorkingDirectorySource = { kind: "repository"; repository_key: string; } | { grant_id: string; kind: "external_grant"; };
|
||||||
|
|
||||||
|
export type WorkingDirectoryStatusKind = "active" | "cleanup_pending" | "corrupted" | "not_found" | "unknown";
|
||||||
|
|
||||||
|
export type WorkingDirectorySummary = { cleanliness?: string | null; cleanup_target?: WorkingDirectoryCleanupTarget | null; creation_ref?: string | null; creation_selector?: string | null; creation_tree?: string | null; current_ref?: string | null; current_selector?: string | null; current_tree?: string | null; display_name?: string | null; materializer_kind: WorkingDirectoryMaterializerKind; observed_at_epoch_seconds?: number | null; occupied_by?: WorkingDirectoryOccupancy | null; source: WorkingDirectorySource; status: WorkingDirectoryStatusKind; working_directory_id: string; };
|
||||||
|
|||||||
@@ -1,34 +1,110 @@
|
|||||||
// Generated from server-api. Do not edit by hand.
|
// @generated by yoi-workdir-openapi-typescript@1. Do not edit.
|
||||||
// Regenerate: cargo run -q -p server-api --features typescript --example generate_workdir_api_types > web/workspace/src/lib/generated/workdir-api.ts
|
// Input: openapi/server-api.json
|
||||||
|
// Input contract: 0.1.0 (sha256:e3f776a17079ce202725bb97de607426f4bfad9afe390ba7bbf76186e871be59)
|
||||||
|
// Options: workdir-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||||
|
// Output: web/workspace/src/lib/generated/workdir-api.ts
|
||||||
|
// Regenerate/check: cargo run -q -p server-api --example generate_workdir_api_types -- --check
|
||||||
|
|
||||||
|
export type CommandOutput = { content: string; exit_code?: number | null; next_cursor?: number | null; output_path?: string | null; status: CommandStatus; timed_out: boolean; truncated: boolean; };
|
||||||
|
|
||||||
|
export type CommandOutputRequest = { cursor: number; handle: string; limit: number; wait: boolean; };
|
||||||
|
|
||||||
|
export type CommandRequest = { command: string; cwd?: FsPath | null; output_limit: number; spill_dir?: string | null; timeout_secs: number; tool_call_id?: string | null; };
|
||||||
|
|
||||||
|
export type CommandStatus = "running" | "completed" | "failed" | "timed_out" | "cancelled";
|
||||||
|
|
||||||
|
export type CurrentWorkerWorkdirAttachRequest = { alias: string; working_directory_id: string; };
|
||||||
|
|
||||||
|
export type CurrentWorkerWorkdirAttachmentResponse = { alias: string; attached: boolean; capabilities: WorkdirSessionCapabilities; working_directory_id: string; workspace_id: string; };
|
||||||
|
|
||||||
|
export type CurrentWorkerWorkdirOperationRequest = { operation: WorkdirSessionOperation; target_workdir: string; };
|
||||||
|
|
||||||
|
export type Diagnostic = { code: string; message: string; severity: DiagnosticSeverity; };
|
||||||
|
|
||||||
export type DiagnosticSeverity = "info" | "warning" | "error";
|
export type DiagnosticSeverity = "info" | "warning" | "error";
|
||||||
|
|
||||||
export type Diagnostic = { code: string, severity: DiagnosticSeverity, message: string, };
|
export type EditRequest = { expected_hash: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number]; new_string: string; old_string: string; path: FsPath; replace_all: boolean; };
|
||||||
|
|
||||||
|
export type EditResult = { bytes_written: number; content_hash: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number]; replacements: number; };
|
||||||
|
|
||||||
|
export type EntryKind = "file" | "directory" | "symlink" | "other";
|
||||||
|
|
||||||
|
export type ExternalWorkdirGrantCreateRequest = { display_name: string; provider_instance_id: string; read_only: boolean; ttl_seconds: number; };
|
||||||
|
|
||||||
|
export type ExternalWorkdirGrantResponse = { display_name: string; expires_at: string; generation: number; grant_id: string; permissions: string; provider_instance_id: string; status: string; working_directory_id: string; workspace_id: string; };
|
||||||
|
|
||||||
|
export type FsPath = string;
|
||||||
|
|
||||||
|
export type GlobRequest = { limit: number; path: FsPath; pattern: string; };
|
||||||
|
|
||||||
|
export type GlobResult = { paths: Array<FsPath>; truncated: boolean; };
|
||||||
|
|
||||||
|
export type GrepOutputMode = "content" | "files_with_matches" | "count";
|
||||||
|
|
||||||
|
export type GrepRequest = { after_context: number; before_context: number; case_insensitive: boolean; file_type?: string | null; glob?: string | null; limit: number; multiline: boolean; offset: number; output_mode: GrepOutputMode; path: FsPath; pattern: string; };
|
||||||
|
|
||||||
|
export type GrepResult = { match_count: number; matched_files: number; output: string; truncated: boolean; };
|
||||||
|
|
||||||
|
export type ListEntry = { kind: EntryKind; path: FsPath; size: number; };
|
||||||
|
|
||||||
|
export type ListRequest = { limit: number; path: FsPath; };
|
||||||
|
|
||||||
|
export type ListResult = { entries: Array<ListEntry>; total_bytes: number; total_entries: number; truncated: boolean; };
|
||||||
|
|
||||||
|
export type ReadRequest = { limit: number; max_bytes: number; offset: number; path: FsPath; };
|
||||||
|
|
||||||
|
export type ReadResult = { bytes: Array<number>; content_hash: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number]; path: FsPath; start_line: number; total_lines: number; truncated: boolean; };
|
||||||
|
|
||||||
|
export type RepositoryApiError = { diagnostics?: Array<Diagnostic>; error: string; message: string; };
|
||||||
|
|
||||||
|
export type StatRequest = { path: FsPath; };
|
||||||
|
|
||||||
|
export type StatResult = { kind: EntryKind; path: FsPath; size: number; };
|
||||||
|
|
||||||
|
export type WorkdirOperationApiError = { code?: WorkdirTransportErrorCode | null; diagnostics?: Array<Diagnostic> | null; error?: string | null; message: string; };
|
||||||
|
|
||||||
|
export type WorkdirScopeAuthorizationRequest = { path: FsPath; permission: WorkdirToolScopePermission; rules: Array<WorkdirToolScopeRule>; };
|
||||||
|
|
||||||
|
export type WorkdirScopeOverlapRequest = { left: WorkdirToolScopeRule; right: WorkdirToolScopeRule; };
|
||||||
|
|
||||||
|
export type WorkdirSessionCapabilities = { bits: number; };
|
||||||
|
|
||||||
|
export type WorkdirSessionOperation = { operation: "authorize_scope"; request: WorkdirScopeAuthorizationRequest; } | { operation: "scope_rules_overlap"; request: WorkdirScopeOverlapRequest; } | { operation: "stat"; request: StatRequest; } | { operation: "read"; request: ReadRequest; } | { operation: "write"; request: WriteRequest; } | { operation: "edit"; request: EditRequest; } | { operation: "list"; request: ListRequest; } | { operation: "glob"; request: GlobRequest; } | { operation: "grep"; request: GrepRequest; } | { operation: "command_start"; request: CommandRequest; } | { operation: "command_status"; request: string; } | { operation: "command_output"; request: CommandOutputRequest; } | { operation: "command_cancel"; request: string; };
|
||||||
|
|
||||||
|
export type WorkdirSessionOperationResult = { operation: "authorize_scope"; } | { operation: "scope_rules_overlap"; result: { overlaps: boolean; }; } | { operation: "stat"; result: StatResult; } | { operation: "read"; result: ReadResult; } | { operation: "write"; result: WriteResult; } | { operation: "edit"; result: EditResult; } | { operation: "list"; result: ListResult; } | { operation: "glob"; result: GlobResult; } | { operation: "grep"; result: GrepResult; } | { operation: "command_start"; result: string; } | { operation: "command_status"; result: CommandStatus; } | { operation: "command_output"; result: CommandOutput; } | { operation: "command_cancel"; };
|
||||||
|
|
||||||
|
export type WorkdirToolScopePermission = "read" | "write";
|
||||||
|
|
||||||
|
export type WorkdirToolScopeRule = { permission: WorkdirToolScopePermission; recursive: boolean; symlink_policy?: string; target: FsPath; };
|
||||||
|
|
||||||
|
export type WorkdirTransportErrorCode = "not_found" | "conflict" | "unsupported" | "invalid_request" | "denied" | "out_of_scope" | "symlink_out_of_scope" | "broken_symlink" | "symlink_target_is_directory" | "read_only" | "is_directory" | "symlink_directory_not_traversed" | "unknown_command" | "unavailable" | "io" | "transport" | "internal";
|
||||||
|
|
||||||
|
export type WorkingDirectoryCleanupTarget = { kind: string; repository_key: string; working_directory_id: string; };
|
||||||
|
|
||||||
|
export type WorkingDirectoryCreateRequest = { display_name?: string | null; operation_id?: string | null; repository_key: string; runtime_id?: string | null; selector?: string | null; };
|
||||||
|
|
||||||
|
export type WorkingDirectoryCreateResponse = { diagnostics: Array<Diagnostic>; item: WorkingDirectorySummary; runtime_id: string; workspace_id: string; };
|
||||||
|
|
||||||
|
export type WorkingDirectoryDetailResponse = { diagnostics: Array<Diagnostic>; item: WorkingDirectorySummary; runtime_id?: string | null; workspace_id: string; };
|
||||||
|
|
||||||
|
export type WorkingDirectoryListResponse = { diagnostics: Array<Diagnostic>; items: Array<WorkingDirectorySummary>; workspace_id: string; };
|
||||||
|
|
||||||
export type WorkingDirectoryMaterializerKind = "runtime_git_clone" | "client_hosted_external";
|
export type WorkingDirectoryMaterializerKind = "runtime_git_clone" | "client_hosted_external";
|
||||||
|
|
||||||
|
export type WorkingDirectoryOccupancy = { display_name: string; linked_at: string; runtime_id: string; worker_id: string; };
|
||||||
|
|
||||||
|
export type WorkingDirectoryRemovalDisposition = "removed" | "retained" | "attention_required";
|
||||||
|
|
||||||
|
export type WorkingDirectoryRemovalRequest = { reason: string; };
|
||||||
|
|
||||||
|
export type WorkingDirectoryRemovalResponse = { disposition: WorkingDirectoryRemovalDisposition; failure_category?: string | null; retryable: boolean; working_directory_id: string; };
|
||||||
|
|
||||||
|
export type WorkingDirectorySource = { kind: "repository"; repository_key: string; } | { grant_id: string; kind: "external_grant"; };
|
||||||
|
|
||||||
export type WorkingDirectoryStatusKind = "active" | "cleanup_pending" | "corrupted" | "not_found" | "unknown";
|
export type WorkingDirectoryStatusKind = "active" | "cleanup_pending" | "corrupted" | "not_found" | "unknown";
|
||||||
|
|
||||||
export type WorkingDirectoryCleanupTarget = { kind: string, working_directory_id: string, repository_key: string, };
|
export type WorkingDirectorySummary = { cleanliness?: string | null; cleanup_target?: WorkingDirectoryCleanupTarget | null; creation_ref?: string | null; creation_selector?: string | null; creation_tree?: string | null; current_ref?: string | null; current_selector?: string | null; current_tree?: string | null; display_name?: string | null; materializer_kind: WorkingDirectoryMaterializerKind; observed_at_epoch_seconds?: number | null; occupied_by?: WorkingDirectoryOccupancy | null; source: WorkingDirectorySource; status: WorkingDirectoryStatusKind; working_directory_id: string; };
|
||||||
|
|
||||||
export type WorkingDirectoryOccupancy = { runtime_id: string, worker_id: string, display_name: string, linked_at: string, };
|
export type WriteRequest = { content: Array<number>; expected_hash?: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number] | null; path: FsPath; };
|
||||||
|
|
||||||
export type WorkingDirectorySource = { "kind": "repository", repository_key: string, } | { "kind": "external_grant", grant_id: string, };
|
export type WriteResult = { bytes_written: number; created: boolean; };
|
||||||
|
|
||||||
export type WorkingDirectorySummary = { working_directory_id: string,
|
|
||||||
/**
|
|
||||||
* Optional human-facing label, never a routing key.
|
|
||||||
*/
|
|
||||||
display_name?: string | null, source: WorkingDirectorySource, creation_selector?: string | null, creation_ref?: string | null, creation_tree?: string | null, current_selector?: string | null, current_ref?: string | null, current_tree?: string | null, observed_at_epoch_seconds?: number | null, materializer_kind: WorkingDirectoryMaterializerKind, cleanup_target?: WorkingDirectoryCleanupTarget | null, status: WorkingDirectoryStatusKind, cleanliness?: string | null, occupied_by?: WorkingDirectoryOccupancy | null, };
|
|
||||||
|
|
||||||
export type WorkingDirectoryCreateRequest = { runtime_id?: string | null,
|
|
||||||
/**
|
|
||||||
* Optional human-facing label, independent of every Worker attachment alias.
|
|
||||||
*/
|
|
||||||
display_name?: string | null, repository_key: string, selector?: string | null, operation_id?: string | null, };
|
|
||||||
|
|
||||||
export type WorkingDirectoryListResponse = { workspace_id: string, items: Array<WorkingDirectorySummary>, diagnostics: Array<Diagnostic>, };
|
|
||||||
|
|
||||||
export type WorkingDirectoryDetailResponse = { workspace_id: string, runtime_id?: string | null, item: WorkingDirectorySummary, diagnostics: Array<Diagnostic>, };
|
|
||||||
|
|
||||||
export type WorkingDirectoryCreateResponse = { workspace_id: string, runtime_id: string, item: WorkingDirectorySummary, diagnostics: Array<Diagnostic>, };
|
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
import type { ApiResult } from "$lib/workspace/api/http";
|
import type { ApiResult } from "$lib/workspace/api/http";
|
||||||
import type {
|
import type {
|
||||||
GitCommitSummary,
|
|
||||||
RepositoryLogResponse,
|
|
||||||
RepositorySshConnectionProbeResponse,
|
|
||||||
RepositorySshConnectionTrustState,
|
|
||||||
RepositorySshHostKeyCandidate,
|
|
||||||
WorkspaceAuthConfig,
|
WorkspaceAuthConfig,
|
||||||
WorkspaceCatalogListResponse,
|
WorkspaceCatalogListResponse,
|
||||||
WorkspaceCreateResponse,
|
WorkspaceCreateResponse,
|
||||||
@@ -24,22 +19,25 @@ import type {
|
|||||||
import type {
|
import type {
|
||||||
CreateWorkspaceRepositoryResponse,
|
CreateWorkspaceRepositoryResponse,
|
||||||
Diagnostic,
|
Diagnostic,
|
||||||
|
GitCommitSummary,
|
||||||
GitRemoteSummary,
|
GitRemoteSummary,
|
||||||
GitRepositorySummary,
|
GitRepositorySummary,
|
||||||
|
HostListResponse,
|
||||||
|
HostSummary,
|
||||||
RepositoryApiError,
|
RepositoryApiError,
|
||||||
RepositoryDetailResponse,
|
RepositoryDetailResponse,
|
||||||
RepositoryDiagnostic,
|
RepositoryDiagnostic,
|
||||||
RepositoryListResponse,
|
RepositoryListResponse,
|
||||||
|
RepositoryLogResponse,
|
||||||
RepositorySource,
|
RepositorySource,
|
||||||
RepositorySourceKind,
|
RepositorySourceKind,
|
||||||
|
RepositorySshConnectionProbeResponse,
|
||||||
|
RepositorySshConnectionTrustState,
|
||||||
|
RepositorySshHostKeyCandidate,
|
||||||
RepositorySummary,
|
RepositorySummary,
|
||||||
} from "$lib/generated/repository-api.ts";
|
} from "$lib/generated/repository-api.ts";
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
GitCommitSummary,
|
|
||||||
RepositoryLogResponse,
|
|
||||||
RepositorySshConnectionProbeResponse,
|
|
||||||
RepositorySshHostKeyCandidate,
|
|
||||||
WorkspaceCatalogListResponse,
|
WorkspaceCatalogListResponse,
|
||||||
WorkspaceCreateResponse,
|
WorkspaceCreateResponse,
|
||||||
WorkspaceDeletionOperationResponse,
|
WorkspaceDeletionOperationResponse,
|
||||||
@@ -51,13 +49,19 @@ export type {
|
|||||||
export type {
|
export type {
|
||||||
CreateWorkspaceRepositoryRequest,
|
CreateWorkspaceRepositoryRequest,
|
||||||
CreateWorkspaceRepositoryResponse,
|
CreateWorkspaceRepositoryResponse,
|
||||||
|
GitCommitSummary,
|
||||||
GitRemoteSummary,
|
GitRemoteSummary,
|
||||||
GitRepositorySummary,
|
GitRepositorySummary,
|
||||||
|
HostListResponse,
|
||||||
|
HostSummary,
|
||||||
RepositoryApiError,
|
RepositoryApiError,
|
||||||
RepositoryDetailResponse,
|
RepositoryDetailResponse,
|
||||||
RepositoryListResponse,
|
RepositoryListResponse,
|
||||||
|
RepositoryLogResponse,
|
||||||
RepositorySource,
|
RepositorySource,
|
||||||
RepositorySourceKind,
|
RepositorySourceKind,
|
||||||
|
RepositorySshConnectionProbeResponse,
|
||||||
|
RepositorySshHostKeyCandidate,
|
||||||
RepositorySummary,
|
RepositorySummary,
|
||||||
} from "$lib/generated/repository-api.ts";
|
} from "$lib/generated/repository-api.ts";
|
||||||
|
|
||||||
@@ -1094,6 +1098,77 @@ export function parseWorkspaceDeletionOperationResponse(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseHostListResponse(value: unknown): HostListResponse {
|
||||||
|
const response = object(value, "host list response");
|
||||||
|
exactKeys(
|
||||||
|
response,
|
||||||
|
["workspace_id", "limit", "items", "source", "diagnostics"],
|
||||||
|
"host list response",
|
||||||
|
);
|
||||||
|
const limit = repositorySourceRevision(
|
||||||
|
response.limit,
|
||||||
|
"host list response.limit",
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
workspace_id: repositoryString(
|
||||||
|
response.workspace_id,
|
||||||
|
"host list response.workspace_id",
|
||||||
|
),
|
||||||
|
limit,
|
||||||
|
items: repositoryArray(response.items, "host list response.items").map(
|
||||||
|
(item, index) => parseHostSummary(item, `host list response.items[${index}]`),
|
||||||
|
),
|
||||||
|
source: repositoryString(response.source, "host list response.source"),
|
||||||
|
diagnostics: repositoryArray(
|
||||||
|
response.diagnostics,
|
||||||
|
"host list response.diagnostics",
|
||||||
|
).map((item, index) =>
|
||||||
|
repositoryApiDiagnostic(
|
||||||
|
item,
|
||||||
|
`host list response.diagnostics[${index}]`,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseHostSummary(value: unknown, path: string): HostSummary {
|
||||||
|
const host = object(value, path);
|
||||||
|
exactKeys(
|
||||||
|
host,
|
||||||
|
[
|
||||||
|
"runtime_id",
|
||||||
|
"host_id",
|
||||||
|
"label",
|
||||||
|
"kind",
|
||||||
|
"status",
|
||||||
|
"observed_at",
|
||||||
|
"last_seen_at",
|
||||||
|
"os",
|
||||||
|
"arch",
|
||||||
|
"diagnostics",
|
||||||
|
],
|
||||||
|
path,
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
runtime_id: repositoryString(host.runtime_id, `${path}.runtime_id`),
|
||||||
|
host_id: repositoryString(host.host_id, `${path}.host_id`),
|
||||||
|
label: repositoryString(host.label, `${path}.label`),
|
||||||
|
kind: repositoryString(host.kind, `${path}.kind`),
|
||||||
|
status: repositoryString(host.status, `${path}.status`),
|
||||||
|
observed_at: repositoryString(host.observed_at, `${path}.observed_at`),
|
||||||
|
last_seen_at: optionalNullableRepositoryString(
|
||||||
|
host.last_seen_at,
|
||||||
|
`${path}.last_seen_at`,
|
||||||
|
),
|
||||||
|
os: repositoryString(host.os, `${path}.os`),
|
||||||
|
arch: repositoryString(host.arch, `${path}.arch`),
|
||||||
|
diagnostics: repositoryArray(host.diagnostics, `${path}.diagnostics`).map(
|
||||||
|
(item, index) =>
|
||||||
|
repositoryApiDiagnostic(item, `${path}.diagnostics[${index}]`),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function parseRepositoryLogResponse(
|
export function parseRepositoryLogResponse(
|
||||||
value: unknown,
|
value: unknown,
|
||||||
): RepositoryLogResponse {
|
): RepositoryLogResponse {
|
||||||
|
|||||||
@@ -71,19 +71,6 @@ export type Runtime = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Host = {
|
|
||||||
runtime_id: string;
|
|
||||||
host_id: string;
|
|
||||||
label: string;
|
|
||||||
kind: string;
|
|
||||||
status: string;
|
|
||||||
observed_at: string;
|
|
||||||
last_seen_at: string | null;
|
|
||||||
os: string;
|
|
||||||
arch: string;
|
|
||||||
diagnostics: Diagnostic[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WorkerCapabilities = {
|
export type WorkerCapabilities = {
|
||||||
can_stop: boolean;
|
can_stop: boolean;
|
||||||
can_spawn_followup: boolean;
|
can_spawn_followup: boolean;
|
||||||
|
|||||||
@@ -1,10 +1,24 @@
|
|||||||
import { loadJson, workspaceApiPath } from "$lib/workspace/api/http";
|
import { loadJson, workspaceApiPath } from "$lib/workspace/api/http";
|
||||||
import type { Host, ListResponse } from "$lib/workspace/sidebar/types";
|
import {
|
||||||
|
parseHostListResponse,
|
||||||
|
type HostListResponse,
|
||||||
|
} from "$lib/workspace/api/workspace-model";
|
||||||
import type { PageLoad } from "./$types";
|
import type { PageLoad } from "./$types";
|
||||||
|
|
||||||
|
const HOST_API_LOAD_POLICY = {
|
||||||
|
diagnosticLabel: "Host API",
|
||||||
|
maxResponseBytes: 4 * 1024 * 1024,
|
||||||
|
} as const;
|
||||||
|
|
||||||
export const load: PageLoad = async ({ fetch, params }) => {
|
export const load: PageLoad = async ({ fetch, params }) => {
|
||||||
const apiPath = (path: string) => workspaceApiPath(params.workspaceId, path);
|
const apiPath = (path: string) => workspaceApiPath(params.workspaceId, path);
|
||||||
const hosts = await loadJson<ListResponse<Host>>(fetch, apiPath("/hosts"));
|
const hosts = await loadJson<HostListResponse>(
|
||||||
|
fetch,
|
||||||
|
apiPath("/hosts"),
|
||||||
|
undefined,
|
||||||
|
parseHostListResponse,
|
||||||
|
HOST_API_LOAD_POLICY,
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
workspaceId: params.workspaceId,
|
workspaceId: params.workspaceId,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
ConfirmRepositorySshHostTrustRequest,
|
ConfirmRepositorySshHostTrustRequest,
|
||||||
RepositorySshConnectionProbeRequest,
|
RepositorySshConnectionProbeRequest,
|
||||||
RepositorySshConnectionProbeResponse
|
RepositorySshConnectionProbeResponse
|
||||||
} from '$lib/generated/legacy-server-api';
|
} from '$lib/generated/repository-api';
|
||||||
import { parseRepositorySshHostTrust } from '$lib/workspace/api/repository-access';
|
import { parseRepositorySshHostTrust } from '$lib/workspace/api/repository-access';
|
||||||
import { formatDate, workspaceApiPath } from '$lib/workspace/api/http';
|
import { formatDate, workspaceApiPath } from '$lib/workspace/api/http';
|
||||||
import { parseRepositorySshConnectionProbeResponse } from '$lib/workspace/api/workspace-model';
|
import { parseRepositorySshConnectionProbeResponse } from '$lib/workspace/api/workspace-model';
|
||||||
|
|||||||
Reference in New Issue
Block a user