feat(encryptid): add wallet lookup + payment notification APIs
CI/CD / deploy (push) Successful in 3m3s Details

Add internal endpoints for payment infrastructure integration:
- GET /api/internal/user-by-wallet — resolve wallet to email/username
- POST /api/internal/notify — trigger in-app notifications by wallet/DID
- Add 'payment' notification category and payment_sent/received event types

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-04-04 00:58:04 +00:00
parent 7e61d23799
commit 8f8ec25788
2 changed files with 64 additions and 2 deletions

View File

@ -67,7 +67,7 @@ async function getSmtpTransport() {
// TYPES
// ============================================================================
export type NotificationCategory = 'space' | 'module' | 'system' | 'social';
export type NotificationCategory = 'space' | 'module' | 'system' | 'social' | 'payment';
export type NotificationEventType =
// Space
@ -85,7 +85,9 @@ export type NotificationEventType =
// Delegation
| 'delegation_received' | 'delegation_revoked' | 'delegation_expired'
// Commitment (rTime)
| 'commitment_requested' | 'commitment_accepted' | 'commitment_declined';
| 'commitment_requested' | 'commitment_accepted' | 'commitment_declined'
// Payment
| 'payment_sent' | 'payment_received' | 'payment_request_fulfilled';
export interface NotifyOptions {
userDid: string;

View File

@ -4260,6 +4260,66 @@ app.get('/api/internal/user-by-email', async (c) => {
});
});
// GET /api/internal/user-by-wallet — look up user by wallet address
app.get('/api/internal/user-by-wallet', async (c) => {
const serviceKey = c.req.header('X-Service-Key');
if (!INTERNAL_SERVICE_KEY || serviceKey !== INTERNAL_SERVICE_KEY) {
return c.json({ error: 'Unauthorized' }, 401);
}
const wallet = c.req.query('wallet');
if (!wallet) return c.json({ found: false }, 200);
const normalizedWallet = wallet.toLowerCase().trim();
// Look up user by wallet_address field in users table
const rows = await sql`SELECT * FROM users WHERE LOWER(wallet_address) = ${normalizedWallet} LIMIT 1`;
if (rows.length === 0) return c.json({ found: false }, 200);
const profile = await getUserProfile(rows[0].id);
return c.json({
found: true,
email: profile?.profileEmail || rows[0].email || undefined,
username: profile?.username || rows[0].username || undefined,
userId: rows[0].id,
did: rows[0].did || undefined,
});
});
// POST /api/internal/notify — trigger in-app notification for a user by DID or wallet
app.post('/api/internal/notify', async (c) => {
const serviceKey = c.req.header('X-Service-Key');
if (!INTERNAL_SERVICE_KEY || serviceKey !== INTERNAL_SERVICE_KEY) {
return c.json({ error: 'Unauthorized' }, 401);
}
const { userDid, wallet, category, eventType, title, body, actionUrl, actorUsername, metadata } = await c.req.json();
// Resolve DID from wallet if not provided
let resolvedDid = userDid;
if (!resolvedDid && wallet) {
const normalizedWallet = wallet.toLowerCase().trim();
const rows = await sql`SELECT did FROM users WHERE LOWER(wallet_address) = ${normalizedWallet} LIMIT 1`;
if (rows.length > 0) resolvedDid = rows[0].did;
}
if (!resolvedDid) {
return c.json({ error: 'Could not resolve user — provide userDid or a registered wallet' }, 400);
}
const notification = await notify({
userDid: resolvedDid,
category: category || 'payment',
eventType: eventType || 'payment_received',
title: title || 'Payment received',
body,
actionUrl,
actorUsername,
metadata,
});
return c.json({ success: true, notificationId: notification.id });
});
// ============================================================================
// USER LOOKUP
// ============================================================================