@tagea/capacitor-matrix 1.1.1 → 1.2.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.
package/README.md CHANGED
@@ -370,6 +370,8 @@ The full API reference is auto-generated below from the TypeScript definitions.
370
370
  * [`addListener('typingChanged', ...)`](#addlistenertypingchanged-)
371
371
  * [`addListener('receiptReceived', ...)`](#addlistenerreceiptreceived-)
372
372
  * [`addListener('presenceChanged', ...)`](#addlistenerpresencechanged-)
373
+ * [`updateAccessToken(...)`](#updateaccesstoken)
374
+ * [`addListener('tokenRefreshRequired', ...)`](#addlistenertokenrefreshrequired-)
373
375
  * [`removeAllListeners()`](#removealllisteners)
374
376
  * [Interfaces](#interfaces)
375
377
  * [Type Aliases](#type-aliases)
@@ -1155,6 +1157,35 @@ addListener(event: 'presenceChanged', listenerFunc: (data: PresenceChangedEvent)
1155
1157
  --------------------
1156
1158
 
1157
1159
 
1160
+ ### updateAccessToken(...)
1161
+
1162
+ ```typescript
1163
+ updateAccessToken(options: { accessToken: string; }) => Promise<void>
1164
+ ```
1165
+
1166
+ | Param | Type |
1167
+ | ------------- | ------------------------------------- |
1168
+ | **`options`** | <code>{ accessToken: string; }</code> |
1169
+
1170
+ --------------------
1171
+
1172
+
1173
+ ### addListener('tokenRefreshRequired', ...)
1174
+
1175
+ ```typescript
1176
+ addListener(event: 'tokenRefreshRequired', listenerFunc: () => void) => Promise<PluginListenerHandle>
1177
+ ```
1178
+
1179
+ | Param | Type |
1180
+ | ------------------ | ----------------------------------- |
1181
+ | **`event`** | <code>'tokenRefreshRequired'</code> |
1182
+ | **`listenerFunc`** | <code>() =&gt; void</code> |
1183
+
1184
+ **Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;</code>
1185
+
1186
+ --------------------
1187
+
1188
+
1158
1189
  ### removeAllListeners()
1159
1190
 
1160
1191
  ```typescript
@@ -1198,18 +1229,31 @@ removeAllListeners() => Promise<void>
1198
1229
 
1199
1230
  #### RoomSummary
1200
1231
 
1201
- | Prop | Type |
1202
- | ----------------- | --------------------------------------------------- |
1203
- | **`roomId`** | <code>string</code> |
1204
- | **`name`** | <code>string</code> |
1205
- | **`topic`** | <code>string</code> |
1206
- | **`memberCount`** | <code>number</code> |
1207
- | **`isEncrypted`** | <code>boolean</code> |
1208
- | **`unreadCount`** | <code>number</code> |
1209
- | **`lastEventTs`** | <code>number</code> |
1210
- | **`membership`** | <code>'join' \| 'invite' \| 'leave' \| 'ban'</code> |
1211
- | **`avatarUrl`** | <code>string</code> |
1212
- | **`isDirect`** | <code>boolean</code> |
1232
+ | Prop | Type |
1233
+ | ----------------- | ----------------------------------------------------------------- |
1234
+ | **`roomId`** | <code>string</code> |
1235
+ | **`name`** | <code>string</code> |
1236
+ | **`topic`** | <code>string</code> |
1237
+ | **`memberCount`** | <code>number</code> |
1238
+ | **`isEncrypted`** | <code>boolean</code> |
1239
+ | **`unreadCount`** | <code>number</code> |
1240
+ | **`lastEventTs`** | <code>number</code> |
1241
+ | **`membership`** | <code>'join' \| 'invite' \| 'leave' \| 'ban'</code> |
1242
+ | **`avatarUrl`** | <code>string</code> |
1243
+ | **`isDirect`** | <code>boolean</code> |
1244
+ | **`latestEvent`** | <code><a href="#latesteventpreview">LatestEventPreview</a></code> |
1245
+
1246
+
1247
+ #### LatestEventPreview
1248
+
1249
+ | Prop | Type |
1250
+ | ----------------------- | ---------------------------------------------------------------- |
1251
+ | **`roomId`** | <code>string</code> |
1252
+ | **`senderId`** | <code>string</code> |
1253
+ | **`type`** | <code>string</code> |
1254
+ | **`content`** | <code><a href="#record">Record</a>&lt;string, unknown&gt;</code> |
1255
+ | **`originServerTs`** | <code>number</code> |
1256
+ | **`senderDisplayName`** | <code>string</code> |
1213
1257
 
1214
1258
 
1215
1259
  #### RoomMember
@@ -186,6 +186,53 @@ class MatrixSDKBridge(private val context: Context) {
186
186
  return sessionStore.load()
187
187
  }
188
188
 
189
+ suspend fun updateAccessToken(accessToken: String) {
190
+ requireClient()
191
+
192
+ // Stop sync service and clean up references
193
+ syncService?.stop()
194
+ syncService = null
195
+ receiptSyncJob?.cancel()
196
+ receiptSyncJob = null
197
+ receiptCache.clear()
198
+ timelineListenerHandles.clear()
199
+ roomTimelines.clear()
200
+ subscribedRoomIds.clear()
201
+
202
+ val oldSession = sessionStore.load()
203
+ ?: throw IllegalStateException("No persisted session to update")
204
+
205
+ // Build a new client pointing to the same data directory (preserves crypto store).
206
+ // The Rust SDK's restoreSession() can only be called once per Client instance.
207
+ val safeUserId = oldSession.userId.replace(Regex("[^a-zA-Z0-9_.-]"), "_")
208
+ val dataDir = context.filesDir.resolve("matrix_sdk/$safeUserId")
209
+ dataDir.mkdirs()
210
+ val dataDirPath = dataDir.absolutePath
211
+
212
+ val newClient = ClientBuilder()
213
+ .homeserverUrl(oldSession.homeserverUrl)
214
+ .slidingSyncVersionBuilder(SlidingSyncVersionBuilder.NATIVE)
215
+ .autoEnableCrossSigning(true)
216
+ .sqliteStore(SqliteStoreBuilder(dataDirPath, dataDirPath))
217
+ .build()
218
+
219
+ val newSession = Session(
220
+ accessToken = accessToken,
221
+ refreshToken = null,
222
+ userId = oldSession.userId,
223
+ deviceId = oldSession.deviceId,
224
+ homeserverUrl = oldSession.homeserverUrl,
225
+ oidcData = null,
226
+ slidingSyncVersion = SlidingSyncVersion.NATIVE,
227
+ )
228
+
229
+ newClient.restoreSession(newSession)
230
+ client = newClient
231
+
232
+ val updatedInfo = oldSession.copy(accessToken = accessToken)
233
+ sessionStore.save(updatedInfo)
234
+ }
235
+
189
236
  // ── Sync ──────────────────────────────────────────────
190
237
 
191
238
  suspend fun startSync(
@@ -997,6 +1044,101 @@ class MatrixSDKBridge(private val context: Context) {
997
1044
  )
998
1045
  }
999
1046
 
1047
+ // ── Presence ─────────────────────────────────────────
1048
+
1049
+ suspend fun setPresence(presence: String, statusMsg: String?) {
1050
+ val session = sessionStore.load() ?: throw IllegalStateException("Not logged in")
1051
+ val baseUrl = session.homeserverUrl.trimEnd('/')
1052
+ val encodedUserId = URLEncoder.encode(session.userId, "UTF-8")
1053
+ val url = URL("$baseUrl/_matrix/client/v3/presence/$encodedUserId/status")
1054
+ val connection = url.openConnection() as HttpURLConnection
1055
+ connection.requestMethod = "PUT"
1056
+ connection.setRequestProperty("Authorization", "Bearer ${session.accessToken}")
1057
+ connection.setRequestProperty("Content-Type", "application/json")
1058
+ connection.doOutput = true
1059
+
1060
+ val body = org.json.JSONObject()
1061
+ body.put("presence", presence)
1062
+ if (statusMsg != null) body.put("status_msg", statusMsg)
1063
+ val writer = OutputStreamWriter(connection.outputStream)
1064
+ writer.write(body.toString())
1065
+ writer.flush()
1066
+ writer.close()
1067
+
1068
+ val responseCode = connection.responseCode
1069
+ if (responseCode !in 200..299) {
1070
+ throw Exception("setPresence failed with status $responseCode")
1071
+ }
1072
+ }
1073
+
1074
+ suspend fun getPresence(userId: String): Map<String, Any?> {
1075
+ val session = sessionStore.load() ?: throw IllegalStateException("Not logged in")
1076
+ val baseUrl = session.homeserverUrl.trimEnd('/')
1077
+ val encodedUserId = URLEncoder.encode(userId, "UTF-8")
1078
+ val url = URL("$baseUrl/_matrix/client/v3/presence/$encodedUserId/status")
1079
+ val connection = url.openConnection() as HttpURLConnection
1080
+ connection.requestMethod = "GET"
1081
+ connection.setRequestProperty("Authorization", "Bearer ${session.accessToken}")
1082
+
1083
+ val responseCode = connection.responseCode
1084
+ if (responseCode !in 200..299) {
1085
+ throw Exception("getPresence failed with status $responseCode")
1086
+ }
1087
+
1088
+ val responseBody = connection.inputStream.bufferedReader().readText()
1089
+ val json = org.json.JSONObject(responseBody)
1090
+ return mapOf(
1091
+ "presence" to json.optString("presence", "offline"),
1092
+ "statusMsg" to if (json.has("status_msg")) json.getString("status_msg") else null,
1093
+ "lastActiveAgo" to if (json.has("last_active_ago")) json.getLong("last_active_ago") else null,
1094
+ )
1095
+ }
1096
+
1097
+ // ── Pushers ───────────────────────────────────────────
1098
+
1099
+ suspend fun setPusher(
1100
+ pushkey: String,
1101
+ kind: String?,
1102
+ appId: String,
1103
+ appDisplayName: String,
1104
+ deviceDisplayName: String,
1105
+ lang: String,
1106
+ dataUrl: String,
1107
+ dataFormat: String?,
1108
+ ) {
1109
+ val session = sessionStore.load() ?: throw IllegalStateException("Not logged in")
1110
+ val baseUrl = session.homeserverUrl.trimEnd('/')
1111
+ val url = URL("$baseUrl/_matrix/client/v3/pushers/set")
1112
+ val connection = url.openConnection() as HttpURLConnection
1113
+ connection.requestMethod = "POST"
1114
+ connection.setRequestProperty("Authorization", "Bearer ${session.accessToken}")
1115
+ connection.setRequestProperty("Content-Type", "application/json")
1116
+ connection.doOutput = true
1117
+
1118
+ val dataObj = org.json.JSONObject()
1119
+ dataObj.put("url", dataUrl)
1120
+ if (dataFormat != null) dataObj.put("format", dataFormat)
1121
+
1122
+ val body = org.json.JSONObject()
1123
+ body.put("pushkey", pushkey)
1124
+ body.put("kind", if (kind != null) kind else org.json.JSONObject.NULL)
1125
+ body.put("app_id", appId)
1126
+ body.put("app_display_name", appDisplayName)
1127
+ body.put("device_display_name", deviceDisplayName)
1128
+ body.put("lang", lang)
1129
+ body.put("data", dataObj)
1130
+
1131
+ val writer = OutputStreamWriter(connection.outputStream)
1132
+ writer.write(body.toString())
1133
+ writer.flush()
1134
+ writer.close()
1135
+
1136
+ val responseCode = connection.responseCode
1137
+ if (responseCode !in 200..299) {
1138
+ throw Exception("setPusher failed with status $responseCode")
1139
+ }
1140
+ }
1141
+
1000
1142
  // ── Helpers ───────────────────────────────────────────
1001
1143
 
1002
1144
  private fun requireClient(): Client {
@@ -54,6 +54,20 @@ class MatrixPlugin : Plugin() {
54
54
  }
55
55
  }
56
56
 
57
+ @PluginMethod
58
+ fun updateAccessToken(call: PluginCall) {
59
+ val accessToken = call.getString("accessToken") ?: return call.reject("Missing accessToken")
60
+
61
+ scope.launch {
62
+ try {
63
+ bridge.updateAccessToken(accessToken)
64
+ call.resolve()
65
+ } catch (e: Exception) {
66
+ call.reject(e.message ?: "updateAccessToken failed", e)
67
+ }
68
+ }
69
+ }
70
+
57
71
  @PluginMethod
58
72
  fun logout(call: PluginCall) {
59
73
  scope.launch {
@@ -530,7 +544,24 @@ class MatrixPlugin : Plugin() {
530
544
 
531
545
  @PluginMethod
532
546
  fun setPusher(call: PluginCall) {
533
- call.reject("setPusher is not yet supported on this platform")
547
+ val pushkey = call.getString("pushkey") ?: return call.reject("Missing pushkey")
548
+ val kind = call.getString("kind")
549
+ val appId = call.getString("appId") ?: return call.reject("Missing appId")
550
+ val appDisplayName = call.getString("appDisplayName") ?: return call.reject("Missing appDisplayName")
551
+ val deviceDisplayName = call.getString("deviceDisplayName") ?: return call.reject("Missing deviceDisplayName")
552
+ val lang = call.getString("lang") ?: return call.reject("Missing lang")
553
+ val dataObj = call.getObject("data") ?: return call.reject("Missing data")
554
+ val dataUrl = dataObj.getString("url") ?: return call.reject("Missing data.url")
555
+ val dataFormat = dataObj.optString("format", null)
556
+
557
+ scope.launch {
558
+ try {
559
+ bridge.setPusher(pushkey, kind, appId, appDisplayName, deviceDisplayName, lang, dataUrl, dataFormat)
560
+ call.resolve()
561
+ } catch (e: Exception) {
562
+ call.reject(e.message ?: "setPusher failed", e)
563
+ }
564
+ }
534
565
  }
535
566
 
536
567
  @PluginMethod
@@ -625,12 +656,31 @@ class MatrixPlugin : Plugin() {
625
656
 
626
657
  @PluginMethod
627
658
  fun setPresence(call: PluginCall) {
628
- call.reject("setPresence is not supported on this platform")
659
+ val presence = call.getString("presence") ?: return call.reject("Missing presence")
660
+ val statusMsg = call.getString("statusMsg")
661
+
662
+ scope.launch {
663
+ try {
664
+ bridge.setPresence(presence, statusMsg)
665
+ call.resolve()
666
+ } catch (e: Exception) {
667
+ call.reject(e.message ?: "setPresence failed", e)
668
+ }
669
+ }
629
670
  }
630
671
 
631
672
  @PluginMethod
632
673
  fun getPresence(call: PluginCall) {
633
- call.reject("getPresence is not supported on this platform")
674
+ val userId = call.getString("userId") ?: return call.reject("Missing userId")
675
+
676
+ scope.launch {
677
+ try {
678
+ val result = bridge.getPresence(userId)
679
+ call.resolve(mapToJSObject(result))
680
+ } catch (e: Exception) {
681
+ call.reject(e.message ?: "getPresence failed", e)
682
+ }
683
+ }
634
684
  }
635
685
 
636
686
  @PluginMethod
package/dist/docs.json CHANGED
@@ -946,6 +946,45 @@
946
946
  ],
947
947
  "slug": "addlistenerpresencechanged-"
948
948
  },
949
+ {
950
+ "name": "updateAccessToken",
951
+ "signature": "(options: { accessToken: string; }) => Promise<void>",
952
+ "parameters": [
953
+ {
954
+ "name": "options",
955
+ "docs": "",
956
+ "type": "{ accessToken: string; }"
957
+ }
958
+ ],
959
+ "returns": "Promise<void>",
960
+ "tags": [],
961
+ "docs": "",
962
+ "complexTypes": [],
963
+ "slug": "updateaccesstoken"
964
+ },
965
+ {
966
+ "name": "addListener",
967
+ "signature": "(event: 'tokenRefreshRequired', listenerFunc: () => void) => Promise<PluginListenerHandle>",
968
+ "parameters": [
969
+ {
970
+ "name": "event",
971
+ "docs": "",
972
+ "type": "'tokenRefreshRequired'"
973
+ },
974
+ {
975
+ "name": "listenerFunc",
976
+ "docs": "",
977
+ "type": "() => void"
978
+ }
979
+ ],
980
+ "returns": "Promise<PluginListenerHandle>",
981
+ "tags": [],
982
+ "docs": "",
983
+ "complexTypes": [
984
+ "PluginListenerHandle"
985
+ ],
986
+ "slug": "addlistenertokenrefreshrequired-"
987
+ },
949
988
  {
950
989
  "name": "removeAllListeners",
951
990
  "signature": "() => Promise<void>",
@@ -1140,6 +1179,68 @@
1140
1179
  "docs": "",
1141
1180
  "complexTypes": [],
1142
1181
  "type": "boolean | undefined"
1182
+ },
1183
+ {
1184
+ "name": "latestEvent",
1185
+ "tags": [],
1186
+ "docs": "",
1187
+ "complexTypes": [
1188
+ "LatestEventPreview"
1189
+ ],
1190
+ "type": "LatestEventPreview"
1191
+ }
1192
+ ]
1193
+ },
1194
+ {
1195
+ "name": "LatestEventPreview",
1196
+ "slug": "latesteventpreview",
1197
+ "docs": "",
1198
+ "tags": [],
1199
+ "methods": [],
1200
+ "properties": [
1201
+ {
1202
+ "name": "roomId",
1203
+ "tags": [],
1204
+ "docs": "",
1205
+ "complexTypes": [],
1206
+ "type": "string"
1207
+ },
1208
+ {
1209
+ "name": "senderId",
1210
+ "tags": [],
1211
+ "docs": "",
1212
+ "complexTypes": [],
1213
+ "type": "string"
1214
+ },
1215
+ {
1216
+ "name": "type",
1217
+ "tags": [],
1218
+ "docs": "",
1219
+ "complexTypes": [],
1220
+ "type": "string"
1221
+ },
1222
+ {
1223
+ "name": "content",
1224
+ "tags": [],
1225
+ "docs": "",
1226
+ "complexTypes": [
1227
+ "Record"
1228
+ ],
1229
+ "type": "Record<string, unknown>"
1230
+ },
1231
+ {
1232
+ "name": "originServerTs",
1233
+ "tags": [],
1234
+ "docs": "",
1235
+ "complexTypes": [],
1236
+ "type": "number"
1237
+ },
1238
+ {
1239
+ "name": "senderDisplayName",
1240
+ "tags": [],
1241
+ "docs": "",
1242
+ "complexTypes": [],
1243
+ "type": "string | undefined"
1143
1244
  }
1144
1245
  ]
1145
1246
  },
@@ -115,6 +115,14 @@ export interface MatrixEvent {
115
115
  /** Unsigned data (e.g. m.relations for edits, transaction_id for local echo) */
116
116
  unsigned?: Record<string, unknown>;
117
117
  }
118
+ export interface LatestEventPreview {
119
+ roomId: string;
120
+ senderId: string;
121
+ type: string;
122
+ content: Record<string, unknown>;
123
+ originServerTs: number;
124
+ senderDisplayName?: string;
125
+ }
118
126
  export interface RoomSummary {
119
127
  roomId: string;
120
128
  name: string;
@@ -126,6 +134,7 @@ export interface RoomSummary {
126
134
  membership?: 'join' | 'invite' | 'leave' | 'ban';
127
135
  avatarUrl?: string;
128
136
  isDirect?: boolean;
137
+ latestEvent?: LatestEventPreview;
129
138
  }
130
139
  export interface RoomMember {
131
140
  userId: string;
@@ -388,5 +397,9 @@ export interface MatrixPlugin {
388
397
  addListener(event: 'typingChanged', listenerFunc: (data: TypingEvent) => void): Promise<PluginListenerHandle>;
389
398
  addListener(event: 'receiptReceived', listenerFunc: (data: ReceiptReceivedEvent) => void): Promise<PluginListenerHandle>;
390
399
  addListener(event: 'presenceChanged', listenerFunc: (data: PresenceChangedEvent) => void): Promise<PluginListenerHandle>;
400
+ updateAccessToken(options: {
401
+ accessToken: string;
402
+ }): Promise<void>;
403
+ addListener(event: 'tokenRefreshRequired', listenerFunc: () => void): Promise<PluginListenerHandle>;
391
404
  removeAllListeners(): Promise<void>;
392
405
  }
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\n// Auth & Session\n\nexport interface LoginOptions {\n homeserverUrl: string;\n userId: string;\n password: string;\n}\n\nexport interface LoginWithTokenOptions {\n homeserverUrl: string;\n accessToken: string;\n userId: string;\n deviceId: string;\n}\n\nexport interface SessionInfo {\n accessToken: string;\n userId: string;\n deviceId: string;\n homeserverUrl: string;\n}\n\n// Messaging\n\nexport interface SendMessageOptions {\n roomId: string;\n body: string;\n msgtype?: 'm.text' | 'm.notice' | 'm.emote' | 'm.image' | 'm.audio' | 'm.video' | 'm.file';\n fileUri?: string;\n fileName?: string;\n mimeType?: string;\n fileSize?: number;\n /** Audio/video duration in milliseconds (sets info.duration per Matrix spec) */\n duration?: number;\n /** Image/video width in pixels (sets info.w per Matrix spec) */\n width?: number;\n /** Image/video height in pixels (sets info.h per Matrix spec) */\n height?: number;\n}\n\n// Presence\n\nexport interface PresenceInfo {\n presence: 'online' | 'offline' | 'unavailable';\n statusMsg?: string;\n lastActiveAgo?: number;\n}\n\n// Typing\n\nexport interface TypingEvent {\n roomId: string;\n userIds: string[];\n}\n\nexport interface ReceiptReceivedEvent {\n roomId: string;\n /** The event that was read */\n eventId: string;\n /** The user who sent the read receipt */\n userId: string;\n}\n\nexport interface PresenceChangedEvent {\n userId: string;\n presence: PresenceInfo;\n}\n\n// Edit & Reply\n\nexport interface EditMessageOptions {\n roomId: string;\n eventId: string;\n newBody: string;\n /** Required when editing a media message; must match the original msgtype */\n msgtype?: 'm.text' | 'm.notice' | 'm.emote' | 'm.image' | 'm.audio' | 'm.video' | 'm.file';\n /** New file to replace the media content (optional for caption-only edits) */\n fileUri?: string;\n fileName?: string;\n mimeType?: string;\n fileSize?: number;\n /** Audio/video duration in milliseconds */\n duration?: number;\n /** Image/video width in pixels */\n width?: number;\n /** Image/video height in pixels */\n height?: number;\n}\n\nexport interface SendReplyOptions {\n roomId: string;\n body: string;\n replyToEventId: string;\n msgtype?: 'm.text' | 'm.notice' | 'm.emote' | 'm.image' | 'm.audio' | 'm.video' | 'm.file';\n fileUri?: string;\n fileName?: string;\n mimeType?: string;\n fileSize?: number;\n /** Audio/video duration in milliseconds (sets info.duration per Matrix spec) */\n duration?: number;\n /** Image/video width in pixels (sets info.w per Matrix spec) */\n width?: number;\n /** Image/video height in pixels (sets info.h per Matrix spec) */\n height?: number;\n}\n\n// Upload\n\nexport interface UploadContentOptions {\n fileUri: string;\n fileName: string;\n mimeType: string;\n}\n\nexport interface UploadContentResult {\n contentUri: string;\n}\n\n// Thumbnail\n\nexport interface ThumbnailUrlOptions {\n mxcUrl: string;\n width: number;\n height: number;\n method?: 'scale' | 'crop';\n}\n\nexport interface MatrixEvent {\n eventId: string;\n roomId: string;\n senderId: string;\n type: string;\n /** State key for state events (e.g. target user ID for m.room.member) */\n stateKey?: string;\n content: Record<string, unknown>;\n originServerTs: number;\n /** Delivery/read status for own messages: 'sending' | 'sent' | 'delivered' | 'read' */\n status?: 'sending' | 'sent' | 'delivered' | 'read';\n /** User IDs that have read this event */\n readBy?: string[];\n /** Unsigned data (e.g. m.relations for edits, transaction_id for local echo) */\n unsigned?: Record<string, unknown>;\n}\n\n// Rooms\n\nexport interface RoomSummary {\n roomId: string;\n name: string;\n topic?: string;\n memberCount: number;\n isEncrypted: boolean;\n unreadCount: number;\n lastEventTs?: number;\n membership?: 'join' | 'invite' | 'leave' | 'ban';\n avatarUrl?: string;\n isDirect?: boolean;\n}\n\nexport interface RoomMember {\n userId: string;\n displayName?: string;\n membership: 'join' | 'invite' | 'leave' | 'ban';\n avatarUrl?: string;\n}\n\n// Device Management\n\nexport interface DeviceInfo {\n deviceId: string;\n displayName?: string;\n lastSeenTs?: number;\n lastSeenIp?: string;\n /** Whether this device is verified via cross-signing */\n isCrossSigningVerified?: boolean;\n}\n\n// Pusher\n\nexport interface PusherOptions {\n pushkey: string;\n kind: string | null;\n appId: string;\n appDisplayName: string;\n deviceDisplayName: string;\n lang: string;\n data: { url: string; format?: string };\n}\n\n// User Discovery\n\nexport interface UserProfile {\n userId: string;\n displayName?: string;\n avatarUrl?: string;\n}\n\n// Encryption\n\nexport interface CrossSigningStatus {\n hasMaster: boolean;\n hasSelfSigning: boolean;\n hasUserSigning: boolean;\n isReady: boolean;\n}\n\nexport interface KeyBackupStatus {\n exists: boolean;\n version?: string;\n enabled: boolean;\n}\n\nexport interface RecoveryKeyInfo {\n recoveryKey: string;\n}\n\nexport interface EncryptionStatus {\n isCrossSigningReady: boolean;\n crossSigningStatus: CrossSigningStatus;\n isKeyBackupEnabled: boolean;\n keyBackupVersion?: string;\n isSecretStorageReady: boolean;\n}\n\n// Events & Sync\n\nexport type SyncState = 'INITIAL' | 'SYNCING' | 'ERROR' | 'STOPPED';\n\nexport interface SyncStateChangeEvent {\n state: SyncState;\n error?: string;\n}\n\nexport interface MessageReceivedEvent {\n event: MatrixEvent;\n}\n\nexport interface RoomUpdatedEvent {\n roomId: string;\n summary: RoomSummary;\n}\n\n// Plugin Interface\n\nexport interface MatrixPlugin {\n // Auth\n login(options: LoginOptions): Promise<SessionInfo>;\n loginWithToken(options: LoginWithTokenOptions): Promise<SessionInfo>;\n logout(): Promise<void>;\n getSession(): Promise<SessionInfo | null>;\n\n // Sync\n startSync(): Promise<void>;\n stopSync(): Promise<void>;\n getSyncState(): Promise<{ state: SyncState }>;\n\n // Rooms\n createRoom(options: {\n name?: string;\n topic?: string;\n isEncrypted?: boolean;\n isDirect?: boolean;\n invite?: string[];\n preset?: 'private_chat' | 'trusted_private_chat' | 'public_chat';\n historyVisibility?: 'invited' | 'joined' | 'shared' | 'world_readable';\n }): Promise<{ roomId: string }>;\n getRooms(): Promise<{ rooms: RoomSummary[] }>;\n getRoomMembers(options: { roomId: string }): Promise<{ members: RoomMember[] }>;\n joinRoom(options: { roomIdOrAlias: string }): Promise<{ roomId: string }>;\n leaveRoom(options: { roomId: string }): Promise<void>;\n forgetRoom(options: { roomId: string }): Promise<void>;\n\n // Messaging\n sendMessage(options: SendMessageOptions): Promise<{ eventId: string }>;\n editMessage(options: EditMessageOptions): Promise<{ eventId: string }>;\n sendReply(options: SendReplyOptions): Promise<{ eventId: string }>;\n getRoomMessages(options: {\n roomId: string;\n limit?: number;\n from?: string;\n }): Promise<{ events: MatrixEvent[]; nextBatch?: string }>;\n markRoomAsRead(options: {\n roomId: string;\n eventId: string;\n }): Promise<void>;\n refreshEventStatuses(options: {\n roomId: string;\n eventIds: string[];\n }): Promise<{ events: MatrixEvent[] }>;\n redactEvent(options: {\n roomId: string;\n eventId: string;\n reason?: string;\n }): Promise<void>;\n sendReaction(options: {\n roomId: string;\n eventId: string;\n key: string;\n }): Promise<{ eventId: string }>;\n\n // Room Management\n setRoomName(options: { roomId: string; name: string }): Promise<void>;\n setRoomTopic(options: { roomId: string; topic: string }): Promise<void>;\n setRoomAvatar(options: { roomId: string; mxcUrl: string }): Promise<void>;\n inviteUser(options: { roomId: string; userId: string }): Promise<void>;\n kickUser(options: { roomId: string; userId: string; reason?: string }): Promise<void>;\n banUser(options: { roomId: string; userId: string; reason?: string }): Promise<void>;\n unbanUser(options: { roomId: string; userId: string }): Promise<void>;\n\n // Typing\n sendTyping(options: {\n roomId: string;\n isTyping: boolean;\n timeout?: number;\n }): Promise<void>;\n\n // Media\n getMediaUrl(options: { mxcUrl: string }): Promise<{ httpUrl: string }>;\n getThumbnailUrl(options: ThumbnailUrlOptions): Promise<{ httpUrl: string }>;\n uploadContent(options: UploadContentOptions): Promise<UploadContentResult>;\n\n // User Discovery\n searchUsers(options: {\n searchTerm: string;\n limit?: number;\n }): Promise<{ results: UserProfile[]; limited: boolean }>;\n\n // Presence\n setPresence(options: {\n presence: 'online' | 'offline' | 'unavailable';\n statusMsg?: string;\n }): Promise<void>;\n getPresence(options: { userId: string }): Promise<PresenceInfo>;\n\n // Device Management\n getDevices(): Promise<{ devices: DeviceInfo[] }>;\n deleteDevice(options: { deviceId: string; auth?: Record<string, unknown> }): Promise<void>;\n verifyDevice(options: { deviceId: string }): Promise<void>;\n\n // Push\n setPusher(options: PusherOptions): Promise<void>;\n\n // Encryption\n initializeCrypto(): Promise<void>;\n getEncryptionStatus(): Promise<EncryptionStatus>;\n bootstrapCrossSigning(): Promise<void>;\n setupKeyBackup(): Promise<KeyBackupStatus>;\n getKeyBackupStatus(): Promise<KeyBackupStatus>;\n restoreKeyBackup(options?: {\n recoveryKey?: string;\n }): Promise<{ importedKeys: number }>;\n setupRecovery(options?: {\n passphrase?: string;\n /**\n * Passphrase for the *existing* secret storage key, used by\n * bootstrapSecretStorage to decrypt and migrate the current cross-signing\n * and backup secrets into the newly created SSSS. Only needed on web;\n * native platforms (Rust SDK) handle the migration internally.\n */\n existingPassphrase?: string;\n }): Promise<RecoveryKeyInfo>;\n /** Wipe all local Matrix state (crypto DB, session, caches). */\n clearAllData(): Promise<void>;\n isRecoveryEnabled(): Promise<{ enabled: boolean }>;\n recoverAndSetup(options: {\n recoveryKey?: string;\n passphrase?: string;\n }): Promise<void>;\n resetRecoveryKey(options?: {\n passphrase?: string;\n }): Promise<RecoveryKeyInfo>;\n exportRoomKeys(options: {\n passphrase: string;\n }): Promise<{ data: string }>;\n importRoomKeys(options: {\n data: string;\n passphrase: string;\n }): Promise<{ importedKeys: number }>;\n\n // Listeners\n addListener(\n event: 'syncStateChange',\n listenerFunc: (data: SyncStateChangeEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n event: 'messageReceived',\n listenerFunc: (data: MessageReceivedEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n event: 'roomUpdated',\n listenerFunc: (data: RoomUpdatedEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n event: 'typingChanged',\n listenerFunc: (data: TypingEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n event: 'receiptReceived',\n listenerFunc: (data: ReceiptReceivedEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n event: 'presenceChanged',\n listenerFunc: (data: PresenceChangedEvent) => void,\n ): Promise<PluginListenerHandle>;\n removeAllListeners(): Promise<void>;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\n// Auth & Session\n\nexport interface LoginOptions {\n homeserverUrl: string;\n userId: string;\n password: string;\n}\n\nexport interface LoginWithTokenOptions {\n homeserverUrl: string;\n accessToken: string;\n userId: string;\n deviceId: string;\n}\n\nexport interface SessionInfo {\n accessToken: string;\n userId: string;\n deviceId: string;\n homeserverUrl: string;\n}\n\n// Messaging\n\nexport interface SendMessageOptions {\n roomId: string;\n body: string;\n msgtype?: 'm.text' | 'm.notice' | 'm.emote' | 'm.image' | 'm.audio' | 'm.video' | 'm.file';\n fileUri?: string;\n fileName?: string;\n mimeType?: string;\n fileSize?: number;\n /** Audio/video duration in milliseconds (sets info.duration per Matrix spec) */\n duration?: number;\n /** Image/video width in pixels (sets info.w per Matrix spec) */\n width?: number;\n /** Image/video height in pixels (sets info.h per Matrix spec) */\n height?: number;\n}\n\n// Presence\n\nexport interface PresenceInfo {\n presence: 'online' | 'offline' | 'unavailable';\n statusMsg?: string;\n lastActiveAgo?: number;\n}\n\n// Typing\n\nexport interface TypingEvent {\n roomId: string;\n userIds: string[];\n}\n\nexport interface ReceiptReceivedEvent {\n roomId: string;\n /** The event that was read */\n eventId: string;\n /** The user who sent the read receipt */\n userId: string;\n}\n\nexport interface PresenceChangedEvent {\n userId: string;\n presence: PresenceInfo;\n}\n\n// Edit & Reply\n\nexport interface EditMessageOptions {\n roomId: string;\n eventId: string;\n newBody: string;\n /** Required when editing a media message; must match the original msgtype */\n msgtype?: 'm.text' | 'm.notice' | 'm.emote' | 'm.image' | 'm.audio' | 'm.video' | 'm.file';\n /** New file to replace the media content (optional for caption-only edits) */\n fileUri?: string;\n fileName?: string;\n mimeType?: string;\n fileSize?: number;\n /** Audio/video duration in milliseconds */\n duration?: number;\n /** Image/video width in pixels */\n width?: number;\n /** Image/video height in pixels */\n height?: number;\n}\n\nexport interface SendReplyOptions {\n roomId: string;\n body: string;\n replyToEventId: string;\n msgtype?: 'm.text' | 'm.notice' | 'm.emote' | 'm.image' | 'm.audio' | 'm.video' | 'm.file';\n fileUri?: string;\n fileName?: string;\n mimeType?: string;\n fileSize?: number;\n /** Audio/video duration in milliseconds (sets info.duration per Matrix spec) */\n duration?: number;\n /** Image/video width in pixels (sets info.w per Matrix spec) */\n width?: number;\n /** Image/video height in pixels (sets info.h per Matrix spec) */\n height?: number;\n}\n\n// Upload\n\nexport interface UploadContentOptions {\n fileUri: string;\n fileName: string;\n mimeType: string;\n}\n\nexport interface UploadContentResult {\n contentUri: string;\n}\n\n// Thumbnail\n\nexport interface ThumbnailUrlOptions {\n mxcUrl: string;\n width: number;\n height: number;\n method?: 'scale' | 'crop';\n}\n\nexport interface MatrixEvent {\n eventId: string;\n roomId: string;\n senderId: string;\n type: string;\n /** State key for state events (e.g. target user ID for m.room.member) */\n stateKey?: string;\n content: Record<string, unknown>;\n originServerTs: number;\n /** Delivery/read status for own messages: 'sending' | 'sent' | 'delivered' | 'read' */\n status?: 'sending' | 'sent' | 'delivered' | 'read';\n /** User IDs that have read this event */\n readBy?: string[];\n /** Unsigned data (e.g. m.relations for edits, transaction_id for local echo) */\n unsigned?: Record<string, unknown>;\n}\n\n// Rooms\n\nexport interface LatestEventPreview {\n roomId: string;\n senderId: string;\n type: string;\n content: Record<string, unknown>;\n originServerTs: number;\n senderDisplayName?: string;\n}\n\nexport interface RoomSummary {\n roomId: string;\n name: string;\n topic?: string;\n memberCount: number;\n isEncrypted: boolean;\n unreadCount: number;\n lastEventTs?: number;\n membership?: 'join' | 'invite' | 'leave' | 'ban';\n avatarUrl?: string;\n isDirect?: boolean;\n latestEvent?: LatestEventPreview;\n}\n\nexport interface RoomMember {\n userId: string;\n displayName?: string;\n membership: 'join' | 'invite' | 'leave' | 'ban';\n avatarUrl?: string;\n}\n\n// Device Management\n\nexport interface DeviceInfo {\n deviceId: string;\n displayName?: string;\n lastSeenTs?: number;\n lastSeenIp?: string;\n /** Whether this device is verified via cross-signing */\n isCrossSigningVerified?: boolean;\n}\n\n// Pusher\n\nexport interface PusherOptions {\n pushkey: string;\n kind: string | null;\n appId: string;\n appDisplayName: string;\n deviceDisplayName: string;\n lang: string;\n data: { url: string; format?: string };\n}\n\n// User Discovery\n\nexport interface UserProfile {\n userId: string;\n displayName?: string;\n avatarUrl?: string;\n}\n\n// Encryption\n\nexport interface CrossSigningStatus {\n hasMaster: boolean;\n hasSelfSigning: boolean;\n hasUserSigning: boolean;\n isReady: boolean;\n}\n\nexport interface KeyBackupStatus {\n exists: boolean;\n version?: string;\n enabled: boolean;\n}\n\nexport interface RecoveryKeyInfo {\n recoveryKey: string;\n}\n\nexport interface EncryptionStatus {\n isCrossSigningReady: boolean;\n crossSigningStatus: CrossSigningStatus;\n isKeyBackupEnabled: boolean;\n keyBackupVersion?: string;\n isSecretStorageReady: boolean;\n}\n\n// Events & Sync\n\nexport type SyncState = 'INITIAL' | 'SYNCING' | 'ERROR' | 'STOPPED';\n\nexport interface SyncStateChangeEvent {\n state: SyncState;\n error?: string;\n}\n\nexport interface MessageReceivedEvent {\n event: MatrixEvent;\n}\n\nexport interface RoomUpdatedEvent {\n roomId: string;\n summary: RoomSummary;\n}\n\n// Plugin Interface\n\nexport interface MatrixPlugin {\n // Auth\n login(options: LoginOptions): Promise<SessionInfo>;\n loginWithToken(options: LoginWithTokenOptions): Promise<SessionInfo>;\n logout(): Promise<void>;\n getSession(): Promise<SessionInfo | null>;\n\n // Sync\n startSync(): Promise<void>;\n stopSync(): Promise<void>;\n getSyncState(): Promise<{ state: SyncState }>;\n\n // Rooms\n createRoom(options: {\n name?: string;\n topic?: string;\n isEncrypted?: boolean;\n isDirect?: boolean;\n invite?: string[];\n preset?: 'private_chat' | 'trusted_private_chat' | 'public_chat';\n historyVisibility?: 'invited' | 'joined' | 'shared' | 'world_readable';\n }): Promise<{ roomId: string }>;\n getRooms(): Promise<{ rooms: RoomSummary[] }>;\n getRoomMembers(options: { roomId: string }): Promise<{ members: RoomMember[] }>;\n joinRoom(options: { roomIdOrAlias: string }): Promise<{ roomId: string }>;\n leaveRoom(options: { roomId: string }): Promise<void>;\n forgetRoom(options: { roomId: string }): Promise<void>;\n\n // Messaging\n sendMessage(options: SendMessageOptions): Promise<{ eventId: string }>;\n editMessage(options: EditMessageOptions): Promise<{ eventId: string }>;\n sendReply(options: SendReplyOptions): Promise<{ eventId: string }>;\n getRoomMessages(options: {\n roomId: string;\n limit?: number;\n from?: string;\n }): Promise<{ events: MatrixEvent[]; nextBatch?: string }>;\n markRoomAsRead(options: {\n roomId: string;\n eventId: string;\n }): Promise<void>;\n refreshEventStatuses(options: {\n roomId: string;\n eventIds: string[];\n }): Promise<{ events: MatrixEvent[] }>;\n redactEvent(options: {\n roomId: string;\n eventId: string;\n reason?: string;\n }): Promise<void>;\n sendReaction(options: {\n roomId: string;\n eventId: string;\n key: string;\n }): Promise<{ eventId: string }>;\n\n // Room Management\n setRoomName(options: { roomId: string; name: string }): Promise<void>;\n setRoomTopic(options: { roomId: string; topic: string }): Promise<void>;\n setRoomAvatar(options: { roomId: string; mxcUrl: string }): Promise<void>;\n inviteUser(options: { roomId: string; userId: string }): Promise<void>;\n kickUser(options: { roomId: string; userId: string; reason?: string }): Promise<void>;\n banUser(options: { roomId: string; userId: string; reason?: string }): Promise<void>;\n unbanUser(options: { roomId: string; userId: string }): Promise<void>;\n\n // Typing\n sendTyping(options: {\n roomId: string;\n isTyping: boolean;\n timeout?: number;\n }): Promise<void>;\n\n // Media\n getMediaUrl(options: { mxcUrl: string }): Promise<{ httpUrl: string }>;\n getThumbnailUrl(options: ThumbnailUrlOptions): Promise<{ httpUrl: string }>;\n uploadContent(options: UploadContentOptions): Promise<UploadContentResult>;\n\n // User Discovery\n searchUsers(options: {\n searchTerm: string;\n limit?: number;\n }): Promise<{ results: UserProfile[]; limited: boolean }>;\n\n // Presence\n setPresence(options: {\n presence: 'online' | 'offline' | 'unavailable';\n statusMsg?: string;\n }): Promise<void>;\n getPresence(options: { userId: string }): Promise<PresenceInfo>;\n\n // Device Management\n getDevices(): Promise<{ devices: DeviceInfo[] }>;\n deleteDevice(options: { deviceId: string; auth?: Record<string, unknown> }): Promise<void>;\n verifyDevice(options: { deviceId: string }): Promise<void>;\n\n // Push\n setPusher(options: PusherOptions): Promise<void>;\n\n // Encryption\n initializeCrypto(): Promise<void>;\n getEncryptionStatus(): Promise<EncryptionStatus>;\n bootstrapCrossSigning(): Promise<void>;\n setupKeyBackup(): Promise<KeyBackupStatus>;\n getKeyBackupStatus(): Promise<KeyBackupStatus>;\n restoreKeyBackup(options?: {\n recoveryKey?: string;\n }): Promise<{ importedKeys: number }>;\n setupRecovery(options?: {\n passphrase?: string;\n /**\n * Passphrase for the *existing* secret storage key, used by\n * bootstrapSecretStorage to decrypt and migrate the current cross-signing\n * and backup secrets into the newly created SSSS. Only needed on web;\n * native platforms (Rust SDK) handle the migration internally.\n */\n existingPassphrase?: string;\n }): Promise<RecoveryKeyInfo>;\n /** Wipe all local Matrix state (crypto DB, session, caches). */\n clearAllData(): Promise<void>;\n isRecoveryEnabled(): Promise<{ enabled: boolean }>;\n recoverAndSetup(options: {\n recoveryKey?: string;\n passphrase?: string;\n }): Promise<void>;\n resetRecoveryKey(options?: {\n passphrase?: string;\n }): Promise<RecoveryKeyInfo>;\n exportRoomKeys(options: {\n passphrase: string;\n }): Promise<{ data: string }>;\n importRoomKeys(options: {\n data: string;\n passphrase: string;\n }): Promise<{ importedKeys: number }>;\n\n // Listeners\n addListener(\n event: 'syncStateChange',\n listenerFunc: (data: SyncStateChangeEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n event: 'messageReceived',\n listenerFunc: (data: MessageReceivedEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n event: 'roomUpdated',\n listenerFunc: (data: RoomUpdatedEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n event: 'typingChanged',\n listenerFunc: (data: TypingEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n event: 'receiptReceived',\n listenerFunc: (data: ReceiptReceivedEvent) => void,\n ): Promise<PluginListenerHandle>;\n addListener(\n event: 'presenceChanged',\n listenerFunc: (data: PresenceChangedEvent) => void,\n ): Promise<PluginListenerHandle>;\n // Token Refresh\n updateAccessToken(options: { accessToken: string }): Promise<void>;\n\n addListener(\n event: 'tokenRefreshRequired',\n listenerFunc: () => void,\n ): Promise<PluginListenerHandle>;\n\n removeAllListeners(): Promise<void>;\n}\n"]}
package/dist/esm/web.d.ts CHANGED
@@ -6,12 +6,17 @@ export declare class MatrixWeb extends WebPlugin implements MatrixPlugin {
6
6
  private secretStorageKeyId?;
7
7
  private recoveryPassphrase?;
8
8
  private fallbackPassphrase?;
9
+ private _tokenRefreshResolve?;
10
+ private _tokenRefreshTimeout?;
9
11
  private readonly _cryptoCallbacks;
10
12
  login(options: LoginOptions): Promise<SessionInfo>;
11
13
  loginWithToken(options: LoginWithTokenOptions): Promise<SessionInfo>;
12
14
  logout(): Promise<void>;
13
15
  clearAllData(): Promise<void>;
14
16
  getSession(): Promise<SessionInfo | null>;
17
+ updateAccessToken(options: {
18
+ accessToken: string;
19
+ }): Promise<void>;
15
20
  startSync(): Promise<void>;
16
21
  stopSync(): Promise<void>;
17
22
  getSyncState(): Promise<{
@@ -188,6 +193,7 @@ export declare class MatrixWeb extends WebPlugin implements MatrixPlugin {
188
193
  private requireCrypto;
189
194
  private ensureCrypto;
190
195
  private persistSession;
196
+ private createTokenRefreshFunction;
191
197
  private serializeEvent;
192
198
  private serializeRoom;
193
199
  searchUsers(options: {