@element-hq/element-call-embedded 0.9.0-rc.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.
Files changed (140) hide show
  1. package/LICENSE-AGPL-3.0 +661 -0
  2. package/LICENSE-COMMERCIAL +6 -0
  3. package/README.md +14 -0
  4. package/dist/assets/IndexedDBWorker-DunQAoUH.js +2 -0
  5. package/dist/assets/IndexedDBWorker-DunQAoUH.js.map +1 -0
  6. package/dist/assets/cat-4r_NkDcK.ogg +0 -0
  7. package/dist/assets/cat-Dd8bv_2W.mp3 +0 -0
  8. package/dist/assets/clap-AxCMZLTd.ogg +0 -0
  9. package/dist/assets/clap-Dxm5qGyl.mp3 +0 -0
  10. package/dist/assets/crickets-CcwrRdbq.mp3 +0 -0
  11. package/dist/assets/crickets-DUJdcuUa.ogg +0 -0
  12. package/dist/assets/de-app-BVrY_LcE.json +218 -0
  13. package/dist/assets/deer-91r1Gyrx.mp3 +0 -0
  14. package/dist/assets/deer-DPSlVch4.ogg +0 -0
  15. package/dist/assets/dog-BoQdnF-w.mp3 +0 -0
  16. package/dist/assets/dog-CxIWtkNX.ogg +0 -0
  17. package/dist/assets/el-app-Bgiig2Nz.json +81 -0
  18. package/dist/assets/en-app-CaNSxxxY.json +218 -0
  19. package/dist/assets/es-app-k4RDObng.json +82 -0
  20. package/dist/assets/et-app-lXLRqT0e.json +115 -0
  21. package/dist/assets/fr-app-DbyWYFAw.json +114 -0
  22. package/dist/assets/generic-BBbS3Wph.ogg +0 -0
  23. package/dist/assets/generic-BFeSb6fL.mp3 +0 -0
  24. package/dist/assets/id-app-C7u2K42_.json +114 -0
  25. package/dist/assets/inconsolata-latin-400-normal-Befkm-iY.woff +0 -0
  26. package/dist/assets/inconsolata-latin-400-normal-CjvQBeBR.woff2 +0 -0
  27. package/dist/assets/inconsolata-latin-700-normal-BUbZx5Dd.woff2 +0 -0
  28. package/dist/assets/inconsolata-latin-700-normal-OU_zouat.woff +0 -0
  29. package/dist/assets/inconsolata-latin-ext-400-normal-DeeBOK-I.woff +0 -0
  30. package/dist/assets/inconsolata-latin-ext-400-normal-e5nDaEKZ.woff2 +0 -0
  31. package/dist/assets/inconsolata-latin-ext-700-normal-BSLPqmaC.woff +0 -0
  32. package/dist/assets/inconsolata-latin-ext-700-normal-BhssidQ1.woff2 +0 -0
  33. package/dist/assets/inconsolata-vietnamese-400-normal-DfMo8OX4.woff2 +0 -0
  34. package/dist/assets/inconsolata-vietnamese-400-normal-hFXvniIJ.woff +0 -0
  35. package/dist/assets/inconsolata-vietnamese-700-normal-D1IfJGt6.woff +0 -0
  36. package/dist/assets/inconsolata-vietnamese-700-normal-DlaT3sch.woff2 +0 -0
  37. package/dist/assets/index-B_Ugqolg.js +221 -0
  38. package/dist/assets/index-B_Ugqolg.js.map +1 -0
  39. package/dist/assets/index-BtY3MdEn.css +1 -0
  40. package/dist/assets/index-CZufW2rm.js +9 -0
  41. package/dist/assets/index-CZufW2rm.js.map +1 -0
  42. package/dist/assets/index-DhG7hwDH.js +3 -0
  43. package/dist/assets/index-DhG7hwDH.js.map +1 -0
  44. package/dist/assets/inter-cyrillic-400-normal-BLGc9T1a.woff2 +0 -0
  45. package/dist/assets/inter-cyrillic-400-normal-ZzOtrSSW.woff +0 -0
  46. package/dist/assets/inter-cyrillic-500-normal-D4Vwzodn.woff2 +0 -0
  47. package/dist/assets/inter-cyrillic-500-normal-DH2hs3aW.woff +0 -0
  48. package/dist/assets/inter-cyrillic-600-normal-BGBWG807.woff2 +0 -0
  49. package/dist/assets/inter-cyrillic-600-normal-BuzJQFbW.woff +0 -0
  50. package/dist/assets/inter-cyrillic-700-normal-Bc8_fv8J.woff +0 -0
  51. package/dist/assets/inter-cyrillic-700-normal-bGtGjVdZ.woff2 +0 -0
  52. package/dist/assets/inter-cyrillic-ext-400-normal-BPnxn4xp.woff +0 -0
  53. package/dist/assets/inter-cyrillic-ext-400-normal-Dc4VJyIJ.woff2 +0 -0
  54. package/dist/assets/inter-cyrillic-ext-500-normal-BShVwWPj.woff2 +0 -0
  55. package/dist/assets/inter-cyrillic-ext-500-normal-CUiC4oBV.woff +0 -0
  56. package/dist/assets/inter-cyrillic-ext-600-normal-Bt9VVOA-.woff +0 -0
  57. package/dist/assets/inter-cyrillic-ext-600-normal-CaqZN2hq.woff2 +0 -0
  58. package/dist/assets/inter-cyrillic-ext-700-normal-Ced3hgUT.woff +0 -0
  59. package/dist/assets/inter-cyrillic-ext-700-normal-ClVoMEGq.woff2 +0 -0
  60. package/dist/assets/inter-greek-400-normal-BZzXV7-1.woff +0 -0
  61. package/dist/assets/inter-greek-400-normal-DxZsaF_h.woff2 +0 -0
  62. package/dist/assets/inter-greek-500-normal-CeQXL5ds.woff2 +0 -0
  63. package/dist/assets/inter-greek-500-normal-d_eO-yCQ.woff +0 -0
  64. package/dist/assets/inter-greek-600-normal-CwicyhtI.woff +0 -0
  65. package/dist/assets/inter-greek-600-normal-Dhlb-90d.woff2 +0 -0
  66. package/dist/assets/inter-greek-700-normal-BRYTaFLL.woff +0 -0
  67. package/dist/assets/inter-greek-700-normal-Cxpycf-U.woff2 +0 -0
  68. package/dist/assets/inter-greek-ext-400-normal-Bput3-QP.woff2 +0 -0
  69. package/dist/assets/inter-greek-ext-400-normal-DCpCPQOf.woff +0 -0
  70. package/dist/assets/inter-greek-ext-500-normal-B6guLgqG.woff2 +0 -0
  71. package/dist/assets/inter-greek-ext-500-normal-M2hEX8vc.woff +0 -0
  72. package/dist/assets/inter-greek-ext-600-normal-C9WLioJ8.woff +0 -0
  73. package/dist/assets/inter-greek-ext-600-normal-Cnui8OiR.woff2 +0 -0
  74. package/dist/assets/inter-greek-ext-700-normal-DXvzx4Na.woff +0 -0
  75. package/dist/assets/inter-greek-ext-700-normal-SzCdnevJ.woff2 +0 -0
  76. package/dist/assets/inter-latin-400-normal-BOOGhInR.woff2 +0 -0
  77. package/dist/assets/inter-latin-400-normal-gitzw0hO.woff +0 -0
  78. package/dist/assets/inter-latin-500-normal-D2bGa7uu.woff2 +0 -0
  79. package/dist/assets/inter-latin-500-normal-deR1Tlfd.woff +0 -0
  80. package/dist/assets/inter-latin-600-normal-B5cFAncS.woff +0 -0
  81. package/dist/assets/inter-latin-600-normal-D273HNI0.woff2 +0 -0
  82. package/dist/assets/inter-latin-700-normal-B8MtJ_2k.woff +0 -0
  83. package/dist/assets/inter-latin-700-normal-Sckx8rpT.woff2 +0 -0
  84. package/dist/assets/inter-latin-ext-400-normal-C1t-h-pH.woff +0 -0
  85. package/dist/assets/inter-latin-ext-400-normal-hnt3BR84.woff2 +0 -0
  86. package/dist/assets/inter-latin-ext-500-normal-CIS2RHJS.woff2 +0 -0
  87. package/dist/assets/inter-latin-ext-500-normal-UMdmhHu2.woff +0 -0
  88. package/dist/assets/inter-latin-ext-600-normal-BnYJhD27.woff2 +0 -0
  89. package/dist/assets/inter-latin-ext-600-normal-CAF0vJDd.woff +0 -0
  90. package/dist/assets/inter-latin-ext-700-normal-6V9MnIL5.woff +0 -0
  91. package/dist/assets/inter-latin-ext-700-normal-CzikT_rs.woff2 +0 -0
  92. package/dist/assets/inter-vietnamese-400-normal-BUNmGMP1.woff +0 -0
  93. package/dist/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
  94. package/dist/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
  95. package/dist/assets/inter-vietnamese-500-normal-DQPw2Hwd.woff +0 -0
  96. package/dist/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
  97. package/dist/assets/inter-vietnamese-600-normal-Cm6aH8_k.woff +0 -0
  98. package/dist/assets/inter-vietnamese-700-normal-CGpBpxLq.woff2 +0 -0
  99. package/dist/assets/inter-vietnamese-700-normal-dAnkLlTo.woff +0 -0
  100. package/dist/assets/it-app-Brq71wxA.json +111 -0
  101. package/dist/assets/join_call-DlMV9nHk.ogg +0 -0
  102. package/dist/assets/join_call-dEJCP2wD.mp3 +0 -0
  103. package/dist/assets/left_call-BbqmRgnC.mp3 +0 -0
  104. package/dist/assets/left_call-C7NMl6WI.ogg +0 -0
  105. package/dist/assets/lightbulb-BIeJtAR_.ogg +0 -0
  106. package/dist/assets/lightbulb-BrnY00qi.mp3 +0 -0
  107. package/dist/assets/livekit-client.e2ee.worker-uNa5aSsA.js +2 -0
  108. package/dist/assets/livekit-client.e2ee.worker-uNa5aSsA.js.map +1 -0
  109. package/dist/assets/lv-app--dkl5K2p.json +89 -0
  110. package/dist/assets/matrix-sdk-crypto-wasm-D9e1T4vy.js +3 -0
  111. package/dist/assets/matrix-sdk-crypto-wasm-D9e1T4vy.js.map +1 -0
  112. package/dist/assets/matrix_sdk_crypto_wasm_bg-B6p0UpxL.wasm +0 -0
  113. package/dist/assets/pako.esm-Bt8vjcgE.js +2 -0
  114. package/dist/assets/pako.esm-Bt8vjcgE.js.map +1 -0
  115. package/dist/assets/party-BZPeTgC3.mp3 +0 -0
  116. package/dist/assets/party-D7rIOhAQ.ogg +0 -0
  117. package/dist/assets/pl-app-DGeQk6oM.json +117 -0
  118. package/dist/assets/polyfill-force-7EA3_RsE.js +2 -0
  119. package/dist/assets/polyfill-force-7EA3_RsE.js.map +1 -0
  120. package/dist/assets/polyfill-force-HZS4jnNh.js +2 -0
  121. package/dist/assets/polyfill-force-HZS4jnNh.js.map +1 -0
  122. package/dist/assets/raise_hand-Bzqn65WB.mp3 +0 -0
  123. package/dist/assets/raise_hand-CUbxEnt9.ogg +0 -0
  124. package/dist/assets/ro-app-C7W3EjXp.json +174 -0
  125. package/dist/assets/rock-BVCJXNC-.ogg +0 -0
  126. package/dist/assets/rock-CHdnB31m.mp3 +0 -0
  127. package/dist/assets/ru-app-B-FtZqJU.json +83 -0
  128. package/dist/assets/screen_share_started-DH3qxml5.mp3 +0 -0
  129. package/dist/assets/screen_share_started-IZDL-kAw.ogg +0 -0
  130. package/dist/assets/sk-app-C-Uhf1j4.json +115 -0
  131. package/dist/assets/spa-Cw7oBEf6.js +2 -0
  132. package/dist/assets/spa-Cw7oBEf6.js.map +1 -0
  133. package/dist/assets/uk-app-BxyP4dDT.json +117 -0
  134. package/dist/assets/wave-Bzf1LSMH.mp3 +0 -0
  135. package/dist/assets/wave-FiiOzicp.ogg +0 -0
  136. package/dist/assets/zh-Hans-app-CCvn5Yaa.json +110 -0
  137. package/dist/assets/zh-Hant-app-bsZKL_R6.json +117 -0
  138. package/dist/config.json +1 -0
  139. package/dist/index.html +1 -0
  140. package/package.json +14 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IndexedDBWorker-DunQAoUH.js","sources":["../node_modules/loglevel/lib/loglevel.js","../node_modules/matrix-js-sdk/src/logger.ts","../node_modules/unhomoglyph/index.js","../node_modules/retry/lib/retry_operation.js","../node_modules/retry/lib/retry.js","../node_modules/retry/index.js","../node_modules/p-retry/index.js","../node_modules/matrix-js-sdk/src/NamespacedValue.ts","../node_modules/matrix-js-sdk/src/@types/location.ts","../node_modules/matrix-js-sdk/src/@types/read_receipts.ts","../node_modules/matrix-js-sdk/src/utils.ts","../node_modules/matrix-js-sdk/src/@types/sync.ts","../node_modules/matrix-js-sdk/src/@types/event.ts","../node_modules/matrix-js-sdk/src/receipt-accumulator.ts","../node_modules/matrix-js-sdk/src/sync-accumulator.ts","../node_modules/matrix-js-sdk/src/indexeddb-helpers.ts","../node_modules/matrix-js-sdk/src/store/indexeddb-local-backend.ts","../node_modules/matrix-js-sdk/src/store/indexeddb-store-worker.ts","../src/IndexedDBWorker.ts"],"sourcesContent":["/*\n* loglevel - https://github.com/pimterry/loglevel\n*\n* Copyright (c) 2013 Tim Perry\n* Licensed under the MIT license.\n*/\n(function (root, definition) {\n \"use strict\";\n if (typeof define === 'function' && define.amd) {\n define(definition);\n } else if (typeof module === 'object' && module.exports) {\n module.exports = definition();\n } else {\n root.log = definition();\n }\n}(this, function () {\n \"use strict\";\n\n // Slightly dubious tricks to cut down minimized file size\n var noop = function() {};\n var undefinedType = \"undefined\";\n var isIE = (typeof window !== undefinedType) && (typeof window.navigator !== undefinedType) && (\n /Trident\\/|MSIE /.test(window.navigator.userAgent)\n );\n\n var logMethods = [\n \"trace\",\n \"debug\",\n \"info\",\n \"warn\",\n \"error\"\n ];\n\n var _loggersByName = {};\n var defaultLogger = null;\n\n // Cross-browser bind equivalent that works at least back to IE6\n function bindMethod(obj, methodName) {\n var method = obj[methodName];\n if (typeof method.bind === 'function') {\n return method.bind(obj);\n } else {\n try {\n return Function.prototype.bind.call(method, obj);\n } catch (e) {\n // Missing bind shim or IE8 + Modernizr, fallback to wrapping\n return function() {\n return Function.prototype.apply.apply(method, [obj, arguments]);\n };\n }\n }\n }\n\n // Trace() doesn't print the message in IE, so for that case we need to wrap it\n function traceForIE() {\n if (console.log) {\n if (console.log.apply) {\n console.log.apply(console, arguments);\n } else {\n // In old IE, native console methods themselves don't have apply().\n Function.prototype.apply.apply(console.log, [console, arguments]);\n }\n }\n if (console.trace) console.trace();\n }\n\n // Build the best logging method possible for this env\n // Wherever possible we want to bind, not wrap, to preserve stack traces\n function realMethod(methodName) {\n if (methodName === 'debug') {\n methodName = 'log';\n }\n\n if (typeof console === undefinedType) {\n return false; // No method possible, for now - fixed later by enableLoggingWhenConsoleArrives\n } else if (methodName === 'trace' && isIE) {\n return traceForIE;\n } else if (console[methodName] !== undefined) {\n return bindMethod(console, methodName);\n } else if (console.log !== undefined) {\n return bindMethod(console, 'log');\n } else {\n return noop;\n }\n }\n\n // These private functions always need `this` to be set properly\n\n function replaceLoggingMethods() {\n /*jshint validthis:true */\n var level = this.getLevel();\n\n // Replace the actual methods.\n for (var i = 0; i < logMethods.length; i++) {\n var methodName = logMethods[i];\n this[methodName] = (i < level) ?\n noop :\n this.methodFactory(methodName, level, this.name);\n }\n\n // Define log.log as an alias for log.debug\n this.log = this.debug;\n\n // Return any important warnings.\n if (typeof console === undefinedType && level < this.levels.SILENT) {\n return \"No console available for logging\";\n }\n }\n\n // In old IE versions, the console isn't present until you first open it.\n // We build realMethod() replacements here that regenerate logging methods\n function enableLoggingWhenConsoleArrives(methodName) {\n return function () {\n if (typeof console !== undefinedType) {\n replaceLoggingMethods.call(this);\n this[methodName].apply(this, arguments);\n }\n };\n }\n\n // By default, we use closely bound real methods wherever possible, and\n // otherwise we wait for a console to appear, and then try again.\n function defaultMethodFactory(methodName, _level, _loggerName) {\n /*jshint validthis:true */\n return realMethod(methodName) ||\n enableLoggingWhenConsoleArrives.apply(this, arguments);\n }\n\n function Logger(name, factory) {\n // Private instance variables.\n var self = this;\n /**\n * The level inherited from a parent logger (or a global default). We\n * cache this here rather than delegating to the parent so that it stays\n * in sync with the actual logging methods that we have installed (the\n * parent could change levels but we might not have rebuilt the loggers\n * in this child yet).\n * @type {number}\n */\n var inheritedLevel;\n /**\n * The default level for this logger, if any. If set, this overrides\n * `inheritedLevel`.\n * @type {number|null}\n */\n var defaultLevel;\n /**\n * A user-specific level for this logger. If set, this overrides\n * `defaultLevel`.\n * @type {number|null}\n */\n var userLevel;\n\n var storageKey = \"loglevel\";\n if (typeof name === \"string\") {\n storageKey += \":\" + name;\n } else if (typeof name === \"symbol\") {\n storageKey = undefined;\n }\n\n function persistLevelIfPossible(levelNum) {\n var levelName = (logMethods[levelNum] || 'silent').toUpperCase();\n\n if (typeof window === undefinedType || !storageKey) return;\n\n // Use localStorage if available\n try {\n window.localStorage[storageKey] = levelName;\n return;\n } catch (ignore) {}\n\n // Use session cookie as fallback\n try {\n window.document.cookie =\n encodeURIComponent(storageKey) + \"=\" + levelName + \";\";\n } catch (ignore) {}\n }\n\n function getPersistedLevel() {\n var storedLevel;\n\n if (typeof window === undefinedType || !storageKey) return;\n\n try {\n storedLevel = window.localStorage[storageKey];\n } catch (ignore) {}\n\n // Fallback to cookies if local storage gives us nothing\n if (typeof storedLevel === undefinedType) {\n try {\n var cookie = window.document.cookie;\n var cookieName = encodeURIComponent(storageKey);\n var location = cookie.indexOf(cookieName + \"=\");\n if (location !== -1) {\n storedLevel = /^([^;]+)/.exec(\n cookie.slice(location + cookieName.length + 1)\n )[1];\n }\n } catch (ignore) {}\n }\n\n // If the stored level is not valid, treat it as if nothing was stored.\n if (self.levels[storedLevel] === undefined) {\n storedLevel = undefined;\n }\n\n return storedLevel;\n }\n\n function clearPersistedLevel() {\n if (typeof window === undefinedType || !storageKey) return;\n\n // Use localStorage if available\n try {\n window.localStorage.removeItem(storageKey);\n } catch (ignore) {}\n\n // Use session cookie as fallback\n try {\n window.document.cookie =\n encodeURIComponent(storageKey) + \"=; expires=Thu, 01 Jan 1970 00:00:00 UTC\";\n } catch (ignore) {}\n }\n\n function normalizeLevel(input) {\n var level = input;\n if (typeof level === \"string\" && self.levels[level.toUpperCase()] !== undefined) {\n level = self.levels[level.toUpperCase()];\n }\n if (typeof level === \"number\" && level >= 0 && level <= self.levels.SILENT) {\n return level;\n } else {\n throw new TypeError(\"log.setLevel() called with invalid level: \" + input);\n }\n }\n\n /*\n *\n * Public logger API - see https://github.com/pimterry/loglevel for details\n *\n */\n\n self.name = name;\n\n self.levels = { \"TRACE\": 0, \"DEBUG\": 1, \"INFO\": 2, \"WARN\": 3,\n \"ERROR\": 4, \"SILENT\": 5};\n\n self.methodFactory = factory || defaultMethodFactory;\n\n self.getLevel = function () {\n if (userLevel != null) {\n return userLevel;\n } else if (defaultLevel != null) {\n return defaultLevel;\n } else {\n return inheritedLevel;\n }\n };\n\n self.setLevel = function (level, persist) {\n userLevel = normalizeLevel(level);\n if (persist !== false) { // defaults to true\n persistLevelIfPossible(userLevel);\n }\n\n // NOTE: in v2, this should call rebuild(), which updates children.\n return replaceLoggingMethods.call(self);\n };\n\n self.setDefaultLevel = function (level) {\n defaultLevel = normalizeLevel(level);\n if (!getPersistedLevel()) {\n self.setLevel(level, false);\n }\n };\n\n self.resetLevel = function () {\n userLevel = null;\n clearPersistedLevel();\n replaceLoggingMethods.call(self);\n };\n\n self.enableAll = function(persist) {\n self.setLevel(self.levels.TRACE, persist);\n };\n\n self.disableAll = function(persist) {\n self.setLevel(self.levels.SILENT, persist);\n };\n\n self.rebuild = function () {\n if (defaultLogger !== self) {\n inheritedLevel = normalizeLevel(defaultLogger.getLevel());\n }\n replaceLoggingMethods.call(self);\n\n if (defaultLogger === self) {\n for (var childName in _loggersByName) {\n _loggersByName[childName].rebuild();\n }\n }\n };\n\n // Initialize all the internal levels.\n inheritedLevel = normalizeLevel(\n defaultLogger ? defaultLogger.getLevel() : \"WARN\"\n );\n var initialLevel = getPersistedLevel();\n if (initialLevel != null) {\n userLevel = normalizeLevel(initialLevel);\n }\n replaceLoggingMethods.call(self);\n }\n\n /*\n *\n * Top-level API\n *\n */\n\n defaultLogger = new Logger();\n\n defaultLogger.getLogger = function getLogger(name) {\n if ((typeof name !== \"symbol\" && typeof name !== \"string\") || name === \"\") {\n throw new TypeError(\"You must supply a name when creating a logger.\");\n }\n\n var logger = _loggersByName[name];\n if (!logger) {\n logger = _loggersByName[name] = new Logger(\n name,\n defaultLogger.methodFactory\n );\n }\n return logger;\n };\n\n // Grab the current global log variable in case of overwrite\n var _log = (typeof window !== undefinedType) ? window.log : undefined;\n defaultLogger.noConflict = function() {\n if (typeof window !== undefinedType &&\n window.log === defaultLogger) {\n window.log = _log;\n }\n\n return defaultLogger;\n };\n\n defaultLogger.getLoggers = function getLoggers() {\n return _loggersByName;\n };\n\n // ES6 default export, for compatibility\n defaultLogger['default'] = defaultLogger;\n\n return defaultLogger;\n}));\n","/*\nCopyright 2018 André Jaenisch\nCopyright 2019, 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport loglevel from \"loglevel\";\n\n/** Backwards-compatibility hack to expose `log` to applications that might still be relying on it. */\ninterface LoggerWithLogMethod extends Logger {\n /**\n * Output debug message to the logger.\n *\n * @param msg - Data to log.\n *\n * @deprecated prefer {@link Logger.debug}.\n */\n log(...msg: any[]): void;\n}\n\n/** Logger interface used within the js-sdk codebase */\nexport interface Logger extends BaseLogger {\n /**\n * Create a child logger.\n *\n * @param namespace - name to add to the current logger to generate the child. Some implementations of `Logger`\n * use this as a prefix; others use a different mechanism.\n */\n getChild(namespace: string): Logger;\n}\n\n/** The basic interface for a logger which doesn't support children */\nexport interface BaseLogger {\n /**\n * Output trace message to the logger, with stack trace.\n *\n * @param msg - Data to log.\n */\n trace(...msg: any[]): void;\n\n /**\n * Output debug message to the logger.\n *\n * @param msg - Data to log.\n */\n debug(...msg: any[]): void;\n\n /**\n * Output info message to the logger.\n *\n * @param msg - Data to log.\n */\n info(...msg: any[]): void;\n\n /**\n * Output warn message to the logger.\n *\n * @param msg - Data to log.\n */\n warn(...msg: any[]): void;\n\n /**\n * Output error message to the logger.\n *\n * @param msg - Data to log.\n */\n error(...msg: any[]): void;\n}\n\n// This is to demonstrate, that you can use any namespace you want.\n// Namespaces allow you to turn on/off the logging for specific parts of the\n// application.\n// An idea would be to control this via an environment variable (on Node.js).\n// See https://www.npmjs.com/package/debug to see how this could be implemented\n// Part of #332 is introducing a logging library in the first place.\nconst DEFAULT_NAMESPACE = \"matrix\";\n\n// because rageshakes in react-sdk hijack the console log, also at module load time,\n// initializing the logger here races with the initialization of rageshakes.\n// to avoid the issue, we override the methodFactory of loglevel that binds to the\n// console methods at initialization time by a factory that looks up the console methods\n// when logging so we always get the current value of console methods.\nloglevel.methodFactory = function (methodName, logLevel, loggerName) {\n return function (this: PrefixedLogger, ...args): void {\n /* eslint-disable @typescript-eslint/no-invalid-this */\n if (this.prefix) {\n args.unshift(this.prefix);\n }\n /* eslint-enable @typescript-eslint/no-invalid-this */\n const supportedByConsole =\n methodName === \"error\" ||\n methodName === \"warn\" ||\n methodName === \"trace\" ||\n methodName === \"info\" ||\n methodName === \"debug\";\n /* eslint-disable no-console */\n if (supportedByConsole) {\n return console[methodName](...args);\n } else {\n return console.log(...args);\n }\n /* eslint-enable no-console */\n };\n};\n\n/**\n * Implementation of {@link Logger} based on `loglevel`.\n */\ninterface PrefixedLogger extends loglevel.Logger, LoggerWithLogMethod {\n prefix?: string;\n}\n\n/**\n * Internal utility function: gets a {@link Logger} based on `loglevel`.\n *\n * Child loggers produced by {@link Logger.getChild} add the name of the child logger as a prefix on each log line.\n *\n * @param prefix Prefix to add to each logged line. If undefined, no prefix will be added.\n */\nfunction getPrefixedLogger(prefix?: string): LoggerWithLogMethod {\n const loggerName = DEFAULT_NAMESPACE + (prefix === undefined ? \"\" : `-${prefix}`);\n const prefixLogger = loglevel.getLogger(loggerName) as PrefixedLogger;\n\n if (prefixLogger.getChild === undefined) {\n // This is a new loglevel Logger which has not been turned into a PrefixedLogger yet.\n prefixLogger.prefix = prefix;\n prefixLogger.getChild = (childPrefix): Logger => getPrefixedLogger((prefix ?? \"\") + childPrefix);\n prefixLogger.setLevel(loglevel.levels.DEBUG, false);\n }\n\n return prefixLogger;\n}\n\n/**\n * Drop-in replacement for `console` using {@link https://www.npmjs.com/package/loglevel|loglevel}.\n * Can be tailored down to specific use cases if needed.\n */\nexport const logger = getPrefixedLogger();\n\n/**\n * A \"span\" for grouping related log lines together.\n *\n * The current implementation just adds the name at the start of each log line.\n *\n * This offers a lighter-weight alternative to 'child' loggers returned by {@link Logger#getChild}. In particular,\n * it's not possible to apply individual filters to the LogSpan such as setting the verbosity level. On the other hand,\n * no reference to the LogSpan is retained in the logging framework, so it is safe to make lots of them over the course\n * of an application's life and just drop references to them when the job is done.\n */\nexport class LogSpan implements BaseLogger {\n private readonly name;\n\n public constructor(\n private readonly parent: BaseLogger,\n name: string,\n ) {\n this.name = name + \":\";\n }\n\n public trace(...msg: any[]): void {\n this.parent.trace(this.name, ...msg);\n }\n\n public debug(...msg: any[]): void {\n this.parent.debug(this.name, ...msg);\n }\n\n public info(...msg: any[]): void {\n this.parent.info(this.name, ...msg);\n }\n\n public warn(...msg: any[]): void {\n this.parent.warn(this.name, ...msg);\n }\n\n public error(...msg: any[]): void {\n this.parent.error(this.name, ...msg);\n }\n}\n","'use strict';\n\n\nvar data = require('./data.json');\n\nfunction escapeRegexp(str) {\n return str.replace(/([.?*+^$[\\]\\\\(){}|-])/g, '\\\\$1');\n}\n\nvar REPLACE_RE = RegExp(Object.keys(data).map(escapeRegexp).join('|'), 'g');\n\nfunction replace_fn(match) {\n return data[match];\n}\n\nfunction unhomoglyph(str) {\n return str.replace(REPLACE_RE, replace_fn);\n}\n\nmodule.exports = unhomoglyph;\n","function RetryOperation(timeouts, options) {\n // Compatibility for the old (timeouts, retryForever) signature\n if (typeof options === 'boolean') {\n options = { forever: options };\n }\n\n this._originalTimeouts = JSON.parse(JSON.stringify(timeouts));\n this._timeouts = timeouts;\n this._options = options || {};\n this._maxRetryTime = options && options.maxRetryTime || Infinity;\n this._fn = null;\n this._errors = [];\n this._attempts = 1;\n this._operationTimeout = null;\n this._operationTimeoutCb = null;\n this._timeout = null;\n this._operationStart = null;\n this._timer = null;\n\n if (this._options.forever) {\n this._cachedTimeouts = this._timeouts.slice(0);\n }\n}\nmodule.exports = RetryOperation;\n\nRetryOperation.prototype.reset = function() {\n this._attempts = 1;\n this._timeouts = this._originalTimeouts.slice(0);\n}\n\nRetryOperation.prototype.stop = function() {\n if (this._timeout) {\n clearTimeout(this._timeout);\n }\n if (this._timer) {\n clearTimeout(this._timer);\n }\n\n this._timeouts = [];\n this._cachedTimeouts = null;\n};\n\nRetryOperation.prototype.retry = function(err) {\n if (this._timeout) {\n clearTimeout(this._timeout);\n }\n\n if (!err) {\n return false;\n }\n var currentTime = new Date().getTime();\n if (err && currentTime - this._operationStart >= this._maxRetryTime) {\n this._errors.push(err);\n this._errors.unshift(new Error('RetryOperation timeout occurred'));\n return false;\n }\n\n this._errors.push(err);\n\n var timeout = this._timeouts.shift();\n if (timeout === undefined) {\n if (this._cachedTimeouts) {\n // retry forever, only keep last error\n this._errors.splice(0, this._errors.length - 1);\n timeout = this._cachedTimeouts.slice(-1);\n } else {\n return false;\n }\n }\n\n var self = this;\n this._timer = setTimeout(function() {\n self._attempts++;\n\n if (self._operationTimeoutCb) {\n self._timeout = setTimeout(function() {\n self._operationTimeoutCb(self._attempts);\n }, self._operationTimeout);\n\n if (self._options.unref) {\n self._timeout.unref();\n }\n }\n\n self._fn(self._attempts);\n }, timeout);\n\n if (this._options.unref) {\n this._timer.unref();\n }\n\n return true;\n};\n\nRetryOperation.prototype.attempt = function(fn, timeoutOps) {\n this._fn = fn;\n\n if (timeoutOps) {\n if (timeoutOps.timeout) {\n this._operationTimeout = timeoutOps.timeout;\n }\n if (timeoutOps.cb) {\n this._operationTimeoutCb = timeoutOps.cb;\n }\n }\n\n var self = this;\n if (this._operationTimeoutCb) {\n this._timeout = setTimeout(function() {\n self._operationTimeoutCb();\n }, self._operationTimeout);\n }\n\n this._operationStart = new Date().getTime();\n\n this._fn(this._attempts);\n};\n\nRetryOperation.prototype.try = function(fn) {\n console.log('Using RetryOperation.try() is deprecated');\n this.attempt(fn);\n};\n\nRetryOperation.prototype.start = function(fn) {\n console.log('Using RetryOperation.start() is deprecated');\n this.attempt(fn);\n};\n\nRetryOperation.prototype.start = RetryOperation.prototype.try;\n\nRetryOperation.prototype.errors = function() {\n return this._errors;\n};\n\nRetryOperation.prototype.attempts = function() {\n return this._attempts;\n};\n\nRetryOperation.prototype.mainError = function() {\n if (this._errors.length === 0) {\n return null;\n }\n\n var counts = {};\n var mainError = null;\n var mainErrorCount = 0;\n\n for (var i = 0; i < this._errors.length; i++) {\n var error = this._errors[i];\n var message = error.message;\n var count = (counts[message] || 0) + 1;\n\n counts[message] = count;\n\n if (count >= mainErrorCount) {\n mainError = error;\n mainErrorCount = count;\n }\n }\n\n return mainError;\n};\n","var RetryOperation = require('./retry_operation');\n\nexports.operation = function(options) {\n var timeouts = exports.timeouts(options);\n return new RetryOperation(timeouts, {\n forever: options && (options.forever || options.retries === Infinity),\n unref: options && options.unref,\n maxRetryTime: options && options.maxRetryTime\n });\n};\n\nexports.timeouts = function(options) {\n if (options instanceof Array) {\n return [].concat(options);\n }\n\n var opts = {\n retries: 10,\n factor: 2,\n minTimeout: 1 * 1000,\n maxTimeout: Infinity,\n randomize: false\n };\n for (var key in options) {\n opts[key] = options[key];\n }\n\n if (opts.minTimeout > opts.maxTimeout) {\n throw new Error('minTimeout is greater than maxTimeout');\n }\n\n var timeouts = [];\n for (var i = 0; i < opts.retries; i++) {\n timeouts.push(this.createTimeout(i, opts));\n }\n\n if (options && options.forever && !timeouts.length) {\n timeouts.push(this.createTimeout(i, opts));\n }\n\n // sort the array numerically ascending\n timeouts.sort(function(a,b) {\n return a - b;\n });\n\n return timeouts;\n};\n\nexports.createTimeout = function(attempt, opts) {\n var random = (opts.randomize)\n ? (Math.random() + 1)\n : 1;\n\n var timeout = Math.round(random * Math.max(opts.minTimeout, 1) * Math.pow(opts.factor, attempt));\n timeout = Math.min(timeout, opts.maxTimeout);\n\n return timeout;\n};\n\nexports.wrap = function(obj, options, methods) {\n if (options instanceof Array) {\n methods = options;\n options = null;\n }\n\n if (!methods) {\n methods = [];\n for (var key in obj) {\n if (typeof obj[key] === 'function') {\n methods.push(key);\n }\n }\n }\n\n for (var i = 0; i < methods.length; i++) {\n var method = methods[i];\n var original = obj[method];\n\n obj[method] = function retryWrapper(original) {\n var op = exports.operation(options);\n var args = Array.prototype.slice.call(arguments, 1);\n var callback = args.pop();\n\n args.push(function(err) {\n if (op.retry(err)) {\n return;\n }\n if (err) {\n arguments[0] = op.mainError();\n }\n callback.apply(this, arguments);\n });\n\n op.attempt(function() {\n original.apply(obj, args);\n });\n }.bind(obj, original);\n obj[method].options = options;\n }\n};\n","module.exports = require('./lib/retry');","'use strict';\nconst retry = require('retry');\n\nconst networkErrorMsgs = [\n\t'Failed to fetch', // Chrome\n\t'NetworkError when attempting to fetch resource.', // Firefox\n\t'The Internet connection appears to be offline.', // Safari\n\t'Network request failed' // `cross-fetch`\n];\n\nclass AbortError extends Error {\n\tconstructor(message) {\n\t\tsuper();\n\n\t\tif (message instanceof Error) {\n\t\t\tthis.originalError = message;\n\t\t\t({message} = message);\n\t\t} else {\n\t\t\tthis.originalError = new Error(message);\n\t\t\tthis.originalError.stack = this.stack;\n\t\t}\n\n\t\tthis.name = 'AbortError';\n\t\tthis.message = message;\n\t}\n}\n\nconst decorateErrorWithCounts = (error, attemptNumber, options) => {\n\t// Minus 1 from attemptNumber because the first attempt does not count as a retry\n\tconst retriesLeft = options.retries - (attemptNumber - 1);\n\n\terror.attemptNumber = attemptNumber;\n\terror.retriesLeft = retriesLeft;\n\treturn error;\n};\n\nconst isNetworkError = errorMessage => networkErrorMsgs.includes(errorMessage);\n\nconst pRetry = (input, options) => new Promise((resolve, reject) => {\n\toptions = {\n\t\tonFailedAttempt: () => {},\n\t\tretries: 10,\n\t\t...options\n\t};\n\n\tconst operation = retry.operation(options);\n\n\toperation.attempt(async attemptNumber => {\n\t\ttry {\n\t\t\tresolve(await input(attemptNumber));\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof Error)) {\n\t\t\t\treject(new TypeError(`Non-error was thrown: \"${error}\". You should only throw errors.`));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (error instanceof AbortError) {\n\t\t\t\toperation.stop();\n\t\t\t\treject(error.originalError);\n\t\t\t} else if (error instanceof TypeError && !isNetworkError(error.message)) {\n\t\t\t\toperation.stop();\n\t\t\t\treject(error);\n\t\t\t} else {\n\t\t\t\tdecorateErrorWithCounts(error, attemptNumber, options);\n\n\t\t\t\ttry {\n\t\t\t\t\tawait options.onFailedAttempt(error);\n\t\t\t\t} catch (error) {\n\t\t\t\t\treject(error);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!operation.retry(error)) {\n\t\t\t\t\treject(operation.mainError());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n});\n\nmodule.exports = pRetry;\n// TODO: remove this in the next major version\nmodule.exports.default = pRetry;\n\nmodule.exports.AbortError = AbortError;\n","/*\nCopyright 2021 - 2022 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { type Optional } from \"matrix-events-sdk/lib/types\";\n\n/**\n * Represents a simple Matrix namespaced value. This will assume that if a stable prefix\n * is provided that the stable prefix should be used when representing the identifier.\n */\nexport class NamespacedValue<S extends string, U extends string> {\n // Stable is optional, but one of the two parameters is required, hence the weird-looking types.\n // Goal is to to have developers explicitly say there is no stable value (if applicable).\n public constructor(stable: S, unstable: U);\n public constructor(stable: S, unstable?: U);\n public constructor(stable: null | undefined, unstable: U);\n public constructor(\n public readonly stable?: S | null,\n public readonly unstable?: U,\n ) {\n if (!this.unstable && !this.stable) {\n throw new Error(\"One of stable or unstable values must be supplied\");\n }\n }\n\n public get name(): U | S {\n if (this.stable) {\n return this.stable;\n }\n return this.unstable!;\n }\n\n public get altName(): U | S | null | undefined {\n if (!this.stable) {\n return null;\n }\n return this.unstable;\n }\n\n public get names(): (U | S)[] {\n const names = [this.name];\n const altName = this.altName;\n if (altName) names.push(altName);\n return names;\n }\n\n public matches(val: string): boolean {\n return this.name === val || this.altName === val;\n }\n\n // this desperately wants https://github.com/microsoft/TypeScript/pull/26349 at the top level of the class\n // so we can instantiate `NamespacedValue<string, _, _>` as a default type for that namespace.\n public findIn<T>(obj: any): Optional<T> {\n let val: T | undefined = undefined;\n if (this.name) {\n val = obj?.[this.name];\n }\n if (!val && this.altName) {\n val = obj?.[this.altName];\n }\n return val;\n }\n\n public includedIn(arr: any[]): boolean {\n let included = false;\n if (this.name) {\n included = arr.includes(this.name);\n }\n if (!included && this.altName) {\n included = arr.includes(this.altName);\n }\n return included;\n }\n}\n\nexport class ServerControlledNamespacedValue<S extends string, U extends string> extends NamespacedValue<S, U> {\n private preferUnstable = false;\n\n public setPreferUnstable(preferUnstable: boolean): void {\n this.preferUnstable = preferUnstable;\n }\n\n public get name(): U | S {\n if (this.stable && !this.preferUnstable) {\n return this.stable;\n }\n return this.unstable!;\n }\n}\n\n/**\n * Represents a namespaced value which prioritizes the unstable value over the stable\n * value.\n */\nexport class UnstableValue<S extends string, U extends string> extends NamespacedValue<S, U> {\n // Note: Constructor difference is that `unstable` is *required*.\n public constructor(stable: S, unstable: U) {\n super(stable, unstable);\n if (!this.unstable) {\n throw new Error(\"Unstable value must be supplied\");\n }\n }\n\n public get name(): U {\n return this.unstable!;\n }\n\n public get altName(): S {\n return this.stable!;\n }\n}\n","/*\nCopyright 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n// Types for MSC3488 - m.location: Extending events with location data\nimport { type EitherAnd } from \"matrix-events-sdk\";\n\nimport { UnstableValue } from \"../NamespacedValue.ts\";\nimport { type M_TEXT } from \"./extensible_events.ts\";\n\nexport enum LocationAssetType {\n Self = \"m.self\",\n Pin = \"m.pin\",\n}\n\nexport const M_ASSET = new UnstableValue(\"m.asset\", \"org.matrix.msc3488.asset\");\nexport type MAssetContent = { type: LocationAssetType };\n/**\n * The event definition for an m.asset event (in content)\n */\nexport type MAssetEvent = EitherAnd<{ [M_ASSET.name]: MAssetContent }, { [M_ASSET.altName]: MAssetContent }>;\n\nexport const M_TIMESTAMP = new UnstableValue(\"m.ts\", \"org.matrix.msc3488.ts\");\n/**\n * The event definition for an m.ts event (in content)\n */\nexport type MTimestampEvent = EitherAnd<{ [M_TIMESTAMP.name]: number }, { [M_TIMESTAMP.altName]: number }>;\n\nexport const M_LOCATION = new UnstableValue(\"m.location\", \"org.matrix.msc3488.location\");\n\nexport type MLocationContent = {\n uri: string;\n description?: string | null;\n};\n\nexport type MLocationEvent = EitherAnd<\n { [M_LOCATION.name]: MLocationContent },\n { [M_LOCATION.altName]: MLocationContent }\n>;\n\nexport type MTextEvent = EitherAnd<{ [M_TEXT.name]: string }, { [M_TEXT.altName]: string }>;\n\n/* From the spec at:\n * https://github.com/matrix-org/matrix-doc/blob/matthew/location/proposals/3488-location.md\n{\n \"type\": \"m.room.message\",\n \"content\": {\n \"body\": \"Matthew was at geo:51.5008,0.1247;u=35 as of Sat Nov 13 18:50:58 2021\",\n \"msgtype\": \"m.location\",\n \"geo_uri\": \"geo:51.5008,0.1247;u=35\",\n \"m.location\": {\n \"uri\": \"geo:51.5008,0.1247;u=35\",\n \"description\": \"Matthew's whereabouts\",\n },\n \"m.asset\": {\n \"type\": \"m.self\"\n },\n \"m.text\": \"Matthew was at geo:51.5008,0.1247;u=35 as of Sat Nov 13 18:50:58 2021\",\n \"m.ts\": 1636829458432,\n }\n}\n*/\ntype OptionalTimestampEvent = MTimestampEvent | undefined;\n/**\n * The content for an m.location event\n */\nexport type MLocationEventContent = MLocationEvent & MAssetEvent & MTextEvent & OptionalTimestampEvent;\n\nexport type LegacyLocationEventContent = {\n body: string;\n msgtype: string;\n geo_uri: string;\n};\n\n/**\n * Possible content for location events as sent over the wire\n */\nexport type LocationEventWireContent = Partial<LegacyLocationEventContent & MLocationEventContent>;\n\nexport type ILocationContent = MLocationEventContent & LegacyLocationEventContent;\n","/*\nCopyright 2022 Šimon Brandner <simon.bra.ag@gmail.com>\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nexport enum ReceiptType {\n Read = \"m.read\",\n FullyRead = \"m.fully_read\",\n ReadPrivate = \"m.read.private\",\n}\n\nexport const MAIN_ROOM_TIMELINE = \"main\";\n\nexport interface Receipt {\n ts: number;\n thread_id?: string;\n}\n\nexport interface WrappedReceipt {\n eventId: string;\n data: Receipt;\n}\n\nexport interface CachedReceipt {\n type: ReceiptType;\n userId: string;\n data: Receipt;\n}\n\nexport type ReceiptCache = Map<string, CachedReceipt[]>;\n\nexport interface ReceiptContent {\n [eventId: string]: {\n [key in ReceiptType | string]: {\n [userId: string]: Receipt;\n };\n };\n}\n\n// We will only hold a synthetic receipt if we do not have a real receipt or the synthetic is newer.\n// map: receipt type → user Id → receipt\nexport type Receipts = Map<string, Map<string, [real: WrappedReceipt | null, synthetic: WrappedReceipt | null]>>;\n\nexport type CachedReceiptStructure = {\n eventId: string;\n receiptType: string | ReceiptType;\n userId: string;\n receipt: Receipt;\n synthetic: boolean;\n};\n","/*\nCopyright 2015, 2016, 2019, 2023 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n/**\n * This is an internal module.\n */\n\nimport unhomoglyph from \"unhomoglyph\";\nimport promiseRetry from \"p-retry\";\nimport { type Optional } from \"matrix-events-sdk\";\n\nimport { type IEvent, type MatrixEvent } from \"./models/event.ts\";\nimport { M_TIMESTAMP } from \"./@types/location.ts\";\nimport { ReceiptType } from \"./@types/read_receipts.ts\";\nimport { type BaseLogger } from \"./logger.ts\";\n\nconst interns = new Map<string, string>();\n\n/**\n * Internalises a string, reusing a known pointer or storing the pointer\n * if needed for future strings.\n * @param str - The string to internalise.\n * @returns The internalised string.\n */\nexport function internaliseString(str: string): string {\n // Unwrap strings before entering the map, if we somehow got a wrapped\n // string as our input. This should only happen from tests.\n if ((str as unknown) instanceof String) {\n str = str.toString();\n }\n\n // Check the map to see if we can store the value\n if (!interns.has(str)) {\n interns.set(str, str);\n }\n\n // Return any cached string reference\n return interns.get(str)!;\n}\n\n/**\n * Encode a dictionary of query parameters.\n * Omits any undefined/null values.\n * @param params - A dict of key/values to encode e.g.\n * `{\"foo\": \"bar\", \"baz\": \"taz\"}`\n * @returns The encoded string e.g. foo=bar&baz=taz\n */\nexport function encodeParams(params: QueryDict, urlSearchParams?: URLSearchParams): URLSearchParams {\n const searchParams = urlSearchParams ?? new URLSearchParams();\n for (const [key, val] of Object.entries(params)) {\n if (val !== undefined && val !== null) {\n if (Array.isArray(val)) {\n val.forEach((v) => {\n searchParams.append(key, String(v));\n });\n } else {\n searchParams.append(key, String(val));\n }\n }\n }\n return searchParams;\n}\n\nexport type QueryDict = Record<string, string[] | string | number | boolean | undefined>;\n\n/**\n * Replace a stable parameter with the unstable naming for params\n */\nexport function replaceParam(stable: string, unstable: string, dict: QueryDict): QueryDict {\n const result = {\n ...dict,\n [unstable]: dict[stable],\n };\n delete result[stable];\n return result;\n}\n\n/**\n * Decode a query string in `application/x-www-form-urlencoded` format.\n * @param query - A query string to decode e.g.\n * foo=bar&via=server1&server2\n * @returns The decoded object, if any keys occurred multiple times\n * then the value will be an array of strings, else it will be an array.\n * This behaviour matches Node's qs.parse but is built on URLSearchParams\n * for native web compatibility\n */\nexport function decodeParams(query: string): Record<string, string | string[]> {\n const o: Record<string, string | string[]> = {};\n const params = new URLSearchParams(query);\n for (const key of params.keys()) {\n const val = params.getAll(key);\n o[key] = val.length === 1 ? val[0] : val;\n }\n return o;\n}\n\n/**\n * Encodes a URI according to a set of template variables. Variables will be\n * passed through encodeURIComponent.\n * @param pathTemplate - The path with template variables e.g. '/foo/$bar'.\n * @param variables - The key/value pairs to replace the template\n * variables with. E.g. `{ \"$bar\": \"baz\" }`.\n * @returns The result of replacing all template variables e.g. '/foo/baz'.\n */\nexport function encodeUri(pathTemplate: string, variables: Record<string, Optional<string>>): string {\n for (const key in variables) {\n if (!variables.hasOwnProperty(key)) {\n continue;\n }\n const value = variables[key];\n if (value === undefined || value === null) {\n continue;\n }\n pathTemplate = pathTemplate.replace(key, encodeURIComponent(value));\n }\n return pathTemplate;\n}\n\n/**\n * The removeElement() method removes the first element in the array that\n * satisfies (returns true) the provided testing function.\n * @param array - The array.\n * @param fn - Function to execute on each value in the array, with the\n * function signature `fn(element, index, array)`. Return true to\n * remove this element and break.\n * @param reverse - True to search in reverse order.\n * @returns True if an element was removed.\n */\nexport function removeElement<T>(array: T[], fn: (t: T, i?: number, a?: T[]) => boolean, reverse?: boolean): boolean {\n let i: number;\n if (reverse) {\n for (i = array.length - 1; i >= 0; i--) {\n if (fn(array[i], i, array)) {\n array.splice(i, 1);\n return true;\n }\n }\n } else {\n for (i = 0; i < array.length; i++) {\n if (fn(array[i], i, array)) {\n array.splice(i, 1);\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Checks if the given thing is a function.\n * @param value - The thing to check.\n * @returns True if it is a function.\n */\nexport function isFunction(value: any): boolean {\n return Object.prototype.toString.call(value) === \"[object Function]\";\n}\n\n/**\n * Checks that the given object has the specified keys.\n * @param obj - The object to check.\n * @param keys - The list of keys that 'obj' must have.\n * @throws If the object is missing keys.\n */\n// note using 'keys' here would shadow the 'keys' function defined above\nexport function checkObjectHasKeys(obj: object, keys: string[]): void {\n for (const key of keys) {\n if (!obj.hasOwnProperty(key)) {\n throw new Error(\"Missing required key: \" + key);\n }\n }\n}\n\n/**\n * Deep copy the given object. The object MUST NOT have circular references and\n * MUST NOT have functions.\n * @param obj - The object to deep copy.\n * @returns A copy of the object without any references to the original.\n */\nexport function deepCopy<T>(obj: T): T {\n return JSON.parse(JSON.stringify(obj));\n}\n\n/**\n * Compare two objects for equality. The objects MUST NOT have circular references.\n *\n * @param x - The first object to compare.\n * @param y - The second object to compare.\n *\n * @returns true if the two objects are equal\n */\nexport function deepCompare(x: any, y: any): boolean {\n // Inspired by\n // http://stackoverflow.com/questions/1068834/object-comparison-in-javascript#1144249\n\n // Compare primitives and functions.\n // Also check if both arguments link to the same object.\n if (x === y) {\n return true;\n }\n\n if (typeof x !== typeof y) {\n return false;\n }\n\n // special-case NaN (since NaN !== NaN)\n if (typeof x === \"number\" && isNaN(x) && isNaN(y)) {\n return true;\n }\n\n // special-case null (since typeof null == 'object', but null.constructor\n // throws)\n if (x === null || y === null) {\n return x === y;\n }\n\n // everything else is either an unequal primitive, or an object\n if (!(x instanceof Object)) {\n return false;\n }\n\n // check they are the same type of object\n if (x.constructor !== y.constructor || x.prototype !== y.prototype) {\n return false;\n }\n\n // special-casing for some special types of object\n if (x instanceof RegExp || x instanceof Date) {\n return x.toString() === y.toString();\n }\n\n // the object algorithm works for Array, but it's sub-optimal.\n if (Array.isArray(x)) {\n if (x.length !== y.length) {\n return false;\n }\n\n for (let i = 0; i < x.length; i++) {\n if (!deepCompare(x[i], y[i])) {\n return false;\n }\n }\n } else {\n // check that all of y's direct keys are in x\n for (const p in y) {\n if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {\n return false;\n }\n }\n\n // finally, compare each of x's keys with y\n for (const p in x) {\n if (y.hasOwnProperty(p) !== x.hasOwnProperty(p) || !deepCompare(x[p], y[p])) {\n return false;\n }\n }\n }\n return true;\n}\n\n// Dev note: This returns an array of tuples, but jsdoc doesn't like that. https://github.com/jsdoc/jsdoc/issues/1703\n/**\n * Creates an array of object properties/values (entries) then\n * sorts the result by key, recursively. The input object must\n * ensure it does not have loops. If the input is not an object\n * then it will be returned as-is.\n * @param obj - The object to get entries of\n * @returns The entries, sorted by key.\n */\nexport function deepSortedObjectEntries(obj: any): [string, any][] {\n if (typeof obj !== \"object\") return obj;\n\n // Apparently these are object types...\n if (obj === null || obj === undefined || Array.isArray(obj)) return obj;\n\n const pairs: [string, any][] = [];\n for (const [k, v] of Object.entries(obj)) {\n pairs.push([k, deepSortedObjectEntries(v)]);\n }\n\n // lexicographicCompare is faster than localeCompare, so let's use that.\n pairs.sort((a, b) => lexicographicCompare(a[0], b[0]));\n\n return pairs;\n}\n\n/**\n * Returns whether the given value is a finite number without type-coercion\n *\n * @param value - the value to test\n * @returns whether or not value is a finite number without type-coercion\n */\nexport function isNumber(value: any): value is number {\n return typeof value === \"number\" && isFinite(value);\n}\n\n/**\n * Removes zero width chars, diacritics and whitespace from the string\n * Also applies an unhomoglyph on the string, to prevent similar looking chars\n * @param str - the string to remove hidden characters from\n * @returns a string with the hidden characters removed\n */\nexport function removeHiddenChars(str: string): string {\n if (typeof str === \"string\") {\n return unhomoglyph(str.normalize(\"NFD\").replace(removeHiddenCharsRegex, \"\"));\n }\n return \"\";\n}\n\n/**\n * Removes the direction override characters from a string\n * @returns string with chars removed\n */\nexport function removeDirectionOverrideChars(str: string): string {\n if (typeof str === \"string\") {\n return str.replace(/[\\u202d-\\u202e]/g, \"\");\n }\n return \"\";\n}\n\nexport function normalize(str: string): string {\n // Note: we have to match the filter with the removeHiddenChars() because the\n // function strips spaces and other characters (M becomes RN for example, in lowercase).\n return (\n removeHiddenChars(str.toLowerCase())\n // Strip all punctuation\n .replace(/[\\\\'!\"#$%&()*+,\\-./:;<=>?@[\\]^_`{|}~\\u2000-\\u206f\\u2e00-\\u2e7f]/g, \"\")\n // We also doubly convert to lowercase to work around oddities of the library.\n .toLowerCase()\n );\n}\n\n// Regex matching bunch of unicode control characters and otherwise misleading/invisible characters.\n// Includes:\n// various width spaces U+2000 - U+200D\n// LTR and RTL marks U+200E and U+200F\n// LTR/RTL and other directional formatting marks U+202A - U+202F\n// Arabic Letter RTL mark U+061C\n// Combining characters U+0300 - U+036F\n// Zero width no-break space (BOM) U+FEFF\n// Blank/invisible characters (U2800, U2062-U2063)\n// eslint-disable-next-line no-misleading-character-class\nconst removeHiddenCharsRegex = /[\\u2000-\\u200F\\u202A-\\u202F\\u0300-\\u036F\\uFEFF\\u061C\\u2800\\u2062-\\u2063\\s]/g;\n\nexport function escapeRegExp(string: string): string {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Converts Matrix glob-style string to a regular expression\n * https://spec.matrix.org/v1.7/appendices/#glob-style-matching\n * @param glob - Matrix glob-style string\n * @returns regular expression\n */\nexport function globToRegexp(glob: string): string {\n return escapeRegExp(glob).replace(/\\\\\\*/g, \".*\").replace(/\\?/g, \".\");\n}\n\nexport function ensureNoTrailingSlash(url: string): string;\nexport function ensureNoTrailingSlash(url: undefined): undefined;\nexport function ensureNoTrailingSlash(url?: string): string | undefined;\nexport function ensureNoTrailingSlash(url?: string): string | undefined {\n if (url?.endsWith(\"/\")) {\n return url.slice(0, -1);\n } else {\n return url;\n }\n}\n\n/**\n * Returns a promise which resolves with a given value after the given number of ms\n */\nexport function sleep<T>(ms: number, value?: T): Promise<T> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms, value);\n });\n}\n\n/**\n * Utility to log the duration of a promise.\n *\n * @param logger - The logger to log to.\n * @param name - The name of the operation.\n * @param block - The block to execute.\n */\nexport async function logDuration<T>(logger: BaseLogger, name: string, block: () => Promise<T>): Promise<T> {\n const start = Date.now();\n try {\n return await block();\n } finally {\n const end = Date.now();\n logger.debug(`[Perf]: ${name} took ${end - start}ms`);\n }\n}\n\n/**\n * Utility to log the duration of a synchronous block.\n *\n * @param logger - The logger to log to.\n * @param name - The name of the operation.\n * @param block - The block to execute.\n */\nexport function logDurationSync<T>(logger: BaseLogger, name: string, block: () => T): T {\n const start = Date.now();\n try {\n return block();\n } finally {\n const end = Date.now();\n logger.debug(`[Perf]: ${name} took ${end - start}ms`);\n }\n}\n\n/**\n * Promise/async version of {@link setImmediate}.\n *\n * Implementation is based on `setTimeout` for wider compatibility.\n * @deprecated Use {@link sleep} instead.\n */\nexport function immediate(): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve));\n}\n\nexport function isNullOrUndefined(val: any): boolean {\n return val === null || val === undefined;\n}\n\nexport interface IDeferred<T> {\n resolve: (value: T | Promise<T>) => void;\n reject: (reason?: any) => void;\n promise: Promise<T>;\n}\n\n// Returns a Deferred\nexport function defer<T = void>(): IDeferred<T> {\n let resolve!: IDeferred<T>[\"resolve\"];\n let reject!: IDeferred<T>[\"reject\"];\n\n const promise = new Promise<T>((_resolve, _reject) => {\n resolve = _resolve;\n reject = _reject;\n });\n\n return { resolve, reject, promise };\n}\n\nexport async function promiseMapSeries<T>(\n promises: Array<T | Promise<T>>,\n fn: (t: T) => Promise<unknown> | undefined, // if async we don't care about the type as we only await resolution\n): Promise<void> {\n for (const o of promises) {\n await fn(await o);\n }\n}\n\nexport function promiseTry<T>(fn: () => T | Promise<T>): Promise<T> {\n return Promise.resolve(fn());\n}\n\n// Creates and awaits all promises, running no more than `chunkSize` at the same time\nexport async function chunkPromises<T>(fns: (() => Promise<T>)[], chunkSize: number): Promise<T[]> {\n const results: T[] = [];\n for (let i = 0; i < fns.length; i += chunkSize) {\n results.push(...(await Promise.all(fns.slice(i, i + chunkSize).map((fn) => fn()))));\n }\n return results;\n}\n\n/**\n * Retries the function until it succeeds or is interrupted. The given function must return\n * a promise which throws/rejects on error, otherwise the retry will assume the request\n * succeeded. The promise chain returned will contain the successful promise. The given function\n * should always return a new promise.\n * @param promiseFn - The function to call to get a fresh promise instance. Takes an\n * attempt count as an argument, for logging/debugging purposes.\n * @returns The promise for the retried operation.\n */\nexport function simpleRetryOperation<T>(promiseFn: (attempt: number) => Promise<T>): Promise<T> {\n return promiseRetry(\n (attempt: number) => {\n return promiseFn(attempt);\n },\n {\n forever: true,\n factor: 2,\n minTimeout: 3000, // ms\n maxTimeout: 15000, // ms\n },\n );\n}\n\n// String averaging inspired by https://stackoverflow.com/a/2510816\n// Dev note: We make the alphabet a string because it's easier to write syntactically\n// than arrays. Thankfully, strings implement the useful parts of the Array interface\n// anyhow.\n\n/**\n * The default alphabet used by string averaging in this SDK. This matches\n * all usefully printable ASCII characters (0x20-0x7E, inclusive).\n */\nexport const DEFAULT_ALPHABET = ((): string => {\n let str = \"\";\n for (let c = 0x20; c <= 0x7e; c++) {\n str += String.fromCharCode(c);\n }\n return str;\n})();\n\n/**\n * Pads a string using the given alphabet as a base. The returned string will be\n * padded at the end with the first character in the alphabet.\n *\n * This is intended for use with string averaging.\n * @param s - The string to pad.\n * @param n - The length to pad to.\n * @param alphabet - The alphabet to use as a single string.\n * @returns The padded string.\n */\nexport function alphabetPad(s: string, n: number, alphabet = DEFAULT_ALPHABET): string {\n return s.padEnd(n, alphabet[0]);\n}\n\n/**\n * Converts a baseN number to a string, where N is the alphabet's length.\n *\n * This is intended for use with string averaging.\n * @param n - The baseN number.\n * @param alphabet - The alphabet to use as a single string.\n * @returns The baseN number encoded as a string from the alphabet.\n */\nexport function baseToString(n: bigint, alphabet = DEFAULT_ALPHABET): string {\n // Developer note: the stringToBase() function offsets the character set by 1 so that repeated\n // characters (ie: \"aaaaaa\" in a..z) don't come out as zero. We have to reverse this here as\n // otherwise we'll be wrong in our conversion. Undoing a +1 before an exponent isn't very fun\n // though, so we rely on a lengthy amount of `x - 1` and integer division rules to reach a\n // sane state. This also means we have to do rollover detection: see below.\n\n const len = BigInt(alphabet.length);\n if (n <= len) {\n return alphabet[Number(n) - 1] ?? \"\";\n }\n\n let d = n / len;\n let r = Number(n % len) - 1;\n\n // Rollover detection: if the remainder is negative, it means that the string needs\n // to roll over by 1 character downwards (ie: in a..z, the previous to \"aaa\" would be\n // \"zz\").\n if (r < 0) {\n d -= BigInt(Math.abs(r)); // abs() is just to be clear what we're doing. Could also `+= r`.\n r = Number(len) - 1;\n }\n\n return baseToString(d, alphabet) + alphabet[r];\n}\n\n/**\n * Converts a string to a baseN number, where N is the alphabet's length.\n *\n * This is intended for use with string averaging.\n * @param s - The string to convert to a number.\n * @param alphabet - The alphabet to use as a single string.\n * @returns The baseN number.\n */\nexport function stringToBase(s: string, alphabet = DEFAULT_ALPHABET): bigint {\n const len = BigInt(alphabet.length);\n\n // In our conversion to baseN we do a couple performance optimizations to avoid using\n // excess CPU and such. To create baseN numbers, the input string needs to be reversed\n // so the exponents stack up appropriately, as the last character in the unreversed\n // string has less impact than the first character (in \"abc\" the A is a lot more important\n // for lexicographic sorts). We also do a trick with the character codes to optimize the\n // alphabet lookup, avoiding an index scan of `alphabet.indexOf(reversedStr[i])` - we know\n // that the alphabet and (theoretically) the input string are constrained on character sets\n // and thus can do simple subtraction to end up with the same result.\n\n // Developer caution: we carefully cast to BigInt here to avoid losing precision. We cannot\n // rely on Math.pow() (for example) to be capable of handling our insane numbers.\n\n let result = BigInt(0);\n for (let i = s.length - 1, j = BigInt(0); i >= 0; i--, j++) {\n const charIndex = s.charCodeAt(i) - alphabet.charCodeAt(0);\n\n // We add 1 to the char index to offset the whole numbering scheme. We unpack this in\n // the baseToString() function.\n result += BigInt(1 + charIndex) * len ** j;\n }\n return result;\n}\n\n/**\n * Averages two strings, returning the midpoint between them. This is accomplished by\n * converting both to baseN numbers (where N is the alphabet's length) then averaging\n * those before re-encoding as a string.\n * @param a - The first string.\n * @param b - The second string.\n * @param alphabet - The alphabet to use as a single string.\n * @returns The midpoint between the strings, as a string.\n */\nexport function averageBetweenStrings(a: string, b: string, alphabet = DEFAULT_ALPHABET): string {\n const padN = Math.max(a.length, b.length);\n const baseA = stringToBase(alphabetPad(a, padN, alphabet), alphabet);\n const baseB = stringToBase(alphabetPad(b, padN, alphabet), alphabet);\n const avg = (baseA + baseB) / BigInt(2);\n\n // Detect integer division conflicts. This happens when two numbers are divided too close so\n // we lose a .5 precision. We need to add a padding character in these cases.\n if (avg === baseA || avg == baseB) {\n return baseToString(avg, alphabet) + alphabet[0];\n }\n\n return baseToString(avg, alphabet);\n}\n\n/**\n * Finds the next string using the alphabet provided. This is done by converting the\n * string to a baseN number, where N is the alphabet's length, then adding 1 before\n * converting back to a string.\n * @param s - The string to start at.\n * @param alphabet - The alphabet to use as a single string.\n * @returns The string which follows the input string.\n */\nexport function nextString(s: string, alphabet = DEFAULT_ALPHABET): string {\n return baseToString(stringToBase(s, alphabet) + BigInt(1), alphabet);\n}\n\n/**\n * Finds the previous string using the alphabet provided. This is done by converting the\n * string to a baseN number, where N is the alphabet's length, then subtracting 1 before\n * converting back to a string.\n * @param s - The string to start at.\n * @param alphabet - The alphabet to use as a single string.\n * @returns The string which precedes the input string.\n */\nexport function prevString(s: string, alphabet = DEFAULT_ALPHABET): string {\n return baseToString(stringToBase(s, alphabet) - BigInt(1), alphabet);\n}\n\n/**\n * Compares strings lexicographically as a sort-safe function.\n * @param a - The first (reference) string.\n * @param b - The second (compare) string.\n * @returns Negative if the reference string is before the compare string;\n * positive if the reference string is after; and zero if equal.\n */\nexport function lexicographicCompare(a: string, b: string): number {\n // Dev note: this exists because I'm sad that you can use math operators on strings, so I've\n // hidden the operation in this function.\n if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n } else {\n return 0;\n }\n}\n\n/**\n * This function is similar to Object.assign() but it assigns recursively and\n * allows you to ignore nullish values from the source\n *\n * @returns the target object\n */\nexport function recursivelyAssign<T1 extends T2, T2 extends Record<string, any>>(\n target: T1,\n source: T2,\n ignoreNullish = false,\n): T1 & T2 {\n for (const [sourceKey, sourceValue] of Object.entries(source)) {\n if (target[sourceKey] instanceof Object && sourceValue) {\n recursivelyAssign(target[sourceKey], sourceValue);\n continue;\n }\n if ((sourceValue !== null && sourceValue !== undefined) || !ignoreNullish) {\n safeSet(target, sourceKey, sourceValue);\n continue;\n }\n }\n return target as T1 & T2;\n}\n\nfunction getContentTimestampWithFallback(event: MatrixEvent): number {\n return M_TIMESTAMP.findIn<number>(event.getContent()) ?? -1;\n}\n\n/**\n * Sort events by their content m.ts property\n * Latest timestamp first\n */\nexport function sortEventsByLatestContentTimestamp(left: MatrixEvent, right: MatrixEvent): number {\n return getContentTimestampWithFallback(right) - getContentTimestampWithFallback(left);\n}\n\nexport function isSupportedReceiptType(receiptType: string): boolean {\n return [ReceiptType.Read, ReceiptType.ReadPrivate].includes(receiptType as ReceiptType);\n}\n\n/**\n * Determines whether two maps are equal.\n * @param eq - The equivalence relation to compare values by. Defaults to strict equality.\n */\nexport function mapsEqual<K, V>(x: Map<K, V>, y: Map<K, V>, eq = (v1: V, v2: V): boolean => v1 === v2): boolean {\n if (x.size !== y.size) return false;\n for (const [k, v1] of x) {\n const v2 = y.get(k);\n if (v2 === undefined || !eq(v1, v2)) return false;\n }\n return true;\n}\n\nfunction processMapToObjectValue(value: any): any {\n if (value instanceof Map) {\n // Value is a Map. Recursively map it to an object.\n return recursiveMapToObject(value);\n } else if (Array.isArray(value)) {\n // Value is an Array. Recursively map the value (e.g. to cover Array of Arrays).\n return value.map((v) => processMapToObjectValue(v));\n } else {\n return value;\n }\n}\n\n/**\n * Recursively converts Maps to plain objects.\n * Also supports sub-lists of Maps.\n */\nexport function recursiveMapToObject(map: Map<any, any>): Record<any, any> {\n const targetMap = new Map();\n\n for (const [key, value] of map) {\n targetMap.set(key, processMapToObjectValue(value));\n }\n\n return Object.fromEntries(targetMap.entries());\n}\n\nexport function unsafeProp<K extends keyof any | undefined>(prop: K): boolean {\n return prop === \"__proto__\" || prop === \"prototype\" || prop === \"constructor\";\n}\n\nexport function safeSet<O extends Record<any, any>, K extends keyof O>(obj: O, prop: K, value: O[K]): void {\n if (unsafeProp(prop)) {\n throw new Error(\"Trying to modify prototype or constructor\");\n }\n\n obj[prop] = value;\n}\n\nexport function noUnsafeEventProps(event: Partial<IEvent>): boolean {\n return !(unsafeProp(event.room_id) || unsafeProp(event.sender) || unsafeProp(event.event_id));\n}\n\nexport class MapWithDefault<K, V> extends Map<K, V> {\n public constructor(private createDefault: () => V) {\n super();\n }\n\n /**\n * Returns the value if the key already exists.\n * If not, it creates a new value under that key using the ctor callback and returns it.\n */\n public getOrCreate(key: K): V {\n if (!this.has(key)) {\n this.set(key, this.createDefault());\n }\n\n return this.get(key)!;\n }\n}\n","/*\nCopyright 2022 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { ServerControlledNamespacedValue } from \"../NamespacedValue.ts\";\n\n/**\n * https://github.com/matrix-org/matrix-doc/pull/3773\n *\n * @experimental\n */\nexport const UNREAD_THREAD_NOTIFICATIONS = new ServerControlledNamespacedValue(\n \"unread_thread_notifications\",\n \"org.matrix.msc3773.unread_thread_notifications\",\n);\n","/*\nCopyright 2020 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { NamespacedValue, UnstableValue } from \"../NamespacedValue.ts\";\nimport {\n type PolicyRuleEventContent,\n type RoomAvatarEventContent,\n type RoomCanonicalAliasEventContent,\n type RoomCreateEventContent,\n type RoomEncryptionEventContent,\n type RoomGuestAccessEventContent,\n type RoomHistoryVisibilityEventContent,\n type RoomJoinRulesEventContent,\n type RoomMemberEventContent,\n type RoomNameEventContent,\n type RoomPinnedEventsEventContent,\n type RoomPowerLevelsEventContent,\n type RoomServerAclEventContent,\n type RoomThirdPartyInviteEventContent,\n type RoomTombstoneEventContent,\n type RoomTopicEventContent,\n type SpaceChildEventContent,\n type SpaceParentEventContent,\n} from \"./state_events.ts\";\nimport { type IGroupCallRoomMemberState, type IGroupCallRoomState } from \"../webrtc/groupCall.ts\";\nimport { type MSC3089EventContent } from \"../models/MSC3089Branch.ts\";\nimport { type M_BEACON, type M_BEACON_INFO, type MBeaconEventContent, type MBeaconInfoEventContent } from \"./beacon.ts\";\nimport { type EmptyObject } from \"./common.ts\";\nimport { type ReactionEventContent, type RoomMessageEventContent, type StickerEventContent } from \"./events.ts\";\nimport {\n type MCallAnswer,\n type MCallBase,\n type MCallCandidates,\n type MCallHangupReject,\n type MCallInviteNegotiate,\n type MCallReplacesEvent,\n type MCallSelectAnswer,\n type SDPStreamMetadata,\n type SDPStreamMetadataKey,\n} from \"../webrtc/callEventTypes.ts\";\nimport { type EncryptionKeysEventContent, type ICallNotifyContent } from \"../matrixrtc/types.ts\";\nimport { type M_POLL_END, type M_POLL_START, type PollEndEventContent, type PollStartEventContent } from \"./polls.ts\";\nimport { type SessionMembershipData } from \"../matrixrtc/CallMembership.ts\";\nimport { type LocalNotificationSettings } from \"./local_notifications.ts\";\nimport { type IPushRules } from \"./PushRules.ts\";\nimport { type SecretInfo, type SecretStorageKeyDescription } from \"../secret-storage.ts\";\nimport { type POLICIES_ACCOUNT_EVENT_TYPE } from \"../models/invites-ignorer-types.ts\";\n\nexport enum EventType {\n // Room state events\n RoomCanonicalAlias = \"m.room.canonical_alias\",\n RoomCreate = \"m.room.create\",\n RoomJoinRules = \"m.room.join_rules\",\n RoomMember = \"m.room.member\",\n RoomThirdPartyInvite = \"m.room.third_party_invite\",\n RoomPowerLevels = \"m.room.power_levels\",\n RoomName = \"m.room.name\",\n RoomTopic = \"m.room.topic\",\n RoomAvatar = \"m.room.avatar\",\n RoomPinnedEvents = \"m.room.pinned_events\",\n RoomEncryption = \"m.room.encryption\",\n RoomHistoryVisibility = \"m.room.history_visibility\",\n RoomGuestAccess = \"m.room.guest_access\",\n RoomServerAcl = \"m.room.server_acl\",\n RoomTombstone = \"m.room.tombstone\",\n RoomPredecessor = \"org.matrix.msc3946.room_predecessor\",\n\n // Moderation policy lists\n PolicyRuleUser = \"m.policy.rule.user\",\n PolicyRuleRoom = \"m.policy.rule.room\",\n PolicyRuleServer = \"m.policy.rule.server\",\n\n SpaceChild = \"m.space.child\",\n SpaceParent = \"m.space.parent\",\n\n // Room timeline events\n RoomRedaction = \"m.room.redaction\",\n RoomMessage = \"m.room.message\",\n RoomMessageEncrypted = \"m.room.encrypted\",\n Sticker = \"m.sticker\",\n CallInvite = \"m.call.invite\",\n CallCandidates = \"m.call.candidates\",\n CallAnswer = \"m.call.answer\",\n CallHangup = \"m.call.hangup\",\n CallReject = \"m.call.reject\",\n CallSelectAnswer = \"m.call.select_answer\",\n CallNegotiate = \"m.call.negotiate\",\n CallSDPStreamMetadataChanged = \"m.call.sdp_stream_metadata_changed\",\n CallSDPStreamMetadataChangedPrefix = \"org.matrix.call.sdp_stream_metadata_changed\",\n CallReplaces = \"m.call.replaces\",\n CallAssertedIdentity = \"m.call.asserted_identity\",\n CallAssertedIdentityPrefix = \"org.matrix.call.asserted_identity\",\n CallEncryptionKeysPrefix = \"io.element.call.encryption_keys\",\n KeyVerificationRequest = \"m.key.verification.request\",\n KeyVerificationStart = \"m.key.verification.start\",\n KeyVerificationCancel = \"m.key.verification.cancel\",\n KeyVerificationMac = \"m.key.verification.mac\",\n KeyVerificationDone = \"m.key.verification.done\",\n KeyVerificationKey = \"m.key.verification.key\",\n KeyVerificationAccept = \"m.key.verification.accept\",\n // Not used directly - see READY_TYPE in VerificationRequest.\n KeyVerificationReady = \"m.key.verification.ready\",\n // use of this is discouraged https://matrix.org/docs/spec/client_server/r0.6.1#m-room-message-feedback\n RoomMessageFeedback = \"m.room.message.feedback\",\n Reaction = \"m.reaction\",\n PollStart = \"org.matrix.msc3381.poll.start\",\n\n // Room ephemeral events\n Typing = \"m.typing\",\n Receipt = \"m.receipt\",\n Presence = \"m.presence\",\n\n // Room account_data events\n FullyRead = \"m.fully_read\",\n Tag = \"m.tag\",\n SpaceOrder = \"org.matrix.msc3230.space_order\", // MSC3230\n\n // User account_data events\n PushRules = \"m.push_rules\",\n Direct = \"m.direct\",\n IgnoredUserList = \"m.ignored_user_list\",\n\n // to_device events\n RoomKey = \"m.room_key\",\n RoomKeyRequest = \"m.room_key_request\",\n ForwardedRoomKey = \"m.forwarded_room_key\",\n Dummy = \"m.dummy\",\n SecretRequest = \"m.secret.request\",\n SecretSend = \"m.secret.send\",\n\n // Group call events\n GroupCallPrefix = \"org.matrix.msc3401.call\",\n GroupCallMemberPrefix = \"org.matrix.msc3401.call.member\",\n\n // MatrixRTC events\n CallNotify = \"org.matrix.msc4075.call.notify\",\n}\n\nexport enum RelationType {\n Annotation = \"m.annotation\",\n Replace = \"m.replace\",\n Reference = \"m.reference\",\n\n // Don't use this yet: it's only the stable version. The code still assumes we support the unstable prefix and,\n // moreover, our tests currently use the unstable prefix. Use THREAD_RELATION_TYPE.name.\n // Once we support *only* the stable prefix, THREAD_RELATION_TYPE can die and we can switch to this.\n Thread = \"m.thread\",\n}\n\nexport enum MsgType {\n Text = \"m.text\",\n Emote = \"m.emote\",\n Notice = \"m.notice\",\n Image = \"m.image\",\n File = \"m.file\",\n Audio = \"m.audio\",\n Location = \"m.location\",\n Video = \"m.video\",\n KeyVerificationRequest = \"m.key.verification.request\",\n}\n\nexport const RoomCreateTypeField = \"type\";\n\nexport enum RoomType {\n Space = \"m.space\",\n UnstableCall = \"org.matrix.msc3417.call\",\n ElementVideo = \"io.element.video\",\n}\n\nexport const ToDeviceMessageId = \"org.matrix.msgid\";\n\n/**\n * Identifier for an [MSC3088](https://github.com/matrix-org/matrix-doc/pull/3088)\n * room purpose. Note that this reference is UNSTABLE and subject to breaking changes,\n * including its eventual removal.\n */\nexport const UNSTABLE_MSC3088_PURPOSE = new UnstableValue(\"m.room.purpose\", \"org.matrix.msc3088.purpose\");\n\n/**\n * Enabled flag for an [MSC3088](https://github.com/matrix-org/matrix-doc/pull/3088)\n * room purpose. Note that this reference is UNSTABLE and subject to breaking changes,\n * including its eventual removal.\n */\nexport const UNSTABLE_MSC3088_ENABLED = new UnstableValue(\"m.enabled\", \"org.matrix.msc3088.enabled\");\n\n/**\n * Subtype for an [MSC3089](https://github.com/matrix-org/matrix-doc/pull/3089) space-room.\n * Note that this reference is UNSTABLE and subject to breaking changes, including its\n * eventual removal.\n */\nexport const UNSTABLE_MSC3089_TREE_SUBTYPE = new UnstableValue(\"m.data_tree\", \"org.matrix.msc3089.data_tree\");\n\n/**\n * Leaf type for an event in a [MSC3089](https://github.com/matrix-org/matrix-doc/pull/3089) space-room.\n * Note that this reference is UNSTABLE and subject to breaking changes, including its\n * eventual removal.\n */\nexport const UNSTABLE_MSC3089_LEAF = new UnstableValue(\"m.leaf\", \"org.matrix.msc3089.leaf\");\n\n/**\n * Branch (Leaf Reference) type for the index approach in a\n * [MSC3089](https://github.com/matrix-org/matrix-doc/pull/3089) space-room. Note that this reference is\n * UNSTABLE and subject to breaking changes, including its eventual removal.\n */\nexport const UNSTABLE_MSC3089_BRANCH = new UnstableValue(\"m.branch\", \"org.matrix.msc3089.branch\");\n\n/**\n * Marker event type to point back at imported historical content in a room. See\n * [MSC2716](https://github.com/matrix-org/matrix-spec-proposals/pull/2716).\n * Note that this reference is UNSTABLE and subject to breaking changes,\n * including its eventual removal.\n */\nexport const UNSTABLE_MSC2716_MARKER = new UnstableValue(\"m.room.marker\", \"org.matrix.msc2716.marker\");\n\n/**\n * Name of the request property for relation based redactions.\n * {@link https://github.com/matrix-org/matrix-spec-proposals/pull/3912}\n */\nexport const MSC3912_RELATION_BASED_REDACTIONS_PROP = new UnstableValue(\n \"with_rel_types\",\n \"org.matrix.msc3912.with_relations\",\n);\n\n/**\n * Functional members type for declaring a purpose of room members (e.g. helpful bots).\n * Note that this reference is UNSTABLE and subject to breaking changes, including its\n * eventual removal.\n *\n * Schema (TypeScript):\n * ```\n * {\n * service_members?: string[]\n * }\n * ```\n *\n * @example\n * ```\n * {\n * \"service_members\": [\n * \"@helperbot:localhost\",\n * \"@reminderbot:alice.tdl\"\n * ]\n * }\n * ```\n */\nexport const UNSTABLE_ELEMENT_FUNCTIONAL_USERS = new UnstableValue(\n \"io.element.functional_members\",\n \"io.element.functional_members\",\n);\n\n/**\n * A type of message that affects visibility of a message,\n * as per https://github.com/matrix-org/matrix-doc/pull/3531\n *\n * @experimental\n */\nexport const EVENT_VISIBILITY_CHANGE_TYPE = new UnstableValue(\"m.visibility\", \"org.matrix.msc3531.visibility\");\n\n/**\n * https://github.com/matrix-org/matrix-doc/pull/3881\n *\n * @experimental\n */\nexport const PUSHER_ENABLED = new UnstableValue(\"enabled\", \"org.matrix.msc3881.enabled\");\n\n/**\n * https://github.com/matrix-org/matrix-doc/pull/3881\n *\n * @experimental\n */\nexport const PUSHER_DEVICE_ID = new UnstableValue(\"device_id\", \"org.matrix.msc3881.device_id\");\n\n/**\n * https://github.com/matrix-org/matrix-doc/pull/3890\n *\n * @experimental\n */\nexport const LOCAL_NOTIFICATION_SETTINGS_PREFIX = new UnstableValue(\n \"m.local_notification_settings\",\n \"org.matrix.msc3890.local_notification_settings\",\n);\n\n/**\n * https://github.com/matrix-org/matrix-doc/pull/4023\n *\n * @experimental\n */\nexport const UNSIGNED_THREAD_ID_FIELD = new UnstableValue(\"thread_id\", \"org.matrix.msc4023.thread_id\");\n\n/**\n * https://github.com/matrix-org/matrix-spec-proposals/pull/4115\n *\n * @experimental\n */\nexport const UNSIGNED_MEMBERSHIP_FIELD = new NamespacedValue(\"membership\", \"io.element.msc4115.membership\");\n\n/**\n * Mapped type from event type to content type for all specified non-state room events.\n */\nexport interface TimelineEvents {\n [EventType.RoomMessage]: RoomMessageEventContent;\n [EventType.Sticker]: StickerEventContent;\n [EventType.Reaction]: ReactionEventContent;\n [EventType.CallReplaces]: MCallReplacesEvent;\n [EventType.CallAnswer]: MCallAnswer;\n [EventType.CallSelectAnswer]: MCallSelectAnswer;\n [EventType.CallNegotiate]: Omit<MCallInviteNegotiate, \"offer\">;\n [EventType.CallInvite]: MCallInviteNegotiate;\n [EventType.CallCandidates]: MCallCandidates;\n [EventType.CallHangup]: MCallHangupReject;\n [EventType.CallReject]: MCallHangupReject;\n [EventType.CallSDPStreamMetadataChangedPrefix]: MCallBase & { [SDPStreamMetadataKey]: SDPStreamMetadata };\n [EventType.CallEncryptionKeysPrefix]: EncryptionKeysEventContent;\n [EventType.CallNotify]: ICallNotifyContent;\n [M_BEACON.name]: MBeaconEventContent;\n [M_POLL_START.name]: PollStartEventContent;\n [M_POLL_END.name]: PollEndEventContent;\n}\n\n/**\n * Mapped type from event type to content type for all specified room state events.\n */\nexport interface StateEvents {\n [EventType.RoomCanonicalAlias]: RoomCanonicalAliasEventContent;\n [EventType.RoomCreate]: RoomCreateEventContent;\n [EventType.RoomJoinRules]: RoomJoinRulesEventContent;\n [EventType.RoomMember]: RoomMemberEventContent;\n // XXX: Spec says this event has 3 required fields but kicking such an invitation requires sending `{}`\n [EventType.RoomThirdPartyInvite]: RoomThirdPartyInviteEventContent | EmptyObject;\n [EventType.RoomPowerLevels]: RoomPowerLevelsEventContent;\n [EventType.RoomName]: RoomNameEventContent;\n [EventType.RoomTopic]: RoomTopicEventContent;\n [EventType.RoomAvatar]: RoomAvatarEventContent;\n [EventType.RoomPinnedEvents]: RoomPinnedEventsEventContent;\n [EventType.RoomEncryption]: RoomEncryptionEventContent;\n [EventType.RoomHistoryVisibility]: RoomHistoryVisibilityEventContent;\n [EventType.RoomGuestAccess]: RoomGuestAccessEventContent;\n [EventType.RoomServerAcl]: RoomServerAclEventContent;\n [EventType.RoomTombstone]: RoomTombstoneEventContent;\n [EventType.SpaceChild]: SpaceChildEventContent;\n [EventType.SpaceParent]: SpaceParentEventContent;\n\n [EventType.PolicyRuleUser]: PolicyRuleEventContent | EmptyObject;\n [EventType.PolicyRuleRoom]: PolicyRuleEventContent | EmptyObject;\n [EventType.PolicyRuleServer]: PolicyRuleEventContent | EmptyObject;\n\n // MSC3401\n [EventType.GroupCallPrefix]: IGroupCallRoomState;\n [EventType.GroupCallMemberPrefix]: IGroupCallRoomMemberState | SessionMembershipData | EmptyObject;\n\n // MSC3089\n [UNSTABLE_MSC3089_BRANCH.name]: MSC3089EventContent;\n\n // MSC3672\n [M_BEACON_INFO.name]: MBeaconInfoEventContent;\n}\n\n/**\n * Mapped type from event type to content type for all specified global account_data events.\n */\nexport interface AccountDataEvents extends SecretStorageAccountDataEvents {\n [EventType.PushRules]: IPushRules;\n [EventType.Direct]: { [userId: string]: string[] };\n [EventType.IgnoredUserList]: { ignored_users: { [userId: string]: EmptyObject } };\n \"m.secret_storage.default_key\": { key: string };\n // Flag set by the rust SDK (Element X) and also used by us to mark that the user opted out of backup\n // (I don't know why it's m.org.matrix...)\n \"m.org.matrix.custom.backup_disabled\": { disabled: boolean };\n \"m.identity_server\": { base_url: string | null };\n [key: `${typeof LOCAL_NOTIFICATION_SETTINGS_PREFIX.name}.${string}`]: LocalNotificationSettings;\n [key: `m.secret_storage.key.${string}`]: SecretStorageKeyDescription;\n\n // Invites-ignorer events\n [POLICIES_ACCOUNT_EVENT_TYPE.name]: { [key: string]: any };\n [POLICIES_ACCOUNT_EVENT_TYPE.altName]: { [key: string]: any };\n}\n\n/**\n * Mapped type from event type to content type for all specified global events encrypted by secret storage.\n *\n * See https://spec.matrix.org/v1.13/client-server-api/#msecret_storagev1aes-hmac-sha2-1\n */\nexport interface SecretStorageAccountDataEvents {\n \"m.megolm_backup.v1\": SecretInfo;\n \"m.cross_signing.master\": SecretInfo;\n \"m.cross_signing.self_signing\": SecretInfo;\n \"m.cross_signing.user_signing\": SecretInfo;\n \"org.matrix.msc3814\": SecretInfo;\n}\n","/*\nCopyright 2023 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { type IMinimalEvent } from \"./sync-accumulator.ts\";\nimport { EventType } from \"./@types/event.ts\";\nimport { isSupportedReceiptType, MapWithDefault, recursiveMapToObject } from \"./utils.ts\";\nimport { type IContent } from \"./models/event.ts\";\nimport { type ReceiptContent, type ReceiptType } from \"./@types/read_receipts.ts\";\n\ninterface AccumulatedReceipt {\n data: IMinimalEvent;\n type: ReceiptType;\n eventId: string;\n}\n\n/**\n * Summarises the read receipts within a room. Used by the sync accumulator.\n *\n * Given receipts for users, picks the most recently-received one and provides\n * the results in a new fake receipt event returned from\n * buildAccumulatedReceiptEvent().\n *\n * Handles unthreaded receipts and receipts in each thread separately, so the\n * returned event contains the most recently received unthreaded receipt, and\n * the most recently received receipt in each thread.\n */\nexport class ReceiptAccumulator {\n /** user_id -\\> most-recently-received unthreaded receipt */\n private unthreadedReadReceipts: Map<string, AccumulatedReceipt> = new Map();\n\n /** thread_id -\\> user_id -\\> most-recently-received receipt for this thread */\n private threadedReadReceipts: MapWithDefault<string, Map<string, AccumulatedReceipt>> = new MapWithDefault(\n () => new Map(),\n );\n\n /**\n * Provide an unthreaded receipt for this user. Overwrites any other\n * unthreaded receipt we have for this user.\n */\n private setUnthreaded(userId: string, receipt: AccumulatedReceipt): void {\n this.unthreadedReadReceipts.set(userId, receipt);\n }\n\n /**\n * Provide a receipt for this user in this thread. Overwrites any other\n * receipt we have for this user in this thread.\n */\n private setThreaded(threadId: string, userId: string, receipt: AccumulatedReceipt): void {\n this.threadedReadReceipts.getOrCreate(threadId).set(userId, receipt);\n }\n\n /**\n * @returns an iterator of pairs of [userId, AccumulatedReceipt] - all the\n * most recently-received unthreaded receipts for each user.\n */\n private allUnthreaded(): IterableIterator<[string, AccumulatedReceipt]> {\n return this.unthreadedReadReceipts.entries();\n }\n\n /**\n * @returns an iterator of pairs of [userId, AccumulatedReceipt] - all the\n * most recently-received threaded receipts for each user, in all\n * threads.\n */\n private *allThreaded(): IterableIterator<[string, AccumulatedReceipt]> {\n for (const receiptsForThread of this.threadedReadReceipts.values()) {\n for (const e of receiptsForThread.entries()) {\n yield e;\n }\n }\n }\n\n /**\n * Given a list of ephemeral events, find the receipts and store the\n * relevant ones to be returned later from buildAccumulatedReceiptEvent().\n */\n public consumeEphemeralEvents(events: IMinimalEvent[] | undefined): void {\n events?.forEach((e) => {\n if (e.type !== EventType.Receipt || !e.content) {\n // This means we'll drop unknown ephemeral events but that\n // seems okay.\n return;\n }\n\n // Handle m.receipt events. They clobber based on:\n // (user_id, receipt_type)\n // but they are keyed in the event as:\n // content:{ $event_id: { $receipt_type: { $user_id: {json} }}}\n // so store them in the former so we can accumulate receipt deltas\n // quickly and efficiently (we expect a lot of them). Fold the\n // receipt type into the key name since we only have 1 at the\n // moment (m.read) and nested JSON objects are slower and more\n // of a hassle to work with. We'll inflate this back out when\n // getJSON() is called.\n Object.keys(e.content).forEach((eventId) => {\n Object.entries<ReceiptContent>(e.content[eventId]).forEach(([key, value]) => {\n if (!isSupportedReceiptType(key)) return;\n\n for (const userId of Object.keys(value)) {\n const data = e.content[eventId][key][userId];\n\n const receipt = {\n data: e.content[eventId][key][userId],\n type: key as ReceiptType,\n eventId,\n };\n\n // In a world that supports threads, read receipts normally have\n // a `thread_id` which is either the thread they belong in or\n // `MAIN_ROOM_TIMELINE`, so we normally use `setThreaded(...)`\n // here. The `MAIN_ROOM_TIMELINE` is just treated as another\n // thread.\n //\n // We still encounter read receipts that are \"unthreaded\"\n // (missing the `thread_id` property). These come from clients\n // that don't support threads, and from threaded clients that\n // are doing a \"Mark room as read\" operation. Unthreaded\n // receipts mark everything \"before\" them as read, in all\n // threads, where \"before\" means in Sync Order i.e. the order\n // the events were received from the homeserver in a sync.\n // [Note: we have some bugs where we use timestamp order instead\n // of Sync Order, because we don't correctly remember the Sync\n // Order. See #3325.]\n //\n // Calling the wrong method will cause incorrect behavior like\n // messages re-appearing as \"new\" when you already read them\n // previously.\n if (!data.thread_id) {\n this.setUnthreaded(userId, receipt);\n } else {\n this.setThreaded(data.thread_id, userId, receipt);\n }\n }\n });\n });\n });\n }\n\n /**\n * Build a receipt event that contains all relevant information for this\n * room, taking the most recently received receipt for each user in an\n * unthreaded context, and in each thread.\n */\n public buildAccumulatedReceiptEvent(roomId: string): IMinimalEvent | null {\n const receiptEvent: IMinimalEvent = {\n type: EventType.Receipt,\n room_id: roomId,\n content: {\n // $event_id: { \"m.read\": { $user_id: $json } }\n } as IContent,\n };\n\n const receiptEventContent: MapWithDefault<\n string,\n MapWithDefault<ReceiptType, Map<string, object>>\n > = new MapWithDefault(() => new MapWithDefault(() => new Map()));\n\n for (const [userId, receiptData] of this.allUnthreaded()) {\n receiptEventContent\n .getOrCreate(receiptData.eventId)\n .getOrCreate(receiptData.type)\n .set(userId, receiptData.data);\n }\n\n for (const [userId, receiptData] of this.allThreaded()) {\n receiptEventContent\n .getOrCreate(receiptData.eventId)\n .getOrCreate(receiptData.type)\n .set(userId, receiptData.data);\n }\n\n receiptEvent.content = recursiveMapToObject(receiptEventContent);\n\n return receiptEventContent.size > 0 ? receiptEvent : null;\n }\n}\n","/*\nCopyright 2017 - 2023 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n/**\n * This is an internal module. See {@link SyncAccumulator} for the public class.\n */\n\nimport { logger } from \"./logger.ts\";\nimport { deepCopy } from \"./utils.ts\";\nimport { type IContent, type IUnsigned } from \"./models/event.ts\";\nimport { type IRoomSummary } from \"./models/room-summary.ts\";\nimport { type EventType } from \"./@types/event.ts\";\nimport { UNREAD_THREAD_NOTIFICATIONS } from \"./@types/sync.ts\";\nimport { ReceiptAccumulator } from \"./receipt-accumulator.ts\";\n\ninterface IOpts {\n /**\n * The ideal maximum number of timeline entries to keep in the sync response.\n * This is best-effort, as clients do not always have a back-pagination token for each event,\n * so it's possible there may be slightly *less* than this value. There will never be more.\n * This cannot be 0 or else it makes it impossible to scroll back in a room.\n * Default: 50.\n */\n maxTimelineEntries?: number;\n}\n\nexport interface IMinimalEvent {\n content: IContent;\n type: EventType | string;\n room_id?: string;\n unsigned?: IUnsigned;\n}\n\nexport interface IEphemeral {\n events: IMinimalEvent[];\n}\n\n/* eslint-disable camelcase */\ninterface UnreadNotificationCounts {\n highlight_count?: number;\n notification_count?: number;\n}\n\nexport interface IRoomEvent extends IMinimalEvent {\n event_id: string;\n sender: string;\n origin_server_ts: number;\n}\n\nexport interface IStateEvent extends IRoomEvent {\n prev_content?: IContent;\n state_key: string;\n}\n\ninterface IState {\n events: IStateEvent[];\n}\n\nexport interface ITimeline {\n events: Array<IRoomEvent | IStateEvent>;\n limited?: boolean;\n prev_batch: string | null;\n}\n\nexport interface IJoinedRoom {\n \"summary\": IRoomSummary;\n // One of `state` or `state_after` is required.\n \"state\"?: IState;\n \"org.matrix.msc4222.state_after\"?: IState; // https://github.com/matrix-org/matrix-spec-proposals/pull/4222\n \"timeline\": ITimeline;\n \"ephemeral\": IEphemeral;\n \"account_data\": IAccountData;\n \"unread_notifications\": UnreadNotificationCounts;\n \"unread_thread_notifications\"?: Record<string, UnreadNotificationCounts>;\n \"org.matrix.msc3773.unread_thread_notifications\"?: Record<string, UnreadNotificationCounts>;\n}\n\nexport interface IStrippedState {\n content: IContent;\n state_key: string;\n type: EventType | string;\n sender: string;\n}\n\nexport interface IInviteState {\n events: IStrippedState[];\n}\n\nexport interface IKnockState {\n events: IStrippedState[];\n}\n\nexport interface IInvitedRoom {\n invite_state: IInviteState;\n}\n\nexport interface ILeftRoom {\n // One of `state` or `state_after` is required.\n \"state\"?: IState;\n \"org.matrix.msc4222.state_after\"?: IState;\n \"timeline\": ITimeline;\n \"account_data\": IAccountData;\n}\n\nexport interface IKnockedRoom {\n knock_state: IKnockState;\n}\n\nexport interface IRooms {\n [Category.Join]: Record<string, IJoinedRoom>;\n [Category.Invite]: Record<string, IInvitedRoom>;\n [Category.Leave]: Record<string, ILeftRoom>;\n [Category.Knock]: Record<string, IKnockedRoom>;\n}\n\ninterface IPresence {\n events: IMinimalEvent[];\n}\n\ninterface IAccountData {\n events: IMinimalEvent[];\n}\n\nexport interface IToDeviceEvent {\n content: IContent;\n sender: string;\n type: string;\n}\n\ninterface IToDevice {\n events: IToDeviceEvent[];\n}\n\nexport interface IDeviceLists {\n changed?: string[];\n left?: string[];\n}\n\nexport interface ISyncResponse {\n \"next_batch\": string;\n \"rooms\": IRooms;\n \"presence\"?: IPresence;\n \"account_data\": IAccountData;\n \"to_device\"?: IToDevice;\n \"device_lists\"?: IDeviceLists;\n \"device_one_time_keys_count\"?: Record<string, number>;\n\n \"device_unused_fallback_key_types\"?: string[];\n \"org.matrix.msc2732.device_unused_fallback_key_types\"?: string[];\n}\n/* eslint-enable camelcase */\n\nexport enum Category {\n Invite = \"invite\",\n Leave = \"leave\",\n Join = \"join\",\n Knock = \"knock\",\n}\n\ninterface IRoom {\n _currentState: { [eventType: string]: { [stateKey: string]: IStateEvent } };\n _timeline: {\n event: IRoomEvent | IStateEvent;\n token: string | null;\n }[];\n _summary: Partial<IRoomSummary>;\n _accountData: { [eventType: string]: IMinimalEvent };\n _unreadNotifications: Partial<UnreadNotificationCounts>;\n _unreadThreadNotifications?: Record<string, Partial<UnreadNotificationCounts>>;\n _receipts: ReceiptAccumulator;\n}\n\nexport interface ISyncData {\n nextBatch: string;\n accountData: IMinimalEvent[];\n roomsData: IRooms;\n}\n\ntype TaggedEvent = IRoomEvent & { _localTs?: number };\n\nfunction isTaggedEvent(event: IRoomEvent): event is TaggedEvent {\n return \"_localTs\" in event && event[\"_localTs\"] !== undefined;\n}\n\n/**\n * The purpose of this class is to accumulate /sync responses such that a\n * complete \"initial\" JSON response can be returned which accurately represents\n * the sum total of the /sync responses accumulated to date. It only handles\n * room data: that is, everything under the \"rooms\" top-level key.\n *\n * This class is used when persisting room data so a complete /sync response can\n * be loaded from disk and incremental syncs can be performed on the server,\n * rather than asking the server to do an initial sync on startup.\n */\nexport class SyncAccumulator {\n private accountData: Record<string, IMinimalEvent> = {}; // $event_type: Object\n private inviteRooms: Record<string, IInvitedRoom> = {}; // $roomId: { ... sync 'invite' json data ... }\n private knockRooms: Record<string, IKnockedRoom> = {}; // $roomId: { ... sync 'knock' json data ... }\n private joinRooms: { [roomId: string]: IRoom } = {};\n // the /sync token which corresponds to the last time rooms were\n // accumulated. We remember this so that any caller can obtain a\n // coherent /sync response and know at what point they should be\n // streaming from without losing events.\n private nextBatch: string | null = null;\n\n public constructor(private readonly opts: IOpts = {}) {\n this.opts.maxTimelineEntries = this.opts.maxTimelineEntries || 50;\n }\n\n public accumulate(syncResponse: ISyncResponse, fromDatabase = false): void {\n this.accumulateRooms(syncResponse, fromDatabase);\n this.accumulateAccountData(syncResponse);\n this.nextBatch = syncResponse.next_batch;\n }\n\n private accumulateAccountData(syncResponse: ISyncResponse): void {\n if (!syncResponse.account_data || !syncResponse.account_data.events) {\n return;\n }\n // Clobbers based on event type.\n syncResponse.account_data.events.forEach((e) => {\n this.accountData[e.type] = e;\n });\n }\n\n /**\n * Accumulate incremental /sync room data.\n * @param syncResponse - the complete /sync JSON\n * @param fromDatabase - True if the sync response is one saved to the database\n */\n private accumulateRooms(syncResponse: ISyncResponse, fromDatabase = false): void {\n if (!syncResponse.rooms) {\n return;\n }\n if (syncResponse.rooms.invite) {\n Object.keys(syncResponse.rooms.invite).forEach((roomId) => {\n this.accumulateRoom(roomId, Category.Invite, syncResponse.rooms.invite[roomId], fromDatabase);\n });\n }\n if (syncResponse.rooms.join) {\n Object.keys(syncResponse.rooms.join).forEach((roomId) => {\n this.accumulateRoom(roomId, Category.Join, syncResponse.rooms.join[roomId], fromDatabase);\n });\n }\n if (syncResponse.rooms.leave) {\n Object.keys(syncResponse.rooms.leave).forEach((roomId) => {\n this.accumulateRoom(roomId, Category.Leave, syncResponse.rooms.leave[roomId], fromDatabase);\n });\n }\n if (syncResponse.rooms.knock) {\n Object.keys(syncResponse.rooms.knock).forEach((roomId) => {\n this.accumulateRoom(roomId, Category.Knock, syncResponse.rooms.knock[roomId], fromDatabase);\n });\n }\n }\n\n private accumulateRoom(roomId: string, category: Category.Invite, data: IInvitedRoom, fromDatabase: boolean): void;\n private accumulateRoom(roomId: string, category: Category.Join, data: IJoinedRoom, fromDatabase: boolean): void;\n private accumulateRoom(roomId: string, category: Category.Leave, data: ILeftRoom, fromDatabase: boolean): void;\n private accumulateRoom(roomId: string, category: Category.Knock, data: IKnockedRoom, fromDatabase: boolean): void;\n private accumulateRoom(roomId: string, category: Category, data: any, fromDatabase = false): void {\n // Valid /sync state transitions\n // +--------+ <======+ 1: Accept an invite\n // +== | INVITE | | (5) 2: Leave a room\n // | +--------+ =====+ | 3: Join a public room previously\n // |(1) (4) | | left (handle as if new room)\n // V (2) V | 4: Reject an invite\n // +------+ ========> +--------+ 5: Invite to a room previously\n // | JOIN | (3) | LEAVE* | left (handle as if new room)\n // +------+ <======== +--------+\n //\n // * equivalent to \"no state\"\n switch (category) {\n case Category.Invite: // (5)\n if (this.knockRooms[roomId]) {\n // was previously knock, now invite, need to delete knock state\n delete this.knockRooms[roomId];\n }\n this.accumulateInviteState(roomId, data as IInvitedRoom);\n break;\n\n case Category.Knock:\n this.accumulateKnockState(roomId, data as IKnockedRoom);\n break;\n\n case Category.Join:\n if (this.inviteRooms[roomId]) {\n // (1)\n // was previously invite, now join. We expect /sync to give\n // the entire state and timeline on 'join', so delete previous\n // invite state\n delete this.inviteRooms[roomId];\n }\n // (3)\n this.accumulateJoinState(roomId, data as IJoinedRoom, fromDatabase);\n break;\n\n case Category.Leave:\n if (this.knockRooms[roomId]) {\n // delete knock state on leave\n delete this.knockRooms[roomId];\n } else if (this.inviteRooms[roomId]) {\n // (4)\n delete this.inviteRooms[roomId];\n } else {\n // (2)\n delete this.joinRooms[roomId];\n }\n break;\n\n default:\n logger.error(\"Unknown cateogory: \", category);\n }\n }\n\n private accumulateInviteState(roomId: string, data: IInvitedRoom): void {\n if (!data.invite_state || !data.invite_state.events) {\n // no new data\n return;\n }\n if (!this.inviteRooms[roomId]) {\n this.inviteRooms[roomId] = {\n invite_state: data.invite_state,\n };\n return;\n }\n // accumulate extra keys for invite->invite transitions\n // clobber based on event type / state key\n // We expect invite_state to be small, so just loop over the events\n const currentData = this.inviteRooms[roomId];\n data.invite_state.events.forEach((e) => {\n let hasAdded = false;\n for (let i = 0; i < currentData.invite_state.events.length; i++) {\n const current = currentData.invite_state.events[i];\n if (current.type === e.type && current.state_key == e.state_key) {\n currentData.invite_state.events[i] = e; // update\n hasAdded = true;\n }\n }\n if (!hasAdded) {\n currentData.invite_state.events.push(e);\n }\n });\n }\n\n private accumulateKnockState(roomId: string, data: IKnockedRoom): void {\n if (!data.knock_state || !data.knock_state.events) {\n // no new data\n return;\n }\n if (!this.knockRooms[roomId]) {\n this.knockRooms[roomId] = {\n knock_state: data.knock_state,\n };\n return;\n }\n // accumulate extra keys\n // clobber based on event type / state key\n // We expect knock_state to be small, so just loop over the events\n const currentData = this.knockRooms[roomId];\n data.knock_state.events.forEach((e) => {\n let hasAdded = false;\n for (let i = 0; i < currentData.knock_state.events.length; i++) {\n const current = currentData.knock_state.events[i];\n if (current.type === e.type && current.state_key == e.state_key) {\n currentData.knock_state.events[i] = e; // update\n hasAdded = true;\n }\n }\n if (!hasAdded) {\n currentData.knock_state.events.push(e);\n }\n });\n }\n\n // Accumulate timeline and state events in a room.\n private accumulateJoinState(roomId: string, data: IJoinedRoom, fromDatabase = false): void {\n // We expect this function to be called a lot (every /sync) so we want\n // this to be fast. /sync stores events in an array but we often want\n // to clobber based on type/state_key. Rather than convert arrays to\n // maps all the time, just keep private maps which contain\n // the actual current accumulated sync state, and array-ify it when\n // getJSON() is called.\n\n // State resolution:\n // The 'state' key is the delta from the previous sync (or start of time\n // if no token was supplied), to the START of the timeline. To obtain\n // the current state, we need to \"roll forward\" state by reading the\n // timeline. We want to store the current state so we can drop events\n // out the end of the timeline based on opts.maxTimelineEntries.\n //\n // 'state' 'timeline' current state\n // |-------x<======================>x\n // T I M E\n //\n // When getJSON() is called, we 'roll back' the current state by the\n // number of entries in the timeline to work out what 'state' should be.\n\n // Back-pagination:\n // On an initial /sync, the server provides a back-pagination token for\n // the start of the timeline. When /sync deltas come down, they also\n // include back-pagination tokens for the start of the timeline. This\n // means not all events in the timeline have back-pagination tokens, as\n // it is only the ones at the START of the timeline which have them.\n // In order for us to have a valid timeline (and back-pagination token\n // to match), we need to make sure that when we remove old timeline\n // events, that we roll forward to an event which has a back-pagination\n // token. This means we can't keep a strict sliding-window based on\n // opts.maxTimelineEntries, and we may have a few less. We should never\n // have more though, provided that the /sync limit is less than or equal\n // to opts.maxTimelineEntries.\n\n if (!this.joinRooms[roomId]) {\n // Create truly empty objects so event types of 'hasOwnProperty' and co\n // don't cause this code to break.\n this.joinRooms[roomId] = {\n _currentState: Object.create(null),\n _timeline: [],\n _accountData: Object.create(null),\n _unreadNotifications: {},\n _unreadThreadNotifications: {},\n _summary: {},\n _receipts: new ReceiptAccumulator(),\n };\n }\n const currentData = this.joinRooms[roomId];\n\n if (data.account_data && data.account_data.events) {\n // clobber based on type\n data.account_data.events.forEach((e) => {\n currentData._accountData[e.type] = e;\n });\n }\n\n // these probably clobber, spec is unclear.\n if (data.unread_notifications) {\n currentData._unreadNotifications = data.unread_notifications;\n }\n currentData._unreadThreadNotifications =\n data[UNREAD_THREAD_NOTIFICATIONS.stable!] ?? data[UNREAD_THREAD_NOTIFICATIONS.unstable!] ?? undefined;\n\n if (data.summary) {\n const HEROES_KEY = \"m.heroes\";\n const INVITED_COUNT_KEY = \"m.invited_member_count\";\n const JOINED_COUNT_KEY = \"m.joined_member_count\";\n\n const acc = currentData._summary;\n const sum = data.summary;\n acc[HEROES_KEY] = sum[HEROES_KEY] ?? acc[HEROES_KEY];\n acc[JOINED_COUNT_KEY] = sum[JOINED_COUNT_KEY] ?? acc[JOINED_COUNT_KEY];\n acc[INVITED_COUNT_KEY] = sum[INVITED_COUNT_KEY] ?? acc[INVITED_COUNT_KEY];\n }\n\n // We purposefully do not persist m.typing events.\n // Technically you could refresh a browser before the timer on a\n // typing event is up, so it'll look like you aren't typing when\n // you really still are. However, the alternative is worse. If\n // we do persist typing events, it will look like people are\n // typing forever until someone really does start typing (which\n // will prompt Synapse to send down an actual m.typing event to\n // clobber the one we persisted).\n\n // Persist the receipts\n currentData._receipts.consumeEphemeralEvents(data.ephemeral?.events);\n\n // if we got a limited sync, we need to remove all timeline entries or else\n // we will have gaps in the timeline.\n if (data.timeline && data.timeline.limited) {\n currentData._timeline = [];\n }\n\n // Work out the current state. The deltas need to be applied in the order:\n // - existing state which didn't come down /sync.\n // - State events under the 'state' key.\n // - State events under the 'state_after' key OR state events in the 'timeline' if 'state_after' is not present.\n data.state?.events?.forEach((e) => {\n setState(currentData._currentState, e);\n });\n data[\"org.matrix.msc4222.state_after\"]?.events?.forEach((e) => {\n setState(currentData._currentState, e);\n });\n data.timeline?.events?.forEach((e, index) => {\n if (!data[\"org.matrix.msc4222.state_after\"]) {\n // this nops if 'e' isn't a state event\n setState(currentData._currentState, e);\n }\n // append the event to the timeline. The back-pagination token\n // corresponds to the first event in the timeline\n let transformedEvent: TaggedEvent;\n if (!fromDatabase) {\n transformedEvent = Object.assign({}, e);\n if (transformedEvent.unsigned !== undefined) {\n transformedEvent.unsigned = Object.assign({}, transformedEvent.unsigned);\n }\n const age = e.unsigned?.age;\n if (age !== undefined) transformedEvent._localTs = Date.now() - age;\n } else {\n transformedEvent = e;\n }\n\n currentData._timeline.push({\n event: transformedEvent,\n token: index === 0 ? (data.timeline.prev_batch ?? null) : null,\n });\n });\n\n // attempt to prune the timeline by jumping between events which have\n // pagination tokens.\n if (currentData._timeline.length > this.opts.maxTimelineEntries!) {\n const startIndex = currentData._timeline.length - this.opts.maxTimelineEntries!;\n for (let i = startIndex; i < currentData._timeline.length; i++) {\n if (currentData._timeline[i].token) {\n // keep all events after this, including this one\n currentData._timeline = currentData._timeline.slice(i, currentData._timeline.length);\n break;\n }\n }\n }\n }\n\n /**\n * Return everything under the 'rooms' key from a /sync response which\n * represents all room data that should be stored. This should be paired\n * with the sync token which represents the most recent /sync response\n * provided to accumulate().\n * @param forDatabase - True to generate a sync to be saved to storage\n * @returns An object with a \"nextBatch\", \"roomsData\" and \"accountData\"\n * keys.\n * The \"nextBatch\" key is a string which represents at what point in the\n * /sync stream the accumulator reached. This token should be used when\n * restarting a /sync stream at startup. Failure to do so can lead to missing\n * events. The \"roomsData\" key is an Object which represents the entire\n * /sync response from the 'rooms' key onwards. The \"accountData\" key is\n * a list of raw events which represent global account data.\n */\n public getJSON(forDatabase = false): ISyncData {\n const data: IRooms = {\n join: {},\n invite: {},\n knock: {},\n // always empty. This is set by /sync when a room was previously\n // in 'invite' or 'join'. On fresh startup, the client won't know\n // about any previous room being in 'invite' or 'join' so we can\n // just omit mentioning it at all, even if it has previously come\n // down /sync.\n // The notable exception is when a client is kicked or banned:\n // we may want to hold onto that room so the client can clearly see\n // why their room has disappeared. We don't persist it though because\n // it is unclear *when* we can safely remove the room from the DB.\n // Instead, we assume that if you're loading from the DB, you've\n // refreshed the page, which means you've seen the kick/ban already.\n leave: {},\n };\n Object.keys(this.inviteRooms).forEach((roomId) => {\n data.invite[roomId] = this.inviteRooms[roomId];\n });\n Object.keys(this.knockRooms).forEach((roomId) => {\n data.knock[roomId] = this.knockRooms[roomId];\n });\n Object.keys(this.joinRooms).forEach((roomId) => {\n const roomData = this.joinRooms[roomId];\n const roomJson: IJoinedRoom & {\n // We track both `state` and `state_after` for downgrade compatibility\n \"state\": IState;\n \"org.matrix.msc4222.state_after\": IState;\n } = {\n \"ephemeral\": { events: [] },\n \"account_data\": { events: [] },\n \"state\": { events: [] },\n \"org.matrix.msc4222.state_after\": { events: [] },\n \"timeline\": {\n events: [],\n prev_batch: null,\n },\n \"unread_notifications\": roomData._unreadNotifications,\n \"unread_thread_notifications\": roomData._unreadThreadNotifications,\n \"summary\": roomData._summary as IRoomSummary,\n };\n // Add account data\n Object.keys(roomData._accountData).forEach((evType) => {\n roomJson.account_data.events.push(roomData._accountData[evType]);\n });\n\n const receiptEvent = roomData._receipts.buildAccumulatedReceiptEvent(roomId);\n\n // add only if we have some receipt data\n if (receiptEvent) {\n roomJson.ephemeral.events.push(receiptEvent);\n }\n\n // Add timeline data\n roomData._timeline.forEach((msgData) => {\n if (!roomJson.timeline.prev_batch) {\n // the first event we add to the timeline MUST match up to\n // the prev_batch token.\n if (!msgData.token) {\n return; // this shouldn't happen as we prune constantly.\n }\n roomJson.timeline.prev_batch = msgData.token;\n }\n\n let transformedEvent: (IRoomEvent | IStateEvent) & { _localTs?: number };\n if (!forDatabase && isTaggedEvent(msgData.event)) {\n // This means we have to copy each event, so we can fix it up to\n // set a correct 'age' parameter whilst keeping the local timestamp\n // on our stored event. If this turns out to be a bottleneck, it could\n // be optimised either by doing this in the main process after the data\n // has been structured-cloned to go between the worker & main process,\n // or special-casing data from saved syncs to read the local timestamp\n // directly rather than turning it into age to then immediately be\n // transformed back again into a local timestamp.\n transformedEvent = Object.assign({}, msgData.event);\n if (transformedEvent.unsigned !== undefined) {\n transformedEvent.unsigned = Object.assign({}, transformedEvent.unsigned);\n }\n delete transformedEvent._localTs;\n transformedEvent.unsigned = transformedEvent.unsigned || {};\n transformedEvent.unsigned.age = Date.now() - msgData.event._localTs!;\n } else {\n transformedEvent = msgData.event;\n }\n roomJson.timeline.events.push(transformedEvent);\n });\n\n // Add state data: roll back current state to the start of timeline,\n // by \"reverse clobbering\" from the end of the timeline to the start.\n // Convert maps back into arrays.\n const rollBackState = Object.create(null);\n for (let i = roomJson.timeline.events.length - 1; i >= 0; i--) {\n const timelineEvent = roomJson.timeline.events[i];\n if (\n (timelineEvent as IStateEvent).state_key === null ||\n (timelineEvent as IStateEvent).state_key === undefined\n ) {\n continue; // not a state event\n }\n // since we're going back in time, we need to use the previous\n // state value else we'll break causality. We don't have the\n // complete previous state event, so we need to create one.\n const prevStateEvent = deepCopy(timelineEvent);\n if (prevStateEvent.unsigned) {\n if (prevStateEvent.unsigned.prev_content) {\n prevStateEvent.content = prevStateEvent.unsigned.prev_content;\n }\n if (prevStateEvent.unsigned.prev_sender) {\n prevStateEvent.sender = prevStateEvent.unsigned.prev_sender;\n }\n }\n setState(rollBackState, prevStateEvent);\n }\n Object.keys(roomData._currentState).forEach((evType) => {\n Object.keys(roomData._currentState[evType]).forEach((stateKey) => {\n let ev = roomData._currentState[evType][stateKey];\n // Push to both fields to provide downgrade compatibility in the sync accumulator db\n // the code will prefer `state_after` if it is present\n roomJson[\"org.matrix.msc4222.state_after\"].events.push(ev);\n // Roll the state back to the value at the start of the timeline if it was changed\n if (rollBackState[evType] && rollBackState[evType][stateKey]) {\n ev = rollBackState[evType][stateKey];\n }\n roomJson.state.events.push(ev);\n });\n });\n data.join[roomId] = roomJson;\n });\n\n // Add account data\n const accData: IMinimalEvent[] = [];\n Object.keys(this.accountData).forEach((evType) => {\n accData.push(this.accountData[evType]);\n });\n\n return {\n nextBatch: this.nextBatch!,\n roomsData: data,\n accountData: accData,\n };\n }\n\n public getNextBatchToken(): string {\n return this.nextBatch!;\n }\n}\n\nfunction setState(eventMap: Record<string, Record<string, IStateEvent>>, event: IRoomEvent | IStateEvent): void {\n if ((event as IStateEvent).state_key === null || (event as IStateEvent).state_key === undefined || !event.type) {\n return;\n }\n if (!eventMap[event.type]) {\n eventMap[event.type] = Object.create(null);\n }\n eventMap[event.type][(event as IStateEvent).state_key] = event as IStateEvent;\n}\n","/*\nCopyright 2019 New Vector Ltd\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n/**\n * Check if an IndexedDB database exists. The only way to do so is to try opening it, so\n * we do that and then delete it did not exist before.\n *\n * @param indexedDB - The `indexedDB` interface\n * @param dbName - The database name to test for\n * @returns Whether the database exists\n */\nexport function exists(indexedDB: IDBFactory, dbName: string): Promise<boolean> {\n return new Promise<boolean>((resolve, reject) => {\n let exists = true;\n const req = indexedDB.open(dbName);\n req.onupgradeneeded = (): void => {\n // Since we did not provide an explicit version when opening, this event\n // should only fire if the DB did not exist before at any version.\n exists = false;\n };\n req.onblocked = (): void => reject(req.error);\n req.onsuccess = (): void => {\n const db = req.result;\n db.close();\n if (!exists) {\n // The DB did not exist before, but has been created as part of this\n // existence check. Delete it now to restore previous state. Delete can\n // actually take a while to complete in some browsers, so don't wait for\n // it. This won't block future open calls that a store might issue next to\n // properly set up the DB.\n indexedDB.deleteDatabase(dbName);\n }\n resolve(exists);\n };\n req.onerror = (): void => reject(req.error);\n });\n}\n","/*\nCopyright 2017 - 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { type IMinimalEvent, type ISyncData, type ISyncResponse, SyncAccumulator } from \"../sync-accumulator.ts\";\nimport { deepCopy, promiseTry } from \"../utils.ts\";\nimport { exists as idbExists } from \"../indexeddb-helpers.ts\";\nimport { logger } from \"../logger.ts\";\nimport { type IStateEventWithRoomId, type IStoredClientOpts } from \"../matrix.ts\";\nimport { type ISavedSync } from \"./index.ts\";\nimport { type IIndexedDBBackend, type UserTuple } from \"./indexeddb-backend.ts\";\nimport { type IndexedToDeviceBatch, type ToDeviceBatchWithTxnId } from \"../models/ToDeviceMessage.ts\";\n\ntype DbMigration = (db: IDBDatabase) => void;\nconst DB_MIGRATIONS: DbMigration[] = [\n (db): void => {\n // Make user store, clobber based on user ID. (userId property of User objects)\n db.createObjectStore(\"users\", { keyPath: [\"userId\"] });\n\n // Make account data store, clobber based on event type.\n // (event.type property of MatrixEvent objects)\n db.createObjectStore(\"accountData\", { keyPath: [\"type\"] });\n\n // Make /sync store (sync tokens, room data, etc), always clobber (const key).\n db.createObjectStore(\"sync\", { keyPath: [\"clobber\"] });\n },\n (db): void => {\n const oobMembersStore = db.createObjectStore(\"oob_membership_events\", {\n keyPath: [\"room_id\", \"state_key\"],\n });\n oobMembersStore.createIndex(\"room\", \"room_id\");\n },\n (db): void => {\n db.createObjectStore(\"client_options\", { keyPath: [\"clobber\"] });\n },\n (db): void => {\n db.createObjectStore(\"to_device_queue\", { autoIncrement: true });\n },\n // Expand as needed.\n];\nconst VERSION = DB_MIGRATIONS.length;\n\n/**\n * Helper method to collect results from a Cursor and promiseify it.\n * @param store - The store to perform openCursor on.\n * @param keyRange - Optional key range to apply on the cursor.\n * @param resultMapper - A function which is repeatedly called with a\n * Cursor.\n * Return the data you want to keep.\n * @returns Promise which resolves to an array of whatever you returned from\n * resultMapper.\n */\nfunction selectQuery<T>(\n store: IDBObjectStore,\n keyRange: IDBKeyRange | IDBValidKey | undefined,\n resultMapper: (cursor: IDBCursorWithValue) => T,\n): Promise<T[]> {\n const query = store.openCursor(keyRange);\n return new Promise((resolve, reject) => {\n const results: T[] = [];\n query.onerror = (): void => {\n reject(new Error(\"Query failed: \" + query.error?.name));\n };\n // collect results\n query.onsuccess = (): void => {\n const cursor = query.result;\n if (!cursor) {\n resolve(results);\n return; // end of results\n }\n results.push(resultMapper(cursor));\n cursor.continue();\n };\n });\n}\n\nfunction txnAsPromise(txn: IDBTransaction): Promise<Event> {\n return new Promise((resolve, reject) => {\n txn.oncomplete = function (event): void {\n resolve(event);\n };\n txn.onerror = function (): void {\n reject(txn.error);\n };\n });\n}\n\nfunction reqAsEventPromise(req: IDBRequest): Promise<Event> {\n return new Promise((resolve, reject) => {\n req.onsuccess = function (event): void {\n resolve(event);\n };\n req.onerror = function (): void {\n reject(req.error);\n };\n });\n}\n\nfunction reqAsPromise(req: IDBRequest): Promise<IDBRequest> {\n return new Promise((resolve, reject) => {\n req.onsuccess = (): void => resolve(req);\n req.onerror = (err): void => reject(err);\n });\n}\n\nfunction reqAsCursorPromise<T>(req: IDBRequest<T>): Promise<T> {\n return reqAsEventPromise(req).then((event) => req.result);\n}\n\nexport class LocalIndexedDBStoreBackend implements IIndexedDBBackend {\n public static exists(indexedDB: IDBFactory, dbName: string): Promise<boolean> {\n dbName = \"matrix-js-sdk:\" + (dbName || \"default\");\n return idbExists(indexedDB, dbName);\n }\n\n private readonly dbName: string;\n private readonly syncAccumulator: SyncAccumulator;\n private db?: IDBDatabase;\n private disconnected = true;\n private _isNewlyCreated = false;\n private syncToDatabasePromise?: Promise<void>;\n private pendingUserPresenceData: UserTuple[] = [];\n\n /**\n * Does the actual reading from and writing to the indexeddb\n *\n * Construct a new Indexed Database store backend. This requires a call to\n * `connect()` before this store can be used.\n * @param indexedDB - The Indexed DB interface e.g\n * `window.indexedDB`\n * @param dbName - Optional database name. The same name must be used\n * to open the same database.\n */\n public constructor(\n private readonly indexedDB: IDBFactory,\n dbName = \"default\",\n ) {\n this.dbName = \"matrix-js-sdk:\" + dbName;\n this.syncAccumulator = new SyncAccumulator();\n }\n\n /**\n * Attempt to connect to the database. This can fail if the user does not\n * grant permission.\n * @returns Promise which resolves if successfully connected.\n */\n public connect(onClose?: () => void): Promise<void> {\n if (!this.disconnected) {\n logger.log(`LocalIndexedDBStoreBackend.connect: already connected or connecting`);\n return Promise.resolve();\n }\n\n this.disconnected = false;\n\n logger.log(`LocalIndexedDBStoreBackend.connect: connecting...`);\n const req = this.indexedDB.open(this.dbName, VERSION);\n req.onupgradeneeded = (ev): void => {\n const db = req.result;\n const oldVersion = ev.oldVersion;\n logger.log(`LocalIndexedDBStoreBackend.connect: upgrading from ${oldVersion}`);\n if (oldVersion < 1) {\n // The database did not previously exist\n this._isNewlyCreated = true;\n }\n DB_MIGRATIONS.forEach((migration, index) => {\n if (oldVersion <= index) migration(db);\n });\n };\n\n req.onblocked = (): void => {\n logger.log(`can't yet open LocalIndexedDBStoreBackend because it is open elsewhere`);\n };\n\n logger.log(`LocalIndexedDBStoreBackend.connect: awaiting connection...`);\n return reqAsEventPromise(req).then(async () => {\n logger.log(`LocalIndexedDBStoreBackend.connect: connected`);\n this.db = req.result;\n\n // add a poorly-named listener for when deleteDatabase is called\n // so we can close our db connections.\n this.db.onversionchange = (): void => {\n this.db?.close(); // this does not call onclose\n this.disconnected = true;\n this.db = undefined;\n };\n this.db.onclose = (): void => {\n this.disconnected = true;\n this.db = undefined;\n onClose?.();\n };\n\n await this.init();\n });\n }\n\n /** @returns whether or not the database was newly created in this session. */\n public isNewlyCreated(): Promise<boolean> {\n return Promise.resolve(this._isNewlyCreated);\n }\n\n /**\n * Having connected, load initial data from the database and prepare for use\n * @returns Promise which resolves on success\n */\n private init(): Promise<unknown> {\n return Promise.all([this.loadAccountData(), this.loadSyncData()]).then(([accountData, syncData]) => {\n logger.log(`LocalIndexedDBStoreBackend: loaded initial data`);\n this.syncAccumulator.accumulate(\n {\n next_batch: syncData.nextBatch,\n rooms: syncData.roomsData,\n account_data: {\n events: accountData,\n },\n },\n true,\n );\n });\n }\n\n /**\n * Returns the out-of-band membership events for this room that\n * were previously loaded.\n * @returns the events, potentially an empty array if OOB loading didn't yield any new members\n * @returns in case the members for this room haven't been stored yet\n */\n public getOutOfBandMembers(roomId: string): Promise<IStateEventWithRoomId[] | null> {\n return new Promise<IStateEventWithRoomId[] | null>((resolve, reject) => {\n const tx = this.db!.transaction([\"oob_membership_events\"], \"readonly\");\n const store = tx.objectStore(\"oob_membership_events\");\n const roomIndex = store.index(\"room\");\n const range = IDBKeyRange.only(roomId);\n const request = roomIndex.openCursor(range);\n\n const membershipEvents: IStateEventWithRoomId[] = [];\n // did we encounter the oob_written marker object\n // amongst the results? That means OOB member\n // loading already happened for this room\n // but there were no members to persist as they\n // were all known already\n let oobWritten = false;\n\n request.onsuccess = (): void => {\n const cursor = request.result;\n if (!cursor) {\n // Unknown room\n if (!membershipEvents.length && !oobWritten) {\n return resolve(null);\n }\n return resolve(membershipEvents);\n }\n const record = cursor.value;\n if (record.oob_written) {\n oobWritten = true;\n } else {\n membershipEvents.push(record);\n }\n cursor.continue();\n };\n request.onerror = (err): void => {\n reject(err);\n };\n }).then((events) => {\n logger.log(`LL: got ${events?.length} membershipEvents from storage for room ${roomId} ...`);\n return events;\n });\n }\n\n /**\n * Stores the out-of-band membership events for this room. Note that\n * it still makes sense to store an empty array as the OOB status for the room is\n * marked as fetched, and getOutOfBandMembers will return an empty array instead of null\n * @param membershipEvents - the membership events to store\n */\n public async setOutOfBandMembers(roomId: string, membershipEvents: IStateEventWithRoomId[]): Promise<void> {\n logger.log(`LL: backend about to store ${membershipEvents.length}` + ` members for ${roomId}`);\n const tx = this.db!.transaction([\"oob_membership_events\"], \"readwrite\");\n const store = tx.objectStore(\"oob_membership_events\");\n membershipEvents.forEach((e) => {\n store.put(e);\n });\n // aside from all the events, we also write a marker object to the store\n // to mark the fact that OOB members have been written for this room.\n // It's possible that 0 members need to be written as all where previously know\n // but we still need to know whether to return null or [] from getOutOfBandMembers\n // where null means out of band members haven't been stored yet for this room\n const markerObject = {\n room_id: roomId,\n oob_written: true,\n state_key: 0,\n };\n store.put(markerObject);\n await txnAsPromise(tx);\n logger.log(`LL: backend done storing for ${roomId}!`);\n }\n\n public async clearOutOfBandMembers(roomId: string): Promise<void> {\n // the approach to delete all members for a room\n // is to get the min and max state key from the index\n // for that room, and then delete between those\n // keys in the store.\n // this should be way faster than deleting every member\n // individually for a large room.\n const readTx = this.db!.transaction([\"oob_membership_events\"], \"readonly\");\n const store = readTx.objectStore(\"oob_membership_events\");\n const roomIndex = store.index(\"room\");\n const roomRange = IDBKeyRange.only(roomId);\n\n const minStateKeyProm = reqAsCursorPromise(roomIndex.openKeyCursor(roomRange, \"next\")).then(\n (cursor) => (<IDBValidKey[]>cursor?.primaryKey)[1],\n );\n const maxStateKeyProm = reqAsCursorPromise(roomIndex.openKeyCursor(roomRange, \"prev\")).then(\n (cursor) => (<IDBValidKey[]>cursor?.primaryKey)[1],\n );\n const [minStateKey, maxStateKey] = await Promise.all([minStateKeyProm, maxStateKeyProm]);\n\n const writeTx = this.db!.transaction([\"oob_membership_events\"], \"readwrite\");\n const writeStore = writeTx.objectStore(\"oob_membership_events\");\n const membersKeyRange = IDBKeyRange.bound([roomId, minStateKey], [roomId, maxStateKey]);\n\n logger.log(\n `LL: Deleting all users + marker in storage for room ${roomId}, with key range:`,\n [roomId, minStateKey],\n [roomId, maxStateKey],\n );\n await reqAsPromise(writeStore.delete(membersKeyRange));\n }\n\n /**\n * Clear the entire database. This should be used when logging out of a client\n * to prevent mixing data between accounts. Closes the database.\n * @returns Resolved when the database is cleared.\n */\n public clearDatabase(): Promise<void> {\n return new Promise((resolve) => {\n logger.log(`Removing indexeddb instance: ${this.dbName}`);\n\n // Close the database first to avoid firing unexpected close events\n this.db?.close();\n\n const req = this.indexedDB.deleteDatabase(this.dbName);\n\n req.onblocked = (): void => {\n logger.log(`can't yet delete indexeddb ${this.dbName} because it is open elsewhere`);\n };\n\n req.onerror = (): void => {\n // in firefox, with indexedDB disabled, this fails with a\n // DOMError. We treat this as non-fatal, so that we can still\n // use the app.\n logger.warn(`unable to delete js-sdk store indexeddb: ${req.error?.name}`);\n resolve();\n };\n\n req.onsuccess = (): void => {\n logger.log(`Removed indexeddb instance: ${this.dbName}`);\n resolve();\n };\n });\n }\n\n /**\n * @param copy - If false, the data returned is from internal\n * buffers and must not be mutated. Otherwise, a copy is made before\n * returning such that the data can be safely mutated. Default: true.\n *\n * @returns Promise which resolves with a sync response to restore the\n * client state to where it was at the last save, or null if there\n * is no saved sync data.\n */\n public getSavedSync(copy = true): Promise<ISavedSync | null> {\n const data = this.syncAccumulator.getJSON();\n if (!data.nextBatch) return Promise.resolve(null);\n if (copy) {\n // We must deep copy the stored data so that the /sync processing code doesn't\n // corrupt the internal state of the sync accumulator (it adds non-clonable keys)\n return Promise.resolve(deepCopy(data));\n } else {\n return Promise.resolve(data);\n }\n }\n\n public getNextBatchToken(): Promise<string> {\n return Promise.resolve(this.syncAccumulator.getNextBatchToken());\n }\n\n public setSyncData(syncData: ISyncResponse): Promise<void> {\n return Promise.resolve().then(() => {\n this.syncAccumulator.accumulate(syncData);\n });\n }\n\n /**\n * Sync users and all accumulated sync data to the database.\n * If a previous sync is in flight, the new data will be added to the\n * next sync and the current sync's promise will be returned.\n * @param userTuples - The user tuples\n * @returns Promise which resolves if the data was persisted.\n */\n public async syncToDatabase(userTuples: UserTuple[]): Promise<void> {\n if (this.syncToDatabasePromise) {\n logger.warn(\"Skipping syncToDatabase() as persist already in flight\");\n this.pendingUserPresenceData.push(...userTuples);\n return this.syncToDatabasePromise;\n }\n userTuples.unshift(...this.pendingUserPresenceData);\n this.syncToDatabasePromise = this.doSyncToDatabase(userTuples);\n return this.syncToDatabasePromise;\n }\n\n private async doSyncToDatabase(userTuples: UserTuple[]): Promise<void> {\n try {\n const syncData = this.syncAccumulator.getJSON(true);\n await Promise.all([\n this.persistUserPresenceEvents(userTuples),\n this.persistAccountData(syncData.accountData),\n this.persistSyncData(syncData.nextBatch, syncData.roomsData),\n ]);\n } finally {\n this.syncToDatabasePromise = undefined;\n }\n }\n\n /**\n * Persist rooms /sync data along with the next batch token.\n * @param nextBatch - The next_batch /sync value.\n * @param roomsData - The 'rooms' /sync data from a SyncAccumulator\n * @returns Promise which resolves if the data was persisted.\n */\n private persistSyncData(nextBatch: string, roomsData: ISyncResponse[\"rooms\"]): Promise<void> {\n logger.log(\"Persisting sync data up to\", nextBatch);\n return promiseTry<void>(() => {\n const txn = this.db!.transaction([\"sync\"], \"readwrite\");\n const store = txn.objectStore(\"sync\");\n store.put({\n clobber: \"-\", // constant key so will always clobber\n nextBatch,\n roomsData,\n }); // put == UPSERT\n return txnAsPromise(txn).then(() => {\n logger.log(\"Persisted sync data up to\", nextBatch);\n });\n });\n }\n\n /**\n * Persist a list of account data events. Events with the same 'type' will\n * be replaced.\n * @param accountData - An array of raw user-scoped account data events\n * @returns Promise which resolves if the events were persisted.\n */\n private persistAccountData(accountData: IMinimalEvent[]): Promise<void> {\n return promiseTry<void>(() => {\n const txn = this.db!.transaction([\"accountData\"], \"readwrite\");\n const store = txn.objectStore(\"accountData\");\n for (const event of accountData) {\n store.put(event); // put == UPSERT\n }\n return txnAsPromise(txn).then();\n });\n }\n\n /**\n * Persist a list of [user id, presence event] they are for.\n * Users with the same 'userId' will be replaced.\n * Presence events should be the event in its raw form (not the Event\n * object)\n * @param tuples - An array of [userid, event] tuples\n * @returns Promise which resolves if the users were persisted.\n */\n private persistUserPresenceEvents(tuples: UserTuple[]): Promise<void> {\n return promiseTry<void>(() => {\n const txn = this.db!.transaction([\"users\"], \"readwrite\");\n const store = txn.objectStore(\"users\");\n for (const tuple of tuples) {\n store.put({\n userId: tuple[0],\n event: tuple[1],\n }); // put == UPSERT\n }\n return txnAsPromise(txn).then();\n });\n }\n\n /**\n * Load all user presence events from the database. This is not cached.\n * FIXME: It would probably be more sensible to store the events in the\n * sync.\n * @returns A list of presence events in their raw form.\n */\n public getUserPresenceEvents(): Promise<UserTuple[]> {\n return promiseTry<UserTuple[]>(() => {\n const txn = this.db!.transaction([\"users\"], \"readonly\");\n const store = txn.objectStore(\"users\");\n return selectQuery(store, undefined, (cursor) => {\n return [cursor.value.userId, cursor.value.event];\n });\n });\n }\n\n /**\n * Load all the account data events from the database. This is not cached.\n * @returns A list of raw global account events.\n */\n private loadAccountData(): Promise<IMinimalEvent[]> {\n logger.log(`LocalIndexedDBStoreBackend: loading account data...`);\n return promiseTry<IMinimalEvent[]>(() => {\n const txn = this.db!.transaction([\"accountData\"], \"readonly\");\n const store = txn.objectStore(\"accountData\");\n return selectQuery(store, undefined, (cursor) => {\n return cursor.value;\n }).then((result: IMinimalEvent[]) => {\n logger.log(`LocalIndexedDBStoreBackend: loaded account data`);\n return result;\n });\n });\n }\n\n /**\n * Load the sync data from the database.\n * @returns An object with \"roomsData\" and \"nextBatch\" keys.\n */\n private loadSyncData(): Promise<ISyncData> {\n logger.log(`LocalIndexedDBStoreBackend: loading sync data...`);\n return promiseTry<ISyncData>(() => {\n const txn = this.db!.transaction([\"sync\"], \"readonly\");\n const store = txn.objectStore(\"sync\");\n return selectQuery(store, undefined, (cursor) => {\n return cursor.value;\n }).then((results: ISyncData[]) => {\n logger.log(`LocalIndexedDBStoreBackend: loaded sync data`);\n if (results.length > 1) {\n logger.warn(\"loadSyncData: More than 1 sync row found.\");\n }\n return results.length > 0 ? results[0] : ({} as ISyncData);\n });\n });\n }\n\n public getClientOptions(): Promise<IStoredClientOpts | undefined> {\n return Promise.resolve().then(() => {\n const txn = this.db!.transaction([\"client_options\"], \"readonly\");\n const store = txn.objectStore(\"client_options\");\n return selectQuery(store, undefined, (cursor) => {\n return cursor.value?.options;\n }).then((results) => results[0]);\n });\n }\n\n public async storeClientOptions(options: IStoredClientOpts): Promise<void> {\n const txn = this.db!.transaction([\"client_options\"], \"readwrite\");\n const store = txn.objectStore(\"client_options\");\n store.put({\n clobber: \"-\", // constant key so will always clobber\n options: options,\n }); // put == UPSERT\n await txnAsPromise(txn);\n }\n\n public async saveToDeviceBatches(batches: ToDeviceBatchWithTxnId[]): Promise<void> {\n const txn = this.db!.transaction([\"to_device_queue\"], \"readwrite\");\n const store = txn.objectStore(\"to_device_queue\");\n for (const batch of batches) {\n store.add(batch);\n }\n await txnAsPromise(txn);\n }\n\n public async getOldestToDeviceBatch(): Promise<IndexedToDeviceBatch | null> {\n const txn = this.db!.transaction([\"to_device_queue\"], \"readonly\");\n const store = txn.objectStore(\"to_device_queue\");\n const cursor = await reqAsCursorPromise(store.openCursor());\n if (!cursor) return null;\n\n const resultBatch = cursor.value as ToDeviceBatchWithTxnId;\n\n return {\n id: cursor.key as number,\n txnId: resultBatch.txnId,\n eventType: resultBatch.eventType,\n batch: resultBatch.batch,\n };\n }\n\n public async removeToDeviceBatch(id: number): Promise<void> {\n const txn = this.db!.transaction([\"to_device_queue\"], \"readwrite\");\n const store = txn.objectStore(\"to_device_queue\");\n store.delete(id);\n await txnAsPromise(txn);\n }\n\n /*\n * Close the database\n */\n public async destroy(): Promise<void> {\n this.db?.close();\n }\n}\n","/*\nCopyright 2017 - 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nimport { LocalIndexedDBStoreBackend } from \"./indexeddb-local-backend.ts\";\nimport { logger } from \"../logger.ts\";\n\ninterface ICmd {\n command: string;\n seq: number;\n args: any[];\n}\n\n/**\n * This class lives in the webworker and drives a LocalIndexedDBStoreBackend\n * controlled by messages from the main process.\n *\n * @example\n * It should be instantiated by a web worker script provided by the application\n * in a script, for example:\n * ```\n * import {IndexedDBStoreWorker} from 'matrix-js-sdk/lib/indexeddb-worker.js';\n * const remoteWorker = new IndexedDBStoreWorker(postMessage);\n * onmessage = remoteWorker.onMessage;\n * ```\n *\n * Note that it is advisable to import this class by referencing the file directly to\n * avoid a dependency on the whole js-sdk.\n *\n */\nexport class IndexedDBStoreWorker {\n private backend?: LocalIndexedDBStoreBackend;\n\n /**\n * @param postMessage - The web worker postMessage function that\n * should be used to communicate back to the main script.\n */\n public constructor(private readonly postMessage: InstanceType<typeof Worker>[\"postMessage\"]) {}\n\n private onClose = (): void => {\n this.postMessage.call(null, {\n command: \"closed\",\n });\n };\n\n /**\n * Passes a message event from the main script into the class. This method\n * can be directly assigned to the web worker `onmessage` variable.\n *\n * @param ev - The message event\n */\n public onMessage = (ev: MessageEvent): void => {\n const msg: ICmd = ev.data;\n let prom: Promise<any> | undefined;\n\n switch (msg.command) {\n case \"setupWorker\":\n // this is the 'indexedDB' global (where global != window\n // because it's a web worker and there is no window).\n this.backend = new LocalIndexedDBStoreBackend(indexedDB, msg.args[0]);\n prom = Promise.resolve();\n break;\n case \"connect\":\n prom = this.backend?.connect(this.onClose);\n break;\n case \"isNewlyCreated\":\n prom = this.backend?.isNewlyCreated();\n break;\n case \"clearDatabase\":\n prom = this.backend?.clearDatabase();\n break;\n case \"getSavedSync\":\n prom = this.backend?.getSavedSync(false);\n break;\n case \"setSyncData\":\n prom = this.backend?.setSyncData(msg.args[0]);\n break;\n case \"syncToDatabase\":\n prom = this.backend?.syncToDatabase(msg.args[0]);\n break;\n case \"getUserPresenceEvents\":\n prom = this.backend?.getUserPresenceEvents();\n break;\n case \"getNextBatchToken\":\n prom = this.backend?.getNextBatchToken();\n break;\n case \"getOutOfBandMembers\":\n prom = this.backend?.getOutOfBandMembers(msg.args[0]);\n break;\n case \"clearOutOfBandMembers\":\n prom = this.backend?.clearOutOfBandMembers(msg.args[0]);\n break;\n case \"setOutOfBandMembers\":\n prom = this.backend?.setOutOfBandMembers(msg.args[0], msg.args[1]);\n break;\n case \"getClientOptions\":\n prom = this.backend?.getClientOptions();\n break;\n case \"storeClientOptions\":\n prom = this.backend?.storeClientOptions(msg.args[0]);\n break;\n case \"saveToDeviceBatches\":\n prom = this.backend?.saveToDeviceBatches(msg.args[0]);\n break;\n case \"getOldestToDeviceBatch\":\n prom = this.backend?.getOldestToDeviceBatch();\n break;\n case \"removeToDeviceBatch\":\n prom = this.backend?.removeToDeviceBatch(msg.args[0]);\n break;\n }\n\n if (prom === undefined) {\n this.postMessage({\n command: \"cmd_fail\",\n seq: msg.seq,\n // Can't be an Error because they're not structured cloneable\n error: \"Unrecognised command\",\n });\n return;\n }\n\n prom.then(\n (ret) => {\n this.postMessage.call(null, {\n command: \"cmd_success\",\n seq: msg.seq,\n result: ret,\n });\n },\n (err) => {\n logger.error(\"Error running command: \" + msg.command, err);\n this.postMessage.call(null, {\n command: \"cmd_fail\",\n seq: msg.seq,\n // Just send a string because Error objects aren't cloneable\n error: {\n message: err.message,\n name: err.name,\n },\n });\n },\n );\n };\n}\n","/*\nCopyright 2022-2024 New Vector Ltd.\n\nSPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial\nPlease see LICENSE in the repository root for full details.\n*/\n\nimport { IndexedDBStoreWorker } from \"matrix-js-sdk/src/indexeddb-worker\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst remoteWorker = new IndexedDBStoreWorker((self as any).postMessage);\n\nself.onmessage = remoteWorker.onMessage;\n"],"names":["root","definition","module","this","noop","undefinedType","isIE","logMethods","_loggersByName","defaultLogger","bindMethod","obj","methodName","method","traceForIE","realMethod","replaceLoggingMethods","level","i","enableLoggingWhenConsoleArrives","defaultMethodFactory","_level","_loggerName","Logger","name","factory","self","inheritedLevel","defaultLevel","userLevel","storageKey","persistLevelIfPossible","levelNum","levelName","getPersistedLevel","storedLevel","cookie","cookieName","location","clearPersistedLevel","normalizeLevel","input","persist","childName","initialLevel","logger","_log","DEFAULT_NAMESPACE","loglevel","logLevel","loggerName","args","getPrefixedLogger","prefix","prefixLogger","childPrefix","data","require$$0","escapeRegexp","str","REPLACE_RE","replace_fn","match","unhomoglyph","hasRequiredRetry_operation","RetryOperation","timeouts","options","retry_operation","err","currentTime","timeout","timeoutOps","fn","counts","error","count","message","mainErrorCount","mainError","requireRetry_operation","exports","opts","key","b","attempt","random","methods","original","op","callback","hasRequiredRetry","hasRequiredPRetry","pRetry","retry","networkErrorMsgs","decorateErrorWithCounts","attemptNumber","retriesLeft","errorMessage","pRetry$1","resolve","reject","operation","isNetworkError","pRetryModule","requirePRetry","NamespacedValue","stable","unstable","altName","names","val","arr","included","ServerControlledNamespacedValue","preferUnstable","UnstableValue","ReceiptType2","ReceiptType","deepCopy","promiseTry","isSupportedReceiptType","receiptType","processMapToObjectValue","value","recursiveMapToObject","v","map","targetMap","createDefault","UNREAD_THREAD_NOTIFICATIONS","EventType2","EventType","ReceiptAccumulator","MapWithDefault","userId","receipt","threadId","receiptsForThread","events","eventId","roomId","receiptEvent","receiptEventContent","receiptData","isTaggedEvent","event","SyncAccumulator","syncResponse","fromDatabase","category","currentData","e","hasAdded","current","HEROES_KEY","INVITED_COUNT_KEY","JOINED_COUNT_KEY","acc","sum","_a","_c","_b","setState","_e","_d","_g","_f","transformedEvent","age","index","startIndex","roomData","evType","roomJson","msgData","rollBackState","timelineEvent","prevStateEvent","stateKey","ev","accData","eventMap","exists","indexedDB","dbName","exists2","req","DB_MIGRATIONS","db","VERSION","selectQuery","store","keyRange","resultMapper","query","results","cursor","txnAsPromise","txn","reqAsEventPromise","reqAsPromise","reqAsCursorPromise","LocalIndexedDBStoreBackend","oldVersion","migration","onClose","accountData","syncData","roomIndex","range","request","membershipEvents","oobWritten","record","tx","markerObject","minStateKeyProm","roomRange","maxStateKeyProm","maxStateKey","writeStore","minStateKey","membersKeyRange","copy","userTuples","roomsData","nextBatch","tuple","tuples","result","batches","batch","resultBatch","id","IndexedDBStoreWorker","postMessage","msg","_h","_i","_j","_k","_l","_m","_n","_o","prom","_p","ret"],"mappings":"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","x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]}
Binary file
Binary file
Binary file
Binary file