my own indieAuth provider! indiko.dunkirk.sh/docs
indieauth oauth2-server
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add favicon route

+70 -54
+70 -54
src/index.ts
··· 1 1 import { env } from "bun"; 2 2 import { db } from "./db"; 3 - import indexHTML from "./html/index.html"; 4 3 import adminHTML from "./html/admin.html"; 5 - import adminInvitesHTML from "./html/admin-invites.html"; 6 4 import adminClientsHTML from "./html/admin-clients.html"; 7 - import loginHTML from "./html/login.html"; 8 - import docsHTML from "./html/docs.html"; 5 + import adminInvitesHTML from "./html/admin-invites.html"; 9 6 import appsHTML from "./html/apps.html"; 7 + import docsHTML from "./html/docs.html"; 8 + import indexHTML from "./html/index.html"; 9 + import loginHTML from "./html/login.html"; 10 10 import { 11 - canRegister, 12 - registerOptions, 13 - registerVerify, 14 - loginOptions, 15 - loginVerify, 16 - } from "./routes/auth"; 17 - import { 11 + deleteSelfAccount, 12 + deleteUser, 13 + disableUser, 14 + enableUser, 15 + getAppDetails, 16 + getAuthorizedApps, 17 + getProfile, 18 18 hello, 19 + listAllApps, 19 20 listUsers, 20 - getProfile, 21 - updateProfile, 22 - getAuthorizedApps, 23 21 revokeApp, 24 - listAllApps, 25 - getAppDetails, 26 22 revokeAppForUser, 27 - disableUser, 28 - enableUser, 29 - deleteUser, 30 - deleteSelfAccount, 23 + updateProfile, 31 24 } from "./routes/api"; 32 25 import { 26 + canRegister, 27 + loginOptions, 28 + loginVerify, 29 + registerOptions, 30 + registerVerify, 31 + } from "./routes/auth"; 32 + import { 33 + createClient, 34 + deleteClient, 35 + getClient, 36 + listClients, 37 + regenerateClientSecret, 38 + setUserRole, 39 + updateClient, 40 + } from "./routes/clients"; 41 + import { 33 42 authorizeGet, 34 43 authorizePost, 35 - token, 36 - logout, 37 - userProfile, 38 44 createInvite, 45 + deleteInvite, 39 46 listInvites, 47 + logout, 48 + token, 40 49 updateInvite, 41 - deleteInvite, 50 + userProfile, 42 51 } from "./routes/indieauth"; 43 - import { 44 - listClients, 45 - createClient, 46 - getClient, 47 - updateClient, 48 - deleteClient, 49 - setUserRole, 50 - regenerateClientSecret, 51 - } from "./routes/clients"; 52 52 53 53 (() => { 54 54 const required = ["ORIGIN", "RP_ID"]; ··· 63 63 } 64 64 65 65 // Validate ORIGIN is HTTPS in production 66 - const origin = process.env.ORIGIN!; 67 - const rpId = process.env.RP_ID!; 66 + const origin = process.env.ORIGIN as string; 67 + const rpId = process.env.RP_ID as string; 68 68 const nodeEnv = process.env.NODE_ENV || "development"; 69 69 70 70 if (nodeEnv === "production" && !origin.startsWith("https://")) { ··· 94 94 const server = Bun.serve({ 95 95 port: env.PORT ? Number.parseInt(env.PORT, 10) : 3000, 96 96 routes: { 97 + "/favicon.svg": Bun.file("./public/favicon.svg"), 97 98 "/": indexHTML, 98 99 "/health": () => { 99 100 try { 100 101 // Verify database is accessible 101 102 db.query("SELECT 1").get(); 102 - return Response.json({ status: "ok", timestamp: new Date().toISOString() }); 103 + return Response.json({ 104 + status: "ok", 105 + timestamp: new Date().toISOString(), 106 + }); 103 107 } catch { 104 108 return Response.json( 105 109 { status: "error", error: "Database unavailable" }, 106 - { status: 503 } 110 + { status: 503 }, 107 111 ); 108 112 } 109 113 }, ··· 193 197 } 194 198 return new Response("Method not allowed", { status: 405 }); 195 199 }, 196 - "/api/admin/users/:id/enable": (req: Request) => { 197 - if (req.method === "POST") { 198 - const url = new URL(req.url); 199 - const userId = url.pathname.split("/")[4]; 200 - return enableUser(req, userId); 201 - } 202 - return new Response("Method not allowed", { status: 405 }); 203 - }, 200 + "/api/admin/users/:id/enable": (req: Request) => { 201 + if (req.method === "POST") { 202 + const url = new URL(req.url); 203 + const userId = url.pathname.split("/")[4]; 204 + return enableUser(req, userId); 205 + } 206 + return new Response("Method not allowed", { status: 405 }); 207 + }, 204 208 "/api/admin/users/:id/delete": (req: Request) => { 205 209 if (req.method === "DELETE") { 206 210 const url = new URL(req.url); ··· 247 251 "/api/admin/clients/:clientId": (req) => { 248 252 if (req.method === "GET") return getClient(req, req.params.clientId); 249 253 if (req.method === "PUT") return updateClient(req, req.params.clientId); 250 - if (req.method === "DELETE") return deleteClient(req, req.params.clientId); 254 + if (req.method === "DELETE") 255 + return deleteClient(req, req.params.clientId); 251 256 return new Response("Method not allowed", { status: 405 }); 252 257 }, 253 258 "/api/admin/clients/:clientId/users/:username/role": (req) => { ··· 269 274 // Cleanup job: runs every hour to remove expired data 270 275 const cleanupJob = setInterval(() => { 271 276 const now = Math.floor(Date.now() / 1000); 272 - 273 - const sessionsDeleted = db.query("DELETE FROM sessions WHERE expires_at < ?").run(now); 274 - const challengesDeleted = db.query("DELETE FROM challenges WHERE expires_at < ?").run(now); 275 - const authcodesDeleted = db.query("DELETE FROM authcodes WHERE expires_at < ?").run(now); 276 - 277 - const total = sessionsDeleted.changes + challengesDeleted.changes + authcodesDeleted.changes; 278 - 277 + 278 + const sessionsDeleted = db 279 + .query("DELETE FROM sessions WHERE expires_at < ?") 280 + .run(now); 281 + const challengesDeleted = db 282 + .query("DELETE FROM challenges WHERE expires_at < ?") 283 + .run(now); 284 + const authcodesDeleted = db 285 + .query("DELETE FROM authcodes WHERE expires_at < ?") 286 + .run(now); 287 + 288 + const total = 289 + sessionsDeleted.changes + 290 + challengesDeleted.changes + 291 + authcodesDeleted.changes; 292 + 279 293 if (total > 0) { 280 - console.log(`[Cleanup] Removed ${total} expired records (sessions: ${sessionsDeleted.changes}, challenges: ${challengesDeleted.changes}, authcodes: ${authcodesDeleted.changes})`); 294 + console.log( 295 + `[Cleanup] Removed ${total} expired records (sessions: ${sessionsDeleted.changes}, challenges: ${challengesDeleted.changes}, authcodes: ${authcodesDeleted.changes})`, 296 + ); 281 297 } 282 298 }, 3600000); // 1 hour in milliseconds 283 299