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

Configure Feed

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

cors and cleanup

+43 -28
+1 -1
bundle/manager.go
··· 294 294 m.logger.Printf("Warning: failed to save mempool: %v", err) 295 295 } 296 296 } 297 - if m.didIndex != nil { // ← ADD THIS 297 + if m.didIndex != nil { 298 298 m.didIndex.Close() 299 299 } 300 300 }
+1 -1
bundle/mempool.go
··· 399 399 didSet[op.DID] = true 400 400 } 401 401 stats["size_bytes"] = totalSize 402 - stats["did_count"] = len(didSet) // ← ADDED 402 + stats["did_count"] = len(didSet) 403 403 } 404 404 405 405 return stats
+2 -2
cmd/plcbundle/detector.go
··· 195 195 bundleNum := fs.Int("bundle", 0, "bundle number to test") 196 196 confidence := fs.Float64("confidence", 0.90, "minimum confidence threshold") 197 197 verbose := fs.Bool("v", false, "verbose output") 198 - fs.Parse(os.Args[4:]) // ← Changed from os.Args[3:] 198 + fs.Parse(os.Args[4:]) 199 199 200 200 if *bundleNum == 0 { 201 201 fmt.Fprintf(os.Stderr, "Error: --bundle required\n") ··· 556 556 var maxConfidence float64 557 557 558 558 for _, det := range detectors { 559 - match, err := det.Detect(ctx, op) // ← op now has ParsedOperation set 559 + match, err := det.Detect(ctx, op) 560 560 if err != nil || match == nil || match.Confidence < minConfidence { 561 561 continue 562 562 }
+6 -9
cmd/plcbundle/main.go
··· 452 452 } 453 453 454 454 config := bundle.DefaultConfig(dir) 455 - config.AutoRebuild = false // ← Disable auto-rebuild 455 + config.AutoRebuild = false 456 456 config.RebuildWorkers = *workers 457 457 458 458 mgr, err := bundle.NewManager(config, nil) ··· 1270 1270 enableWebSocket := fs.Bool("websocket", false, "enable WebSocket endpoint for streaming records") 1271 1271 workers := fs.Int("workers", 4, "number of workers for auto-rebuild (0 = CPU count)") 1272 1272 verbose := fs.Bool("verbose", false, "verbose sync logging") 1273 - enableResolver := fs.Bool("resolver", false, "enable DID resolution endpoints (/<did>)") // ← NEW 1273 + enableResolver := fs.Bool("resolver", false, "enable DID resolution endpoints (/<did>)") 1274 1274 fs.Parse(os.Args[2:]) 1275 1275 1276 1276 serverStartTime = time.Now() 1277 1277 syncInterval = *syncIntervalFlag 1278 1278 verboseMode = *verbose 1279 - resolverEnabled = *enableResolver // ← NEW global 1279 + resolverEnabled = *enableResolver 1280 1280 1281 1281 // Auto-detect CPU count 1282 1282 if *workers == 0 { ··· 1329 1329 } 1330 1330 defer mgr.Close() 1331 1331 1332 - // ═══════════════════════════════════════════════════════════ 1333 - // DID INDEX AUTO-BUILD LOGIC 1334 - // ═══════════════════════════════════════════════════════════ 1335 1332 if *enableResolver { 1336 1333 index := mgr.GetIndex() 1337 1334 bundleCount := index.Count() ··· 1348 1345 // Check version 1349 1346 didIndex := mgr.GetDIDIndex() 1350 1347 if didIndex != nil { 1351 - config := didIndex.GetConfig() // ← Need to expose this 1348 + config := didIndex.GetConfig() 1352 1349 if config.Version != bundle.DIDINDEX_VERSION { 1353 1350 needsBuild = true 1354 1351 reason = fmt.Sprintf("index version outdated (v%d, need v%d)", ··· 1432 1429 defer cancel() 1433 1430 1434 1431 if *sync { 1435 - go runSync(ctx, mgr, syncInterval, *verbose, *enableResolver) // ← Pass resolver flag 1432 + go runSync(ctx, mgr, syncInterval, *verbose, *enableResolver) 1436 1433 } 1437 1434 1438 1435 server := &http.Server{ 1439 1436 Addr: addr, 1440 - Handler: newServerHandler(mgr, *sync, *enableWebSocket, *enableResolver), // ← Pass resolver flag 1437 + Handler: newServerHandler(mgr, *sync, *enableWebSocket, *enableResolver), 1441 1438 ReadTimeout: 30 * time.Second, 1442 1439 WriteTimeout: 30 * time.Second, 1443 1440 }
+1 -1
cmd/plcbundle/progress.go
··· 81 81 pb.current = pb.total 82 82 pb.currentBytes = pb.totalBytes 83 83 pb.print() 84 - fmt.Fprintf(os.Stderr, "\n") // ← FIXED: Use stderr 84 + fmt.Fprintf(os.Stderr, "\n") 85 85 } 86 86 87 87 // print renders the progress bar (must be called with lock held)
+25 -7
cmd/plcbundle/server.go
··· 318 318 mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 319 319 path := r.URL.Path 320 320 321 - // DID Resolution - delegate to specific handler 322 - if strings.HasPrefix(path, "/did:plc:") { 321 + // DID Resolution - only if resolver is enabled 322 + if resolverEnabled && strings.HasPrefix(path, "/did:plc:") { 323 323 handleDIDEndpoint(w, r, mgr) 324 324 return 325 325 } ··· 332 332 http.NotFound(w, r) 333 333 }) 334 334 335 - // Index JSON (reload from disk each time for fresh data during rebuild) 335 + // Index JSON 336 336 mux.HandleFunc("/index.json", func(w http.ResponseWriter, r *http.Request) { 337 - // Reload index to get latest data 338 - mgr.GetIndex() // This will refresh if needed 337 + mgr.GetIndex() 339 338 handleIndexJSON(w, mgr) 340 339 }) 341 340 ··· 373 372 fmt.Fprintf(w, "\nDID Index:\n") 374 373 fmt.Fprintf(w, " Cached shards: %d/%d\n", didStats["cached_shards"], didStats["cache_limit"]) 375 374 376 - // Force GC and show again 377 375 runtime.GC() 378 376 runtime.ReadMemStats(&m) 379 377 fmt.Fprintf(w, "\nAfter GC:\n") ··· 394 392 }) 395 393 } 396 394 397 - return mux 395 + return corsMiddleware(mux) 398 396 } 399 397 400 398 // handleWebSocket streams all records via WebSocket starting from cursor ··· 1234 1232 1235 1233 json.NewEncoder(w).Encode(auditLog) 1236 1234 } 1235 + 1236 + // corsMiddleware adds CORS headers to all responses 1237 + func corsMiddleware(next http.Handler) http.Handler { 1238 + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1239 + // Set CORS headers 1240 + w.Header().Set("Access-Control-Allow-Origin", "*") 1241 + w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS") 1242 + w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") 1243 + w.Header().Set("Access-Control-Max-Age", "86400") // 24 hours 1244 + 1245 + // Handle preflight OPTIONS request 1246 + if r.Method == "OPTIONS" { 1247 + w.WriteHeader(http.StatusNoContent) 1248 + return 1249 + } 1250 + 1251 + // Call the next handler 1252 + next.ServeHTTP(w, r) 1253 + }) 1254 + }
+1 -1
detector/detector.go
··· 37 37 BundleNumber int 38 38 Position int 39 39 DID string 40 - CID string // ← Add this field 40 + CID string 41 41 Match *Match // nil if no match 42 42 Error error 43 43 DetectorName string
+1 -1
detector/runner.go
··· 139 139 BundleNumber: bundleNum, 140 140 Position: pos, 141 141 DID: op.DID, 142 - CID: op.CID, // ← Add this 142 + CID: op.CID, 143 143 DetectorName: detector.Name(), 144 144 DetectedAt: time.Now(), 145 145 }
+5 -5
plc/resolver.go
··· 206 206 // Convert services 207 207 for id, svc := range state.Services { 208 208 doc.Service = append(doc.Service, Service{ 209 - ID: "#" + id, // ← Just fragment (matching plc.directory) 209 + ID: "#" + id, 210 210 Type: svc.Type, 211 211 ServiceEndpoint: svc.Endpoint, 212 212 }) ··· 215 215 // Keep verification methods with full DID (they're correct): 216 216 for id, didKey := range state.VerificationMethods { 217 217 doc.VerificationMethod = append(doc.VerificationMethod, VerificationMethod{ 218 - ID: state.DID + "#" + id, // ← Keep this as-is 218 + ID: state.DID + "#" + id, 219 219 Type: "Multikey", 220 220 Controller: state.DID, 221 221 PublicKeyMultibase: ExtractMultibaseFromDIDKey(didKey), ··· 236 236 // The 'z' is the base58btc multibase prefix 237 237 // Actual key starts at position 1 238 238 switch { 239 - case multibase[1] == 'Q' && multibase[2] == '3': // ← Fixed: was [0] and [1] 239 + case multibase[1] == 'Q' && multibase[2] == '3': 240 240 return "secp256k1" // Starts with zQ3s 241 - case multibase[1] == 'D' && multibase[2] == 'n': // ← Fixed 241 + case multibase[1] == 'D' && multibase[2] == 'n': 242 242 return "p256" // Starts with zDn 243 - case multibase[1] == '6' && multibase[2] == 'M': // ← Fixed 243 + case multibase[1] == '6' && multibase[2] == 'M': 244 244 return "ed25519" // Starts with z6Mk 245 245 default: 246 246 return "unknown"