From 643de5f342dab643f3dc7624c00c70ad48b93d73 Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Wed, 5 Nov 2025 16:19:47 -0500 Subject: [PATCH 1/4] Delayed event management: split endpoints, no auth Use the new js-sdk client methods for calling the dedicated, unauthenticated endpoints for each of the cancel/restart/send actions for updating a delayed event. Note that these methods are compatible with homeservers that support only the original endpoint where the update action is in the request body. --- package.json | 2 +- src/stores/widgets/StopGapWidgetDriver.ts | 27 ++++++++-- test/test-utils/test-utils.ts | 4 +- .../widgets/StopGapWidgetDriver-test.ts | 49 +++++++++++++------ yarn.lock | 12 ++++- 5 files changed, 73 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index cffdcdab40c..6e780204f31 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "matrix-encrypt-attachment": "^1.0.3", "matrix-events-sdk": "0.0.1", "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", - "matrix-widget-api": "^1.10.0", + "matrix-widget-api": "^1.14.0", "memoize-one": "^6.0.0", "mime": "^4.0.4", "oidc-client-ts": "^3.0.1", diff --git a/src/stores/widgets/StopGapWidgetDriver.ts b/src/stores/widgets/StopGapWidgetDriver.ts index afd0a85cfc5..42abdc801db 100644 --- a/src/stores/widgets/StopGapWidgetDriver.ts +++ b/src/stores/widgets/StopGapWidgetDriver.ts @@ -26,7 +26,6 @@ import { type IWidgetApiErrorResponseDataDetails, type ISearchUserDirectoryResult, type IGetMediaConfigResult, - type UpdateDelayedEventAction, } from "matrix-widget-api"; import { ClientEvent, @@ -425,12 +424,34 @@ export class StopGapWidgetDriver extends WidgetDriver { /** * @experimental Part of MSC4140 & MSC4157 */ - public async updateDelayedEvent(delayId: string, action: UpdateDelayedEventAction): Promise { + public async cancelScheduledDelayedEvent(delayId: string): Promise { const client = MatrixClientPeg.get(); if (!client) throw new Error("Not in a room or not attached to a client"); - await client._unstable_updateDelayedEvent(delayId, action); + await client._unstable_cancelScheduledDelayedEvent(delayId); + } + + /** + * @experimental Part of MSC4140 & MSC4157 + */ + public async restartScheduledDelayedEvent(delayId: string): Promise { + const client = MatrixClientPeg.get(); + + if (!client) throw new Error("Not in a room or not attached to a client"); + + await client._unstable_restartScheduledDelayedEvent(delayId); + } + + /** + * @experimental Part of MSC4140 & MSC4157 + */ + public async sendScheduledDelayedEvent(delayId: string): Promise { + const client = MatrixClientPeg.get(); + + if (!client) throw new Error("Not in a room or not attached to a client"); + + await client._unstable_sendScheduledDelayedEvent(delayId); } /** diff --git a/test/test-utils/test-utils.ts b/test/test-utils/test-utils.ts index 8f70d089dd5..a0fa715bad0 100644 --- a/test/test-utils/test-utils.ts +++ b/test/test-utils/test-utils.ts @@ -276,7 +276,9 @@ export function createTestClient(): MatrixClient { _unstable_sendDelayedEvent: jest.fn(), _unstable_sendDelayedStateEvent: jest.fn(), - _unstable_updateDelayedEvent: jest.fn(), + _unstable_cancelScheduledDelayedEvent: jest.fn(), + _unstable_restartScheduledDelayedEvent: jest.fn(), + _unstable_sendScheduledDelayedEvent: jest.fn(), searchUserDirectory: jest.fn().mockResolvedValue({ limited: false, results: [] }), setDeviceVerified: jest.fn(), diff --git a/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts b/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts index d8d115411d4..f84cf9d3257 100644 --- a/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts +++ b/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts @@ -27,7 +27,6 @@ import { SimpleObservable, OpenIDRequestState, type IOpenIDUpdate, - UpdateDelayedEventAction, } from "matrix-widget-api"; import { type ApprovalOpts, @@ -554,22 +553,44 @@ describe("StopGapWidgetDriver", () => { driver = mkDefaultDriver(); }); - it("updates delayed events", async () => { - client._unstable_updateDelayedEvent.mockResolvedValue({}); - for (const action of [ - UpdateDelayedEventAction.Cancel, - UpdateDelayedEventAction.Restart, - UpdateDelayedEventAction.Send, - ]) { - await expect(driver.updateDelayedEvent("id", action)).resolves.toBeUndefined(); - expect(client._unstable_updateDelayedEvent).toHaveBeenCalledWith("id", action); - } + it("can cancel scheduled delayed events", async () => { + client._unstable_cancelScheduledDelayedEvent.mockResolvedValue({}); + await expect(driver.cancelScheduledDelayedEvent("id")).resolves.toBeUndefined(); + expect(client._unstable_cancelScheduledDelayedEvent).toHaveBeenCalledWith("id"); + }); + + it("can restart scheduled delayed events", async () => { + client._unstable_restartScheduledDelayedEvent.mockResolvedValue({}); + await expect(driver.restartScheduledDelayedEvent("id")).resolves.toBeUndefined(); + expect(client._unstable_restartScheduledDelayedEvent).toHaveBeenCalledWith("id"); }); - it("fails to update delayed events", async () => { + it("can send scheduled delayed events", async () => { + client._unstable_sendScheduledDelayedEvent.mockResolvedValue({}); + await expect(driver.sendScheduledDelayedEvent("id")).resolves.toBeUndefined(); + expect(client._unstable_sendScheduledDelayedEvent).toHaveBeenCalledWith("id"); + }); + + it("fails to cancel scheduled delayed events", async () => { + const errorMessage = "Cannot cancel this delayed event"; + client._unstable_cancelScheduledDelayedEvent.mockRejectedValue(new Error(errorMessage)); + await expect(driver.cancelScheduledDelayedEvent("id")).rejects.toThrow( + errorMessage, + ); + }); + + it("fails to restart scheduled delayed events", async () => { const errorMessage = "Cannot restart this delayed event"; - client._unstable_updateDelayedEvent.mockRejectedValue(new Error(errorMessage)); - await expect(driver.updateDelayedEvent("id", UpdateDelayedEventAction.Restart)).rejects.toThrow( + client._unstable_restartScheduledDelayedEvent.mockRejectedValue(new Error(errorMessage)); + await expect(driver.restartScheduledDelayedEvent("id")).rejects.toThrow( + errorMessage, + ); + }); + + it("fails to send scheduled delayed events", async () => { + const errorMessage = "Cannot send this delayed event"; + client._unstable_sendScheduledDelayedEvent.mockRejectedValue(new Error(errorMessage)); + await expect(driver.sendScheduledDelayedEvent("id")).rejects.toThrow( errorMessage, ); }); diff --git a/yarn.lock b/yarn.lock index 20e11c7b121..4cb8ed6b354 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4089,7 +4089,7 @@ classnames "^2.5.1" vaul "^1.0.0" -"@vector-im/matrix-wysiwyg-wasm@link:../../Library/Caches/Yarn/v6/npm-@vector-im-matrix-wysiwyg-2.40.0-53c9ca5ea907d91e4515da64f20a82e5586b882c-integrity/node_modules/bindings/wysiwyg-wasm": +"@vector-im/matrix-wysiwyg-wasm@link:../../.cache/yarn/v6/npm-@vector-im-matrix-wysiwyg-2.40.0-53c9ca5ea907d91e4515da64f20a82e5586b882c-integrity/node_modules/bindings/wysiwyg-wasm": version "0.0.0" uid "" @@ -4098,7 +4098,7 @@ resolved "https://registry.yarnpkg.com/@vector-im/matrix-wysiwyg/-/matrix-wysiwyg-2.40.0.tgz#53c9ca5ea907d91e4515da64f20a82e5586b882c" integrity sha512-8LRFLs5PEKYs4lOL7aJ4lL/hGCrvEvOYkCR3JggXYXDVMtX4LmfdlKYucSAe98pCmqAAbLRvlRcR1bTOYvM8ug== dependencies: - "@vector-im/matrix-wysiwyg-wasm" "link:../../../.cache/yarn/v6/npm-@vector-im-matrix-wysiwyg-2.40.0-53c9ca5ea907d91e4515da64f20a82e5586b882c-integrity/node_modules/bindings/wysiwyg-wasm" + "@vector-im/matrix-wysiwyg-wasm" "link:../../.cache/yarn/v6/npm-@vector-im-matrix-wysiwyg-2.40.0-53c9ca5ea907d91e4515da64f20a82e5586b882c-integrity/node_modules/bindings/wysiwyg-wasm" "@vitest/expect@3.2.4": version "3.2.4" @@ -9716,6 +9716,14 @@ matrix-widget-api@^1.10.0: "@types/events" "^3.0.0" events "^3.2.0" +matrix-widget-api@^1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/matrix-widget-api/-/matrix-widget-api-1.14.0.tgz#aa90c40ace27d3165299f7dbc760a53001ce1446" + integrity sha512-DDvZGOQhI/rilPWg5VlLN7pHIsPt0Jt14lsuHDP+KU+fmpAQNITJ6aIld1ZoXWsrVGv2PS3x6K/MHtfruIOQJQ== + dependencies: + "@types/events" "^3.0.0" + events "^3.2.0" + mdn-data@2.0.28: version "2.0.28" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.28.tgz#5ec48e7bef120654539069e1ae4ddc81ca490eba" From a69aa762005b3ada0b52b3d8809ab7be74b8ff77 Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Wed, 5 Nov 2025 16:32:54 -0500 Subject: [PATCH 2/4] REPLACEME: pull in dependant js-sdk branch see matrix-org/matrix-js-sdk#5066 --- package.json | 2 +- yarn.lock | 14 +++----------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 6e780204f31..413f3973a79 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "maplibre-gl": "^5.0.0", "matrix-encrypt-attachment": "^1.0.3", "matrix-events-sdk": "0.0.1", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#d41011bd4ac53dc85761af1c3ef2f57e788a9b4d", "matrix-widget-api": "^1.14.0", "memoize-one": "^6.0.0", "mime": "^4.0.4", diff --git a/yarn.lock b/yarn.lock index 4cb8ed6b354..f3672c866d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9678,9 +9678,9 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#d41011bd4ac53dc85761af1c3ef2f57e788a9b4d": version "39.1.2" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/b489bb15cf3f5de8024a3e31ccb36cf294f82887" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/d41011bd4ac53dc85761af1c3ef2f57e788a9b4d" dependencies: "@babel/runtime" "^7.12.5" "@matrix-org/matrix-sdk-crypto-wasm" "^15.3.0" @@ -9690,7 +9690,7 @@ matrix-events-sdk@0.0.1: jwt-decode "^4.0.0" loglevel "^1.9.2" matrix-events-sdk "0.0.1" - matrix-widget-api "^1.10.0" + matrix-widget-api "^1.14.0" oidc-client-ts "^3.0.1" p-retry "7" sdp-transform "^3.0.0" @@ -9708,14 +9708,6 @@ matrix-web-i18n@^3.2.1, matrix-web-i18n@^3.4.0: minimist "^1.2.8" walk "^2.3.15" -matrix-widget-api@^1.10.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/matrix-widget-api/-/matrix-widget-api-1.13.1.tgz#5b1caeed2fc58148bcd2984e0546d2d06a1713ad" - integrity sha512-mkOHUVzaN018TCbObfGOSaMW2GoUxOfcxNNlTVx5/HeMk3OSQPQM0C9oEME5Liiv/dBUoSrEB64V8wF7e/gb1w== - dependencies: - "@types/events" "^3.0.0" - events "^3.2.0" - matrix-widget-api@^1.14.0: version "1.14.0" resolved "https://registry.yarnpkg.com/matrix-widget-api/-/matrix-widget-api-1.14.0.tgz#aa90c40ace27d3165299f7dbc760a53001ce1446" From 43c6181a7e9d2054c34871e5588fd5ee7868c23d Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Thu, 6 Nov 2025 11:05:51 -0500 Subject: [PATCH 3/4] Format with Prettier --- .../stores/widgets/StopGapWidgetDriver-test.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts b/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts index f84cf9d3257..9b6411b134a 100644 --- a/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts +++ b/test/unit-tests/stores/widgets/StopGapWidgetDriver-test.ts @@ -574,25 +574,19 @@ describe("StopGapWidgetDriver", () => { it("fails to cancel scheduled delayed events", async () => { const errorMessage = "Cannot cancel this delayed event"; client._unstable_cancelScheduledDelayedEvent.mockRejectedValue(new Error(errorMessage)); - await expect(driver.cancelScheduledDelayedEvent("id")).rejects.toThrow( - errorMessage, - ); + await expect(driver.cancelScheduledDelayedEvent("id")).rejects.toThrow(errorMessage); }); it("fails to restart scheduled delayed events", async () => { const errorMessage = "Cannot restart this delayed event"; client._unstable_restartScheduledDelayedEvent.mockRejectedValue(new Error(errorMessage)); - await expect(driver.restartScheduledDelayedEvent("id")).rejects.toThrow( - errorMessage, - ); + await expect(driver.restartScheduledDelayedEvent("id")).rejects.toThrow(errorMessage); }); it("fails to send scheduled delayed events", async () => { const errorMessage = "Cannot send this delayed event"; client._unstable_sendScheduledDelayedEvent.mockRejectedValue(new Error(errorMessage)); - await expect(driver.sendScheduledDelayedEvent("id")).rejects.toThrow( - errorMessage, - ); + await expect(driver.sendScheduledDelayedEvent("id")).rejects.toThrow(errorMessage); }); }); From ec446642e0ce619919d39f67907a530616afbc02 Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Tue, 11 Nov 2025 08:10:44 -0500 Subject: [PATCH 4/4] Update matrix-js-sdk --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 413f3973a79..6e780204f31 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "maplibre-gl": "^5.0.0", "matrix-encrypt-attachment": "^1.0.3", "matrix-events-sdk": "0.0.1", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#d41011bd4ac53dc85761af1c3ef2f57e788a9b4d", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", "matrix-widget-api": "^1.14.0", "memoize-one": "^6.0.0", "mime": "^4.0.4", diff --git a/yarn.lock b/yarn.lock index f3672c866d9..25fcbca2b75 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9678,9 +9678,9 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#d41011bd4ac53dc85761af1c3ef2f57e788a9b4d": +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": version "39.1.2" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/d41011bd4ac53dc85761af1c3ef2f57e788a9b4d" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/df88edfda0aa00ad1d574e367f024db9a927e96b" dependencies: "@babel/runtime" "^7.12.5" "@matrix-org/matrix-sdk-crypto-wasm" "^15.3.0"