feat: builder-style InputSpec API, prefill plumbing, and port forward fix

- Add addKey() and add() builder methods to InputSpec with InputSpecTools
- Move OuterType to last generic param on Value, List, and all dynamic methods
- Plumb prefill through getActionInput end-to-end (core → container-runtime → SDK)
- Filter port_forwards to enabled addresses only
- Bump SDK to 0.4.0-beta.50
This commit is contained in:
Aiden McClelland
2026-02-19 16:44:44 -07:00
parent 4527046f2e
commit 7909941b70
21 changed files with 688 additions and 250 deletions

View File

@@ -67,6 +67,10 @@ pub struct GetActionInputParams {
pub package_id: PackageId,
#[arg(help = "help.arg.action-id")]
pub action_id: ActionId,
#[ts(type = "Record<string, unknown> | null")]
#[serde(default)]
#[arg(skip)]
pub prefill: Option<Value>,
}
#[instrument(skip_all)]
@@ -75,6 +79,7 @@ pub async fn get_action_input(
GetActionInputParams {
package_id,
action_id,
prefill,
}: GetActionInputParams,
) -> Result<Option<ActionInput>, Error> {
ctx.services
@@ -82,7 +87,7 @@ pub async fn get_action_input(
.await
.as_ref()
.or_not_found(lazy_format!("Manager for {}", package_id))?
.get_action_input(Guid::new(), action_id)
.get_action_input(Guid::new(), action_id, prefill.unwrap_or(Value::Null))
.await
}

View File

@@ -533,7 +533,7 @@ impl RpcContext {
for (package_id, action_id) in tasks {
if let Some(service) = self.services.get(&package_id).await.as_ref() {
if let Some(input) = service
.get_action_input(procedure_id.clone(), action_id.clone())
.get_action_input(procedure_id.clone(), action_id.clone(), Value::Null)
.await
.log_err()
.flatten()

View File

@@ -298,7 +298,7 @@ impl Model<Host> {
let bindings: Bindings = this.bindings.de()?;
let mut port_forwards = BTreeSet::new();
for bind in bindings.values() {
for addr in &bind.addresses.available {
for addr in bind.addresses.enabled() {
if !addr.public {
continue;
}

View File

@@ -17,6 +17,7 @@ use crate::{ActionId, PackageId, ReplayId};
pub(super) struct GetActionInput {
id: ActionId,
prefill: Value,
}
impl Handler<GetActionInput> for ServiceActor {
type Response = Result<Option<ActionInput>, Error>;
@@ -26,7 +27,10 @@ impl Handler<GetActionInput> for ServiceActor {
async fn handle(
&mut self,
id: Guid,
GetActionInput { id: action_id }: GetActionInput,
GetActionInput {
id: action_id,
prefill,
}: GetActionInput,
_: &BackgroundJobQueue,
) -> Self::Response {
let container = &self.0.persistent_container;
@@ -34,7 +38,7 @@ impl Handler<GetActionInput> for ServiceActor {
.execute::<Option<ActionInput>>(
id,
ProcedureName::GetActionInput(action_id),
Value::Null,
json!({ "prefill": prefill }),
Some(Duration::from_secs(30)),
)
.await
@@ -47,6 +51,7 @@ impl Service {
&self,
id: Guid,
action_id: ActionId,
prefill: Value,
) -> Result<Option<ActionInput>, Error> {
if !self
.seed
@@ -67,7 +72,7 @@ impl Service {
return Ok(None);
}
self.actor
.send(id, GetActionInput { id: action_id })
.send(id, GetActionInput { id: action_id, prefill })
.await?
}
}

View File

@@ -122,6 +122,10 @@ pub struct GetActionInputParams {
package_id: Option<PackageId>,
#[arg(help = "help.arg.action-id")]
action_id: ActionId,
#[ts(type = "Record<string, unknown> | null")]
#[serde(default)]
#[arg(skip)]
prefill: Option<Value>,
}
async fn get_action_input(
context: EffectContext,
@@ -129,9 +133,11 @@ async fn get_action_input(
procedure_id,
package_id,
action_id,
prefill,
}: GetActionInputParams,
) -> Result<Option<ActionInput>, Error> {
let context = context.deref()?;
let prefill = prefill.unwrap_or(Value::Null);
if let Some(package_id) = package_id {
context
@@ -142,10 +148,10 @@ async fn get_action_input(
.await
.as_ref()
.or_not_found(&package_id)?
.get_action_input(procedure_id, action_id)
.get_action_input(procedure_id, action_id, prefill)
.await
} else {
context.get_action_input(procedure_id, action_id).await
context.get_action_input(procedure_id, action_id, prefill).await
}
}
@@ -245,7 +251,7 @@ async fn create_task(
.as_ref()
{
let Some(prev) = service
.get_action_input(procedure_id.clone(), task.action_id.clone())
.get_action_input(procedure_id.clone(), task.action_id.clone(), Value::Null)
.await?
else {
return Err(Error::new(

View File

@@ -534,7 +534,7 @@ impl Service {
.contains_key(&action_id)?
{
if let Some(input) = service
.get_action_input(procedure_id.clone(), action_id.clone())
.get_action_input(procedure_id.clone(), action_id.clone(), Value::Null)
.await
.log_err()
.flatten()