feat: fetch and consume device prekey bundle - #211
Conversation
feat(backend): PostgreSQL connection with Drizzle ORM + base schema
feat(backend): SIWS wallet auth with JWT + Socket.IO middleware
feat(backend): real-time messaging via Socket.IO with persistent storage
feat(contracts): TokenTransfer Soroban contract with testnet deploy script
…Works, TechStack, CTA, Footer)
feat(web): landing page for Clicked
ci(backend): format check, lint, and test pipeline
Adds GET /users/:id — requires a valid JWT, returns id/username/avatarUrl plus wallet address/isPrimary pairs; explicit serialization prevents leaking internal fields. Returns 404 for unknown or malformed IDs. Fixes codebestia#10
Adds proposals Soroban contract with cast_vote/execute_proposal: double-vote prevention, expiry enforcement, yes>no pass threshold, and cross-contract treasury withdraw on passed proposals. Also adds group_treasury contract gating withdraw behind the proposals contract. 20 tests cover all acceptance criteria. Fixes codebestia#39
Adds contracts/scripts/deploy_group_treasury.sh mirroring deploy_token_transfer.sh. Validates DEPLOYER_SECRET, ADMIN_ADDRESS, TOKEN_CONTRACT_ID, and INITIAL_MEMBERS (comma-separated) before building, uploading WASM, deploying, and calling initialize. Outputs contract ID and .env setup instructions. Adds GROUP_TREASURY_CONTRACT_ID to .env.example. Fixes codebestia#42
- Add useSocket hook connecting to backend via socket.io-client - Add /app/conversations/[id]/page.tsx with scrollable message thread - Messages grouped by date with day separators - Self messages right-aligned (accent), others left-aligned - Auto-scroll to bottom only when user is already at the bottom - Shows avatar, sender name, content, and timestamp per message
- Add reusable validate(schema) Express middleware returning structured 400s
- Add ChallengeSchema and VerifySchema for auth routes
- Replace manual if(!field) guards in auth.ts with validate middleware
- Structured error format: { error, issues: [{ field, message }] }
- Add supertest + 6 tests covering valid input, missing fields, wrong types
feat: group treasury contract, Makefile, and AI agent chat/fraud endpoints
…oint-10 feat(api): implement GET user profile endpoint
- Add last_read_message_id nullable FK column to conversation_members schema
- Generate migration 0002_greedy_hellion.sql (ALTER TABLE + FK constraint)
- Add message_read Socket.IO event handler with membership + message validation
- Persist lastReadMessageId per userId/conversationId in conversation_members
- Broadcast read_receipt { userId, lastReadMessageId } to conversation room
- Prevent spoofed reads: validates message exists in target conversation
- Add 4 tests covering success, non-member error, invalid message, DB persistence
- Extract Express app into src/app.ts for testability (server start stays in index.ts)
- Add supertest dev dependency for HTTP assertion
- Add 10 integration test cases for POST /auth/challenge and POST /auth/verify:
challenge: valid walletAddress, missing walletAddress, empty body
verify: new user JWT, existing user JWT, expired nonce, invalid sig,
missing fields, empty body, malformed wallet address (Keypair throws)
- All mocks (DB, nonce, Stellar SDK) are offline — no real network or DB required
- 21 tests pass across 3 test files
- Add ioredis dependency and src/lib/redis.ts with graceful null fallback - Cache GET /conversations per userId with 30-second TTL (CONV_CACHE_TTL) - Cache key format: conversations:<userId> - Invalidate cache for all conversation members after send_message - Invalidate cache for all new members after create_conversation - Redis errors silently degrade: requests fall through to DB - Add 5 tests: cache hit skips DB, cache miss writes to Redis, null Redis fallback, Redis error fallback, per-user key format verified
[CONTRACT] Add member management to Group Treasury
created apps/web/src/components/ui/Modal.tsx:1
…mponent add WalletAddress component with copy and explorer link
…ndicator feat: add online presence indicator to DM avatars and member count to…
feat(ui): implement CopyButton with clipboard API and framer-motion t…
Centralize admin check and update backend configuration
|
@Andreschuks101 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
There was a problem hiding this comment.
No need to create a new devices schema.
The device schema has already been created in a different pr.
Merge main to get it and work with it.
Also, please resolve the conflicts.
|
Hello @Andreschuks101 |
|
Please update your main branch before raising another PR. |
Fetch + consume prekey bundle — GET /users/:userId/devices/:deviceId/key-bundle
closes #160
Serves a recipient device's public prekey bundle and consumes one one-time prekey
per fetch, so a sender can start an X3DH/Signal-style encrypted session.
Changes
devices(identity public key, registrationId, signedprekey + signature,
revokedAt) andone_time_pre_keys(consumedflag,unique
(device_id, key_id),(device_id, consumed)index). Migration0007_device_key_bundles. Only public key material is stored.fetchAndConsumeKeyBundle: looks up the device, returns 404 if it isunknown or revoked, and otherwise returns
{ identityPublicKey, registrationId, signedPreKey, oneTimePreKey | null }.GET /users/:userId/devices/:deviceId/key-bundle, authenticated.Atomic, race-free consumption
The one-time prekey is claimed in a single statement:
FOR UPDATE SKIP LOCKEDensures concurrent senders skip a row another transactionis already claiming, so the same one-time prekey can never be issued twice. When
the pool is exhausted the bundle is still returned with
oneTimePreKey: null.Acceptance criteria
oneTimePreKey: nullgracefully when the pool is exhausted.Testing
null on exhaustion, 404 for unknown and revoked devices, and a "no private
material" shape assertion.