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,26 @@
1
+ import { Homeserver } from "../homeserver.js";
2
+ import { KeyObject } from "node:crypto";
3
+ //#region src/federation/keyring.d.ts
4
+ /**
5
+ * Remote server signing keys. Keys are fetched directly from the server
6
+ * (`/_matrix/key/v2/server`), verified against their self-signature, cached in
7
+ * memory and persisted in the database.
8
+ */
9
+ export declare class KeyRing {
10
+ private hs;
11
+ private cache;
12
+ private inflight;
13
+ constructor(hs: Homeserver);
14
+ /** Get a verify key, fetching the server's keys when unknown or expired (as of `minValidUntil`). */
15
+ getKey(serverName: string, keyId: string, minValidUntil?: number): Promise<KeyObject | null>;
16
+ private remember;
17
+ private fetchKeys;
18
+ private doFetch;
19
+ /** Validate and store a `/_matrix/key/v2/server` response. */
20
+ ingestServerKeys(serverName: string, body: Record<string, any>): Promise<void>;
21
+ /** Verify that `obj` carries a valid signature from `serverName`. */
22
+ verifySignedBy(obj: Record<string, any>, serverName: string, minValidUntil?: number): Promise<boolean>;
23
+ /** Cached keys in `/_matrix/key/v2/query` format (we act as a basic notary for keys we know). */
24
+ knownKeys(serverName: string): Promise<Record<string, any>[]>;
25
+ }
26
+ //#endregion
@@ -0,0 +1,122 @@
1
+ import { isObject } from "../core/json.js";
2
+ import { publicKeyFromBase64, verifyJsonSignature } from "../core/crypto.js";
3
+ import { createPublicKey } from "node:crypto";
4
+ //#region src/federation/keyring.ts
5
+ /**
6
+ * Remote server signing keys. Keys are fetched directly from the server
7
+ * (`/_matrix/key/v2/server`), verified against their self-signature, cached in
8
+ * memory and persisted in the database.
9
+ */
10
+ var KeyRing = class {
11
+ hs;
12
+ cache = /* @__PURE__ */ new Map();
13
+ inflight = /* @__PURE__ */ new Map();
14
+ constructor(hs) {
15
+ this.hs = hs;
16
+ }
17
+ /** Get a verify key, fetching the server's keys when unknown or expired (as of `minValidUntil`). */
18
+ async getKey(serverName, keyId, minValidUntil = Date.now()) {
19
+ if (serverName === this.hs.serverName) return keyId === `ed25519:${this.hs.signingKey.keyId}` ? createPublicKey(this.hs.signingKey.privateKey) : null;
20
+ const cached = this.cache.get(serverName)?.get(keyId);
21
+ if (cached && cached.validUntil >= minValidUntil) return cached.key;
22
+ if (!cached) {
23
+ const row = await this.hs.db.findOne("remote_server_keys", [{
24
+ field: "server_name",
25
+ value: serverName
26
+ }, {
27
+ field: "key_id",
28
+ value: keyId
29
+ }]);
30
+ if (row) {
31
+ this.remember(serverName, keyId, row.key, row.valid_until_ts);
32
+ if (row.valid_until_ts >= minValidUntil) return this.cache.get(serverName).get(keyId).key;
33
+ }
34
+ }
35
+ await this.fetchKeys(serverName);
36
+ const fetched = this.cache.get(serverName)?.get(keyId);
37
+ return fetched ? fetched.key : null;
38
+ }
39
+ remember(serverName, keyId, key, validUntil) {
40
+ let m = this.cache.get(serverName);
41
+ if (!m) this.cache.set(serverName, m = /* @__PURE__ */ new Map());
42
+ m.set(keyId, {
43
+ key: publicKeyFromBase64(key),
44
+ validUntil
45
+ });
46
+ }
47
+ fetchKeys(serverName) {
48
+ let p = this.inflight.get(serverName);
49
+ if (!p) {
50
+ p = this.doFetch(serverName).finally(() => this.inflight.delete(serverName));
51
+ this.inflight.set(serverName, p);
52
+ }
53
+ return p;
54
+ }
55
+ async doFetch(serverName) {
56
+ try {
57
+ const body = await this.hs.federation.client.request(serverName, "GET", "/_matrix/key/v2/server", { signed: false });
58
+ await this.ingestServerKeys(serverName, body);
59
+ } catch (err) {
60
+ this.hs.logger.debug("Fetching keys for", serverName, "failed", err);
61
+ }
62
+ }
63
+ /** Validate and store a `/_matrix/key/v2/server` response. */
64
+ async ingestServerKeys(serverName, body) {
65
+ if (body.server_name !== serverName || !isObject(body.verify_keys)) return;
66
+ const validUntil = Number(body.valid_until_ts) || 0;
67
+ const entries = [];
68
+ for (const [keyId, v] of Object.entries(body.verify_keys)) if (typeof v?.key === "string") entries.push([
69
+ keyId,
70
+ v.key,
71
+ validUntil
72
+ ]);
73
+ for (const [keyId, v] of Object.entries(isObject(body.old_verify_keys) ? body.old_verify_keys : {})) if (typeof v?.key === "string") entries.push([
74
+ keyId,
75
+ v.key,
76
+ Number(v.expired_ts) || 0
77
+ ]);
78
+ for (const [keyId, key] of entries.filter(([id]) => id in body.verify_keys)) if (!verifyJsonSignature(body, serverName, keyId, publicKeyFromBase64(key))) return;
79
+ for (const [keyId, key, until] of entries) {
80
+ this.remember(serverName, keyId, key, until);
81
+ await this.hs.db.upsert("remote_server_keys", {
82
+ server_name: serverName,
83
+ key_id: keyId,
84
+ key,
85
+ valid_until_ts: until
86
+ });
87
+ }
88
+ }
89
+ /** Verify that `obj` carries a valid signature from `serverName`. */
90
+ async verifySignedBy(obj, serverName, minValidUntil) {
91
+ const sigs = obj.signatures?.[serverName];
92
+ if (!isObject(sigs)) return false;
93
+ for (const keyId of Object.keys(sigs)) {
94
+ if (!keyId.startsWith("ed25519:")) continue;
95
+ const key = await this.getKey(serverName, keyId, minValidUntil);
96
+ if (key && verifyJsonSignature(obj, serverName, keyId, key)) return true;
97
+ }
98
+ return false;
99
+ }
100
+ /** Cached keys in `/_matrix/key/v2/query` format (we act as a basic notary for keys we know). */
101
+ async knownKeys(serverName) {
102
+ const rows = await this.hs.db.findMany("remote_server_keys", { where: [{
103
+ field: "server_name",
104
+ value: serverName
105
+ }] });
106
+ if (!rows.length) return [];
107
+ const verify_keys = {};
108
+ let until = 0;
109
+ for (const r of rows) {
110
+ verify_keys[r.key_id] = { key: r.key };
111
+ until = Math.max(until, r.valid_until_ts);
112
+ }
113
+ return [{
114
+ server_name: serverName,
115
+ valid_until_ts: until,
116
+ verify_keys,
117
+ old_verify_keys: {}
118
+ }];
119
+ }
120
+ };
121
+ //#endregion
122
+ export { KeyRing };
@@ -0,0 +1,26 @@
1
+ import { Homeserver } from "../homeserver.js";
2
+ //#region src/federation/sender.d.ts
3
+ /**
4
+ * Outbound transaction queue backed by the database (`federation_outbox`), so any
5
+ * instance can enqueue and pending items survive restarts. Per destination, one
6
+ * instance at a time (cluster lock) builds and sends transactions. Failed
7
+ * destinations back off; ephemeral EDUs (typing, presence) are dropped on failure.
8
+ */
9
+ export declare class TransactionSender {
10
+ private hs;
11
+ private timers;
12
+ private sweepTimer;
13
+ constructor(hs: Homeserver);
14
+ /** Start background sweeping for destinations with pending items (e.g. after a restart). */
15
+ start(): void;
16
+ private sweep;
17
+ sendPdu(destinations: Iterable<string>, pdu: Record<string, any>): Promise<void>;
18
+ sendEdu(destinations: Iterable<string>, eduType: string, content: Record<string, any>, durable?: boolean): Promise<void>;
19
+ private enqueue;
20
+ private schedule;
21
+ private flush;
22
+ /** Retry a destination immediately (e.g. after it contacted us). */
23
+ wake(destination: string): Promise<void>;
24
+ stop(): void;
25
+ }
26
+ //#endregion
@@ -0,0 +1,164 @@
1
+ import { randomString } from "../core/crypto.js";
2
+ //#region src/federation/sender.ts
3
+ const MAX_PDUS = 50;
4
+ const MAX_EDUS = 100;
5
+ const MIN_RETRY_MS = 1e3;
6
+ const MAX_RETRY_MS = 36e5;
7
+ /** Destinations that only just went down are retried quickly; long outages back off further. */
8
+ const FAST_RETRY_CAP_MS = 1e4;
9
+ const FAST_RETRY_ATTEMPTS = 10;
10
+ const SWEEP_INTERVAL_MS = 3e4;
11
+ /**
12
+ * Outbound transaction queue backed by the database (`federation_outbox`), so any
13
+ * instance can enqueue and pending items survive restarts. Per destination, one
14
+ * instance at a time (cluster lock) builds and sends transactions. Failed
15
+ * destinations back off; ephemeral EDUs (typing, presence) are dropped on failure.
16
+ */
17
+ var TransactionSender = class {
18
+ hs;
19
+ timers = /* @__PURE__ */ new Map();
20
+ sweepTimer = null;
21
+ constructor(hs) {
22
+ this.hs = hs;
23
+ }
24
+ /** Start background sweeping for destinations with pending items (e.g. after a restart). */
25
+ start() {
26
+ if (this.sweepTimer) return;
27
+ this.sweepTimer = setInterval(() => void this.sweep().catch(() => {}), SWEEP_INTERVAL_MS);
28
+ this.sweepTimer.unref?.();
29
+ this.sweep().catch(() => {});
30
+ }
31
+ async sweep() {
32
+ const rows = await this.hs.db.findMany("federation_outbox", {
33
+ sortBy: {
34
+ field: "id",
35
+ direction: "asc"
36
+ },
37
+ limit: 1e3
38
+ });
39
+ for (const dest of new Set(rows.map((r) => r.destination))) this.schedule(dest, 0);
40
+ }
41
+ async sendPdu(destinations, pdu) {
42
+ await this.enqueue(destinations, "pdu", pdu);
43
+ }
44
+ async sendEdu(destinations, eduType, content, durable = true) {
45
+ await this.enqueue(destinations, durable ? "edu" : "edu-ephemeral", {
46
+ edu_type: eduType,
47
+ content
48
+ });
49
+ }
50
+ async enqueue(destinations, kind, payload) {
51
+ for (const destination of new Set(destinations)) {
52
+ if (destination === this.hs.serverName) continue;
53
+ const id = await this.hs.cluster.nextId("federation_outbox");
54
+ await this.hs.db.create("federation_outbox", {
55
+ id,
56
+ destination,
57
+ kind,
58
+ payload,
59
+ created_ts: Date.now()
60
+ });
61
+ this.schedule(destination, 0);
62
+ }
63
+ }
64
+ schedule(destination, delayMs) {
65
+ if (this.hs.isClosed) return;
66
+ const existing = this.timers.get(destination);
67
+ if (existing && delayMs > 0) return;
68
+ if (existing) clearTimeout(existing);
69
+ const timer = setTimeout(() => {
70
+ this.timers.delete(destination);
71
+ this.flush(destination).catch((err) => this.hs.logger.debug("Federation flush failed", err));
72
+ }, delayMs);
73
+ timer.unref?.();
74
+ this.timers.set(destination, timer);
75
+ }
76
+ async flush(destination) {
77
+ await this.hs.cluster.lock(`fedsend:${destination}`, async () => {
78
+ const status = await this.hs.db.findOne("destination_status", [{
79
+ field: "destination",
80
+ value: destination
81
+ }]);
82
+ if (status && status.retry_after_ts > Date.now()) {
83
+ this.schedule(destination, status.retry_after_ts - Date.now());
84
+ return;
85
+ }
86
+ try {
87
+ for (;;) {
88
+ const rows = await this.hs.db.findMany("federation_outbox", {
89
+ where: [{
90
+ field: "destination",
91
+ value: destination
92
+ }],
93
+ sortBy: {
94
+ field: "id",
95
+ direction: "asc"
96
+ },
97
+ limit: 150
98
+ });
99
+ if (!rows.length) break;
100
+ const pdus = rows.filter((r) => r.kind === "pdu").slice(0, MAX_PDUS);
101
+ const edus = rows.filter((r) => r.kind !== "pdu").slice(0, MAX_EDUS);
102
+ const txnId = `${Date.now()}${randomString(6)}`;
103
+ await this.hs.federation.client.request(destination, "PUT", `/_matrix/federation/v1/send/${txnId}`, {
104
+ body: {
105
+ origin: this.hs.serverName,
106
+ origin_server_ts: Date.now(),
107
+ pdus: pdus.map((p) => p.payload),
108
+ edus: edus.map((e) => e.payload)
109
+ },
110
+ timeoutMs: 2e4
111
+ });
112
+ const sent = [...pdus, ...edus].map((r) => r.id);
113
+ await this.hs.db.delete("federation_outbox", [{
114
+ field: "id",
115
+ operator: "in",
116
+ value: sent
117
+ }]);
118
+ }
119
+ if (status) await this.hs.db.delete("destination_status", [{
120
+ field: "destination",
121
+ value: destination
122
+ }]);
123
+ } catch (err) {
124
+ const failures = (status?.failures ?? 0) + 1;
125
+ const cap = failures <= FAST_RETRY_ATTEMPTS ? FAST_RETRY_CAP_MS : MAX_RETRY_MS;
126
+ const delay = Math.min(Math.round(MIN_RETRY_MS * 1.5 ** (failures - 1)), cap);
127
+ await this.hs.db.upsert("destination_status", {
128
+ destination,
129
+ failures,
130
+ retry_after_ts: Date.now() + delay
131
+ });
132
+ await this.hs.db.delete("federation_outbox", [{
133
+ field: "destination",
134
+ value: destination
135
+ }, {
136
+ field: "kind",
137
+ value: "edu-ephemeral"
138
+ }]);
139
+ this.hs.logger.debug("Federation send to", destination, "failed; retrying in", delay, "ms", err);
140
+ this.schedule(destination, delay);
141
+ }
142
+ });
143
+ }
144
+ /** Retry a destination immediately (e.g. after it contacted us). */
145
+ async wake(destination) {
146
+ if (!await this.hs.db.findOne("destination_status", [{
147
+ field: "destination",
148
+ value: destination
149
+ }])) return;
150
+ await this.hs.db.delete("destination_status", [{
151
+ field: "destination",
152
+ value: destination
153
+ }]);
154
+ this.schedule(destination, 0);
155
+ }
156
+ stop() {
157
+ for (const t of this.timers.values()) clearTimeout(t);
158
+ this.timers.clear();
159
+ if (this.sweepTimer) clearInterval(this.sweepTimer);
160
+ this.sweepTimer = null;
161
+ }
162
+ };
163
+ //#endregion
164
+ export { TransactionSender };
@@ -0,0 +1,224 @@
1
+ import { PartialStateService } from "./core/partialstate.js";
2
+ import { SigningKey } from "./core/crypto.js";
3
+ import { PolicyServers } from "./core/policy.js";
4
+ import { ThreepidOptions, ThreepidService } from "./core/threepid.js";
5
+ import { IdentityServers } from "./core/identity.js";
6
+ import { M } from "./core/m.js";
7
+ import { AppServiceRegistration, AppServiceService } from "./core/appservices.js";
8
+ import { AuthService } from "./core/auth.js";
9
+ import { KeyService } from "./core/keys.js";
10
+ import { ClusterAdapter, StreamManager } from "./core/cluster.js";
11
+ import { Notifier } from "./core/notifier.js";
12
+ import { DatabaseAdapter } from "./storage/types.js";
13
+ import { RoomService } from "./core/rooms.js";
14
+ import { TypingService } from "./core/typing.js";
15
+ import { PushService } from "./core/push.js";
16
+ import { AdminService, ServerNoticesOptions } from "./core/admin.js";
17
+ import { OAuthDelegation, OAuthDelegationOptions } from "./core/oauth.js";
18
+ import { SsoOptions, SsoService } from "./core/sso.js";
19
+ import { FederationOptions, FederationService } from "./federation/index.js";
20
+ import { DelayedEventService, DelayedEventsOptions } from "./core/delayed.js";
21
+ import { RateLimitAction, RateLimitRule, RateLimiter, RateLimits } from "./core/ratelimit.js";
22
+ import { Router } from "./http/router.js";
23
+ import { RtcOptions } from "./api/rtc.js";
24
+ import { AuditOptions, AuditService } from "./core/audit.js";
25
+ import { SettingsService } from "./core/settings.js";
26
+ import { AdminRoomOptions, AdminRoomService } from "./core/adminroom.js";
27
+ import { ResolvedUserAuth, UserAuthAdapter } from "./adapters/auth.js";
28
+ import { MediaAdapter, Thumbnailer } from "./adapters/media.js";
29
+ import { EventEmitter } from "node:events";
30
+ //#region src/homeserver.d.ts
31
+ export interface Logger {
32
+ debug(...args: unknown[]): void;
33
+ info(...args: unknown[]): void;
34
+ warn(...args: unknown[]): void;
35
+ error(...args: unknown[]): void;
36
+ }
37
+ export interface HomeserverOptions {
38
+ /** The server name, i.e. the part after the colon in `@user:server`. */
39
+ homeserver: string;
40
+ /** Storage backend. Defaults to an in-memory database. */
41
+ databaseAdapter?: DatabaseAdapter | Record<string, never>;
42
+ /** Authentication customisation. Defaults to built-in password auth. */
43
+ userAuthAdapter?: UserAuthAdapter;
44
+ /** Media byte storage. Defaults to in-memory storage. */
45
+ mediaAdapter?: MediaAdapter | Record<string, never>;
46
+ /** Public URL of the client API, advertised via `/.well-known/matrix/client`. */
47
+ publicBaseUrl?: string;
48
+ /**
49
+ * Federation address ("host" or "host:port") advertised at `/.well-known/matrix/server`, when
50
+ * other servers should reach this server somewhere else than `<server name>:8448`.
51
+ */
52
+ federationAddress?: string;
53
+ /** Contacts and page served at `/.well-known/matrix/support` (e.g. to appeal a locked account). */
54
+ support?: {
55
+ contacts?: {
56
+ role: typeof M.ROLE.ADMIN | typeof M.ROLE.SECURITY | (string & {});
57
+ matrix_id?: string;
58
+ email_address?: string;
59
+ }[];
60
+ supportPage?: string;
61
+ };
62
+ /**
63
+ * Email addresses and phone numbers (3PIDs): how validation messages are sent, and whether
64
+ * registration needs an email address. 3PID invites through identity servers work without it.
65
+ */
66
+ threepid?: ThreepidOptions;
67
+ /**
68
+ * Lets a logged-in client generate a one-time login token for a new device
69
+ * (`POST /login/get_token`, after re-authentication). Default: true.
70
+ */
71
+ loginViaExistingSession?: boolean;
72
+ /** Enables Synapse-compatible shared-secret registration at `/_synapse/admin/v1/register`. */
73
+ registrationSharedSecret?: string;
74
+ /** Persisted ed25519 signing key. Generated and stored in the database when omitted. */
75
+ signingKey?: {
76
+ keyId: string;
77
+ seed: string;
78
+ };
79
+ /** Room version used when clients do not ask for one. Default: "10". */
80
+ defaultRoomVersion?: string;
81
+ /** When set, clients requesting refresh tokens get access tokens that expire after this many ms. */
82
+ accessTokenLifetimeMs?: number;
83
+ /** Maximum `/sync` long-poll duration in ms. Default: 30000. */
84
+ maxSyncTimeoutMs?: number;
85
+ /**
86
+ * Enables `/preview_url`. Off by default because it makes the server fetch arbitrary URLs.
87
+ * Private/internal addresses stay blocked unless `allowPrivateAddresses` is set.
88
+ */
89
+ urlPreviews?: boolean | {
90
+ allowPrivateAddresses?: boolean;
91
+ };
92
+ logger?: Logger;
93
+ /** Custom `fetch` for outgoing HTTP requests. */
94
+ fetch?: typeof globalThis.fetch;
95
+ /**
96
+ * Rate limiting. `false` disables it; otherwise per-action overrides and an optional
97
+ * shared limiter (defaults to an in-memory token bucket). Admins are never limited.
98
+ */
99
+ /** Delegate authentication to an external OAuth 2.0 / OIDC provider (disables password login and registration). */
100
+ oauth?: OAuthDelegationOptions;
101
+ /** Upstream OpenID Connect providers for `m.login.sso`. Requires `publicBaseUrl`. */
102
+ sso?: SsoOptions;
103
+ /**
104
+ * Coordination between instances. The default (`localCluster()`) supports one process;
105
+ * use `postgresCluster()` / `redisCluster()` to scale horizontally.
106
+ */
107
+ cluster?: ClusterAdapter;
108
+ /**
109
+ * Admin room with an admin bot (tuwunel-style); the first registered account becomes
110
+ * a server admin. Pass `true` or options to enable. Default: disabled.
111
+ */
112
+ adminRoom?: boolean | AdminRoomOptions;
113
+ /** Audit log of security-relevant actions. Default: disabled. */
114
+ audit?: AuditOptions;
115
+ /** Application service registrations (bridges, bots). */
116
+ appservices?: AppServiceRegistration[];
117
+ /** VoIP (TURN) and MatrixRTC configuration. */
118
+ rtc?: RtcOptions;
119
+ /** Delayed events (MSC4140) limits. */
120
+ delayedEvents?: DelayedEventsOptions;
121
+ /** Federation (server-server API). Enabled by default. */
122
+ federation?: FederationOptions;
123
+ /** Generates image thumbnails, e.g. `sharpThumbnailer(sharp)`. Without one, originals are served. */
124
+ thumbnailer?: Thumbnailer;
125
+ /** Server notices (system messages to users). */
126
+ serverNotices?: ServerNoticesOptions;
127
+ rateLimits?: false | {
128
+ limiter?: RateLimiter;
129
+ rules?: Partial<Record<RateLimitAction, RateLimitRule>>;
130
+ };
131
+ /** Interval for background cleanup of expired data, in ms. Default: 10 minutes. `0` disables it. */
132
+ cleanupIntervalMs?: number;
133
+ }
134
+ export interface ResolvedConfig {
135
+ serverName: string;
136
+ publicBaseUrl: string | null;
137
+ federationAddress: string | null;
138
+ support: {
139
+ contacts: {
140
+ role: string;
141
+ matrix_id?: string;
142
+ email_address?: string;
143
+ }[];
144
+ support_page?: string;
145
+ } | null;
146
+ loginViaExistingSession: boolean;
147
+ threepid: ThreepidOptions & {
148
+ identityServerProtocol: "https" | "http";
149
+ };
150
+ registrationSharedSecret: string | null;
151
+ defaultRoomVersion: string;
152
+ accessTokenLifetimeMs: number | null;
153
+ maxSyncTimeoutMs: number;
154
+ urlPreviews: {
155
+ allowPrivateAddresses: boolean;
156
+ } | null;
157
+ serverNotices: Required<ServerNoticesOptions>;
158
+ thumbnailer: Thumbnailer | null;
159
+ rtc: RtcOptions;
160
+ }
161
+ export declare class Homeserver extends EventEmitter {
162
+ readonly serverName: string;
163
+ readonly config: ResolvedConfig;
164
+ readonly db: DatabaseAdapter;
165
+ readonly media: MediaAdapter;
166
+ readonly userAuth: ResolvedUserAuth;
167
+ readonly logger: Logger;
168
+ readonly router: Router;
169
+ readonly cluster: ClusterAdapter;
170
+ readonly instanceId: string;
171
+ readonly streams: StreamManager;
172
+ readonly notifier: Notifier;
173
+ readonly auth: AuthService;
174
+ readonly rooms: RoomService;
175
+ readonly keys: KeyService;
176
+ readonly typing: TypingService;
177
+ readonly push: PushService;
178
+ readonly rateLimits: RateLimits;
179
+ readonly admin: AdminService;
180
+ readonly oauth: OAuthDelegation | null;
181
+ readonly sso: SsoService | null;
182
+ readonly federation: FederationService;
183
+ readonly delayedEvents: DelayedEventService;
184
+ readonly audit: AuditService;
185
+ readonly settings: SettingsService;
186
+ readonly adminRoom: AdminRoomService | null;
187
+ readonly appservices: AppServiceService;
188
+ readonly partialState: PartialStateService;
189
+ readonly policyServers: PolicyServers;
190
+ readonly threepids: ThreepidService;
191
+ readonly identityServers: IdentityServers;
192
+ /** `fetch` used for outgoing requests (push gateways, URL previews, OAuth). Overridable for testing. */
193
+ readonly fetch: typeof globalThis.fetch;
194
+ /** Resolves once storage is migrated and the server is ready to serve requests. */
195
+ readonly ready: Promise<void>;
196
+ private _signingKey;
197
+ private cleanupTimer;
198
+ private closed;
199
+ constructor(options: HomeserverOptions);
200
+ get signingKey(): SigningKey;
201
+ private init;
202
+ /** Remove expired tokens, abandoned uploads and old notifications. */
203
+ cleanup(): Promise<void>;
204
+ /** Stop background work and release long-polling requests. Call before shutting down your HTTP server. */
205
+ close(): Promise<void>;
206
+ get isClosed(): boolean;
207
+ /**
208
+ * Effective registration mode: an admin's runtime setting overrides the configuration.
209
+ * "open" | "token" | "closed".
210
+ */
211
+ registrationMode(): Promise<"open" | "token" | "closed">;
212
+ /** Whether `/register` is allowed right now, including the first-user exception. */
213
+ registrationAllowed(): Promise<boolean>;
214
+ /** Run `fn` atomically when the database adapter supports transactions. */
215
+ transaction<T>(fn: (db: DatabaseAdapter) => Promise<T>): Promise<T>;
216
+ /** The user's current profile, as included in member events. */
217
+ profile(userId: string): Promise<{
218
+ displayname?: string;
219
+ avatar_url?: string;
220
+ }>;
221
+ isLocalUser(userId: string): boolean;
222
+ }
223
+ export declare function createHomeserver(options: HomeserverOptions): Homeserver;
224
+ //#endregion