A Transparent and Verifiable Way to Sync the AT Protocol's PLC Directory

update lib docs

+62 -10
+62 -10
docs/library.md
··· 228 228 229 229 ```go 230 230 type PLCOperation struct { 231 - DID string // The DID (did:plc:...) 232 - Operation map[string]interface{} // The operation data 233 - CID string // Content identifier 234 - Nullified interface{} // nil, false, or CID string 235 - CreatedAt time.Time // When it was created 236 - RawJSON []byte // Original JSON bytes 231 + DID string // The DID (did:plc:...) 232 + Operation json.RawMessage // Raw JSON bytes (use GetOperationMap() to parse) 233 + CID string // Content identifier 234 + Nullified interface{} // nil, false, or CID string 235 + CreatedAt time.Time // When it was created 236 + 237 + // Internal fields (populated automatically) 238 + RawJSON []byte // Original JSON line 239 + ParsedOperation map[string]interface{} // Cached parsed data 237 240 } 238 241 242 + // Accessing operation data: 243 + operation, err := op.GetOperationMap() // Parses Operation field (cached) 244 + if err != nil || operation == nil { 245 + return 246 + } 247 + 248 + // Now you can access fields 249 + services := operation["services"].(map[string]interface{}) 250 + 239 251 // Check if operation was nullified 240 252 if op.IsNullified() { 241 253 log.Printf("Operation %s was nullified by %s", op.CID, op.GetNullifyingCID()) 242 254 } 243 255 ``` 244 256 257 + ### Accessing Operation Data 258 + 259 + The `Operation` field uses lazy parsing for performance. Always parse it before accessing: 260 + 261 + ```go 262 + // ❌ Wrong - won't compile 263 + services := op.Operation["services"] 264 + 265 + // ✅ Correct 266 + operation, err := op.GetOperationMap() 267 + if err != nil || operation == nil { 268 + return 269 + } 270 + services, ok := operation["services"].(map[string]interface{}) 271 + ``` 272 + 273 + The parsed data is cached, so repeated calls are fast: 274 + // First call: parses JSON 275 + data1, _ := op.GetOperationMap() 276 + 277 + // Second call: returns cached data (fast) 278 + data2, _ := op.GetOperationMap() 279 + 245 280 --- 246 281 247 282 ## Common Patterns ··· 441 476 } 442 477 443 478 func (p *OperationProcessor) processOperation(op plcbundle.PLCOperation) { 479 + // Parse Operation field on-demand 480 + operation, err := op.GetOperationMap() 481 + if err != nil || operation == nil { 482 + return 483 + } 484 + 444 485 // Example: Extract PDS endpoints 445 - if services, ok := op.Operation["services"].(map[string]interface{}); ok { 486 + if services, ok := operation["services"].(map[string]interface{}); ok { 446 487 if pds, ok := services["atproto_pds"].(map[string]interface{}); ok { 447 488 if endpoint, ok := pds["endpoint"].(string); ok { 448 489 log.Printf("DID %s uses PDS: %s", op.DID, endpoint) ··· 450 491 } 451 492 } 452 493 } 494 + 453 495 454 496 func main() { 455 497 processor, err := NewOperationProcessor("./plc_data") ··· 815 857 } 816 858 817 859 func (pt *PDSTracker) extractPDS(op plcbundle.PLCOperation) string { 818 - services, ok := op.Operation["services"].(map[string]interface{}) 860 + // Parse Operation field on-demand 861 + operation, err := op.GetOperationMap() 862 + if err != nil || operation == nil { 863 + return "" 864 + } 865 + 866 + services, ok := operation["services"].(map[string]interface{}) 819 867 if !ok { 820 868 return "" 821 869 } ··· 832 880 833 881 return endpoint 834 882 } 883 + 835 884 836 885 func (pt *PDSTracker) PrintResults() { 837 886 log.Printf("\nFound %d unique PDS endpoints:\n", len(pt.endpoints)) ··· 1045 1094 } 1046 1095 1047 1096 // Check for new DIDs (operation type "create") 1048 - if opType, ok := op.Operation["type"].(string); ok && opType == "create" { 1049 - log.Printf(" ➕ New DID: %s", op.DID) 1097 + operation, err := op.GetOperationMap() 1098 + if err == nil && operation != nil { 1099 + if opType, ok := operation["type"].(string); ok && opType == "create" { 1100 + log.Printf(" ➕ New DID: %s", op.DID) 1101 + } 1050 1102 } 1051 1103 } 1052 1104 }