atagen

malice

public
Star0
Watch0

Commit f7069be9f61e

tarball

atagen <boss@atagen.co>2026-10-24 13:11 UTC

9 files changed+5-283
build: remove unsupported event context requests
Modified file: crates/malice-core/src/request.rs−61 deletions
@@ -77,32 +77,6 @@ pub enum Request {
7777 #[serde(default)]
7878 room_id: String,
7979 },
80- EventContext {
81- #[serde(default)]
82- room_id: String,
83- #[serde(default)]
84- event_id: String,
85- #[serde(default)]
86- before_limit: u32,
87- #[serde(default)]
88- after_limit: u32,
89- },
90- EventContextBefore {
91- #[serde(default)]
92- room_id: String,
93- #[serde(default)]
94- token: String,
95- #[serde(default)]
96- limit: u32,
97- },
98- EventContextAfter {
99- #[serde(default)]
100- room_id: String,
101- #[serde(default)]
102- token: String,
103- #[serde(default)]
104- limit: u32,
105- },
10680 Join {
10781 #[serde(default)]
10882 room: String,
@@ -507,41 +481,6 @@ pub async fn dispatch(
507481 handle.paginate(TimelineId::Room(room_id), 30).await?;
508482 Ok(Reply::Done)
509483 }
510- Request::EventContext {
511- room_id,
512- event_id,
513- before_limit,
514- after_limit,
515- } => {
516- let room_id = parse_room_id(&room_id)?;
517- let event_id = parse_event_id(&event_id)?;
518- let context = handle
519- .event_context(&room_id, &event_id, before_limit, after_limit)
520- .await?;
521- Ok(Reply::Json(json!(context)))
522- }
523- Request::EventContextBefore {
524- room_id,
525- token,
526- limit,
527- } => {
528- let room_id = parse_room_id(&room_id)?;
529- let page = handle
530- .event_context_before(&room_id, &token, limit)
531- .await?;
532- Ok(Reply::Json(json!(page)))
533- }
534- Request::EventContextAfter {
535- room_id,
536- token,
537- limit,
538- } => {
539- let room_id = parse_room_id(&room_id)?;
540- let page = handle
541- .event_context_after(&room_id, &token, limit)
542- .await?;
543- Ok(Reply::Json(json!(page)))
544- }
545484 Request::Join { room } => {
546485 let room = parse_room_or_alias(&room)?;
547486 let room_id = handle.join_room(room, Vec::new()).await?;
Modified file: crates/malice-server/src/routes.rs−95 deletions
@@ -56,28 +56,6 @@ struct PaginateBody {
5656 }
5757
5858 #[derive(Debug, Deserialize)]
59-struct EventContextBody {
60- #[serde(default)]
61- room_id: String,
62- #[serde(default)]
63- event_id: String,
64- #[serde(default)]
65- before_limit: u32,
66- #[serde(default)]
67- after_limit: u32,
68-}
69-
70-#[derive(Debug, Deserialize)]
71-struct EventContextPageBody {
72- #[serde(default)]
73- room_id: String,
74- #[serde(default)]
75- token: String,
76- #[serde(default)]
77- limit: u32,
78-}
79-
80-#[derive(Debug, Deserialize)]
8159 struct JoinBody {
8260 #[serde(default)]
8361 room: String,
@@ -682,76 +660,6 @@ async fn rooms_paginate(
682660 )
683661 }
684662
685-async fn rooms_context(
686- State(state): State<AppState>,
687- headers: HeaderMap,
688- body: axum::Json<EventContextBody>,
689-) -> Response {
690- let (user, _) = match auth(&state, &headers).await {
691- Ok(pair) => pair,
692- Err(error) => return error.into_response(),
693- };
694- respond(
695- dispatch(
696- &user.handle,
697- &user.mirror,
698- Request::EventContext {
699- room_id: body.0.room_id,
700- event_id: body.0.event_id,
701- before_limit: body.0.before_limit,
702- after_limit: body.0.after_limit,
703- },
704- )
705- .await,
706- )
707-}
708-
709-async fn rooms_context_before(
710- State(state): State<AppState>,
711- headers: HeaderMap,
712- body: axum::Json<EventContextPageBody>,
713-) -> Response {
714- let (user, _) = match auth(&state, &headers).await {
715- Ok(pair) => pair,
716- Err(error) => return error.into_response(),
717- };
718- respond(
719- dispatch(
720- &user.handle,
721- &user.mirror,
722- Request::EventContextBefore {
723- room_id: body.0.room_id,
724- token: body.0.token,
725- limit: body.0.limit,
726- },
727- )
728- .await,
729- )
730-}
731-
732-async fn rooms_context_after(
733- State(state): State<AppState>,
734- headers: HeaderMap,
735- body: axum::Json<EventContextPageBody>,
736-) -> Response {
737- let (user, _) = match auth(&state, &headers).await {
738- Ok(pair) => pair,
739- Err(error) => return error.into_response(),
740- };
741- respond(
742- dispatch(
743- &user.handle,
744- &user.mirror,
745- Request::EventContextAfter {
746- room_id: body.0.room_id,
747- token: body.0.token,
748- limit: body.0.limit,
749- },
750- )
751- .await,
752- )
753-}
754-
755663 async fn rooms_join(
756664 State(state): State<AppState>,
757665 headers: HeaderMap,
@@ -1138,9 +1046,6 @@ pub fn router(state: AppState, web_dir: Option<String>) -> Router {
11381046 .route("/rooms/close", post(rooms_close))
11391047 .route("/rooms/send", post(rooms_send))
11401048 .route("/rooms/paginate", post(rooms_paginate))
1141- .route("/rooms/context", post(rooms_context))
1142- .route("/rooms/context/before", post(rooms_context_before))
1143- .route("/rooms/context/after", post(rooms_context_after))
11441049 .route(
11451050 "/rooms/upload",
11461051 post(rooms_upload).layer(DefaultBodyLimit::max(21 * 1024 * 1024)),
Modified file: web/src/app.css+1 additions
@@ -894,6 +894,7 @@ input, textarea { font: inherit; }
894894 }
895895 .app > .rail, .app > .sidebar { visibility: visible !important; }
896896 .account .me-names, .account-actions { display: none; }
897+ .account { padding-top: 10px; padding-bottom: 12px; }
897898 .pane-resize { display: none; }
898899 .app > .sidebar { transition: transform var(--pane-ease); }
899900 .app > .sidebar > *, .app > .members > * { min-width: 0; }
Modified file: web/src/lib/api.ts+1 additions−7 deletions
@@ -1,6 +1,6 @@
11 // Backend-agnostic API surface. Every call forwards to whichever transport
22 // this build was compiled for, hosted (fetch + SSE) or on-device (worker).
3-import type { EventContext, EventContextPage, MemberSummary, RoomSummary } from './types';
3+import type { MemberSummary, RoomSummary } from './types';
44 import type { Emote } from './emotes';
55 import { formatBody } from './markdown';
66 import { mentionedUserIds, type Mention } from './mentions';
@@ -50,12 +50,6 @@ export const uploadAvatar = (file: File) => transport.uploadAvatar(file);
5050 export const uploadRoomAvatar = (room_id: string, file: File) => transport.uploadRoomAvatar(room_id, file);
5151 export const uploadMedia = (file: File) => transport.uploadMedia(file);
5252 export const paginateRoom = (room_id: string) => transport.paginateRoom(room_id);
53-export const eventContext = (room_id: string, event_id: string, limit?: number): Promise<EventContext> =>
54- transport.eventContext(room_id, event_id, limit);
55-export const eventContextBefore = (room_id: string, event_id: string, from: string, limit?: number): Promise<EventContextPage> =>
56- transport.eventContextBefore(room_id, event_id, from, limit);
57-export const eventContextAfter = (room_id: string, event_id: string, from: string, limit?: number): Promise<EventContextPage> =>
58- transport.eventContextAfter(room_id, event_id, from, limit);
5953 export const setTyping = (room_id: string, typing: boolean) => transport.setTyping(room_id, typing);
6054 export const getAccountData = (eventType: string) => transport.getAccountData(eventType);
6155 export const getUrlPreview = (room_id: string, url: string) => transport.getUrlPreview(room_id, url);
Modified file: web/src/lib/store.ts−24 deletions
@@ -14,7 +14,6 @@ import {
1414 } from './types';
1515 import type {
1616 EncryptionState,
17- EventContext,
1817 ImagePacks,
1918 MemberSummary,
2019 RoomSummary,
@@ -29,12 +28,6 @@ export const blocked = writable<boolean>(false);
2928 export const rooms = writable<RoomSummary[]>([]);
3029 export const timelines = writable<Record<string, TimelineItem[]>>({});
3130 export const pinnedTimelines = writable<Record<string, TimelineItem[]>>({});
32-export interface EventContextState {
33- room_id: string;
34- request_id: string;
35- context: EventContext;
36-}
37-export const eventContexts = writable<Record<string, EventContextState>>({});
3831 export const connection = writable<string>('connecting');
3932 export const selectedRoomId = writable<string | null>(null);
4033 export const membersByRoom = writable<Record<string, MemberSummary[]>>({});
@@ -64,7 +57,6 @@ export function resetClientState(): void {
6457 rooms.set([]);
6558 timelines.set({});
6659 pinnedTimelines.set({});
67- eventContexts.set({});
6860 connection.set('connecting');
6961 selectedRoomId.set(null);
7062 membersByRoom.set({});
@@ -77,22 +69,6 @@ export function resetClientState(): void {
7769 resetLinkPreviews();
7870 }
7971
80-export function setEventContext(state: EventContextState): void {
81- const key = `${state.room_id}:${state.request_id}`;
82- eventContexts.update((all) => ({ ...all, [key]: state }));
83-}
84-
85-export function clearEventContext(roomId: string, requestId?: string): void {
86- eventContexts.update((all) => {
87- const prefix = `${roomId}:`;
88- const next = { ...all };
89- for (const key of Object.keys(next)) {
90- if (key.startsWith(prefix) && (requestId === undefined || key === `${prefix}${requestId}`)) delete next[key];
91- }
92- return next;
93- });
94-}
95-
9672 function applyTimelinePayload(roomId: string, payload: Record<string, unknown>): void {
9773 if (!Array.isArray(payload['items'])) return;
9874 const items = parseTimelineList(payload['items']);
Modified file: web/src/lib/transport-http.ts+1 additions−30 deletions
@@ -1,5 +1,4 @@
1-import type { EventContext, EventContextPage, MemberSummary, RoomSummary } from './types';
2-import { parseEventContext, parseEventContextPage } from './types';
1+import type { MemberSummary, RoomSummary } from './types';
32 import { ApiError, type CommandRequest, type SendKind, type SessionInfo, type Transport, type UploadExtras, type VerifyAction } from './transport';
43
54 async function parseFailure(res: Response, fallback: string): Promise<never> {
@@ -104,34 +103,6 @@ export class HttpTransport implements Transport {
104103 paginateRoom(room_id: string): Promise<void> {
105104 return this.roomCommand(ROOM_COMMAND_PATHS.paginate, { room_id });
106105 }
107- async eventContext(room_id: string, event_id: string, limit = 20): Promise<EventContext> {
108- const res = await fetch('/api/rooms/context', {
109- method: 'POST',
110- credentials: 'same-origin',
111- headers: { 'content-type': 'application/json' },
112- body: JSON.stringify({ room_id, event_id, limit })
113- });
114- const parsed = parseEventContext(await json<unknown>(res, 'Could not load event context'));
115- if (!parsed) throw new ApiError(502, 'Invalid event context response');
116- return parsed;
117- }
118- async eventContextBefore(room_id: string, event_id: string, from: string, limit = 20): Promise<EventContextPage> {
119- return this.eventContextPage('before', room_id, event_id, from, limit);
120- }
121- async eventContextAfter(room_id: string, event_id: string, from: string, limit = 20): Promise<EventContextPage> {
122- return this.eventContextPage('after', room_id, event_id, from, limit);
123- }
124- private async eventContextPage(direction: 'before' | 'after', room_id: string, event_id: string, from: string, limit: number): Promise<EventContextPage> {
125- const res = await fetch(`/api/rooms/context/${direction}`, {
126- method: 'POST',
127- credentials: 'same-origin',
128- headers: { 'content-type': 'application/json' },
129- body: JSON.stringify({ room_id, event_id, from, limit })
130- });
131- const parsed = parseEventContextPage(await json<unknown>(res, 'Could not load event context'));
132- if (!parsed) throw new ApiError(502, 'Invalid event context page response');
133- return parsed;
134- }
135106 setTyping(room_id: string, typing: boolean): Promise<void> {
136107 return this.roomCommand(ROOM_COMMAND_PATHS.typing, { room_id, typing });
137108 }
Modified file: web/src/lib/transport-worker.ts+1 additions−21 deletions
@@ -1,5 +1,4 @@
1-import { parseEventContext, parseEventContextPage } from './types';
2-import type { EventContext, EventContextPage, MemberSummary, RoomSummary } from './types';
1+import type { MemberSummary, RoomSummary } from './types';
32 import { ApiError, type CommandRequest, type SendKind, type SessionInfo, type SoftLogout, type Transport, type UploadExtras, type VerifyAction } from './transport';
43 import { statusForKind } from './wire-status';
54
@@ -230,25 +229,6 @@ export class WorkerTransport implements Transport {
230229 paginateRoom(room_id: string): Promise<void> {
231230 return this.client.call('paginate', { room_id });
232231 }
233- eventContext(room_id: string, event_id: string, limit = 20): Promise<EventContext> {
234- return this.contextCall('event_context', { room_id, event_id, limit });
235- }
236- eventContextBefore(room_id: string, event_id: string, from: string, limit = 20): Promise<EventContextPage> {
237- return this.contextPageCall('event_context_before', { room_id, event_id, from, limit });
238- }
239- eventContextAfter(room_id: string, event_id: string, from: string, limit = 20): Promise<EventContextPage> {
240- return this.contextPageCall('event_context_after', { room_id, event_id, from, limit });
241- }
242- private async contextCall(op: string, fields: Record<string, unknown>): Promise<EventContext> {
243- const parsed = parseEventContext(await this.client.call(op, fields));
244- if (!parsed) throw new ApiError(502, 'Invalid event context response');
245- return parsed;
246- }
247- private async contextPageCall(op: string, fields: Record<string, unknown>): Promise<EventContextPage> {
248- const parsed = parseEventContextPage(await this.client.call(op, fields));
249- if (!parsed) throw new ApiError(502, 'Invalid event context page response');
250- return parsed;
251- }
252232 setTyping(room_id: string, typing: boolean): Promise<void> {
253233 return this.client.call('typing', { room_id, typing });
254234 }
Modified file: web/src/lib/transport.ts+1 additions−4 deletions
@@ -1,4 +1,4 @@
1-import type { EventContext, EventContextPage, MemberSummary, PackUsage, RoomSummary } from './types';
1+import type { MemberSummary, PackUsage, RoomSummary } from './types';
22
33 export class ApiError extends Error {
44 status: number;
@@ -98,9 +98,6 @@ export interface Transport {
9898 kind?: SendKind
9999 ): Promise<void>;
100100 paginateRoom(room_id: string): Promise<void>;
101- eventContext(room_id: string, event_id: string, limit?: number): Promise<EventContext>;
102- eventContextBefore(room_id: string, event_id: string, from: string, limit?: number): Promise<EventContextPage>;
103- eventContextAfter(room_id: string, event_id: string, from: string, limit?: number): Promise<EventContextPage>;
104101 setTyping(room_id: string, typing: boolean): Promise<void>;
105102 getAccountData(eventType: string): Promise<unknown | null>;
106103 getUrlPreview(room_id: string, url: string): Promise<unknown | null>;
Modified file: web/src/lib/types.ts−41 deletions
@@ -654,23 +654,6 @@ export type TimelineItem =
654654 | { kind: 'start' }
655655 | { kind: 'unknown'; label: string };
656656
657-export interface EventContext {
658- events_before: TimelineItem[];
659- event: TimelineItem | null;
660- events_after: TimelineItem[];
661- start_token: string | null;
662- end_token: string | null;
663-}
664-
665-export type EventContextDirection = 'Before' | 'After';
666-
667-export interface EventContextPage {
668- direction: EventContextDirection;
669- events: TimelineItem[];
670- next_token: string | null;
671- end_reached: boolean;
672-}
673-
674657 /** Normalize one TimelineItem from external-tag serde form. */
675658 export function parseTimelineItem(raw: unknown): TimelineItem | null {
676659 if (raw === 'ReadMarker') return { kind: 'readMarker' };
@@ -697,30 +680,6 @@ export function parseTimelineList(raw: unknown): TimelineItem[] {
697680 return out;
698681 }
699682
700-export function parseEventContext(raw: unknown): EventContext | null {
701- if (!isRecord(raw)) return null;
702- const eventRaw = raw['event'];
703- return {
704- events_before: parseTimelineList(raw['events_before']),
705- event: eventRaw == null ? null : parseTimelineItem(eventRaw),
706- events_after: parseTimelineList(raw['events_after']),
707- start_token: optionalString(raw, 'start_token'),
708- end_token: optionalString(raw, 'end_token')
709- };
710-}
711-
712-export function parseEventContextPage(raw: unknown): EventContextPage | null {
713- if (!isRecord(raw)) return null;
714- const direction = raw['direction'];
715- if (direction !== 'Before' && direction !== 'After') return null;
716- return {
717- direction,
718- events: parseTimelineList(raw['events']),
719- next_token: optionalString(raw, 'next_token'),
720- end_reached: raw['end_reached'] === true
721- };
722-}
723-
724683 export type PackUsage = 'Emoticon' | 'Sticker';
725684 export interface PackImage {
726685 shortcode: string;