@tagea/capacitor-matrix 1.1.1 → 1.2.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/README.md +31 -0
- package/android/src/main/kotlin/de/tremaze/capacitor/matrix/CapMatrix.kt +142 -0
- package/android/src/main/kotlin/de/tremaze/capacitor/matrix/CapMatrixPlugin.kt +53 -3
- package/dist/docs.json +39 -0
- package/dist/esm/definitions.d.ts +4 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +6 -0
- package/dist/esm/web.js +39 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +39 -0
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +39 -0
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapMatrixPlugin/CapMatrix.swift +354 -32
- package/ios/Sources/CapMatrixPlugin/CapMatrixPlugin.swift +70 -3
- package/package.json +1 -1
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>() => void</code> |
|
|
1183
|
+
|
|
1184
|
+
**Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code>
|
|
1185
|
+
|
|
1186
|
+
--------------------
|
|
1187
|
+
|
|
1188
|
+
|
|
1158
1189
|
### removeAllListeners()
|
|
1159
1190
|
|
|
1160
1191
|
```typescript
|
|
@@ -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.
|
|
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.
|
|
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.
|
|
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>",
|
|
@@ -388,5 +388,9 @@ export interface MatrixPlugin {
|
|
|
388
388
|
addListener(event: 'typingChanged', listenerFunc: (data: TypingEvent) => void): Promise<PluginListenerHandle>;
|
|
389
389
|
addListener(event: 'receiptReceived', listenerFunc: (data: ReceiptReceivedEvent) => void): Promise<PluginListenerHandle>;
|
|
390
390
|
addListener(event: 'presenceChanged', listenerFunc: (data: PresenceChangedEvent) => void): Promise<PluginListenerHandle>;
|
|
391
|
+
updateAccessToken(options: {
|
|
392
|
+
accessToken: string;
|
|
393
|
+
}): Promise<void>;
|
|
394
|
+
addListener(event: 'tokenRefreshRequired', listenerFunc: () => void): Promise<PluginListenerHandle>;
|
|
391
395
|
removeAllListeners(): Promise<void>;
|
|
392
396
|
}
|
|
@@ -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 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 // 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: {
|
package/dist/esm/web.js
CHANGED
|
@@ -57,6 +57,8 @@ export class MatrixWeb extends WebPlugin {
|
|
|
57
57
|
userId: res.user_id,
|
|
58
58
|
deviceId: res.device_id,
|
|
59
59
|
cryptoCallbacks: this._cryptoCallbacks,
|
|
60
|
+
refreshToken: 'jwt-placeholder',
|
|
61
|
+
tokenRefreshFunction: this.createTokenRefreshFunction(),
|
|
60
62
|
});
|
|
61
63
|
const session = {
|
|
62
64
|
accessToken: res.access_token,
|
|
@@ -80,6 +82,8 @@ export class MatrixWeb extends WebPlugin {
|
|
|
80
82
|
userId: options.userId,
|
|
81
83
|
deviceId: options.deviceId,
|
|
82
84
|
cryptoCallbacks: this._cryptoCallbacks,
|
|
85
|
+
refreshToken: 'jwt-placeholder',
|
|
86
|
+
tokenRefreshFunction: this.createTokenRefreshFunction(),
|
|
83
87
|
});
|
|
84
88
|
const session = {
|
|
85
89
|
accessToken: options.accessToken,
|
|
@@ -127,6 +131,27 @@ export class MatrixWeb extends WebPlugin {
|
|
|
127
131
|
return null;
|
|
128
132
|
}
|
|
129
133
|
}
|
|
134
|
+
async updateAccessToken(options) {
|
|
135
|
+
this.requireClient();
|
|
136
|
+
this.client.setAccessToken(options.accessToken);
|
|
137
|
+
// Update persisted session
|
|
138
|
+
const raw = localStorage.getItem(SESSION_KEY);
|
|
139
|
+
if (raw) {
|
|
140
|
+
const session = JSON.parse(raw);
|
|
141
|
+
session.accessToken = options.accessToken;
|
|
142
|
+
this.persistSession(session);
|
|
143
|
+
}
|
|
144
|
+
// Resolve pending tokenRefreshFunction promise (if SDK is waiting)
|
|
145
|
+
if (this._tokenRefreshResolve) {
|
|
146
|
+
const resolve = this._tokenRefreshResolve;
|
|
147
|
+
this._tokenRefreshResolve = undefined;
|
|
148
|
+
if (this._tokenRefreshTimeout) {
|
|
149
|
+
clearTimeout(this._tokenRefreshTimeout);
|
|
150
|
+
this._tokenRefreshTimeout = undefined;
|
|
151
|
+
}
|
|
152
|
+
resolve({ accessToken: options.accessToken, refreshToken: 'jwt-placeholder' });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
130
155
|
// ── Sync ──────────────────────────────────────────────
|
|
131
156
|
async startSync() {
|
|
132
157
|
this.requireClient();
|
|
@@ -957,6 +982,20 @@ export class MatrixWeb extends WebPlugin {
|
|
|
957
982
|
persistSession(session) {
|
|
958
983
|
localStorage.setItem(SESSION_KEY, JSON.stringify(session));
|
|
959
984
|
}
|
|
985
|
+
createTokenRefreshFunction() {
|
|
986
|
+
return (_refreshToken) => {
|
|
987
|
+
this.notifyListeners('tokenRefreshRequired', {});
|
|
988
|
+
return new Promise((resolve, reject) => {
|
|
989
|
+
if (this._tokenRefreshTimeout)
|
|
990
|
+
clearTimeout(this._tokenRefreshTimeout);
|
|
991
|
+
this._tokenRefreshResolve = resolve;
|
|
992
|
+
this._tokenRefreshTimeout = setTimeout(() => {
|
|
993
|
+
this._tokenRefreshResolve = undefined;
|
|
994
|
+
reject(new Error('Token refresh timed out'));
|
|
995
|
+
}, 30000);
|
|
996
|
+
});
|
|
997
|
+
};
|
|
998
|
+
}
|
|
960
999
|
serializeEvent(event, fallbackRoomId) {
|
|
961
1000
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
962
1001
|
const roomId = (_b = (_a = event.getRoomId()) !== null && _a !== void 0 ? _a : fallbackRoomId) !== null && _b !== void 0 ? _b : '';
|