diff --git a/lib/src/hub_client.dart b/lib/src/hub_client.dart index b8173c5..2c3a795 100644 --- a/lib/src/hub_client.dart +++ b/lib/src/hub_client.dart @@ -6,6 +6,7 @@ import 'package:grpc/grpc.dart'; +import 'generated/fai/v1/common.pb.dart' as pb_common; import 'generated/fai/v1/hub.pb.dart' as pb; import 'generated/fai/v1/hub.pbgrpc.dart' as grpc_hub; import 'generated/google/protobuf/empty.pb.dart' show Empty; @@ -41,6 +42,9 @@ typedef PendingApprovalEntry = pb.PendingApprovalEntry; typedef DeclaredService = pb.DeclaredService; typedef VerifyEventChainResponse = pb.VerifyEventChainResponse; typedef ModuleInfoResponse = pb.ModuleInfoResponse; +typedef FlowSummary = pb.FlowSummary; +typedef Payload = pb_common.Payload; +typedef SubmitResponse = pb.SubmitResponse; /// Typed client for the F∆I Hub gRPC surface. Construct once, /// reuse for the process lifetime, call [close] on shutdown. @@ -159,6 +163,29 @@ class HubClient { return r.services; } + /// All saved flows known to the hub. Each entry carries the + /// flow name, on-disk path and byte size. + Future> listFlows() async { + final r = await _admin.listFlows(Empty()); + return r.flows; + } + + /// Run a saved flow by name with the supplied named inputs. + /// Each input value is wrapped as a text Payload — the most + /// common case for human-driven runs from Studio. Callers + /// that need bytes / file payloads use the lower-level + /// SubmitRequest path. + Future runSavedFlow({ + required String name, + required Map textInputs, + }) async { + final req = pb.RunSavedFlowRequest()..name = name; + for (final entry in textInputs.entries) { + req.inputs[entry.key] = pb_common.Payload()..text = entry.value; + } + return _admin.runSavedFlow(req); + } + /// Closes the gRPC channel. Idempotent. Future close() async { await _channel.shutdown();