halkyon_base: a Serverpod module for sign-in, accounts and instance basics
What every Halkyon server has, taken from Halkyon Learn's: anonymous, GitHub and email-code sign-in with their endpoints, an account's ways in and its deletion, the pruning of abandoned anonymous people, of sign-up attempts and of expired codes, and the instance's basics (the sign-in ways offered, the source link, the minimum app build, where people's data and its backups are). Endpoints sit under the nickname `base`. A host configures it in one place before its pod starts: its name for the mails, its source link, its minimum build, and hooks that delete its own data with a person. The tables keep Learn's names, columns and indexes, so a host moving onto the module migrates nothing but version rows. Server package under the SSPL, client under the AGPL, as Learn's are. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
80fa7b9628
commit
af1de799f4
1 changed files with 17704 additions and 3 deletions
296
packages/halkyon_base_client/lib/src/protocol/protocol.dart
Normal file
296
packages/halkyon_base_client/lib/src/protocol/protocol.dart
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
/* 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: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 'auth/email_code_accepted.dart' as _iys46ui1;
|
||||
import 'auth/email_sign_in_refusal.dart' as _ieyvcag1;
|
||||
import 'auth/email_sign_in_refused_exception.dart' as _iztfgag5;
|
||||
import 'auth/github_sign_in_refusal.dart' as _ir1gd9p5;
|
||||
import 'auth/github_sign_in_refused_exception.dart' as _i0xfcu5n;
|
||||
import 'auth/sign_in_ways.dart' as _ie6tbh85;
|
||||
import 'instance/instance_basics.dart' as _i8jixqx6;
|
||||
export 'auth/email_code_accepted.dart';
|
||||
export 'auth/email_sign_in_refusal.dart';
|
||||
export 'auth/email_sign_in_refused_exception.dart';
|
||||
export 'auth/github_sign_in_refusal.dart';
|
||||
export 'auth/github_sign_in_refused_exception.dart';
|
||||
export 'auth/sign_in_ways.dart';
|
||||
export 'instance/instance_basics.dart';
|
||||
export 'client.dart';
|
||||
|
||||
class Protocol extends _isc.SerializationManager {
|
||||
Protocol._();
|
||||
|
||||
factory Protocol() => _instance;
|
||||
|
||||
static final Protocol _instance = Protocol._();
|
||||
|
||||
final Set<_isc.SerializationManager> _hostProtocols = {};
|
||||
|
||||
void registerHostProtocol(
|
||||
String projectName,
|
||||
_isc.SerializationManager protocol,
|
||||
) {
|
||||
_hostProtocols.add(protocol);
|
||||
}
|
||||
|
||||
static String? getClassNameFromObjectJson(dynamic data) {
|
||||
if (data is! Map) return null;
|
||||
final className = data['__className__'] as String?;
|
||||
if (className == null) return null;
|
||||
if (!className.startsWith('halkyon_base.')) return className;
|
||||
return className.substring(13);
|
||||
}
|
||||
|
||||
@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.
|
||||
}
|
||||
}
|
||||
|
||||
if (t == _iys46ui1.EmailCodeAccepted) {
|
||||
return _iys46ui1.EmailCodeAccepted.fromJson(data) as T;
|
||||
}
|
||||
if (t == _ieyvcag1.EmailSignInRefusal) {
|
||||
return _ieyvcag1.EmailSignInRefusal.fromJson(data) as T;
|
||||
}
|
||||
if (t == _iztfgag5.EmailSignInRefusedException) {
|
||||
return _iztfgag5.EmailSignInRefusedException.fromJson(data) as T;
|
||||
}
|
||||
if (t == _ir1gd9p5.GitHubSignInRefusal) {
|
||||
return _ir1gd9p5.GitHubSignInRefusal.fromJson(data) as T;
|
||||
}
|
||||
if (t == _i0xfcu5n.GitHubSignInRefusedException) {
|
||||
return _i0xfcu5n.GitHubSignInRefusedException.fromJson(data) as T;
|
||||
}
|
||||
if (t == _ie6tbh85.SignInWays) {
|
||||
return _ie6tbh85.SignInWays.fromJson(data) as T;
|
||||
}
|
||||
if (t == _i8jixqx6.InstanceBasics) {
|
||||
return _i8jixqx6.InstanceBasics.fromJson(data) as T;
|
||||
}
|
||||
if (t == _isc.getType<_iys46ui1.EmailCodeAccepted?>()) {
|
||||
return (data != null ? _iys46ui1.EmailCodeAccepted.fromJson(data) : null)
|
||||
as T;
|
||||
}
|
||||
if (t == _isc.getType<_ieyvcag1.EmailSignInRefusal?>()) {
|
||||
return (data != null ? _ieyvcag1.EmailSignInRefusal.fromJson(data) : null)
|
||||
as T;
|
||||
}
|
||||
if (t == _isc.getType<_iztfgag5.EmailSignInRefusedException?>()) {
|
||||
return (data != null
|
||||
? _iztfgag5.EmailSignInRefusedException.fromJson(data)
|
||||
: null)
|
||||
as T;
|
||||
}
|
||||
if (t == _isc.getType<_ir1gd9p5.GitHubSignInRefusal?>()) {
|
||||
return (data != null
|
||||
? _ir1gd9p5.GitHubSignInRefusal.fromJson(data)
|
||||
: null)
|
||||
as T;
|
||||
}
|
||||
if (t == _isc.getType<_i0xfcu5n.GitHubSignInRefusedException?>()) {
|
||||
return (data != null
|
||||
? _i0xfcu5n.GitHubSignInRefusedException.fromJson(data)
|
||||
: null)
|
||||
as T;
|
||||
}
|
||||
if (t == _isc.getType<_ie6tbh85.SignInWays?>()) {
|
||||
return (data != null ? _ie6tbh85.SignInWays.fromJson(data) : null) as T;
|
||||
}
|
||||
if (t == _isc.getType<_i8jixqx6.InstanceBasics?>()) {
|
||||
return (data != null ? _i8jixqx6.InstanceBasics.fromJson(data) : null)
|
||||
as T;
|
||||
}
|
||||
try {
|
||||
return _iaic.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) {
|
||||
_iys46ui1.EmailCodeAccepted => 'EmailCodeAccepted',
|
||||
_ieyvcag1.EmailSignInRefusal => 'EmailSignInRefusal',
|
||||
_iztfgag5.EmailSignInRefusedException => 'EmailSignInRefusedException',
|
||||
_ir1gd9p5.GitHubSignInRefusal => 'GitHubSignInRefusal',
|
||||
_i0xfcu5n.GitHubSignInRefusedException => 'GitHubSignInRefusedException',
|
||||
_ie6tbh85.SignInWays => 'SignInWays',
|
||||
_i8jixqx6.InstanceBasics => 'InstanceBasics',
|
||||
_ => 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_base.',
|
||||
'',
|
||||
);
|
||||
}
|
||||
|
||||
switch (data) {
|
||||
case _iys46ui1.EmailCodeAccepted():
|
||||
return 'EmailCodeAccepted';
|
||||
case _ieyvcag1.EmailSignInRefusal():
|
||||
return 'EmailSignInRefusal';
|
||||
case _iztfgag5.EmailSignInRefusedException():
|
||||
return 'EmailSignInRefusedException';
|
||||
case _ir1gd9p5.GitHubSignInRefusal():
|
||||
return 'GitHubSignInRefusal';
|
||||
case _i0xfcu5n.GitHubSignInRefusedException():
|
||||
return 'GitHubSignInRefusedException';
|
||||
case _ie6tbh85.SignInWays():
|
||||
return 'SignInWays';
|
||||
case _i8jixqx6.InstanceBasics():
|
||||
return 'InstanceBasics';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic deserializeByClassName(Map<String, dynamic> data) {
|
||||
var dataClassName = data['className'];
|
||||
if (dataClassName is! String) {
|
||||
return super.deserializeByClassName(data);
|
||||
}
|
||||
if (dataClassName == 'EmailCodeAccepted') {
|
||||
return deserialize<_iys46ui1.EmailCodeAccepted>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'EmailSignInRefusal') {
|
||||
return deserialize<_ieyvcag1.EmailSignInRefusal>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'EmailSignInRefusedException') {
|
||||
return deserialize<_iztfgag5.EmailSignInRefusedException>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'GitHubSignInRefusal') {
|
||||
return deserialize<_ir1gd9p5.GitHubSignInRefusal>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'GitHubSignInRefusedException') {
|
||||
return deserialize<_i0xfcu5n.GitHubSignInRefusedException>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'SignInWays') {
|
||||
return deserialize<_ie6tbh85.SignInWays>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'InstanceBasics') {
|
||||
return deserialize<_i8jixqx6.InstanceBasics>(data['data']);
|
||||
}
|
||||
return super.deserializeByClassName(data);
|
||||
}
|
||||
|
||||
@override
|
||||
Object? dynamicFieldToJson(
|
||||
Object? object, {
|
||||
bool forProtocol = false,
|
||||
}) {
|
||||
if ((object is List || object is Set || object is Map) ||
|
||||
getClassNameForObject(object) != null) {
|
||||
return super.dynamicFieldToJson(object, forProtocol: forProtocol);
|
||||
}
|
||||
for (final protocol in _hostProtocols) {
|
||||
final className = protocol.getClassNameForObject(object);
|
||||
if (className == null) continue;
|
||||
final host = protocol.getModuleName();
|
||||
final wrapped = {
|
||||
'className': className.contains('.') ? className : '$host.$className',
|
||||
'data': object,
|
||||
};
|
||||
return forProtocol
|
||||
? _isc.SerializationManager.toEncodableForProtocol(wrapped)
|
||||
: _isc.SerializationManager.toEncodable(wrapped);
|
||||
}
|
||||
return super.dynamicFieldToJson(object, forProtocol: forProtocol);
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic deserializeDynamicFieldValue(Object? value) {
|
||||
if (value == null) return null;
|
||||
if (value is! Map<String, dynamic> || value['className'] is! String) {
|
||||
throw FormatException(
|
||||
'Dynamic fields are encoded as a Map with className and data, but got '
|
||||
'${value.runtimeType} instead.',
|
||||
);
|
||||
}
|
||||
final className = value['className'] as String;
|
||||
for (final protocol in _hostProtocols) {
|
||||
final host = protocol.getModuleName();
|
||||
final hostPrefix = '$host.';
|
||||
if (className.startsWith(hostPrefix)) {
|
||||
final strippedClassName = className.substring(hostPrefix.length);
|
||||
if (strippedClassName.contains('.')) {
|
||||
throw FormatException(
|
||||
'Dynamic field className must not use multiple prefixes: $className',
|
||||
);
|
||||
}
|
||||
final hostData = Map<String, dynamic>.from(value);
|
||||
hostData['className'] = strippedClassName;
|
||||
return protocol.deserializeByClassName(hostData);
|
||||
}
|
||||
}
|
||||
if (className.contains('.')) {
|
||||
for (final protocol in _hostProtocols) {
|
||||
try {
|
||||
return protocol.deserializeByClassName(value);
|
||||
} on _isc.DeserializationClassNameNotFoundException catch (_) {}
|
||||
}
|
||||
}
|
||||
return deserializeByClassName(value);
|
||||
}
|
||||
|
||||
@override
|
||||
String getModuleName() => 'halkyon_base';
|
||||
|
||||
/// 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 _iaic.Protocol().mapRecordToJson(record);
|
||||
} catch (_) {}
|
||||
try {
|
||||
return _iacc.Protocol().mapRecordToJson(record);
|
||||
} catch (_) {}
|
||||
throw Exception('Unsupported record type ${record.runtimeType}');
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue