@zooid/transport-matrix 0.7.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zooid contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,288 @@
1
+ import { TransportContextProvider, HistoryOptions, HistoryPage, ThreadOverviewPage, Member, ChannelInfo, AcpRegistry, ApprovalCorrelator } from '@zooid/core';
2
+ import * as hono_types from 'hono/types';
3
+ import { Hono } from 'hono';
4
+
5
+ interface MatrixClientOptions {
6
+ homeserver: string;
7
+ asToken: string;
8
+ fetch?: typeof globalThis.fetch;
9
+ }
10
+ interface SendMessageInput {
11
+ roomId: string;
12
+ asUserId: string;
13
+ content: {
14
+ msgtype: string;
15
+ body: string;
16
+ [k: string]: unknown;
17
+ };
18
+ threadRoot?: string;
19
+ }
20
+ interface SendCustomEventInput {
21
+ roomId: string;
22
+ asUserId: string;
23
+ eventType: string;
24
+ content: Record<string, unknown>;
25
+ }
26
+ interface SetTypingInput {
27
+ roomId: string;
28
+ asUserId: string;
29
+ typing: boolean;
30
+ /** ms — homeserver expects re-PUTs before this expires. Ignored when typing=false. */
31
+ timeoutMs?: number;
32
+ }
33
+ interface SetPresenceInput {
34
+ asUserId: string;
35
+ presence: 'online' | 'unavailable' | 'offline';
36
+ statusMsg?: string;
37
+ }
38
+ declare class MatrixClient {
39
+ private readonly homeserver;
40
+ private readonly asToken;
41
+ private readonly fetch;
42
+ constructor(opts: MatrixClientOptions);
43
+ registerBot(localpart: string): Promise<{
44
+ user_id: string;
45
+ device_id: string;
46
+ } | undefined>;
47
+ resolveAlias(alias: string): Promise<string | null>;
48
+ createRoom(opts: {
49
+ roomAliasName: string;
50
+ invite: string[];
51
+ senderUserId: string;
52
+ preset?: 'public_chat' | 'private_chat' | 'trusted_private_chat';
53
+ /** Optional `m.room.name`. When set, sent in the createRoom body so the
54
+ * room has a display name from the moment it exists. */
55
+ name?: string;
56
+ }): Promise<string>;
57
+ createRoomRaw(opts: {
58
+ asUserId: string;
59
+ body: Record<string, unknown>;
60
+ }): Promise<string>;
61
+ sendStateEvent(opts: {
62
+ roomId: string;
63
+ asUserId: string;
64
+ eventType: string;
65
+ stateKey?: string;
66
+ content: Record<string, unknown>;
67
+ }): Promise<{
68
+ event_id: string;
69
+ }>;
70
+ joinRoom(roomIdOrAlias: string, asUserId: string): Promise<void>;
71
+ sendMessage(input: SendMessageInput): Promise<{
72
+ event_id: string;
73
+ }>;
74
+ sendCustomEvent(input: SendCustomEventInput): Promise<{
75
+ event_id: string;
76
+ }>;
77
+ setTyping(input: SetTypingInput): Promise<void>;
78
+ setDisplayName(asUserId: string, displayName: string): Promise<void>;
79
+ setPresence(input: SetPresenceInput): Promise<void>;
80
+ /**
81
+ * Fetch a single event from a room. Used to recover thread-root context
82
+ * after a daemon restart wipes the in-memory threadStates cache.
83
+ */
84
+ fetchEvent(roomId: string, eventId: string, asUserId: string): Promise<Record<string, unknown> | null>;
85
+ /**
86
+ * Fetch replies to a thread root via the relations endpoint, oldest-first.
87
+ * Pass `limit` and `from` for pagination; `next_batch` echoes back when
88
+ * there are more replies. Returns `{ chunk: [] }` when the root is unknown.
89
+ */
90
+ fetchThreadRelations(opts: {
91
+ roomId: string;
92
+ rootEventId: string;
93
+ asUserId: string;
94
+ limit?: number;
95
+ from?: string;
96
+ }): Promise<{
97
+ chunk: Array<Record<string, unknown>>;
98
+ next_batch?: string;
99
+ }>;
100
+ /**
101
+ * Paginate the room timeline. Returns events newest-first (dir=b) per Matrix
102
+ * spec. The caller is responsible for reversing if it wants oldest-first.
103
+ */
104
+ fetchRoomMessages(opts: {
105
+ roomId: string;
106
+ asUserId: string;
107
+ limit?: number;
108
+ /** Opaque pagination token returned in `end` from a previous call. */
109
+ from?: string;
110
+ /**
111
+ * Server-side RoomEventFilter. Common keys: `types` (whitelist event types),
112
+ * `not_types`, `not_rel_types` (e.g. `['m.thread']` to exclude thread
113
+ * replies). Encoded as JSON into the `filter` query param.
114
+ */
115
+ filter?: {
116
+ types?: string[];
117
+ not_types?: string[];
118
+ rel_types?: string[];
119
+ not_rel_types?: string[];
120
+ };
121
+ }): Promise<{
122
+ chunk: Array<Record<string, unknown>>;
123
+ end?: string;
124
+ }>;
125
+ getJoinedMembers(roomId: string, asUserId: string): Promise<{
126
+ joined: Record<string, {
127
+ display_name?: string;
128
+ }>;
129
+ }>;
130
+ fetchRoomName(roomId: string, asUserId: string): Promise<string | null>;
131
+ private sendEvent;
132
+ }
133
+
134
+ interface MatrixContextProviderOpts {
135
+ client: MatrixClient;
136
+ /** AS sender_localpart user (read access). */
137
+ asUserId: string;
138
+ /** Map of Matrix user IDs → agent names, for is_agent / agent_name flags. */
139
+ agentBots: Map<string, string>;
140
+ }
141
+ declare class MatrixContextProvider implements TransportContextProvider {
142
+ private readonly opts;
143
+ constructor(opts: MatrixContextProviderOpts);
144
+ getRoomHistory(channelId: string, hopts: HistoryOptions): Promise<HistoryPage>;
145
+ getRecentThreads(channelId: string, hopts: HistoryOptions): Promise<ThreadOverviewPage>;
146
+ getThreadHistory(channelId: string, threadId: string, hopts: HistoryOptions): Promise<HistoryPage>;
147
+ private toMessage;
148
+ getChannelMembers(channelId: string): Promise<Member[]>;
149
+ getChannelInfo(channelId: string): Promise<ChannelInfo>;
150
+ }
151
+
152
+ interface MatrixTransportConfig {
153
+ id: string;
154
+ url: string;
155
+ homeserver: string;
156
+ asToken: string;
157
+ hsToken: string;
158
+ senderLocalpart: string;
159
+ /** Regex covering all bot users, e.g. `@.*:example.com` */
160
+ userNamespace: string;
161
+ /**
162
+ * Optional regex covering aliases the AS may claim, e.g. `#.*:example.com`.
163
+ * Required when the AS calls `createRoom` with a `room_alias_name`.
164
+ */
165
+ aliasNamespace?: string;
166
+ /**
167
+ * Whether the AS exclusively owns the user_namespace. Default true.
168
+ * Set false when humans share the namespace (e.g., `zooid dev` registers
169
+ * a predefined admin under the same `@.*:localhost` regex).
170
+ */
171
+ exclusive?: boolean;
172
+ }
173
+ declare function renderRegistration(c: MatrixTransportConfig): string;
174
+
175
+ interface MaybeMessage {
176
+ content?: {
177
+ 'm.mentions'?: {
178
+ user_ids?: string[];
179
+ };
180
+ body?: string;
181
+ formatted_body?: string;
182
+ };
183
+ }
184
+ declare function extractMentions(event: MaybeMessage): string[];
185
+
186
+ interface AgentBinding {
187
+ name: string;
188
+ userId: string;
189
+ /** Optional human-readable display name. Falls back to the user_id localpart. */
190
+ displayName?: string;
191
+ rooms: string[];
192
+ trigger: 'mention' | 'any';
193
+ }
194
+ interface ThreadState {
195
+ /** Agent names that have posted in this thread, in order. */
196
+ participants: string[];
197
+ /** Agent names @mentioned in the thread root event (or subsequently). */
198
+ rootMentions: string[];
199
+ }
200
+ interface MaybeEvent {
201
+ type?: string;
202
+ room_id?: string;
203
+ sender?: string;
204
+ content?: {
205
+ msgtype?: string;
206
+ 'm.relates_to'?: {
207
+ rel_type?: string;
208
+ event_id?: string;
209
+ };
210
+ };
211
+ }
212
+ type RouteMatch = AgentBinding;
213
+ declare function route(event: MaybeEvent, agents: AgentBinding[], threadStates?: Map<string, ThreadState>): RouteMatch[];
214
+
215
+ interface BootstrapOpts {
216
+ /** Invited to any newly-created room; absent = no invite. */
217
+ adminUserId?: string;
218
+ /** Workforce space room ID. When set, every resolved agent room is attached as m.space.child. */
219
+ spaceRoomId?: string;
220
+ /** AS bot user ID. Required when spaceRoomId is set; sender of the m.space.child write. */
221
+ asUserId?: string;
222
+ }
223
+ declare class BotPool {
224
+ private readonly client;
225
+ private readonly agents;
226
+ constructor(client: Pick<MatrixClient, 'registerBot' | 'joinRoom' | 'resolveAlias' | 'createRoom' | 'sendStateEvent' | 'setDisplayName'>, agents: AgentBinding[]);
227
+ bootstrap(opts?: BootstrapOpts): Promise<void>;
228
+ findByUserId(userId: string): AgentBinding | undefined;
229
+ findByName(name: string): AgentBinding | undefined;
230
+ }
231
+
232
+ interface CreateMatrixTransportOptions {
233
+ agents: AcpRegistry;
234
+ approvals: ApprovalCorrelator;
235
+ client: MatrixClient;
236
+ bindings: AgentBinding[];
237
+ hsToken: string;
238
+ /** Admin Matrix user ID. When set, BotPool.bootstrap invites this user into rooms it creates. */
239
+ adminUserId?: string;
240
+ }
241
+ declare function createMatrixTransport(opts: CreateMatrixTransportOptions): {
242
+ app: Hono<hono_types.BlankEnv, hono_types.BlankSchema, "/">;
243
+ bootstrap: (bootstrapOpts?: {
244
+ spaceRoomId?: string;
245
+ asUserId?: string;
246
+ }) => Promise<void>;
247
+ pool: BotPool;
248
+ };
249
+
250
+ interface EnsureSpaceOpts {
251
+ client: MatrixClient;
252
+ asUserId: string;
253
+ serverName: string;
254
+ spaceLocalpart: string;
255
+ preset: 'public_chat' | 'private_chat';
256
+ }
257
+ declare function ensureWorkforceSpace(opts: EnsureSpaceOpts): Promise<string>;
258
+ declare function serverNameFromMxid(mxid: string): string;
259
+
260
+ interface WorkforceRoster {
261
+ version: 1;
262
+ agents: {
263
+ user_id: string;
264
+ name: string;
265
+ rooms: string[];
266
+ }[];
267
+ }
268
+ declare function buildWorkforceRoster(agents: AgentBinding[]): WorkforceRoster;
269
+ interface PublishOpts {
270
+ client: MatrixClient;
271
+ spaceRoomId: string;
272
+ asUserId: string;
273
+ agents: AgentBinding[];
274
+ }
275
+ declare function publishWorkforce(opts: PublishOpts): Promise<void>;
276
+ interface PublisherHandle {
277
+ reload(): Promise<void>;
278
+ stop(): Promise<void>;
279
+ }
280
+ interface StartOpts {
281
+ client: MatrixClient;
282
+ spaceRoomId: string;
283
+ asUserId: string;
284
+ getAgents: () => AgentBinding[];
285
+ }
286
+ declare function startWorkforcePublisher(opts: StartOpts): Promise<PublisherHandle>;
287
+
288
+ export { type AgentBinding, BotPool, type CreateMatrixTransportOptions, type EnsureSpaceOpts, MatrixClient, type MatrixClientOptions, MatrixContextProvider, type MatrixContextProviderOpts, type MatrixTransportConfig, type MaybeMessage, type PublishOpts, type PublisherHandle, type RouteMatch, type SendCustomEventInput, type SendMessageInput, type StartOpts as StartWorkforcePublisherOpts, type WorkforceRoster, buildWorkforceRoster, createMatrixTransport, ensureWorkforceSpace, extractMentions, publishWorkforce, renderRegistration, route, serverNameFromMxid, startWorkforcePublisher };