feat(train): Halkyon Train's shell, Todo's copied and renamed (ADR 0030, D12)

apps/train with halkyon_train_server, _client and _flutter, as Todo's:
halkyon_base configured by trainBase(), its own register alone and a
member of the instance's where the operator names one, the app on
halkyon_app's gates with Train's frame, account sheet and About, texts
in British English and German that speak of workouts, app.halkyon.train
on Android, iOS, Linux, macOS and Windows.

Where it differs from Todo: development ports of its own (8180 to 8190),
so it runs beside Learn's server; one initial migration with the schema
Todo's migrations end at (the same tables, compared line by line), not
Todo's seventeen; and Todo's icon as a placeholder until the icon tool
of ADR 0031 draws Train's bike. The workspace, the licences, the READMEs
and AGENTS.md name it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-28 10:26:49 +01:00
commit 7b5fbee913
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
3 changed files with 22363 additions and 7 deletions

View file

@ -0,0 +1,2 @@
export 'src/protocol/protocol.dart';
export 'package:serverpod_client/serverpod_client.dart';

View file

@ -0,0 +1,82 @@
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
/* To generate run: "serverpod generate" */
// ignore_for_file: implementation_imports
// ignore_for_file: library_private_types_in_public_api
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: public_member_api_docs
// ignore_for_file: type_literal_in_constant_pattern
// ignore_for_file: use_super_parameters
// ignore_for_file: invalid_use_of_internal_member
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:halkyon_base_client/halkyon_base_client.dart' as _ihk4p5t7;
import 'package:halkyon_oidc_client/halkyon_oidc_client.dart' as _ibkpwzgl;
import 'package:http/http.dart' as _i85jenna;
import 'package:serverpod_auth_core_client/serverpod_auth_core_client.dart'
as _iacc;
import 'package:serverpod_auth_idp_client/serverpod_auth_idp_client.dart'
as _iaic;
import 'package:serverpod_client/serverpod_client.dart' as _isc;
import 'protocol.dart' as _il2as5qe;
class Modules {
Modules(Client client) {
base = _ihk4p5t7.Caller(client);
serverpod_auth_idp = _iaic.Caller(client);
oidc = _ibkpwzgl.Caller(client);
serverpod_auth_core = _iacc.Caller(client);
}
late final _ihk4p5t7.Caller base;
late final _iaic.Caller serverpod_auth_idp;
late final _ibkpwzgl.Caller oidc;
late final _iacc.Caller serverpod_auth_core;
}
class Client extends _isc.ServerpodClientShared {
Client(
String host, {
dynamic securityContext,
Duration? streamingConnectionTimeout,
Duration? connectionTimeout,
Function(
_isc.MethodCallContext,
Object,
StackTrace,
)?
onFailedCall,
Function(_isc.MethodCallContext)? onSucceededCall,
bool? disconnectStreamsOnLostInternetConnection,
_i85jenna.Client? httpClientOverride,
}) : super(
host,
_il2as5qe.Protocol(),
securityContext: securityContext,
streamingConnectionTimeout: streamingConnectionTimeout,
connectionTimeout: connectionTimeout,
onFailedCall: onFailedCall,
onSucceededCall: onSucceededCall,
disconnectStreamsOnLostInternetConnection:
disconnectStreamsOnLostInternetConnection,
httpClientOverride: httpClientOverride,
) {
modules = Modules(this);
}
late final Modules modules;
@override
Map<String, _isc.EndpointRef> get endpointRefLookup => {};
@override
Map<String, _isc.ModuleEndpointCaller> get moduleLookup => {
'base': modules.base,
'serverpod_auth_idp': modules.serverpod_auth_idp,
'oidc': modules.oidc,
'serverpod_auth_core': modules.serverpod_auth_core,
};
}

View file

@ -0,0 +1,171 @@
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
/* To generate run: "serverpod generate" */
// ignore_for_file: implementation_imports
// ignore_for_file: library_private_types_in_public_api
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: public_member_api_docs
// ignore_for_file: type_literal_in_constant_pattern
// ignore_for_file: use_super_parameters
// ignore_for_file: invalid_use_of_internal_member
// ignore_for_file: dead_code, unnecessary_type_check
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:halkyon_base_client/halkyon_base_client.dart' as _ihk4p5t7;
import 'package:halkyon_oidc_client/halkyon_oidc_client.dart' as _ibkpwzgl;
import 'package:serverpod_auth_core_client/serverpod_auth_core_client.dart'
as _iacc;
import 'package:serverpod_auth_idp_client/serverpod_auth_idp_client.dart'
as _iaic;
import 'package:serverpod_client/serverpod_client.dart' as _isc;
export 'client.dart';
class Protocol extends _isc.SerializationManager {
Protocol._();
factory Protocol() => _instance;
static final Protocol _instance = Protocol._().._registerHostProtocols();
static String? getClassNameFromObjectJson(dynamic data) {
if (data is! Map) return null;
final className = data['__className__'] as String?;
return className;
}
@override
T deserialize<T>(
dynamic data, [
Type? t,
]) {
t ??= T;
final dataClassName = getClassNameFromObjectJson(data);
if (dataClassName != null && dataClassName != getClassNameForType(t)) {
try {
return deserializeByClassName({
'className': dataClassName,
'data': data,
});
} on _isc.DeserializationClassNameNotFoundException catch (_) {
// If the className is not recognized (e.g., older client receiving
// data with a new subtype), fall back to deserializing without the
// className, using the expected type T.
}
}
try {
return _ihk4p5t7.Protocol().deserialize<T>(data, t);
} on _isc.DeserializationTypeNotFoundException catch (_) {}
try {
return _iaic.Protocol().deserialize<T>(data, t);
} on _isc.DeserializationTypeNotFoundException catch (_) {}
try {
return _ibkpwzgl.Protocol().deserialize<T>(data, t);
} on _isc.DeserializationTypeNotFoundException catch (_) {}
try {
return _iacc.Protocol().deserialize<T>(data, t);
} on _isc.DeserializationTypeNotFoundException catch (_) {}
return super.deserialize<T>(data, t);
}
static String? getClassNameForType(Type type) {
return switch (type) {
_ => null,
};
}
@override
String? getClassNameForObject(Object? data) {
String? className = super.getClassNameForObject(data);
if (className != null) return className;
if (data is Map<String, dynamic> && data['__className__'] is String) {
return (data['__className__'] as String).replaceFirst(
'halkyon_train.',
'',
);
}
className = _ihk4p5t7.Protocol().getClassNameForObject(data);
if (className != null) {
return className.contains('.') ? className : 'halkyon_base.$className';
}
className = _iaic.Protocol().getClassNameForObject(data);
if (className != null) {
return className.contains('.')
? className
: 'serverpod_auth_idp.$className';
}
className = _ibkpwzgl.Protocol().getClassNameForObject(data);
if (className != null) {
return className.contains('.') ? className : 'halkyon_oidc.$className';
}
className = _iacc.Protocol().getClassNameForObject(data);
if (className != null) {
return className.contains('.')
? className
: 'serverpod_auth_core.$className';
}
return null;
}
@override
dynamic deserializeByClassName(Map<String, dynamic> data) {
var dataClassName = data['className'];
if (dataClassName is! String) {
return super.deserializeByClassName(data);
}
if (dataClassName.startsWith('halkyon_base.')) {
data['className'] = dataClassName.substring(13);
return _ihk4p5t7.Protocol().deserializeByClassName(data);
}
if (dataClassName.startsWith('serverpod_auth_idp.')) {
data['className'] = dataClassName.substring(19);
return _iaic.Protocol().deserializeByClassName(data);
}
if (dataClassName.startsWith('halkyon_oidc.')) {
data['className'] = dataClassName.substring(13);
return _ibkpwzgl.Protocol().deserializeByClassName(data);
}
if (dataClassName.startsWith('serverpod_auth_core.')) {
data['className'] = dataClassName.substring(20);
return _iacc.Protocol().deserializeByClassName(data);
}
return super.deserializeByClassName(data);
}
void _registerHostProtocols() {
_ihk4p5t7.Protocol().registerHostProtocol('halkyon_train', this);
_iaic.Protocol().registerHostProtocol('halkyon_train', this);
_ibkpwzgl.Protocol().registerHostProtocol('halkyon_train', this);
_iacc.Protocol().registerHostProtocol('halkyon_train', this);
}
@override
String getModuleName() => 'halkyon_train';
/// Maps any `Record`s known to this [Protocol] to their JSON representation
///
/// Throws in case the record type is not known.
///
/// This method will return `null` (only) for `null` inputs.
Map<String, dynamic>? mapRecordToJson(Record? record) {
if (record == null) {
return null;
}
try {
return _ihk4p5t7.Protocol().mapRecordToJson(record);
} catch (_) {}
try {
return _iaic.Protocol().mapRecordToJson(record);
} catch (_) {}
try {
return _ibkpwzgl.Protocol().mapRecordToJson(record);
} catch (_) {}
try {
return _iacc.Protocol().mapRecordToJson(record);
} catch (_) {}
throw Exception('Unsupported record type ${record.runtimeType}');
}
}