feat(server): add /search and /:did/search endpoints
GET /search is public and filters to discoverable=true. GET /:did/search
requires a JWT for that DID and includes non-discoverable notes (drafts).
Both reuse the existing PAGINATION default and { results, cursor }
envelope. The requireDidOwnership 403 message is generalized since it
now guards more than webhooks.
This commit is contained in:
40
server.ts
40
server.ts
@@ -11,6 +11,7 @@ import {
|
||||
type WebhookVerb,
|
||||
} from "./src/data/db.ts";
|
||||
import { authenticateRequest } from "./src/auth/verify.ts";
|
||||
import { searchNotes } from "./src/search/opensearch.ts";
|
||||
import { log } from "./src/log.ts";
|
||||
|
||||
type AuthCtx = {
|
||||
@@ -34,7 +35,7 @@ const requireDidOwnership = async (
|
||||
}
|
||||
if (verifiedDid !== did) {
|
||||
ctx.response.status = 403;
|
||||
ctx.response.body = { error: "You can only manage your own webhooks" };
|
||||
ctx.response.body = { error: "Forbidden: DID mismatch" };
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -131,6 +132,43 @@ router.get("/:did/notes", (ctx) => {
|
||||
ctx.response.body = getNotesByDid(did, cursor, limit);
|
||||
});
|
||||
|
||||
router.get("/search", async (ctx) => {
|
||||
const q = ctx.request.url.searchParams.get("q") ?? "";
|
||||
if (!q.trim()) {
|
||||
ctx.response.status = 400;
|
||||
ctx.response.body = { error: "q is required" };
|
||||
return;
|
||||
}
|
||||
const cursor = ctx.request.url.searchParams.get("cursor") ?? undefined;
|
||||
const limit = Number(ctx.request.url.searchParams.get("limit")) || PAGINATION;
|
||||
ctx.response.body = await searchNotes({
|
||||
q,
|
||||
discoverableOnly: true,
|
||||
cursor,
|
||||
limit,
|
||||
});
|
||||
});
|
||||
|
||||
router.get("/:did/search", async (ctx) => {
|
||||
const { did } = ctx.params;
|
||||
if (!(await requireDidOwnership(ctx, did))) return;
|
||||
const q = ctx.request.url.searchParams.get("q") ?? "";
|
||||
if (!q.trim()) {
|
||||
ctx.response.status = 400;
|
||||
ctx.response.body = { error: "q is required" };
|
||||
return;
|
||||
}
|
||||
const cursor = ctx.request.url.searchParams.get("cursor") ?? undefined;
|
||||
const limit = Number(ctx.request.url.searchParams.get("limit")) || PAGINATION;
|
||||
ctx.response.body = await searchNotes({
|
||||
q,
|
||||
discoverableOnly: false,
|
||||
did,
|
||||
cursor,
|
||||
limit,
|
||||
});
|
||||
});
|
||||
|
||||
router.post("/notes/feed", async (ctx) => {
|
||||
const body = await ctx.request.body.json();
|
||||
const { dids, cursor, limit } = body ?? {};
|
||||
|
||||
Reference in New Issue
Block a user