Lines 9-49javascript
9const MAX_FORWARD_PAGES = 50;
10/** Bound on backward `limited`-burst recovery pagination so it always terminates (BUG-09). */
11const MAX_BACKFILL_PAGES = 50;
13 * Matrix (Synapse) backend (DESIGN §6/§9) — first external-network backend, over the raw
14 * Client-Server HTTP API (no SDK; unencrypted rooms). By default a topic maps to its own room via
15 * the canonical alias `#parley_<topic>:<server_name>`. The Matrix `event_id` is globally unique and
16 * serves as BOTH `backendMsgId` (dedup key) AND `cursor` (order key). "Strictly after a cursor" is
17 * resolved server-side: `/context/<event_id>` → a forward pagination token → `/messages?dir=f`. The
18 * live path is a filtered `/sync` long-poll loop (timeline limit 0 skips history). Core never
19 * compares cursor values — the homeserver's stream ordering is the single source of order.
21 * `shared_room` mode (see {@link MatrixBackendConfig.shared_room}) folds all topics into one room,
22 * isolating them by an `app.parley.topic` content tag — the only practical way to run the suite
23 * under Synapse's strict per-user room-creation rate limit without an appservice.
25export class MatrixPlugin {
26 baseUrl = 'http://127.0.0.1:8008';
27 serverName = 'parley.local';
29 password = 'parleypass';
30 syncTimeoutMs = 25_000;
31 /** Set → shared-room mode: alias localpart every topic resolves to; else per-topic rooms. */
37 /** room cache key → room_id, deduped so concurrent first-posts share one create/resolve. */
39 /** In-flight sync long-polls, aborted on disconnect so teardown is immediate. */
40 controllers = new Set();
41 async connect(config) {
43 this.baseUrl = (cfg.homeserver_url ?? 'http://127.0.0.1:8008').replace(/\/+$/, '');
44 this.serverName = cfg.server_name ?? 'parley.local';
45 this.user = cfg.user ?? 'parley';
46 this.password = cfg.password ?? 'parleypass';
47 this.syncTimeoutMs = cfg.sync_timeout_ms ?? 25_000;
48 this.sharedLocalpart = cfg.shared_room;