A Minecraft Fabric mod that connects the game with ATProtocol ⛏️
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
458 ↓
459AtProtoCommands (Coroutine handler)
460 ↓
461AtProtoSessionManager (Get/create session)
462 ↓
463PlayerSyncPreferencesStore (Check sync settings)
464 ↓
465RecordManager (Create/read/update records)
466 ↓
467AtProtoClient (Make HTTP requests via XRPC)
468 ↓
469SecurityAuditor (Log security events)
470 ↓
471AT 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.