@undefineds.co/xpod 0.3.48 → 0.3.50

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 (128) hide show
  1. package/bin/xpod.js +0 -0
  2. package/dist/api/auth/MultiAuthenticator.js +2 -2
  3. package/dist/api/auth/MultiAuthenticator.js.map +1 -1
  4. package/dist/api/chatkit/pod-store.d.ts +16 -17
  5. package/dist/api/chatkit/pod-store.js +299 -231
  6. package/dist/api/chatkit/pod-store.js.map +1 -1
  7. package/dist/api/chatkit/schema.d.ts +1 -1
  8. package/dist/api/chatkit/service.js +13 -11
  9. package/dist/api/chatkit/service.js.map +1 -1
  10. package/dist/api/chatkit/store.d.ts +1 -0
  11. package/dist/api/chatkit/store.js +23 -11
  12. package/dist/api/chatkit/store.js.map +1 -1
  13. package/dist/api/chatkit/types.d.ts +17 -10
  14. package/dist/api/chatkit/types.js +97 -14
  15. package/dist/api/chatkit/types.js.map +1 -1
  16. package/dist/api/container/common.js +16 -2
  17. package/dist/api/container/common.js.map +1 -1
  18. package/dist/api/container/routes.js +3 -0
  19. package/dist/api/container/routes.js.map +1 -1
  20. package/dist/api/container/types.d.ts +3 -0
  21. package/dist/api/container/types.js.map +1 -1
  22. package/dist/api/handlers/ChatKitV1Handler.js +1 -2
  23. package/dist/api/handlers/ChatKitV1Handler.js.map +1 -1
  24. package/dist/api/handlers/CoordinationHandler.d.ts +6 -0
  25. package/dist/api/handlers/CoordinationHandler.js +115 -0
  26. package/dist/api/handlers/CoordinationHandler.js.map +1 -0
  27. package/dist/api/handlers/MatrixHandler.d.ts +11 -0
  28. package/dist/api/handlers/MatrixHandler.js +144 -2
  29. package/dist/api/handlers/MatrixHandler.js.map +1 -1
  30. package/dist/api/handlers/RunHandler.js +33 -15
  31. package/dist/api/handlers/RunHandler.js.map +1 -1
  32. package/dist/api/handlers/index.d.ts +1 -0
  33. package/dist/api/handlers/index.js +1 -0
  34. package/dist/api/handlers/index.js.map +1 -1
  35. package/dist/api/index.d.ts +1 -0
  36. package/dist/api/index.js +1 -0
  37. package/dist/api/index.js.map +1 -1
  38. package/dist/api/matrix/PodMatrixStore.d.ts +25 -1
  39. package/dist/api/matrix/PodMatrixStore.js +253 -41
  40. package/dist/api/matrix/PodMatrixStore.js.map +1 -1
  41. package/dist/api/matrix/index.d.ts +1 -1
  42. package/dist/api/matrix/index.js.map +1 -1
  43. package/dist/api/matrix/types.d.ts +25 -2
  44. package/dist/api/matrix/types.js.map +1 -1
  45. package/dist/api/middleware/AuthMiddleware.d.ts +1 -0
  46. package/dist/api/middleware/AuthMiddleware.js +13 -1
  47. package/dist/api/middleware/AuthMiddleware.js.map +1 -1
  48. package/dist/api/protocol-metadata.d.ts +4 -0
  49. package/dist/api/protocol-metadata.js +64 -0
  50. package/dist/api/protocol-metadata.js.map +1 -0
  51. package/dist/api/reconciler/ClientReconcilerCoordinator.d.ts +42 -0
  52. package/dist/api/reconciler/ClientReconcilerCoordinator.js +250 -0
  53. package/dist/api/reconciler/ClientReconcilerCoordinator.js.map +1 -0
  54. package/dist/api/reconciler/ClientReconcilerCoordinator.jsonld +186 -0
  55. package/dist/api/reconciler/ServerGroupReconcilerService.d.ts +39 -0
  56. package/dist/api/reconciler/ServerGroupReconcilerService.js +91 -0
  57. package/dist/api/reconciler/ServerGroupReconcilerService.js.map +1 -0
  58. package/dist/api/reconciler/ServerGroupReconcilerService.jsonld +146 -0
  59. package/dist/api/reconciler/WakeAgentQueue.d.ts +23 -0
  60. package/dist/api/reconciler/WakeAgentQueue.js +123 -0
  61. package/dist/api/reconciler/WakeAgentQueue.js.map +1 -0
  62. package/dist/api/reconciler/WakeAgentQueue.jsonld +91 -0
  63. package/dist/api/reconciler/coordination.d.ts +61 -0
  64. package/dist/api/reconciler/coordination.js +109 -0
  65. package/dist/api/reconciler/coordination.js.map +1 -0
  66. package/dist/api/reconciler/coordination.jsonld +186 -0
  67. package/dist/api/reconciler/index.d.ts +4 -0
  68. package/dist/api/reconciler/index.js +21 -0
  69. package/dist/api/reconciler/index.js.map +1 -0
  70. package/dist/api/runs/ManagedRunWorker.js +0 -5
  71. package/dist/api/runs/ManagedRunWorker.js.map +1 -1
  72. package/dist/api/runs/RunStateCenter.d.ts +1 -1
  73. package/dist/api/runs/RunStateCenter.js +12 -28
  74. package/dist/api/runs/RunStateCenter.js.map +1 -1
  75. package/dist/api/runs/store.d.ts +12 -15
  76. package/dist/api/runs/store.js +24 -15
  77. package/dist/api/runs/store.js.map +1 -1
  78. package/dist/api/tasks/TaskMaterializer.d.ts +1 -0
  79. package/dist/api/tasks/TaskMaterializer.js +10 -13
  80. package/dist/api/tasks/TaskMaterializer.js.map +1 -1
  81. package/dist/api/tasks/TaskService.d.ts +0 -2
  82. package/dist/api/tasks/TaskService.js +6 -16
  83. package/dist/api/tasks/TaskService.js.map +1 -1
  84. package/dist/api/tasks/store.d.ts +0 -2
  85. package/dist/api/tasks/store.js.map +1 -1
  86. package/dist/cli/commands/auth.d.ts +1 -1
  87. package/dist/cli/commands/auth.js +4 -5
  88. package/dist/cli/commands/auth.js.map +1 -1
  89. package/dist/cli/commands/backup.js +1 -1
  90. package/dist/cli/commands/backup.js.map +1 -1
  91. package/dist/cli/commands/login.js +1 -1
  92. package/dist/cli/commands/login.js.map +1 -1
  93. package/dist/cli/commands/pod.js +1 -1
  94. package/dist/cli/commands/pod.js.map +1 -1
  95. package/dist/cli/lib/auth-context.js +10 -7
  96. package/dist/cli/lib/auth-context.js.map +1 -1
  97. package/dist/cli/lib/auth-helper.d.ts +10 -6
  98. package/dist/cli/lib/auth-helper.js +10 -6
  99. package/dist/cli/lib/auth-helper.js.map +1 -1
  100. package/dist/cli/lib/credentials-store.d.ts +22 -4
  101. package/dist/cli/lib/credentials-store.js +68 -51
  102. package/dist/cli/lib/credentials-store.js.map +1 -1
  103. package/dist/cli/lib/oidc-auth.d.ts +4 -0
  104. package/dist/cli/lib/oidc-auth.js +90 -0
  105. package/dist/cli/lib/oidc-auth.js.map +1 -0
  106. package/dist/cli/lib/oidc-session-storage.d.ts +3 -0
  107. package/dist/cli/lib/oidc-session-storage.js +41 -0
  108. package/dist/cli/lib/oidc-session-storage.js.map +1 -0
  109. package/dist/components/components.jsonld +5 -1
  110. package/dist/components/context.jsonld +103 -0
  111. package/dist/index.d.ts +1 -0
  112. package/dist/index.js +15 -0
  113. package/dist/index.js.map +1 -1
  114. package/dist/provision/LocalPodProvisioningService.d.ts +1 -0
  115. package/dist/provision/LocalPodProvisioningService.js +9 -0
  116. package/dist/provision/LocalPodProvisioningService.js.map +1 -1
  117. package/dist/provision/LocalPodProvisioningService.jsonld +4 -0
  118. package/dist/runtime/Proxy.d.ts +1 -0
  119. package/dist/runtime/Proxy.js +8 -1
  120. package/dist/runtime/Proxy.js.map +1 -1
  121. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/select-query-builder.d.ts.map +1 -1
  122. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/select-query-builder.js +19 -9
  123. package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/select-query-builder.js.map +1 -1
  124. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/select-query-builder.d.ts.map +1 -1
  125. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/select-query-builder.js +19 -9
  126. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/select-query-builder.js.map +1 -1
  127. package/node_modules/@undefineds.co/drizzle-solid/package.json +1 -1
  128. package/package.json +5 -4
@@ -2,8 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PodMatrixStore = void 0;
4
4
  const node_crypto_1 = require("node:crypto");
5
+ const global_logger_factory_1 = require("global-logger-factory");
5
6
  const drizzle_solid_1 = require("@undefineds.co/drizzle-solid");
6
7
  const models_1 = require("@undefineds.co/models");
8
+ const reconciler_1 = require("../reconciler");
9
+ const protocol_metadata_1 = require("../protocol-metadata");
7
10
  const AuthContext_1 = require("../auth/AuthContext");
8
11
  const schema = {
9
12
  chat: models_1.chatResource,
@@ -12,7 +15,17 @@ const schema = {
12
15
  };
13
16
  class PodMatrixStore {
14
17
  constructor(options) {
18
+ this.logger = (0, global_logger_factory_1.getLoggerFor)(this);
15
19
  this.serverName = options.serverName;
20
+ this.serverGroupReconcilerService = options.serverGroupReconcilerService;
21
+ }
22
+ async getAccount(context) {
23
+ const matrixUserId = this.getMatrixUserId(context);
24
+ return {
25
+ userId: matrixUserId,
26
+ deviceId: this.deviceIdFromUserId(context.webId),
27
+ displayName: this.displayNameFromUserId(matrixUserId),
28
+ };
16
29
  }
17
30
  async createRoom(input, context) {
18
31
  const db = await this.getDb(context);
@@ -21,45 +34,48 @@ class PodMatrixStore {
21
34
  const roomId = this.generateRoomId(context);
22
35
  const chatId = this.chatResourceIdFromRoomId(roomId);
23
36
  const threadId = this.threadResourceIdFromRoomId(roomId);
37
+ const reconcilerOwner = 'server';
38
+ const coordination = (0, reconciler_1.reconcilerCoordinationMetadata)(reconcilerOwner);
24
39
  await db.insert(models_1.chatResource).values({
25
40
  id: chatId,
26
41
  title: input.name ?? roomId,
27
42
  description: input.topic ?? null,
28
- author: context.userId,
43
+ author: context.webId,
29
44
  status: 'active',
30
- participants: [context.userId],
31
- metadata: {
45
+ participants: [context.webId],
46
+ metadata: (0, protocol_metadata_1.withProtocolMetadata)({
32
47
  protocol: 'matrix',
48
+ ...coordination,
49
+ }, 'matrix', {
33
50
  roomId,
34
51
  canonicalAlias: input.room_alias_name ? `#${input.room_alias_name}:${this.getServerName(context)}` : null,
35
52
  visibility: input.visibility === 'public' ? 'public' : 'private',
36
53
  roomVersion: String(input.creation_content?.room_version ?? '11'),
37
54
  federate: input.creation_content?.['m.federate'] === true,
38
- members: [context.userId],
55
+ members: [context.webId],
39
56
  preset: input.preset,
40
- is_direct: input.is_direct,
41
57
  invite: input.invite ?? [],
42
- },
58
+ }),
43
59
  createdAt: new Date(now).toISOString(),
44
60
  updatedAt: new Date(now).toISOString(),
45
61
  });
46
62
  await db.insert(models_1.threadResource).values({
47
63
  id: threadId,
48
- chat: chatId,
64
+ parent: this.chatParentRefFromRoomId(roomId),
49
65
  title: input.name ?? roomId,
50
66
  status: 'active',
51
- metadata: {
67
+ metadata: (0, protocol_metadata_1.withProtocolMetadata)({
52
68
  protocol: 'matrix',
53
- roomId,
54
69
  commandKind: 'chat',
55
70
  surface_id: this.surfaceIdFromRoomId(roomId),
56
- chat_id: this.surfaceIdFromRoomId(roomId),
57
- },
71
+ ...coordination,
72
+ }, 'matrix', { roomId }),
58
73
  createdAt: new Date(now).toISOString(),
59
74
  updatedAt: new Date(now).toISOString(),
60
75
  });
61
76
  await this.appendEvent(db, {
62
77
  roomId,
78
+ reconcilerOwner,
63
79
  type: 'm.room.create',
64
80
  sender,
65
81
  originServerTs: now,
@@ -73,6 +89,7 @@ class PodMatrixStore {
73
89
  }, context);
74
90
  await this.appendEvent(db, {
75
91
  roomId,
92
+ reconcilerOwner,
76
93
  type: 'm.room.member',
77
94
  sender,
78
95
  originServerTs: now + 1,
@@ -85,6 +102,7 @@ class PodMatrixStore {
85
102
  if (input.name) {
86
103
  await this.appendEvent(db, {
87
104
  roomId,
105
+ reconcilerOwner,
88
106
  type: 'm.room.name',
89
107
  sender,
90
108
  originServerTs: now + 2,
@@ -95,6 +113,7 @@ class PodMatrixStore {
95
113
  if (input.topic) {
96
114
  await this.appendEvent(db, {
97
115
  roomId,
116
+ reconcilerOwner,
98
117
  type: 'm.room.topic',
99
118
  sender,
100
119
  originServerTs: now + 3,
@@ -105,6 +124,7 @@ class PodMatrixStore {
105
124
  for (const state of input.initial_state ?? []) {
106
125
  await this.appendEvent(db, {
107
126
  roomId,
127
+ reconcilerOwner,
108
128
  type: state.type,
109
129
  sender,
110
130
  originServerTs: Date.now(),
@@ -112,14 +132,40 @@ class PodMatrixStore {
112
132
  content: state.content ?? {},
113
133
  }, context);
114
134
  }
135
+ for (const invitee of input.invite ?? []) {
136
+ await this.appendMembershipEvent(db, roomId, invitee, 'invite', context, { sender, reconcilerOwner });
137
+ }
115
138
  return {
116
139
  roomId,
140
+ canonicalAlias: input.room_alias_name ? `#${input.room_alias_name}:${this.getServerName(context)}` : undefined,
117
141
  name: input.name,
118
142
  topic: input.topic,
119
143
  creator: sender,
144
+ reconcilerOwner: coordination.reconcilerOwner,
120
145
  createdAt: now,
121
146
  };
122
147
  }
148
+ async joinRoom(roomIdOrAlias, context) {
149
+ const db = await this.getDb(context);
150
+ const roomId = await this.resolveRoomId(db, roomIdOrAlias);
151
+ await this.ensureRoomExists(db, roomId);
152
+ const sender = this.getMatrixUserId(context);
153
+ const existing = await this.findLatestStateEvent(db, roomId, 'm.room.member', sender, context);
154
+ if (existing?.content.membership !== 'join') {
155
+ await this.appendMembershipEvent(db, roomId, sender, 'join', context);
156
+ }
157
+ return { roomId };
158
+ }
159
+ async inviteUser(roomId, userId, context) {
160
+ const db = await this.getDb(context);
161
+ await this.ensureRoomExists(db, roomId);
162
+ await this.appendMembershipEvent(db, roomId, userId, 'invite', context);
163
+ }
164
+ async leaveRoom(roomId, context) {
165
+ const db = await this.getDb(context);
166
+ await this.ensureRoomExists(db, roomId);
167
+ await this.appendMembershipEvent(db, roomId, this.getMatrixUserId(context), 'leave', context);
168
+ }
123
169
  async sendEvent(roomId, eventType, txnId, content, context) {
124
170
  const db = await this.getDb(context);
125
171
  await this.ensureRoomExists(db, roomId);
@@ -138,9 +184,21 @@ class PodMatrixStore {
138
184
  }, context);
139
185
  return event;
140
186
  }
187
+ async setState(roomId, eventType, stateKey, content, context) {
188
+ const db = await this.getDb(context);
189
+ await this.ensureRoomExists(db, roomId);
190
+ return this.appendEvent(db, {
191
+ roomId,
192
+ type: eventType,
193
+ sender: this.getMatrixUserId(context),
194
+ stateKey,
195
+ originServerTs: Date.now(),
196
+ content,
197
+ }, context);
198
+ }
141
199
  async sync(context, options = {}) {
142
200
  const db = await this.getDb(context);
143
- const rooms = await this.listRooms(db);
201
+ const rooms = await this.listJoinedRoomRecords(db, context);
144
202
  const sinceTs = this.parseSyncToken(options.since);
145
203
  const limit = options.limit && options.limit > 0 ? options.limit : 50;
146
204
  const join = {};
@@ -157,6 +215,9 @@ class PodMatrixStore {
157
215
  events: events.map((event) => this.toClientEvent(event)),
158
216
  limited: false,
159
217
  },
218
+ 'co.undefineds.coordination': {
219
+ reconcilerOwner: room.reconcilerOwner,
220
+ },
160
221
  };
161
222
  }
162
223
  return {
@@ -164,6 +225,25 @@ class PodMatrixStore {
164
225
  rooms: { join },
165
226
  };
166
227
  }
228
+ async listJoinedRooms(context) {
229
+ const db = await this.getDb(context);
230
+ return (await this.listJoinedRoomRecords(db, context)).map((room) => room.roomId);
231
+ }
232
+ async getMembers(roomId, context) {
233
+ const db = await this.getDb(context);
234
+ await this.ensureRoomExists(db, roomId);
235
+ const events = await this.listEvents(db, roomId, context, { newestFirst: true });
236
+ const latestByStateKey = new Map();
237
+ for (const event of events) {
238
+ if (event.type !== 'm.room.member' || event.stateKey === undefined || latestByStateKey.has(event.stateKey)) {
239
+ continue;
240
+ }
241
+ latestByStateKey.set(event.stateKey, event);
242
+ }
243
+ return Array.from(latestByStateKey.values())
244
+ .sort((left, right) => (left.originServerTs - right.originServerTs) || ((left.depth ?? 0) - (right.depth ?? 0)))
245
+ .map((event) => this.toClientEvent(event));
246
+ }
167
247
  async listMessages(roomId, context, options = {}) {
168
248
  const db = await this.getDb(context);
169
249
  await this.ensureRoomExists(db, roomId);
@@ -209,8 +289,15 @@ class PodMatrixStore {
209
289
  }
210
290
  const db = (0, drizzle_solid_1.drizzle)({
211
291
  fetch: this.createAccessTokenFetch(auth.accessToken, auth.tokenType),
212
- info: { webId: auth.webId, isLoggedIn: true },
213
- }, { schema });
292
+ info: {
293
+ webId: auth.webId,
294
+ isLoggedIn: true,
295
+ podUrl: context.podUrl,
296
+ },
297
+ }, {
298
+ schema,
299
+ podUrl: context.podUrl,
300
+ });
214
301
  await db.init(models_1.chatResource, models_1.threadResource, models_1.messageResource);
215
302
  context._matrixDb = db;
216
303
  return db;
@@ -235,12 +322,23 @@ class PodMatrixStore {
235
322
  const eventId = this.generateEventId(context);
236
323
  const depth = await this.nextEventDepth(db, input.roomId, context);
237
324
  const originIso = new Date(input.originServerTs).toISOString();
325
+ const needsRoomMetadata = input.reconcilerOwner === undefined
326
+ || (input.type === 'm.room.message' && this.serverGroupReconcilerService !== undefined);
327
+ const roomContext = needsRoomMetadata ? await this.getRoomContext(db, input.roomId) : undefined;
328
+ const roomMetadata = roomContext?.metadata;
329
+ const reconcilerOwner = input.reconcilerOwner ?? this.reconcilerOwnerFromRoomMetadata(roomMetadata);
330
+ const coordination = (0, reconciler_1.reconcilerCoordinationMetadata)(reconcilerOwner);
331
+ const messageResourceId = this.messageResourceIdFromEvent(input.roomId, eventId, input.originServerTs);
332
+ const thread = this.resolveDataResourceUriFromId(this.threadResourceIdFromRoomId(input.roomId), context);
333
+ const contentText = this.messageContentFromMatrixEvent(input.type, input.content);
334
+ const mentions = this.mentionsFromMatrixContent(input.content);
335
+ const routeTargetAgent = this.routeTargetAgentFromMatrixContent(input.content);
238
336
  const record = {
239
337
  eventId,
240
338
  roomId: input.roomId,
241
339
  type: input.type,
242
340
  sender: input.sender,
243
- senderWebId: context.userId,
341
+ senderWebId: context.webId,
244
342
  originServerTs: input.originServerTs,
245
343
  depth,
246
344
  txnId: input.txnId ?? undefined,
@@ -249,40 +347,93 @@ class PodMatrixStore {
249
347
  createdAt: originIso,
250
348
  };
251
349
  await db.insert(models_1.messageResource).values({
252
- id: this.messageResourceIdFromEvent(input.roomId, eventId, input.originServerTs),
350
+ id: messageResourceId,
351
+ parent: this.resolveDataResourceUriFromId(this.messageParentResourceIdFromRoomId(input.roomId), context),
253
352
  chat: this.chatResourceIdFromRoomId(input.roomId),
254
- thread: this.resolveDataResourceUriFromId(this.threadResourceIdFromRoomId(input.roomId), context),
255
- maker: context.userId,
353
+ thread,
354
+ maker: context.webId,
256
355
  role: input.type === 'm.room.message' ? models_1.MessageRole.USER : models_1.MessageRole.SYSTEM,
257
- content: this.messageContentFromMatrixEvent(input.type, input.content),
356
+ content: contentText,
258
357
  status: models_1.MessageStatus.SENT,
259
- metadata: {
358
+ mentions,
359
+ routeTargetAgent: routeTargetAgent ?? null,
360
+ metadata: (0, protocol_metadata_1.withProtocolMetadata)({
260
361
  protocol: 'matrix',
362
+ commandKind: 'chat',
363
+ surface_id: this.surfaceIdFromRoomId(input.roomId),
364
+ ...coordination,
365
+ }, 'matrix', {
261
366
  eventId,
262
367
  roomId: input.roomId,
263
368
  eventType: input.type,
264
369
  sender: input.sender,
265
- senderWebId: context.userId,
370
+ senderWebId: context.webId,
266
371
  originServerTs: input.originServerTs,
267
372
  depth,
268
373
  txnId: input.txnId ?? null,
269
374
  stateKey: input.stateKey ?? null,
270
375
  content: input.content,
271
- commandKind: 'chat',
272
- surface_id: this.surfaceIdFromRoomId(input.roomId),
273
- chat_id: this.surfaceIdFromRoomId(input.roomId),
274
- },
376
+ }),
275
377
  createdAt: originIso,
276
378
  updatedAt: originIso,
277
379
  });
380
+ await this.reconcileGroupUserMessage({
381
+ thread,
382
+ triggerMessage: this.resolveDataResourceUriFromId(messageResourceId, context),
383
+ actor: context.webId,
384
+ role: input.type === 'm.room.message' ? models_1.MessageRole.USER : models_1.MessageRole.SYSTEM,
385
+ content: contentText,
386
+ reconcilerOwner,
387
+ mentions,
388
+ routeTargetAgent,
389
+ participants: roomContext?.participants,
390
+ });
278
391
  return record;
279
392
  }
393
+ async appendMembershipEvent(db, roomId, memberUserId, membership, context, options = {}) {
394
+ const sender = options.sender ?? this.getMatrixUserId(context);
395
+ return this.appendEvent(db, {
396
+ roomId,
397
+ reconcilerOwner: options.reconcilerOwner,
398
+ type: 'm.room.member',
399
+ sender,
400
+ originServerTs: Date.now(),
401
+ stateKey: memberUserId,
402
+ content: {
403
+ membership,
404
+ displayname: this.displayNameFromUserId(memberUserId),
405
+ },
406
+ }, context);
407
+ }
280
408
  async listRooms(db) {
281
409
  const rooms = await db.select().from(models_1.chatResource);
282
410
  return rooms
283
411
  .map((room) => this.chatSourceToRoomRecord(room))
284
412
  .filter((room) => room !== undefined);
285
413
  }
414
+ async listJoinedRoomRecords(db, context) {
415
+ const rooms = await this.listRooms(db);
416
+ const matrixUserId = this.getMatrixUserId(context);
417
+ const joined = [];
418
+ for (const room of rooms) {
419
+ const membership = await this.findLatestStateEvent(db, room.roomId, 'm.room.member', matrixUserId, context);
420
+ if (!membership || membership.content.membership === 'join' || membership.content.membership === 'invite') {
421
+ joined.push(room);
422
+ }
423
+ }
424
+ return joined;
425
+ }
426
+ async resolveRoomId(db, roomIdOrAlias) {
427
+ if (!roomIdOrAlias.startsWith('#')) {
428
+ return roomIdOrAlias;
429
+ }
430
+ const rooms = await this.listRooms(db);
431
+ const room = rooms.find((candidate) => candidate.canonicalAlias === roomIdOrAlias);
432
+ if (!room) {
433
+ throw new Error(`Matrix room alias not found: ${roomIdOrAlias}`);
434
+ }
435
+ return room.roomId;
436
+ }
286
437
  async listEvents(db, roomId, context, options = {}) {
287
438
  const conditions = [
288
439
  (0, drizzle_solid_1.eq)(models_1.messageResource.thread, this.resolveDataResourceUriFromId(this.threadResourceIdFromRoomId(roomId), context)),
@@ -292,7 +443,7 @@ class PodMatrixStore {
292
443
  let query = db.select().from(models_1.messageResource).where((0, drizzle_solid_1.and)(...conditions));
293
444
  query = options.newestFirst
294
445
  ? query.orderBy((0, drizzle_solid_1.desc)(models_1.messageResource.createdAt))
295
- : query.orderBy(models_1.messageResource.createdAt);
446
+ : query.orderBy((0, drizzle_solid_1.asc)(models_1.messageResource.createdAt));
296
447
  if (options.limit && options.limit > 0) {
297
448
  query = query.limit(options.limit);
298
449
  }
@@ -317,20 +468,23 @@ class PodMatrixStore {
317
468
  }
318
469
  eventSourceToRecord(source) {
319
470
  const metadata = this.parseJsonObject(source.metadata) ?? {};
320
- const content = this.parseJsonObject(metadata.content)
471
+ const matrix = (0, protocol_metadata_1.getProtocolMetadata)(metadata, 'matrix') ?? {};
472
+ const content = this.parseJsonObject(matrix.content)
473
+ ?? this.parseJsonObject(metadata.content)
321
474
  ?? this.parseJsonObject(source.content)
322
475
  ?? {};
323
- const unsigned = this.parseJsonObject(metadata.unsigned);
324
- const stateKey = this.stringValue(metadata.stateKey);
325
- const txnId = this.stringValue(metadata.txnId);
476
+ const unsigned = this.parseJsonObject(matrix.unsigned)
477
+ ?? this.parseJsonObject(metadata.unsigned);
478
+ const stateKey = this.stringValue(matrix.stateKey ?? matrix.state_key ?? metadata.stateKey);
479
+ const txnId = this.stringValue(matrix.txnId ?? matrix.txn_id ?? metadata.txnId);
326
480
  return {
327
- eventId: this.stringValue(metadata.eventId) ?? source.id,
328
- roomId: this.stringValue(metadata.roomId) ?? '',
329
- type: this.stringValue(metadata.eventType) ?? 'm.room.message',
330
- sender: this.stringValue(metadata.sender) ?? '',
331
- senderWebId: this.stringValue(metadata.senderWebId) ?? source.maker ?? undefined,
332
- originServerTs: this.numberValue(metadata.originServerTs) ?? this.isoToMillis(source.createdAt) ?? Date.now(),
333
- depth: this.numberValue(metadata.depth),
481
+ eventId: this.stringValue(matrix.eventId ?? matrix.event_id ?? metadata.eventId) ?? source.id,
482
+ roomId: this.stringValue(matrix.roomId ?? matrix.room_id ?? metadata.roomId) ?? '',
483
+ type: this.stringValue(matrix.eventType ?? matrix.event_type ?? metadata.eventType) ?? 'm.room.message',
484
+ sender: this.stringValue(matrix.sender ?? metadata.sender) ?? '',
485
+ senderWebId: this.stringValue(matrix.senderWebId ?? matrix.sender_web_id ?? metadata.senderWebId) ?? source.maker ?? undefined,
486
+ originServerTs: this.numberValue(matrix.originServerTs ?? matrix.origin_server_ts ?? metadata.originServerTs) ?? this.isoToMillis(source.createdAt) ?? Date.now(),
487
+ depth: this.numberValue(matrix.depth ?? metadata.depth),
334
488
  txnId: txnId ?? undefined,
335
489
  content,
336
490
  stateKey: stateKey ?? undefined,
@@ -342,15 +496,20 @@ class PodMatrixStore {
342
496
  if (metadata.protocol !== 'matrix') {
343
497
  return undefined;
344
498
  }
345
- const roomId = this.stringValue(metadata.roomId);
499
+ const matrix = (0, protocol_metadata_1.getProtocolMetadata)(metadata, 'matrix') ?? {};
500
+ const roomId = this.stringValue(matrix.roomId ?? matrix.room_id ?? metadata.roomId);
346
501
  if (!roomId) {
347
502
  return undefined;
348
503
  }
504
+ const reconcilerOwner = (0, reconciler_1.normalizeReconcilerOwner)(metadata.reconcilerOwner, 'server');
505
+ const coordination = (0, reconciler_1.reconcilerCoordinationMetadata)(reconcilerOwner);
349
506
  return {
350
507
  roomId,
508
+ canonicalAlias: this.stringValue(matrix.canonicalAlias ?? matrix.canonical_alias ?? metadata.canonicalAlias),
351
509
  name: source.title ?? undefined,
352
510
  topic: source.description ?? undefined,
353
511
  creator: source.author ?? '',
512
+ reconcilerOwner: coordination.reconcilerOwner,
354
513
  createdAt: this.isoToMillis(source.createdAt) ?? 0,
355
514
  };
356
515
  }
@@ -395,15 +554,59 @@ class PodMatrixStore {
395
554
  }
396
555
  return Number.isFinite(value) ? value : undefined;
397
556
  }
557
+ async getRoomContext(db, roomId) {
558
+ const room = await db.findById(models_1.chatResource, this.chatResourceIdFromRoomId(roomId));
559
+ return {
560
+ metadata: this.parseJsonObject(room?.metadata),
561
+ participants: (0, reconciler_1.normalizeAgentUris)(room?.participants),
562
+ };
563
+ }
564
+ reconcilerOwnerFromRoomMetadata(metadata) {
565
+ return (0, reconciler_1.normalizeReconcilerOwner)(metadata?.reconcilerOwner, 'server');
566
+ }
567
+ async reconcileGroupUserMessage(input) {
568
+ if (!this.serverGroupReconcilerService || input.role !== models_1.MessageRole.USER) {
569
+ return;
570
+ }
571
+ try {
572
+ await this.serverGroupReconcilerService.reconcileThreadMessage({
573
+ thread: input.thread,
574
+ triggerMessage: input.triggerMessage,
575
+ actor: input.actor,
576
+ role: 'user',
577
+ content: input.content,
578
+ reconcilerOwner: input.reconcilerOwner,
579
+ mentions: input.mentions,
580
+ routeTargetAgent: input.routeTargetAgent,
581
+ participants: input.participants,
582
+ });
583
+ }
584
+ catch (error) {
585
+ this.logger.warn(`Failed to enqueue Matrix group Reconciler wake: ${error}`);
586
+ }
587
+ }
398
588
  messageContentFromMatrixEvent(eventType, content) {
399
589
  if (eventType === 'm.room.message' && typeof content.body === 'string') {
400
590
  return content.body;
401
591
  }
402
592
  return JSON.stringify(content);
403
593
  }
594
+ mentionsFromMatrixContent(content) {
595
+ const matrixMentions = this.parseJsonObject(content['m.mentions']);
596
+ return (0, reconciler_1.normalizeAgentUris)([
597
+ ...(0, reconciler_1.normalizeAgentUris)(content.mentions),
598
+ ...(0, reconciler_1.normalizeAgentUris)(content['co.undefineds.mentions']),
599
+ ...(0, reconciler_1.normalizeAgentUris)(matrixMentions?.agents),
600
+ ]);
601
+ }
602
+ routeTargetAgentFromMatrixContent(content) {
603
+ return this.stringValue(content.routeTargetAgent)
604
+ ?? this.stringValue(content['co.undefineds.routeTargetAgent'])
605
+ ?? this.stringValue(content['co.undefineds.route_target_agent']);
606
+ }
404
607
  getMatrixUserId(context) {
405
608
  const serverName = this.getServerName(context);
406
- const localpart = this.localpartFromUserId(context.userId);
609
+ const localpart = this.localpartFromUserId(context.webId);
407
610
  return `@${localpart}:${serverName}`;
408
611
  }
409
612
  getServerName(context) {
@@ -411,7 +614,7 @@ class PodMatrixStore {
411
614
  return this.serverName;
412
615
  }
413
616
  try {
414
- return new URL(context.userId).host || 'localhost';
617
+ return new URL(context.webId).host || 'localhost';
415
618
  }
416
619
  catch {
417
620
  return 'localhost';
@@ -436,6 +639,9 @@ class PodMatrixStore {
436
639
  generateEventId(context) {
437
640
  return `$${this.randomId(24)}:${this.getServerName(context)}`;
438
641
  }
642
+ deviceIdFromUserId(userId) {
643
+ return `XPOD${(0, node_crypto_1.createHash)('sha256').update(userId).digest('hex').slice(0, 12).toUpperCase()}`;
644
+ }
439
645
  randomId(size) {
440
646
  return (0, node_crypto_1.randomBytes)(size).toString('base64url');
441
647
  }
@@ -448,15 +654,21 @@ class PodMatrixStore {
448
654
  chatResourceIdFromRoomId(roomId) {
449
655
  return `${this.surfaceIdFromRoomId(roomId)}/index.ttl#this`;
450
656
  }
657
+ messageParentResourceIdFromRoomId(roomId) {
658
+ return `chat/${this.surfaceIdFromRoomId(roomId)}/index.ttl#this`;
659
+ }
451
660
  threadResourceIdFromRoomId(roomId) {
452
661
  return `chat/${this.surfaceIdFromRoomId(roomId)}/index.ttl#thread`;
453
662
  }
663
+ chatParentRefFromRoomId(roomId) {
664
+ return `/.data/chat/${this.chatResourceIdFromRoomId(roomId)}`;
665
+ }
454
666
  messageResourceIdFromEvent(roomId, eventId, ts) {
455
667
  const { yyyy, MM, dd } = this.dateParts(ts);
456
668
  return `chat/${this.surfaceIdFromRoomId(roomId)}/${yyyy}/${MM}/${dd}/messages.ttl#${this.slug(eventId)}`;
457
669
  }
458
670
  resolveDataResourceUriFromId(resourceId, context) {
459
- const podBaseUrl = this.derivePodBaseUrl((0, AuthContext_1.getWebId)(context.auth) ?? context.userId);
671
+ const podBaseUrl = context.podUrl ?? this.derivePodBaseUrl(context.webId);
460
672
  if (!podBaseUrl) {
461
673
  return resourceId;
462
674
  }