diff --git a/CHANGELOG.md b/CHANGELOG.md index b7f3c4febd..e578d777f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +Changes in [1.11.107](https://github.com/element-hq/element-web/releases/tag/v1.11.107) (2025-07-29) +==================================================================================================== +## ✨ Features + +* Message preview should show tooltip with the full message on hover ([#30265](https://github.com/element-hq/element-web/pull/30265)). Contributed by @MidhunSureshR. +* Support rendering notification badges on platforms that do their own icon overlays ([#30315](https://github.com/element-hq/element-web/pull/30315)). Contributed by @Half-Shot. +* Add SubscriptionViewModel base class ([#30297](https://github.com/element-hq/element-web/pull/30297)). Contributed by @dbkr. +* Enhancement: Save image on CTRL+S ([#30330](https://github.com/element-hq/element-web/pull/30330)). Contributed by @ioalexander. +* Add quote functionality to MessageContextMenu (#29893) ([#30323](https://github.com/element-hq/element-web/pull/30323)). Contributed by @AlirezaMrtz. +* Initial structure for shared component views ([#30216](https://github.com/element-hq/element-web/pull/30216)). Contributed by @dbkr. + +## 🐛 Bug Fixes + +* [Backport staging] Fix e2e shield being invisible in white mode for encrypted room ([#30411](https://github.com/element-hq/element-web/pull/30411)). Contributed by @RiotRobot. +* Force ED titlebar color for new room list ([#30332](https://github.com/element-hq/element-web/pull/30332)). Contributed by @florianduros. +* Add a background color to left panel for macos titlebar in element desktop ([#30328](https://github.com/element-hq/element-web/pull/30328)). Contributed by @florianduros. +* Fix: Prevent page refresh on Enter key in right panel member search ([#30312](https://github.com/element-hq/element-web/pull/30312)). Contributed by @AlirezaMrtz. + + Changes in [1.11.106](https://github.com/element-hq/element-web/releases/tag/v1.11.106) (2025-07-15) ==================================================================================================== ## ✨ Features diff --git a/package.json b/package.json index 61fed8cb14..e48d36d004 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "element-web", - "version": "1.11.106", + "version": "1.11.107", "description": "Element: the future of secure communication", "author": "New Vector Ltd.", "repository": { @@ -99,7 +99,7 @@ "@types/react-virtualized": "^9.21.30", "@vector-im/compound-design-tokens": "^5.0.0", "@vector-im/compound-web": "^8.1.2", - "@vector-im/matrix-wysiwyg": "2.38.4", + "@vector-im/matrix-wysiwyg": "2.39.0", "@zxcvbn-ts/core": "^3.0.4", "@zxcvbn-ts/language-common": "^3.0.4", "@zxcvbn-ts/language-en": "^3.0.2", @@ -117,7 +117,7 @@ "emojibase-regex": "15.3.2", "escape-html": "^1.0.3", "file-saver": "^2.0.5", - "filesize": "10.1.6", + "filesize": "11.0.2", "github-markdown-css": "^5.5.1", "glob-to-regexp": "^0.4.1", "highlight.js": "^11.3.1", diff --git a/playwright/e2e/crypto/device-verification.spec.ts b/playwright/e2e/crypto/device-verification.spec.ts index f325754326..eb21dfc909 100644 --- a/playwright/e2e/crypto/device-verification.spec.ts +++ b/playwright/e2e/crypto/device-verification.spec.ts @@ -124,6 +124,10 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => { const toasts = new Toasts(page); await toasts.rejectToast("Notifications"); await toasts.assertNoToasts(); + + // There may still be a `/sendToDevice/m.secret.request` in flight, which will later throw an error and cause + // a *subsequent* test to fail. Tell playwright to ignore any errors resulting from in-flight routes. + await page.unrouteAll({ behavior: "ignoreErrors" }); }); test("Verify device with QR code during login", async ({ page, app, credentials, homeserver }) => { diff --git a/playwright/e2e/spaces/spaces.spec.ts b/playwright/e2e/spaces/spaces.spec.ts index 56c8ae22b8..b3f7ecb0c9 100644 --- a/playwright/e2e/spaces/spaces.spec.ts +++ b/playwright/e2e/spaces/spaces.spec.ts @@ -23,7 +23,7 @@ async function openSpaceContextMenu(page: Page, app: ElementAppPage, spaceName: return page.locator(".mx_SpacePanel_contextMenu"); } -function spaceCreateOptions(spaceName: string, roomIds: string[] = []): ICreateRoomOpts { +function spaceCreateOptions(serverName: string, spaceName: string, roomIds: string[] = []): ICreateRoomOpts { return { creation_content: { type: "m.space", @@ -35,17 +35,21 @@ function spaceCreateOptions(spaceName: string, roomIds: string[] = []): ICreateR name: spaceName, }, }, - ...roomIds.map((r) => spaceChildInitialState(r)), + ...roomIds.map((r) => spaceChildInitialState(serverName, r)), ], }; } -function spaceChildInitialState(roomId: string, order?: string): ICreateRoomOpts["initial_state"]["0"] { +function spaceChildInitialState( + serverName: string, + roomId: string, + order?: string, +): ICreateRoomOpts["initial_state"]["0"] { return { type: "m.space.child", state_key: roomId, content: { - via: [roomId.split(":")[1]], + via: [serverName], order, }, }; @@ -240,7 +244,7 @@ test.describe("Spaces", () => { }); await expect(await app.getSpacePanelButton("My Space")).toBeVisible(); - const roomId = await bot.createRoom(spaceCreateOptions("Space Space")); + const roomId = await bot.createRoom(spaceCreateOptions(user.homeServer, "Space Space")); await bot.inviteUser(roomId, user.userId); // Assert that `Space Space` is above `My Space` due to it being an invite @@ -260,7 +264,10 @@ test.describe("Spaces", () => { const spaceName = "Spacey Mc. Space Space"; await app.client.createSpace({ name: spaceName, - initial_state: [spaceChildInitialState(roomId1), spaceChildInitialState(roomId2)], + initial_state: [ + spaceChildInitialState(user.homeServer, roomId1), + spaceChildInitialState(user.homeServer, roomId2), + ], }); await app.viewSpaceHomeByName(spaceName); @@ -287,7 +294,7 @@ test.describe("Spaces", () => { }); await app.client.createSpace({ name: "Root Space", - initial_state: [spaceChildInitialState(childSpaceId)], + initial_state: [spaceChildInitialState(user.homeServer, childSpaceId)], }); // Find collapsed Space panel @@ -323,7 +330,7 @@ test.describe("Spaces", () => { name: "Test Room", topic: "This is a topic https://github.com/matrix-org/matrix-react-sdk/pull/10060 with a link", }); - const spaceId = await bot.createRoom(spaceCreateOptions("Test Space", [roomId])); + const spaceId = await bot.createRoom(spaceCreateOptions(user.homeServer, "Test Space", [roomId])); await bot.inviteUser(spaceId, user.userId); await expect(await app.getSpacePanelButton("Test Space")).toBeVisible(); @@ -361,9 +368,9 @@ test.describe("Spaces", () => { await app.client.createSpace({ name: "Root Space", initial_state: [ - spaceChildInitialState(childSpaceId1, "a"), - spaceChildInitialState(childSpaceId2, "b"), - spaceChildInitialState(childSpaceId3, "c"), + spaceChildInitialState(user.homeServer, childSpaceId1, "a"), + spaceChildInitialState(user.homeServer, childSpaceId2, "b"), + spaceChildInitialState(user.homeServer, childSpaceId3, "c"), ], }); await app.viewSpaceByName("Root Space"); diff --git a/src/hooks/useDownloadMedia.ts b/src/hooks/useDownloadMedia.ts index 74328ac7ca..eb0af954e0 100644 --- a/src/hooks/useDownloadMedia.ts +++ b/src/hooks/useDownloadMedia.ts @@ -59,15 +59,19 @@ export function useDownloadMedia(url: string, fileName?: string, mxEvent?: Matri return downloadBlob(blobRef.current); } - const res = await fetch(url); - if (!res.ok) { - throw parseErrorResponse(res, await res.text()); + // We must download via the mediaEventHelper if given as the file may need decryption. + if (mediaEventHelper) { + blobRef.current = await mediaEventHelper.sourceBlob.value; + } else { + const res = await fetch(url); + if (!res.ok) { + throw parseErrorResponse(res, await res.text()); + } + + blobRef.current = await res.blob(); } - const blob = await res.blob(); - blobRef.current = blob; - - await downloadBlob(blob); + await downloadBlob(blobRef.current); } catch (e) { showError(e); } diff --git a/src/stores/widgets/StopGapWidgetDriver.ts b/src/stores/widgets/StopGapWidgetDriver.ts index 282d6f5d92..d47c9d18e4 100644 --- a/src/stores/widgets/StopGapWidgetDriver.ts +++ b/src/stores/widgets/StopGapWidgetDriver.ts @@ -168,6 +168,7 @@ export class StopGapWidgetDriver extends WidgetDriver { WidgetEventCapability.forStateEvent(EventDirection.Receive, EventType.RoomCreate).raw, ); + const sendRoomEvents = [EventType.CallNotify, EventType.RTCNotification]; const sendRecvRoomEvents = [ "io.element.call.encryption_keys", "org.matrix.rageshake_request", @@ -175,10 +176,10 @@ export class StopGapWidgetDriver extends WidgetDriver { EventType.RoomRedaction, "io.element.call.reaction", ]; - for (const eventType of sendRecvRoomEvents) { + for (const eventType of [...sendRoomEvents, ...sendRecvRoomEvents]) this.allowedCapabilities.add(WidgetEventCapability.forRoomEvent(EventDirection.Send, eventType).raw); + for (const eventType of sendRecvRoomEvents) this.allowedCapabilities.add(WidgetEventCapability.forRoomEvent(EventDirection.Receive, eventType).raw); - } const sendRecvToDevice = [ EventType.CallInvite, diff --git a/src/utils/FileUtils.ts b/src/utils/FileUtils.ts index 1240dc61db..7958489057 100644 --- a/src/utils/FileUtils.ts +++ b/src/utils/FileUtils.ts @@ -7,16 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { - filesize, - type FileSizeOptionsArray, - type FileSizeOptionsBase, - type FileSizeOptionsExponent, - type FileSizeOptionsObject, - type FileSizeOptionsString, - type FileSizeReturnArray, - type FileSizeReturnObject, -} from "filesize"; +import { filesize, type FilesizeOptions, type FilesizeReturn } from "filesize"; import { type MediaEventContent } from "matrix-js-sdk/src/types"; import { _t } from "../languageHandler"; @@ -27,7 +18,7 @@ export function downloadLabelForFile(content: MediaEventContent, withSize = true if (content.info?.size && withSize) { // If we know the size of the file then add it as human-readable string to the end of the link text // so that the user knows how big a file they are downloading. - text += " (" + fileSize(content.info.size, { base: 2, standard: "jedec" }) + ")"; + text += " (" + fileSize(content.info.size, { base: 2, standard: "jedec" }) + ")"; } return text; } @@ -83,18 +74,11 @@ export function presentableTextForFile( // it since it is "ugly", users generally aren't aware what it // means and the type of the attachment can usually be inferred // from the file extension. - text += " (" + fileSize(content.info.size, { base: 2, standard: "jedec" }) + ")"; + text += " (" + fileSize(content.info.size, { base: 2, standard: "jedec" }) + ")"; } return text; } -type FileSizeOptions = - | FileSizeOptionsString - | FileSizeOptionsBase - | FileSizeOptionsArray - | FileSizeOptionsExponent - | FileSizeOptionsObject; - /** * wrapper function to set default values for filesize function * @@ -106,15 +90,7 @@ type FileSizeOptions = * exponent: number; * unit: string;}} formatted file size with unit e.g. 12kB, 12KB */ -export function fileSize(byteCount: number, options: FileSizeOptionsString | FileSizeOptionsBase): string; -export function fileSize(byteCount: number, options: FileSizeOptionsArray): FileSizeReturnArray; -export function fileSize(byteCount: number, options: FileSizeOptionsExponent): number; -export function fileSize(byteCount: number, options: FileSizeOptionsObject): FileSizeReturnObject; -export function fileSize(byteCount: number): string; -export function fileSize( - byteCount: number, - options?: FileSizeOptions, -): string | number | FileSizeReturnArray | FileSizeReturnObject { - const defaultOption: FileSizeOptions = { base: 2, standard: "jedec", ...options }; - return filesize(byteCount, defaultOption); +export function fileSize(byteCount: number, options?: O): FilesizeReturn { + const defaultOption = { base: 2, standard: "jedec", ...options } as O; + return filesize(byteCount, defaultOption); } diff --git a/test/unit-tests/components/structures/MatrixChat-test.tsx b/test/unit-tests/components/structures/MatrixChat-test.tsx index c813143142..6d8dcec1a7 100644 --- a/test/unit-tests/components/structures/MatrixChat-test.tsx +++ b/test/unit-tests/components/structures/MatrixChat-test.tsx @@ -71,6 +71,8 @@ import { SetupEncryptionStore } from "../../../../src/stores/SetupEncryptionStor import { ShareFormat } from "../../../../src/dispatcher/payloads/SharePayload.ts"; import { clearStorage } from "../../../../src/Lifecycle"; import RoomListStore from "../../../../src/stores/room-list/RoomListStore.ts"; +import UserSettingsDialog from "../../../../src/components/views/dialogs/UserSettingsDialog.tsx"; +import { SdkContextClass } from "../../../../src/contexts/SDKContext.ts"; jest.mock("matrix-js-sdk/src/oidc/authorize", () => ({ completeAuthorizationCodeGrant: jest.fn(), @@ -268,6 +270,10 @@ describe("", () => { // (must be sync otherwise the next test will start before it happens) act(() => defaultDispatcher.dispatch({ action: Action.OnLoggedOut }, true)); + // that will cause the Login to kick off an update in the background, which we need to allow to finish within + // an `act` to avoid warnings + await flushPromises(); + localStorage.clear(); }); @@ -640,22 +646,29 @@ describe("", () => { }); describe("onAction()", () => { - beforeEach(() => { - jest.spyOn(defaultDispatcher, "dispatch").mockClear(); - jest.spyOn(defaultDispatcher, "fire").mockClear(); + afterEach(() => { + jest.restoreAllMocks(); }); - it("should open user device settings", async () => { + + it("ViewUserDeviceSettings should open user device settings", async () => { await getComponentAndWaitForReady(); - defaultDispatcher.dispatch({ - action: Action.ViewUserDeviceSettings, - }); + const createDialog = jest.spyOn(Modal, "createDialog").mockReturnValue({} as any); - await flushPromises(); + await act(async () => { + defaultDispatcher.dispatch({ + action: Action.ViewUserDeviceSettings, + }); - expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({ - action: Action.ViewUserSettings, - initialTabId: UserTab.SessionManager, + await waitFor(() => + expect(createDialog).toHaveBeenCalledWith( + UserSettingsDialog, + { initialTabId: UserTab.SessionManager, sdkContext: expect.any(SdkContextClass) }, + /*className=*/ undefined, + /*isPriority=*/ false, + /*isStatic=*/ true, + ), + ); }); }); @@ -674,10 +687,6 @@ describe("", () => { jest.spyOn(ReleaseAnnouncementStore.instance, "getReleaseAnnouncement").mockReturnValue(null); }); - afterEach(() => { - jest.restoreAllMocks(); - }); - describe("forget_room", () => { it("should dispatch after_forget_room action on successful forget", async () => { await clearAllModals(); @@ -1604,7 +1613,7 @@ describe("", () => { }); // Flaky test, see https://github.com/element-hq/element-web/issues/30337 - it.skip("waits for other tab to stop during startup", async () => { + it("waits for other tab to stop during startup", async () => { fetchMock.get("/welcome.html", { body: "

Hello

" }); jest.spyOn(Lifecycle, "attemptDelegatedAuthLogin"); diff --git a/test/unit-tests/components/views/elements/ImageView-test.tsx b/test/unit-tests/components/views/elements/ImageView-test.tsx index b0e9338f69..6537a3948a 100644 --- a/test/unit-tests/components/views/elements/ImageView-test.tsx +++ b/test/unit-tests/components/views/elements/ImageView-test.tsx @@ -10,11 +10,13 @@ import React from "react"; import { mocked } from "jest-mock"; import { render, fireEvent, waitFor } from "jest-matrix-react"; import fetchMock from "fetch-mock-jest"; +import { MatrixEvent } from "matrix-js-sdk/src/matrix"; import ImageView from "../../../../../src/components/views/elements/ImageView"; import { FileDownloader } from "../../../../../src/utils/FileDownloader"; import Modal from "../../../../../src/Modal"; import ErrorDialog from "../../../../../src/components/views/dialogs/ErrorDialog"; +import { stubClient } from "../../../../test-utils"; jest.mock("../../../../../src/utils/FileDownloader"); @@ -44,6 +46,39 @@ describe("", () => { expect(fetchMock).toHaveFetched("https://example.com/image.png"); }); + it("should use event as download source if given", async () => { + stubClient(); + + const event = new MatrixEvent({ + event_id: "$eventId", + type: "m.image", + content: { + body: "fromEvent.png", + url: "mxc://test.dummy/fromEvent.png", + file_name: "filename.png", + }, + origin_server_ts: new Date(2000, 0, 1, 0, 0, 0, 0).getTime(), + }); + + fetchMock.get("http://this.is.a.url/test.dummy/fromEvent.png", "TESTFILE"); + const { getByRole } = render( + , + ); + fireEvent.click(getByRole("button", { name: "Download" })); + await waitFor(() => + expect(mocked(FileDownloader).mock.instances[0].download).toHaveBeenCalledWith({ + blob: expect.anything(), + name: "fromEvent.png", + }), + ); + expect(fetchMock).toHaveFetched("http://this.is.a.url/test.dummy/fromEvent.png"); + }); + it("should start download on Ctrl+S", async () => { fetchMock.get("https://example.com/image.png", "TESTFILE"); diff --git a/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts b/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts index 1b646498bb..ec352f28d0 100644 --- a/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts +++ b/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts @@ -92,12 +92,16 @@ describe("StopGapWidgetDriver", () => { "m.always_on_screen", "town.robin.msc3846.turn_servers", "org.matrix.msc2762.timeline:!1:example.org", + "org.matrix.msc2762.send.event:org.matrix.msc4075.call.notify", + "org.matrix.msc2762.send.event:org.matrix.msc4075.rtc.notification", "org.matrix.msc2762.send.event:org.matrix.rageshake_request", "org.matrix.msc2762.receive.event:org.matrix.rageshake_request", "org.matrix.msc2762.send.event:m.reaction", "org.matrix.msc2762.receive.event:m.reaction", "org.matrix.msc2762.send.event:m.room.redaction", "org.matrix.msc2762.receive.event:m.room.redaction", + "org.matrix.msc2762.send.event:io.element.call.reaction", + "org.matrix.msc2762.receive.event:io.element.call.reaction", "org.matrix.msc2762.receive.state_event:m.room.create", "org.matrix.msc2762.receive.state_event:m.room.name", "org.matrix.msc2762.receive.state_event:m.room.member", diff --git a/yarn.lock b/yarn.lock index 017ae1efb5..393892437a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2463,10 +2463,10 @@ emojibase "^15.3.1" emojibase-data "^15.3.1" -"@matrix-org/matrix-sdk-crypto-wasm@^15.0.0": - version "15.0.0" - resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-15.0.0.tgz#5b29ca1c62f3aface9db06d7441d0a9ba2cd3439" - integrity sha512-tzBGf/jugrOw190Na77LljZIQMTSL6SAnZaATKMlb2j1XOfc5Q+bSJTb9ZWBR7TFs0d8K9spcwRHPc4S/7CMYw== +"@matrix-org/matrix-sdk-crypto-wasm@^15.1.0": + version "15.1.0" + resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-15.1.0.tgz#653956f5f6daced55a9df3d2c1114eb2c017b528" + integrity sha512-ZsDdjn46J3+VxsDLmaSODuS+qtGZB/i3Cg9tWL1QPNjvAWzNaTHQ7glleByI2PKVBm83aklfuhGKT2MqE1ZsEA== "@matrix-org/react-sdk-module-api@^2.4.0": version "2.5.0" @@ -4543,16 +4543,16 @@ classnames "^2.5.1" vaul "^1.0.0" -"@vector-im/matrix-wysiwyg-wasm@link:../../../../Library/Caches/Yarn/v6/npm-@vector-im-matrix-wysiwyg-2.38.4-fb0001dea01010a1e3ffc7042596e2d001ce9389-integrity/node_modules/bindings/wysiwyg-wasm": +"@vector-im/matrix-wysiwyg-wasm@link:../../Library/Caches/Yarn/v6/npm-@vector-im-matrix-wysiwyg-2.39.0-a6238e517f23a2f3025d9c65445914771c63b163-integrity/node_modules/bindings/wysiwyg-wasm": version "0.0.0" uid "" -"@vector-im/matrix-wysiwyg@2.38.4": - version "2.38.4" - resolved "https://registry.yarnpkg.com/@vector-im/matrix-wysiwyg/-/matrix-wysiwyg-2.38.4.tgz#fb0001dea01010a1e3ffc7042596e2d001ce9389" - integrity sha512-X6ky+1cf33SPdEVd6iTmOKfZZ2mDJv9cz3sHtDhuclS6uitK3QE8td/pmGqBj4ek2Ia4y0mnU61LfxvMry1SMA== +"@vector-im/matrix-wysiwyg@2.39.0": + version "2.39.0" + resolved "https://registry.yarnpkg.com/@vector-im/matrix-wysiwyg/-/matrix-wysiwyg-2.39.0.tgz#a6238e517f23a2f3025d9c65445914771c63b163" + integrity sha512-OROXnzPcQWrCMoUpIrCKEC4FYU+9SsRomUgu+VbJwWtBDkCbfvLD4z6w/mgiADw3iTUpBPgmcWJoGxesFuB20Q== dependencies: - "@vector-im/matrix-wysiwyg-wasm" "link:../../Library/Caches/Yarn/v6/npm-@vector-im-matrix-wysiwyg-2.38.4-fb0001dea01010a1e3ffc7042596e2d001ce9389-integrity/node_modules/bindings/wysiwyg-wasm" + "@vector-im/matrix-wysiwyg-wasm" "link:../../../.cache/yarn/v6/npm-@vector-im-matrix-wysiwyg-2.39.0-a6238e517f23a2f3025d9c65445914771c63b163-integrity/node_modules/bindings/wysiwyg-wasm" "@vitest/expect@3.2.4": version "3.2.4" @@ -8108,10 +8108,10 @@ filelist@^1.0.4: dependencies: minimatch "^5.0.1" -filesize@10.1.6: - version "10.1.6" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-10.1.6.tgz#31194da825ac58689c0bce3948f33ce83aabd361" - integrity sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w== +filesize@11.0.2: + version "11.0.2" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-11.0.2.tgz#b7771e3836812582ad74b8a10d6eb0dc58c1ceda" + integrity sha512-s/iAeeWLk5BschUIpmdrF8RA8lhFZ/xDZgKw1Tan72oGws1/dFGB06nYEiyyssWUfjKNQTNRlrwMVjO9/hvXDw== fill-range@^7.1.1: version "7.1.1" @@ -10846,11 +10846,11 @@ matrix-events-sdk@0.0.1: integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== "matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": - version "37.11.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/f8f1bf38373a944f12a739a301c1770c7bf08265" + version "37.12.0" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/56b24c0bdc3e1c6b9778dffa5cab7959848f4e0e" dependencies: "@babel/runtime" "^7.12.5" - "@matrix-org/matrix-sdk-crypto-wasm" "^15.0.0" + "@matrix-org/matrix-sdk-crypto-wasm" "^15.1.0" another-json "^0.2.0" bs58 "^6.0.0" content-type "^1.0.4"