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.
Files changed (141) hide show
  1. package/LICENSE +75 -0
  2. package/README.md +479 -2
  3. package/dist/adapters/auth.d.ts +50 -0
  4. package/dist/adapters/auth.js +18 -0
  5. package/dist/adapters/cluster.d.ts +55 -0
  6. package/dist/adapters/cluster.js +249 -0
  7. package/dist/adapters/media.d.ts +50 -0
  8. package/dist/adapters/media.js +63 -0
  9. package/dist/adapters/s3.d.ts +33 -0
  10. package/dist/adapters/s3.js +95 -0
  11. package/dist/api/account.js +594 -0
  12. package/dist/api/admin.js +267 -0
  13. package/dist/api/appservice.js +45 -0
  14. package/dist/api/backup.js +280 -0
  15. package/dist/api/federation.js +826 -0
  16. package/dist/api/filters.js +88 -0
  17. package/dist/api/index.js +47 -0
  18. package/dist/api/legacy.js +183 -0
  19. package/dist/api/media.js +271 -0
  20. package/dist/api/misc.js +95 -0
  21. package/dist/api/preview.js +201 -0
  22. package/dist/api/profile.js +176 -0
  23. package/dist/api/push.js +202 -0
  24. package/dist/api/relationships.js +270 -0
  25. package/dist/api/rooms.js +1487 -0
  26. package/dist/api/rtc.d.ts +23 -0
  27. package/dist/api/rtc.js +66 -0
  28. package/dist/api/search.js +161 -0
  29. package/dist/api/slidingsync.js +474 -0
  30. package/dist/api/spaces.js +177 -0
  31. package/dist/api/sync.js +609 -0
  32. package/dist/api/threadsubs.js +140 -0
  33. package/dist/api/threepid.js +155 -0
  34. package/dist/api/uia.js +127 -0
  35. package/dist/api/user.js +329 -0
  36. package/dist/core/admin.d.ts +84 -0
  37. package/dist/core/admin.js +308 -0
  38. package/dist/core/adminroom.d.ts +49 -0
  39. package/dist/core/adminroom.js +483 -0
  40. package/dist/core/appservices.d.ts +74 -0
  41. package/dist/core/appservices.js +369 -0
  42. package/dist/core/audit.d.ts +50 -0
  43. package/dist/core/audit.js +86 -0
  44. package/dist/core/auth.d.ts +48 -0
  45. package/dist/core/auth.js +237 -0
  46. package/dist/core/authrules.d.ts +4 -0
  47. package/dist/core/authrules.js +348 -0
  48. package/dist/core/cluster.d.ts +66 -0
  49. package/dist/core/cluster.js +191 -0
  50. package/dist/core/crypto.d.ts +10 -0
  51. package/dist/core/crypto.js +100 -0
  52. package/dist/core/delayed.d.ts +39 -0
  53. package/dist/core/delayed.js +160 -0
  54. package/dist/core/errors.d.ts +9 -0
  55. package/dist/core/errors.js +45 -0
  56. package/dist/core/events.d.ts +32 -0
  57. package/dist/core/events.js +186 -0
  58. package/dist/core/glob.js +66 -0
  59. package/dist/core/identity.d.ts +24 -0
  60. package/dist/core/identity.js +96 -0
  61. package/dist/core/ids.js +36 -0
  62. package/dist/core/invitefilter.js +36 -0
  63. package/dist/core/json.js +16 -0
  64. package/dist/core/keys.d.ts +36 -0
  65. package/dist/core/keys.js +450 -0
  66. package/dist/core/m.d.ts +209 -0
  67. package/dist/core/m.js +182 -0
  68. package/dist/core/notifier.d.ts +17 -0
  69. package/dist/core/notifier.js +54 -0
  70. package/dist/core/oauth.d.ts +38 -0
  71. package/dist/core/oauth.js +108 -0
  72. package/dist/core/partialstate.d.ts +32 -0
  73. package/dist/core/partialstate.js +198 -0
  74. package/dist/core/phone.js +268 -0
  75. package/dist/core/policy.d.ts +29 -0
  76. package/dist/core/policy.js +97 -0
  77. package/dist/core/profile.js +39 -0
  78. package/dist/core/push.d.ts +46 -0
  79. package/dist/core/push.js +307 -0
  80. package/dist/core/pushrules.js +229 -0
  81. package/dist/core/ratelimit.d.ts +23 -0
  82. package/dist/core/ratelimit.js +77 -0
  83. package/dist/core/rooms.d.ts +215 -0
  84. package/dist/core/rooms.js +1731 -0
  85. package/dist/core/settings.d.ts +11 -0
  86. package/dist/core/settings.js +29 -0
  87. package/dist/core/sso.d.ts +46 -0
  88. package/dist/core/sso.js +165 -0
  89. package/dist/core/stateres.d.ts +4 -0
  90. package/dist/core/stateres.js +209 -0
  91. package/dist/core/threepid.d.ts +80 -0
  92. package/dist/core/threepid.js +275 -0
  93. package/dist/core/typing.d.ts +16 -0
  94. package/dist/core/typing.js +60 -0
  95. package/dist/federation/client.d.ts +51 -0
  96. package/dist/federation/client.js +279 -0
  97. package/dist/federation/index.d.ts +153 -0
  98. package/dist/federation/index.js +1059 -0
  99. package/dist/federation/keyring.d.ts +26 -0
  100. package/dist/federation/keyring.js +122 -0
  101. package/dist/federation/sender.d.ts +26 -0
  102. package/dist/federation/sender.js +164 -0
  103. package/dist/homeserver.d.ts +224 -0
  104. package/dist/homeserver.js +302 -0
  105. package/dist/http/adapters.d.ts +40 -0
  106. package/dist/http/adapters.js +130 -0
  107. package/dist/http/handler.d.ts +8 -0
  108. package/dist/http/handler.js +181 -0
  109. package/dist/http/input.js +24 -0
  110. package/dist/http/procedure.js +25 -0
  111. package/dist/http/router.d.ts +43 -0
  112. package/dist/http/router.js +56 -0
  113. package/dist/index.d.ts +26 -0
  114. package/dist/index.js +15 -0
  115. package/dist/storage/memory.d.ts +5 -0
  116. package/dist/storage/memory.js +122 -0
  117. package/dist/storage/schema.d.ts +4 -0
  118. package/dist/storage/schema.js +664 -0
  119. package/dist/storage/sql.d.ts +72 -0
  120. package/dist/storage/sql.js +274 -0
  121. package/dist/storage/types.d.ts +55 -0
  122. package/dist/vendor/zod/LICENSE +21 -0
  123. package/dist/vendor/zod/v4/classic/errors.js +54 -0
  124. package/dist/vendor/zod/v4/classic/parse.js +17 -0
  125. package/dist/vendor/zod/v4/classic/schemas.js +865 -0
  126. package/dist/vendor/zod/v4/core/api.js +512 -0
  127. package/dist/vendor/zod/v4/core/checks.js +300 -0
  128. package/dist/vendor/zod/v4/core/core.js +109 -0
  129. package/dist/vendor/zod/v4/core/doc.js +35 -0
  130. package/dist/vendor/zod/v4/core/errors.js +118 -0
  131. package/dist/vendor/zod/v4/core/json-schema-processors.js +428 -0
  132. package/dist/vendor/zod/v4/core/memoizer.js +255 -0
  133. package/dist/vendor/zod/v4/core/parse.js +206 -0
  134. package/dist/vendor/zod/v4/core/regexes.js +73 -0
  135. package/dist/vendor/zod/v4/core/registries.js +48 -0
  136. package/dist/vendor/zod/v4/core/schemas.js +1378 -0
  137. package/dist/vendor/zod/v4/core/to-json-schema.js +448 -0
  138. package/dist/vendor/zod/v4/core/util.js +537 -0
  139. package/dist/vendor/zod/v4/core/versions.js +8 -0
  140. package/dist/vendor/zod/v4/locales/en.js +110 -0
  141. 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
@@ -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 };