Return first page of statuses in profile
This commit is contained in:
parent
6fa897145e
commit
502af2cd48
|
@ -4,6 +4,7 @@ import {
|
||||||
accountController,
|
accountController,
|
||||||
accountLookupController,
|
accountLookupController,
|
||||||
accountSearchController,
|
accountSearchController,
|
||||||
|
accountStatusesController,
|
||||||
credentialsController,
|
credentialsController,
|
||||||
relationshipsController,
|
relationshipsController,
|
||||||
} from './controllers/api/accounts.ts';
|
} from './controllers/api/accounts.ts';
|
||||||
|
@ -45,6 +46,7 @@ app.get('/api/v1/accounts/verify_credentials', requireAuth, credentialsControlle
|
||||||
app.get('/api/v1/accounts/search', accountSearchController);
|
app.get('/api/v1/accounts/search', accountSearchController);
|
||||||
app.get('/api/v1/accounts/lookup', accountLookupController);
|
app.get('/api/v1/accounts/lookup', accountLookupController);
|
||||||
app.get('/api/v1/accounts/relationships', relationshipsController);
|
app.get('/api/v1/accounts/relationships', relationshipsController);
|
||||||
|
app.get('/api/v1/accounts/:pubkey{[0-9a-f]{64}}/statuses', accountStatusesController);
|
||||||
app.get('/api/v1/accounts/:pubkey{[0-9a-f]{64}}', accountController);
|
app.get('/api/v1/accounts/:pubkey{[0-9a-f]{64}}', accountController);
|
||||||
|
|
||||||
app.get('/api/v1/statuses/:id{[0-9a-f]{64}}/context', contextController);
|
app.get('/api/v1/statuses/:id{[0-9a-f]{64}}/context', contextController);
|
||||||
|
@ -55,7 +57,6 @@ app.get('/api/v1/timelines/home', requireAuth, homeController);
|
||||||
|
|
||||||
// Not (yet) implemented.
|
// Not (yet) implemented.
|
||||||
app.get('/api/v1/notifications', emptyArrayController);
|
app.get('/api/v1/notifications', emptyArrayController);
|
||||||
app.get('/api/v1/accounts/:id/statuses', emptyArrayController);
|
|
||||||
app.get('/api/v1/bookmarks', emptyArrayController);
|
app.get('/api/v1/bookmarks', emptyArrayController);
|
||||||
app.get('/api/v1/custom_emojis', emptyArrayController);
|
app.get('/api/v1/custom_emojis', emptyArrayController);
|
||||||
app.get('/api/v1/accounts/search', emptyArrayController);
|
app.get('/api/v1/accounts/search', emptyArrayController);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Author, type Filter, findReplyTag, matchFilter, RelayPool } from '@/deps.ts';
|
import { Author, findReplyTag, matchFilter, RelayPool } from '@/deps.ts';
|
||||||
import { type Event, type SignedEvent } from '@/event.ts';
|
import { type Event, type SignedEvent } from '@/event.ts';
|
||||||
|
|
||||||
import { poolRelays } from './config.ts';
|
import { poolRelays } from './config.ts';
|
||||||
|
@ -7,12 +7,23 @@ import { eventDateComparator, nostrNow } from './utils.ts';
|
||||||
|
|
||||||
const pool = new RelayPool(poolRelays);
|
const pool = new RelayPool(poolRelays);
|
||||||
|
|
||||||
|
type Filter<K extends number = number> = {
|
||||||
|
ids?: string[];
|
||||||
|
kinds?: K[];
|
||||||
|
authors?: string[];
|
||||||
|
since?: number;
|
||||||
|
until?: number;
|
||||||
|
limit?: number;
|
||||||
|
search?: string;
|
||||||
|
[key: `#${string}`]: string[];
|
||||||
|
};
|
||||||
|
|
||||||
interface GetFilterOpts {
|
interface GetFilterOpts {
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get events from a NIP-01 filter. */
|
/** Get events from a NIP-01 filter. */
|
||||||
function getFilter(filter: Filter, opts: GetFilterOpts = {}): Promise<SignedEvent[]> {
|
function getFilter<K extends number>(filter: Filter<K>, opts: GetFilterOpts = {}): Promise<SignedEvent<K>[]> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let tid: number;
|
let tid: number;
|
||||||
const results: SignedEvent[] = [];
|
const results: SignedEvent[] = [];
|
||||||
|
@ -27,21 +38,21 @@ function getFilter(filter: Filter, opts: GetFilterOpts = {}): Promise<SignedEven
|
||||||
if (filter.limit && results.length >= filter.limit) {
|
if (filter.limit && results.length >= filter.limit) {
|
||||||
unsub();
|
unsub();
|
||||||
clearTimeout(tid);
|
clearTimeout(tid);
|
||||||
resolve(results);
|
resolve(results as SignedEvent<K>[]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
undefined,
|
undefined,
|
||||||
() => {
|
() => {
|
||||||
unsub();
|
unsub();
|
||||||
clearTimeout(tid);
|
clearTimeout(tid);
|
||||||
resolve(results);
|
resolve(results as SignedEvent<K>[]);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (typeof opts.timeout === 'number') {
|
if (typeof opts.timeout === 'number') {
|
||||||
tid = setTimeout(() => {
|
tid = setTimeout(() => {
|
||||||
unsub();
|
unsub();
|
||||||
resolve(results);
|
resolve(results as SignedEvent<K>[]);
|
||||||
}, opts.timeout);
|
}, opts.timeout);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -121,4 +132,4 @@ function getDescendants(eventId: string): Promise<SignedEvent<1>[]> {
|
||||||
return getFilter({ kinds: [1], '#e': [eventId], limit: 200 }, { timeout: 2000 }) as Promise<SignedEvent<1>[]>;
|
return getFilter({ kinds: [1], '#e': [eventId], limit: 200 }, { timeout: 2000 }) as Promise<SignedEvent<1>[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { getAncestors, getAuthor, getDescendants, getEvent, getFeed, getFollows, pool };
|
export { getAncestors, getAuthor, getDescendants, getEvent, getFeed, getFilter, getFollows, pool };
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { type AppController } from '@/app.ts';
|
import { type AppController } from '@/app.ts';
|
||||||
import { nip05 } from '@/deps.ts';
|
import { nip05, z } from '@/deps.ts';
|
||||||
import { getAuthor } from '@/client.ts';
|
import { getAuthor, getFilter } from '@/client.ts';
|
||||||
import { toAccount } from '@/transmute.ts';
|
import { toAccount, toStatus } from '@/transmute.ts';
|
||||||
import { bech32ToPubkey } from '@/utils.ts';
|
import { bech32ToPubkey } from '@/utils.ts';
|
||||||
|
|
||||||
import type { Event } from '@/event.ts';
|
import type { Event } from '@/event.ts';
|
||||||
|
@ -83,6 +83,26 @@ const relationshipsController: AppController = (c) => {
|
||||||
return c.json(result);
|
return c.json(result);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const accountStatusesQuerySchema = z.object({
|
||||||
|
pinned: z.coerce.boolean(),
|
||||||
|
limit: z.coerce.number().positive().transform((v) => Math.min(v, 40)).catch(20),
|
||||||
|
});
|
||||||
|
|
||||||
|
const accountStatusesController: AppController = async (c) => {
|
||||||
|
const pubkey = c.req.param('pubkey');
|
||||||
|
const { pinned, limit } = accountStatusesQuerySchema.parse(c.req.query());
|
||||||
|
|
||||||
|
// Nostr doesn't support pinned statuses.
|
||||||
|
if (pinned) {
|
||||||
|
return c.json([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const events = await getFilter({ authors: [pubkey], kinds: [1], limit });
|
||||||
|
const statuses = await Promise.all(events.map((event) => toStatus(event)));
|
||||||
|
|
||||||
|
return c.json(statuses);
|
||||||
|
};
|
||||||
|
|
||||||
/** Resolve a bech32 or NIP-05 identifier to an account. */
|
/** Resolve a bech32 or NIP-05 identifier to an account. */
|
||||||
async function lookupAccount(value: string): Promise<Event<0> | undefined> {
|
async function lookupAccount(value: string): Promise<Event<0> | undefined> {
|
||||||
console.log(`Looking up ${value}`);
|
console.log(`Looking up ${value}`);
|
||||||
|
@ -98,6 +118,7 @@ export {
|
||||||
accountController,
|
accountController,
|
||||||
accountLookupController,
|
accountLookupController,
|
||||||
accountSearchController,
|
accountSearchController,
|
||||||
|
accountStatusesController,
|
||||||
credentialsController,
|
credentialsController,
|
||||||
relationshipsController,
|
relationshipsController,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue