diff --git a/container-runtime/src/Adapters/EffectCreator.ts b/container-runtime/src/Adapters/EffectCreator.ts index 6512b0d6c..c549a28ab 100644 --- a/container-runtime/src/Adapters/EffectCreator.ts +++ b/container-runtime/src/Adapters/EffectCreator.ts @@ -35,13 +35,13 @@ const SOCKET_PATH = "/media/startos/rpc/host.sock" let hostSystemId = 0 export type EffectContext = { - procedureId: string | null + eventId: string | null callbacks?: CallbackHolder constRetry?: () => void } const rpcRoundFor = - (procedureId: string | null) => + (eventId: string | null) => ( method: K, params: Record, @@ -52,7 +52,7 @@ const rpcRoundFor = JSON.stringify({ id, method, - params: { ...params, procedureId: procedureId || undefined }, + params: { ...params, eventId: eventId ?? undefined }, }) + "\n", ) }) @@ -103,8 +103,9 @@ const rpcRoundFor = } export function makeEffects(context: EffectContext): Effects { - const rpcRound = rpcRoundFor(context.procedureId) + const rpcRound = rpcRoundFor(context.eventId) const self: Effects = { + eventId: context.eventId, child: (name) => makeEffects({ ...context, callbacks: context.callbacks?.child(name) }), constRetry: context.constRetry, diff --git a/container-runtime/src/Adapters/RpcListener.ts b/container-runtime/src/Adapters/RpcListener.ts index 8033478da..e8876aea1 100644 --- a/container-runtime/src/Adapters/RpcListener.ts +++ b/container-runtime/src/Adapters/RpcListener.ts @@ -242,11 +242,11 @@ export class RpcListener { .when(runType, async ({ id, params }) => { const system = this.system const procedure = jsonPath.unsafeCast(params.procedure) - const { input, timeout, id: procedureId } = params + const { input, timeout, id: eventId } = params const result = this.getResult( procedure, system, - procedureId, + eventId, timeout, input, ) @@ -256,11 +256,11 @@ export class RpcListener { .when(sandboxRunType, async ({ id, params }) => { const system = this.system const procedure = jsonPath.unsafeCast(params.procedure) - const { input, timeout, id: procedureId } = params + const { input, timeout, id: eventId } = params const result = this.getResult( procedure, system, - procedureId, + eventId, timeout, input, ) @@ -275,7 +275,7 @@ export class RpcListener { const callbacks = this.callbacks?.getChild("main") || this.callbacks?.child("main") const effects = makeEffects({ - procedureId: null, + eventId: null, callbacks, }) return handleRpc( @@ -304,7 +304,7 @@ export class RpcListener { } await this._system.exit( makeEffects({ - procedureId: params.id, + eventId: params.id, }), target, ) @@ -320,14 +320,14 @@ export class RpcListener { const system = await this.getDependencies.system() this.callbacks = new CallbackHolder( makeEffects({ - procedureId: params.id, + eventId: params.id, }), ) const callbacks = this.callbacks.child("init") console.error("Initializing...") await system.init( makeEffects({ - procedureId: params.id, + eventId: params.id, callbacks, }), params.kind, @@ -399,7 +399,7 @@ export class RpcListener { private getResult( procedure: typeof jsonPath._TYPE, system: System, - procedureId: string, + eventId: string, timeout: number | null | undefined, input: any, ) { @@ -410,7 +410,7 @@ export class RpcListener { } const callbacks = this.callbacks?.child(procedure) const effects = makeEffects({ - procedureId, + eventId, callbacks, }) diff --git a/container-runtime/src/Adapters/Systems/SystemForEmbassy/index.ts b/container-runtime/src/Adapters/Systems/SystemForEmbassy/index.ts index 05ff5a427..a33a03058 100644 --- a/container-runtime/src/Adapters/Systems/SystemForEmbassy/index.ts +++ b/container-runtime/src/Adapters/Systems/SystemForEmbassy/index.ts @@ -509,13 +509,18 @@ export class SystemForEmbassy implements System { ): Promise { if (actionId === "config") { const config = await this.getConfig(effects, timeoutMs) - return { spec: config.spec, value: config.config } + return { + eventId: effects.eventId!, + spec: config.spec, + value: config.config, + } } else if (actionId === "properties") { return null } else { const oldSpec = this.manifest.actions?.[actionId]?.["input-spec"] if (!oldSpec) return null return { + eventId: effects.eventId!, spec: transformConfigSpec(oldSpec as OldConfigSpec), value: null, } diff --git a/core/startos/src/action.rs b/core/startos/src/action.rs index 4079ca7ad..4bc3e4380 100644 --- a/core/startos/src/action.rs +++ b/core/startos/src/action.rs @@ -52,6 +52,7 @@ pub fn action_api() -> ParentHandler { #[ts(export)] #[serde(rename_all = "camelCase")] pub struct ActionInput { + pub event_id: Guid, #[ts(type = "Record")] pub spec: Value, #[ts(type = "Record | null")] @@ -270,6 +271,7 @@ pub fn display_action_result( #[serde(rename_all = "camelCase")] pub struct RunActionParams { pub package_id: PackageId, + pub event_id: Option, pub action_id: ActionId, #[ts(optional, type = "any")] pub input: Option, @@ -278,6 +280,7 @@ pub struct RunActionParams { #[derive(Parser)] struct CliRunActionParams { pub package_id: PackageId, + pub event_id: Option, pub action_id: ActionId, #[command(flatten)] pub input: StdinDeserializable>, @@ -286,12 +289,14 @@ impl From for RunActionParams { fn from( CliRunActionParams { package_id, + event_id, action_id, input, }: CliRunActionParams, ) -> Self { Self { package_id, + event_id, action_id, input: input.0, } @@ -331,6 +336,7 @@ pub async fn run_action( ctx: RpcContext, RunActionParams { package_id, + event_id, action_id, input, }: RunActionParams, @@ -340,7 +346,11 @@ pub async fn run_action( .await .as_ref() .or_not_found(lazy_format!("Manager for {}", package_id))? - .run_action(Guid::new(), action_id, input.unwrap_or_default()) + .run_action( + event_id.unwrap_or_default(), + action_id, + input.unwrap_or_default(), + ) .await .map(|res| res.map(ActionResult::upcast)) } diff --git a/core/startos/src/db/model/public.rs b/core/startos/src/db/model/public.rs index 1fad92be6..ef6566476 100644 --- a/core/startos/src/db/model/public.rs +++ b/core/startos/src/db/model/public.rs @@ -198,13 +198,12 @@ pub struct NetworkInfo { #[model = "Model"] #[ts(export)] pub struct NetworkInterfaceInfo { - pub inbound: Option, - pub outbound: Option, + pub public: Option, pub ip_info: Option, } impl NetworkInterfaceInfo { - pub fn inbound(&self) -> bool { - self.inbound.unwrap_or_else(|| { + pub fn public(&self) -> bool { + self.public.unwrap_or_else(|| { !self.ip_info.as_ref().map_or(true, |ip_info| { let ip4s = ip_info .subnets diff --git a/core/startos/src/net/forward.rs b/core/startos/src/net/forward.rs index 9e189f013..0c3daca73 100644 --- a/core/startos/src/net/forward.rs +++ b/core/startos/src/net/forward.rs @@ -169,7 +169,7 @@ impl LanPortForwardController { ( iface.clone(), ( - info.inbound(), + info.public(), info.ip_info.as_ref().map_or(Vec::new(), |i| { i.subnets .iter() @@ -205,7 +205,7 @@ impl LanPortForwardController { ip_info .iter() .map(|(iface, info)| (iface.clone(), ( - info.inbound(), + info.public(), info.ip_info.as_ref().map_or(Vec::new(), |i| { i.subnets .iter() diff --git a/core/startos/src/net/net_controller.rs b/core/startos/src/net/net_controller.rs index 2a6dc535c..2c6fabda7 100644 --- a/core/startos/src/net/net_controller.rs +++ b/core/startos/src/net/net_controller.rs @@ -335,7 +335,7 @@ impl NetServiceData { for (interface, public, ip_info) in net_ifaces.iter().filter_map(|(interface, info)| { if let Some(ip_info) = &info.ip_info { - Some((interface, info.inbound(), ip_info)) + Some((interface, info.public(), ip_info)) } else { None } diff --git a/core/startos/src/net/network_interface.rs b/core/startos/src/net/network_interface.rs index f69989261..e963029eb 100644 --- a/core/startos/src/net/network_interface.rs +++ b/core/startos/src/net/network_interface.rs @@ -58,7 +58,7 @@ pub fn network_interface_api() -> ParentHandler { info.ip_info.as_ref() .and_then(|ip_info| ip_info.device_type) .map_or_else(|| "UNKNOWN".to_owned(), |ty| format!("{ty:?}")), - info.inbound(), + info.public(), info.ip_info.as_ref().map_or_else( || "".to_owned(), |ip_info| ip_info.subnets @@ -585,21 +585,24 @@ async fn watch_ip( None }; - write_to.send_if_modified(|m| { - let (inbound, outbound) = m - .get(&iface) - .map_or((None, None), |i| (i.inbound, i.outbound)); - m.insert( - iface.clone(), - NetworkInterfaceInfo { - inbound, - outbound, - ip_info: ip_info.clone(), - }, - ) - .filter(|old| &old.ip_info == &ip_info) - .is_none() - }); + write_to.send_if_modified( + |m: &mut BTreeMap< + InternedString, + NetworkInterfaceInfo, + >| { + let public = + m.get(&iface).map_or(None, |i| i.public); + m.insert( + iface.clone(), + NetworkInterfaceInfo { + public, + ip_info: ip_info.clone(), + }, + ) + .filter(|old| &old.ip_info == &ip_info) + .is_none() + }, + ); Ok::<_, Error>(()) }) @@ -856,7 +859,7 @@ impl NetworkInterfaceController { return false; } } - .inbound, + .public, public, ); prev != public @@ -968,8 +971,7 @@ impl ListenerMap { ) -> Result<(), Error> { let mut keep = BTreeSet::::new(); for info in ip_info.values().chain([&NetworkInterfaceInfo { - inbound: Some(false), - outbound: Some(false), + public: Some(false), ip_info: Some(IpInfo { name: "lo".into(), scope_id: 1, @@ -984,7 +986,7 @@ impl ListenerMap { ntp_servers: Default::default(), }), }]) { - if public || !info.inbound() { + if public || !info.public() { if let Some(ip_info) = &info.ip_info { for ipnet in &ip_info.subnets { let addr = match ipnet.addr() { @@ -1003,7 +1005,7 @@ impl ListenerMap { }; keep.insert(addr); if let Some((_, is_public, wan_ip)) = self.listeners.get_mut(&addr) { - *is_public = info.inbound(); + *is_public = info.public(); *wan_ip = info.ip_info.as_ref().and_then(|i| i.wan_ip); continue; } @@ -1021,7 +1023,7 @@ impl ListenerMap { .into(), ) .with_kind(ErrorKind::Network)?, - info.inbound(), + info.public(), info.ip_info.as_ref().and_then(|i| i.wan_ip), ), ); diff --git a/core/startos/src/notifications.rs b/core/startos/src/notifications.rs index d982f3962..5a1255705 100644 --- a/core/startos/src/notifications.rs +++ b/core/startos/src/notifications.rs @@ -110,10 +110,6 @@ pub async fn list( }) }) .collect::, Error>>()?; - db.as_public_mut() - .as_server_info_mut() - .as_unread_notification_count_mut() - .ser(&0)?; Ok(notifs) } Some(before) => { @@ -195,22 +191,23 @@ pub async fn mark_seen( ) -> Result<(), Error> { ctx.db .mutate(|db| { - let mut diff = 0; let n = db.as_private_mut().as_notifications_mut(); for id in ids { - if !n - .as_idx_mut(&id) + n.as_idx_mut(&id) .or_not_found(lazy_format!("Notification #{id}"))? .as_seen_mut() - .replace(&true)? - { - diff += 1; + .ser(&true)?; + } + let mut unread = 0; + for (_, n) in n.as_entries()? { + if !n.as_seen().de()? { + unread += 1; } } db.as_public_mut() .as_server_info_mut() .as_unread_notification_count_mut() - .mutate(|n| Ok(*n -= diff))?; + .ser(&unread)?; Ok(()) }) .await @@ -223,22 +220,23 @@ pub async fn mark_seen_before( ) -> Result<(), Error> { ctx.db .mutate(|db| { - let mut diff = 0; let n = db.as_private_mut().as_notifications_mut(); for id in n.keys()?.range(..before) { - if !n - .as_idx_mut(&id) + n.as_idx_mut(&id) .or_not_found(lazy_format!("Notification #{id}"))? .as_seen_mut() - .replace(&true)? - { - diff += 1; + .ser(&true)?; + } + let mut unread = 0; + for (_, n) in n.as_entries()? { + if !n.as_seen().de()? { + unread += 1; } } db.as_public_mut() .as_server_info_mut() .as_unread_notification_count_mut() - .mutate(|n| Ok(*n -= diff))?; + .ser(&unread)?; Ok(()) }) .await @@ -251,21 +249,23 @@ pub async fn mark_unseen( ) -> Result<(), Error> { ctx.db .mutate(|db| { - let mut diff = 0; let n = db.as_private_mut().as_notifications_mut(); for id in ids { - if n.as_idx_mut(&id) + n.as_idx_mut(&id) .or_not_found(lazy_format!("Notification #{id}"))? .as_seen_mut() - .replace(&false)? - { - diff += 1; + .ser(&false)?; + } + let mut unread = 0; + for (_, n) in n.as_entries()? { + if !n.as_seen().de()? { + unread += 1; } } db.as_public_mut() .as_server_info_mut() .as_unread_notification_count_mut() - .mutate(|n| Ok(*n += diff))?; + .ser(&unread)?; Ok(()) }) .await diff --git a/core/startos/src/service/action.rs b/core/startos/src/service/action.rs index b2c11260c..ae7b17de8 100644 --- a/core/startos/src/service/action.rs +++ b/core/startos/src/service/action.rs @@ -115,7 +115,7 @@ pub fn update_tasks( } pub(super) struct RunAction { - id: ActionId, + action_id: ActionId, input: Value, } impl Handler for ServiceActor { @@ -127,7 +127,7 @@ impl Handler for ServiceActor { &mut self, id: Guid, RunAction { - id: ref action_id, + ref action_id, input, }: RunAction, jobs: &BackgroundJobQueue, @@ -145,7 +145,7 @@ impl Handler for ServiceActor { .into_idx(package_id) .or_not_found(package_id)? .into_actions() - .into_idx(&action_id) + .into_idx(action_id) .or_not_found(lazy_format!("{package_id} action {action_id}"))? .de()?; if matches!(&action.visibility, ActionVisibility::Disabled(_)) { @@ -226,14 +226,6 @@ impl Service { action_id: ActionId, input: Value, ) -> Result, Error> { - self.actor - .send( - id, - RunAction { - id: action_id, - input, - }, - ) - .await? + self.actor.send(id, RunAction { action_id, input }).await? } } diff --git a/core/startos/src/service/effects/control.rs b/core/startos/src/service/effects/control.rs index a6e2eb87b..266680e05 100644 --- a/core/startos/src/service/effects/control.rs +++ b/core/startos/src/service/effects/control.rs @@ -21,21 +21,15 @@ pub async fn rebuild(context: EffectContext) -> Result<(), Error> { Ok(()) } -pub async fn restart( - context: EffectContext, - ProcedureId { procedure_id }: ProcedureId, -) -> Result<(), Error> { +pub async fn restart(context: EffectContext, EventId { event_id }: EventId) -> Result<(), Error> { let context = context.deref()?; - context.restart(procedure_id, false).await?; + context.restart(event_id, false).await?; Ok(()) } -pub async fn shutdown( - context: EffectContext, - ProcedureId { procedure_id }: ProcedureId, -) -> Result<(), Error> { +pub async fn shutdown(context: EffectContext, EventId { event_id }: EventId) -> Result<(), Error> { let context = context.deref()?; - context.stop(procedure_id, false).await?; + context.stop(event_id, false).await?; Ok(()) } diff --git a/core/startos/src/service/effects/prelude.rs b/core/startos/src/service/effects/prelude.rs index 2dc848c0c..74a3ce476 100644 --- a/core/startos/src/service/effects/prelude.rs +++ b/core/startos/src/service/effects/prelude.rs @@ -9,8 +9,8 @@ pub(super) use crate::service::effects::context::EffectContext; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Parser, TS)] #[serde(rename_all = "camelCase")] #[ts(export)] -pub struct ProcedureId { +pub struct EventId { #[serde(default)] #[arg(default_value_t, long)] - pub procedure_id: Guid, + pub event_id: Guid, } diff --git a/core/startos/src/service/persistent_container.rs b/core/startos/src/service/persistent_container.rs index b6a29c945..c81497f69 100644 --- a/core/startos/src/service/persistent_container.rs +++ b/core/startos/src/service/persistent_container.rs @@ -105,7 +105,6 @@ pub struct PersistentContainer { pub(super) lxc_container: OnceCell, pub(super) rpc_client: UnixRpcClient, pub(super) rpc_server: watch::Sender, ShutdownHandle)>>, - // procedures: Mutex>, js_mount: MountGuard, volumes: BTreeMap, assets: Vec, diff --git a/core/startos/src/update/mod.rs b/core/startos/src/update/mod.rs index 8826f78dc..7a346d4af 100644 --- a/core/startos/src/update/mod.rs +++ b/core/startos/src/update/mod.rs @@ -202,6 +202,7 @@ pub async fn cli_update_system( prev.overall.set_complete(); progress.update(&prev); } + println!("Update complete. Restart your server to apply the update.") } else { println!("Updating to v{v}...") } diff --git a/sdk/base/lib/Effects.ts b/sdk/base/lib/Effects.ts index 91231f19c..24aafd310 100644 --- a/sdk/base/lib/Effects.ts +++ b/sdk/base/lib/Effects.ts @@ -27,6 +27,7 @@ import { /** Used to reach out from the pure js runtime */ export type Effects = { + readonly eventId: string | null child: (name: string) => Effects constRetry?: () => void isInContext: boolean diff --git a/sdk/base/lib/actions/input/builder/value.ts b/sdk/base/lib/actions/input/builder/value.ts index 5bfaadf0b..7e13b6cce 100644 --- a/sdk/base/lib/actions/input/builder/value.ts +++ b/sdk/base/lib/actions/input/builder/value.ts @@ -1,8 +1,7 @@ -import { ExtractInputSpecType, InputSpec, LazyBuild } from "./inputSpec" +import { InputSpec, LazyBuild } from "./inputSpec" import { List } from "./list" import { UnionRes, UnionResStaticValidatedAs, Variants } from "./variants" import { - FilePath, Pattern, RandomString, ValueSpec, @@ -27,6 +26,12 @@ import { } from "ts-matches" import { DeepPartial } from "../../../types" +export const fileInfoParser = object({ + path: string, + commitment: object({ hash: string, size: number }), +}) +export type FileInfo = typeof fileInfoParser._TYPE + type AsRequired = Required extends true ? T : T | null @@ -891,47 +896,54 @@ export class Value { } }, spec.validator) } - // static file(a: { - // name: string - // description?: string | null - // extensions: string[] - // required: Required - // }) { - // const buildValue = { - // type: "file" as const, - // description: null, - // warning: null, - // ...a, - // } - // return new Value, Store>( - // () => ({ - // ...buildValue, - // }), - // asRequiredParser(object({ filePath: string }), a), - // ) - // } - // static dynamicFile( - // a: LazyBuild< - // Store, - // { - // name: string - // description?: string | null - // warning?: string | null - // extensions: string[] - // required: boolean - // } - // >, - // ) { - // return new Value( - // async (options) => ({ - // type: "file" as const, - // description: null, - // warning: null, - // ...(await a(options)), - // }), - // object({ filePath: string }).nullable(), - // ) - // } + static file(a: { + name: string + description?: string | null + warning?: string | null + extensions: string[] + required: Required + }) { + const buildValue = { + type: "file" as const, + description: null, + warning: null, + ...a, + } + return new Value>( + () => ({ + spec: { + ...buildValue, + }, + validator: asRequiredParser(fileInfoParser, a), + }), + asRequiredParser(fileInfoParser, a), + ) + } + static dynamicFile( + a: LazyBuild<{ + name: string + description?: string | null + warning?: string | null + extensions: string[] + required: Required + }>, + ) { + return new Value, FileInfo | null>( + async (options) => { + const spec = { + type: "file" as const, + description: null, + warning: null, + ...(await a(options)), + } + return { + spec, + validator: asRequiredParser(fileInfoParser, spec), + } + }, + fileInfoParser.nullable(), + ) + } /** * @description Displays a dropdown, allowing for a single selection. Depending on the selection, a different object ("sub form") is presented. * @example diff --git a/sdk/base/lib/actions/input/inputSpecTypes.ts b/sdk/base/lib/actions/input/inputSpecTypes.ts index 362a56ea1..3e2dfabb1 100644 --- a/sdk/base/lib/actions/input/inputSpecTypes.ts +++ b/sdk/base/lib/actions/input/inputSpecTypes.ts @@ -66,9 +66,6 @@ export type ValueSpecTextarea = { immutable: boolean } -export type FilePath = { - filePath: string -} export type ValueSpecNumber = { type: "number" min: number | null diff --git a/sdk/base/lib/actions/setupActions.ts b/sdk/base/lib/actions/setupActions.ts index 91f93f688..26a72a117 100644 --- a/sdk/base/lib/actions/setupActions.ts +++ b/sdk/base/lib/actions/setupActions.ts @@ -5,9 +5,11 @@ import { once } from "../util" import { InitScript } from "../inits" import { Parser } from "ts-matches" +type MaybeInputSpec = {} extends Type ? null : InputSpec export type Run> = (options: { effects: T.Effects input: A + spec: T.inputSpecTypes.InputSpec }) => Promise<(T.ActionResult & { version: "1" }) | null | void | undefined> export type GetInput> = (options: { effects: T.Effects @@ -47,11 +49,14 @@ export class Action> implements ActionInfo { readonly _INPUT: Type = null as any as Type - private cachedParser?: Parser + private prevInputSpec: Record< + string, + { spec: T.inputSpecTypes.InputSpec; validator: Parser } + > = {} private constructor( readonly id: Id, private readonly metadataFn: MaybeFn, - private readonly inputSpec: InputSpec, + private readonly inputSpec: MaybeInputSpec, private readonly getInputFn: GetInput, private readonly runFn: Run, ) {} @@ -81,7 +86,7 @@ export class Action> return new Action( id, mapMaybeFn(metadata, (m) => ({ ...m, hasInput: false })), - InputSpec.of({}), + null, async () => null, run, ) @@ -100,10 +105,15 @@ export class Action> return metadata } async getInput(options: { effects: T.Effects }): Promise { - const built = await this.inputSpec.build(options) - this.cachedParser = built.validator + let spec = {} + if (this.inputSpec) { + const built = await this.inputSpec.build(options) + this.prevInputSpec[options.effects.eventId!] = built + spec = built.spec + } return { - spec: built.spec, + eventId: options.effects.eventId!, + spec, value: ((await this.getInputFn(options)) as | Record @@ -115,15 +125,23 @@ export class Action> effects: T.Effects input: Type }): Promise { - const parser = - this.cachedParser ?? (await this.inputSpec.build(options)).validator + let spec = {} + if (this.inputSpec) { + const prevInputSpec = this.prevInputSpec[options.effects.eventId!] + if (!prevInputSpec) { + throw new Error( + `getActionInput has not been called for EventID ${options.effects.eventId}`, + ) + } + options.input = prevInputSpec.validator.unsafeCast(options.input) + spec = prevInputSpec.spec + } return ( (await this.runFn({ effects: options.effects, - input: this.cachedParser - ? this.cachedParser.unsafeCast(options.input) - : options.input, - })) || null + input: options.input, + spec, + })) ?? null ) } } diff --git a/sdk/base/lib/osBindings/ActionInput.ts b/sdk/base/lib/osBindings/ActionInput.ts index a19a5f1a4..c81ce7547 100644 --- a/sdk/base/lib/osBindings/ActionInput.ts +++ b/sdk/base/lib/osBindings/ActionInput.ts @@ -1,6 +1,8 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { Guid } from "./Guid" export type ActionInput = { + eventId: Guid spec: Record value: Record | null } diff --git a/sdk/base/lib/osBindings/ProcedureId.ts b/sdk/base/lib/osBindings/EventId.ts similarity index 75% rename from sdk/base/lib/osBindings/ProcedureId.ts rename to sdk/base/lib/osBindings/EventId.ts index 4d9a0debd..4449fb8a3 100644 --- a/sdk/base/lib/osBindings/ProcedureId.ts +++ b/sdk/base/lib/osBindings/EventId.ts @@ -1,4 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { Guid } from "./Guid" -export type ProcedureId = { procedureId: Guid } +export type EventId = { eventId: Guid } diff --git a/sdk/base/lib/osBindings/NetworkInterfaceInfo.ts b/sdk/base/lib/osBindings/NetworkInterfaceInfo.ts index 324b3df78..796046b93 100644 --- a/sdk/base/lib/osBindings/NetworkInterfaceInfo.ts +++ b/sdk/base/lib/osBindings/NetworkInterfaceInfo.ts @@ -2,7 +2,6 @@ import type { IpInfo } from "./IpInfo" export type NetworkInterfaceInfo = { - inbound: boolean | null - outbound: boolean | null + public: boolean | null ipInfo: IpInfo | null } diff --git a/sdk/base/lib/osBindings/index.ts b/sdk/base/lib/osBindings/index.ts index e6e3a7bff..d3066f334 100644 --- a/sdk/base/lib/osBindings/index.ts +++ b/sdk/base/lib/osBindings/index.ts @@ -70,6 +70,7 @@ export { Duration } from "./Duration" export { EchoParams } from "./EchoParams" export { EditSignerParams } from "./EditSignerParams" export { EncryptedWire } from "./EncryptedWire" +export { EventId } from "./EventId" export { ExportActionParams } from "./ExportActionParams" export { ExportServiceInterfaceParams } from "./ExportServiceInterfaceParams" export { FileType } from "./FileType" @@ -155,7 +156,6 @@ export { PackageVersionInfo } from "./PackageVersionInfo" export { PasswordType } from "./PasswordType" export { PathOrUrl } from "./PathOrUrl" export { Percentage } from "./Percentage" -export { ProcedureId } from "./ProcedureId" export { Progress } from "./Progress" export { ProgressUnits } from "./ProgressUnits" export { Public } from "./Public" diff --git a/sdk/base/lib/test/startosTypeValidation.test.ts b/sdk/base/lib/test/startosTypeValidation.test.ts index b6a29fc00..e07db88b4 100644 --- a/sdk/base/lib/test/startosTypeValidation.test.ts +++ b/sdk/base/lib/test/startosTypeValidation.test.ts @@ -46,6 +46,7 @@ type EffectsTypeChecker = { describe("startosTypeValidation ", () => { test(`checking the params match`, () => { typeEquality({ + eventId: {} as never, child: "", isInContext: {} as never, onLeaveContext: () => {}, diff --git a/sdk/package/lib/StartSdk.ts b/sdk/package/lib/StartSdk.ts index 3f74b172a..345b2f3a7 100644 --- a/sdk/package/lib/StartSdk.ts +++ b/sdk/package/lib/StartSdk.ts @@ -104,7 +104,7 @@ export class StartSdk { // prettier-ignore type StartSdkEffectWrapper = { - [K in keyof Omit]: (effects: Effects, ...args: Parameters) => ReturnType + [K in keyof Omit]: (effects: Effects, ...args: Parameters) => ReturnType } const startSdkEffectWrapper: StartSdkEffectWrapper = { restart: (effects, ...args) => effects.restart(...args), diff --git a/web/projects/ui/src/app/routes/portal/routes/services/modals/action-input.component.ts b/web/projects/ui/src/app/routes/portal/routes/services/modals/action-input.component.ts index 8c8820d24..4d82e1e74 100644 --- a/web/projects/ui/src/app/routes/portal/routes/services/modals/action-input.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/services/modals/action-input.component.ts @@ -133,6 +133,7 @@ export class ActionInputModal { readonly warning = this.context.data.actionInfo.metadata.warning readonly pkgInfo = this.context.data.pkgInfo readonly requestInfo = this.context.data.requestInfo + eventId: string | null = null buttons: ActionButton[] = [ { @@ -151,6 +152,7 @@ export class ActionInputModal { ).pipe( map(res => { const originalValue = res.value || {} + this.eventId = res.eventId return { spec: res.spec, @@ -174,7 +176,12 @@ export class ActionInputModal { async execute(input: object) { if (await this.checkConflicts(input)) { - await this.actionService.execute(this.pkgInfo.id, this.actionId, input) + await this.actionService.execute( + this.pkgInfo.id, + this.eventId, + this.actionId, + input, + ) this.context.$implicit.complete() } } diff --git a/web/projects/ui/src/app/services/action.service.ts b/web/projects/ui/src/app/services/action.service.ts index 51cf57906..40d7e1a42 100644 --- a/web/projects/ui/src/app/services/action.service.ts +++ b/web/projects/ui/src/app/services/action.service.ts @@ -67,9 +67,9 @@ export class ActionService { }, }) .pipe(filter(Boolean)) - .subscribe(() => this.execute(pkgInfo.id, actionInfo.id)) + .subscribe(() => this.execute(pkgInfo.id, null, actionInfo.id)) } else { - this.execute(pkgInfo.id, actionInfo.id) + this.execute(pkgInfo.id, null, actionInfo.id) } } } else { @@ -96,14 +96,20 @@ export class ActionService { } } - async execute(packageId: string, actionId: string, input?: object) { + async execute( + packageId: string, + eventId: string | null, + actionId: string, + input?: object, + ) { const loader = this.loader.open('Loading').subscribe() try { const res = await this.api.runAction({ packageId, + eventId, actionId, - input: input || null, + input: input ?? null, }) if (!res) return diff --git a/web/projects/ui/src/app/services/api/api.types.ts b/web/projects/ui/src/app/services/api/api.types.ts index 864a264f9..df7a8a735 100644 --- a/web/projects/ui/src/app/services/api/api.types.ts +++ b/web/projects/ui/src/app/services/api/api.types.ts @@ -347,12 +347,14 @@ export namespace RR { export type GetActionInputReq = { packageId: string; actionId: string } // package.action.get-input export type GetActionInputRes = { + eventId: string spec: IST.InputSpec value: object | null } export type ActionReq = { packageId: string + eventId: string | null actionId: string input: object | null } // package.action.run diff --git a/web/projects/ui/src/app/services/api/embassy-mock-api.service.ts b/web/projects/ui/src/app/services/api/embassy-mock-api.service.ts index 54c7e937b..d461fe8fa 100644 --- a/web/projects/ui/src/app/services/api/embassy-mock-api.service.ts +++ b/web/projects/ui/src/app/services/api/embassy-mock-api.service.ts @@ -1108,6 +1108,7 @@ export class MockApiService extends ApiService { ): Promise { await pauseFor(2000) return { + eventId: 'ANZXNWIFRTTBZ6T52KQPZILIQQODDHXQ', value: Mock.MockConfig, spec: await Mock.getActionInputSpec(), }