commit d405a6a9bd16b9bb3f4af5f10da0ea9bfbb579fb Author: flemming-it Date: Tue May 5 14:19:39 2026 +0200 feat: fai_dart_sdk scaffold Dart package skeleton for the F∆I gRPC client. Used by F∆I Studio (Tier-2) and Tier-3 domain apps (DigiScout / J∆I / Scout). Public surface — HubClient, HubEndpoint — is committed as a typed stub so downstream apps can compile against it immediately. Generated proto bindings land in a follow-up commit once the codegen step (planned: tools/generate.sh wrapping protoc-gen-dart against ../fai_platform/proto) is wired in. Future Forgejo path: fai/dart-sdk. dart analyze: clean. dart test: 4/4. Signed-off-by: flemming-it diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/README.md b/README.md new file mode 100644 index 0000000..cce1999 --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +# fai_dart_sdk + +gRPC client SDK for the F∆I Platform hub. Used by F∆I Studio +(Tier-2 generic GUI) and any Tier-3 Dart/Flutter domain app +(DigiScout, J∆I, Scout, …) that wants to talk to a running +`fai serve`. + +> **Status (2026-05-05):** scaffold. Public surface (`HubClient`, +> `HubEndpoint`) is committed; generated proto bindings land in +> a follow-up commit once the codegen step is wired in. Until +> then, downstream apps can compile against the stub and Studio +> uses mock data. + +## Why a separate SDK package + +The platform hub speaks gRPC. Each Dart consumer (Studio plus +each Tier-3 domain app) would otherwise re-generate proto +bindings independently and write near-identical client +boilerplate. This package centralises that work: + +- One source of generated proto bindings. +- One typed `HubClient` wrapper with helpers. +- One place to bump when the wire protocol evolves. + +## Layout + +``` +fai_dart_sdk/ +├── lib/ +│ ├── fai_dart_sdk.dart # Public API +│ └── src/ +│ ├── hub_client.dart # Typed client wrapper +│ └── generated/ # protoc output (committed; pinned to platform tag) +├── tools/ +│ └── generate.sh # Wraps `protoc --dart_out=...` against ../fai_platform/proto +├── example/ +└── pubspec.yaml +``` + +## Repo placement + +Will be published as `fai/dart-sdk` on Forgejo +(`git.flemming.ws`). The local directory `fai_dart_sdk/` +follows the established `fai_platform/` layout convention. + +## Versioning + +Tracks the platform's wire-protocol version, not the platform +binary version. As long as `fai:platform@1.x` is current, this +SDK stays at `0.x` (will move to `1.0` once API stabilises); +when `fai:platform@2.0` lands, a `2.x` SDK ships in parallel +during the transition. diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/example/fai_dart_sdk_example.dart b/example/fai_dart_sdk_example.dart new file mode 100644 index 0000000..262377b --- /dev/null +++ b/example/fai_dart_sdk_example.dart @@ -0,0 +1,20 @@ +// Example: connect to a locally-running F∆I hub. +// +// Run with `dart run example/fai_dart_sdk_example.dart`. +// Currently the SDK is a stub; once codegen lands, this example +// will exercise the actual Hub RPCs. + +import 'package:fai_dart_sdk/fai_dart_sdk.dart'; + +Future main() async { + final client = HubClient( + endpoint: const HubEndpoint(host: '127.0.0.1', port: 50051), + ); + + // ignore: avoid_print + print('would connect to ${client.endpoint}'); + // ignore: avoid_print + print('(SDK is a stub today; live RPC arrives with codegen)'); + + await client.close(); +} diff --git a/lib/fai_dart_sdk.dart b/lib/fai_dart_sdk.dart new file mode 100644 index 0000000..99e5c1d --- /dev/null +++ b/lib/fai_dart_sdk.dart @@ -0,0 +1,14 @@ +/// gRPC client for the F∆I Platform hub. +/// +/// Provides a typed Dart wrapper around the hub's gRPC services +/// (Hub, HubAdmin) defined in `fai/platform`'s `proto/fai/v1/` +/// directory. Used by F∆I Studio and any Tier-3 Dart/Flutter +/// app (DigiScout, J∆I, Scout, …) that wants to talk to a hub. +/// +/// Status (2026-05-05): scaffold only. Generated proto bindings +/// land in `lib/src/generated/` once the codegen step is wired +/// in (`tools/generate.sh`). Until then, [HubClient] is a stub +/// type that documents the intended surface. +library; + +export 'src/hub_client.dart'; diff --git a/lib/src/hub_client.dart b/lib/src/hub_client.dart new file mode 100644 index 0000000..25e57f4 --- /dev/null +++ b/lib/src/hub_client.dart @@ -0,0 +1,43 @@ +// HubClient — typed wrapper around the F∆I Hub gRPC service. +// +// Status (2026-05-05): scaffold. The generated proto bindings +// from `fai/platform`'s proto/fai/v1/ directory will populate +// the actual RPC implementations under `lib/src/generated/` +// once the codegen tooling is wired (planned: a small +// `tools/generate.sh` script that runs `protoc` with +// `protoc-gen-dart` against the platform repo's protos). + +/// Connection coordinates for a hub endpoint. +class HubEndpoint { + /// Hostname or IP. Defaults to localhost for the canonical + /// `fai serve` setup. + final String host; + + /// gRPC port. Defaults to 50051. + final int port; + + /// When true, use TLS. Phase 1+ will add credential support. + final bool secure; + + const HubEndpoint({ + this.host = '127.0.0.1', + this.port = 50051, + this.secure = false, + }); + + @override + String toString() => '${secure ? "https" : "http"}://$host:$port'; +} + +/// Stub client interface. The real implementation will arrive +/// when proto codegen is wired in. Studio uses this type as the +/// future-stable surface; the mock data layer in +/// `fai_studio/lib/data/mock.dart` is the placeholder until then. +class HubClient { + final HubEndpoint endpoint; + + HubClient({this.endpoint = const HubEndpoint()}); + + /// Closes the underlying channel. No-op while stubbed. + Future close() async {} +} diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..cb610fe --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,16 @@ +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.1.0 +publish_to: 'none' +repository: https://git.flemming.ws/fai/dart-sdk + +environment: + sdk: ^3.11.0-200.1.beta + +dependencies: + grpc: ^4.0.0 + protobuf: ^4.0.0 + +dev_dependencies: + lints: ^6.0.0 + test: ^1.25.6 diff --git a/test/fai_dart_sdk_test.dart b/test/fai_dart_sdk_test.dart new file mode 100644 index 0000000..59e700c --- /dev/null +++ b/test/fai_dart_sdk_test.dart @@ -0,0 +1,31 @@ +import 'package:fai_dart_sdk/fai_dart_sdk.dart'; +import 'package:test/test.dart'; + +void main() { + group('HubEndpoint', () { + test('default endpoint targets local fai serve', () { + const e = HubEndpoint(); + expect(e.host, '127.0.0.1'); + expect(e.port, 50051); + expect(e.secure, false); + expect(e.toString(), 'http://127.0.0.1:50051'); + }); + + test('secure flag flips scheme', () { + const e = HubEndpoint(host: 'hub.example', port: 443, secure: true); + expect(e.toString(), 'https://hub.example:443'); + }); + }); + + group('HubClient', () { + test('constructs with default endpoint', () { + final c = HubClient(); + expect(c.endpoint.host, '127.0.0.1'); + }); + + test('close is a no-op on the stub', () async { + final c = HubClient(); + await c.close(); + }); + }); +}