diff --git a/deno.lock b/deno.lock index 874085e8..70dc97b8 100644 --- a/deno.lock +++ b/deno.lock @@ -31,7 +31,6 @@ "jsr:@hono/hono@^4.4.6": "4.6.15", "jsr:@negrel/http-ece@0.6.0": "0.6.0", "jsr:@negrel/webpush@0.3": "0.3.0", - "jsr:@nostrify/db@0.38": "0.38.0", "jsr:@nostrify/nostrify@0.31": "0.31.0", "jsr:@nostrify/nostrify@0.32": "0.32.0", "jsr:@nostrify/nostrify@0.36": "0.36.2", @@ -357,15 +356,6 @@ "jsr:@std/path@0.224.0" ] }, - "@nostrify/db@0.38.0": { - "integrity": "44118756b95f747779839f0e578a5e1dbca164ec44edb8885bd1c99840775e8a", - "dependencies": [ - "jsr:@nostrify/nostrify@~0.38.1", - "jsr:@nostrify/types@0.36", - "npm:kysely@~0.27.3", - "npm:nostr-tools@^2.10.4" - ] - }, "@nostrify/nostrify@0.22.4": { "integrity": "1c8a7847e5773213044b491e85fd7cafae2ad194ce59da4d957d2b27c776b42d", "dependencies": [ @@ -2372,7 +2362,7 @@ "jsr:@gfx/canvas-wasm@~0.4.2", "jsr:@hono/hono@^4.4.6", "jsr:@negrel/webpush@0.3", - "jsr:@nostrify/db@0.38", + "jsr:@nostrify/db@0.39", "jsr:@nostrify/nostrify@~0.38.1", "jsr:@nostrify/policies@~0.36.1", "jsr:@nostrify/types@0.36", diff --git a/src/controllers/api/search.ts b/src/controllers/api/search.ts index c0a4a54e..c050fe9d 100644 --- a/src/controllers/api/search.ts +++ b/src/controllers/api/search.ts @@ -12,6 +12,7 @@ import { accountFromPubkey, renderAccount } from '@/views/mastodon/accounts.ts'; import { renderStatus } from '@/views/mastodon/statuses.ts'; import { getFollowedPubkeys } from '@/queries.ts'; import { getPubkeysBySearch } from '@/utils/search.ts'; +import { paginated } from '@/utils/api.ts'; const searchQuerySchema = z.object({ q: z.string().transform(decodeURIComponent), @@ -19,14 +20,14 @@ const searchQuerySchema = z.object({ resolve: booleanParamSchema.optional().transform(Boolean), following: z.boolean().default(false), account_id: n.id().optional(), - limit: z.coerce.number().catch(20).transform((value) => Math.min(Math.max(value, 0), 40)), offset: z.coerce.number().nonnegative().catch(0), }); -type SearchQuery = z.infer; +type SearchQuery = z.infer & { since?: number; until?: number; limit: number }; const searchController: AppController = async (c) => { const result = searchQuerySchema.safeParse(c.req.query()); + const params = c.get('pagination'); const { signal } = c.req.raw; const viewerPubkey = await c.get('signer')?.getPublicKey(); @@ -34,14 +35,14 @@ const searchController: AppController = async (c) => { return c.json({ error: 'Bad request', schema: result.error }, 422); } - const event = await lookupEvent(result.data, signal); + const event = await lookupEvent({ ...result.data, ...params }, signal); const lookup = extractIdentifier(result.data.q); // Render account from pubkey. if (!event && lookup) { const pubkey = await lookupPubkey(lookup); return c.json({ - accounts: pubkey ? [await accountFromPubkey(pubkey)] : [], + accounts: pubkey ? [accountFromPubkey(pubkey)] : [], statuses: [], hashtags: [], }); @@ -52,7 +53,8 @@ const searchController: AppController = async (c) => { if (event) { events = [event]; } - events.push(...(await searchEvents({ ...result.data, viewerPubkey }, signal))); + + events.push(...(await searchEvents({ ...result.data, ...params, viewerPubkey }, signal))); const [accounts, statuses] = await Promise.all([ Promise.all( @@ -69,16 +71,18 @@ const searchController: AppController = async (c) => { ), ]); - return c.json({ + const body = { accounts, statuses, hashtags: [], - }); + }; + + return paginated(c, events, body); }; /** Get events for the search params. */ async function searchEvents( - { q, type, limit, offset, account_id, viewerPubkey }: SearchQuery & { viewerPubkey?: string }, + { q, type, since, until, limit, offset, account_id, viewerPubkey }: SearchQuery & { viewerPubkey?: string }, signal: AbortSignal, ): Promise { // Hashtag search is not supported. @@ -91,6 +95,8 @@ async function searchEvents( const filter: NostrFilter = { kinds: typeToKinds(type), search: q, + since, + until, limit, }; diff --git a/src/utils/api.ts b/src/utils/api.ts index 29304cbd..ebe07748 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -207,12 +207,10 @@ function buildLinkHeader(url: string, events: NostrEvent[]): string | undefined return `<${next}>; rel="next", <${prev}>; rel="prev"`; } -// deno-lint-ignore ban-types -type Entity = {}; type HeaderRecord = Record; /** Return results with pagination headers. Assumes chronological sorting of events. */ -function paginated(c: AppContext, events: NostrEvent[], entities: (Entity | undefined)[], headers: HeaderRecord = {}) { +function paginated(c: AppContext, events: NostrEvent[], body: object | unknown[], headers: HeaderRecord = {}) { const link = buildLinkHeader(c.req.url, events); if (link) { @@ -220,7 +218,7 @@ function paginated(c: AppContext, events: NostrEvent[], entities: (Entity | unde } // Filter out undefined entities. - const results = entities.filter((entity): entity is Entity => Boolean(entity)); + const results = Array.isArray(body) ? body.filter(Boolean) : body; return c.json(results, 200, headers); }