From 6efbdb2ff941dbda2b84062ee0452e54d245ee8a Mon Sep 17 00:00:00 2001 From: flemming-it Date: Thu, 7 May 2026 20:45:59 +0200 Subject: [PATCH] feat: fetchModuleDocs wrapper (v0.10.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Picks up HubAdmin.FetchModuleDocs. HubClient exposes it as fetchModuleDocs(name) returning the FetchModuleDocsResponse verbatim — Studio maps the error_kind to friendly copy. Signed-off-by: flemming-it --- lib/src/generated/fai/v1/hub.pb.dart | 130 +++++++++++++++++++++++ lib/src/generated/fai/v1/hub.pbgrpc.dart | 25 +++++ lib/src/generated/fai/v1/hub.pbjson.dart | 27 +++++ lib/src/hub_client.dart | 10 ++ pubspec.yaml | 2 +- 5 files changed, 193 insertions(+), 1 deletion(-) diff --git a/lib/src/generated/fai/v1/hub.pb.dart b/lib/src/generated/fai/v1/hub.pb.dart index 038242d..d6be173 100644 --- a/lib/src/generated/fai/v1/hub.pb.dart +++ b/lib/src/generated/fai/v1/hub.pb.dart @@ -1732,6 +1732,136 @@ class UninstallModuleResponse extends $pb.GeneratedMessage { void clearVersion() => $_clearField(2); } +class FetchModuleDocsRequest extends $pb.GeneratedMessage { + factory FetchModuleDocsRequest({ + $core.String? name, + }) { + final $result = create(); + if (name != null) { + $result.name = name; + } + return $result; + } + FetchModuleDocsRequest._() : super(); + factory FetchModuleDocsRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory FetchModuleDocsRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'FetchModuleDocsRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'fai.v1'), createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'name') + ..hasRequiredFields = false + ; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + FetchModuleDocsRequest clone() => FetchModuleDocsRequest()..mergeFromMessage(this); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + FetchModuleDocsRequest copyWith(void Function(FetchModuleDocsRequest) updates) => super.copyWith((message) => updates(message as FetchModuleDocsRequest)) as FetchModuleDocsRequest; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static FetchModuleDocsRequest create() => FetchModuleDocsRequest._(); + FetchModuleDocsRequest createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static FetchModuleDocsRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static FetchModuleDocsRequest? _defaultInstance; + + /// Module name as the store-index knows it. The hub looks up + /// its repository URL and tries the well-known raw-README + /// paths (Forgejo / GitHub / GitLab style), then any + /// `docs_url` override the module declares. + @$pb.TagNumber(1) + $core.String get name => $_getSZ(0); + @$pb.TagNumber(1) + set name($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasName() => $_has(0); + @$pb.TagNumber(1) + void clearName() => $_clearField(1); +} + +class FetchModuleDocsResponse extends $pb.GeneratedMessage { + factory FetchModuleDocsResponse({ + $core.String? errorKind, + $core.String? text, + $core.String? sourceUrl, + }) { + final $result = create(); + if (errorKind != null) { + $result.errorKind = errorKind; + } + if (text != null) { + $result.text = text; + } + if (sourceUrl != null) { + $result.sourceUrl = sourceUrl; + } + return $result; + } + FetchModuleDocsResponse._() : super(); + factory FetchModuleDocsResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory FetchModuleDocsResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + + static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'FetchModuleDocsResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'fai.v1'), createEmptyInstance: create) + ..aOS(1, _omitFieldNames ? '' : 'errorKind') + ..aOS(2, _omitFieldNames ? '' : 'text') + ..aOS(3, _omitFieldNames ? '' : 'sourceUrl') + ..hasRequiredFields = false + ; + + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + FetchModuleDocsResponse clone() => FetchModuleDocsResponse()..mergeFromMessage(this); + @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') + FetchModuleDocsResponse copyWith(void Function(FetchModuleDocsResponse) updates) => super.copyWith((message) => updates(message as FetchModuleDocsResponse)) as FetchModuleDocsResponse; + + $pb.BuilderInfo get info_ => _i; + + @$core.pragma('dart2js:noInline') + static FetchModuleDocsResponse create() => FetchModuleDocsResponse._(); + FetchModuleDocsResponse createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static FetchModuleDocsResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static FetchModuleDocsResponse? _defaultInstance; + + /// Empty on success; otherwise one of: + /// "not_found" — module not in the store-index + /// "no_docs" — index has no repository or docs URL + /// "network" — http error / unreachable + /// "auth" — registry returned 401/403 + /// "parse" — body was not utf-8 + @$pb.TagNumber(1) + $core.String get errorKind => $_getSZ(0); + @$pb.TagNumber(1) + set errorKind($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasErrorKind() => $_has(0); + @$pb.TagNumber(1) + void clearErrorKind() => $_clearField(1); + + /// Human-readable detail. On success this is the markdown + /// content; on failure a fix hint. + @$pb.TagNumber(2) + $core.String get text => $_getSZ(1); + @$pb.TagNumber(2) + set text($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasText() => $_has(1); + @$pb.TagNumber(2) + void clearText() => $_clearField(2); + + /// The URL the hub fetched from, so Studio can render a + /// "View on " link for context. + @$pb.TagNumber(3) + $core.String get sourceUrl => $_getSZ(2); + @$pb.TagNumber(3) + set sourceUrl($core.String v) { $_setString(2, v); } + @$pb.TagNumber(3) + $core.bool hasSourceUrl() => $_has(2); + @$pb.TagNumber(3) + void clearSourceUrl() => $_clearField(3); +} + class ListApprovalsRequest extends $pb.GeneratedMessage { factory ListApprovalsRequest({ $core.Iterable<$core.String>? statuses, diff --git a/lib/src/generated/fai/v1/hub.pbgrpc.dart b/lib/src/generated/fai/v1/hub.pbgrpc.dart index b42649f..f04aab7 100644 --- a/lib/src/generated/fai/v1/hub.pbgrpc.dart +++ b/lib/src/generated/fai/v1/hub.pbgrpc.dart @@ -167,6 +167,10 @@ class HubAdminClient extends $grpc.Client { '/fai.v1.HubAdmin/UninstallModule', ($0.UninstallModuleRequest value) => value.writeToBuffer(), ($core.List<$core.int> value) => $0.UninstallModuleResponse.fromBuffer(value)); + static final _$fetchModuleDocs = $grpc.ClientMethod<$0.FetchModuleDocsRequest, $0.FetchModuleDocsResponse>( + '/fai.v1.HubAdmin/FetchModuleDocs', + ($0.FetchModuleDocsRequest value) => value.writeToBuffer(), + ($core.List<$core.int> value) => $0.FetchModuleDocsResponse.fromBuffer(value)); static final _$listApprovals = $grpc.ClientMethod<$0.ListApprovalsRequest, $0.ApprovalList>( '/fai.v1.HubAdmin/ListApprovals', ($0.ListApprovalsRequest value) => value.writeToBuffer(), @@ -300,6 +304,15 @@ class HubAdminClient extends $grpc.Client { return $createUnaryCall(_$uninstallModule, request, options: options); } + /// Fetch a module's README (or other docs) and return the + /// markdown content as a string. The hub knows how to + /// authenticate against the configured registry — Studio + /// doesn't need to handle credentials. Studio's Store detail + /// sheet renders the result inline. + $grpc.ResponseFuture<$0.FetchModuleDocsResponse> fetchModuleDocs($0.FetchModuleDocsRequest request, {$grpc.CallOptions? options}) { + return $createUnaryCall(_$fetchModuleDocs, request, options: options); + } + /// List system.approval@^0 entries, optionally filtered by status. $grpc.ResponseFuture<$0.ApprovalList> listApprovals($0.ListApprovalsRequest request, {$grpc.CallOptions? options}) { return $createUnaryCall(_$listApprovals, request, options: options); @@ -521,6 +534,13 @@ abstract class HubAdminServiceBase extends $grpc.Service { false, ($core.List<$core.int> value) => $0.UninstallModuleRequest.fromBuffer(value), ($0.UninstallModuleResponse value) => value.writeToBuffer())); + $addMethod($grpc.ServiceMethod<$0.FetchModuleDocsRequest, $0.FetchModuleDocsResponse>( + 'FetchModuleDocs', + fetchModuleDocs_Pre, + false, + false, + ($core.List<$core.int> value) => $0.FetchModuleDocsRequest.fromBuffer(value), + ($0.FetchModuleDocsResponse value) => value.writeToBuffer())); $addMethod($grpc.ServiceMethod<$0.ListApprovalsRequest, $0.ApprovalList>( 'ListApprovals', listApprovals_Pre, @@ -693,6 +713,10 @@ abstract class HubAdminServiceBase extends $grpc.Service { return uninstallModule($call, await $request); } + $async.Future<$0.FetchModuleDocsResponse> fetchModuleDocs_Pre($grpc.ServiceCall $call, $async.Future<$0.FetchModuleDocsRequest> $request) async { + return fetchModuleDocs($call, await $request); + } + $async.Future<$0.ApprovalList> listApprovals_Pre($grpc.ServiceCall $call, $async.Future<$0.ListApprovalsRequest> $request) async { return listApprovals($call, await $request); } @@ -776,6 +800,7 @@ abstract class HubAdminServiceBase extends $grpc.Service { $async.Future<$0.StoreSearchResponse> searchStore($grpc.ServiceCall call, $0.SearchStoreRequest request); $async.Future<$0.InstallModuleResponse> installModule($grpc.ServiceCall call, $0.InstallModuleRequest request); $async.Future<$0.UninstallModuleResponse> uninstallModule($grpc.ServiceCall call, $0.UninstallModuleRequest request); + $async.Future<$0.FetchModuleDocsResponse> fetchModuleDocs($grpc.ServiceCall call, $0.FetchModuleDocsRequest request); $async.Future<$0.ApprovalList> listApprovals($grpc.ServiceCall call, $0.ListApprovalsRequest request); $async.Future<$0.DecideApprovalResponse> decideApproval($grpc.ServiceCall call, $0.DecideApprovalRequest request); $async.Future<$0.VerifyEventChainResponse> verifyEventChain($grpc.ServiceCall call, $1.Empty request); diff --git a/lib/src/generated/fai/v1/hub.pbjson.dart b/lib/src/generated/fai/v1/hub.pbjson.dart index 4806391..15b920d 100644 --- a/lib/src/generated/fai/v1/hub.pbjson.dart +++ b/lib/src/generated/fai/v1/hub.pbjson.dart @@ -461,6 +461,33 @@ final $typed_data.Uint8List uninstallModuleResponseDescriptor = $convert.base64D 'ChdVbmluc3RhbGxNb2R1bGVSZXNwb25zZRISCgRuYW1lGAEgASgJUgRuYW1lEhgKB3ZlcnNpb2' '4YAiABKAlSB3ZlcnNpb24='); +@$core.Deprecated('Use fetchModuleDocsRequestDescriptor instead') +const FetchModuleDocsRequest$json = { + '1': 'FetchModuleDocsRequest', + '2': [ + {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'}, + ], +}; + +/// Descriptor for `FetchModuleDocsRequest`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List fetchModuleDocsRequestDescriptor = $convert.base64Decode( + 'ChZGZXRjaE1vZHVsZURvY3NSZXF1ZXN0EhIKBG5hbWUYASABKAlSBG5hbWU='); + +@$core.Deprecated('Use fetchModuleDocsResponseDescriptor instead') +const FetchModuleDocsResponse$json = { + '1': 'FetchModuleDocsResponse', + '2': [ + {'1': 'error_kind', '3': 1, '4': 1, '5': 9, '10': 'errorKind'}, + {'1': 'text', '3': 2, '4': 1, '5': 9, '10': 'text'}, + {'1': 'source_url', '3': 3, '4': 1, '5': 9, '10': 'sourceUrl'}, + ], +}; + +/// Descriptor for `FetchModuleDocsResponse`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List fetchModuleDocsResponseDescriptor = $convert.base64Decode( + 'ChdGZXRjaE1vZHVsZURvY3NSZXNwb25zZRIdCgplcnJvcl9raW5kGAEgASgJUgllcnJvcktpbm' + 'QSEgoEdGV4dBgCIAEoCVIEdGV4dBIdCgpzb3VyY2VfdXJsGAMgASgJUglzb3VyY2VVcmw='); + @$core.Deprecated('Use listApprovalsRequestDescriptor instead') const ListApprovalsRequest$json = { '1': 'ListApprovalsRequest', diff --git a/lib/src/hub_client.dart b/lib/src/hub_client.dart index 8b3c44f..dc31447 100644 --- a/lib/src/hub_client.dart +++ b/lib/src/hub_client.dart @@ -56,6 +56,7 @@ typedef CuratedModel = pb.CuratedModel; typedef ClearEventLogResponse = pb.ClearEventLogResponse; typedef DaemonPathsResponse = pb.DaemonPathsResponse; typedef UninstallModuleResponse = pb.UninstallModuleResponse; +typedef FetchModuleDocsResponse = pb.FetchModuleDocsResponse; typedef ModuleInfoResponse = pb.ModuleInfoResponse; typedef FlowSummary = pb.FlowSummary; typedef StoreEntry = pb.StoreEntry; @@ -226,6 +227,15 @@ class HubClient { return _admin.uninstallModule(pb.UninstallModuleRequest(name: name)); } + /// Fetch a module's README markdown via the hub. The hub + /// authenticates against the registry with FAI_REGISTRY_TOKEN + /// when set, so Studio doesn't have to handle credentials. + /// Errors come back inside [FetchModuleDocsResponse.errorKind] + /// (not as exceptions) so the UI can render fallbacks. + Future fetchModuleDocs(String name) { + return _admin.fetchModuleDocs(pb.FetchModuleDocsRequest(name: name)); + } + /// Read-only system-AI status. `enabled=false` lets Studio /// render "configure in Settings" without making a request. Future systemAiStatus() { diff --git a/pubspec.yaml b/pubspec.yaml index 345461e..1cf2504 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: fai_dart_sdk description: gRPC client SDK for the F∆I Platform hub. Used by F∆I Studio and Tier-3 domain apps. -version: 0.9.0 +version: 0.10.0 publish_to: 'none' repository: https://git.flemming.ws/fai/dart-sdk