matrix-nodejs-homeserver 0.2.0 → 0.3.2
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/README.md +89 -11
- package/dist/adapters/cluster.d.ts +1 -26
- package/dist/adapters/cluster.js +50 -103
- package/dist/api/account.js +407 -354
- package/dist/api/admin.js +82 -61
- package/dist/api/appservice.js +37 -25
- package/dist/api/backup.js +73 -62
- package/dist/api/federation.js +172 -138
- package/dist/api/filters.js +4 -3
- package/dist/api/legacy.js +91 -78
- package/dist/api/media.js +71 -55
- package/dist/api/misc.js +46 -37
- package/dist/api/preview.js +37 -73
- package/dist/api/profile.js +108 -97
- package/dist/api/push.js +114 -99
- package/dist/api/relationships.js +64 -58
- package/dist/api/rooms.js +703 -580
- package/dist/api/rtc.d.ts +0 -1
- package/dist/api/rtc.js +48 -34
- package/dist/api/search.js +133 -127
- package/dist/api/slidingsync.js +41 -31
- package/dist/api/spaces.js +82 -77
- package/dist/api/sync.js +325 -135
- package/dist/api/threadsubs.js +72 -61
- package/dist/api/threepid.js +99 -66
- package/dist/api/uia.js +17 -16
- package/dist/api/user.js +221 -178
- package/dist/core/admin.d.ts +0 -1
- package/dist/core/admin.js +6 -5
- package/dist/core/adminroom.js +9 -8
- package/dist/core/appservices.d.ts +2 -1
- package/dist/core/appservices.js +5 -4
- package/dist/core/audit.d.ts +0 -1
- package/dist/core/authrules.js +26 -25
- package/dist/core/cluster.d.ts +12 -5
- package/dist/core/cluster.js +46 -29
- package/dist/core/delayed.js +2 -1
- package/dist/core/events.js +11 -10
- package/dist/core/html.js +13 -0
- package/dist/core/identity.js +1 -1
- package/dist/core/invitefilter.js +2 -1
- package/dist/core/json.js +10 -1
- package/dist/core/keys.d.ts +10 -1
- package/dist/core/keys.js +62 -42
- package/dist/core/m.d.ts +209 -0
- package/dist/core/m.js +182 -0
- package/dist/core/outbound.d.ts +16 -0
- package/dist/core/outbound.js +172 -0
- package/dist/core/partialstate.js +2 -1
- package/dist/core/policy.js +4 -3
- package/dist/core/push.d.ts +0 -1
- package/dist/core/push.js +41 -28
- package/dist/core/pushrules.js +36 -35
- package/dist/core/ratelimit.d.ts +1 -1
- package/dist/core/rooms.d.ts +10 -1
- package/dist/core/rooms.js +101 -74
- package/dist/core/semaphore.js +23 -0
- package/dist/core/sso.d.ts +15 -1
- package/dist/core/sso.js +38 -2
- package/dist/core/stateres.js +7 -6
- package/dist/core/threepid.js +1 -9
- package/dist/federation/client.js +9 -1
- package/dist/federation/index.d.ts +2 -2
- package/dist/federation/index.js +43 -35
- package/dist/homeserver.d.ts +23 -4
- package/dist/homeserver.js +12 -3
- package/dist/http/handler.js +2 -23
- package/dist/http/input.js +2 -2
- package/dist/http/procedure.js +25 -0
- package/dist/http/router.d.ts +9 -26
- package/dist/http/router.js +10 -30
- package/dist/index.d.ts +4 -3
- package/dist/index.js +3 -2
- package/dist/storage/batch.js +11 -0
- package/dist/storage/memory.js +1 -0
- package/dist/storage/schema.js +1 -1
- package/dist/storage/sql.js +20 -1
- package/dist/storage/types.d.ts +16 -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 +8 -6
- package/dist/core/pushrules.d.ts +0 -1
package/dist/api/spaces.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { M } from "../core/m.js";
|
|
1
2
|
import { splitStateKey, stripState } from "../core/events.js";
|
|
2
3
|
import { errors } from "../core/errors.js";
|
|
3
4
|
import { getState, membershipOf } from "../core/authrules.js";
|
|
5
|
+
import { procedure } from "../http/procedure.js";
|
|
4
6
|
//#region src/api/spaces.ts
|
|
5
7
|
/** Room-level details shared by /hierarchy, /room_summary and /publicRooms. */
|
|
6
8
|
async function roomDetails(hs, roomId) {
|
|
@@ -9,16 +11,16 @@ async function roomDetails(hs, roomId) {
|
|
|
9
11
|
const out = {
|
|
10
12
|
room_id: roomId,
|
|
11
13
|
num_joined_members: (await hs.rooms.joinedMembers(roomId)).length,
|
|
12
|
-
world_readable: get(
|
|
13
|
-
guest_can_join: get(
|
|
14
|
-
join_rule: get(
|
|
14
|
+
world_readable: get(M.ROOM.HISTORY_VISIBILITY)?.history_visibility === "world_readable",
|
|
15
|
+
guest_can_join: get(M.ROOM.GUEST_ACCESS)?.guest_access === "can_join",
|
|
16
|
+
join_rule: get(M.ROOM.JOIN_RULES)?.join_rule ?? "invite"
|
|
15
17
|
};
|
|
16
18
|
const str = (v) => typeof v === "string" ? v : void 0;
|
|
17
|
-
if (str(get(
|
|
18
|
-
if (str(get(
|
|
19
|
-
if (str(get(
|
|
20
|
-
if (str(get(
|
|
21
|
-
if (str(get(
|
|
19
|
+
if (str(get(M.ROOM.NAME)?.name)) out.name = get(M.ROOM.NAME).name;
|
|
20
|
+
if (str(get(M.ROOM.TOPIC)?.topic)) out.topic = get(M.ROOM.TOPIC).topic;
|
|
21
|
+
if (str(get(M.ROOM.CANONICAL_ALIAS)?.alias)) out.canonical_alias = get(M.ROOM.CANONICAL_ALIAS).alias;
|
|
22
|
+
if (str(get(M.ROOM.AVATAR)?.url)) out.avatar_url = get(M.ROOM.AVATAR).url;
|
|
23
|
+
if (str(get(M.ROOM.CREATE)?.type)) out.room_type = get(M.ROOM.CREATE).type;
|
|
22
24
|
return out;
|
|
23
25
|
}
|
|
24
26
|
/** Whether a user may see a room's summary (spec: "accessible" rooms). */
|
|
@@ -29,13 +31,13 @@ async function canAccess(hs, roomId, userId) {
|
|
|
29
31
|
"invite",
|
|
30
32
|
"knock"
|
|
31
33
|
].includes(membershipOf(state, userId))) return true;
|
|
32
|
-
if (getState(state,
|
|
33
|
-
const joinRules = getState(state,
|
|
34
|
+
if (getState(state, M.ROOM.HISTORY_VISIBILITY)?.content?.history_visibility === "world_readable") return true;
|
|
35
|
+
const joinRules = getState(state, M.ROOM.JOIN_RULES)?.content;
|
|
34
36
|
const rule = joinRules?.join_rule ?? "invite";
|
|
35
37
|
if (rule === "public" || rule === "knock") return true;
|
|
36
38
|
if ((rule === "restricted" || rule === "knock_restricted") && userId) {
|
|
37
39
|
if (rule === "knock_restricted") return true;
|
|
38
|
-
for (const allow of Array.isArray(joinRules?.allow) ? joinRules.allow : []) if (allow?.type ===
|
|
40
|
+
for (const allow of Array.isArray(joinRules?.allow) ? joinRules.allow : []) if (allow?.type === M.ROOM_MEMBERSHIP && typeof allow.room_id === "string" && await hs.rooms.exists(allow.room_id)) {
|
|
39
41
|
if (await hs.rooms.membership(allow.room_id, userId) === "join") return true;
|
|
40
42
|
}
|
|
41
43
|
}
|
|
@@ -43,7 +45,7 @@ async function canAccess(hs, roomId, userId) {
|
|
|
43
45
|
}
|
|
44
46
|
function allowedRoomIds(joinRules) {
|
|
45
47
|
if (!joinRules || !["restricted", "knock_restricted"].includes(joinRules.join_rule)) return void 0;
|
|
46
|
-
return (Array.isArray(joinRules.allow) ? joinRules.allow : []).filter((a) => a?.type ===
|
|
48
|
+
return (Array.isArray(joinRules.allow) ? joinRules.allow : []).filter((a) => a?.type === M.ROOM_MEMBERSHIP && typeof a.room_id === "string").map((a) => a.room_id);
|
|
47
49
|
}
|
|
48
50
|
/** Spec ordering of space children: valid `order` strings first, then child event timestamp, then room ID. */
|
|
49
51
|
function childOrder(a, b) {
|
|
@@ -78,73 +80,76 @@ async function remoteSummary(hs, roomId, via, suggestedOnly, userId) {
|
|
|
78
80
|
return null;
|
|
79
81
|
}
|
|
80
82
|
function registerSpaceRoutes(r) {
|
|
81
|
-
r.client("GET", "/rooms/:roomId/hierarchy",
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (!
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
83
|
+
r.client("GET", "/rooms/:roomId/hierarchy", procedure({
|
|
84
|
+
auth: "user",
|
|
85
|
+
handler: async (ctx) => {
|
|
86
|
+
const s = ctx.session;
|
|
87
|
+
const hs = ctx.hs;
|
|
88
|
+
const rootId = ctx.params.roomId;
|
|
89
|
+
if (!await hs.rooms.exists(rootId) || !await canAccess(hs, rootId, s.userId)) throw errors.forbidden("You cannot view this room");
|
|
90
|
+
const suggestedOnly = ctx.query.get("suggested_only") === "true";
|
|
91
|
+
const maxDepth = ctx.query.has("max_depth") ? Number.parseInt(ctx.query.get("max_depth"), 10) : Infinity;
|
|
92
|
+
const limit = Math.min(Math.max(Number.parseInt(ctx.query.get("limit") ?? "50", 10) || 50, 1), 100);
|
|
93
|
+
const from = ctx.query.get("from");
|
|
94
|
+
let offset = 0;
|
|
95
|
+
if (from) {
|
|
96
|
+
const m = /^(\d+)_(.+)$/.exec(from);
|
|
97
|
+
if (!m || m[2] !== `${rootId}|${suggestedOnly}|${ctx.query.get("max_depth") ?? ""}`) throw errors.invalidParam("Invalid pagination token");
|
|
98
|
+
offset = Number(m[1]);
|
|
99
|
+
}
|
|
100
|
+
const rooms = [];
|
|
101
|
+
const seen = /* @__PURE__ */ new Set();
|
|
102
|
+
const queue = [{
|
|
103
|
+
roomId: rootId,
|
|
104
|
+
depth: 0,
|
|
105
|
+
via: []
|
|
106
|
+
}];
|
|
107
|
+
while (queue.length) {
|
|
108
|
+
const { roomId, depth, via } = queue.pop();
|
|
109
|
+
if (seen.has(roomId)) continue;
|
|
110
|
+
seen.add(roomId);
|
|
111
|
+
if (!await hs.rooms.serverIsJoined(roomId)) {
|
|
112
|
+
const remote = await remoteSummary(hs, roomId, via, suggestedOnly, s.userId);
|
|
113
|
+
if (!remote) continue;
|
|
114
|
+
rooms.push(remote);
|
|
115
|
+
const remoteChildren = (remote.room_type === M.SPACE._ ? remote.children_state ?? [] : []).filter((c) => Array.isArray(c.content?.via) && c.content.via.length).sort(childOrder);
|
|
116
|
+
if (depth < maxDepth) for (const child of [...remoteChildren].reverse()) queue.push({
|
|
117
|
+
roomId: child.state_key,
|
|
118
|
+
depth: depth + 1,
|
|
119
|
+
via: child.content.via
|
|
120
|
+
});
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (roomId !== rootId && !await canAccess(hs, roomId, s.userId)) continue;
|
|
124
|
+
const state = await hs.rooms.currentState(roomId);
|
|
125
|
+
const children = [];
|
|
126
|
+
const isSpace = getState(state, M.ROOM.CREATE)?.content?.type === M.SPACE._;
|
|
127
|
+
for (const [key, ev] of isSpace ? state : []) {
|
|
128
|
+
const [type] = splitStateKey(key);
|
|
129
|
+
if (type !== M.SPACE.CHILD || !Array.isArray(ev.content?.via) || ev.content.via.length === 0) continue;
|
|
130
|
+
if (suggestedOnly && ev.content.suggested !== true) continue;
|
|
131
|
+
children.push({
|
|
132
|
+
...stripState(ev),
|
|
133
|
+
origin_server_ts: ev.origin_server_ts
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
children.sort(childOrder);
|
|
137
|
+
if (depth < maxDepth) for (const child of [...children].reverse()) queue.push({
|
|
113
138
|
roomId: child.state_key,
|
|
114
139
|
depth: depth + 1,
|
|
115
140
|
via: child.content.via
|
|
116
141
|
});
|
|
117
|
-
|
|
142
|
+
const details = await roomDetails(hs, roomId);
|
|
143
|
+
const allowed = allowedRoomIds(getState(state, M.ROOM.JOIN_RULES)?.content);
|
|
144
|
+
if (allowed) details.allowed_room_ids = allowed;
|
|
145
|
+
details.children_state = children;
|
|
146
|
+
rooms.push(details);
|
|
118
147
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const isSpace = getState(state, "m.room.create")?.content?.type === "m.space";
|
|
123
|
-
for (const [key, ev] of isSpace ? state : []) {
|
|
124
|
-
const [type] = splitStateKey(key);
|
|
125
|
-
if (type !== "m.space.child" || !Array.isArray(ev.content?.via) || ev.content.via.length === 0) continue;
|
|
126
|
-
if (suggestedOnly && ev.content.suggested !== true) continue;
|
|
127
|
-
children.push({
|
|
128
|
-
...stripState(ev),
|
|
129
|
-
origin_server_ts: ev.origin_server_ts
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
children.sort(childOrder);
|
|
133
|
-
if (depth < maxDepth) for (const child of [...children].reverse()) queue.push({
|
|
134
|
-
roomId: child.state_key,
|
|
135
|
-
depth: depth + 1,
|
|
136
|
-
via: child.content.via
|
|
137
|
-
});
|
|
138
|
-
const details = await roomDetails(hs, roomId);
|
|
139
|
-
const allowed = allowedRoomIds(getState(state, "m.room.join_rules")?.content);
|
|
140
|
-
if (allowed) details.allowed_room_ids = allowed;
|
|
141
|
-
details.children_state = children;
|
|
142
|
-
rooms.push(details);
|
|
148
|
+
const out = { rooms: rooms.slice(offset, offset + limit) };
|
|
149
|
+
if (offset + limit < rooms.length) out.next_batch = `${offset + limit}_${rootId}|${suggestedOnly}|${ctx.query.get("max_depth") ?? ""}`;
|
|
150
|
+
return out;
|
|
143
151
|
}
|
|
144
|
-
|
|
145
|
-
if (offset + limit < rooms.length) out.next_batch = `${offset + limit}_${rootId}|${suggestedOnly}|${ctx.query.get("max_depth") ?? ""}`;
|
|
146
|
-
return out;
|
|
147
|
-
}, ["v1"]);
|
|
152
|
+
}), ["v1"]);
|
|
148
153
|
const summary = async (ctx) => {
|
|
149
154
|
const s = await ctx.optionalAuth();
|
|
150
155
|
const hs = ctx.hs;
|
|
@@ -158,15 +163,15 @@ function registerSpaceRoutes(r) {
|
|
|
158
163
|
const state = await hs.rooms.currentState(roomId);
|
|
159
164
|
const out = await roomDetails(hs, roomId);
|
|
160
165
|
out.room_version = await hs.rooms.roomVersion(roomId);
|
|
161
|
-
const enc = getState(state,
|
|
166
|
+
const enc = getState(state, M.ROOM.ENCRYPTION)?.content?.algorithm;
|
|
162
167
|
if (typeof enc === "string") out.encryption = enc;
|
|
163
168
|
if (s) out.membership = membershipOf(state, s.userId);
|
|
164
|
-
const allowed = allowedRoomIds(getState(state,
|
|
169
|
+
const allowed = allowedRoomIds(getState(state, M.ROOM.JOIN_RULES)?.content);
|
|
165
170
|
if (allowed) out.allowed_room_ids = allowed;
|
|
166
171
|
return out;
|
|
167
172
|
};
|
|
168
|
-
r.client("GET", "/room_summary/:roomIdOrAlias", summary, ["v1"]);
|
|
169
|
-
r.get("/_matrix/client/unstable/im.nheko.summary/summary/:roomIdOrAlias", summary);
|
|
173
|
+
r.client("GET", "/room_summary/:roomIdOrAlias", procedure({ handler: summary }), ["v1"]);
|
|
174
|
+
r.get("/_matrix/client/unstable/im.nheko.summary/summary/:roomIdOrAlias", procedure({ handler: summary }));
|
|
170
175
|
}
|
|
171
176
|
//#endregion
|
|
172
177
|
export { registerSpaceRoutes, roomDetails };
|