this repo has no description

chore: add shfmt for bash formatting

- Format test/e2e.sh with shfmt
- Add shfmt to npm run format script

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Changed files
+40 -36
test
+1 -1
package.json
··· 9 "test": "node --test test/*.test.js", 10 "test:e2e": "./test/e2e.sh", 11 "setup": "node scripts/setup.js", 12 - "format": "biome format --write .", 13 "lint": "biome lint .", 14 "check": "biome check ." 15 },
··· 9 "test": "node --test test/*.test.js", 10 "test:e2e": "./test/e2e.sh", 11 "setup": "node scripts/setup.js", 12 + "format": "biome format --write . && shfmt -w -i 2 test/*.sh", 13 "lint": "biome lint .", 14 "check": "biome check ." 15 },
+39 -35
test/e2e.sh
··· 7 8 # Helper for colored output 9 pass() { echo "✓ $1"; } 10 - fail() { echo "✗ $1" >&2; cleanup; exit 1; } 11 12 # Cleanup function 13 cleanup() { ··· 21 22 # Start wrangler dev 23 echo "Starting wrangler dev..." 24 - npx wrangler dev --port 8787 > /dev/null 2>&1 & 25 WRANGLER_PID=$! 26 27 # Wait for server to be ready 28 for i in {1..30}; do 29 - if curl -sf "$BASE/" > /dev/null 2>&1; then 30 break 31 fi 32 sleep 0.5 33 done 34 35 # Verify server is up 36 - curl -sf "$BASE/" > /dev/null || fail "Server failed to start" 37 pass "Server started" 38 39 # Initialize PDS 40 PRIVKEY=$(openssl rand -hex 32) 41 curl -sf -X POST "$BASE/init?did=$DID" \ 42 -H "Content-Type: application/json" \ 43 - -d "{\"did\":\"$DID\",\"privateKey\":\"$PRIVKEY\",\"handle\":\"test.local\"}" > /dev/null \ 44 - && pass "PDS initialized" || fail "PDS init" 45 46 echo 47 echo "Running tests..." ··· 51 curl -sf "$BASE/" | grep -q "PDS" && pass "Root returns ASCII art" || fail "Root" 52 53 # 2. describeServer works 54 - curl -sf "$BASE/xrpc/com.atproto.server.describeServer" | jq -e '.did' > /dev/null \ 55 - && pass "describeServer" || fail "describeServer" 56 57 # 3. resolveHandle works 58 - curl -sf "$BASE/xrpc/com.atproto.identity.resolveHandle?handle=test.local" \ 59 - | jq -e '.did' > /dev/null && pass "resolveHandle" || fail "resolveHandle" 60 61 # 4. createSession returns tokens 62 SESSION=$(curl -sf -X POST "$BASE/xrpc/com.atproto.server.createSession" \ ··· 67 68 # 5. getSession works with token 69 curl -sf "$BASE/xrpc/com.atproto.server.getSession" \ 70 - -H "Authorization: Bearer $TOKEN" | jq -e '.did' > /dev/null \ 71 - && pass "getSession with valid token" || fail "getSession" 72 73 # 6. Protected endpoint rejects without auth 74 STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST "$BASE/xrpc/com.atproto.repo.createRecord" \ ··· 78 79 # 7. getPreferences works (returns empty array initially) 80 curl -sf "$BASE/xrpc/app.bsky.actor.getPreferences" \ 81 - -H "Authorization: Bearer $TOKEN" | jq -e '.preferences' > /dev/null \ 82 - && pass "getPreferences" || fail "getPreferences" 83 84 # 8. putPreferences works 85 curl -sf -X POST "$BASE/xrpc/app.bsky.actor.putPreferences" \ 86 -H "Authorization: Bearer $TOKEN" \ 87 -H "Content-Type: application/json" \ 88 - -d '{"preferences":[{"$type":"app.bsky.actor.defs#savedFeedsPrefV2"}]}' > /dev/null \ 89 - && pass "putPreferences" || fail "putPreferences" 90 91 # 9. createRecord works with auth 92 RECORD=$(curl -sf -X POST "$BASE/xrpc/com.atproto.repo.createRecord" \ ··· 98 99 # 10. getRecord retrieves it 100 RKEY=$(echo "$URI" | sed 's|.*/||') 101 - curl -sf "$BASE/xrpc/com.atproto.repo.getRecord?repo=$DID&collection=app.bsky.feed.post&rkey=$RKEY" \ 102 - | jq -e '.value.text' > /dev/null && pass "getRecord" || fail "getRecord" 103 104 # 11. putRecord updates the record 105 curl -sf -X POST "$BASE/xrpc/com.atproto.repo.putRecord" \ 106 -H "Authorization: Bearer $TOKEN" \ 107 -H "Content-Type: application/json" \ 108 - -d "{\"repo\":\"$DID\",\"collection\":\"app.bsky.feed.post\",\"rkey\":\"$RKEY\",\"record\":{\"text\":\"updated\",\"createdAt\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}}" \ 109 - | jq -e '.uri' > /dev/null && pass "putRecord" || fail "putRecord" 110 111 # 12. listRecords shows the record 112 - curl -sf "$BASE/xrpc/com.atproto.repo.listRecords?repo=$DID&collection=app.bsky.feed.post" \ 113 - | jq -e '.records | length > 0' > /dev/null && pass "listRecords" || fail "listRecords" 114 115 # 13. describeRepo returns repo info 116 - curl -sf "$BASE/xrpc/com.atproto.repo.describeRepo?repo=$DID" \ 117 - | jq -e '.did' > /dev/null && pass "describeRepo" || fail "describeRepo" 118 119 # 14. applyWrites batch operation (create then delete a record) 120 APPLY_RESULT=$(curl -sf -X POST "$BASE/xrpc/com.atproto.repo.applyWrites" \ 121 -H "Authorization: Bearer $TOKEN" \ 122 -H "Content-Type: application/json" \ 123 -d "{\"repo\":\"$DID\",\"writes\":[{\"\$type\":\"com.atproto.repo.applyWrites#create\",\"collection\":\"app.bsky.feed.post\",\"rkey\":\"applytest\",\"value\":{\"text\":\"batch\",\"createdAt\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}}]}") 124 - echo "$APPLY_RESULT" | jq -e '.results' > /dev/null && pass "applyWrites create" || fail "applyWrites create" 125 126 # 15. applyWrites delete 127 curl -sf -X POST "$BASE/xrpc/com.atproto.repo.applyWrites" \ 128 -H "Authorization: Bearer $TOKEN" \ 129 -H "Content-Type: application/json" \ 130 - -d "{\"repo\":\"$DID\",\"writes\":[{\"\$type\":\"com.atproto.repo.applyWrites#delete\",\"collection\":\"app.bsky.feed.post\",\"rkey\":\"applytest\"}]}" \ 131 - | jq -e '.results' > /dev/null && pass "applyWrites delete" || fail "applyWrites delete" 132 133 # 16. sync.getLatestCommit returns head 134 - curl -sf "$BASE/xrpc/com.atproto.sync.getLatestCommit?did=$DID" \ 135 - | jq -e '.cid' > /dev/null && pass "sync.getLatestCommit" || fail "sync.getLatestCommit" 136 137 # 17. sync.getRepoStatus returns status 138 - curl -sf "$BASE/xrpc/com.atproto.sync.getRepoStatus?did=$DID" \ 139 - | jq -e '.did' > /dev/null && pass "sync.getRepoStatus" || fail "sync.getRepoStatus" 140 141 # 18. sync.getRepo returns CAR file 142 REPO_SIZE=$(curl -sf "$BASE/xrpc/com.atproto.sync.getRepo?did=$DID" | wc -c) ··· 147 [ "$RECORD_SIZE" -gt 50 ] && pass "sync.getRecord" || fail "sync.getRecord" 148 149 # 20. sync.listRepos lists repos 150 - curl -sf "$BASE/xrpc/com.atproto.sync.listRepos" \ 151 - | jq -e '.repos | length > 0' > /dev/null && pass "sync.listRepos" || fail "sync.listRepos" 152 153 # Error handling tests 154 echo ··· 175 curl -sf -X POST "$BASE/xrpc/com.atproto.repo.deleteRecord" \ 176 -H "Authorization: Bearer $TOKEN" \ 177 -H "Content-Type: application/json" \ 178 - -d "{\"repo\":\"$DID\",\"collection\":\"app.bsky.feed.post\",\"rkey\":\"$RKEY\"}" > /dev/null \ 179 - && pass "deleteRecord (cleanup)" || fail "deleteRecord" 180 181 echo 182 echo "All tests passed!"
··· 7 8 # Helper for colored output 9 pass() { echo "✓ $1"; } 10 + fail() { 11 + echo "✗ $1" >&2 12 + cleanup 13 + exit 1 14 + } 15 16 # Cleanup function 17 cleanup() { ··· 25 26 # Start wrangler dev 27 echo "Starting wrangler dev..." 28 + npx wrangler dev --port 8787 >/dev/null 2>&1 & 29 WRANGLER_PID=$! 30 31 # Wait for server to be ready 32 for i in {1..30}; do 33 + if curl -sf "$BASE/" >/dev/null 2>&1; then 34 break 35 fi 36 sleep 0.5 37 done 38 39 # Verify server is up 40 + curl -sf "$BASE/" >/dev/null || fail "Server failed to start" 41 pass "Server started" 42 43 # Initialize PDS 44 PRIVKEY=$(openssl rand -hex 32) 45 curl -sf -X POST "$BASE/init?did=$DID" \ 46 -H "Content-Type: application/json" \ 47 + -d "{\"did\":\"$DID\",\"privateKey\":\"$PRIVKEY\",\"handle\":\"test.local\"}" >/dev/null && 48 + pass "PDS initialized" || fail "PDS init" 49 50 echo 51 echo "Running tests..." ··· 55 curl -sf "$BASE/" | grep -q "PDS" && pass "Root returns ASCII art" || fail "Root" 56 57 # 2. describeServer works 58 + curl -sf "$BASE/xrpc/com.atproto.server.describeServer" | jq -e '.did' >/dev/null && 59 + pass "describeServer" || fail "describeServer" 60 61 # 3. resolveHandle works 62 + curl -sf "$BASE/xrpc/com.atproto.identity.resolveHandle?handle=test.local" | 63 + jq -e '.did' >/dev/null && pass "resolveHandle" || fail "resolveHandle" 64 65 # 4. createSession returns tokens 66 SESSION=$(curl -sf -X POST "$BASE/xrpc/com.atproto.server.createSession" \ ··· 71 72 # 5. getSession works with token 73 curl -sf "$BASE/xrpc/com.atproto.server.getSession" \ 74 + -H "Authorization: Bearer $TOKEN" | jq -e '.did' >/dev/null && 75 + pass "getSession with valid token" || fail "getSession" 76 77 # 6. Protected endpoint rejects without auth 78 STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST "$BASE/xrpc/com.atproto.repo.createRecord" \ ··· 82 83 # 7. getPreferences works (returns empty array initially) 84 curl -sf "$BASE/xrpc/app.bsky.actor.getPreferences" \ 85 + -H "Authorization: Bearer $TOKEN" | jq -e '.preferences' >/dev/null && 86 + pass "getPreferences" || fail "getPreferences" 87 88 # 8. putPreferences works 89 curl -sf -X POST "$BASE/xrpc/app.bsky.actor.putPreferences" \ 90 -H "Authorization: Bearer $TOKEN" \ 91 -H "Content-Type: application/json" \ 92 + -d '{"preferences":[{"$type":"app.bsky.actor.defs#savedFeedsPrefV2"}]}' >/dev/null && 93 + pass "putPreferences" || fail "putPreferences" 94 95 # 9. createRecord works with auth 96 RECORD=$(curl -sf -X POST "$BASE/xrpc/com.atproto.repo.createRecord" \ ··· 102 103 # 10. getRecord retrieves it 104 RKEY=$(echo "$URI" | sed 's|.*/||') 105 + curl -sf "$BASE/xrpc/com.atproto.repo.getRecord?repo=$DID&collection=app.bsky.feed.post&rkey=$RKEY" | 106 + jq -e '.value.text' >/dev/null && pass "getRecord" || fail "getRecord" 107 108 # 11. putRecord updates the record 109 curl -sf -X POST "$BASE/xrpc/com.atproto.repo.putRecord" \ 110 -H "Authorization: Bearer $TOKEN" \ 111 -H "Content-Type: application/json" \ 112 + -d "{\"repo\":\"$DID\",\"collection\":\"app.bsky.feed.post\",\"rkey\":\"$RKEY\",\"record\":{\"text\":\"updated\",\"createdAt\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}}" | 113 + jq -e '.uri' >/dev/null && pass "putRecord" || fail "putRecord" 114 115 # 12. listRecords shows the record 116 + curl -sf "$BASE/xrpc/com.atproto.repo.listRecords?repo=$DID&collection=app.bsky.feed.post" | 117 + jq -e '.records | length > 0' >/dev/null && pass "listRecords" || fail "listRecords" 118 119 # 13. describeRepo returns repo info 120 + curl -sf "$BASE/xrpc/com.atproto.repo.describeRepo?repo=$DID" | 121 + jq -e '.did' >/dev/null && pass "describeRepo" || fail "describeRepo" 122 123 # 14. applyWrites batch operation (create then delete a record) 124 APPLY_RESULT=$(curl -sf -X POST "$BASE/xrpc/com.atproto.repo.applyWrites" \ 125 -H "Authorization: Bearer $TOKEN" \ 126 -H "Content-Type: application/json" \ 127 -d "{\"repo\":\"$DID\",\"writes\":[{\"\$type\":\"com.atproto.repo.applyWrites#create\",\"collection\":\"app.bsky.feed.post\",\"rkey\":\"applytest\",\"value\":{\"text\":\"batch\",\"createdAt\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}}]}") 128 + echo "$APPLY_RESULT" | jq -e '.results' >/dev/null && pass "applyWrites create" || fail "applyWrites create" 129 130 # 15. applyWrites delete 131 curl -sf -X POST "$BASE/xrpc/com.atproto.repo.applyWrites" \ 132 -H "Authorization: Bearer $TOKEN" \ 133 -H "Content-Type: application/json" \ 134 + -d "{\"repo\":\"$DID\",\"writes\":[{\"\$type\":\"com.atproto.repo.applyWrites#delete\",\"collection\":\"app.bsky.feed.post\",\"rkey\":\"applytest\"}]}" | 135 + jq -e '.results' >/dev/null && pass "applyWrites delete" || fail "applyWrites delete" 136 137 # 16. sync.getLatestCommit returns head 138 + curl -sf "$BASE/xrpc/com.atproto.sync.getLatestCommit?did=$DID" | 139 + jq -e '.cid' >/dev/null && pass "sync.getLatestCommit" || fail "sync.getLatestCommit" 140 141 # 17. sync.getRepoStatus returns status 142 + curl -sf "$BASE/xrpc/com.atproto.sync.getRepoStatus?did=$DID" | 143 + jq -e '.did' >/dev/null && pass "sync.getRepoStatus" || fail "sync.getRepoStatus" 144 145 # 18. sync.getRepo returns CAR file 146 REPO_SIZE=$(curl -sf "$BASE/xrpc/com.atproto.sync.getRepo?did=$DID" | wc -c) ··· 151 [ "$RECORD_SIZE" -gt 50 ] && pass "sync.getRecord" || fail "sync.getRecord" 152 153 # 20. sync.listRepos lists repos 154 + curl -sf "$BASE/xrpc/com.atproto.sync.listRepos" | 155 + jq -e '.repos | length > 0' >/dev/null && pass "sync.listRepos" || fail "sync.listRepos" 156 157 # Error handling tests 158 echo ··· 179 curl -sf -X POST "$BASE/xrpc/com.atproto.repo.deleteRecord" \ 180 -H "Authorization: Bearer $TOKEN" \ 181 -H "Content-Type: application/json" \ 182 + -d "{\"repo\":\"$DID\",\"collection\":\"app.bsky.feed.post\",\"rkey\":\"$RKEY\"}" >/dev/null && 183 + pass "deleteRecord (cleanup)" || fail "deleteRecord" 184 185 echo 186 echo "All tests passed!"