A Minecraft Fabric mod that connects the game with ATProtocol ⛏️
8
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 557 lines 12 kB view raw view rendered
1# Developer Guide: Complete API Reference 2 3## Table of Contents 41. [Authentication & Session Management](#authentication--session-management) 52. [Record Management](#record-management) 63. [Security & Utilities](#security--utilities) 74. [Configuration & Storage](#configuration--storage) 85. [Command System](#command-system) 9 10--- 11 12## Authentication & Session Management 13 14### AtProtoSessionManager 15 16The `AtProtoSessionManager` handles all authentication, token management, and session lifecycle. 17 18#### Key Methods 19 20**Authentication** 21 22```kotlin 23suspend fun authenticateWithPassword( 24 playerUuid: UUID, 25 handle: String, 26 appPassword: String 27): Result<Session> 28``` 29Authenticates a player with their handle and app password. 30 31**Parameters:** 32- `playerUuid`: Minecraft player UUID 33- `handle`: AT Protocol handle (e.g., "alice.bsky.social") 34- `appPassword`: AT Protocol app password 35 36**Returns:** `Session` object containing DID, access token, refresh token 37 38**Example:** 39```kotlin 40val session = sessionManager.authenticateWithPassword( 41 UUID.fromString("550e8400-e29b-41d4-a716-446655440000"), 42 "alice.bsky.social", 43 "abcd-1234-efgh-5678" 44).onSuccess { session -> 45 println("Authenticated as ${session.did}") 46}.onFailure { error -> 47 println("Auth failed: ${error.message}") 48} 49``` 50 51--- 52 53**Get Active Session** 54 55```kotlin 56suspend fun getSession(playerUuid: UUID): Result<Session> 57``` 58Retrieves the active session for a player, auto-refreshing if needed. 59 60**Parameters:** 61- `playerUuid`: Minecraft player UUID 62 63**Returns:** Active `Session` or error if not authenticated 64 65--- 66 67**Logout** 68 69```kotlin 70suspend fun logout(playerUuid: UUID): Result<Unit> 71``` 72Invalidates a player's session and clears stored tokens. 73 74--- 75 76**Link Identity** 77 78```kotlin 79suspend fun linkIdentity( 80 playerUuid: UUID, 81 handle: String 82): Result<DidInfo> 83``` 84Links a Minecraft UUID to an AT Protocol DID (read-only, no authentication). 85 86--- 87 88### Session Data Model 89 90```kotlin 91@Serializable 92data class Session( 93 val did: String, // AT Protocol DID 94 val handle: String, // Handle 95 val accessToken: String, // JWT access token 96 val refreshToken: String?, // JWT refresh token 97 val accessTokenExpiry: Long, // Expiration time (millis) 98 val createdAt: Long, // Creation time 99 val refreshedAt: Long? // Last refresh time 100) 101``` 102 103--- 104 105## Record Management 106 107### RecordManager 108 109Provides type-safe CRUD operations for AT Protocol records. 110 111#### Create Operations 112 113**Create Record (Auto-generated TID)** 114 115```kotlin 116suspend fun createRecord( 117 playerUuid: UUID, 118 collection: String, 119 record: JsonElement, 120 validate: Boolean = true 121): Result<StrongRef> 122``` 123 124**Parameters:** 125- `playerUuid`: Player UUID 126- `collection`: Lexicon collection name 127- `record`: JSON record data (must include `$type`) 128- `validate`: Whether to validate against lexicon schema 129 130**Returns:** `StrongRef` with URI and CID 131 132**Example:** 133```kotlin 134val statsRecord = json.parseToJsonElement(""" 135{ 136 "$type": "com.jollywhoppers.minecraft.player.stats", 137 "player": {"uuid": "$playerUuid", "username": "Alice"}, 138 "statistics": [{"key": "minecraft.mined.oak_log", "value": 1250}], 139 "playtimeMinutes": 7200, 140 "level": 34, 141 "gamemode": "survival", 142 "syncedAt": "${Instant.now()}" 143} 144""") 145 146recordManager.createRecord( 147 playerUuid, 148 "com.jollywhoppers.minecraft.player.stats", 149 statsRecord 150).onSuccess { ref -> 151 println("Record created: ${ref.uri}") 152} 153``` 154 155--- 156 157**Create Typed Record** 158 159```kotlin 160suspend inline fun <reified T> createTypedRecord( 161 playerUuid: UUID, 162 collection: String, 163 record: T, 164 validate: Boolean = true 165): Result<StrongRef> 166``` 167 168Convenience method with automatic serialization. 169 170--- 171 172#### Read Operations 173 174**Get Single Record** 175 176```kotlin 177suspend fun getRecord( 178 playerUuid: UUID, 179 collection: String, 180 rkey: String, 181 cid: String? = null 182): Result<RecordData> 183``` 184 185**Parameters:** 186- `rkey`: Record key (TID or "self" for literal records) 187- `cid`: Optional specific version 188 189**Returns:** `RecordData` with URI, value, and CID 190 191--- 192 193**List Records (Paginated)** 194 195```kotlin 196suspend fun listRecords( 197 playerUuid: UUID, 198 collection: String, 199 limit: Int = 100, 200 cursor: String? = null 201): Result<RecordPage> 202``` 203 204**Returns:** `RecordPage` with records and pagination cursor 205 206--- 207 208#### Update Operations 209 210**Put Record (Update or Create)** 211 212```kotlin 213suspend fun putRecord( 214 playerUuid: UUID, 215 collection: String, 216 rkey: String, 217 record: JsonElement, 218 validate: Boolean = true 219): Result<StrongRef> 220``` 221 222--- 223 224#### Delete Operations 225 226**Delete Record** 227 228```kotlin 229suspend fun deleteRecord( 230 playerUuid: UUID, 231 collection: String, 232 rkey: String 233): Result<Unit> 234``` 235 236--- 237 238## Security & Utilities 239 240### SecurityUtils 241 242Cryptography and validation utilities. 243 244#### Encryption 245 246**Encrypt Data** 247 248```kotlin 249fun encryptData( 250 data: String, 251 key: ByteArray 252): Result<String> // Returns base64-encoded ciphertext 253``` 254 255Uses AES-256-GCM encryption. 256 257--- 258 259**Decrypt Data** 260 261```kotlin 262fun decryptData( 263 encryptedData: String, // Base64-encoded 264 key: ByteArray 265): Result<String> 266``` 267 268--- 269 270#### Key Generation 271 272**Generate Encryption Key** 273 274```kotlin 275fun generateEncryptionKey(): ByteArray // 32 bytes for AES-256 276``` 277 278--- 279 280### SecurityAuditor 281 282Security event logging and monitoring. 283 284**Log Event** 285 286```kotlin 287fun logEvent( 288 level: AuditLevel, 289 eventType: String, 290 playerId: String?, 291 message: String, 292 metadata: Map<String, String>? = null 293) 294``` 295 296**Event Types:** 297- `AUTH_SUCCESS` 298- `AUTH_FAILURE` 299- `RATE_LIMIT_EXCEEDED` 300- `SESSION_CREATED` 301- `SESSION_DELETED` 302- `TOKEN_REFRESH` 303- `RECORD_CREATED` 304- `RECORD_DELETED` 305 306--- 307 308### RateLimiter 309 310Prevents brute-force attacks. 311 312**Check Rate Limit** 313 314```kotlin 315fun checkRateLimit( 316 identifier: String, 317 maxAttempts: Int = 3, 318 windowMinutes: Int = 15, 319 lockoutMinutes: Int = 30 320): Result<Unit> 321``` 322 323Returns `Result.success()` if within limits, or `Result.failure()` if rate limited. 324 325--- 326 327## Configuration & Storage 328 329### PlayerIdentityStore 330 331Persistent UUID ↔ DID/handle mapping storage. 332 333```kotlin 334suspend fun saveIdentity( 335 playerUuid: UUID, 336 did: String, 337 handle: String 338): Result<Unit> 339 340suspend fun getIdentity(playerUuid: UUID): Result<DidInfo?> 341 342suspend fun getAllIdentities(): Result<List<PlayerIdentity>> 343 344suspend fun removeIdentity(playerUuid: UUID): Result<Unit> 345``` 346 347**Data Model:** 348```kotlin 349data class PlayerIdentity( 350 val playerUuid: UUID, 351 val did: String, 352 val handle: String, 353 val createdAt: Instant, 354 val verifiedAt: Instant? 355) 356``` 357 358--- 359 360### PlayerSyncPreferencesStore 361 362Sync consent management (single source of truth). 363 364```kotlin 365suspend fun getSyncPreferences(playerUuid: UUID): Result<SyncPreferences> 366 367suspend fun updateSyncPreferences( 368 playerUuid: UUID, 369 preferences: SyncPreferences 370): Result<Unit> 371``` 372 373**Data Model:** 374```kotlin 375@Serializable 376data class SyncPreferences( 377 val playerUuid: UUID, 378 val syncStats: Boolean = false, 379 val syncSessions: Boolean = false, 380 val syncAchievements: Boolean = false, 381 val syncServerStatus: Boolean = false, 382 val syncIntervalMinutes: Int = 60, 383 val updatedAt: Long = System.currentTimeMillis() 384) 385``` 386 387--- 388 389### Configuration Files 390 391**Location:** `config/atproto-connect/` 392 393**Files:** 394- `player-identities.json` - UUID↔DID mappings 395- `player-sessions.json` - Encrypted auth tokens 396- `sync-preferences/` - Per-player settings 397- `.encryption.key` - AES-256 master key 398- `security-audit.log` - Security events 399 400--- 401 402## Command System 403 404### AtProtoCommands 405 406All player-facing commands are implemented in `AtProtoCommands.kt`. 407 408#### Command Structure 409 410``` 411/atproto <subcommand> [arguments] 412``` 413 414#### Available Commands 415 416**Identity Management** 417 418| Command | Purpose | 419|---------|---------| 420| `/atproto link <handle\|DID>` | Link Minecraft UUID to AT Protocol identity | 421| `/atproto unlink` | Remove identity link | 422| `/atproto whoami` | Show linked identity and status | 423| `/atproto whois <player\|handle>` | Look up another player's identity | 424 425**Authentication** 426 427| Command | Purpose | 428|---------|---------| 429| `/atproto login <handle> <app-password>` | Authenticate with app password | 430| `/atproto logout` | Remove authentication | 431| `/atproto status` | Check authentication status | 432 433**Sync Control** 434 435| Command | Purpose | 436|---------|---------| 437| `/atproto sync` | View sync consent settings | 438| `/atproto sync stats <on\|off>` | Toggle stat syncing | 439| `/atproto sync sessions <on\|off>` | Toggle session tracking | 440| `/atproto sync achievements <on\|off>` | Toggle achievement syncing | 441| `/atproto sync server-status <on\|off>` | Toggle server status snapshots | 442 443**Utilities** 444 445| Command | Purpose | 446|---------|---------| 447| `/atproto help` | Show help message | 448| `/atproto version` | Show mod version | 449 450--- 451 452## Service Integration 453 454### How Services Work Together 455 456``` 457Player Command 458459AtProtoCommands (Coroutine handler) 460461AtProtoSessionManager (Get/create session) 462463PlayerSyncPreferencesStore (Check sync settings) 464465RecordManager (Create/read/update records) 466467AtProtoClient (Make HTTP requests via XRPC) 468469SecurityAuditor (Log security events) 470471AT Protocol Network (Firehose, PDS, etc.) 472``` 473 474--- 475 476## Error Handling 477 478All services return `Result<T>` types for composable error handling. 479 480**Pattern:** 481```kotlin 482service.doSomething() 483 .onSuccess { result -> 484 println("Success: $result") 485 } 486 .onFailure { error -> 487 println("Error: ${error.message}") 488 securityAuditor.logEvent( 489 AuditLevel.WARNING, 490 "OPERATION_FAILED", 491 playerId, 492 error.message ?: "Unknown error" 493 ) 494 } 495``` 496 497--- 498 499## Performance Considerations 500 5011. **Session Caching**: Sessions are cached to avoid repeated token refresh 5022. **Rate Limiting**: Prevents brute-force attacks without blocking legitimate users 5033. **Encryption**: AES-256-GCM is fast while maintaining security 5044. **Async Operations**: All I/O uses Kotlin Coroutines for non-blocking execution 5055. **Pagination**: Record listings use cursors to handle large datasets 506 507--- 508 509## Thread Safety 510 511- All mutable state is protected with proper synchronization 512- Session storage uses atomic writes 513- Configuration file access is serialized 514- Security audit logging is thread-safe 515 516--- 517 518## Testing 519 520See [TEST_GUIDE.md](TEST_GUIDE.md) for comprehensive testing documentation. 521 522--- 523 524## Troubleshooting 525 526### Common Issues 527 528**"Authentication failed: Invalid token"** 529- App password may be expired or revoked 530- Create a new app password and login again 531 532**"Session not found"** 533- Player needs to authenticate first with `/atproto login` 534- Check `config/atproto-connect/player-sessions.json` exists 535 536**"Rate limit exceeded"** 537- Too many failed login attempts 538- Wait 30 minutes or check `security-audit.log` for details 539 540**"Record creation failed: Invalid collection"** 541- Collection name may be misspelled 542- Verify against defined lexicon namespaces 543 544--- 545 546## Examples 547 548See `docs/examples/` for complete working code examples: 549- `RecordCreationExample.kt` - Creating and syncing records 550- `AppViewExample.kt` - Building an AppView service 551- `RecordManagerExamples.kt` - CRUD operations 552 553--- 554 555## API Stability 556 557This API is currently in **Alpha**. Breaking changes may occur in minor version updates.