feat(base,app,learn,todo,train,meditate): agent accounts with tokens

ADR 0044's step 6a (D42, D43, D45): accounts for programs, such as AI
assistants, that an identified person makes from the Profile.

halkyon_base keeps them on the instance's register, which its members
ask: an agent is an account (agent_account: its owner, its name, its
public keys, set by itself once) with one token (agent_token: 32
random bytes, kept as their SHA-256 alone, shown once). agents.create,
mine, newToken, revoke, delete and setKeys serve its owner;
agentSignIn.signIn exchanges the token for an ordinary server-side
session of a day, with the scopes identified and agent, at most 60
sign-ins an hour from a network. Revoking a token or making a new one
ends the agent's sessions; a token unused for 90 days lapses in every
service's pruning. Up to 5 agents a person, where the operator didn't
switch them off (AGENTS=off; said on the privacy page and in
instance.basics). An agent makes no agents, creates or owns no shared
space, is invited and raised as a Viewer alone, is never handed a
space on, is named no operator and granted no assistants; each refusal
has its test. Deleting a person deletes their agents first; an agent's
public profile names whose agent it is.

In the apps, every Profile has an Agents card (halkyon_app's
AgentsSection): made with a name and a handle, its token shown once to
copy, a new token, the token taken back, deleted. Learn's Share sheet
marks an agent among the members and offers it no role above Viewer.

The migrations, the module's and each host's (Learn, Meditate, Todo,
Train), are additive alone: CREATE TABLE "agent_account" with a unique
index on "agentId" (one row an agent account) and one on "ownerId" (a
person's agents, and deleting them with the person), and CREATE TABLE
"agent_token" with unique indexes on "agentId" (one token an agent)
and "tokenHash" (the sign-in finds the token by its hash). No existing
table is touched, so the server before the deploy keeps working on the
migrated database.

Whats-New: Make agents in your Profile: accounts for programs such as AI assistants, which sign in with a token and see only what you share with them.
Whats-New-De: Leg in deinem Profil Agenten an: Konten für Programme wie KI-Assistenten, die sich mit einem Token anmelden und nur sehen, was du mit ihnen teilst.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-11-11 19:55:27 +01:00
commit 7aee78bd87
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
11 changed files with 113257 additions and 50 deletions

View file

@ -0,0 +1,164 @@
/* 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:serverpod_client/serverpod_client.dart' as _isc;
/// An agent as its owner's Profile lists it (Halkyon's ADR 0044, D45).
abstract class AgentInfo
implements _isc.SerializableModel, _isc.ProtocolSerialization {
AgentInfo._({
required this.id,
required this.name,
required this.handle,
required this.createdAt,
this.lastUsedAt,
required this.hasToken,
required this.hasKeys,
});
factory AgentInfo({
required _isc.UuidValue id,
required String name,
required String handle,
required DateTime createdAt,
DateTime? lastUsedAt,
required bool hasToken,
required bool hasKeys,
}) = _AgentInfoImpl;
factory AgentInfo.fromJson(Map<String, dynamic> jsonSerialization) {
return AgentInfo(
id: _isc.UuidValueJsonExtension.fromJson(jsonSerialization['id']),
name: jsonSerialization['name'] as String,
handle: jsonSerialization['handle'] as String,
createdAt: _isc.DateTimeJsonExtension.fromJson(
jsonSerialization['createdAt'],
),
lastUsedAt: jsonSerialization['lastUsedAt'] == null
? null
: _isc.DateTimeJsonExtension.fromJson(
jsonSerialization['lastUsedAt'],
),
hasToken: _isc.BoolJsonExtension.fromJson(jsonSerialization['hasToken']),
hasKeys: _isc.BoolJsonExtension.fromJson(jsonSerialization['hasKeys']),
);
}
/// The agent's account.
_isc.UuidValue id;
String name;
String handle;
DateTime createdAt;
/// When it last signed in with its token; null while never.
DateTime? lastUsedAt;
/// Whether it has a token: revoked, it has none until a new one is made.
bool hasToken;
/// Whether it set its public keys.
bool hasKeys;
/// Returns a shallow copy of this [AgentInfo]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
AgentInfo copyWith({
_isc.UuidValue? id,
String? name,
String? handle,
DateTime? createdAt,
DateTime? lastUsedAt,
bool? hasToken,
bool? hasKeys,
});
@override
Map<String, dynamic> toJson() {
return {
'__className__': 'halkyon_base.AgentInfo',
'id': id.toJson(),
'name': name,
'handle': handle,
'createdAt': createdAt.toJson(),
if (lastUsedAt != null) 'lastUsedAt': lastUsedAt?.toJson(),
'hasToken': hasToken,
'hasKeys': hasKeys,
};
}
@override
Map<String, dynamic> toJsonForProtocol() {
return {
'__className__': 'halkyon_base.AgentInfo',
'id': id.toJson(),
'name': name,
'handle': handle,
'createdAt': createdAt.toJson(),
if (lastUsedAt != null) 'lastUsedAt': lastUsedAt?.toJson(),
'hasToken': hasToken,
'hasKeys': hasKeys,
};
}
@override
String toString() {
return _isc.SerializationManager.encode(this);
}
}
class _Undefined {}
class _AgentInfoImpl extends AgentInfo {
_AgentInfoImpl({
required _isc.UuidValue id,
required String name,
required String handle,
required DateTime createdAt,
DateTime? lastUsedAt,
required bool hasToken,
required bool hasKeys,
}) : super._(
id: id,
name: name,
handle: handle,
createdAt: createdAt,
lastUsedAt: lastUsedAt,
hasToken: hasToken,
hasKeys: hasKeys,
);
/// Returns a shallow copy of this [AgentInfo]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
@override
AgentInfo copyWith({
_isc.UuidValue? id,
String? name,
String? handle,
DateTime? createdAt,
Object? lastUsedAt = _Undefined,
bool? hasToken,
bool? hasKeys,
}) {
return AgentInfo(
id: id ?? this.id,
name: name ?? this.name,
handle: handle ?? this.handle,
createdAt: createdAt ?? this.createdAt,
lastUsedAt: lastUsedAt is DateTime? ? lastUsedAt : this.lastUsedAt,
hasToken: hasToken ?? this.hasToken,
hasKeys: hasKeys ?? this.hasKeys,
);
}
}

View file

@ -0,0 +1,96 @@
/* 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/src/protocol/protocol.dart' as _iwgbpyo5;
import 'package:serverpod_client/serverpod_client.dart' as _isc;
import '../agent/agent_info.dart' as _idw6egxv;
/// An agent just made, or given a new token: the token, shown this once.
abstract class AgentMade
implements _isc.SerializableModel, _isc.ProtocolSerialization {
AgentMade._({
required this.agent,
required this.token,
});
factory AgentMade({
required _idw6egxv.AgentInfo agent,
required String token,
}) = _AgentMadeImpl;
factory AgentMade.fromJson(Map<String, dynamic> jsonSerialization) {
return AgentMade(
agent: _iwgbpyo5.Protocol().deserialize<_idw6egxv.AgentInfo>(
jsonSerialization['agent'],
),
token: jsonSerialization['token'] as String,
);
}
_idw6egxv.AgentInfo agent;
String token;
/// Returns a shallow copy of this [AgentMade]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
AgentMade copyWith({
_idw6egxv.AgentInfo? agent,
String? token,
});
@override
Map<String, dynamic> toJson() {
return {
'__className__': 'halkyon_base.AgentMade',
'agent': agent.toJson(),
'token': token,
};
}
@override
Map<String, dynamic> toJsonForProtocol() {
return {
'__className__': 'halkyon_base.AgentMade',
'agent': agent.toJsonForProtocol(),
'token': token,
};
}
@override
String toString() {
return _isc.SerializationManager.encode(this);
}
}
class _AgentMadeImpl extends AgentMade {
_AgentMadeImpl({
required _idw6egxv.AgentInfo agent,
required String token,
}) : super._(
agent: agent,
token: token,
);
/// Returns a shallow copy of this [AgentMade]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
@override
AgentMade copyWith({
_idw6egxv.AgentInfo? agent,
String? token,
}) {
return AgentMade(
agent: agent ?? this.agent.copyWith(),
token: token ?? this.token,
);
}
}

View file

@ -0,0 +1,67 @@
/* 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:serverpod_client/serverpod_client.dart' as _isc;
/// Why a call about agents was refused (Halkyon's ADR 0044, D45).
enum AgentRefusal implements _isc.SerializableModel {
/// The operator switched agents off (`AGENTS=off`).
agentsOff,
/// The person has as many agents as they may (5).
tooMany,
/// An agent asked for what only people do, or a person for what only
/// agents do.
notForAgents,
/// No agent of yours is that: another person's answers alike.
noSuchAgent,
/// No token is that, or it lapsed.
notValid,
/// The agent set its keys already.
keysSet,
/// Too many sign-ins from this network this hour.
tooManyAttempts;
static AgentRefusal fromJson(String name) {
switch (name) {
case 'agentsOff':
return AgentRefusal.agentsOff;
case 'tooMany':
return AgentRefusal.tooMany;
case 'notForAgents':
return AgentRefusal.notForAgents;
case 'noSuchAgent':
return AgentRefusal.noSuchAgent;
case 'notValid':
return AgentRefusal.notValid;
case 'keysSet':
return AgentRefusal.keysSet;
case 'tooManyAttempts':
return AgentRefusal.tooManyAttempts;
default:
throw ArgumentError(
'Value "$name" cannot be converted to "AgentRefusal"',
);
}
}
@override
String toJson() => name;
@override
String toString() => name;
}

View file

@ -0,0 +1,76 @@
/* 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:serverpod_client/serverpod_client.dart' as _isc;
import '../agent/agent_refusal.dart' as _igo9c1fx;
/// A call about agents was refused; nothing changed.
abstract class AgentRefusedException
implements
_isc.SerializableException,
_isc.SerializableModel,
_isc.ProtocolSerialization {
AgentRefusedException._({required this.reason});
factory AgentRefusedException({required _igo9c1fx.AgentRefusal reason}) =
_AgentRefusedExceptionImpl;
factory AgentRefusedException.fromJson(
Map<String, dynamic> jsonSerialization,
) {
return AgentRefusedException(
reason: _igo9c1fx.AgentRefusal.fromJson(
(jsonSerialization['reason'] as String),
),
);
}
_igo9c1fx.AgentRefusal reason;
/// Returns a shallow copy of this [AgentRefusedException]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
AgentRefusedException copyWith({_igo9c1fx.AgentRefusal? reason});
@override
Map<String, dynamic> toJson() {
return {
'__className__': 'halkyon_base.AgentRefusedException',
'reason': reason.toJson(),
};
}
@override
Map<String, dynamic> toJsonForProtocol() {
return {
'__className__': 'halkyon_base.AgentRefusedException',
'reason': reason.toJson(),
};
}
@override
String toString() {
return 'AgentRefusedException(reason: $reason)';
}
}
class _AgentRefusedExceptionImpl extends AgentRefusedException {
_AgentRefusedExceptionImpl({required _igo9c1fx.AgentRefusal reason})
: super._(reason: reason);
/// Returns a shallow copy of this [AgentRefusedException]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
@override
AgentRefusedException copyWith({_igo9c1fx.AgentRefusal? reason}) {
return AgentRefusedException(reason: reason ?? this.reason);
}
}

View file

@ -14,6 +14,10 @@ import 'dart:async' as _ida;
import 'dart:typed_data' as _idt;
import 'package:halkyon_base_client/src/protocol/admission/waiting_state.dart'
as _i1sx1z35;
import 'package:halkyon_base_client/src/protocol/agent/agent_info.dart'
as _ihwevl5h;
import 'package:halkyon_base_client/src/protocol/agent/agent_made.dart'
as _ir0q7xv5;
import 'package:halkyon_base_client/src/protocol/assistant/assistant_answer.dart'
as _il9lgl6t;
import 'package:halkyon_base_client/src/protocol/assistant/assistant_grantee.dart'
@ -141,6 +145,108 @@ class EndpointWaiting extends _isc.EndpointRef {
);
}
/// An agent signing in with its token (Halkyon's ADR 0044, D43): the
/// register checks the token and stamps its use, and this server makes a
/// session lasting a day, as an agent.
/// {@category Endpoint}
class EndpointAgentSignIn extends _isc.EndpointRef {
EndpointAgentSignIn(_isc.EndpointCaller caller) : super(caller);
@override
String get name => 'halkyon_base.agentSignIn';
/// A session for the agent [token] is of. Refused for a token that is
/// none or lapsed (`AgentRefusal.notValid`), where the operator switched
/// agents off (`agentsOff`), and past this network's sign-ins this hour
/// (`tooManyAttempts`).
_ida.Future<_iacc.AuthSuccess> signIn({required String token}) =>
caller.callServerEndpoint<_iacc.AuthSuccess>(
'halkyon_base.agentSignIn',
'signIn',
{'token': token},
);
}
/// A person's agents (Halkyon's ADR 0044, D6, D12, D45), made and taken
/// back from their Profile, and an agent's own keys. Everything goes
/// through the register, which keeps agents.
/// {@category Endpoint}
class EndpointAgents extends _isc.EndpointRef {
EndpointAgents(_isc.EndpointCaller caller) : super(caller);
@override
String get name => 'halkyon_base.agents';
/// Makes an agent called [name] with [handle], with you its owner; its
/// token is in the answer alone (D45). Refused where the operator
/// switched agents off (`AgentRefusal.agentsOff`), past 5 agents
/// (`tooMany`), to an agent (`notForAgents`), and for a handle or name a
/// profile couldn't have (`ProfileRefusedException`); counts as an
/// answer about a handle.
_ida.Future<_ir0q7xv5.AgentMade> create({
required String name,
required String handle,
}) => caller.callServerEndpoint<_ir0q7xv5.AgentMade>(
'halkyon_base.agents',
'create',
{
'name': name,
'handle': handle,
},
);
/// Your agents, the first made first.
_ida.Future<List<_ihwevl5h.AgentInfo>> mine() =>
caller.callServerEndpoint<List<_ihwevl5h.AgentInfo>>(
'halkyon_base.agents',
'mine',
{},
);
/// A new token for your agent [agent], in the answer alone: the one
/// before ends, and the agent's sessions with it. Refused for an agent
/// not yours (`noSuchAgent`).
_ida.Future<_ir0q7xv5.AgentMade> newToken({required _isc.UuidValue agent}) =>
caller.callServerEndpoint<_ir0q7xv5.AgentMade>(
'halkyon_base.agents',
'newToken',
{'agent': agent},
);
/// Takes your agent [agent]'s token back: it signs in no more, and its
/// sessions end. Refused for an agent not yours (`noSuchAgent`).
_ida.Future<void> revoke({required _isc.UuidValue agent}) =>
caller.callServerEndpoint<void>(
'halkyon_base.agents',
'revoke',
{'agent': agent},
);
/// Deletes your agent [agent], as an account is deleted. Refused for an
/// agent not yours (`noSuchAgent`).
_ida.Future<void> delete({required _isc.UuidValue agent}) =>
caller.callServerEndpoint<void>(
'halkyon_base.agents',
'delete',
{'agent': agent},
);
/// Sets your public keys, as an agent, once (D6): what members seal
/// shared keys to, pinning them on first sight. Refused for a person
/// (`notForAgents`) and once set (`keysSet`).
_ida.Future<void> setKeys({
required _idt.ByteData encryption,
required _idt.ByteData signing,
}) => caller.callServerEndpoint<void>(
'halkyon_base.agents',
'setKeys',
{
'encryption': encryption,
'signing': signing,
},
);
}
/// The operator's assistants as a person uses them (Halkyon Learn's ADR
/// 0021, points 6 to 9): those granted to them, their agreement, their
/// questions with the answers streamed (D35), and their own figures.
@ -1762,6 +1868,8 @@ class EndpointSimpleLogin extends _isc.EndpointRef {
class Caller extends _isc.ModuleEndpointCaller {
Caller(_isc.ServerpodClientShared client) : super(client) {
waiting = EndpointWaiting(this);
agentSignIn = EndpointAgentSignIn(this);
agents = EndpointAgents(this);
assistant = EndpointAssistant(this);
assistantOperator = EndpointAssistantOperator(this);
account = EndpointAccount(this);
@ -1783,6 +1891,10 @@ class Caller extends _isc.ModuleEndpointCaller {
late final EndpointWaiting waiting;
late final EndpointAgentSignIn agentSignIn;
late final EndpointAgents agents;
late final EndpointAssistant assistant;
late final EndpointAssistantOperator assistantOperator;
@ -1820,6 +1932,8 @@ class Caller extends _isc.ModuleEndpointCaller {
@override
Map<String, _isc.EndpointRef> get endpointRefLookup => {
'halkyon_base.waiting': waiting,
'halkyon_base.agentSignIn': agentSignIn,
'halkyon_base.agents': agents,
'halkyon_base.assistant': assistant,
'halkyon_base.assistantOperator': assistantOperator,
'halkyon_base.account': account,

View file

@ -30,10 +30,12 @@ abstract class InstanceBasics
bool? simpleLogin,
_iypagcol.SignUpMode? signUp,
bool? assistantOwnKeys,
bool? agents,
}) : passwordSignIn = passwordSignIn ?? false,
simpleLogin = simpleLogin ?? false,
signUp = signUp ?? _iypagcol.SignUpMode.open,
assistantOwnKeys = assistantOwnKeys ?? false;
assistantOwnKeys = assistantOwnKeys ?? false,
agents = agents ?? false;
factory InstanceBasics({
required String app,
@ -46,6 +48,7 @@ abstract class InstanceBasics
bool? simpleLogin,
_iypagcol.SignUpMode? signUp,
bool? assistantOwnKeys,
bool? agents,
}) = _InstanceBasicsImpl;
factory InstanceBasics.fromJson(Map<String, dynamic> jsonSerialization) {
@ -76,6 +79,9 @@ abstract class InstanceBasics
: _isc.BoolJsonExtension.fromJson(
jsonSerialization['assistantOwnKeys'],
),
agents: jsonSerialization['agents'] == null
? null
: _isc.BoolJsonExtension.fromJson(jsonSerialization['agents']),
);
}
@ -124,6 +130,10 @@ abstract class InstanceBasics
/// service, which offers no assistant yet (D43).
bool assistantOwnKeys;
/// Whether people may make agents here (Halkyon's ADR 0044, D45): the
/// register's operator didn't switch them off (`AGENTS=off`).
bool agents;
/// Returns a shallow copy of this [InstanceBasics]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
@ -138,6 +148,7 @@ abstract class InstanceBasics
bool? simpleLogin,
_iypagcol.SignUpMode? signUp,
bool? assistantOwnKeys,
bool? agents,
});
@override
Map<String, dynamic> toJson() {
@ -153,6 +164,7 @@ abstract class InstanceBasics
'simpleLogin': simpleLogin,
'signUp': signUp.toJson(),
'assistantOwnKeys': assistantOwnKeys,
'agents': agents,
};
}
@ -170,6 +182,7 @@ abstract class InstanceBasics
'simpleLogin': simpleLogin,
'signUp': signUp.toJson(),
'assistantOwnKeys': assistantOwnKeys,
'agents': agents,
};
}
@ -193,6 +206,7 @@ class _InstanceBasicsImpl extends InstanceBasics {
bool? simpleLogin,
_iypagcol.SignUpMode? signUp,
bool? assistantOwnKeys,
bool? agents,
}) : super._(
app: app,
emailSignIn: emailSignIn,
@ -204,6 +218,7 @@ class _InstanceBasicsImpl extends InstanceBasics {
simpleLogin: simpleLogin,
signUp: signUp,
assistantOwnKeys: assistantOwnKeys,
agents: agents,
);
/// Returns a shallow copy of this [InstanceBasics]
@ -221,6 +236,7 @@ class _InstanceBasicsImpl extends InstanceBasics {
bool? simpleLogin,
_iypagcol.SignUpMode? signUp,
bool? assistantOwnKeys,
bool? agents,
}) {
return InstanceBasics(
app: app ?? this.app,
@ -235,6 +251,7 @@ class _InstanceBasicsImpl extends InstanceBasics {
simpleLogin: simpleLogin ?? this.simpleLogin,
signUp: signUp ?? this.signUp,
assistantOwnKeys: assistantOwnKeys ?? this.assistantOwnKeys,
agents: agents ?? this.agents,
);
}
}

View file

@ -30,7 +30,11 @@ enum OperatorRefusal implements _isc.SerializableModel {
assistantNotSet,
/// A limit below 0.
invalidLimit;
invalidLimit,
/// The account is an agent (Halkyon's ADR 0044, D45): never an operator,
/// and granted no assistant.
isAgent;
static OperatorRefusal fromJson(String name) {
switch (name) {
@ -44,6 +48,8 @@ enum OperatorRefusal implements _isc.SerializableModel {
return OperatorRefusal.assistantNotSet;
case 'invalidLimit':
return OperatorRefusal.invalidLimit;
case 'isAgent':
return OperatorRefusal.isAgent;
default:
throw ArgumentError(
'Value "$name" cannot be converted to "OperatorRefusal"',

View file

@ -27,6 +27,7 @@ abstract class Profile
this.pageUrl,
this.avatarUrl,
required this.handleFixed,
this.agentOf,
});
factory Profile({
@ -39,6 +40,7 @@ abstract class Profile
String? pageUrl,
String? avatarUrl,
required bool handleFixed,
String? agentOf,
}) = _ProfileImpl;
factory Profile.fromJson(Map<String, dynamic> jsonSerialization) {
@ -60,6 +62,7 @@ abstract class Profile
handleFixed: _isc.BoolJsonExtension.fromJson(
jsonSerialization['handleFixed'],
),
agentOf: jsonSerialization['agentOf'] as String?,
);
}
@ -94,6 +97,10 @@ abstract class Profile
/// Whether the handle is fixed, as its person has published.
bool handleFixed;
/// For an agent (Halkyon's ADR 0044, D45), its owner's handle; null for a
/// person.
String? agentOf;
/// Returns a shallow copy of this [Profile]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
@ -107,6 +114,7 @@ abstract class Profile
String? pageUrl,
String? avatarUrl,
bool? handleFixed,
String? agentOf,
});
@override
Map<String, dynamic> toJson() {
@ -121,6 +129,7 @@ abstract class Profile
if (pageUrl != null) 'pageUrl': pageUrl,
if (avatarUrl != null) 'avatarUrl': avatarUrl,
'handleFixed': handleFixed,
if (agentOf != null) 'agentOf': agentOf,
};
}
@ -137,6 +146,7 @@ abstract class Profile
if (pageUrl != null) 'pageUrl': pageUrl,
if (avatarUrl != null) 'avatarUrl': avatarUrl,
'handleFixed': handleFixed,
if (agentOf != null) 'agentOf': agentOf,
};
}
@ -159,6 +169,7 @@ class _ProfileImpl extends Profile {
String? pageUrl,
String? avatarUrl,
required bool handleFixed,
String? agentOf,
}) : super._(
handle: handle,
address: address,
@ -169,6 +180,7 @@ class _ProfileImpl extends Profile {
pageUrl: pageUrl,
avatarUrl: avatarUrl,
handleFixed: handleFixed,
agentOf: agentOf,
);
/// Returns a shallow copy of this [Profile]
@ -185,6 +197,7 @@ class _ProfileImpl extends Profile {
Object? pageUrl = _Undefined,
Object? avatarUrl = _Undefined,
bool? handleFixed,
Object? agentOf = _Undefined,
}) {
return Profile(
handle: handle ?? this.handle,
@ -198,6 +211,7 @@ class _ProfileImpl extends Profile {
pageUrl: pageUrl is String? ? pageUrl : this.pageUrl,
avatarUrl: avatarUrl is String? ? avatarUrl : this.avatarUrl,
handleFixed: handleFixed ?? this.handleFixed,
agentOf: agentOf is String? ? agentOf : this.agentOf,
);
}
}

View file

@ -11,6 +11,8 @@
// ignore_for_file: dead_code, unnecessary_type_check
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:halkyon_base_client/src/protocol/agent/agent_info.dart'
as _ihwevl5h;
import 'package:halkyon_base_client/src/protocol/assistant/assistant_grantee.dart'
as _irq97saf;
import 'package:halkyon_base_client/src/protocol/assistant/assistant_month_figures.dart'
@ -40,6 +42,10 @@ import 'admission/sign_up_mode.dart' as _iws42x5t;
import 'admission/sign_up_refusal.dart' as _i3fmyy9u;
import 'admission/sign_up_refused_exception.dart' as _ihsvd1xl;
import 'admission/waiting_state.dart' as _ia0s7l9v;
import 'agent/agent_info.dart' as _it87j9ex;
import 'agent/agent_made.dart' as _i4fdujfq;
import 'agent/agent_refusal.dart' as _i4y2xtqd;
import 'agent/agent_refused_exception.dart' as _iuwiiyy0;
import 'assistant/assistant_answer.dart' as _i4xvagvh;
import 'assistant/assistant_effort.dart' as _iy0r1pfb;
import 'assistant/assistant_granted.dart' as _iask2wp0;
@ -118,6 +124,10 @@ export 'admission/sign_up_mode.dart';
export 'admission/sign_up_refusal.dart';
export 'admission/sign_up_refused_exception.dart';
export 'admission/waiting_state.dart';
export 'agent/agent_info.dart';
export 'agent/agent_made.dart';
export 'agent/agent_refusal.dart';
export 'agent/agent_refused_exception.dart';
export 'assistant/assistant_answer.dart';
export 'assistant/assistant_effort.dart';
export 'assistant/assistant_granted.dart';
@ -253,6 +263,18 @@ class Protocol extends _isc.SerializationManager {
if (t == _ia0s7l9v.WaitingState) {
return _ia0s7l9v.WaitingState.fromJson(data) as T;
}
if (t == _it87j9ex.AgentInfo) {
return _it87j9ex.AgentInfo.fromJson(data) as T;
}
if (t == _i4fdujfq.AgentMade) {
return _i4fdujfq.AgentMade.fromJson(data) as T;
}
if (t == _i4y2xtqd.AgentRefusal) {
return _i4y2xtqd.AgentRefusal.fromJson(data) as T;
}
if (t == _iuwiiyy0.AgentRefusedException) {
return _iuwiiyy0.AgentRefusedException.fromJson(data) as T;
}
if (t == _i4xvagvh.AssistantAnswer) {
return _i4xvagvh.AssistantAnswer.fromJson(data) as T;
}
@ -494,6 +516,21 @@ class Protocol extends _isc.SerializationManager {
if (t == _isc.getType<_ia0s7l9v.WaitingState?>()) {
return (data != null ? _ia0s7l9v.WaitingState.fromJson(data) : null) as T;
}
if (t == _isc.getType<_it87j9ex.AgentInfo?>()) {
return (data != null ? _it87j9ex.AgentInfo.fromJson(data) : null) as T;
}
if (t == _isc.getType<_i4fdujfq.AgentMade?>()) {
return (data != null ? _i4fdujfq.AgentMade.fromJson(data) : null) as T;
}
if (t == _isc.getType<_i4y2xtqd.AgentRefusal?>()) {
return (data != null ? _i4y2xtqd.AgentRefusal.fromJson(data) : null) as T;
}
if (t == _isc.getType<_iuwiiyy0.AgentRefusedException?>()) {
return (data != null
? _iuwiiyy0.AgentRefusedException.fromJson(data)
: null)
as T;
}
if (t == _isc.getType<_i4xvagvh.AssistantAnswer?>()) {
return (data != null ? _i4xvagvh.AssistantAnswer.fromJson(data) : null)
as T;
@ -864,6 +901,12 @@ class Protocol extends _isc.SerializationManager {
if (t == Set<String>) {
return (data as List).map((e) => deserialize<String>(e)).toSet() as T;
}
if (t == List<_ihwevl5h.AgentInfo>) {
return (data as List)
.map((e) => deserialize<_ihwevl5h.AgentInfo>(e))
.toList()
as T;
}
if (t == List<_igllc81w.AssistantMonthFigures>) {
return (data as List)
.map((e) => deserialize<_igllc81w.AssistantMonthFigures>(e))
@ -944,6 +987,10 @@ class Protocol extends _isc.SerializationManager {
_i3fmyy9u.SignUpRefusal => 'SignUpRefusal',
_ihsvd1xl.SignUpRefusedException => 'SignUpRefusedException',
_ia0s7l9v.WaitingState => 'WaitingState',
_it87j9ex.AgentInfo => 'AgentInfo',
_i4fdujfq.AgentMade => 'AgentMade',
_i4y2xtqd.AgentRefusal => 'AgentRefusal',
_iuwiiyy0.AgentRefusedException => 'AgentRefusedException',
_i4xvagvh.AssistantAnswer => 'AssistantAnswer',
_iy0r1pfb.AssistantEffort => 'AssistantEffort',
_iask2wp0.AssistantGranted => 'AssistantGranted',
@ -1044,6 +1091,14 @@ class Protocol extends _isc.SerializationManager {
return 'SignUpRefusedException';
case _ia0s7l9v.WaitingState():
return 'WaitingState';
case _it87j9ex.AgentInfo():
return 'AgentInfo';
case _i4fdujfq.AgentMade():
return 'AgentMade';
case _i4y2xtqd.AgentRefusal():
return 'AgentRefusal';
case _iuwiiyy0.AgentRefusedException():
return 'AgentRefusedException';
case _i4xvagvh.AssistantAnswer():
return 'AssistantAnswer';
case _iy0r1pfb.AssistantEffort():
@ -1215,6 +1270,18 @@ class Protocol extends _isc.SerializationManager {
if (dataClassName == 'WaitingState') {
return deserialize<_ia0s7l9v.WaitingState>(data['data']);
}
if (dataClassName == 'AgentInfo') {
return deserialize<_it87j9ex.AgentInfo>(data['data']);
}
if (dataClassName == 'AgentMade') {
return deserialize<_i4fdujfq.AgentMade>(data['data']);
}
if (dataClassName == 'AgentRefusal') {
return deserialize<_i4y2xtqd.AgentRefusal>(data['data']);
}
if (dataClassName == 'AgentRefusedException') {
return deserialize<_iuwiiyy0.AgentRefusedException>(data['data']);
}
if (dataClassName == 'AssistantAnswer') {
return deserialize<_i4xvagvh.AssistantAnswer>(data['data']);
}

View file

@ -27,7 +27,9 @@ abstract class SharedSpaceMemberInfo
required this.invited,
required this.you,
bool? byEmail,
}) : byEmail = byEmail ?? false;
bool? agent,
}) : byEmail = byEmail ?? false,
agent = agent ?? false;
factory SharedSpaceMemberInfo({
required _isc.UuidValue id,
@ -38,6 +40,7 @@ abstract class SharedSpaceMemberInfo
required bool invited,
required bool you,
bool? byEmail,
bool? agent,
}) = _SharedSpaceMemberInfoImpl;
factory SharedSpaceMemberInfo.fromJson(
@ -58,6 +61,9 @@ abstract class SharedSpaceMemberInfo
byEmail: jsonSerialization['byEmail'] == null
? null
: _isc.BoolJsonExtension.fromJson(jsonSerialization['byEmail']),
agent: jsonSerialization['agent'] == null
? null
: _isc.BoolJsonExtension.fromJson(jsonSerialization['agent']),
);
}
@ -86,6 +92,9 @@ abstract class SharedSpaceMemberInfo
/// space's members never see: neither handle nor name.
bool byEmail;
/// Whether it is an agent (ADR 0044, D6, D45), a Viewer alone.
bool agent;
/// Returns a shallow copy of this [SharedSpaceMemberInfo]
/// with some or all fields replaced by the given arguments.
@_isc.useResult
@ -98,6 +107,7 @@ abstract class SharedSpaceMemberInfo
bool? invited,
bool? you,
bool? byEmail,
bool? agent,
});
@override
Map<String, dynamic> toJson() {
@ -111,6 +121,7 @@ abstract class SharedSpaceMemberInfo
'invited': invited,
'you': you,
'byEmail': byEmail,
'agent': agent,
};
}
@ -126,6 +137,7 @@ abstract class SharedSpaceMemberInfo
'invited': invited,
'you': you,
'byEmail': byEmail,
'agent': agent,
};
}
@ -147,6 +159,7 @@ class _SharedSpaceMemberInfoImpl extends SharedSpaceMemberInfo {
required bool invited,
required bool you,
bool? byEmail,
bool? agent,
}) : super._(
id: id,
handle: handle,
@ -156,6 +169,7 @@ class _SharedSpaceMemberInfoImpl extends SharedSpaceMemberInfo {
invited: invited,
you: you,
byEmail: byEmail,
agent: agent,
);
/// Returns a shallow copy of this [SharedSpaceMemberInfo]
@ -171,6 +185,7 @@ class _SharedSpaceMemberInfoImpl extends SharedSpaceMemberInfo {
bool? invited,
bool? you,
bool? byEmail,
bool? agent,
}) {
return SharedSpaceMemberInfo(
id: id ?? this.id,
@ -181,6 +196,7 @@ class _SharedSpaceMemberInfoImpl extends SharedSpaceMemberInfo {
invited: invited ?? this.invited,
you: you ?? this.you,
byEmail: byEmail ?? this.byEmail,
agent: agent ?? this.agent,
);
}
}

View file

@ -43,7 +43,10 @@ enum SharedSpaceRefusal implements _isc.SerializableModel {
handleNeeded,
/// The code proved another address than the one invited (D37).
otherAddress;
otherAddress,
/// An agent is a Viewer alone, and creates no shared space (D45).
agentViewer;
static SharedSpaceRefusal fromJson(String name) {
switch (name) {
@ -67,6 +70,8 @@ enum SharedSpaceRefusal implements _isc.SerializableModel {
return SharedSpaceRefusal.handleNeeded;
case 'otherAddress':
return SharedSpaceRefusal.otherAddress;
case 'agentViewer':
return SharedSpaceRefusal.agentViewer;
default:
throw ArgumentError(
'Value "$name" cannot be converted to "SharedSpaceRefusal"',