fix: Discord Activity token exchange, CSP headers, subscription routes, and static asset 404
- Remove redirect_uri from Discord token exchange (Activities use proxy auth, not redirect flow) - Add Content-Security-Policy with frame-ancestors for Discord embedding (was only in vercel.json) - Wire up subscription create-checkout and manage routes in Express - Add Studio arm to ArmSwitcher with external link - Prevent SPA catch-all from serving HTML for missing static assets (fixes script.js Unexpected token error) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
34368e1dde
commit
f1bcc957f9
4 changed files with 37 additions and 6 deletions
|
|
@ -38,9 +38,6 @@ export default async function handler(req: any, res: any) {
|
|||
client_secret: clientSecret,
|
||||
grant_type: "authorization_code",
|
||||
code,
|
||||
redirect_uri:
|
||||
process.env.DISCORD_ACTIVITY_REDIRECT_URI ||
|
||||
"https://aethex.dev/activity",
|
||||
}).toString(),
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -68,9 +68,22 @@ const ARMS: Arm[] = [
|
|||
textColor: "text-purple-400",
|
||||
href: "/staff",
|
||||
},
|
||||
{
|
||||
id: "studio",
|
||||
name: "AeThex | Studio",
|
||||
label: "Studio",
|
||||
color: "#00ffff",
|
||||
bgColor: "bg-cyan-500/20",
|
||||
textColor: "text-cyan-400",
|
||||
href: "https://aethex.studio",
|
||||
external: true,
|
||||
},
|
||||
];
|
||||
|
||||
const STUDIO_SVG = `data:image/svg+xml,${encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><rect width="512" height="512" rx="96" fill="%23050505"/><polygon points="256,48 444,152 444,360 256,464 68,360 68,152" fill="none" stroke="%2300ffff" stroke-width="18" opacity="0.9"/><text x="256" y="320" text-anchor="middle" font-family="Orbitron,monospace" font-size="220" font-weight="700" fill="%2300ffff">Æ</text></svg>')}`;
|
||||
|
||||
const LOGO_URLS: Record<string, string> = {
|
||||
studio: STUDIO_SVG,
|
||||
staff:
|
||||
"https://cdn.builder.io/api/v1/image/assets%2Ffc53d607e21d497595ac97e0637001a1%2Fc0414efd7af54ef4b821a05d469150d0?format=webp&width=800",
|
||||
labs: "https://cdn.builder.io/api/v1/image/assets%2Ffc53d607e21d497595ac97e0637001a1%2Fd93f7113d34347469e74421c3a3412e5?format=webp&width=800",
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ import blogIndexHandler from "../api/blog/index";
|
|||
import blogSlugHandler from "../api/blog/[slug]";
|
||||
import aiChatHandler from "../api/ai/chat";
|
||||
import aiTitleHandler from "../api/ai/title";
|
||||
import createCheckoutHandler from "../api/subscriptions/create-checkout";
|
||||
import manageSubscriptionHandler from "../api/subscriptions/manage";
|
||||
|
||||
// Developer API Keys handlers
|
||||
import {
|
||||
|
|
@ -340,6 +342,11 @@ export function createServer() {
|
|||
app.use((req, res, next) => {
|
||||
// Allow embedding in iframes (Discord Activities need this)
|
||||
res.setHeader("X-Frame-Options", "ALLOWALL");
|
||||
// CSP with frame-ancestors for Discord Activity embedding
|
||||
res.setHeader(
|
||||
"Content-Security-Policy",
|
||||
"default-src 'self' https: data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' data: blob: https:; font-src 'self' data: https:; connect-src 'self' https: wss:; frame-ancestors 'self' https://discord.com https://*.discord.com https://*.discordsays.com",
|
||||
);
|
||||
// Allow Discord to access the iframe
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
res.setHeader(
|
||||
|
|
@ -1815,9 +1822,6 @@ export function createServer() {
|
|||
client_secret: clientSecret,
|
||||
grant_type: "authorization_code",
|
||||
code,
|
||||
redirect_uri:
|
||||
process.env.DISCORD_ACTIVITY_REDIRECT_URI ||
|
||||
"https://aethex.dev/activity",
|
||||
}).toString(),
|
||||
},
|
||||
);
|
||||
|
|
@ -8177,5 +8181,16 @@ export function createServer() {
|
|||
app.post("/api/ai/chat", aiChatHandler);
|
||||
app.post("/api/ai/title", aiTitleHandler);
|
||||
|
||||
// Subscription API routes
|
||||
app.post("/api/subscriptions/create-checkout", (req: express.Request, res: express.Response) => {
|
||||
return createCheckoutHandler(req as any, res as any);
|
||||
});
|
||||
app.get("/api/subscriptions/manage", (req: express.Request, res: express.Response) => {
|
||||
return manageSubscriptionHandler(req as any, res as any);
|
||||
});
|
||||
app.post("/api/subscriptions/manage", (req: express.Request, res: express.Response) => {
|
||||
return manageSubscriptionHandler(req as any, res as any);
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -335,6 +335,12 @@ app.get("*", async (req, res) => {
|
|||
return res.status(404).json({ error: "API endpoint not found" });
|
||||
}
|
||||
|
||||
// Don't serve the SPA shell for missing static-asset requests — they should 404
|
||||
// cleanly rather than returning HTML (which causes "Unexpected token '<'" JS errors).
|
||||
if (/\.(js|mjs|cjs|css|map|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|webp|avif)$/i.test(req.path)) {
|
||||
return res.status(404).send("Not found");
|
||||
}
|
||||
|
||||
try {
|
||||
const template = getTemplate();
|
||||
const meta = await resolveRouteMeta(req.path);
|
||||
|
|
|
|||
Loading…
Reference in a new issue