mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-07 03:00:29 +00:00
feat(server): add Daytona VNC preview endpoint
Adds the sandbox VNC API contract, Daytona Computer Use startup flow, signed noVNC preview response, and generated TypeScript client support.
This commit is contained in:
parent
36c5a86005
commit
ac90bb199c
9 changed files with 504 additions and 34 deletions
|
|
@ -2653,6 +2653,49 @@ paths:
|
|||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
|
||||
/api/v1/runs/{id}/sandbox/vnc:
|
||||
post:
|
||||
operationId: createSandboxVncPreview
|
||||
tags: [Human-in-the-Loop]
|
||||
summary: Create Sandbox VNC Preview
|
||||
description: Starts or ensures Daytona Computer Use for the run sandbox and returns a signed noVNC preview URL.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/RunId"
|
||||
responses:
|
||||
"201":
|
||||
description: Signed noVNC preview URL created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/VncPreviewResponse"
|
||||
"404":
|
||||
description: Run not found
|
||||
headers:
|
||||
x-request-id:
|
||||
$ref: "#/components/headers/XRequestId"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
"409":
|
||||
description: Run has no active sandbox, Computer Use startup failed, or signed preview generation failed
|
||||
headers:
|
||||
x-request-id:
|
||||
$ref: "#/components/headers/XRequestId"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
"501":
|
||||
description: Sandbox provider does not support VNC previews
|
||||
headers:
|
||||
x-request-id:
|
||||
$ref: "#/components/headers/XRequestId"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
|
||||
/api/v1/runs/{id}/sandbox/files:
|
||||
get:
|
||||
operationId: listSandboxFiles
|
||||
|
|
@ -7910,6 +7953,35 @@ components:
|
|||
items:
|
||||
$ref: "#/components/schemas/SandboxFileEntry"
|
||||
|
||||
VncPreviewResponse:
|
||||
description: Response containing a signed noVNC preview URL for a Daytona sandbox.
|
||||
type: object
|
||||
required:
|
||||
- url
|
||||
- provider
|
||||
- port
|
||||
- expires_in_secs
|
||||
properties:
|
||||
url:
|
||||
type: string
|
||||
description: Signed noVNC preview URL.
|
||||
example: "https://preview.example.com/sb-a1b2c3d4/6080?token=..."
|
||||
provider:
|
||||
type: string
|
||||
description: Sandbox provider that produced the VNC preview.
|
||||
example: daytona
|
||||
port:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 65535
|
||||
description: noVNC port exposed by the sandbox.
|
||||
example: 6080
|
||||
expires_in_secs:
|
||||
type: integer
|
||||
minimum: 1
|
||||
description: Signed URL time-to-live in seconds.
|
||||
example: 3600
|
||||
|
||||
# ── Insights Schemas ─────────────────────────────────────────────────
|
||||
|
||||
SavedQuery:
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ pub use fabro_api::types::{
|
|||
RunError, RunManifest, RunStage, RunStatusResponse, SandboxDetails, SandboxFileEntry,
|
||||
SandboxFileListResponse, SshAccessRequest, SshAccessResponse, StageHandler, StageState,
|
||||
StartRunRequest, SubmitAnswerRequest, SystemFeatures, SystemInfoResponse, SystemRepairRunIssue,
|
||||
SystemRepairRunsResponse, SystemRunCounts, TimelineEntryResponse, WriteBlobResponse,
|
||||
SystemRepairRunsResponse, SystemRunCounts, TimelineEntryResponse, VncPreviewResponse,
|
||||
WriteBlobResponse,
|
||||
};
|
||||
use fabro_auth::{
|
||||
CredentialSource, VaultCredentialSource, auth_issue_message, parse_credential_secret,
|
||||
|
|
|
|||
|
|
@ -1,18 +1,59 @@
|
|||
use std::num::NonZeroU64;
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::extract::ws::{Message as WsMessage, WebSocket, WebSocketUpgrade};
|
||||
use fabro_sandbox::{TerminalSize, open_terminal_for_run};
|
||||
use futures_util::FutureExt;
|
||||
use futures_util::future::BoxFuture;
|
||||
|
||||
use super::super::{
|
||||
ApiError, AppState, Bytes, DaytonaSandbox, EnvVars, HeaderMap, IntoResponse, Json,
|
||||
NamedTempFile, Path, PreviewUrlRequest, PreviewUrlResponse, Query, RequiredUser, Response,
|
||||
Router, RunId, Sandbox, SandboxDetails, SandboxFileEntry, SandboxFileListResponse,
|
||||
SandboxProvider, SshAccessRequest, SshAccessResponse, State, StatusCode, collect_causes, fs,
|
||||
get, octet_stream_response, parse_run_id_path, post, reconnect_for_run, reject_if_archived,
|
||||
render_with_causes, sandbox_details,
|
||||
SandboxProvider, SshAccessRequest, SshAccessResponse, State, StatusCode, VncPreviewResponse,
|
||||
collect_causes, fs, get, octet_stream_response, parse_run_id_path, post, reconnect_for_run,
|
||||
reject_if_archived, render_with_causes, sandbox_details,
|
||||
};
|
||||
|
||||
const MAX_TERMINAL_CONTROL_BYTES: usize = 4096;
|
||||
const DEFAULT_VNC_NO_VNC_PORT: u16 = 6080;
|
||||
const DEFAULT_VNC_TTL_SECS: i32 = 3600;
|
||||
|
||||
trait VncSandbox {
|
||||
fn start_computer_use(&self) -> BoxFuture<'_, fabro_sandbox::Result<()>>;
|
||||
fn signed_preview_url(
|
||||
&self,
|
||||
port: u16,
|
||||
expires_in_secs: i32,
|
||||
) -> BoxFuture<'_, fabro_sandbox::Result<String>>;
|
||||
}
|
||||
|
||||
impl VncSandbox for DaytonaSandbox {
|
||||
fn start_computer_use(&self) -> BoxFuture<'_, fabro_sandbox::Result<()>> {
|
||||
async move {
|
||||
let computer_use = self.computer_use().await?;
|
||||
computer_use
|
||||
.start()
|
||||
.await
|
||||
.map_err(|err| fabro_sandbox::Error::context("Failed to start Computer Use", err))
|
||||
.map(|_| ())
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn signed_preview_url(
|
||||
&self,
|
||||
port: u16,
|
||||
expires_in_secs: i32,
|
||||
) -> BoxFuture<'_, fabro_sandbox::Result<String>> {
|
||||
async move {
|
||||
self.get_signed_preview_url(port, Some(expires_in_secs))
|
||||
.await
|
||||
.map(|preview| preview.url)
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn routes() -> Router<Arc<AppState>> {
|
||||
Router::new()
|
||||
|
|
@ -20,6 +61,7 @@ pub(super) fn routes() -> Router<Arc<AppState>> {
|
|||
.route("/runs/{id}/ssh", post(create_ssh_access))
|
||||
.route("/runs/{id}/terminal", get(run_terminal))
|
||||
.route("/runs/{id}/sandbox", get(retrieve_run_sandbox))
|
||||
.route("/runs/{id}/sandbox/vnc", post(create_sandbox_vnc_preview))
|
||||
.route("/runs/{id}/sandbox/files", get(list_sandbox_files))
|
||||
.route(
|
||||
"/runs/{id}/sandbox/file",
|
||||
|
|
@ -374,6 +416,60 @@ async fn create_ssh_access(
|
|||
}
|
||||
}
|
||||
|
||||
async fn create_sandbox_vnc_preview(
|
||||
_auth: RequiredUser,
|
||||
State(state): State<Arc<AppState>>,
|
||||
Path(id): Path<String>,
|
||||
) -> Response {
|
||||
let id = match parse_run_id_path(&id) {
|
||||
Ok(id) => id,
|
||||
Err(response) => return response,
|
||||
};
|
||||
let record = match load_run_sandbox_record(&state, &id).await {
|
||||
Ok(record) => record,
|
||||
Err(response) => return response,
|
||||
};
|
||||
if record.provider != SandboxProvider::Daytona.to_string() {
|
||||
return ApiError::new(
|
||||
StatusCode::NOT_IMPLEMENTED,
|
||||
"Sandbox provider does not support VNC previews.",
|
||||
)
|
||||
.into_response();
|
||||
}
|
||||
let sandbox = match reconnect_daytona_sandbox(&state, &id).await {
|
||||
Ok(sandbox) => sandbox,
|
||||
Err(response) => return response,
|
||||
};
|
||||
match build_vnc_preview_response(&sandbox).await {
|
||||
Ok(response) => (StatusCode::CREATED, Json(response)).into_response(),
|
||||
Err(response) => response,
|
||||
}
|
||||
}
|
||||
|
||||
async fn build_vnc_preview_response(
|
||||
sandbox: &impl VncSandbox,
|
||||
) -> Result<VncPreviewResponse, Response> {
|
||||
sandbox.start_computer_use().await.map_err(|err| {
|
||||
ApiError::new(StatusCode::CONFLICT, err.display_with_causes()).into_response()
|
||||
})?;
|
||||
let url = sandbox
|
||||
.signed_preview_url(DEFAULT_VNC_NO_VNC_PORT, DEFAULT_VNC_TTL_SECS)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
ApiError::new(StatusCode::CONFLICT, err.display_with_causes()).into_response()
|
||||
})?;
|
||||
Ok(VncPreviewResponse {
|
||||
expires_in_secs: NonZeroU64::new(
|
||||
u64::try_from(DEFAULT_VNC_TTL_SECS).expect("default VNC TTL should fit in u64"),
|
||||
)
|
||||
.expect("default VNC TTL should be nonzero"),
|
||||
port: NonZeroU64::new(u64::from(DEFAULT_VNC_NO_VNC_PORT))
|
||||
.expect("default VNC port should be nonzero"),
|
||||
provider: "daytona".to_string(),
|
||||
url,
|
||||
})
|
||||
}
|
||||
|
||||
async fn list_sandbox_files(
|
||||
_auth: RequiredUser,
|
||||
State(state): State<Arc<AppState>>,
|
||||
|
|
@ -579,6 +675,7 @@ async fn load_run_sandbox_record_or_not_found(
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use axum::http::{HeaderMap, HeaderValue};
|
||||
use futures_util::FutureExt;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
@ -623,6 +720,87 @@ mod tests {
|
|||
headers.insert("origin", HeaderValue::from_static("https://evil.example"));
|
||||
assert!(!origin_allowed(&headers));
|
||||
}
|
||||
|
||||
struct FakeVncSandbox {
|
||||
start_error: Option<&'static str>,
|
||||
signed_url_error: Option<&'static str>,
|
||||
signed_url: &'static str,
|
||||
}
|
||||
|
||||
impl VncSandbox for FakeVncSandbox {
|
||||
fn start_computer_use(
|
||||
&self,
|
||||
) -> futures_util::future::BoxFuture<'_, fabro_sandbox::Result<()>> {
|
||||
async move {
|
||||
match self.start_error {
|
||||
Some(message) => Err(fabro_sandbox::Error::message(message)),
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn signed_preview_url(
|
||||
&self,
|
||||
port: u16,
|
||||
expires_in_secs: i32,
|
||||
) -> futures_util::future::BoxFuture<'_, fabro_sandbox::Result<String>> {
|
||||
async move {
|
||||
assert_eq!(port, DEFAULT_VNC_NO_VNC_PORT);
|
||||
assert_eq!(expires_in_secs, DEFAULT_VNC_TTL_SECS);
|
||||
match self.signed_url_error {
|
||||
Some(message) => Err(fabro_sandbox::Error::message(message)),
|
||||
None => Ok(self.signed_url.to_string()),
|
||||
}
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn vnc_preview_response_uses_daytona_defaults() {
|
||||
let sandbox = FakeVncSandbox {
|
||||
start_error: None,
|
||||
signed_url_error: None,
|
||||
signed_url: "https://preview.example.test/sandbox/6080",
|
||||
};
|
||||
|
||||
let response = build_vnc_preview_response(&sandbox).await.unwrap();
|
||||
|
||||
assert_eq!(response.url, "https://preview.example.test/sandbox/6080");
|
||||
assert_eq!(response.provider, "daytona");
|
||||
assert_eq!(response.port.get(), u64::from(DEFAULT_VNC_NO_VNC_PORT));
|
||||
assert_eq!(
|
||||
response.expires_in_secs.get(),
|
||||
u64::try_from(DEFAULT_VNC_TTL_SECS).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn vnc_preview_response_maps_computer_use_start_failure_to_conflict() {
|
||||
let sandbox = FakeVncSandbox {
|
||||
start_error: Some("computer use failed"),
|
||||
signed_url_error: None,
|
||||
signed_url: "https://preview.example.test/sandbox/6080",
|
||||
};
|
||||
|
||||
let response = build_vnc_preview_response(&sandbox).await.unwrap_err();
|
||||
|
||||
assert_eq!(response.status(), StatusCode::CONFLICT);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn vnc_preview_response_maps_signed_preview_failure_to_conflict() {
|
||||
let sandbox = FakeVncSandbox {
|
||||
start_error: None,
|
||||
signed_url_error: Some("preview failed"),
|
||||
signed_url: "https://preview.example.test/sandbox/6080",
|
||||
};
|
||||
|
||||
let response = build_vnc_preview_response(&sandbox).await.unwrap_err();
|
||||
|
||||
assert_eq!(response.status(), StatusCode::CONFLICT);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -643,6 +821,14 @@ mod retrieve_sandbox_tests {
|
|||
.expect("sandbox details GET request should build")
|
||||
}
|
||||
|
||||
fn req_post(uri: &str) -> Request<Body> {
|
||||
Request::builder()
|
||||
.method("POST")
|
||||
.uri(uri)
|
||||
.body(Body::empty())
|
||||
.expect("sandbox POST request should build")
|
||||
}
|
||||
|
||||
async fn body_json(response: axum::response::Response) -> Value {
|
||||
let bytes = to_bytes(response.into_body(), usize::MAX)
|
||||
.await
|
||||
|
|
@ -669,6 +855,28 @@ mod retrieve_sandbox_tests {
|
|||
run_store.append_event(&payload).await.unwrap();
|
||||
}
|
||||
|
||||
async fn append_sandbox_initialized(
|
||||
run_store: &fabro_store::RunDatabase,
|
||||
run_id: &RunId,
|
||||
provider: &str,
|
||||
) {
|
||||
let payload = fabro_store::EventPayload::new(
|
||||
json!({
|
||||
"id": "evt-sandbox-init",
|
||||
"ts": "2026-05-09T12:00:00Z",
|
||||
"run_id": run_id,
|
||||
"event": "sandbox.initialized",
|
||||
"properties": {
|
||||
"provider": provider,
|
||||
"working_directory": "/workspace",
|
||||
},
|
||||
}),
|
||||
run_id,
|
||||
)
|
||||
.expect("sandbox.initialized payload should validate");
|
||||
run_store.append_event(&payload).await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn missing_run_returns_404() {
|
||||
let app = build_test_router(test_app_state());
|
||||
|
|
@ -725,21 +933,7 @@ mod retrieve_sandbox_tests {
|
|||
.await
|
||||
.expect("test run should be creatable");
|
||||
append_run_created(&run_store, &run_id).await;
|
||||
let payload = fabro_store::EventPayload::new(
|
||||
json!({
|
||||
"id": "evt-sandbox-init",
|
||||
"ts": "2026-05-09T12:00:00Z",
|
||||
"run_id": run_id,
|
||||
"event": "sandbox.initialized",
|
||||
"properties": {
|
||||
"provider": "local",
|
||||
"working_directory": "/workspace",
|
||||
},
|
||||
}),
|
||||
&run_id,
|
||||
)
|
||||
.expect("sandbox.initialized payload should validate");
|
||||
run_store.append_event(&payload).await.unwrap();
|
||||
append_sandbox_initialized(&run_store, &run_id, "local").await;
|
||||
|
||||
let response = app
|
||||
.oneshot(req_get(&format!("/api/v1/runs/{run_id}/sandbox")))
|
||||
|
|
@ -764,21 +958,7 @@ mod retrieve_sandbox_tests {
|
|||
.await
|
||||
.expect("test run should be creatable");
|
||||
append_run_created(&run_store, &run_id).await;
|
||||
let payload = fabro_store::EventPayload::new(
|
||||
json!({
|
||||
"id": "evt-sandbox-init",
|
||||
"ts": "2026-05-09T12:00:00Z",
|
||||
"run_id": run_id,
|
||||
"event": "sandbox.initialized",
|
||||
"properties": {
|
||||
"provider": "ephemeral-mystery-cloud",
|
||||
"working_directory": "/workspace",
|
||||
},
|
||||
}),
|
||||
&run_id,
|
||||
)
|
||||
.expect("sandbox.initialized payload should validate");
|
||||
run_store.append_event(&payload).await.unwrap();
|
||||
append_sandbox_initialized(&run_store, &run_id, "ephemeral-mystery-cloud").await;
|
||||
|
||||
let response = app
|
||||
.oneshot(req_get(&format!("/api/v1/runs/{run_id}/sandbox")))
|
||||
|
|
@ -786,4 +966,46 @@ mod retrieve_sandbox_tests {
|
|||
.unwrap();
|
||||
assert_eq!(response.status(), StatusCode::NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn local_sandbox_vnc_returns_501() {
|
||||
let state = test_app_state();
|
||||
let app = build_test_router(state.clone());
|
||||
let run_id = RunId::new();
|
||||
let run_store = state
|
||||
.store_ref()
|
||||
.create_run(&run_id)
|
||||
.await
|
||||
.expect("test run should be creatable");
|
||||
append_run_created(&run_store, &run_id).await;
|
||||
append_sandbox_initialized(&run_store, &run_id, "local").await;
|
||||
|
||||
let response = app
|
||||
.oneshot(req_post(&format!("/api/v1/runs/{run_id}/sandbox/vnc")))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(response.status(), StatusCode::NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn docker_sandbox_vnc_returns_501_without_reconnect() {
|
||||
let state = test_app_state();
|
||||
let app = build_test_router(state.clone());
|
||||
let run_id = RunId::new();
|
||||
let run_store = state
|
||||
.store_ref()
|
||||
.create_run(&run_id)
|
||||
.await
|
||||
.expect("test run should be creatable");
|
||||
append_run_created(&run_store, &run_id).await;
|
||||
append_sandbox_initialized(&run_store, &run_id, "docker").await;
|
||||
|
||||
let response = app
|
||||
.oneshot(req_post(&format!("/api/v1/runs/{run_id}/sandbox/vnc")))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(response.status(), StatusCode::NOT_IMPLEMENTED);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ mod install_openai_compatible;
|
|||
mod routing;
|
||||
mod run_files;
|
||||
mod runs;
|
||||
mod sandbox_vnc;
|
||||
mod settings;
|
||||
mod system;
|
||||
mod tcp;
|
||||
|
|
|
|||
58
lib/crates/fabro-server/tests/it/api/sandbox_vnc.rs
Normal file
58
lib/crates/fabro-server/tests/it/api/sandbox_vnc.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
use axum::body::Body;
|
||||
use axum::http::{Request, StatusCode};
|
||||
use tower::ServiceExt;
|
||||
|
||||
use crate::helpers::{
|
||||
MINIMAL_DOT, api, minimal_manifest_json, response_json, response_status, test_app_state,
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
async fn vnc_for_missing_run_returns_not_found() {
|
||||
let app = fabro_server::test_support::build_test_router(test_app_state());
|
||||
let fake = "01ARZ3NDEKTSV4RRFFQ69G5FAV";
|
||||
let req = Request::builder()
|
||||
.method("POST")
|
||||
.uri(api(&format!("/runs/{fake}/sandbox/vnc")))
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
|
||||
let response = app.oneshot(req).await.unwrap();
|
||||
|
||||
response_status(
|
||||
response,
|
||||
StatusCode::NOT_FOUND,
|
||||
"POST /api/v1/runs/{id}/sandbox/vnc",
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn vnc_for_run_without_sandbox_returns_conflict() {
|
||||
let app = fabro_server::test_support::build_test_router(test_app_state());
|
||||
let create_req = Request::builder()
|
||||
.method("POST")
|
||||
.uri(api("/runs"))
|
||||
.header("content-type", "application/json")
|
||||
.body(Body::from(
|
||||
serde_json::to_string(&minimal_manifest_json(MINIMAL_DOT)).unwrap(),
|
||||
))
|
||||
.unwrap();
|
||||
let create_response = app.clone().oneshot(create_req).await.unwrap();
|
||||
let create_body =
|
||||
response_json(create_response, StatusCode::CREATED, "POST /api/v1/runs").await;
|
||||
let run_id = create_body["id"].as_str().unwrap();
|
||||
let req = Request::builder()
|
||||
.method("POST")
|
||||
.uri(api(&format!("/runs/{run_id}/sandbox/vnc")))
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
|
||||
let response = app.oneshot(req).await.unwrap();
|
||||
|
||||
response_status(
|
||||
response,
|
||||
StatusCode::CONFLICT,
|
||||
format!("POST /api/v1/runs/{run_id}/sandbox/vnc"),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
|
@ -346,6 +346,7 @@ models/tls-mode.ts
|
|||
models/update-run-request.ts
|
||||
models/user-response.ts
|
||||
models/validate-response.ts
|
||||
models/vnc-preview-response.ts
|
||||
models/webhook-strategy.ts
|
||||
models/workflow-detail-response.ts
|
||||
models/workflow-diagnostic.ts
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ import type { SshAccessResponse } from '../models';
|
|||
import type { SteerRunRequest } from '../models';
|
||||
// @ts-ignore
|
||||
import type { SubmitAnswerRequest } from '../models';
|
||||
// @ts-ignore
|
||||
import type { VncPreviewResponse } from '../models';
|
||||
/**
|
||||
* HumanInTheLoopApi - axios parameter creator
|
||||
*/
|
||||
|
|
@ -91,6 +93,46 @@ export const HumanInTheLoopApiAxiosParamCreator = function (configuration?: Conf
|
|||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Starts or ensures Daytona Computer Use for the run sandbox and returns a signed noVNC preview URL.
|
||||
* @summary Create Sandbox VNC Preview
|
||||
* @param {string} id Unique run identifier (ULID).
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
createSandboxVncPreview: async (id: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'id' is not null or undefined
|
||||
assertParamExists('createSandboxVncPreview', 'id', id)
|
||||
const localVarPath = `/api/v1/runs/{id}/sandbox/vnc`
|
||||
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
let baseOptions;
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions;
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
|
||||
const localVarHeaderParameter = {} as any;
|
||||
const localVarQueryParameter = {} as any;
|
||||
|
||||
// authentication SessionCookie required
|
||||
|
||||
// authentication BearerAuth required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
localVarHeaderParameter['Accept'] = 'application/json';
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Generates a preview URL for a port exposed by the run\'s sandbox environment.
|
||||
* @summary Preview URL
|
||||
|
|
@ -534,6 +576,19 @@ export const HumanInTheLoopApiFp = function(configuration?: Configuration) {
|
|||
const localVarOperationServerBasePath = operationServerMap['HumanInTheLoopApi.createRunSshAccess']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
* Starts or ensures Daytona Computer Use for the run sandbox and returns a signed noVNC preview URL.
|
||||
* @summary Create Sandbox VNC Preview
|
||||
* @param {string} id Unique run identifier (ULID).
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async createSandboxVncPreview(id: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<VncPreviewResponse>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.createSandboxVncPreview(id, options);
|
||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||
const localVarOperationServerBasePath = operationServerMap['HumanInTheLoopApi.createSandboxVncPreview']?.[localVarOperationServerIndex]?.url;
|
||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||
},
|
||||
/**
|
||||
* Generates a preview URL for a port exposed by the run\'s sandbox environment.
|
||||
* @summary Preview URL
|
||||
|
|
@ -682,6 +737,16 @@ export const HumanInTheLoopApiFactory = function (configuration?: Configuration,
|
|||
createRunSshAccess(id: string, sshAccessRequest: SshAccessRequest, options?: RawAxiosRequestConfig): AxiosPromise<SshAccessResponse> {
|
||||
return localVarFp.createRunSshAccess(id, sshAccessRequest, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* Starts or ensures Daytona Computer Use for the run sandbox and returns a signed noVNC preview URL.
|
||||
* @summary Create Sandbox VNC Preview
|
||||
* @param {string} id Unique run identifier (ULID).
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
createSandboxVncPreview(id: string, options?: RawAxiosRequestConfig): AxiosPromise<VncPreviewResponse> {
|
||||
return localVarFp.createSandboxVncPreview(id, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
* Generates a preview URL for a port exposed by the run\'s sandbox environment.
|
||||
* @summary Preview URL
|
||||
|
|
@ -802,6 +867,17 @@ export class HumanInTheLoopApi extends BaseAPI {
|
|||
return HumanInTheLoopApiFp(this.configuration).createRunSshAccess(id, sshAccessRequest, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts or ensures Daytona Computer Use for the run sandbox and returns a signed noVNC preview URL.
|
||||
* @summary Create Sandbox VNC Preview
|
||||
* @param {string} id Unique run identifier (ULID).
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
public createSandboxVncPreview(id: string, options?: RawAxiosRequestConfig) {
|
||||
return HumanInTheLoopApiFp(this.configuration).createSandboxVncPreview(id, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a preview URL for a port exposed by the run\'s sandbox environment.
|
||||
* @summary Preview URL
|
||||
|
|
|
|||
|
|
@ -323,6 +323,7 @@ export * from './tls-mode';
|
|||
export * from './update-run-request';
|
||||
export * from './user-response';
|
||||
export * from './validate-response';
|
||||
export * from './vnc-preview-response';
|
||||
export * from './webhook-strategy';
|
||||
export * from './workflow-detail-response';
|
||||
export * from './workflow-diagnostic';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Fabro Run API
|
||||
* HTTP API for managing Fabro workflow run executions.
|
||||
*
|
||||
* The version of the OpenAPI document: 0.1.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Response containing a signed noVNC preview URL for a Daytona sandbox.
|
||||
*/
|
||||
export interface VncPreviewResponse {
|
||||
/**
|
||||
* Signed noVNC preview URL.
|
||||
*/
|
||||
'url': string;
|
||||
/**
|
||||
* Sandbox provider that produced the VNC preview.
|
||||
*/
|
||||
'provider': string;
|
||||
/**
|
||||
* noVNC port exposed by the sandbox.
|
||||
*/
|
||||
'port': number;
|
||||
/**
|
||||
* Signed URL time-to-live in seconds.
|
||||
*/
|
||||
'expires_in_secs': number;
|
||||
}
|
||||
|
||||
Loading…
Add table
Reference in a new issue