diff --git a/bun.lockb b/bun.lockb index 01f5381b..0949aa88 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/packages/core/src/events/edu/m.presence.ts b/packages/core/src/events/edu/m.presence.ts new file mode 100644 index 00000000..4504544f --- /dev/null +++ b/packages/core/src/events/edu/m.presence.ts @@ -0,0 +1,22 @@ +// rc1 | receive send -> { +// rc1 | txnId: "1733946113255", +// rc1 | } +// rc1 | body -> { +// rc1 | edus: [ +// rc1 | { +// rc1 | content: { +// rc1 | push: [ +// rc1 | { +// rc1 | last_active_ago: 28963, +// rc1 | presence: "unavailable", +// rc1 | user_id: "@admin:hs1", +// rc1 | } +// rc1 | ], +// rc1 | }, +// rc1 | edu_type: "m.presence", +// rc1 | } +// rc1 | ], +// rc1 | origin: "hs1", +// rc1 | origin_server_ts: 1733946148285, +// rc1 | pdus: [], +// rc1 | } diff --git a/packages/core/src/events/edu/m.receipt.ts b/packages/core/src/events/edu/m.receipt.ts new file mode 100644 index 00000000..f5f43965 --- /dev/null +++ b/packages/core/src/events/edu/m.receipt.ts @@ -0,0 +1,35 @@ +// rc1 | { +// rc1 | content: { +// rc1 | "!JOQWtMhsTYVzpvWKfT:hs1": { +// rc1 | "m.read": { +// rc1 | "@admin:hs2": { +// rc1 | data: { +// rc1 | thread_id: "$-W5aLCocUCe3XdccJ5Ireep8HjMHbc_-TcVSpIh-7_w", +// rc1 | ts: 1733949851033, +// rc1 | }, +// rc1 | event_ids: [ "$qorXw8WtCpzCJndxv22ZbNH5BZGSXYInAymU2hH01dA" ], +// rc1 | }, +// rc1 | }, +// rc1 | }, +// rc1 | }, +// rc1 | edu_type: "m.receipt", +// rc1 | } + + + +// rc1 | { +// rc1 | content: { +// rc1 | "!JOQWtMhsTYVzpvWKfT:hs1": { +// rc1 | "m.read": { +// rc1 | "@admin:hs1": { +// rc1 | data: { +// rc1 | thread_id: "main", +// rc1 | ts: 1733949751894, +// rc1 | }, +// rc1 | event_ids: [ "$RDJXNzR-kIv-Y3t4ISFAK8SZ_TRRaIi1-8N_dSeg3Jw" ], +// rc1 | }, +// rc1 | }, +// rc1 | }, +// rc1 | }, +// rc1 | edu_type: "m.receipt", +// rc1 | } diff --git a/packages/core/src/events/edu/m.typing.ts b/packages/core/src/events/edu/m.typing.ts new file mode 100644 index 00000000..a4dc3489 --- /dev/null +++ b/packages/core/src/events/edu/m.typing.ts @@ -0,0 +1,49 @@ +// ( +// destination=domain, +// edu_type=EduTypes.TYPING, +// content={ +// "room_id": member.room_id, +// "user_id": member.user_id, +// "typing": typing, +// }, +// key=member, +// ) + +// rc1 | receive send -> { +// rc1 | txnId: "1733946113259", +// rc1 | } +// rc1 | body -> { +// rc1 | edus: [ +// rc1 | { +// rc1 | content: { +// rc1 | room_id: "!JOQWtMhsTYVzpvWKfT:hs1", +// rc1 | typing: true, +// rc1 | user_id: "@admin:hs1", +// rc1 | }, +// rc1 | edu_type: "m.typing", +// rc1 | } +// rc1 | ], +// rc1 | origin: "hs1", +// rc1 | origin_server_ts: 1733946457918, +// rc1 | pdus: [], +// rc1 | } + +export type TypingEvent = { + edu_type: "m.typing"; + content: { + room_id: string; + user_id: string; + typing: boolean; + }; +}; + +export function createTypingEvent({ roomId, sender, typing }: { roomId: string; sender: string; typing: boolean; }): TypingEvent { + return { + edu_type: "m.typing", + content: { + room_id: roomId, + user_id: sender, + typing, + }, + }; +} diff --git a/packages/core/src/events/edu/types.ts b/packages/core/src/events/edu/types.ts new file mode 100644 index 00000000..942269ae --- /dev/null +++ b/packages/core/src/events/edu/types.ts @@ -0,0 +1,8 @@ +export type eduTypes = + 'm.presence' | + 'm.typing' | + 'm.receipt' | + 'm.device_list_update' | + 'm.signing_key_update' | + 'org.matrix.signing_key_update' | + 'm.direct_to_device'; diff --git a/packages/fake/src/room.ts b/packages/fake/src/room.ts index 3281d650..ac623587 100644 --- a/packages/fake/src/room.ts +++ b/packages/fake/src/room.ts @@ -14,6 +14,8 @@ import { roomMemberEvent } from "@hs/core/src/events/m.room.member"; import { makeUnsignedRequest } from "@hs/homeserver/src/makeRequest"; import type { EventBase } from "@hs/core/src/events/eventBase"; +import { typingEndpoint } from "./room/typing"; + function createMediaId(length: number) { const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; let result = ""; @@ -25,6 +27,7 @@ function createMediaId(length: number) { } export const fakeEndpoints = new Elysia({ prefix: "/fake" }) + .use(typingEndpoint) .post( "/createRoom", async ({ body, error, ...context }) => { diff --git a/packages/fake/src/room/typing.ts b/packages/fake/src/room/typing.ts new file mode 100644 index 00000000..c3061298 --- /dev/null +++ b/packages/fake/src/room/typing.ts @@ -0,0 +1,80 @@ +import { makeUnsignedRequest } from "@hs/homeserver/src/makeRequest"; +import { isConfigContext } from "@hs/homeserver/src/plugins/isConfigContext"; +import { Elysia, t } from "elysia"; + +import { createTypingEvent } from "@hs/core/src/events/edu/m.typing"; + +export const typingEndpoint = new Elysia().post( + "/typing", + async ({ body, error, ...context }) => { + if (!isConfigContext(context)) { + throw new Error("No config context"); + } + const { config } = context; + + console.log("body.typing ->", body.typing); + + const payload = { + origin: config.name, + origin_server_ts: Date.now(), + edus: [ + createTypingEvent({ + roomId: body.roomId, + sender: body.sender, + typing: body.typing, + }), + ], + pdus: [], + }; + console.log("payload ->", payload); + + const responses = await Promise.all( + body.targets.map((target) => + makeUnsignedRequest({ + method: "PUT", + domain: target, + uri: `/_matrix/federation/v1/send/${Date.now()}`, + options: { body: payload }, + signingKey: config.signingKey[0], + signingName: config.name, + } as any), + ), + ); + + // const responseMake = await makeUnsignedRequest({ + // method: "PUT", + // domain: body.target, + // uri: `/_matrix/federation/v1/send/${Date.now()}`, + // body: payload, + // signingKey: config.signingKey[0], + // signingName: config.name, + // } as any); + + console.log("responses ->", responses); + + return { responses }; + }, + { + body: t.Object( + { + sender: t.String(), + roomId: t.String(), + typing: t.Boolean({ default: true }), + targets: t.Array(t.String()), + }, + { + examples: [ + { + sender: "@a1:rc1", + roomId: "!uTqsSSWabZzthsSCNf:hs1", + targets: ["hs1", "hs2"], + }, + ], + }, + ), + detail: { + description: + "Send a message to a room. The sender must be the user ID. The target must be the server name.", + }, + }, +);