mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 03:19:46 +00:00
Set up DittoApp, minor fixes to controllers
This commit is contained in:
parent
d3730284de
commit
e5100530da
3 changed files with 30 additions and 54 deletions
|
|
@ -1,6 +1,8 @@
|
|||
import { DittoApp } from '@ditto/api';
|
||||
import { DittoConf } from '@ditto/conf';
|
||||
import { DittoDatabase, DittoTables } from '@ditto/db';
|
||||
import { type Context, Env as HonoEnv, Handler, Hono, Input as HonoInput, MiddlewareHandler } from '@hono/hono';
|
||||
import { type DittoTranslator } from '@ditto/translators';
|
||||
import { type Context, Env as HonoEnv, Handler, Input as HonoInput, MiddlewareHandler } from '@hono/hono';
|
||||
import { every } from '@hono/hono/combine';
|
||||
import { cors } from '@hono/hono/cors';
|
||||
import { serveStatic } from '@hono/hono/deno';
|
||||
|
|
@ -137,7 +139,6 @@ import { metricsController } from '@/controllers/metrics.ts';
|
|||
import { manifestController } from '@/controllers/manifest.ts';
|
||||
import { nodeInfoController, nodeInfoSchemaController } from '@/controllers/well-known/nodeinfo.ts';
|
||||
import { nostrController } from '@/controllers/well-known/nostr.ts';
|
||||
import { DittoTranslator } from '@/interfaces/DittoTranslator.ts';
|
||||
import { requireProof, requireRole } from '@/middleware/auth98Middleware.ts';
|
||||
import { cacheControlMiddleware } from '@/middleware/cacheControlMiddleware.ts';
|
||||
import { cspMiddleware } from '@/middleware/cspMiddleware.ts';
|
||||
|
|
@ -222,26 +223,13 @@ type AppMiddleware = MiddlewareHandler<AppEnv>;
|
|||
// deno-lint-ignore no-explicit-any
|
||||
type AppController<P extends string = any> = Handler<AppEnv, P, HonoInput, Response | Promise<Response>>;
|
||||
|
||||
const app = new Hono<AppEnv>({ strict: false });
|
||||
const app = new DittoApp({ conf, db, store }, { strict: false });
|
||||
|
||||
/** User-provided files in the gitignored `public/` directory. */
|
||||
const publicFiles = serveStatic({ root: conf.publicDir });
|
||||
/** Static files provided by the Ditto repo, checked into git. */
|
||||
const staticFiles = serveStatic({ root: new URL('./static', import.meta.url).pathname });
|
||||
|
||||
// Set up the base context.
|
||||
app.use((c, next) => {
|
||||
c.set('db', db);
|
||||
c.set('conf', conf);
|
||||
c.set('kysely', kysely);
|
||||
c.set('pool', pool);
|
||||
c.set('store', store);
|
||||
c.set('pubsub', pubsub);
|
||||
c.set('signal', c.req.raw.signal);
|
||||
c.set('pipeline', pipeline);
|
||||
return next();
|
||||
});
|
||||
|
||||
app.use(cacheControlMiddleware({ noStore: true }));
|
||||
|
||||
const ratelimit = every(
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { Proof } from '@cashu/cashu-ts';
|
||||
import { confRequiredMw } from '@ditto/api/middleware';
|
||||
import { Hono } from '@hono/hono';
|
||||
import { generateSecretKey, getPublicKey } from 'nostr-tools';
|
||||
import { DittoRoute } from '@ditto/api';
|
||||
import { bytesToString, stringToBytes } from '@scure/base';
|
||||
import { generateSecretKey, getPublicKey } from 'nostr-tools';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { createEvent, parseBody } from '@/utils/api.ts';
|
||||
|
|
@ -15,7 +14,7 @@ import { errorJson } from '@/utils/log.ts';
|
|||
|
||||
type Wallet = z.infer<typeof walletSchema>;
|
||||
|
||||
const app = new Hono().use('*', confRequiredMw, requireStore);
|
||||
const app = new DittoRoute();
|
||||
|
||||
// app.delete('/wallet') -> 204
|
||||
|
||||
|
|
@ -44,9 +43,8 @@ const createCashuWalletAndNutzapInfoSchema = z.object({
|
|||
* https://github.com/nostr-protocol/nips/blob/master/61.md#nutzap-informational-event
|
||||
*/
|
||||
app.put('/wallet', requireNip44Signer, async (c) => {
|
||||
const { conf, signer } = c.var;
|
||||
const store = c.get('store');
|
||||
const pubkey = await signer.getPublicKey();
|
||||
const { conf, store, user } = c.var;
|
||||
const pubkey = await user.signer.getPublicKey();
|
||||
const body = await parseBody(c.req.raw);
|
||||
const { signal } = c.req.raw;
|
||||
const result = createCashuWalletAndNutzapInfoSchema.safeParse(body);
|
||||
|
|
@ -74,23 +72,23 @@ app.put('/wallet', requireNip44Signer, async (c) => {
|
|||
walletContentTags.push(['mint', mint]);
|
||||
}
|
||||
|
||||
const encryptedWalletContentTags = await signer.nip44.encrypt(pubkey, JSON.stringify(walletContentTags));
|
||||
const encryptedWalletContentTags = await user.signer.nip44.encrypt(pubkey, JSON.stringify(walletContentTags));
|
||||
|
||||
// Wallet
|
||||
await createEvent({
|
||||
await createEvent(c.var, {
|
||||
kind: 17375,
|
||||
content: encryptedWalletContentTags,
|
||||
}, c);
|
||||
});
|
||||
|
||||
// Nutzap information
|
||||
await createEvent({
|
||||
await createEvent(c.var, {
|
||||
kind: 10019,
|
||||
tags: [
|
||||
...mints.map((mint) => ['mint', mint, 'sat']),
|
||||
['relay', conf.relay], // TODO: add more relays once things get more stable
|
||||
['pubkey', p2pk],
|
||||
],
|
||||
}, c);
|
||||
});
|
||||
|
||||
// TODO: hydrate wallet and add a 'balance' field when a 'renderWallet' view function is created
|
||||
const walletEntity: Wallet = {
|
||||
|
|
@ -105,9 +103,9 @@ app.put('/wallet', requireNip44Signer, async (c) => {
|
|||
|
||||
/** Gets a wallet, if it exists. */
|
||||
app.get('/wallet', requireNip44Signer, swapNutzapsMiddleware, async (c) => {
|
||||
const { conf, signer } = c.var;
|
||||
const { conf, user } = c.var;
|
||||
const store = c.get('store');
|
||||
const pubkey = await signer.getPublicKey();
|
||||
const pubkey = await user.signer.getPublicKey();
|
||||
const { signal } = c.req.raw;
|
||||
|
||||
const [event] = await store.query([{ authors: [pubkey], kinds: [17375] }], { signal });
|
||||
|
|
@ -115,7 +113,7 @@ app.get('/wallet', requireNip44Signer, swapNutzapsMiddleware, async (c) => {
|
|||
return c.json({ error: 'Wallet not found' }, 404);
|
||||
}
|
||||
|
||||
const decryptedContent: string[][] = JSON.parse(await signer.nip44.decrypt(pubkey, event.content));
|
||||
const decryptedContent: string[][] = JSON.parse(await user.signer.nip44.decrypt(pubkey, event.content));
|
||||
|
||||
const privkey = decryptedContent.find(([value]) => value === 'privkey')?.[1];
|
||||
if (!privkey || !isNostrId(privkey)) {
|
||||
|
|
@ -131,7 +129,7 @@ app.get('/wallet', requireNip44Signer, swapNutzapsMiddleware, async (c) => {
|
|||
for (const token of tokens) {
|
||||
try {
|
||||
const decryptedContent: { mint: string; proofs: Proof[] } = JSON.parse(
|
||||
await signer.nip44.decrypt(pubkey, token.content),
|
||||
await user.signer.nip44.decrypt(pubkey, token.content),
|
||||
);
|
||||
|
||||
if (!mints.includes(decryptedContent.mint)) {
|
||||
|
|
|
|||
|
|
@ -29,18 +29,17 @@ export class TimelineRoute {
|
|||
const homeTimelineController: AppController = async (c) => {
|
||||
const { user, pagination } = c.var;
|
||||
|
||||
const pubkey = await user.signer.getPublicKey()!;
|
||||
const pubkey = await user!.signer.getPublicKey()!;
|
||||
const result = homeQuerySchema.safeParse(c.req.query());
|
||||
|
||||
if (!result.success) {const homeTimelineController: AppController = async (c) => {
|
||||
|
||||
if (!result.success) {
|
||||
return c.json({ error: 'Bad request', schema: result.error }, 400);
|
||||
}
|
||||
|
||||
const { exclude_replies, only_media } = result.data;
|
||||
|
||||
const authors = [...await getFeedPubkeys(pubkey)];
|
||||
const filter: NostrFilter = { authors, kinds: [1, 6, 20], ...params };
|
||||
const authors = [...await getFeedPubkeys(c.var, pubkey)];
|
||||
const filter: NostrFilter = { authors, kinds: [1, 6, 20], ...pagination };
|
||||
|
||||
const search: string[] = [];
|
||||
|
||||
|
|
@ -66,8 +65,7 @@ const publicQuerySchema = z.object({
|
|||
});
|
||||
|
||||
const publicTimelineController: AppController = (c) => {
|
||||
const { conf } = c.var;
|
||||
const params = c.get('pagination');
|
||||
const { conf, pagination } = c.var;
|
||||
const result = publicQuerySchema.safeParse(c.req.query());
|
||||
|
||||
if (!result.success) {
|
||||
|
|
@ -76,7 +74,7 @@ const publicTimelineController: AppController = (c) => {
|
|||
|
||||
const { local, instance, language } = result.data;
|
||||
|
||||
const filter: NostrFilter = { kinds: [1, 20], ...params };
|
||||
const filter: NostrFilter = { kinds: [1, 20], ...pagination };
|
||||
|
||||
const search: `${string}:${string}`[] = [];
|
||||
|
||||
|
|
@ -98,9 +96,9 @@ const publicTimelineController: AppController = (c) => {
|
|||
};
|
||||
|
||||
const hashtagTimelineController: AppController = (c) => {
|
||||
const { pagination } = c.var;
|
||||
const hashtag = c.req.param('hashtag')!.toLowerCase();
|
||||
const params = c.get('pagination');
|
||||
return renderStatuses(c, [{ kinds: [1, 20], '#t': [hashtag], ...params }]);
|
||||
return renderStatuses(c, [{ kinds: [1, 20], '#t': [hashtag], ...pagination }]);
|
||||
};
|
||||
|
||||
const suggestedTimelineController: AppController = async (c) => {
|
||||
|
|
@ -119,27 +117,19 @@ const suggestedTimelineController: AppController = async (c) => {
|
|||
|
||||
/** Render statuses for timelines. */
|
||||
async function renderStatuses(c: AppContext, filters: NostrFilter[]) {
|
||||
const { conf } = c.var;
|
||||
const { signal } = c.req.raw;
|
||||
const store = c.get('store');
|
||||
const { conf, store, user, signal } = c.var;
|
||||
const opts = { signal, timeout: conf.db.timeouts.timelines };
|
||||
|
||||
const events = await store
|
||||
.query(filters, opts)
|
||||
.then((events) => hydrateEvents({ events, store, signal }));
|
||||
.then((events) => hydrateEvents(c.var, events));
|
||||
|
||||
if (!events.length) {
|
||||
return c.json([]);
|
||||
}
|
||||
|
||||
const viewerPubkey = await c.get('signer')?.getPublicKey();
|
||||
|
||||
const statuses = (await Promise.all(events.map((event) => {
|
||||
if (event.kind === 6) {
|
||||
return renderReblog(event, { viewerPubkey });
|
||||
}
|
||||
return renderStatus(event, { viewerPubkey });
|
||||
}))).filter(Boolean);
|
||||
const view = new StatusView(c.var);
|
||||
const statuses = (await Promise.all(events.map((event) => view.render(event)))).filter(Boolean);
|
||||
|
||||
if (!statuses.length) {
|
||||
return c.json([]);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue