fix: await Discord SDK voice subscribes and add missing Activity API endpoints
Some checks failed
Build / build (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Lint & Type Check / lint (push) Has been cancelled
Security Scan / semgrep (push) Has been cancelled
Security Scan / dependency-check (push) Has been cancelled
Test / test (18.x) (push) Has been cancelled
Test / test (20.x) (push) Has been cancelled
Some checks failed
Build / build (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Lint & Type Check / lint (push) Has been cancelled
Security Scan / semgrep (push) Has been cancelled
Security Scan / dependency-check (push) Has been cancelled
Test / test (18.x) (push) Has been cancelled
Test / test (20.x) (push) Has been cancelled
- Await SPEAKING_START/SPEAKING_STOP subscribes so try-catch handles 4006 scope errors - Add GET /api/feed and POST /api/feed/:id/like (community posts alias for Activity) - Add DELETE /api/activity/polls/:id (soft-delete via is_active=false) - Add POST /api/activity/challenges/:id/claim (marks challenge progress as completed) - Add GET /api/activity/badges (all badges, no userId required) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
be30e01a50
commit
1a4321a531
2 changed files with 95 additions and 4 deletions
|
|
@ -284,7 +284,7 @@ export const DiscordActivityProvider: React.FC<
|
||||||
// Subscribe to speaking updates if in voice channel
|
// Subscribe to speaking updates if in voice channel
|
||||||
if (sdk.channelId) {
|
if (sdk.channelId) {
|
||||||
try {
|
try {
|
||||||
sdk.subscribe("SPEAKING_START", (data: any) => {
|
await sdk.subscribe("SPEAKING_START", (data: any) => {
|
||||||
console.log("[Discord Activity] Speaking start:", data);
|
console.log("[Discord Activity] Speaking start:", data);
|
||||||
if (data?.user_id) {
|
if (data?.user_id) {
|
||||||
setSpeakingUsers(prev => new Set(prev).add(data.user_id));
|
setSpeakingUsers(prev => new Set(prev).add(data.user_id));
|
||||||
|
|
@ -294,7 +294,7 @@ export const DiscordActivityProvider: React.FC<
|
||||||
}
|
}
|
||||||
}, { channel_id: sdk.channelId });
|
}, { channel_id: sdk.channelId });
|
||||||
|
|
||||||
sdk.subscribe("SPEAKING_STOP", (data: any) => {
|
await sdk.subscribe("SPEAKING_STOP", (data: any) => {
|
||||||
console.log("[Discord Activity] Speaking stop:", data);
|
console.log("[Discord Activity] Speaking stop:", data);
|
||||||
if (data?.user_id) {
|
if (data?.user_id) {
|
||||||
setSpeakingUsers(prev => {
|
setSpeakingUsers(prev => {
|
||||||
|
|
|
||||||
|
|
@ -2817,6 +2817,41 @@ export function createServer() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Activity feed alias (used by Discord Activity)
|
||||||
|
app.get("/api/feed", async (req, res) => {
|
||||||
|
const limit = Math.max(1, Math.min(50, Number(req.query.limit) || 10));
|
||||||
|
try {
|
||||||
|
const { data, error } = await adminSupabase
|
||||||
|
.from("community_posts")
|
||||||
|
.select(`id, title, content, likes_count, author_id, created_at, user_profiles ( username, full_name, avatar_url )`)
|
||||||
|
.eq("is_published", true)
|
||||||
|
.order("created_at", { ascending: false })
|
||||||
|
.limit(limit);
|
||||||
|
if (error) return res.status(500).json({ error: error.message });
|
||||||
|
res.json({ data: data || [] });
|
||||||
|
} catch (e: any) {
|
||||||
|
res.status(500).json({ error: e?.message || String(e) });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post("/api/feed/:id/like", async (req, res) => {
|
||||||
|
const postId = req.params.id;
|
||||||
|
try {
|
||||||
|
const { data: post } = await adminSupabase
|
||||||
|
.from("community_posts")
|
||||||
|
.select("likes_count")
|
||||||
|
.eq("id", postId)
|
||||||
|
.single();
|
||||||
|
await adminSupabase
|
||||||
|
.from("community_posts")
|
||||||
|
.update({ likes_count: (post?.likes_count || 0) + 1 })
|
||||||
|
.eq("id", postId);
|
||||||
|
res.json({ ok: true });
|
||||||
|
} catch (e: any) {
|
||||||
|
res.status(500).json({ error: e?.message || String(e) });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.get("/api/user/:id/posts", async (req, res) => {
|
app.get("/api/user/:id/posts", async (req, res) => {
|
||||||
const userId = req.params.id;
|
const userId = req.params.id;
|
||||||
try {
|
try {
|
||||||
|
|
@ -3862,6 +3897,20 @@ export function createServer() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.delete("/api/activity/polls/:id", async (req, res) => {
|
||||||
|
const pollId = req.params.id;
|
||||||
|
try {
|
||||||
|
const { error } = await adminSupabase
|
||||||
|
.from("activity_polls")
|
||||||
|
.update({ is_active: false })
|
||||||
|
.eq("id", pollId);
|
||||||
|
if (error) return res.status(500).json({ error: error.message });
|
||||||
|
res.json({ ok: true });
|
||||||
|
} catch (e: any) {
|
||||||
|
res.status(500).json({ error: e?.message || String(e) });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.post("/api/activity/polls/:id/vote", async (req, res) => {
|
app.post("/api/activity/polls/:id/vote", async (req, res) => {
|
||||||
const pollId = req.params.id;
|
const pollId = req.params.id;
|
||||||
const { user_id, option_index } = req.body || {};
|
const { user_id, option_index } = req.body || {};
|
||||||
|
|
@ -3942,6 +3991,29 @@ export function createServer() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.post("/api/activity/challenges/:id/claim", async (req, res) => {
|
||||||
|
const challengeId = req.params.id;
|
||||||
|
const { user_id } = req.body || {};
|
||||||
|
if (!user_id) return res.status(400).json({ error: "user_id required" });
|
||||||
|
try {
|
||||||
|
const { data, error } = await adminSupabase
|
||||||
|
.from("activity_challenge_progress")
|
||||||
|
.upsert({
|
||||||
|
challenge_id: challengeId,
|
||||||
|
user_id,
|
||||||
|
progress: 1,
|
||||||
|
completed: true,
|
||||||
|
completed_at: new Date().toISOString(),
|
||||||
|
}, { onConflict: "challenge_id,user_id" })
|
||||||
|
.select()
|
||||||
|
.single();
|
||||||
|
if (error) return res.status(500).json({ error: error.message });
|
||||||
|
res.json(data);
|
||||||
|
} catch (e: any) {
|
||||||
|
res.status(500).json({ error: e?.message || String(e) });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.get("/api/activity/challenges/:id/progress", async (req, res) => {
|
app.get("/api/activity/challenges/:id/progress", async (req, res) => {
|
||||||
const challengeId = req.params.id;
|
const challengeId = req.params.id;
|
||||||
const user_id = req.query.user_id as string;
|
const user_id = req.query.user_id as string;
|
||||||
|
|
@ -4053,6 +4125,25 @@ export function createServer() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// All badges (for Activity badges tab when no userId)
|
||||||
|
app.get("/api/activity/badges", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { data, error } = await adminSupabase
|
||||||
|
.from("badges")
|
||||||
|
.select("*")
|
||||||
|
.order("created_at", { ascending: true });
|
||||||
|
if (error) {
|
||||||
|
if (error.code === "42P01" || error.message?.includes("does not exist")) {
|
||||||
|
return res.json([]);
|
||||||
|
}
|
||||||
|
return res.status(500).json({ error: error.message });
|
||||||
|
}
|
||||||
|
res.json(data || []);
|
||||||
|
} catch (e: any) {
|
||||||
|
res.status(500).json({ error: e?.message || String(e) });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// User Badges (real data)
|
// User Badges (real data)
|
||||||
app.get("/api/activity/badges/:userId", async (req, res) => {
|
app.get("/api/activity/badges/:userId", async (req, res) => {
|
||||||
const userId = req.params.userId;
|
const userId = req.params.userId;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue