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 <stefan.a.flemming@googlemail.com>
This commit is contained in:
commit
d405a6a9bd
9 changed files with 216 additions and 0 deletions
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
|
@ -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
|
||||||
3
CHANGELOG.md
Normal file
3
CHANGELOG.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
## 1.0.0
|
||||||
|
|
||||||
|
- Initial version.
|
||||||
52
README.md
Normal file
52
README.md
Normal file
|
|
@ -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.
|
||||||
30
analysis_options.yaml
Normal file
30
analysis_options.yaml
Normal file
|
|
@ -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
|
||||||
20
example/fai_dart_sdk_example.dart
Normal file
20
example/fai_dart_sdk_example.dart
Normal file
|
|
@ -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<void> 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();
|
||||||
|
}
|
||||||
14
lib/fai_dart_sdk.dart
Normal file
14
lib/fai_dart_sdk.dart
Normal file
|
|
@ -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';
|
||||||
43
lib/src/hub_client.dart
Normal file
43
lib/src/hub_client.dart
Normal file
|
|
@ -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<void> close() async {}
|
||||||
|
}
|
||||||
16
pubspec.yaml
Normal file
16
pubspec.yaml
Normal file
|
|
@ -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
|
||||||
31
test/fai_dart_sdk_test.dart
Normal file
31
test/fai_dart_sdk_test.dart
Normal file
|
|
@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue