# Hold Service Endpoint Testing Guide ## Quick Reference Your hold service: `http://172.28.0.3:8080` Default DID format for local testing: `did:web:172.28.0.3%3A8080` (URL-encoded `did:web:172.28.0.3:8080`) ## Individual cURL Commands ### 1. List Repositories ```bash curl -s "http://172.28.0.3:8080/xrpc/com.atproto.sync.listRepos" | jq . ``` **Expected response:** ```json { "repos": [ { "did": "did:web:172.28.0.3%3A8080", "head": "...", "rev": "..." } ] } ``` ### 2. Describe Repository ```bash curl -s "http://172.28.0.3:8080/xrpc/com.atproto.repo.describeRepo?repo=did:web:172.28.0.3%3A8080" | jq . ``` **Expected response:** ```json { "did": "did:web:172.28.0.3%3A8080", "handle": "172.28.0.3:8080", "didDoc": {...}, "collections": ["io.atcr.hold.captain", "io.atcr.hold.crew"] } ``` ### 3. Get Repository (CAR file) ```bash # Download entire repo as CAR file curl -s "http://172.28.0.3:8080/xrpc/com.atproto.sync.getRepo?did=did:web:172.28.0.3%3A8080" -o repo.car # Get repo diff since revision curl -s "http://172.28.0.3:8080/xrpc/com.atproto.sync.getRepo?did=did:web:172.28.0.3%3A8080&since=abc123" -o repo-diff.car ``` **Expected response:** Binary CAR (Content Addressable aRchive) file ### 4. List Captain Records ```bash curl -s "http://172.28.0.3:8080/xrpc/com.atproto.repo.listRecords?repo=did:web:172.28.0.3%3A8080&collection=io.atcr.hold.captain" | jq . ``` **Expected response:** ```json { "records": [ { "uri": "at://did:web:172.28.0.3%3A8080/io.atcr.hold.captain/self", "cid": "...", "value": { "$type": "io.atcr.hold.captain", "allowAllCrew": true, "public": false, "createdAt": "2025-10-22T..." } } ] } ``` ### 5. List Crew Records ```bash curl -s "http://172.28.0.3:8080/xrpc/com.atproto.repo.listRecords?repo=did:web:172.28.0.3%3A8080&collection=io.atcr.hold.crew" | jq . ``` **Expected response:** ```json { "records": [ { "uri": "at://did:web:172.28.0.3%3A8080/io.atcr.hold.crew/{rkey}", "cid": "...", "value": { "$type": "io.atcr.hold.crew", "did": "did:plc:...", "permissions": ["blob:read", "blob:write"], "createdAt": "2025-10-22T..." } } ] } ``` ### 6. Get Specific Record ```bash curl -s "http://172.28.0.3:8080/xrpc/com.atproto.repo.getRecord?repo=did:web:172.28.0.3%3A8080&collection=io.atcr.hold.captain&rkey=self" | jq . ``` ### 7. Get Blob ```bash # Replace with actual CID from your hold curl -s "http://172.28.0.3:8080/xrpc/com.atproto.sync.getBlob?did=did:web:172.28.0.3%3A8080&cid=bafyreiabc123..." | jq . ``` **Expected response (for OCI blobs):** ```json { "url": "https://s3.amazonaws.com/bucket/path?presigned-params...", "expiresAt": "2025-10-22T12:15:00Z" } ``` ### 8. Subscribe to Repository Events (WebSocket) Using **websocat** (recommended): ```bash # Install: cargo install websocat websocat "ws://172.28.0.3:8080/xrpc/com.atproto.sync.subscribeRepos" ``` Using **wscat**: ```bash # Install: npm install -g wscat wscat -c "ws://172.28.0.3:8080/xrpc/com.atproto.sync.subscribeRepos" ``` Using **curl** (HTTP upgrade - may not work with all servers): ```bash curl -i -N \ -H "Connection: Upgrade" \ -H "Upgrade: websocket" \ -H "Sec-WebSocket-Version: 13" \ -H "Sec-WebSocket-Key: $(echo -n "test" | base64)" \ "http://172.28.0.3:8080/xrpc/com.atproto.sync.subscribeRepos" ``` **Expected response:** Stream of CBOR-encoded events (commits, identities, handles, etc.) ## DID Resolution ### Get DID Document ```bash curl -s "http://172.28.0.3:8080/.well-known/did.json" | jq . ``` **Expected response:** ```json { "@context": ["https://www.w3.org/ns/did/v1"], "id": "did:web:172.28.0.3%3A8080", "service": [ { "id": "#atproto_pds", "type": "AtprotoPersonalDataServer", "serviceEndpoint": "http://172.28.0.3:8080" } ] } ``` ### Get DID from Handle ```bash curl -s "http://172.28.0.3:8080/.well-known/atproto-did" ``` **Expected response:** Plain text DID ``` did:web:172.28.0.3%3A8080 ``` ## Running the Test Script ```bash # Default (uses 172.28.0.3:8080) ./test-hold-endpoints.sh # Custom hold URL ./test-hold-endpoints.sh "http://localhost:8080" # Custom hold URL and DID ./test-hold-endpoints.sh "http://localhost:8080" "did:web:localhost%3A8080" ``` ## Troubleshooting ### "Connection refused" - Ensure hold service is running: `docker ps` or check process - Verify IP address: `docker inspect | grep IPAddress` ### "Empty response" or "404 Not Found" - Check hold service logs for errors - Verify DID format (use URL-encoded version with `%3A` for `:`) - Ensure hold has been initialized (should have captain record) ### WebSocket connection fails - Install websocat: `cargo install websocat` - Or install wscat: `npm install -g wscat` - WebSocket endpoints only work with proper WS clients, not regular curl ### "No records found" - Captain record created on hold startup if `HOLD_OWNER` is set - Crew records created when users call `io.atcr.hold.requestCrew` - Blobs only exist after pushing container images ## Next Steps After verifying these endpoints work: 1. Test OCI upload endpoints (requires authentication) 2. Push a real container image to create blob data 3. Test blob retrieval with real CIDs 4. Monitor WebSocket events during pushes