- Increase logo size (48x48 desktop, 56x56 mobile) for better visibility - Add logo as favicon - Add logo to mobile header - Move user menu to navigation bars (sidebar on desktop, bottom bar on mobile) - Fix desktop chat layout - container structure prevents voice controls cutoff - Fix mobile bottom bar - use icon-only ActionIcons instead of truncated text buttons - Hide Create Node/New Conversation buttons on mobile to save header space - Make fixed header and voice controls work properly with containers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
3.4 KiB
SurrealDB Cache Authentication Fix
Problem
Node publishing was showing a yellow warning notification:
Node published to Bluesky, but cache update failed. Advanced features may be unavailable.
Server logs showed:
[POST /api/nodes] ⚠ SurrealDB cache write failed (non-critical):
Error [ResponseError]: There was a problem with the database: There was a problem with authentication
Root Cause
The connectToDB() function in lib/db.ts was attempting to authenticate with SurrealDB using our application's custom JWT token:
await db.authenticate(token);
However, SurrealDB doesn't know how to validate our custom JWT tokens. The db.authenticate() method is for SurrealDB's own token-based authentication system, not for validating external JWTs.
Solution
Changed connectToDB() to use root credentials instead:
Before:
export async function connectToDB(token: string): Promise<Surreal> {
const db = new Surreal();
await db.connect(SURREALDB_URL);
await db.authenticate(token); // ❌ This fails
await db.use({ namespace, database });
return db;
}
After:
export async function connectToDB(): Promise<Surreal> {
const db = new Surreal();
await db.connect(SURREALDB_URL);
await db.signin({
username: SURREALDB_USER, // ✅ Use root credentials
password: SURREALDB_PASS,
});
await db.use({ namespace, database });
return db;
}
Data Security
Since we're now using root credentials instead of JWT-based authentication, we maintain data isolation by:
- Extracting user_did from the verified JWT in API routes
- Filtering all queries by user_did to ensure users only access their own data
Example from /app/api/nodes/route.ts:
// Verify JWT to get user's DID
const userSession = verifySurrealJwt(surrealJwt);
const { did: userDid } = userSession;
// Create node with user_did field
const nodeData = {
user_did: userDid, // ✅ Enforces data ownership
atp_uri: atp_uri,
title: title,
body: body,
embedding: embedding,
};
await db.create('node', nodeData);
Example from /app/api/suggest-links/route.ts:
// Query filtered by user_did
const query = `
SELECT * FROM node
WHERE user_did = $user_did // ✅ Only user's own nodes
ORDER BY score DESC
LIMIT 5;
`;
await db.query(query, { user_did: userDid });
Files Changed
/lib/db.ts- Changed authentication method/app/api/nodes/route.ts- Removed JWT parameter fromconnectToDB()call/app/api/suggest-links/route.ts- Updated to use root credentials and filter byuser_did
Test
Created /tests/magnitude/cache-success.mag.ts to verify:
- Node publishes successfully
- GREEN success notification (not yellow warning)
- No "cache update failed" message
Verification
After the fix, server logs show:
[POST /api/nodes] ✓ Published to ATproto PDS
[POST /api/nodes] ✓ Generated embedding vector
[POST /api/nodes] ✓ Cached node in SurrealDB
POST /api/nodes 200 in 1078ms
No more authentication errors! 🎉
Architecture Note
This implements the "App View Cache" pattern where:
- ATproto PDS is the source of truth (decentralized, user-owned)
- SurrealDB is a performance cache (centralized, app-managed)
The cache uses root credentials but enforces data isolation through user_did filtering in application code, similar to how the OAuth session store works (lib/auth/oauth-session-store.ts).