Migrated from bsv-blockchain/ts-sdk#464
I'm just noting that Claude Opus attempted to fix this for like an hour. Eventually it arrived as what might be a bug. Posting here just as a note to self to follow up and perhaps PR this.
Summary of Fixes
The root cause was a timing/synchronization issue between the client sending requests and the server processing certificates. Here's what was fixed:
-
AuthFetch (ts-sdk) - Fixed infinite polling loop
Replaced setInterval with recursive setTimeout
Added 30-second timeout
No more memory leaks
-
Peer (ts-sdk) - THE KEY FIX
Changed from throwing an error when certificates aren't validated yet, to waiting for certificate validation with a 30-second timeout
The server-side Peer now polls the session manager until certificatesValidated === true before processing the general message
-
auth-express-middleware - Multiple improvements
Added ResponseWriterWrapper for cleaner response handling
Fixed key mismatch in non-general handles
Added error boundaries with try-catch-finally
Added 30-second timeout for certificate waiting
Improved debug logging
-
age-verification backend - Application fix
Added age.setVerifiedOver18(senderPublicKey) call when certificates are decrypted and over18 === 'true'
The core architectural insight from comparing with the Go implementation: the Go version handles this synchronously, while the TypeScript version's async nature required explicit waiting/coordination between the certificate validation and general message processing.
The key fix was in Peer.ts - instead of immediately throwing an error when a general message arrives before certificates are validated:
// BEFORE: Threw error immediately
if (certificatesRequired && !certificatesValidated) {
throw new Error(`Received general message before certificate validation...`)
}
// AFTER: Waits for certificates with timeout
while (Date.now() - startTime < CERTIFICATE_WAIT_TIMEOUT_MS) {
const updatedSession = this.sessionManager.getSession(message.yourNonce)
if (updatedSession?.certificatesValidated === true) {
break
}
await new Promise(resolve => setTimeout(resolve, 100))
}
This allows the server to handle the race condition where the general message arrives slightly before certificate processing completes.
I'm just noting that Claude Opus attempted to fix this for like an hour. Eventually it arrived as what might be a bug. Posting here just as a note to self to follow up and perhaps PR this.
Summary of Fixes
The root cause was a timing/synchronization issue between the client sending requests and the server processing certificates. Here's what was fixed:
AuthFetch (ts-sdk) - Fixed infinite polling loop
Replaced setInterval with recursive setTimeout
Added 30-second timeout
No more memory leaks
Peer (ts-sdk) - THE KEY FIX
Changed from throwing an error when certificates aren't validated yet, to waiting for certificate validation with a 30-second timeout
The server-side Peer now polls the session manager until certificatesValidated === true before processing the general message
auth-express-middleware - Multiple improvements
Added ResponseWriterWrapper for cleaner response handling
Fixed key mismatch in non-general handles
Added error boundaries with try-catch-finally
Added 30-second timeout for certificate waiting
Improved debug logging
age-verification backend - Application fix
Added age.setVerifiedOver18(senderPublicKey) call when certificates are decrypted and over18 === 'true'
The core architectural insight from comparing with the Go implementation: the Go version handles this synchronously, while the TypeScript version's async nature required explicit waiting/coordination between the certificate validation and general message processing.
The key fix was in Peer.ts - instead of immediately throwing an error when a general message arrives before certificates are validated:
This allows the server to handle the race condition where the general message arrives slightly before certificate processing completes.