matrix-nodejs-homeserver 0.0.0-stage → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +75 -0
- package/README.md +479 -2
- package/dist/adapters/auth.d.ts +50 -0
- package/dist/adapters/auth.js +18 -0
- package/dist/adapters/cluster.d.ts +55 -0
- package/dist/adapters/cluster.js +249 -0
- package/dist/adapters/media.d.ts +50 -0
- package/dist/adapters/media.js +63 -0
- package/dist/adapters/s3.d.ts +33 -0
- package/dist/adapters/s3.js +95 -0
- package/dist/api/account.js +594 -0
- package/dist/api/admin.js +267 -0
- package/dist/api/appservice.js +45 -0
- package/dist/api/backup.js +280 -0
- package/dist/api/federation.js +826 -0
- package/dist/api/filters.js +88 -0
- package/dist/api/index.js +47 -0
- package/dist/api/legacy.js +183 -0
- package/dist/api/media.js +271 -0
- package/dist/api/misc.js +95 -0
- package/dist/api/preview.js +201 -0
- package/dist/api/profile.js +176 -0
- package/dist/api/push.js +202 -0
- package/dist/api/relationships.js +270 -0
- package/dist/api/rooms.js +1487 -0
- package/dist/api/rtc.d.ts +23 -0
- package/dist/api/rtc.js +66 -0
- package/dist/api/search.js +161 -0
- package/dist/api/slidingsync.js +474 -0
- package/dist/api/spaces.js +177 -0
- package/dist/api/sync.js +609 -0
- package/dist/api/threadsubs.js +140 -0
- package/dist/api/threepid.js +155 -0
- package/dist/api/uia.js +127 -0
- package/dist/api/user.js +329 -0
- package/dist/core/admin.d.ts +84 -0
- package/dist/core/admin.js +308 -0
- package/dist/core/adminroom.d.ts +49 -0
- package/dist/core/adminroom.js +483 -0
- package/dist/core/appservices.d.ts +74 -0
- package/dist/core/appservices.js +369 -0
- package/dist/core/audit.d.ts +50 -0
- package/dist/core/audit.js +86 -0
- package/dist/core/auth.d.ts +48 -0
- package/dist/core/auth.js +237 -0
- package/dist/core/authrules.d.ts +4 -0
- package/dist/core/authrules.js +348 -0
- package/dist/core/cluster.d.ts +66 -0
- package/dist/core/cluster.js +191 -0
- package/dist/core/crypto.d.ts +10 -0
- package/dist/core/crypto.js +100 -0
- package/dist/core/delayed.d.ts +39 -0
- package/dist/core/delayed.js +160 -0
- package/dist/core/errors.d.ts +9 -0
- package/dist/core/errors.js +45 -0
- package/dist/core/events.d.ts +32 -0
- package/dist/core/events.js +186 -0
- package/dist/core/glob.js +66 -0
- package/dist/core/identity.d.ts +24 -0
- package/dist/core/identity.js +96 -0
- package/dist/core/ids.js +36 -0
- package/dist/core/invitefilter.js +36 -0
- package/dist/core/json.js +16 -0
- package/dist/core/keys.d.ts +36 -0
- package/dist/core/keys.js +450 -0
- package/dist/core/m.d.ts +209 -0
- package/dist/core/m.js +182 -0
- package/dist/core/notifier.d.ts +17 -0
- package/dist/core/notifier.js +54 -0
- package/dist/core/oauth.d.ts +38 -0
- package/dist/core/oauth.js +108 -0
- package/dist/core/partialstate.d.ts +32 -0
- package/dist/core/partialstate.js +198 -0
- package/dist/core/phone.js +268 -0
- package/dist/core/policy.d.ts +29 -0
- package/dist/core/policy.js +97 -0
- package/dist/core/profile.js +39 -0
- package/dist/core/push.d.ts +46 -0
- package/dist/core/push.js +307 -0
- package/dist/core/pushrules.js +229 -0
- package/dist/core/ratelimit.d.ts +23 -0
- package/dist/core/ratelimit.js +77 -0
- package/dist/core/rooms.d.ts +215 -0
- package/dist/core/rooms.js +1731 -0
- package/dist/core/settings.d.ts +11 -0
- package/dist/core/settings.js +29 -0
- package/dist/core/sso.d.ts +46 -0
- package/dist/core/sso.js +165 -0
- package/dist/core/stateres.d.ts +4 -0
- package/dist/core/stateres.js +209 -0
- package/dist/core/threepid.d.ts +80 -0
- package/dist/core/threepid.js +275 -0
- package/dist/core/typing.d.ts +16 -0
- package/dist/core/typing.js +60 -0
- package/dist/federation/client.d.ts +51 -0
- package/dist/federation/client.js +279 -0
- package/dist/federation/index.d.ts +153 -0
- package/dist/federation/index.js +1059 -0
- package/dist/federation/keyring.d.ts +26 -0
- package/dist/federation/keyring.js +122 -0
- package/dist/federation/sender.d.ts +26 -0
- package/dist/federation/sender.js +164 -0
- package/dist/homeserver.d.ts +224 -0
- package/dist/homeserver.js +302 -0
- package/dist/http/adapters.d.ts +40 -0
- package/dist/http/adapters.js +130 -0
- package/dist/http/handler.d.ts +8 -0
- package/dist/http/handler.js +181 -0
- package/dist/http/input.js +24 -0
- package/dist/http/procedure.js +25 -0
- package/dist/http/router.d.ts +43 -0
- package/dist/http/router.js +56 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +15 -0
- package/dist/storage/memory.d.ts +5 -0
- package/dist/storage/memory.js +122 -0
- package/dist/storage/schema.d.ts +4 -0
- package/dist/storage/schema.js +664 -0
- package/dist/storage/sql.d.ts +72 -0
- package/dist/storage/sql.js +274 -0
- package/dist/storage/types.d.ts +55 -0
- package/dist/vendor/zod/LICENSE +21 -0
- package/dist/vendor/zod/v4/classic/errors.js +54 -0
- package/dist/vendor/zod/v4/classic/parse.js +17 -0
- package/dist/vendor/zod/v4/classic/schemas.js +865 -0
- package/dist/vendor/zod/v4/core/api.js +512 -0
- package/dist/vendor/zod/v4/core/checks.js +300 -0
- package/dist/vendor/zod/v4/core/core.js +109 -0
- package/dist/vendor/zod/v4/core/doc.js +35 -0
- package/dist/vendor/zod/v4/core/errors.js +118 -0
- package/dist/vendor/zod/v4/core/json-schema-processors.js +428 -0
- package/dist/vendor/zod/v4/core/memoizer.js +255 -0
- package/dist/vendor/zod/v4/core/parse.js +206 -0
- package/dist/vendor/zod/v4/core/regexes.js +73 -0
- package/dist/vendor/zod/v4/core/registries.js +48 -0
- package/dist/vendor/zod/v4/core/schemas.js +1378 -0
- package/dist/vendor/zod/v4/core/to-json-schema.js +448 -0
- package/dist/vendor/zod/v4/core/util.js +537 -0
- package/dist/vendor/zod/v4/core/versions.js +8 -0
- package/dist/vendor/zod/v4/locales/en.js +110 -0
- package/package.json +65 -4
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/api/rtc.d.ts
|
|
2
|
+
export interface TurnOptions {
|
|
3
|
+
uris: string[];
|
|
4
|
+
/** coturn `static-auth-secret`: time-limited credentials are derived from it. */
|
|
5
|
+
sharedSecret?: string;
|
|
6
|
+
/** Static credentials, when not using a shared secret. */
|
|
7
|
+
username?: string;
|
|
8
|
+
password?: string;
|
|
9
|
+
/** Credential lifetime in seconds. Default: 86400. */
|
|
10
|
+
ttlSeconds?: number;
|
|
11
|
+
/** Whether guests may obtain credentials. Default: false. */
|
|
12
|
+
allowGuests?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface RtcOptions {
|
|
15
|
+
/** VoIP TURN servers. */
|
|
16
|
+
turn?: TurnOptions;
|
|
17
|
+
/**
|
|
18
|
+
* MatrixRTC transports (MSC4143), e.g. `[{ type: "livekit", livekit_service_url: "https://lk-jwt.example.com" }]`.
|
|
19
|
+
* Advertised at /rtc/transports and in /.well-known/matrix/client.
|
|
20
|
+
*/
|
|
21
|
+
transports?: Record<string, unknown>[];
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
package/dist/api/rtc.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { errors } from "../core/errors.js";
|
|
2
|
+
import { string } from "../vendor/zod/v4/classic/schemas.js";
|
|
3
|
+
import { body, fail } from "../http/input.js";
|
|
4
|
+
import { procedure } from "../http/procedure.js";
|
|
5
|
+
import { createHmac } from "node:crypto";
|
|
6
|
+
//#region src/api/rtc.ts
|
|
7
|
+
function registerRtcRoutes(r) {
|
|
8
|
+
r.client("GET", "/voip/turnServer", procedure({
|
|
9
|
+
auth: "user",
|
|
10
|
+
handler: async (ctx) => {
|
|
11
|
+
const s = ctx.session;
|
|
12
|
+
const turn = ctx.hs.config.rtc.turn;
|
|
13
|
+
if (!turn || !turn.uris.length) return {};
|
|
14
|
+
if (s.isGuest && !turn.allowGuests) throw errors.forbidden("Guests may not use TURN");
|
|
15
|
+
const ttl = turn.ttlSeconds ?? 86400;
|
|
16
|
+
if (turn.sharedSecret) {
|
|
17
|
+
const username = `${Math.floor(Date.now() / 1e3) + ttl}:${s.userId}`;
|
|
18
|
+
return {
|
|
19
|
+
username,
|
|
20
|
+
password: createHmac("sha1", turn.sharedSecret).update(username).digest("base64"),
|
|
21
|
+
uris: turn.uris,
|
|
22
|
+
ttl
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
username: turn.username ?? "",
|
|
27
|
+
password: turn.password ?? "",
|
|
28
|
+
uris: turn.uris,
|
|
29
|
+
ttl
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}));
|
|
33
|
+
const transports = async (ctx) => {
|
|
34
|
+
await ctx.auth();
|
|
35
|
+
return { rtc_transports: ctx.hs.config.rtc.transports ?? [] };
|
|
36
|
+
};
|
|
37
|
+
r.client("GET", "/rtc/transports", procedure({ handler: transports }), ["v1"]);
|
|
38
|
+
r.get("/_matrix/client/unstable/org.matrix.msc4143/rtc/transports", procedure({ handler: transports }));
|
|
39
|
+
const base = "/_matrix/client/unstable/org.matrix.msc4140/delayed_events";
|
|
40
|
+
r.get(base, procedure({
|
|
41
|
+
auth: "user",
|
|
42
|
+
handler: async (ctx) => {
|
|
43
|
+
const s = ctx.session;
|
|
44
|
+
return { delayed_events: await ctx.hs.delayedEvents.list(s.userId) };
|
|
45
|
+
}
|
|
46
|
+
}));
|
|
47
|
+
r.post(`${base}/:delayId`, procedure({
|
|
48
|
+
auth: "user",
|
|
49
|
+
input: body({ action: string(fail("M_MISSING_PARAM", "Missing action")) }),
|
|
50
|
+
handler: async (ctx) => {
|
|
51
|
+
const s = ctx.session;
|
|
52
|
+
await ctx.hs.delayedEvents.update(s.userId, ctx.params.delayId, ctx.input.action);
|
|
53
|
+
return {};
|
|
54
|
+
}
|
|
55
|
+
}));
|
|
56
|
+
r.post(`${base}/:delayId/:action`, procedure({
|
|
57
|
+
auth: "user",
|
|
58
|
+
handler: async (ctx) => {
|
|
59
|
+
const s = ctx.session;
|
|
60
|
+
await ctx.hs.delayedEvents.update(s.userId, ctx.params.delayId, ctx.params.action);
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
export { registerRtcRoutes };
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { isObject } from "../core/json.js";
|
|
2
|
+
import { M } from "../core/m.js";
|
|
3
|
+
import { getState } from "../core/authrules.js";
|
|
4
|
+
import { looseObject, string, unknown } from "../vendor/zod/v4/classic/schemas.js";
|
|
5
|
+
import { body, fail } from "../http/input.js";
|
|
6
|
+
import { procedure } from "../http/procedure.js";
|
|
7
|
+
import { matchesFilter } from "./filters.js";
|
|
8
|
+
import { paginate, topoToken } from "./rooms.js";
|
|
9
|
+
//#region src/api/search.ts
|
|
10
|
+
const DEFAULT_KEYS = [
|
|
11
|
+
"content.body",
|
|
12
|
+
"content.name",
|
|
13
|
+
"content.topic"
|
|
14
|
+
];
|
|
15
|
+
function valueAt(obj, path) {
|
|
16
|
+
return path.split(".").reduce((o, k) => isObject(o) ? o[k] : void 0, obj);
|
|
17
|
+
}
|
|
18
|
+
function registerSearchRoutes(r) {
|
|
19
|
+
const missingTerm = fail("M_BAD_JSON", "Missing search_categories.room_events.search_term");
|
|
20
|
+
const searchBody = body({ search_categories: looseObject({ room_events: looseObject({
|
|
21
|
+
search_term: string(missingTerm),
|
|
22
|
+
keys: unknown().optional(),
|
|
23
|
+
filter: unknown().optional(),
|
|
24
|
+
order_by: unknown().optional()
|
|
25
|
+
}, missingTerm) }, missingTerm) });
|
|
26
|
+
r.client("POST", "/search", procedure({
|
|
27
|
+
auth: "user",
|
|
28
|
+
input: searchBody,
|
|
29
|
+
handler: async (ctx) => {
|
|
30
|
+
const s = ctx.session;
|
|
31
|
+
const hs = ctx.hs;
|
|
32
|
+
const criteria = ctx.input.search_categories.room_events;
|
|
33
|
+
const terms = criteria.search_term.toLowerCase().split(/\s+/).filter(Boolean);
|
|
34
|
+
const keys = Array.isArray(criteria.keys) && criteria.keys.length ? criteria.keys : DEFAULT_KEYS;
|
|
35
|
+
const filter = isObject(criteria.filter) ? criteria.filter : {};
|
|
36
|
+
const limit = Math.min(filter.limit ?? 10, 100);
|
|
37
|
+
const orderBy = criteria.order_by === "recent" ? "recent" : "rank";
|
|
38
|
+
const offset = Number.parseInt(ctx.query.get("next_batch") ?? "0", 10) || 0;
|
|
39
|
+
let rooms = await hs.rooms.roomsForUser(s.userId);
|
|
40
|
+
if (filter.rooms) rooms = rooms.filter((r) => filter.rooms.includes(r));
|
|
41
|
+
if (filter.not_rooms) rooms = rooms.filter((r) => !filter.not_rooms.includes(r));
|
|
42
|
+
const hits = [];
|
|
43
|
+
for (const roomId of rooms) {
|
|
44
|
+
const rows = await hs.db.findMany("events", {
|
|
45
|
+
where: [{
|
|
46
|
+
field: "room_id",
|
|
47
|
+
value: roomId
|
|
48
|
+
}],
|
|
49
|
+
sortBy: {
|
|
50
|
+
field: "stream",
|
|
51
|
+
direction: "desc"
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
const candidates = [];
|
|
55
|
+
for (const row of rows) {
|
|
56
|
+
if (row.state_key !== null || !matchesFilter(filter, row.json)) continue;
|
|
57
|
+
let rank = 0;
|
|
58
|
+
const words = [];
|
|
59
|
+
for (const key of keys) {
|
|
60
|
+
const v = valueAt(row.json, key);
|
|
61
|
+
if (typeof v === "string") words.push(...v.toLowerCase().split(/[^\p{L}\p{N}]+/u));
|
|
62
|
+
}
|
|
63
|
+
if (terms.every((t) => words.includes(t))) for (const t of terms) rank += words.filter((w) => w === t).length;
|
|
64
|
+
if (rank > 0) candidates.push({
|
|
65
|
+
ev: hs.rooms.rowToStored(row),
|
|
66
|
+
rank
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const visible = new Set((await hs.rooms.filterVisible(s.userId, roomId, candidates.map((c) => c.ev))).map((v) => v.pdu.event_id));
|
|
70
|
+
hits.push(...candidates.filter((c) => visible.has(c.ev.pdu.event_id)));
|
|
71
|
+
}
|
|
72
|
+
hits.sort((a, b) => orderBy === "rank" && b.rank !== a.rank ? b.rank - a.rank : b.ev.stream - a.ev.stream);
|
|
73
|
+
const page = hits.slice(offset, offset + limit);
|
|
74
|
+
const viewer = {
|
|
75
|
+
userId: s.userId,
|
|
76
|
+
deviceId: s.deviceId
|
|
77
|
+
};
|
|
78
|
+
const ec = isObject(criteria.event_context) ? criteria.event_context : null;
|
|
79
|
+
const results = [];
|
|
80
|
+
for (const hit of page) {
|
|
81
|
+
const result = {
|
|
82
|
+
rank: hit.rank,
|
|
83
|
+
result: hs.rooms.formatEvent(hit.ev, viewer)
|
|
84
|
+
};
|
|
85
|
+
if (ec) {
|
|
86
|
+
const roomId = hit.ev.pdu.room_id;
|
|
87
|
+
const here = {
|
|
88
|
+
depth: hit.ev.pdu.depth,
|
|
89
|
+
stream: hit.ev.stream
|
|
90
|
+
};
|
|
91
|
+
const before = await paginate(hs, s.userId, roomId, {
|
|
92
|
+
from: here,
|
|
93
|
+
to: null,
|
|
94
|
+
dir: "b",
|
|
95
|
+
limit: ec.before_limit ?? 5
|
|
96
|
+
});
|
|
97
|
+
const after = await paginate(hs, s.userId, roomId, {
|
|
98
|
+
from: here,
|
|
99
|
+
to: null,
|
|
100
|
+
dir: "f",
|
|
101
|
+
limit: ec.after_limit ?? 5
|
|
102
|
+
});
|
|
103
|
+
const context = {
|
|
104
|
+
events_before: before.events.map((e) => hs.rooms.formatEvent(e, viewer)),
|
|
105
|
+
events_after: after.events.map((e) => hs.rooms.formatEvent(e, viewer)),
|
|
106
|
+
start: before.end ?? topoToken(before.events.at(-1) ?? hit.ev),
|
|
107
|
+
end: topoToken(after.events.at(-1) ?? hit.ev)
|
|
108
|
+
};
|
|
109
|
+
if (ec.include_profile) {
|
|
110
|
+
const state = await hs.rooms.currentState(roomId);
|
|
111
|
+
const profile_info = {};
|
|
112
|
+
for (const e of [
|
|
113
|
+
...before.events,
|
|
114
|
+
hit.ev,
|
|
115
|
+
...after.events
|
|
116
|
+
]) {
|
|
117
|
+
const m = getState(state, M.ROOM.MEMBER, e.pdu.sender)?.content;
|
|
118
|
+
profile_info[e.pdu.sender] = {
|
|
119
|
+
displayname: m?.displayname,
|
|
120
|
+
avatar_url: m?.avatar_url
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
context.profile_info = profile_info;
|
|
124
|
+
}
|
|
125
|
+
result.context = context;
|
|
126
|
+
}
|
|
127
|
+
results.push(result);
|
|
128
|
+
}
|
|
129
|
+
const out = {
|
|
130
|
+
results,
|
|
131
|
+
count: hits.length,
|
|
132
|
+
highlights: terms
|
|
133
|
+
};
|
|
134
|
+
if (page.length === limit && offset + limit <= hits.length) out.next_batch = String(offset + limit);
|
|
135
|
+
if (criteria.include_state) {
|
|
136
|
+
out.state = {};
|
|
137
|
+
for (const roomId of new Set(page.map((h) => h.ev.pdu.room_id))) out.state[roomId] = [...(await hs.rooms.currentState(roomId)).values()].map((e) => hs.rooms.formatEvent({
|
|
138
|
+
pdu: e,
|
|
139
|
+
stream: 0,
|
|
140
|
+
snapshot: 0,
|
|
141
|
+
txnId: null,
|
|
142
|
+
txnToken: null
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
145
|
+
if (criteria.groupings?.group_by?.some?.((g) => g?.key === "room_id")) {
|
|
146
|
+
const groups = {};
|
|
147
|
+
hits.forEach((h, i) => {
|
|
148
|
+
(groups[h.ev.pdu.room_id] ??= {
|
|
149
|
+
results: [],
|
|
150
|
+
order: i,
|
|
151
|
+
next_batch: null
|
|
152
|
+
}).results.push(h.ev.pdu.event_id);
|
|
153
|
+
});
|
|
154
|
+
out.groups = { room_id: groups };
|
|
155
|
+
}
|
|
156
|
+
return { search_categories: { room_events: out } };
|
|
157
|
+
}
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
//#endregion
|
|
161
|
+
export { registerSearchRoutes };
|