152 lines
4.0 KiB
TypeScript
152 lines
4.0 KiB
TypeScript
import { Application, Router } from "@oak/oak";
|
|
import {
|
|
addWebhookSubscription,
|
|
deleteWebhooksByDid,
|
|
getNotes,
|
|
getNotesByDid,
|
|
getNotesByDids,
|
|
} from "./src/data/db.ts";
|
|
import { log } from "./src/log.ts";
|
|
|
|
const router = new Router();
|
|
|
|
const PAGINATION = 20;
|
|
const GITHUB_CLIENT_ID = Deno.env.get("GITHUB_CLIENT_ID") ?? "";
|
|
const GITHUB_CLIENT_SECRET = Deno.env.get("GITHUB_CLIENT_SECRET") ?? "";
|
|
|
|
router.get("/", (ctx) => {
|
|
ctx.response.body = "Hello world";
|
|
});
|
|
|
|
router.get("/auth/github", async (ctx) => {
|
|
const code = ctx.request.url.searchParams.get("code");
|
|
const type = ctx.request.url.searchParams.get("type");
|
|
|
|
if (!code) {
|
|
ctx.response.status = 400;
|
|
ctx.response.body = { error: "code is required" };
|
|
return;
|
|
}
|
|
|
|
const params: Record<string, string> = {
|
|
client_id: GITHUB_CLIENT_ID,
|
|
client_secret: GITHUB_CLIENT_SECRET,
|
|
};
|
|
|
|
if (type === "refresh") {
|
|
params.grant_type = "refresh_token";
|
|
params.refresh_token = code;
|
|
} else {
|
|
params.code = code;
|
|
}
|
|
|
|
const response = await fetch(
|
|
"https://github.com/login/oauth/access_token",
|
|
{
|
|
method: "POST",
|
|
headers: {
|
|
"Accept": "application/json",
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify(params),
|
|
},
|
|
);
|
|
|
|
ctx.response.status = response.status;
|
|
ctx.response.body = await response.json();
|
|
});
|
|
|
|
router.get("/health", (ctx) => {
|
|
ctx.response.body = { status: "ok" };
|
|
});
|
|
|
|
router.get("/notes", (ctx) => {
|
|
const cursor = ctx.request.url.searchParams.get("cursor") ?? undefined;
|
|
const limit = Number(ctx.request.url.searchParams.get("limit")) || PAGINATION;
|
|
ctx.response.body = getNotes(cursor, limit);
|
|
});
|
|
|
|
router.get("/:did/notes", (ctx) => {
|
|
const { did } = ctx.params;
|
|
const cursor = ctx.request.url.searchParams.get("cursor") ?? undefined;
|
|
const limit = Number(ctx.request.url.searchParams.get("limit")) || PAGINATION;
|
|
ctx.response.body = getNotesByDid(did, cursor, limit);
|
|
});
|
|
|
|
router.post("/notes/feed", async (ctx) => {
|
|
const body = await ctx.request.body.json();
|
|
const { dids, cursor, limit } = body ?? {};
|
|
if (!Array.isArray(dids) || dids.length === 0) {
|
|
ctx.response.status = 400;
|
|
ctx.response.body = { error: "dids must be a non-empty array" };
|
|
return;
|
|
}
|
|
ctx.response.body = getNotesByDids(dids, cursor, Number(limit) || PAGINATION);
|
|
});
|
|
|
|
router.post("/:did/webhooks", async (ctx) => {
|
|
const { did } = ctx.params;
|
|
const body = await ctx.request.body.json();
|
|
const { method, url, token } = body ?? {};
|
|
if (!method || !url) {
|
|
ctx.response.status = 400;
|
|
ctx.response.body = { error: "method and url are required" };
|
|
return;
|
|
}
|
|
const subscription = addWebhookSubscription({ did, method, url, token });
|
|
ctx.response.status = 201;
|
|
ctx.response.body = subscription;
|
|
});
|
|
|
|
router.delete("/:did/webhooks", (ctx) => {
|
|
const { did } = ctx.params;
|
|
deleteWebhooksByDid(did);
|
|
ctx.response.status = 204;
|
|
});
|
|
|
|
// router.delete("/:did/:rkey", async (ctx) => {
|
|
// const { did, rkey } = ctx.params;
|
|
// let verifiedDid: string;
|
|
// try {
|
|
// verifiedDid = await authenticateRequest(
|
|
// ctx.request.headers.get("Authorization"),
|
|
// );
|
|
// } catch {
|
|
// ctx.response.status = 401;
|
|
// ctx.response.body = { error: "Unauthorized" };
|
|
// return;
|
|
// }
|
|
// if (verifiedDid !== did) {
|
|
// ctx.response.status = 403;
|
|
// ctx.response.body = { error: "You can only delete your own notes" };
|
|
// return;
|
|
// }
|
|
// deleteNote({ did, rkey });
|
|
// ctx.response.status = 204;
|
|
// })
|
|
|
|
const app = new Application();
|
|
|
|
app.use(async (ctx, next) => {
|
|
ctx.response.headers.set("Access-Control-Allow-Origin", "*");
|
|
ctx.response.headers.set(
|
|
"Access-Control-Allow-Methods",
|
|
"GET, POST, PUT, DELETE, OPTIONS",
|
|
);
|
|
ctx.response.headers.set(
|
|
"Access-Control-Allow-Headers",
|
|
"Content-Type, Authorization",
|
|
);
|
|
if (ctx.request.method === "OPTIONS") {
|
|
ctx.response.status = 204;
|
|
return;
|
|
}
|
|
await next();
|
|
});
|
|
|
|
app.use(router.routes());
|
|
app.use(router.allowedMethods());
|
|
|
|
log("[server] listening on port 8080");
|
|
app.listen({ port: 8080 });
|