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.
Files changed (99) hide show
  1. package/README.md +89 -11
  2. package/dist/adapters/cluster.d.ts +1 -26
  3. package/dist/adapters/cluster.js +50 -103
  4. package/dist/api/account.js +407 -354
  5. package/dist/api/admin.js +82 -61
  6. package/dist/api/appservice.js +37 -25
  7. package/dist/api/backup.js +73 -62
  8. package/dist/api/federation.js +172 -138
  9. package/dist/api/filters.js +4 -3
  10. package/dist/api/legacy.js +91 -78
  11. package/dist/api/media.js +71 -55
  12. package/dist/api/misc.js +46 -37
  13. package/dist/api/preview.js +37 -73
  14. package/dist/api/profile.js +108 -97
  15. package/dist/api/push.js +114 -99
  16. package/dist/api/relationships.js +64 -58
  17. package/dist/api/rooms.js +703 -580
  18. package/dist/api/rtc.d.ts +0 -1
  19. package/dist/api/rtc.js +48 -34
  20. package/dist/api/search.js +133 -127
  21. package/dist/api/slidingsync.js +41 -31
  22. package/dist/api/spaces.js +82 -77
  23. package/dist/api/sync.js +325 -135
  24. package/dist/api/threadsubs.js +72 -61
  25. package/dist/api/threepid.js +99 -66
  26. package/dist/api/uia.js +17 -16
  27. package/dist/api/user.js +221 -178
  28. package/dist/core/admin.d.ts +0 -1
  29. package/dist/core/admin.js +6 -5
  30. package/dist/core/adminroom.js +9 -8
  31. package/dist/core/appservices.d.ts +2 -1
  32. package/dist/core/appservices.js +5 -4
  33. package/dist/core/audit.d.ts +0 -1
  34. package/dist/core/authrules.js +26 -25
  35. package/dist/core/cluster.d.ts +12 -5
  36. package/dist/core/cluster.js +46 -29
  37. package/dist/core/delayed.js +2 -1
  38. package/dist/core/events.js +11 -10
  39. package/dist/core/html.js +13 -0
  40. package/dist/core/identity.js +1 -1
  41. package/dist/core/invitefilter.js +2 -1
  42. package/dist/core/json.js +10 -1
  43. package/dist/core/keys.d.ts +10 -1
  44. package/dist/core/keys.js +62 -42
  45. package/dist/core/m.d.ts +209 -0
  46. package/dist/core/m.js +182 -0
  47. package/dist/core/outbound.d.ts +16 -0
  48. package/dist/core/outbound.js +172 -0
  49. package/dist/core/partialstate.js +2 -1
  50. package/dist/core/policy.js +4 -3
  51. package/dist/core/push.d.ts +0 -1
  52. package/dist/core/push.js +41 -28
  53. package/dist/core/pushrules.js +36 -35
  54. package/dist/core/ratelimit.d.ts +1 -1
  55. package/dist/core/rooms.d.ts +10 -1
  56. package/dist/core/rooms.js +101 -74
  57. package/dist/core/semaphore.js +23 -0
  58. package/dist/core/sso.d.ts +15 -1
  59. package/dist/core/sso.js +38 -2
  60. package/dist/core/stateres.js +7 -6
  61. package/dist/core/threepid.js +1 -9
  62. package/dist/federation/client.js +9 -1
  63. package/dist/federation/index.d.ts +2 -2
  64. package/dist/federation/index.js +43 -35
  65. package/dist/homeserver.d.ts +23 -4
  66. package/dist/homeserver.js +12 -3
  67. package/dist/http/handler.js +2 -23
  68. package/dist/http/input.js +2 -2
  69. package/dist/http/procedure.js +25 -0
  70. package/dist/http/router.d.ts +9 -26
  71. package/dist/http/router.js +10 -30
  72. package/dist/index.d.ts +4 -3
  73. package/dist/index.js +3 -2
  74. package/dist/storage/batch.js +11 -0
  75. package/dist/storage/memory.js +1 -0
  76. package/dist/storage/schema.js +1 -1
  77. package/dist/storage/sql.js +20 -1
  78. package/dist/storage/types.d.ts +16 -0
  79. package/dist/vendor/zod/LICENSE +21 -0
  80. package/dist/vendor/zod/v4/classic/errors.js +54 -0
  81. package/dist/vendor/zod/v4/classic/parse.js +17 -0
  82. package/dist/vendor/zod/v4/classic/schemas.js +865 -0
  83. package/dist/vendor/zod/v4/core/api.js +512 -0
  84. package/dist/vendor/zod/v4/core/checks.js +300 -0
  85. package/dist/vendor/zod/v4/core/core.js +109 -0
  86. package/dist/vendor/zod/v4/core/doc.js +35 -0
  87. package/dist/vendor/zod/v4/core/errors.js +118 -0
  88. package/dist/vendor/zod/v4/core/json-schema-processors.js +428 -0
  89. package/dist/vendor/zod/v4/core/memoizer.js +255 -0
  90. package/dist/vendor/zod/v4/core/parse.js +206 -0
  91. package/dist/vendor/zod/v4/core/regexes.js +73 -0
  92. package/dist/vendor/zod/v4/core/registries.js +48 -0
  93. package/dist/vendor/zod/v4/core/schemas.js +1378 -0
  94. package/dist/vendor/zod/v4/core/to-json-schema.js +448 -0
  95. package/dist/vendor/zod/v4/core/util.js +537 -0
  96. package/dist/vendor/zod/v4/core/versions.js +8 -0
  97. package/dist/vendor/zod/v4/locales/en.js +110 -0
  98. package/package.json +8 -6
  99. package/dist/core/pushrules.d.ts +0 -1
@@ -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("m.room.history_visibility")?.history_visibility === "world_readable",
13
- guest_can_join: get("m.room.guest_access")?.guest_access === "can_join",
14
- join_rule: get("m.room.join_rules")?.join_rule ?? "invite"
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("m.room.name")?.name)) out.name = get("m.room.name").name;
18
- if (str(get("m.room.topic")?.topic)) out.topic = get("m.room.topic").topic;
19
- if (str(get("m.room.canonical_alias")?.alias)) out.canonical_alias = get("m.room.canonical_alias").alias;
20
- if (str(get("m.room.avatar")?.url)) out.avatar_url = get("m.room.avatar").url;
21
- if (str(get("m.room.create")?.type)) out.room_type = get("m.room.create").type;
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, "m.room.history_visibility")?.content?.history_visibility === "world_readable") return true;
33
- const joinRules = getState(state, "m.room.join_rules")?.content;
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 === "m.room_membership" && typeof allow.room_id === "string" && await hs.rooms.exists(allow.room_id)) {
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 === "m.room_membership" && typeof a.room_id === "string").map((a) => a.room_id);
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", async (ctx) => {
82
- const s = await ctx.auth();
83
- const hs = ctx.hs;
84
- const rootId = ctx.params.roomId;
85
- if (!await hs.rooms.exists(rootId) || !await canAccess(hs, rootId, s.userId)) throw errors.forbidden("You cannot view this room");
86
- const suggestedOnly = ctx.query.get("suggested_only") === "true";
87
- const maxDepth = ctx.query.has("max_depth") ? Number.parseInt(ctx.query.get("max_depth"), 10) : Infinity;
88
- const limit = Math.min(Math.max(Number.parseInt(ctx.query.get("limit") ?? "50", 10) || 50, 1), 100);
89
- const from = ctx.query.get("from");
90
- let offset = 0;
91
- if (from) {
92
- const m = /^(\d+)_(.+)$/.exec(from);
93
- if (!m || m[2] !== `${rootId}|${suggestedOnly}|${ctx.query.get("max_depth") ?? ""}`) throw errors.invalidParam("Invalid pagination token");
94
- offset = Number(m[1]);
95
- }
96
- const rooms = [];
97
- const seen = /* @__PURE__ */ new Set();
98
- const queue = [{
99
- roomId: rootId,
100
- depth: 0,
101
- via: []
102
- }];
103
- while (queue.length) {
104
- const { roomId, depth, via } = queue.pop();
105
- if (seen.has(roomId)) continue;
106
- seen.add(roomId);
107
- if (!await hs.rooms.serverIsJoined(roomId)) {
108
- const remote = await remoteSummary(hs, roomId, via, suggestedOnly, s.userId);
109
- if (!remote) continue;
110
- rooms.push(remote);
111
- const remoteChildren = (remote.room_type === "m.space" ? remote.children_state ?? [] : []).filter((c) => Array.isArray(c.content?.via) && c.content.via.length).sort(childOrder);
112
- if (depth < maxDepth) for (const child of [...remoteChildren].reverse()) queue.push({
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
- continue;
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
- if (roomId !== rootId && !await canAccess(hs, roomId, s.userId)) continue;
120
- const state = await hs.rooms.currentState(roomId);
121
- const children = [];
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
- const out = { rooms: rooms.slice(offset, offset + limit) };
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, "m.room.encryption")?.content?.algorithm;
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, "m.room.join_rules")?.content);
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 };