From 7231c681da35944d1800a510db15090908c0ab4d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 30 Sep 2022 14:46:19 +0100 Subject: [PATCH 01/38] Make `useAuthorizationHeader` default on --- src/http-api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/http-api.ts b/src/http-api.ts index 1a7376b00a0..90c46e46bbe 100644 --- a/src/http-api.ts +++ b/src/http-api.ts @@ -214,7 +214,7 @@ export class MatrixHttpApi { ) { utils.checkObjectHasKeys(opts, ["baseUrl", "request", "prefix"]); opts.onlyData = !!opts.onlyData; - opts.useAuthorizationHeader = !!opts.useAuthorizationHeader; + opts.useAuthorizationHeader = opts.useAuthorizationHeader ?? true; } /** From e36d41a4fbea3c5e39d4288d7ffce64e022dcdf2 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 30 Sep 2022 14:56:06 +0100 Subject: [PATCH 02/38] Consolidate API prefixes into enums with method --- src/client.ts | 70 +++++++++++++++++------------------ src/crypto/EncryptionSetup.ts | 6 +-- src/http-api.ts | 43 +++------------------ src/http-api/index.ts | 24 ++++++++++++ src/http-api/prefix.ts | 53 ++++++++++++++++++++++++++ 5 files changed, 118 insertions(+), 78 deletions(-) create mode 100644 src/http-api/index.ts create mode 100644 src/http-api/prefix.ts diff --git a/src/client.ts b/src/client.ts index e0e05112627..253f5fe7640 100644 --- a/src/client.ts +++ b/src/client.ts @@ -57,14 +57,11 @@ import { MatrixError, MatrixHttpApi, Method, - PREFIX_IDENTITY_V2, - PREFIX_MEDIA_R0, - PREFIX_R0, - PREFIX_UNSTABLE, - PREFIX_V1, - PREFIX_V3, retryNetworkOperation, UploadContentResponseType, + ClientPrefix, + MediaPrefix, + IdentityPrefix, } from "./http-api"; import { Crypto, @@ -1001,7 +998,7 @@ export class MatrixClient extends TypedEventEmitter( undefined, Method.Get, "/room_keys/version", undefined, undefined, - { prefix: PREFIX_UNSTABLE }, + { prefix: ClientPrefix.Unstable }, ); } catch (e) { if (e.errcode === 'M_NOT_FOUND') { @@ -2849,7 +2846,7 @@ export class MatrixClient extends TypedEventEmitter( undefined, Method.Post, "/room_keys/version", undefined, data, - { prefix: PREFIX_UNSTABLE }, + { prefix: ClientPrefix.Unstable }, ); // We could assume everything's okay and enable directly, but this ensures @@ -2881,7 +2878,7 @@ export class MatrixClient extends TypedEventEmitter( undefined, Method.Get, path.path, path.queryData, undefined, - { prefix: PREFIX_UNSTABLE }, + { prefix: ClientPrefix.Unstable }, ); if ((res as IRoomsKeysResponse).rooms) { @@ -3291,7 +3288,7 @@ export class MatrixClient extends TypedEventEmitter { return this.http.authedRequest( callback, Method.Get, "/config", undefined, undefined, { - prefix: PREFIX_MEDIA_R0, + prefix: MediaPrefix.R0, }, ); } @@ -4760,7 +4757,7 @@ export class MatrixClient extends TypedEventEmitter( undefined, Method.Get, path, undefined, undefined, - { prefix: PREFIX_UNSTABLE }, + { prefix: ClientPrefix.Unstable }, ); return res.joined; } @@ -6888,7 +6885,7 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/rooms/$roomId/aliases", { $roomId: roomId }); - const prefix = PREFIX_V3; + const prefix = ClientPrefix.V3; return this.http.authedRequest(undefined, Method.Get, path, undefined, undefined, { prefix }); } @@ -7970,7 +7967,7 @@ export class MatrixClient extends TypedEventEmitter { const path = "/account/3pid/add"; - const prefix = await this.isVersionSupported("r0.6.0") ? PREFIX_R0 : PREFIX_UNSTABLE; + const prefix = await this.isVersionSupported("r0.6.0") ? ClientPrefix.R0 : ClientPrefix.Unstable; return this.http.authedRequest(undefined, Method.Post, path, undefined, data, { prefix }); } @@ -7990,8 +7987,7 @@ export class MatrixClient extends TypedEventEmitter { const path = "/account/3pid/bind"; - const prefix = await this.isVersionSupported("r0.6.0") ? - PREFIX_R0 : PREFIX_UNSTABLE; + const prefix = await this.isVersionSupported("r0.6.0") ? ClientPrefix.R0 : ClientPrefix.Unstable; return this.http.authedRequest( undefined, Method.Post, path, undefined, data, { prefix }, ); @@ -8019,7 +8015,7 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types return this.http.idServerRequest( undefined, Method.Get, "/hash_details", - null, PREFIX_IDENTITY_V2, identityAccessToken, + null, IdentityPrefix.V2, identityAccessToken, ); } @@ -8750,7 +8746,7 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types return this.http.idServerRequest( undefined, Method.Get, "/account", - undefined, PREFIX_IDENTITY_V2, identityAccessToken, + undefined, IdentityPrefix.V2, identityAccessToken, ); } @@ -9035,7 +9031,7 @@ export class MatrixClient extends TypedEventEmitter(undefined, Method.Get, path, queryParams, undefined, { - prefix: PREFIX_V1, + prefix: ClientPrefix.V1, }).catch(e => { if (e.errcode === "M_UNRECOGNIZED") { // fall back to the prefixed hierarchy API. diff --git a/src/crypto/EncryptionSetup.ts b/src/crypto/EncryptionSetup.ts index 61ba34eaf99..40e571142a9 100644 --- a/src/crypto/EncryptionSetup.ts +++ b/src/crypto/EncryptionSetup.ts @@ -18,7 +18,7 @@ import { logger } from "../logger"; import { MatrixEvent } from "../models/event"; import { createCryptoStoreCacheCallbacks, ICacheCallbacks } from "./CrossSigning"; import { IndexedDBCryptoStore } from './store/indexeddb-crypto-store'; -import { Method, PREFIX_UNSTABLE } from "../http-api"; +import { Method, ClientPrefix } from "../http-api"; import { Crypto, IBootstrapCrossSigningOpts } from "./index"; import { ClientEvent, @@ -246,14 +246,14 @@ export class EncryptionSetupOperation { algorithm: this.keyBackupInfo.algorithm, auth_data: this.keyBackupInfo.auth_data, }, - { prefix: PREFIX_UNSTABLE }, + { prefix: ClientPrefix.Unstable }, ); } else { // add new key backup await baseApis.http.authedRequest( undefined, Method.Post, "/room_keys/version", undefined, this.keyBackupInfo, - { prefix: PREFIX_UNSTABLE }, + { prefix: ClientPrefix.Unstable }, ); } } diff --git a/src/http-api.ts b/src/http-api.ts index 90c46e46bbe..291b6917f5a 100644 --- a/src/http-api.ts +++ b/src/http-api.ts @@ -34,6 +34,7 @@ import { IDeferred, sleep } from "./utils"; import { Callback } from "./client"; import * as utils from "./utils"; import { logger } from './logger'; +import { MediaPrefix } from "./http-api/prefix"; import { TypedEventEmitter } from "./models/typed-event-emitter"; /* @@ -42,42 +43,6 @@ TODO: - Identity server: linkEmail, authEmail, bindEmail, lookup3pid */ -/** - * A constant representing the URI path for release 0 of the Client-Server HTTP API. - */ -export const PREFIX_R0 = "/_matrix/client/r0"; - -/** - * A constant representing the URI path for the legacy release v1 of the Client-Server HTTP API. - */ -export const PREFIX_V1 = "/_matrix/client/v1"; - -/** - * A constant representing the URI path for Client-Server API endpoints versioned at v3. - */ -export const PREFIX_V3 = "/_matrix/client/v3"; - -/** - * A constant representing the URI path for as-yet unspecified Client-Server HTTP APIs. - */ -export const PREFIX_UNSTABLE = "/_matrix/client/unstable"; - -/** - * URI path for v1 of the the identity API - * @deprecated Use v2. - */ -export const PREFIX_IDENTITY_V1 = "/_matrix/identity/api/v1"; - -/** - * URI path for the v2 identity API - */ -export const PREFIX_IDENTITY_V2 = "/_matrix/identity/v2"; - -/** - * URI path for the media repo API - */ -export const PREFIX_MEDIA_R0 = "/_matrix/media/r0"; - type RequestProps = "method" | "withCredentials" | "json" @@ -168,6 +133,8 @@ export enum Method { Delete = "DELETE", } +export * from "./http-api/prefix"; + export type FileType = Document | XMLHttpRequestBodyInit; export enum HttpApiEvent { @@ -429,7 +396,7 @@ export class MatrixHttpApi { }); } }); - let url = this.opts.baseUrl + "/_matrix/media/r0/upload"; + let url = this.opts.baseUrl + MediaPrefix.R0 + "/upload"; const queryArgs = []; @@ -474,7 +441,7 @@ export class MatrixHttpApi { promise = this.authedRequest>( opts.callback, Method.Post, "/upload", queryParams, body, { - prefix: "/_matrix/media/r0", + prefix: MediaPrefix.R0, headers, json: false, bodyParser, diff --git a/src/http-api/index.ts b/src/http-api/index.ts new file mode 100644 index 00000000000..1027c76934c --- /dev/null +++ b/src/http-api/index.ts @@ -0,0 +1,24 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export * from "./prefix"; + +export enum Method { + Get = "GET", + Put = "PUT", + Post = "POST", + Delete = "DELETE", +} diff --git a/src/http-api/prefix.ts b/src/http-api/prefix.ts new file mode 100644 index 00000000000..8111bc3557a --- /dev/null +++ b/src/http-api/prefix.ts @@ -0,0 +1,53 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export enum ClientPrefix { + /** + * A constant representing the URI path for release 0 of the Client-Server HTTP API. + */ + R0 = "/_matrix/client/r0", + /** + * A constant representing the URI path for the legacy release v1 of the Client-Server HTTP API. + */ + V1 = "/_matrix/client/v1", + /** + * A constant representing the URI path for Client-Server API endpoints versioned at v3. + */ + V3 = "/_matrix/client/v3", + /** + * A constant representing the URI path for as-yet unspecified Client-Server HTTP APIs. + */ + Unstable = "/_matrix/client/unstable", +} + +export enum IdentityPrefix { + /** + * URI path for v1 of the identity API + * @deprecated Use v2. + */ + V1 = "/_matrix/identity/api/v1", + /** + * URI path for the v2 identity API + */ + V2 = "/_matrix/identity/api/v2", +} + +export enum MediaPrefix { + /** + * URI path for the media repo API + */ + R0 = "/_matrix/media/r0", +} From 2ff24afbb5eea142d7239a666ef12ba90de21810 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 3 Oct 2022 11:39:09 +0100 Subject: [PATCH 03/38] Remove deprecated callbacks support --- spec/unit/crypto/backup.spec.ts | 8 +- spec/unit/crypto/cross-signing.spec.ts | 2 +- spec/unit/crypto/secrets.spec.ts | 9 +- spec/unit/matrix-client.spec.ts | 36 +- src/@types/requests.ts | 2 - src/client.ts | 863 ++++++++----------------- src/crypto/EncryptionSetup.ts | 4 +- src/crypto/dehydration.ts | 2 - src/http-api.ts | 59 +- src/sync.ts | 9 +- 10 files changed, 301 insertions(+), 693 deletions(-) diff --git a/spec/unit/crypto/backup.spec.ts b/spec/unit/crypto/backup.spec.ts index acec47fcee2..e20f3679d51 100644 --- a/spec/unit/crypto/backup.spec.ts +++ b/spec/unit/crypto/backup.spec.ts @@ -299,7 +299,7 @@ describe("MegolmBackup", function() { let numCalls = 0; return new Promise((resolve, reject) => { client.http.authedRequest = function( - callback, method, path, queryParams, data, opts, + method, path, queryParams, data, opts, ) { ++numCalls; expect(numCalls).toBeLessThanOrEqual(1); @@ -382,7 +382,7 @@ describe("MegolmBackup", function() { let numCalls = 0; return new Promise((resolve, reject) => { client.http.authedRequest = function( - callback, method, path, queryParams, data, opts, + method, path, queryParams, data, opts, ) { ++numCalls; expect(numCalls).toBeLessThanOrEqual(1); @@ -439,7 +439,7 @@ describe("MegolmBackup", function() { new Promise((resolve, reject) => { let backupInfo; client.http.authedRequest = function( - callback, method, path, queryParams, data, opts, + method, path, queryParams, data, opts, ) { ++numCalls; expect(numCalls).toBeLessThanOrEqual(2); @@ -543,7 +543,7 @@ describe("MegolmBackup", function() { await new Promise((resolve, reject) => { client.http.authedRequest = function( - callback, method, path, queryParams, data, opts, + method, path, queryParams, data, opts, ) { ++numCalls; expect(numCalls).toBeLessThanOrEqual(2); diff --git a/spec/unit/crypto/cross-signing.spec.ts b/spec/unit/crypto/cross-signing.spec.ts index 30c1bf82ce3..bfa7625cbe8 100644 --- a/spec/unit/crypto/cross-signing.spec.ts +++ b/spec/unit/crypto/cross-signing.spec.ts @@ -141,7 +141,7 @@ describe("Cross Signing", function() { }; alice.uploadKeySignatures = async () => ({ failures: {} }); alice.setAccountData = async () => ({}); - alice.getAccountDataFromServer = async (): Promise => ({} as T); + alice.getAccountDataFromServer = async (): Promise => ({} as T); const authUploadDeviceSigningKeys = async func => await func({}); // Try bootstrap, expecting `authUploadDeviceSigningKeys` to pass diff --git a/spec/unit/crypto/secrets.spec.ts b/spec/unit/crypto/secrets.spec.ts index d6ae8c3a363..7692292fff2 100644 --- a/spec/unit/crypto/secrets.spec.ts +++ b/spec/unit/crypto/secrets.spec.ts @@ -109,16 +109,13 @@ describe("Secrets", function() { const secretStorage = alice.crypto.secretStorage; jest.spyOn(alice, 'setAccountData').mockImplementation( - async function(eventType, contents, callback) { + async function(eventType, contents) { alice.store.storeAccountDataEvents([ new MatrixEvent({ type: eventType, content: contents, }), ]); - if (callback) { - callback(undefined, undefined); - } return {}; }); @@ -192,7 +189,7 @@ describe("Secrets", function() { }, }, ); - alice.setAccountData = async function(eventType, contents, callback) { + alice.setAccountData = async function(eventType, contents) { alice.store.storeAccountDataEvents([ new MatrixEvent({ type: eventType, @@ -332,7 +329,7 @@ describe("Secrets", function() { ); bob.uploadDeviceSigningKeys = async () => ({}); bob.uploadKeySignatures = jest.fn().mockResolvedValue(undefined); - bob.setAccountData = async function(eventType, contents, callback) { + bob.setAccountData = async function(eventType, contents) { const event = new MatrixEvent({ type: eventType, content: contents, diff --git a/spec/unit/matrix-client.spec.ts b/spec/unit/matrix-client.spec.ts index 2b8faf5065a..f854d600835 100644 --- a/spec/unit/matrix-client.spec.ts +++ b/spec/unit/matrix-client.spec.ts @@ -103,7 +103,7 @@ describe("MatrixClient", function() { ]; let acceptKeepalives: boolean; let pendingLookup = null; - function httpReq(cb, method, path, qp, data, prefix) { + function httpReq(method, path, qp, data, prefix) { if (path === KEEP_ALIVE_PATH && acceptKeepalives) { return Promise.resolve({ unstable_features: { @@ -1153,8 +1153,7 @@ describe("MatrixClient", function() { // event type combined const expectedEventType = M_BEACON_INFO.name; - const [callback, method, path, queryParams, requestContent] = client.http.authedRequest.mock.calls[0]; - expect(callback).toBeFalsy(); + const [method, path, queryParams, requestContent] = client.http.authedRequest.mock.calls[0]; expect(method).toBe('PUT'); expect(path).toEqual( `/rooms/${encodeURIComponent(roomId)}/state/` + @@ -1168,7 +1167,7 @@ describe("MatrixClient", function() { await client.unstable_setLiveBeacon(roomId, content); // event type combined - const [, , path, , requestContent] = client.http.authedRequest.mock.calls[0]; + const [, path, , requestContent] = client.http.authedRequest.mock.calls[0]; expect(path).toEqual( `/rooms/${encodeURIComponent(roomId)}/state/` + `${encodeURIComponent(M_BEACON_INFO.name)}/${encodeURIComponent(userId)}`, @@ -1229,7 +1228,7 @@ describe("MatrixClient", function() { it("is called with plain text topic and callback and sends state event", async () => { const sendStateEvent = createSendStateEventMock("pizza"); client.sendStateEvent = sendStateEvent; - await client.setRoomTopic(roomId, "pizza", () => {}); + await client.setRoomTopic(roomId, "pizza"); expect(sendStateEvent).toHaveBeenCalledTimes(1); }); @@ -1244,15 +1243,9 @@ describe("MatrixClient", function() { describe("setPassword", () => { const auth = { session: 'abcdef', type: 'foo' }; const newPassword = 'newpassword'; - const callback = () => {}; - - const passwordTest = (expectedRequestContent: any, expectedCallback?: Function) => { - const [callback, method, path, queryParams, requestContent] = client.http.authedRequest.mock.calls[0]; - if (expectedCallback) { - expect(callback).toBe(expectedCallback); - } else { - expect(callback).toBeFalsy(); - } + + const passwordTest = (expectedRequestContent: any) => { + const [method, path, queryParams, requestContent] = client.http.authedRequest.mock.calls[0]; expect(method).toBe('POST'); expect(path).toEqual('/account/password'); expect(queryParams).toBeFalsy(); @@ -1269,8 +1262,8 @@ describe("MatrixClient", function() { }); it("no logout_devices specified + callback", async () => { - await client.setPassword(auth, newPassword, callback); - passwordTest({ auth, new_password: newPassword }, callback); + await client.setPassword(auth, newPassword); + passwordTest({ auth, new_password: newPassword }); }); it("overload logoutDevices=true", async () => { @@ -1279,8 +1272,8 @@ describe("MatrixClient", function() { }); it("overload logoutDevices=true + callback", async () => { - await client.setPassword(auth, newPassword, true, callback); - passwordTest({ auth, new_password: newPassword, logout_devices: true }, callback); + await client.setPassword(auth, newPassword, true); + passwordTest({ auth, new_password: newPassword, logout_devices: true }); }); it("overload logoutDevices=false", async () => { @@ -1289,8 +1282,8 @@ describe("MatrixClient", function() { }); it("overload logoutDevices=false + callback", async () => { - await client.setPassword(auth, newPassword, false, callback); - passwordTest({ auth, new_password: newPassword, logout_devices: false }, callback); + await client.setPassword(auth, newPassword, false); + passwordTest({ auth, new_password: newPassword, logout_devices: false }); }); }); @@ -1305,8 +1298,7 @@ describe("MatrixClient", function() { const result = await client.getLocalAliases(roomId); // Current version of the endpoint we support is v3 - const [callback, method, path, queryParams, data, opts] = client.http.authedRequest.mock.calls[0]; - expect(callback).toBeFalsy(); + const [method, path, queryParams, data, opts] = client.http.authedRequest.mock.calls[0]; expect(data).toBeFalsy(); expect(method).toBe('GET'); expect(path).toEqual(`/rooms/${encodeURIComponent(roomId)}/aliases`); diff --git a/src/@types/requests.ts b/src/@types/requests.ts index 9d0472cee1a..15e2faa0c15 100644 --- a/src/@types/requests.ts +++ b/src/@types/requests.ts @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { Callback } from "../client"; import { IContent, IEvent } from "../models/event"; import { Preset, Visibility } from "./partials"; import { IEventWithRoomId, SearchKey } from "./search"; @@ -125,7 +124,6 @@ export interface IUploadOpts { type?: string; rawResponse?: boolean; onlyContentUri?: boolean; - callback?: Callback; progressHandler?: (state: {loaded: number, total: number}) => void; } diff --git a/src/client.ts b/src/client.ts index 253f5fe7640..f68e7c98313 100644 --- a/src/client.ts +++ b/src/client.ts @@ -204,7 +204,6 @@ import { LocalNotificationSettings } from "./@types/local_notifications"; export type Store = IStore; -export type Callback = (err: Error | any | null, data?: T) => void; export type ResetTimelineCallback = (roomId: string) => boolean; const SCROLLBACK_DELAY_MS = 3000; @@ -1321,7 +1320,6 @@ export class MatrixClient extends TypedEventEmitter( - undefined, Method.Post, "/dehydrated_device/claim", undefined, @@ -1362,7 +1360,6 @@ export class MatrixClient extends TypedEventEmitter { try { return await this.http.authedRequest( - undefined, Method.Get, "/dehydrated_device", undefined, undefined, @@ -1655,9 +1652,7 @@ export class MatrixClient extends TypedEventEmitter { + return this.http.authedRequest(Method.Get, "/capabilities").catch((e: Error): void => { // We swallow errors because we need a default object anyhow logger.error(e); }).then((r: { capabilities?: ICapabilities } = {}) => { @@ -2689,7 +2684,7 @@ export class MatrixClient extends TypedEventEmitter( - undefined, Method.Get, "/room_keys/version", undefined, undefined, + Method.Get, "/room_keys/version", undefined, undefined, { prefix: ClientPrefix.Unstable }, ); } catch (e) { @@ -2845,7 +2840,7 @@ export class MatrixClient extends TypedEventEmitter( - undefined, Method.Post, "/room_keys/version", undefined, data, + Method.Post, "/room_keys/version", undefined, data, { prefix: ClientPrefix.Unstable }, ); @@ -2877,19 +2872,15 @@ export class MatrixClient extends TypedEventEmitter; - public sendKeyBackup(roomId: string, sessionId: undefined, version: string, data: IKeyBackup): Promise; - public sendKeyBackup(roomId: string, sessionId: string, version: string, data: IKeyBackup): Promise; + public sendKeyBackup( + roomId: undefined, + sessionId: undefined, + version: string | undefined, + data: IKeyBackup, + ): Promise; public sendKeyBackup( roomId: string, + sessionId: undefined, + version: string | undefined, + data: IKeyBackup, + ): Promise; + public sendKeyBackup( + roomId: string, + sessionId: string, + version: string | undefined, + data: IKeyBackup, + ): Promise; + public sendKeyBackup( + roomId: string | undefined, sessionId: string | undefined, version: string | undefined, data: IKeyBackup, @@ -2931,7 +2937,7 @@ export class MatrixClient extends TypedEventEmitter( - undefined, Method.Get, path.path, path.queryData, undefined, + Method.Get, path.path, path.queryData, undefined, { prefix: ClientPrefix.Unstable }, ); @@ -3273,21 +3279,17 @@ export class MatrixClient extends TypedEventEmitter; - public deleteKeysFromBackup(roomId: string, sessionId: undefined, version: string): Promise; - public deleteKeysFromBackup(roomId: string, sessionId: string, version: string): Promise; - public deleteKeysFromBackup( - roomId: string | undefined, - sessionId: string | undefined, - version: string, - ): Promise { + public deleteKeysFromBackup(roomId: undefined, sessionId: undefined, version?: string): Promise; + public deleteKeysFromBackup(roomId: string, sessionId: undefined, version?: string): Promise; + public deleteKeysFromBackup(roomId: string, sessionId: string, version?: string): Promise; + public deleteKeysFromBackup(roomId?: string, sessionId?: string, version?: string): Promise { if (!this.crypto) { throw new Error("End-to-end encryption disabled"); } const path = this.makeKeyBackupPath(roomId, sessionId, version); return this.http.authedRequest( - undefined, Method.Delete, path.path, path.queryData, undefined, + Method.Delete, path.path, path.queryData, undefined, { prefix: ClientPrefix.Unstable }, ); } @@ -3328,12 +3330,11 @@ export class MatrixClient extends TypedEventEmitter { + public getMediaConfig(): Promise { return this.http.authedRequest( - callback, Method.Get, "/config", undefined, undefined, { + Method.Get, "/config", undefined, undefined, { prefix: MediaPrefix.R0, }, ); @@ -3416,22 +3417,17 @@ export class MatrixClient extends TypedEventEmitter { + public setAccountData(eventType: EventType | string, content: IContent): Promise<{}> { const path = utils.encodeUri("/user/$userId/account_data/$type", { $userId: this.credentials.userId, $type: eventType, }); - const promise = retryNetworkOperation(5, () => { - return this.http.authedRequest(undefined, Method.Put, path, undefined, content); + return retryNetworkOperation(5, () => { + return this.http.authedRequest(Method.Put, path, undefined, content); }); - if (callback) { - promise.then(result => callback(null, result), callback); - } - return promise; } /** @@ -3448,11 +3444,10 @@ export class MatrixClient extends TypedEventEmitter(eventType: string): Promise { + public async getAccountDataFromServer(eventType: string): Promise { if (this.isInitialSyncComplete()) { const event = this.store.getAccountData(eventType); if (!event) { @@ -3460,14 +3455,14 @@ export class MatrixClient extends TypedEventEmitter(); } const path = utils.encodeUri("/user/$userId/account_data/$type", { $userId: this.credentials.userId, $type: eventType, }); try { - return await this.http.authedRequest(undefined, Method.Get, path); + return await this.http.authedRequest(Method.Get, path); } catch (e) { if (e.data?.errcode === 'M_NOT_FOUND') { return null; @@ -3489,16 +3484,15 @@ export class MatrixClient extends TypedEventEmitter { + public setIgnoredUsers(userIds: string[]): Promise<{}> { const content = { ignored_users: {} }; userIds.forEach((u) => { content.ignored_users[u] = {}; }); - return this.setAccountData("m.ignored_user_list", content, callback); + return this.setAccountData("m.ignored_user_list", content); } /** @@ -3519,22 +3513,16 @@ export class MatrixClient extends TypedEventEmitter Default: true. * @param {boolean} opts.inviteSignUrl If the caller has a keypair 3pid invite, the signing URL is passed in this parameter. * @param {string[]} opts.viaServers The server names to try and join through in addition to those that are automatically chosen. - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: Room object. * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public async joinRoom(roomIdOrAlias: string, opts?: IJoinRoomOpts, callback?: Callback): Promise { - // to help people when upgrading.. - if (utils.isFunction(opts)) { - throw new Error("Expected 'opts' object, got function."); - } - opts = opts || {}; + public async joinRoom(roomIdOrAlias: string, opts: IJoinRoomOpts = {}): Promise { if (opts.syncRoom === undefined) { opts.syncRoom = true; } const room = this.getRoom(roomIdOrAlias); - if (room && room.hasMembershipState(this.credentials.userId, "join")) { + if (room?.hasMembershipState(this.credentials.userId, "join")) { return Promise.resolve(room); } @@ -3542,7 +3530,7 @@ export class MatrixClient extends TypedEventEmitter { - return this.sendStateEvent(roomId, EventType.RoomName, { name: name }, undefined, callback); + public setRoomName(roomId: string, name: string): Promise { + return this.sendStateEvent(roomId, EventType.RoomName, { name: name }); } /** * @param {string} roomId * @param {string} topic * @param {string} htmlTopic Optional. - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: TODO * @return {module:http-api.MatrixError} Rejects: with an error response. */ @@ -3643,76 +3627,59 @@ export class MatrixClient extends TypedEventEmitter; - public setRoomTopic( - roomId: string, - topic: string, - callback?: Callback, - ): Promise; - public setRoomTopic( - roomId: string, - topic: string, - htmlTopicOrCallback?: string | Callback, ): Promise { - const isCallback = typeof htmlTopicOrCallback === 'function'; - const htmlTopic = isCallback ? undefined : htmlTopicOrCallback; - const callback = isCallback ? htmlTopicOrCallback : undefined; const content = ContentHelpers.makeTopicContent(topic, htmlTopic); - return this.sendStateEvent(roomId, EventType.RoomTopic, content, undefined, callback); + return this.sendStateEvent(roomId, EventType.RoomTopic, content); } /** * @param {string} roomId - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: to an object keyed by tagId with objects containing a numeric order field. * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public getRoomTags(roomId: string, callback?: Callback): Promise { + public getRoomTags(roomId: string): Promise { const path = utils.encodeUri("/user/$userId/rooms/$roomId/tags", { $userId: this.credentials.userId, $roomId: roomId, }); - return this.http.authedRequest(callback, Method.Get, path); + return this.http.authedRequest(Method.Get, path); } /** * @param {string} roomId * @param {string} tagName name of room tag to be set * @param {object} metadata associated with that tag to be stored - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: to an empty object * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public setRoomTag(roomId: string, tagName: string, metadata: ITagMetadata, callback?: Callback): Promise<{}> { + public setRoomTag(roomId: string, tagName: string, metadata: ITagMetadata): Promise<{}> { const path = utils.encodeUri("/user/$userId/rooms/$roomId/tags/$tag", { $userId: this.credentials.userId, $roomId: roomId, $tag: tagName, }); - return this.http.authedRequest(callback, Method.Put, path, undefined, metadata); + return this.http.authedRequest(Method.Put, path, undefined, metadata); } /** * @param {string} roomId * @param {string} tagName name of room tag to be removed - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: void * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public deleteRoomTag(roomId: string, tagName: string, callback?: Callback): Promise { + public deleteRoomTag(roomId: string, tagName: string): Promise { const path = utils.encodeUri("/user/$userId/rooms/$roomId/tags/$tag", { $userId: this.credentials.userId, $roomId: roomId, $tag: tagName, }); - return this.http.authedRequest(callback, Method.Delete, path); + return this.http.authedRequest(Method.Delete, path); } /** * @param {string} roomId * @param {string} eventType event type to be set * @param {object} content event content - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: to an empty object {} * @return {module:http-api.MatrixError} Rejects: with an error response. */ @@ -3720,14 +3687,13 @@ export class MatrixClient extends TypedEventEmitter, - callback?: Callback, ): Promise<{}> { const path = utils.encodeUri("/user/$userId/rooms/$roomId/account_data/$type", { $userId: this.credentials.userId, $roomId: roomId, $type: eventType, }); - return this.http.authedRequest(callback, Method.Put, path, undefined, content); + return this.http.authedRequest(Method.Put, path, undefined, content); } /** @@ -3736,7 +3702,6 @@ export class MatrixClient extends TypedEventEmitter { let content = { users: {}, @@ -3759,7 +3723,7 @@ export class MatrixClient extends TypedEventEmitter; public sendEvent( roomId: string, @@ -3815,18 +3777,15 @@ export class MatrixClient extends TypedEventEmitter; public sendEvent( roomId: string, threadId: string | null, eventType: string | IContent, content: IContent | string, - txnId?: string | Callback, - callback?: Callback, + txnId?: string, ): Promise { if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) { - callback = txnId as Callback; txnId = content as string; content = eventType as IContent; eventType = threadId; @@ -3854,7 +3813,7 @@ export class MatrixClient extends TypedEventEmitter { - if (utils.isFunction(txnId)) { - callback = txnId as any as Callback; // convert for legacy - txnId = undefined; - } - if (!txnId) { txnId = this.makeTxnId(); } @@ -3935,18 +3887,17 @@ export class MatrixClient extends TypedEventEmitter { + private encryptAndSendEvent(room: Room, event: MatrixEvent): Promise { let cancelled = false; // Add an extra Promise.resolve() to turn synchronous exceptions into promise rejections, // so that we can handle synchronous and asynchronous exceptions with the @@ -3992,9 +3943,6 @@ export class MatrixClient extends TypedEventEmitter { - callback?.(null, res); - return res; }).catch(err => { logger.error("Error sending event", err.stack || err); try { @@ -4006,8 +3954,6 @@ export class MatrixClient extends TypedEventEmitter( - undefined, Method.Put, path, undefined, event.getWireContent(), + Method.Put, path, undefined, event.getWireContent(), ).then((res) => { logger.log(`Event sent to ${event.getRoomId()} with event id ${res.event_id}`); return res; @@ -4126,11 +4072,8 @@ export class MatrixClient extends TypedEventEmitter; public redactEvent( roomId: string, threadId: string | null, eventId: string, txnId?: string | undefined, - cbOrOpts?: Callback | IRedactOpts, + opts?: IRedactOpts, ): Promise; public redactEvent( roomId: string, threadId: string | null, eventId?: string, - txnId?: string | Callback | IRedactOpts, - cbOrOpts?: Callback | IRedactOpts, + txnId?: string | IRedactOpts, + opts?: IRedactOpts, ): Promise { if (!eventId?.startsWith(EVENT_ID_PREFIX)) { - cbOrOpts = txnId as (Callback | IRedactOpts); + opts = txnId as IRedactOpts; txnId = eventId; eventId = threadId; threadId = null; } - const opts = typeof (cbOrOpts) === 'object' ? cbOrOpts : {}; - const reason = opts.reason; - const callback = typeof (cbOrOpts) === 'function' ? cbOrOpts : undefined; + const reason = opts?.reason; return this.sendCompleteEvent(roomId, threadId, { type: EventType.RoomRedaction, content: { reason }, redacts: eventId, - }, txnId as string, callback); + }, txnId as string); } /** @@ -4175,7 +4116,6 @@ export class MatrixClient extends TypedEventEmitter; public sendMessage( roomId: string, threadId: string | null, content: IContent, txnId?: string, - callback?: Callback, ): Promise; public sendMessage( roomId: string, threadId: string | null | IContent, content: IContent | string, - txnId?: string | Callback, - callback?: Callback, + txnId?: string, ): Promise { if (typeof threadId !== "string" && threadId !== null) { - callback = txnId as Callback; txnId = content as string; content = threadId as IContent; threadId = null; } - if (utils.isFunction(txnId)) { - callback = txnId as any as Callback; // for legacy - txnId = undefined; - } // Populate all outbound events with Extensible Events metadata to ensure there's a // reasonably large pool of messages to parse. @@ -4254,8 +4186,7 @@ export class MatrixClient extends TypedEventEmitter; public sendTextMessage( roomId: string, threadId: string | null, body: string, txnId?: string, - callback?: Callback, ): Promise; public sendTextMessage( roomId: string, threadId: string | null, body: string, - txnId?: string | Callback, - callback?: Callback, + txnId?: string, ): Promise { if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) { - callback = txnId as Callback; txnId = body; body = threadId; threadId = null; } const content = ContentHelpers.makeTextMessage(body); - return this.sendMessage(roomId, threadId, content, txnId as string, callback); + return this.sendMessage(roomId, threadId, content, txnId); } /** @@ -4303,7 +4229,6 @@ export class MatrixClient extends TypedEventEmitter; public sendNotice( roomId: string, threadId: string | null, body: string, txnId?: string, - callback?: Callback, ): Promise; public sendNotice( roomId: string, threadId: string | null, body: string, - txnId?: string | Callback, - callback?: Callback, + txnId?: string, ): Promise { if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) { - callback = txnId as Callback; txnId = body; body = threadId; threadId = null; } const content = ContentHelpers.makeNotice(body); - return this.sendMessage(roomId, threadId, content, txnId as string, callback); + return this.sendMessage(roomId, threadId, content, txnId); } /** @@ -4342,7 +4263,6 @@ export class MatrixClient extends TypedEventEmitter; public sendEmoteMessage( roomId: string, threadId: string | null, body: string, txnId?: string, - callback?: Callback, ): Promise; public sendEmoteMessage( roomId: string, threadId: string | null, body: string, - txnId?: string | Callback, - callback?: Callback, + txnId?: string, ): Promise { if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) { - callback = txnId as Callback; txnId = body; body = threadId; threadId = null; } const content = ContentHelpers.makeEmoteMessage(body); - return this.sendMessage(roomId, threadId, content, txnId as string, callback); + return this.sendMessage(roomId, threadId, content, txnId); } /** @@ -4382,7 +4298,6 @@ export class MatrixClient extends TypedEventEmitter; public sendImageMessage( roomId: string, @@ -4399,34 +4313,27 @@ export class MatrixClient extends TypedEventEmitter; public sendImageMessage( roomId: string, threadId: string | null, url: string | IImageInfo, info?: IImageInfo | string, - text: Callback | string = "Image", - callback?: Callback, + text = "Image", ): Promise { if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) { - callback = text as Callback; text = info as string || "Image"; info = url as IImageInfo; url = threadId as string; threadId = null; } - if (utils.isFunction(text)) { - callback = text as any as Callback; // legacy - text = undefined; - } const content = { msgtype: MsgType.Image, url: url, info: info, body: text, }; - return this.sendMessage(roomId, threadId, content, undefined, callback); + return this.sendMessage(roomId, threadId, content); } /** @@ -4435,7 +4342,6 @@ export class MatrixClient extends TypedEventEmitter; public sendStickerMessage( roomId: string, @@ -4452,34 +4357,27 @@ export class MatrixClient extends TypedEventEmitter; public sendStickerMessage( roomId: string, threadId: string | null, url: string | IImageInfo, info?: IImageInfo | string, - text: Callback | string = "Sticker", - callback?: Callback, + text = "Sticker", ): Promise { if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) { - callback = text as Callback; text = info as string || "Sticker"; info = url as IImageInfo; url = threadId as string; threadId = null; } - if (utils.isFunction(text)) { - callback = text as any as Callback; // legacy - text = undefined; - } const content = { url: url, info: info, body: text, }; - return this.sendEvent(roomId, threadId, EventType.Sticker, content, undefined, callback); + return this.sendEvent(roomId, threadId, EventType.Sticker, content); } /** @@ -4487,7 +4385,6 @@ export class MatrixClient extends TypedEventEmitter; public sendHtmlMessage( roomId: string, threadId: string | null, body: string, htmlBody: string, - callback?: Callback, ): Promise; public sendHtmlMessage( roomId: string, threadId: string | null, body: string, - htmlBody: string | Callback, - callback?: Callback, + htmlBody?: string, ): Promise { if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) { - callback = htmlBody as Callback; htmlBody = body as string; body = threadId; threadId = null; } - const content = ContentHelpers.makeHtmlMessage(body, htmlBody as string); - return this.sendMessage(roomId, threadId, content, undefined, callback); + const content = ContentHelpers.makeHtmlMessage(body, htmlBody); + return this.sendMessage(roomId, threadId, content); } /** * @param {string} roomId * @param {string} body * @param {string} htmlBody - * @param {module:client.callback} callback Optional. Deprecated * @return {Promise} Resolves: to a ISendEventResponse object * @return {module:http-api.MatrixError} Rejects: with an error response. */ @@ -4533,30 +4425,26 @@ export class MatrixClient extends TypedEventEmitter; public sendHtmlNotice( roomId: string, threadId: string | null, body: string, htmlBody: string, - callback?: Callback, ): Promise; public sendHtmlNotice( roomId: string, threadId: string | null, body: string, - htmlBody: string | Callback, - callback?: Callback, + htmlBody?: string, ): Promise { if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) { - callback = htmlBody as Callback; htmlBody = body as string; body = threadId; threadId = null; } - const content = ContentHelpers.makeHtmlNotice(body, htmlBody as string); - return this.sendMessage(roomId, threadId, content, undefined, callback); + const content = ContentHelpers.makeHtmlNotice(body, htmlBody); + return this.sendMessage(roomId, threadId, content); } /** @@ -4564,7 +4452,6 @@ export class MatrixClient extends TypedEventEmitter; public sendHtmlEmote( roomId: string, threadId: string | null, body: string, htmlBody: string, - callback?: Callback, ): Promise; public sendHtmlEmote( roomId: string, threadId: string | null, body: string, - htmlBody: string | Callback, - callback?: Callback, + htmlBody?: string, ): Promise { if (!threadId?.startsWith(EVENT_ID_PREFIX) && threadId !== null) { - callback = htmlBody as Callback; htmlBody = body as string; body = threadId; threadId = null; } - const content = ContentHelpers.makeHtmlEmote(body, htmlBody as string); - return this.sendMessage(roomId, threadId, content, undefined, callback); + const content = ContentHelpers.makeHtmlEmote(body, htmlBody); + return this.sendMessage(roomId, threadId, content); } /** @@ -4604,7 +4487,6 @@ export class MatrixClient extends TypedEventEmitter { - if (typeof (body) === 'function') { - callback = body as any as Callback; // legacy - body = {}; - } - if (this.isGuest()) { return Promise.resolve({}); // guests cannot send receipts so don't bother. } @@ -4637,7 +4513,7 @@ export class MatrixClient extends TypedEventEmitter { if (!event) return; const eventId = event.getId(); @@ -4666,7 +4540,7 @@ export class MatrixClient extends TypedEventEmitter { + public getUrlPreview(url: string, ts: number): Promise { // bucket the timestamp to the nearest minute to prevent excessive spam to the server // Surely 60-second accuracy is enough for anyone. ts = Math.floor(ts / 60000) * 60000; @@ -4746,20 +4619,15 @@ export class MatrixClient extends TypedEventEmitter(Method.Get, "/preview_url", { + url, + ts: ts.toString(), + }, undefined, { + prefix: MediaPrefix.R0, + }); // TODO: Expire the URL preview cache sometimes this.urlPreviewCache[key] = resp; return resp; @@ -4769,11 +4637,10 @@ export class MatrixClient extends TypedEventEmitter { + public sendTyping(roomId: string, isTyping: boolean, timeoutMs: number): Promise<{}> { if (this.isGuest()) { return Promise.resolve({}); // guests cannot send typing notifications so don't bother. } @@ -4788,7 +4655,7 @@ export class MatrixClient extends TypedEventEmitter { - return this.membershipChange(roomId, userId, "invite", reason, callback); + public invite(roomId: string, userId: string, reason?: string): Promise<{}> { + return this.membershipChange(roomId, userId, "invite", reason); } /** * Invite a user to a room based on their email address. * @param {string} roomId The room to invite the user to. * @param {string} email The email address to invite. - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: {} an empty object. * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public inviteByEmail(roomId: string, email: string, callback?: Callback): Promise<{}> { - return this.inviteByThreePid(roomId, "email", email, callback); + public inviteByEmail(roomId: string, email: string): Promise<{}> { + return this.inviteByThreePid(roomId, "email", email); } /** @@ -4898,11 +4763,10 @@ export class MatrixClient extends TypedEventEmitter { + public async inviteByThreePid(roomId: string, medium: string, address: string): Promise<{}> { const path = utils.encodeUri( "/rooms/$roomId/invite", { $roomId: roomId }, @@ -4931,17 +4795,16 @@ export class MatrixClient extends TypedEventEmitter { - return this.membershipChange(roomId, undefined, "leave", undefined, callback); + public leave(roomId: string): Promise<{}> { + return this.membershipChange(roomId, undefined, "leave"); } /** @@ -4995,28 +4858,22 @@ export class MatrixClient extends TypedEventEmitter { + return this.membershipChange(roomId, userId, "ban", reason); } /** * @param {string} roomId * @param {boolean} deleteRoom True to delete the room from the store on success. * Default: true. - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: {} an empty object. * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public forget(roomId: string, deleteRoom?: boolean, callback?: Callback): Promise<{}> { - if (deleteRoom === undefined) { - deleteRoom = true; - } - const promise = this.membershipChange(roomId, undefined, "forget", undefined, - callback); + public forget(roomId: string, deleteRoom = true): Promise<{}> { + const promise = this.membershipChange(roomId, undefined, "forget"); if (!deleteRoom) { return promise; } @@ -5030,11 +4887,10 @@ export class MatrixClient extends TypedEventEmitter { + public unban(roomId: string, userId: string): Promise { // unbanning != set their state to leave: this used to be // the case, but was then changed so that leaving was always // a revoking of privilege, otherwise two people racing to @@ -5046,20 +4902,17 @@ export class MatrixClient extends TypedEventEmitter { + public kick(roomId: string, userId: string, reason?: string): Promise<{}> { const path = utils.encodeUri("/rooms/$roomId/kick", { $roomId: roomId, }); @@ -5067,9 +4920,7 @@ export class MatrixClient extends TypedEventEmitter { // API returns an empty object - if (utils.isFunction(reason)) { - callback = reason as any as Callback; // legacy - reason = undefined; - } - const path = utils.encodeUri("/rooms/$room_id/$membership", { $room_id: roomId, $membership: membership, }); return this.http.authedRequest( - callback, Method.Post, path, undefined, { + Method.Post, path, undefined, { user_id: userId, // may be undefined e.g. on leave reason: reason, }, @@ -5114,29 +4959,27 @@ export class MatrixClient extends TypedEventEmitter; - public setProfileInfo(info: "displayname", data: { displayname: string }, callback?: Callback): Promise<{}>; - public setProfileInfo(info: "avatar_url" | "displayname", data: object, callback?: Callback): Promise<{}> { + public setProfileInfo(info: "avatar_url", data: { avatar_url: string }): Promise<{}>; + public setProfileInfo(info: "displayname", data: { displayname: string }): Promise<{}>; + public setProfileInfo(info: "avatar_url" | "displayname", data: object): Promise<{}> { const path = utils.encodeUri("/profile/$userId/$info", { $userId: this.credentials.userId, $info: info, }); - return this.http.authedRequest(callback, Method.Put, path, undefined, data); + return this.http.authedRequest(Method.Put, path, undefined, data); } /** * @param {string} name - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: {} an empty object. * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public async setDisplayName(name: string, callback?: Callback): Promise<{}> { - const prom = await this.setProfileInfo("displayname", { displayname: name }, callback); + public async setDisplayName(name: string): Promise<{}> { + const prom = await this.setProfileInfo("displayname", { displayname: name }); // XXX: synthesise a profile update for ourselves because Synapse is broken and won't const user = this.getUser(this.getUserId()); if (user) { @@ -5148,12 +4991,11 @@ export class MatrixClient extends TypedEventEmitter { - const prom = await this.setProfileInfo("avatar_url", { avatar_url: url }, callback); + public async setAvatarUrl(url: string): Promise<{}> { + const prom = await this.setProfileInfo("avatar_url", { avatar_url: url }); // XXX: synthesise a profile update for ourselves because Synapse is broken and won't const user = this.getUser(this.getUserId()); if (user) { @@ -5190,12 +5032,11 @@ export class MatrixClient extends TypedEventEmitter { + public setPresence(opts: IPresenceOpts): Promise { const path = utils.encodeUri("/presence/$userId/status", { $userId: this.credentials.userId, }); @@ -5208,23 +5049,20 @@ export class MatrixClient extends TypedEventEmitter { + public getPresence(userId: string): Promise { const path = utils.encodeUri("/presence/$userId/status", { $userId: userId, }); - return this.http.authedRequest(callback, Method.Get, path); + return this.http.authedRequest(Method.Get, path); } /** @@ -5238,17 +5076,12 @@ export class MatrixClient extends TypedEventEmitterRoom.oldState.paginationToken will be * null. * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public scrollback(room: Room, limit = 30, callback?: Callback): Promise { - if (utils.isFunction(limit)) { - callback = limit as any as Callback; // legacy - limit = undefined; - } + public scrollback(room: Room, limit = 30): Promise { let timeToWaitMs = 0; let info = this.ongoingScrollbacks[room.roomId] || {}; @@ -5300,13 +5133,11 @@ export class MatrixClient extends TypedEventEmitter { this.ongoingScrollbacks[room.roomId] = { errorTs: Date.now(), }; - callback?.(err); reject(err); }); }); @@ -5369,7 +5200,7 @@ export class MatrixClient extends TypedEventEmitter(undefined, Method.Get, path, params); + const res = await this.http.authedRequest(Method.Get, path, params); if (!res.event) { throw new Error("'event' not in '/context' result - homeserver too old?"); } @@ -5476,7 +5307,7 @@ export class MatrixClient extends TypedEventEmitter(undefined, Method.Get, messagesPath, params); + const res = await this.http.authedRequest(Method.Get, messagesPath, params); const event = res.chunk?.[0]; if (!event) { throw new Error("No message returned from /messages when trying to construct getLatestTimeline"); @@ -5531,7 +5362,7 @@ export class MatrixClient extends TypedEventEmitter( - undefined, Method.Get, path, params, + Method.Get, path, params, ).then(async (res) => { const token = res.next_token; const matrixEvents = []; @@ -5897,7 +5728,6 @@ export class MatrixClient extends TypedEventEmitter { + public searchMessageText(opts: ISearchOpts): Promise { const roomEvents: ISearchRequestBody["search_categories"]["room_events"] = { search_term: opts.query, }; @@ -6094,7 +5924,7 @@ export class MatrixClient extends TypedEventEmitter(undefined, Method.Post, path, undefined, content) + return this.http.authedRequest(Method.Post, path, undefined, content) .then((response) => { // persist the filter const filter = Filter.fromJson(this.credentials.userId, response.filter_id, content); @@ -6292,7 +6122,7 @@ export class MatrixClient extends TypedEventEmitter(undefined, Method.Get, path).then((response) => { + return this.http.authedRequest(Method.Get, path).then((response) => { // persist the filter const filter = Filter.fromJson(userId, filterId, response); this.store.storeFilter(filter); @@ -6367,9 +6197,7 @@ export class MatrixClient extends TypedEventEmitter { @@ -6380,12 +6208,11 @@ export class MatrixClient extends TypedEventEmitter { - return this.http.authedRequest(callback, Method.Get, "/voip/turnServer"); + public turnServer(): Promise { + return this.http.authedRequest(Method.Get, "/voip/turnServer"); } /** @@ -6491,7 +6318,7 @@ export class MatrixClient extends TypedEventEmitter r['admin']); // pull out the specific boolean we want } @@ -6507,7 +6334,7 @@ export class MatrixClient extends TypedEventEmitter { @@ -6582,7 +6407,7 @@ export class MatrixClient extends TypedEventEmitter( - undefined, Method.Get, path, undefined, undefined, + Method.Get, path, undefined, undefined, { prefix: ClientPrefix.Unstable }, ); return res.joined; @@ -6599,7 +6424,6 @@ export class MatrixClient extends TypedEventEmitter( - undefined, // callback Method.Get, "/_matrix/client/versions", undefined, // queryParams undefined, // data @@ -6963,7 +6787,7 @@ export class MatrixClient extends TypedEventEmitter { return this.http.authedRequest<{ available: true }>( - undefined, Method.Get, '/register/available', { username }, + Method.Get, '/register/available', { username }, ).then((response) => { return response.available; }).catch(response => { @@ -6984,7 +6808,6 @@ export class MatrixClient extends TypedEventEmitter { // backwards compat if (bindThreepids === true) { @@ -7004,11 +6826,6 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types + public registerGuest(opts: { body?: any }): Promise { // TODO: Types opts = opts || {}; opts.body = opts.body || {}; - return this.registerRequest(opts.body, "guest", callback); + return this.registerRequest(opts.body, "guest"); } /** * @param {Object} data parameters for registration request * @param {string=} kind type of user to register. may be "guest" - * @param {module:client.callback=} callback * @return {Promise} Resolves: to the /register response * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public registerRequest(data: IRegisterRequestParams, kind?: string, callback?: Callback): Promise { + public registerRequest(data: IRegisterRequestParams, kind?: string): Promise { const params: { kind?: string } = {}; if (kind) { params.kind = kind; } - return this.http.request(callback, Method.Post, "/register", params, data); + return this.http.request(Method.Post, "/register", params, data); } /** @@ -7106,7 +6921,6 @@ export class MatrixClient extends TypedEventEmitter { return this.http.authedRequest( - undefined, Method.Post, "/refresh", undefined, @@ -7119,22 +6933,20 @@ export class MatrixClient extends TypedEventEmitter} Resolves to the available login flows * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public loginFlows(callback?: Callback): Promise { - return this.http.request(callback, Method.Get, "/login"); + public loginFlows(): Promise { + return this.http.request(Method.Get, "/login"); } /** * @param {string} loginType * @param {Object} data - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: TODO * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public login(loginType: string, data: any, callback?: Callback): Promise { // TODO: Types + public login(loginType: string, data: any): Promise { // TODO: Types const loginData = { type: loginType, }; @@ -7142,46 +6954,41 @@ export class MatrixClient extends TypedEventEmitter { - if (response && response.access_token && response.user_id) { - this.http.opts.accessToken = response.access_token; - this.credentials = { - userId: response.user_id, - }; - } - - if (callback) { - callback(error, response); - } - }, Method.Post, "/login", undefined, loginData, - ); + return this.http.authedRequest<{ + access_token?: string; + user_id?: string; + }>(Method.Post, "/login", undefined, loginData).then(response => { + if (response.access_token && response.user_id) { + this.http.opts.accessToken = response.access_token; + this.credentials = { + userId: response.user_id, + }; + } + }); } /** * @param {string} user * @param {string} password - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: TODO * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public loginWithPassword(user: string, password: string, callback?: Callback): Promise { // TODO: Types + public loginWithPassword(user: string, password: string): Promise { // TODO: Types return this.login("m.login.password", { user: user, password: password, - }, callback); + }); } /** * @param {string} relayState URL Callback after SAML2 Authentication - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: TODO * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public loginWithSAML2(relayState: string, callback?: Callback): Promise { // TODO: Types + public loginWithSAML2(relayState: string): Promise { // TODO: Types return this.login("m.login.saml2", { relay_state: relayState, - }, callback); + }); } /** @@ -7223,14 +7030,13 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types + public loginWithToken(token: string): Promise { // TODO: Types return this.login("m.login.token", { token: token, - }, callback); + }); } /** @@ -7239,11 +7045,10 @@ export class MatrixClient extends TypedEventEmitter { + public async logout(stopClient = false): Promise<{}> { if (this.crypto?.backupManager?.getKeyBackupEnabled()) { try { while (await this.crypto.backupManager.backupPendingKeys(200) > 0); @@ -7259,9 +7064,7 @@ export class MatrixClient extends TypedEventEmitter { - if (typeof (erase) === 'function') { - throw new Error('deactivateAccount no longer accepts a callback parameter'); - } - const body: any = {}; if (auth) { body.auth = auth; @@ -7289,7 +7088,7 @@ export class MatrixClient extends TypedEventEmitter> { const body: UIARequest<{}> = { auth }; return this.http.authedRequest( - undefined, // no callback support Method.Post, "/org.matrix.msc3882/login/token", undefined, // no query params @@ -7340,14 +7138,10 @@ export class MatrixClient extends TypedEventEmitter{room_id: {string}} * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public async createRoom( - options: ICreateRoomOpts, - callback?: Callback, - ): Promise<{ room_id: string }> { // eslint-disable-line camelcase + public async createRoom(options: ICreateRoomOpts): Promise<{ room_id: string }> { // eslint-disable-line camelcase // some valid options include: room_alias_name, visibility, invite // inject the id_access_token if inviting 3rd party addresses @@ -7366,7 +7160,7 @@ export class MatrixClient extends TypedEventEmitter { + public roomState(roomId: string): Promise { const path = utils.encodeUri("/rooms/$roomId/state", { $roomId: roomId }); - return this.http.authedRequest(callback, Method.Get, path); + return this.http.authedRequest(Method.Get, path); } /** * Get an event in a room by its event id. * @param {string} roomId * @param {string} eventId - * @param {module:client.callback} callback Optional. * * @return {Promise} Resolves to an object containing the event. * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public fetchRoomEvent( - roomId: string, - eventId: string, - callback?: Callback, - ): Promise { + public fetchRoomEvent(roomId: string, eventId: string): Promise { const path = utils.encodeUri( "/rooms/$roomId/event/$eventId", { $roomId: roomId, $eventId: eventId, }, ); - return this.http.authedRequest(callback, Method.Get, path); + return this.http.authedRequest(Method.Get, path); } /** @@ -7452,7 +7240,6 @@ export class MatrixClient extends TypedEventEmitter { const queryParams: Record = {}; if (includeMembership) { @@ -7478,7 +7264,7 @@ export class MatrixClient extends TypedEventEmitter { // eslint-disable-line camelcase const path = utils.encodeUri("/rooms/$roomId/upgrade", { $roomId: roomId }); - return this.http.authedRequest( - undefined, Method.Post, path, undefined, { new_version: newVersion }, - ); + return this.http.authedRequest(Method.Post, path, undefined, { new_version: newVersion }); } /** @@ -7503,7 +7287,6 @@ export class MatrixClient extends TypedEventEmitter> { const pathParams = { $roomId: roomId, @@ -7522,9 +7304,7 @@ export class MatrixClient extends TypedEventEmitter { const pathParams = { $roomId: roomId, @@ -7552,27 +7330,21 @@ export class MatrixClient extends TypedEventEmitter { - if (utils.isFunction(limit)) { - callback = limit as any as Callback; // legacy - limit = undefined; - } - + public roomInitialSync(roomId: string, limit: number): Promise { const path = utils.encodeUri("/rooms/$roomId/initialSync", { $roomId: roomId }, ); - return this.http.authedRequest(callback, Method.Get, path, { limit: limit?.toString() ?? "30" }); + return this.http.authedRequest(Method.Get, path, { limit: limit?.toString() ?? "30" }); } /** @@ -7608,7 +7380,7 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/joined_rooms", {}); - return this.http.authedRequest(undefined, Method.Get, path); + return this.http.authedRequest(Method.Get, path); } /** @@ -7631,7 +7403,7 @@ export class MatrixClient extends TypedEventEmitter { - if (typeof (options) == 'function') { - callback = options; - options = {}; - } - if (options === undefined) { - options = {}; - } - + public publicRooms(options: IRoomDirectoryOptions = {}): Promise { const queryParams: any = {}; if (options.server) { queryParams.server = options.server; @@ -7663,9 +7426,9 @@ export class MatrixClient extends TypedEventEmitter { + public createAlias(alias: string, roomId: string): Promise<{}> { const path = utils.encodeUri("/directory/room/$alias", { $alias: alias, }); const data = { room_id: roomId, }; - return this.http.authedRequest(callback, Method.Put, path, undefined, data); + return this.http.authedRequest(Method.Put, path, undefined, data); } /** * Delete an alias to room ID mapping. This alias must be on your local server, * and you must have sufficient access to do this operation. * @param {string} alias The room alias to delete. - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: an empty object {}. * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public deleteAlias(alias: string, callback?: Callback): Promise<{}> { + public deleteAlias(alias: string): Promise<{}> { const path = utils.encodeUri("/directory/room/$alias", { $alias: alias, }); - return this.http.authedRequest(callback, Method.Delete, path); + return this.http.authedRequest(Method.Delete, path); } /** @@ -7712,52 +7473,48 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/rooms/$roomId/aliases", { $roomId: roomId }); const prefix = ClientPrefix.V3; - return this.http.authedRequest(undefined, Method.Get, path, undefined, undefined, { prefix }); + return this.http.authedRequest(Method.Get, path, undefined, undefined, { prefix }); } /** * Get room info for the given alias. * @param {string} alias The room alias to resolve. - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: Object with room_id and servers. * @return {module:http-api.MatrixError} Rejects: with an error response. */ public getRoomIdForAlias( alias: string, - callback?: Callback, ): Promise<{ room_id: string, servers: string[] }> { // eslint-disable-line camelcase // TODO: deprecate this or resolveRoomAlias const path = utils.encodeUri("/directory/room/$alias", { $alias: alias, }); - return this.http.authedRequest(callback, Method.Get, path); + return this.http.authedRequest(Method.Get, path); } /** * @param {string} roomAlias - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: Object with room_id and servers. * @return {module:http-api.MatrixError} Rejects: with an error response. */ // eslint-disable-next-line camelcase - public resolveRoomAlias(roomAlias: string, callback?: Callback): Promise<{ room_id: string, servers: string[] }> { + public resolveRoomAlias(roomAlias: string): Promise<{ room_id: string, servers: string[] }> { // TODO: deprecate this or getRoomIdForAlias const path = utils.encodeUri("/directory/room/$alias", { $alias: roomAlias }); - return this.http.request(callback, Method.Get, path); + return this.http.request(Method.Get, path); } /** * Get the visibility of a room in the current HS's room directory * @param {string} roomId - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: TODO * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public getRoomDirectoryVisibility(roomId: string, callback?: Callback): Promise<{ visibility: Visibility }> { + public getRoomDirectoryVisibility(roomId: string): Promise<{ visibility: Visibility }> { const path = utils.encodeUri("/directory/list/room/$roomId", { $roomId: roomId, }); - return this.http.authedRequest(callback, Method.Get, path); + return this.http.authedRequest(Method.Get, path); } /** @@ -7766,15 +7523,14 @@ export class MatrixClient extends TypedEventEmitter { + public setRoomDirectoryVisibility(roomId: string, visibility: Visibility): Promise<{}> { const path = utils.encodeUri("/directory/list/room/$roomId", { $roomId: roomId, }); - return this.http.authedRequest(callback, Method.Put, path, undefined, { visibility }); + return this.http.authedRequest(Method.Put, path, undefined, { visibility }); } /** @@ -7786,7 +7542,6 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types const path = utils.encodeUri("/directory/list/appservice/$networkId/$roomId", { $networkId: networkId, $roomId: roomId, }); - return this.http.authedRequest( - callback, Method.Put, path, undefined, { "visibility": visibility }, - ); + return this.http.authedRequest(Method.Put, path, undefined, { "visibility": visibility }); } /** @@ -7822,7 +7574,7 @@ export class MatrixClient extends TypedEventEmitter { - if (utils.isFunction(info)) { - callback = info as any as Callback; // legacy - info = undefined; - } - const path = info ? utils.encodeUri("/profile/$userId/$info", { $userId: userId, $info: info }) : utils.encodeUri("/profile/$userId", { $userId: userId }); - return this.http.authedRequest(callback, Method.Get, path); + return this.http.authedRequest(Method.Get, path); } /** - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves to a list of the user's threepids. * @return {module:http-api.MatrixError} Rejects: with an error response. */ - public getThreePids(callback?: Callback): Promise<{ threepids: IThreepid[] }> { - return this.http.authedRequest(callback, Method.Get, "/account/3pid"); + public getThreePids(): Promise<{ threepids: IThreepid[] }> { + return this.http.authedRequest(Method.Get, "/account/3pid"); } /** @@ -7938,19 +7678,16 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types + public addThreePid(creds: any, bind: boolean): Promise { // TODO: Types const path = "/account/3pid"; const data = { 'threePidCreds': creds, 'bind': bind, }; - return this.http.authedRequest( - callback, Method.Post, path, undefined, data, - ); + return this.http.authedRequest(Method.Post, path, undefined, data); } /** @@ -7968,7 +7705,7 @@ export class MatrixClient extends TypedEventEmitter { const path = "/account/3pid/add"; const prefix = await this.isVersionSupported("r0.6.0") ? ClientPrefix.R0 : ClientPrefix.Unstable; - return this.http.authedRequest(undefined, Method.Post, path, undefined, data, { prefix }); + return this.http.authedRequest(Method.Post, path, undefined, data, { prefix }); } /** @@ -7988,9 +7725,7 @@ export class MatrixClient extends TypedEventEmitter { const path = "/account/3pid/bind"; const prefix = await this.isVersionSupported("r0.6.0") ? ClientPrefix.R0 : ClientPrefix.Unstable; - return this.http.authedRequest( - undefined, Method.Post, path, undefined, data, { prefix }, - ); + return this.http.authedRequest(Method.Post, path, undefined, data, { prefix }); } /** @@ -8016,7 +7751,7 @@ export class MatrixClient extends TypedEventEmitter { const path = "/account/3pid/delete"; - return this.http.authedRequest(undefined, Method.Post, path, undefined, { medium, address }); + return this.http.authedRequest(Method.Post, path, undefined, { medium, address }); } /** @@ -8041,36 +7776,14 @@ export class MatrixClient extends TypedEventEmitter; - public setPassword( - authDict: any, - newPassword: string, - logoutDevices: boolean, - callback?: Callback, - ): Promise<{}>; - public setPassword( - authDict: any, - newPassword: string, - logoutDevices?: Callback | boolean, - callback?: Callback, + logoutDevices?: boolean, ): Promise<{}> { - if (typeof logoutDevices === 'function') { - callback = logoutDevices; - } - if (typeof logoutDevices !== 'boolean') { - // Use backwards compatible behaviour of not specifying logout_devices - // This way it is left up to the server: - logoutDevices = undefined; - } - const path = "/account/password"; const data = { 'auth': authDict, @@ -8078,9 +7791,7 @@ export class MatrixClient extends TypedEventEmitter( - callback, Method.Post, path, undefined, data, - ); + return this.http.authedRequest<{}>(Method.Post, path, undefined, data); } /** @@ -8089,7 +7800,7 @@ export class MatrixClient extends TypedEventEmitter { - return this.http.authedRequest(undefined, Method.Get, "/devices"); + return this.http.authedRequest(Method.Get, "/devices"); } /** @@ -8102,7 +7813,7 @@ export class MatrixClient extends TypedEventEmitter { - const response = await this.http.authedRequest(callback, Method.Get, "/pushers"); + public async getPushers(): Promise<{ pushers: IPusher[] }> { + const response = await this.http.authedRequest<{ pushers: IPusher[] }>(Method.Get, "/pushers"); // Migration path for clients that connect to a homeserver that does not support // MSC3881 yet, see https://github.com/matrix-org/matrix-spec-proposals/blob/kerry/remote-push-toggle/proposals/3881-remote-push-notification-toggling.md#migration @@ -8191,13 +7901,12 @@ export class MatrixClient extends TypedEventEmitter { + public setPusher(pusher: IPusherRequest): Promise<{}> { const path = "/pushers/set"; - return this.http.authedRequest(callback, Method.Post, path, undefined, pusher); + return this.http.authedRequest(Method.Post, path, undefined, pusher); } /** @@ -8217,12 +7926,11 @@ export class MatrixClient extends TypedEventEmitter { - return this.http.authedRequest(callback, Method.Get, "/pushrules/").then((rules: IPushRules) => { + public getPushRules(): Promise { + return this.http.authedRequest(Method.Get, "/pushrules/").then((rules: IPushRules) => { return PushProcessor.rewriteDefaultRules(rules); }); } @@ -8232,7 +7940,6 @@ export class MatrixClient extends TypedEventEmitter, body: Pick, - callback?: Callback, ): Promise<{}> { // NB. Scope not uri encoded because devices need the '/' const path = utils.encodeUri("/pushrules/" + scope + "/$kind/$ruleId", { $kind: kind, $ruleId: ruleId, }); - return this.http.authedRequest(callback, Method.Put, path, undefined, body); + return this.http.authedRequest(Method.Put, path, undefined, body); } /** * @param {string} scope * @param {string} kind * @param {string} ruleId - * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: an empty object {} * @return {module:http-api.MatrixError} Rejects: with an error response. */ @@ -8263,14 +7968,13 @@ export class MatrixClient extends TypedEventEmitter, - callback?: Callback, ): Promise<{}> { // NB. Scope not uri encoded because devices need the '/' const path = utils.encodeUri("/pushrules/" + scope + "/$kind/$ruleId", { $kind: kind, $ruleId: ruleId, }); - return this.http.authedRequest(callback, Method.Delete, path); + return this.http.authedRequest(Method.Delete, path); } /** @@ -8279,7 +7983,6 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/pushrules/" + scope + "/$kind/$ruleId/enabled", { $kind: kind, $ruleId: ruleId, }); - return this.http.authedRequest( - callback, Method.Put, path, undefined, { "enabled": enabled }, - ); + return this.http.authedRequest(Method.Put, path, undefined, { "enabled": enabled }); } /** @@ -8305,7 +8005,6 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/pushrules/" + scope + "/$kind/$ruleId/actions", { $kind: kind, $ruleId: ruleId, }); - return this.http.authedRequest( - callback, Method.Put, path, undefined, { "actions": actions }, - ); + return this.http.authedRequest(Method.Put, path, undefined, { "actions": actions }); } /** @@ -8330,19 +8026,17 @@ export class MatrixClient extends TypedEventEmitter { const queryParams: any = {}; if (opts.next_batch) { queryParams.next_batch = opts.next_batch; } - return this.http.authedRequest(callback, Method.Post, "/search", queryParams, opts.body); + return this.http.authedRequest(Method.Post, "/search", queryParams, opts.body); } /** @@ -8353,22 +8047,19 @@ export class MatrixClient extends TypedEventEmitter { - return this.http.authedRequest(callback, Method.Post, "/keys/upload", undefined, content); + return this.http.authedRequest(Method.Post, "/keys/upload", undefined, content); } public uploadKeySignatures(content: KeySignatures): Promise { return this.http.authedRequest( - undefined, Method.Post, '/keys/signatures/upload', undefined, + Method.Post, '/keys/signatures/upload', undefined, content, { prefix: ClientPrefix.Unstable, }, @@ -8388,13 +8079,7 @@ export class MatrixClient extends TypedEventEmitter { - if (utils.isFunction(opts)) { - // opts used to be 'callback'. - throw new Error('downloadKeysForUsers no longer accepts a callback parameter'); - } - opts = opts || {}; - + public downloadKeysForUsers(userIds: string[], opts: { token?: string } = {}): Promise { const content: any = { device_keys: {}, }; @@ -8405,7 +8090,7 @@ export class MatrixClient extends TypedEventEmitter { // API returns empty object const data = Object.assign({}, keys); if (auth) Object.assign(data, { auth }); return this.http.authedRequest( - undefined, Method.Post, "/keys/device_signing/upload", undefined, data, { + Method.Post, "/keys/device_signing/upload", undefined, data, { prefix: ClientPrefix.Unstable, }, ); @@ -8495,10 +8180,7 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types const params = { @@ -8541,7 +8221,7 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types const params = { @@ -8591,7 +8269,7 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types return this.http.idServerRequest( - undefined, Method.Get, "/hash_details", + Method.Get, "/hash_details", null, IdentityPrefix.V2, identityAccessToken, ); } @@ -8745,7 +8421,7 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types // Note: we're using the V2 API by calling this function, but our @@ -8793,7 +8467,6 @@ export class MatrixClient extends TypedEventEmitter p.address === address); if (!result) { - if (callback) callback(null, {}); return {}; } @@ -8809,7 +8482,6 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types return this.http.idServerRequest( - undefined, Method.Get, "/account", + Method.Get, "/account", undefined, IdentityPrefix.V2, identityAccessToken, ); } @@ -8901,7 +8573,7 @@ export class MatrixClient extends TypedEventEmitter { return this.http.authedRequest>( - undefined, Method.Get, "/thirdparty/protocols", + Method.Get, "/thirdparty/protocols", ).then((response) => { // sanity check if (!response || typeof (response) !== 'object') { @@ -8948,7 +8620,7 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types const url = this.termsUrlForService(serviceType, baseUrl); - return this.http.requestOtherUrl(undefined, Method.Get, url); + return this.http.requestOtherUrl(Method.Get, url); } public agreeToTerms( @@ -8982,7 +8654,7 @@ export class MatrixClient extends TypedEventEmitter(undefined, Method.Get, path, queryParams, undefined, { + return this.http.authedRequest(Method.Get, path, queryParams, undefined, { prefix: ClientPrefix.V1, }).catch(e => { if (e.errcode === "M_UNRECOGNIZED") { // fall back to the prefixed hierarchy API. - return this.http.authedRequest(undefined, Method.Get, path, queryParams, undefined, { + return this.http.authedRequest(Method.Get, path, queryParams, undefined, { prefix: "/_matrix/client/unstable/org.matrix.msc2946", }); } @@ -9133,7 +8805,6 @@ export class MatrixClient extends TypedEventEmitter( - undefined, Method.Post, "/sync", qps, @@ -9161,8 +8832,7 @@ export class MatrixClient extends TypedEventEmitter { const path = utils.encodeUri("/rooms/$roomid/summary", { $roomid: roomIdOrAlias }); - return this.http.authedRequest(undefined, Method.Get, path, { via }, undefined, { - qsStringifyOptions: { arrayFormat: 'repeat' }, + return this.http.authedRequest(Method.Get, path, { via }, undefined, { prefix: "/_matrix/client/unstable/im.nheko.summary", }); } @@ -9188,7 +8858,7 @@ export class MatrixClient extends TypedEventEmitter { // eslint-disable-line camelcase - return this.http.authedRequest(undefined, Method.Get, "/account/whoami"); + return this.http.authedRequest(Method.Get, "/account/whoami"); } /** @@ -9207,7 +8877,6 @@ export class MatrixClient extends TypedEventEmitter( - undefined, Method.Put, "/dehydrated_device", undefined, @@ -273,7 +272,6 @@ export class DehydrationManager { logger.log("Uploading keys to server"); await this.crypto.baseApis.http.authedRequest( - undefined, Method.Post, "/keys/upload/" + encodeURI(deviceId), undefined, diff --git a/src/http-api.ts b/src/http-api.ts index 291b6917f5a..ed0ae10435a 100644 --- a/src/http-api.ts +++ b/src/http-api.ts @@ -31,7 +31,6 @@ import * as callbacks from "./realtime-callbacks"; import { IUploadOpts } from "./@types/requests"; import { IAbortablePromise, IUsageLimit } from "./@types/partials"; import { IDeferred, sleep } from "./utils"; -import { Callback } from "./client"; import * as utils from "./utils"; import { logger } from './logger'; import { MediaPrefix } from "./http-api/prefix"; @@ -235,10 +234,6 @@ export class MatrixHttpApi { * where it defaults to true for backwards compatibility). Ignored if * opts.rawResponse is true. * - * @param {Function=} opts.callback Deprecated. Optional. The callback to - * invoke on success/failure. See the promise return values for more - * information. - * * @param {Function=} opts.progressHandler Optional. Called when a chunk of * data has been uploaded, with an object containing the fields `loaded` * (number of bytes transferred) and `total` (total size, if known). @@ -249,17 +244,8 @@ export class MatrixHttpApi { */ public uploadContent( file: FileType, - opts?: O, + opts: O = {} as O, ): IAbortablePromise> { - if (utils.isFunction(opts)) { - // opts used to be callback, backwards compatibility - opts = { - callback: opts as unknown as IUploadOpts["callback"], - } as O; - } else if (!opts) { - opts = {} as O; - } - // default opts.includeFilename to true (ignoring falsey values) const includeFilename = opts.includeFilename !== false; @@ -349,7 +335,7 @@ export class MatrixHttpApi { if (global.XMLHttpRequest) { const defer = utils.defer>(); const xhr = new global.XMLHttpRequest(); - const cb = requestCallback(defer, opts.callback, this.opts.onlyData); + const cb = requestCallback(defer, this.opts.onlyData); const timeoutFn = function() { xhr.abort(); @@ -440,7 +426,7 @@ export class MatrixHttpApi { } promise = this.authedRequest>( - opts.callback, Method.Post, "/upload", queryParams, body, { + Method.Post, "/upload", queryParams, body, { prefix: MediaPrefix.R0, headers, json: false, @@ -479,7 +465,6 @@ export class MatrixHttpApi { } public idServerRequest( - callback: Callback, method: Method, path: string, params: Record, @@ -492,12 +477,6 @@ export class MatrixHttpApi { const fullUri = this.opts.idBaseUrl + prefix + path; - if (callback !== undefined && !utils.isFunction(callback)) { - throw Error( - "Expected callback to be a function but got " + typeof callback, - ); - } - const opts = { uri: fullUri, method, @@ -518,14 +497,12 @@ export class MatrixHttpApi { } const defer = utils.defer(); - this.opts.request(opts, requestCallback(defer, callback, this.opts.onlyData)); + this.opts.request(opts, requestCallback(defer, this.opts.onlyData)); return defer.promise; } /** * Perform an authorised request to the homeserver. - * @param {Function} callback Optional. The callback to invoke on - * success/failure. See the promise return values for more information. * @param {string} method The HTTP method e.g. "GET". * @param {string} path The HTTP path after the supplied prefix e.g. * "/createRoom". @@ -557,7 +534,6 @@ export class MatrixHttpApi { * occurred. This includes network problems and Matrix-specific error JSON. */ public authedRequest = IRequestOpts>( - callback: Callback | undefined, method: Method, path: string, queryParams?: Record, @@ -588,7 +564,7 @@ export class MatrixHttpApi { queryParams.access_token = this.opts.accessToken; } - const requestPromise = this.request(callback, method, path, queryParams, data, requestOpts); + const requestPromise = this.request(method, path, queryParams, data, requestOpts); requestPromise.catch((err: MatrixError) => { if (err.errcode == 'M_UNKNOWN_TOKEN' && !requestOpts?.inhibitLogoutEmit) { @@ -605,8 +581,6 @@ export class MatrixHttpApi { /** * Perform a request to the homeserver without any credentials. - * @param {Function} callback Optional. The callback to invoke on - * success/failure. See the promise return values for more information. * @param {string} method The HTTP method e.g. "GET". * @param {string} path The HTTP path after the supplied prefix e.g. * "/createRoom". @@ -634,7 +608,6 @@ export class MatrixHttpApi { * occurred. This includes network problems and Matrix-specific error JSON. */ public request = IRequestOpts>( - callback: Callback | undefined, method: Method, path: string, queryParams?: CoreOptions["qs"], @@ -645,13 +618,11 @@ export class MatrixHttpApi { const baseUrl = opts?.baseUrl ?? this.opts.baseUrl; const fullUri = baseUrl + prefix + path; - return this.requestOtherUrl(callback, method, fullUri, queryParams, data, opts); + return this.requestOtherUrl(method, fullUri, queryParams, data, opts); } /** * Perform a request to an arbitrary URL. - * @param {Function} callback Optional. The callback to invoke on - * success/failure. See the promise return values for more information. * @param {string} method The HTTP method e.g. "GET". * @param {string} uri The HTTP URI * @@ -678,7 +649,6 @@ export class MatrixHttpApi { * occurred. This includes network problems and Matrix-specific error JSON. */ public requestOtherUrl = IRequestOpts>( - callback: Callback | undefined, method: Method, uri: string, queryParams?: CoreOptions["qs"], @@ -693,7 +663,7 @@ export class MatrixHttpApi { } as O; } - return this.doRequest(callback, method, uri, queryParams, data, requestOpts); + return this.doRequest(method, uri, queryParams, data, requestOpts); } /** @@ -718,7 +688,6 @@ export class MatrixHttpApi { /** * @private * - * @param {function} callback * @param {string} method * @param {string} uri * @param {object} queryParams @@ -745,17 +714,12 @@ export class MatrixHttpApi { * Generic O should be inferred */ private doRequest = IRequestOpts>( - callback: Callback | undefined, method: Method, uri: string, queryParams?: Record, data?: CoreOptions["body"], opts?: O, ): IAbortablePromise> { - if (callback !== undefined && !utils.isFunction(callback)) { - throw Error("Expected callback to be a function but got " + typeof callback); - } - if (this.opts.extraParams) { queryParams = { ...(queryParams || {}), @@ -840,7 +804,7 @@ export class MatrixHttpApi { } } - const handlerFn = requestCallback(defer, callback, this.opts.onlyData, bodyParser); + const handlerFn = requestCallback(defer, this.opts.onlyData, bodyParser); handlerFn(err, response, body); }, ); @@ -865,9 +829,6 @@ export class MatrixHttpApi { } } catch (ex) { defer.reject(ex); - if (callback) { - callback(ex); - } } return reqPromise; } @@ -902,7 +863,6 @@ function getStatusCode(response: XMLHttpRequest | IncomingMessage): number { */ function requestCallback( defer: IDeferred, - userDefinedCallback?: Callback, onlyData = false, bodyParser?: (body: string) => T, ): RequestCallback { @@ -935,10 +895,8 @@ function requestCallback( if (err) { defer.reject(err); - userDefinedCallback?.(err); } else if (onlyData) { defer.resolve(data as T); - userDefinedCallback?.(null, data as T); } else { const res: IResponse = { code: getStatusCode(response), @@ -951,7 +909,6 @@ function requestCallback( // XXX: the variations in caller-expected types here are horrible, // typescript doesn't do conditional types based on runtime values defer.resolve(res as any as T); - userDefinedCallback?.(null, res as any as T); } }; } diff --git a/src/sync.ts b/src/sync.ts index 7685479499a..592c870d79a 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -296,9 +296,7 @@ export class SyncApi { getFilterName(client.credentials.userId, "LEFT_ROOMS"), filter, ).then(function(filterId) { qps.filter = filterId; - return client.http.authedRequest( - undefined, Method.Get, "/sync", qps as any, undefined, localTimeoutMs, - ); + return client.http.authedRequest(Method.Get, "/sync", qps as any, undefined, localTimeoutMs); }).then(async (data) => { let leaveRooms = []; if (data.rooms?.leave) { @@ -431,7 +429,7 @@ export class SyncApi { } // FIXME: gut wrenching; hard-coded timeout values - this.client.http.authedRequest(undefined, Method.Get, "/events", { + this.client.http.authedRequest(Method.Get, "/events", { room_id: peekRoom.roomId, timeout: String(30 * 1000), from: token, @@ -899,7 +897,7 @@ export class SyncApi { private doSyncRequest(syncOptions: ISyncOptions, syncToken: string): IAbortablePromise { const qps = this.getSyncParams(syncOptions, syncToken); return this.client.http.authedRequest( - undefined, Method.Get, "/sync", qps as any, undefined, + Method.Get, "/sync", qps as any, undefined, qps.timeout + BUFFER_PERIOD_MS, ); } @@ -1492,7 +1490,6 @@ export class SyncApi { }; this.client.http.request( - undefined, // callback Method.Get, "/_matrix/client/versions", undefined, // queryParams undefined, // data From f8a44b773d95c570edda4d5d984629ec665bef4f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 12:04:43 +0100 Subject: [PATCH 04/38] Migrate from `request` and `browser-request` to `fetch` --- README.md | 4 - package.json | 5 +- spec/TestClient.ts | 5 +- spec/integ/matrix-client-methods.spec.js | 72 +- spec/integ/matrix-client-opts.spec.js | 4 +- .../integ/matrix-client-room-timeline.spec.js | 21 +- spec/integ/matrix-client-syncing.spec.ts | 2 +- spec/integ/sliding-sync-sdk.spec.ts | 4 +- spec/unit/autodiscovery.spec.ts | 3 +- spec/unit/crypto/backup.spec.ts | 54 +- spec/unit/event-mapper.spec.ts | 2 +- spec/unit/matrix-client.spec.ts | 3 +- spec/unit/models/MSC3089TreeSpace.spec.ts | 6 +- spec/unit/pusher.spec.ts | 4 +- spec/unit/queueToDevice.spec.ts | 4 +- spec/unit/read-receipt.spec.ts | 3 +- spec/unit/utils.spec.ts | 6 +- src/@types/partials.ts | 5 - src/@types/requests.ts | 9 - src/ToDeviceMessageQueue.ts | 2 +- src/autodiscovery.ts | 97 +- src/browser-index.js | 17 +- src/client.ts | 75 +- src/http-api.ts | 1064 -------- src/http-api/errors.ts | 64 + src/http-api/fetch.ts | 308 +++ src/http-api/index.ts | 190 +- src/http-api/interface.ts | 92 + src/http-api/method.ts | 22 + src/http-api/utils.ts | 145 + src/index.ts | 7 +- src/matrix.ts | 64 +- src/models/MSC3089TreeSpace.ts | 5 +- src/sliding-sync-sdk.ts | 2 +- src/sliding-sync.ts | 15 +- src/sync.ts | 23 +- src/utils.ts | 20 +- yarn.lock | 2332 ++++++++--------- 38 files changed, 2072 insertions(+), 2688 deletions(-) delete mode 100644 src/http-api.ts create mode 100644 src/http-api/errors.ts create mode 100644 src/http-api/fetch.ts create mode 100644 src/http-api/interface.ts create mode 100644 src/http-api/method.ts create mode 100644 src/http-api/utils.ts diff --git a/README.md b/README.md index 257337d2ca3..c1721e11b70 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,6 @@ In Node.js Ensure you have the latest LTS version of Node.js installed. -This SDK targets Node 12 for compatibility, which translates to ES6. If you're using -a bundler like webpack you'll likely have to transpile dependencies, including this -SDK, to match your target browsers. - Using `yarn` instead of `npm` is recommended. Please see the Yarn [install guide](https://classic.yarnpkg.com/en/docs/install) if you do not have it already. diff --git a/package.json b/package.json index 8395a22659a..d440c6f7bd0 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "20.0.2", "description": "Matrix Client-Server SDK for Javascript", "engines": { - "node": ">=12.9.0" + "node": ">=16.0.0" }, "scripts": { "prepublishOnly": "yarn build", @@ -55,14 +55,12 @@ "dependencies": { "@babel/runtime": "^7.12.5", "another-json": "^0.2.0", - "browser-request": "^0.3.3", "bs58": "^5.0.0", "content-type": "^1.0.4", "loglevel": "^1.7.1", "matrix-events-sdk": "^0.0.1-beta.7", "p-retry": "4", "qs": "^6.9.6", - "request": "^2.88.2", "unhomoglyph": "^1.0.6" }, "devDependencies": { @@ -83,7 +81,6 @@ "@types/content-type": "^1.1.5", "@types/jest": "^29.0.0", "@types/node": "16", - "@types/request": "^2.48.5", "@typescript-eslint/eslint-plugin": "^5.6.0", "@typescript-eslint/parser": "^5.6.0", "allchange": "^1.0.6", diff --git a/spec/TestClient.ts b/spec/TestClient.ts index 0a6c4e0eee2..6056884dd31 100644 --- a/spec/TestClient.ts +++ b/spec/TestClient.ts @@ -30,7 +30,6 @@ import { MockStorageApi } from "./MockStorageApi"; import { encodeUri } from "../src/utils"; import { IDeviceKeys, IOneTimeKey } from "../src/crypto/dehydration"; import { IKeyBackupSession } from "../src/crypto/keybackup"; -import { IHttpOpts } from "../src/http-api"; import { IKeysUploadResponse, IUploadKeysRequest } from '../src/client'; /** @@ -56,11 +55,11 @@ export class TestClient { this.httpBackend = new MockHttpBackend(); const fullOptions: ICreateClientOpts = { - baseUrl: "http://" + userId + ".test.server", + baseUrl: "http://" + userId?.slice(1).replace(":", ".") + ".test.server", userId: userId, accessToken: accessToken, deviceId: deviceId, - request: this.httpBackend.requestFn as IHttpOpts["request"], + fetchFn: this.httpBackend.fetchFn as typeof global.fetch, ...options, }; if (!fullOptions.cryptoStore) { diff --git a/spec/integ/matrix-client-methods.spec.js b/spec/integ/matrix-client-methods.spec.js index 69bfa89ca56..1943ed5962a 100644 --- a/spec/integ/matrix-client-methods.spec.js +++ b/spec/integ/matrix-client-methods.spec.js @@ -51,26 +51,25 @@ describe("MatrixClient", function() { describe("uploadContent", function() { const buf = Buffer.from('hello world'); + const file = buf; + const opts = { + type: "text/plain", + name: "hi.txt", + }; + it("should upload the file", function() { httpBackend.when( "POST", "/_matrix/media/r0/upload", ).check(function(req) { expect(req.rawData).toEqual(buf); expect(req.queryParams.filename).toEqual("hi.txt"); - if (!(req.queryParams.access_token == accessToken || - req.headers["Authorization"] == "Bearer " + accessToken)) { - expect(true).toBe(false); - } + expect(req.headers["Authorization"]).toBe("Bearer " + accessToken); expect(req.headers["Content-Type"]).toEqual("text/plain"); expect(req.opts.json).toBeFalsy(); expect(req.opts.timeout).toBe(undefined); - }).respond(200, "content", true); + }).respond(200, '{"content_uri": "content"}', true); - const prom = client.uploadContent({ - stream: buf, - name: "hi.txt", - type: "text/plain", - }); + const prom = client.uploadContent(file, opts).promise; expect(prom).toBeTruthy(); @@ -80,8 +79,7 @@ describe("MatrixClient", function() { expect(uploads[0].loaded).toEqual(0); const prom2 = prom.then(function(response) { - // for backwards compatibility, we return the raw JSON - expect(response).toEqual("content"); + expect(response.content_uri).toEqual("content"); const uploads = client.getCurrentUploads(); expect(uploads.length).toEqual(0); @@ -91,27 +89,6 @@ describe("MatrixClient", function() { return prom2; }); - it("should parse the response if rawResponse=false", function() { - httpBackend.when( - "POST", "/_matrix/media/r0/upload", - ).check(function(req) { - expect(req.opts.json).toBeFalsy(); - }).respond(200, { "content_uri": "uri" }); - - const prom = client.uploadContent({ - stream: buf, - name: "hi.txt", - type: "text/plain", - }, { - rawResponse: false, - }).then(function(response) { - expect(response.content_uri).toEqual("uri"); - }); - - httpBackend.flush(); - return prom; - }); - it("should parse errors into a MatrixError", function() { httpBackend.when( "POST", "/_matrix/media/r0/upload", @@ -123,11 +100,7 @@ describe("MatrixClient", function() { "error": "broken", }); - const prom = client.uploadContent({ - stream: buf, - name: "hi.txt", - type: "text/plain", - }).then(function(response) { + const prom = client.uploadContent(file, opts).promise.then(function(response) { throw Error("request not failed"); }, function(error) { expect(error.httpStatus).toEqual(400); @@ -139,30 +112,19 @@ describe("MatrixClient", function() { return prom; }); - it("should return a promise which can be cancelled", function() { - const prom = client.uploadContent({ - stream: buf, - name: "hi.txt", - type: "text/plain", - }); + it("should return a promise which can be cancelled", async () => { + const upload = client.uploadContent(file, opts); + const prom = upload.promise; const uploads = client.getCurrentUploads(); expect(uploads.length).toEqual(1); expect(uploads[0].promise).toBe(prom); expect(uploads[0].loaded).toEqual(0); - const prom2 = prom.then(function(response) { - throw Error("request not aborted"); - }, function(error) { - expect(error).toEqual("aborted"); - - const uploads = client.getCurrentUploads(); - expect(uploads.length).toEqual(0); - }); - - const r = client.cancelUpload(prom); + const r = client.cancelUpload(upload); expect(r).toBe(true); - return prom2; + await expect(prom).rejects.toThrow("Aborted"); + expect(client.getCurrentUploads()).toHaveLength(0); }); }); diff --git a/spec/integ/matrix-client-opts.spec.js b/spec/integ/matrix-client-opts.spec.js index 8e342b2592a..31d4b592951 100644 --- a/spec/integ/matrix-client-opts.spec.js +++ b/spec/integ/matrix-client-opts.spec.js @@ -67,7 +67,7 @@ describe("MatrixClient opts", function() { let client; beforeEach(function() { client = new MatrixClient({ - request: httpBackend.requestFn, + fetchFn: httpBackend.fetchFn, store: undefined, baseUrl: baseUrl, userId: userId, @@ -127,7 +127,7 @@ describe("MatrixClient opts", function() { let client; beforeEach(function() { client = new MatrixClient({ - request: httpBackend.requestFn, + fetchFn: httpBackend.fetchFn, store: new MemoryStore(), baseUrl: baseUrl, userId: userId, diff --git a/spec/integ/matrix-client-room-timeline.spec.js b/spec/integ/matrix-client-room-timeline.spec.js index acf751a8c09..33f53f2185b 100644 --- a/spec/integ/matrix-client-room-timeline.spec.js +++ b/spec/integ/matrix-client-room-timeline.spec.js @@ -1,6 +1,6 @@ import * as utils from "../test-utils/test-utils"; import { EventStatus } from "../../src/models/event"; -import { RoomEvent } from "../../src"; +import { MatrixError, RoomEvent } from "../../src"; import { TestClient } from "../TestClient"; describe("MatrixClient room timelines", function() { @@ -794,17 +794,14 @@ describe("MatrixClient room timelines", function() { it('Timeline recovers after `/context` request to generate new timeline fails', async () => { // `/context` request for `refreshLiveTimeline()` -> `getEventTimeline()` // to construct a new timeline from. - httpBackend.when("GET", contextUrl) - .respond(500, function() { - // The timeline should be cleared at this point in the refresh - expect(room.timeline.length).toEqual(0); - - return { - errcode: 'TEST_FAKE_ERROR', - error: 'We purposely intercepted this /context request to make it fail ' + - 'in order to test whether the refresh timeline code is resilient', - }; - }); + httpBackend.when("GET", contextUrl).check(() => { + // The timeline should be cleared at this point in the refresh + expect(room.timeline.length).toEqual(0); + }).fail(500, new MatrixError({ + errcode: 'TEST_FAKE_ERROR', + error: 'We purposely intercepted this /context request to make it fail ' + + 'in order to test whether the refresh timeline code is resilient', + })); // Refresh the timeline and expect it to fail const settledFailedRefreshPromises = await Promise.allSettled([ diff --git a/spec/integ/matrix-client-syncing.spec.ts b/spec/integ/matrix-client-syncing.spec.ts index e07e52c7b83..3f5d95e60f8 100644 --- a/spec/integ/matrix-client-syncing.spec.ts +++ b/spec/integ/matrix-client-syncing.spec.ts @@ -1491,7 +1491,7 @@ describe("MatrixClient syncing (IndexedDB version)", () => { const idbHttpBackend = idbTestClient.httpBackend; const idbClient = idbTestClient.client; idbHttpBackend.when("GET", "/versions").respond(200, {}); - idbHttpBackend.when("GET", "/pushrules").respond(200, {}); + idbHttpBackend.when("GET", "/pushrules/").respond(200, {}); idbHttpBackend.when("POST", "/filter").respond(200, { filter_id: "a filter id" }); await idbClient.initCrypto(); diff --git a/spec/integ/sliding-sync-sdk.spec.ts b/spec/integ/sliding-sync-sdk.spec.ts index f7dc6875492..a96d80a607c 100644 --- a/spec/integ/sliding-sync-sdk.spec.ts +++ b/spec/integ/sliding-sync-sdk.spec.ts @@ -23,12 +23,13 @@ import { TestClient } from "../TestClient"; import { IRoomEvent, IStateEvent } from "../../src/sync-accumulator"; import { MatrixClient, MatrixEvent, NotificationCountType, JoinRule, MatrixError, - EventType, IPushRules, PushRuleKind, TweakName, ClientEvent, + EventType, IPushRules, PushRuleKind, TweakName, ClientEvent, RoomMemberEvent, } from "../../src"; import { SlidingSyncSdk } from "../../src/sliding-sync-sdk"; import { SyncState } from "../../src/sync"; import { IStoredClientOpts } from "../../src/client"; import { logger } from "../../src/logger"; +import { emitPromise } from "../test-utils/test-utils"; describe("SlidingSyncSdk", () => { let client: MatrixClient = null; @@ -530,6 +531,7 @@ describe("SlidingSyncSdk", () => { ], }); await httpBackend.flush("/profile", 1, 1000); + await emitPromise(client, RoomMemberEvent.Name); const room = client.getRoom(roomId); expect(room).toBeDefined(); const inviteeMember = room.getMember(invitee); diff --git a/spec/unit/autodiscovery.spec.ts b/spec/unit/autodiscovery.spec.ts index 939f477977a..38058c93cc7 100644 --- a/spec/unit/autodiscovery.spec.ts +++ b/spec/unit/autodiscovery.spec.ts @@ -17,13 +17,12 @@ limitations under the License. import MockHttpBackend from "matrix-mock-request"; -import { request } from "../../src/matrix"; import { AutoDiscovery } from "../../src/autodiscovery"; describe("AutoDiscovery", function() { const getHttpBackend = (): MockHttpBackend => { const httpBackend = new MockHttpBackend(); - request(httpBackend.requestFn); + AutoDiscovery.setFetchFn(httpBackend.fetchFn as typeof global.fetch); return httpBackend; }; diff --git a/spec/unit/crypto/backup.spec.ts b/spec/unit/crypto/backup.spec.ts index e20f3679d51..d54f871d42b 100644 --- a/spec/unit/crypto/backup.spec.ts +++ b/spec/unit/crypto/backup.spec.ts @@ -30,7 +30,7 @@ import { Crypto } from "../../../src/crypto"; import { resetCrossSigningKeys } from "./crypto-utils"; import { BackupManager } from "../../../src/crypto/backup"; import { StubStore } from "../../../src/store/stub"; -import { IAbortablePromise, MatrixScheduler } from '../../../src'; +import { MatrixScheduler } from '../../../src'; const Olm = global.Olm; @@ -131,7 +131,7 @@ function makeTestClient(cryptoStore) { baseUrl: "https://my.home.server", idBaseUrl: "https://identity.server", accessToken: "my.access.token", - request: jest.fn(), // NOP + fetchFn: jest.fn(), // NOP store: store, scheduler: scheduler, userId: "@alice:bar", @@ -298,25 +298,25 @@ describe("MegolmBackup", function() { }); let numCalls = 0; return new Promise((resolve, reject) => { - client.http.authedRequest = function( + client.http.authedRequest = function( method, path, queryParams, data, opts, - ) { + ): Promise { ++numCalls; expect(numCalls).toBeLessThanOrEqual(1); if (numCalls >= 2) { // exit out of retry loop if there's something wrong reject(new Error("authedRequest called too many timmes")); - return Promise.resolve({}) as IAbortablePromise; + return Promise.resolve({} as T); } expect(method).toBe("PUT"); expect(path).toBe("/room_keys/keys"); expect(queryParams.version).toBe('1'); - expect(data.rooms[ROOM_ID].sessions).toBeDefined(); - expect(data.rooms[ROOM_ID].sessions).toHaveProperty( + expect((data as Record).rooms[ROOM_ID].sessions).toBeDefined(); + expect((data as Record).rooms[ROOM_ID].sessions).toHaveProperty( groupSession.session_id(), ); resolve(); - return Promise.resolve({}) as IAbortablePromise; + return Promise.resolve({} as T); }; client.crypto.backupManager.backupGroupSession( "F0Q2NmyJNgUVj9DGsb4ZQt3aVxhVcUQhg7+gvW0oyKI", @@ -381,25 +381,25 @@ describe("MegolmBackup", function() { }); let numCalls = 0; return new Promise((resolve, reject) => { - client.http.authedRequest = function( + client.http.authedRequest = function( method, path, queryParams, data, opts, - ) { + ): Promise { ++numCalls; expect(numCalls).toBeLessThanOrEqual(1); if (numCalls >= 2) { // exit out of retry loop if there's something wrong reject(new Error("authedRequest called too many timmes")); - return Promise.resolve({}) as IAbortablePromise; + return Promise.resolve({} as T); } expect(method).toBe("PUT"); expect(path).toBe("/room_keys/keys"); expect(queryParams.version).toBe('1'); - expect(data.rooms[ROOM_ID].sessions).toBeDefined(); - expect(data.rooms[ROOM_ID].sessions).toHaveProperty( + expect((data as Record).rooms[ROOM_ID].sessions).toBeDefined(); + expect((data as Record).rooms[ROOM_ID].sessions).toHaveProperty( groupSession.session_id(), ); resolve(); - return Promise.resolve({}) as IAbortablePromise; + return Promise.resolve({} as T); }; client.crypto.backupManager.backupGroupSession( "F0Q2NmyJNgUVj9DGsb4ZQt3aVxhVcUQhg7+gvW0oyKI", @@ -449,23 +449,23 @@ describe("MegolmBackup", function() { try { // make sure auth_data is signed by the master key olmlib.pkVerify( - data.auth_data, client.getCrossSigningId(), "@alice:bar", + (data as Record).auth_data, client.getCrossSigningId(), "@alice:bar", ); } catch (e) { reject(e); - return Promise.resolve({}) as IAbortablePromise; + return Promise.resolve({}); } backupInfo = data; - return Promise.resolve({}) as IAbortablePromise; + return Promise.resolve({}); } else if (numCalls === 2) { expect(method).toBe("GET"); expect(path).toBe("/room_keys/version"); resolve(); - return Promise.resolve(backupInfo) as IAbortablePromise; + return Promise.resolve(backupInfo); } else { // exit out of retry loop if there's something wrong reject(new Error("authedRequest called too many times")); - return Promise.resolve({}) as IAbortablePromise; + return Promise.resolve({}); } }; }), @@ -495,7 +495,7 @@ describe("MegolmBackup", function() { baseUrl: "https://my.home.server", idBaseUrl: "https://identity.server", accessToken: "my.access.token", - request: jest.fn(), // NOP + fetchFn: jest.fn(), // NOP store: store, scheduler: scheduler, userId: "@alice:bar", @@ -542,30 +542,30 @@ describe("MegolmBackup", function() { let numCalls = 0; await new Promise((resolve, reject) => { - client.http.authedRequest = function( + client.http.authedRequest = function( method, path, queryParams, data, opts, - ) { + ): Promise { ++numCalls; expect(numCalls).toBeLessThanOrEqual(2); if (numCalls >= 3) { // exit out of retry loop if there's something wrong reject(new Error("authedRequest called too many timmes")); - return Promise.resolve({}) as IAbortablePromise; + return Promise.resolve({} as T); } expect(method).toBe("PUT"); expect(path).toBe("/room_keys/keys"); expect(queryParams.version).toBe('1'); - expect(data.rooms[ROOM_ID].sessions).toBeDefined(); - expect(data.rooms[ROOM_ID].sessions).toHaveProperty( + expect((data as Record).rooms[ROOM_ID].sessions).toBeDefined(); + expect((data as Record).rooms[ROOM_ID].sessions).toHaveProperty( groupSession.session_id(), ); if (numCalls > 1) { resolve(); - return Promise.resolve({}) as IAbortablePromise; + return Promise.resolve({} as T); } else { return Promise.reject( new Error("this is an expected failure"), - ) as IAbortablePromise; + ); } }; return client.crypto.backupManager.backupGroupSession( diff --git a/spec/unit/event-mapper.spec.ts b/spec/unit/event-mapper.spec.ts index a444c34fb0c..c21348c80e4 100644 --- a/spec/unit/event-mapper.spec.ts +++ b/spec/unit/event-mapper.spec.ts @@ -29,7 +29,7 @@ describe("eventMapperFor", function() { client = new MatrixClient({ baseUrl: "https://my.home.server", accessToken: "my.access.token", - request: function() {} as any, // NOP + fetchFn: function() {} as any, // NOP store: { getRoom(roomId: string): Room | null { return rooms.find(r => r.roomId === roomId); diff --git a/spec/unit/matrix-client.spec.ts b/spec/unit/matrix-client.spec.ts index f854d600835..458c05f203e 100644 --- a/spec/unit/matrix-client.spec.ts +++ b/spec/unit/matrix-client.spec.ts @@ -132,7 +132,6 @@ describe("MatrixClient", function() { method: method, path: path, }; - pendingLookup.promise.abort = () => {}; // to make it a valid IAbortablePromise return pendingLookup.promise; } if (next.path === path && next.method === method) { @@ -178,7 +177,7 @@ describe("MatrixClient", function() { baseUrl: "https://my.home.server", idBaseUrl: identityServerUrl, accessToken: "my.access.token", - request: function() {} as any, // NOP + fetchFn: function() {} as any, // NOP store: store, scheduler: scheduler, userId: userId, diff --git a/spec/unit/models/MSC3089TreeSpace.spec.ts b/spec/unit/models/MSC3089TreeSpace.spec.ts index fdc8101ebb8..2e72d44be8a 100644 --- a/spec/unit/models/MSC3089TreeSpace.spec.ts +++ b/spec/unit/models/MSC3089TreeSpace.spec.ts @@ -890,9 +890,8 @@ describe("MSC3089TreeSpace", () => { expect(contents.length).toEqual(fileContents.length); expect(opts).toMatchObject({ includeFilename: false, - onlyContentUri: true, // because the tests rely on this - we shouldn't really be testing for this. }); - return Promise.resolve(mxc); + return { promise: Promise.resolve({ content_uri: mxc }) }; }); client.uploadContent = uploadFn; @@ -950,9 +949,8 @@ describe("MSC3089TreeSpace", () => { expect(contents.length).toEqual(fileContents.length); expect(opts).toMatchObject({ includeFilename: false, - onlyContentUri: true, // because the tests rely on this - we shouldn't really be testing for this. }); - return Promise.resolve(mxc); + return { promise: Promise.resolve({ content_uri: mxc }) }; }); client.uploadContent = uploadFn; diff --git a/spec/unit/pusher.spec.ts b/spec/unit/pusher.spec.ts index 4a27ef55b5b..dd46770a4aa 100644 --- a/spec/unit/pusher.spec.ts +++ b/spec/unit/pusher.spec.ts @@ -16,7 +16,7 @@ limitations under the License. import MockHttpBackend from 'matrix-mock-request'; -import { IHttpOpts, MatrixClient, PUSHER_ENABLED } from "../../src/matrix"; +import { MatrixClient, PUSHER_ENABLED } from "../../src/matrix"; import { mkPusher } from '../test-utils/test-utils'; const realSetTimeout = setTimeout; @@ -35,7 +35,7 @@ describe("Pushers", () => { client = new MatrixClient({ baseUrl: "https://my.home.server", accessToken: "my.access.token", - request: httpBackend.requestFn as unknown as IHttpOpts["request"], + fetchFn: httpBackend.fetchFn as typeof global.fetch, }); }); diff --git a/spec/unit/queueToDevice.spec.ts b/spec/unit/queueToDevice.spec.ts index a1ae2bcfe93..c5b1f8a29d2 100644 --- a/spec/unit/queueToDevice.spec.ts +++ b/spec/unit/queueToDevice.spec.ts @@ -17,7 +17,7 @@ limitations under the License. import MockHttpBackend from 'matrix-mock-request'; import { indexedDB as fakeIndexedDB } from 'fake-indexeddb'; -import { IHttpOpts, IndexedDBStore, MatrixEvent, MemoryStore, Room } from "../../src"; +import { IndexedDBStore, MatrixEvent, MemoryStore, Room } from "../../src"; import { MatrixClient } from "../../src/client"; import { ToDeviceBatch } from '../../src/models/ToDeviceMessage'; import { logger } from '../../src/logger'; @@ -89,7 +89,7 @@ describe.each([ client = new MatrixClient({ baseUrl: "https://my.home.server", accessToken: "my.access.token", - request: httpBackend.requestFn as IHttpOpts["request"], + fetchFn: httpBackend.fetchFn as typeof global.fetch, store, }); }); diff --git a/spec/unit/read-receipt.spec.ts b/spec/unit/read-receipt.spec.ts index 2e906a3cc41..f5345ca558f 100644 --- a/spec/unit/read-receipt.spec.ts +++ b/spec/unit/read-receipt.spec.ts @@ -18,7 +18,6 @@ import MockHttpBackend from 'matrix-mock-request'; import { ReceiptType } from '../../src/@types/read_receipts'; import { MatrixClient } from "../../src/client"; -import { IHttpOpts } from '../../src/http-api'; import { EventType } from '../../src/matrix'; import { MAIN_ROOM_TIMELINE } from '../../src/models/read-receipt'; import { encodeUri } from '../../src/utils'; @@ -87,7 +86,7 @@ describe("Read receipt", () => { client = new MatrixClient({ baseUrl: "https://my.home.server", accessToken: "my.access.token", - request: httpBackend.requestFn as unknown as IHttpOpts["request"], + fetchFn: httpBackend.fetchFn as typeof global.fetch, }); client.isGuest = () => false; }); diff --git a/spec/unit/utils.spec.ts b/spec/unit/utils.spec.ts index 5d804022ede..117f4c88c96 100644 --- a/spec/unit/utils.spec.ts +++ b/spec/unit/utils.spec.ts @@ -26,9 +26,7 @@ describe("utils", function() { foo: "bar", baz: "beer@", }; - expect(utils.encodeParams(params)).toEqual( - "foo=bar&baz=beer%40", - ); + expect(utils.encodeParams(params).toString()).toEqual("foo=bar&baz=beer%40"); }); it("should handle boolean and numeric values", function() { @@ -37,7 +35,7 @@ describe("utils", function() { number: 12345, boolean: false, }; - expect(utils.encodeParams(params)).toEqual("string=foobar&number=12345&boolean=false"); + expect(utils.encodeParams(params).toString()).toEqual("string=foobar&number=12345&boolean=false"); }); }); diff --git a/src/@types/partials.ts b/src/@types/partials.ts index a729d80dc64..bf27eab0e53 100644 --- a/src/@types/partials.ts +++ b/src/@types/partials.ts @@ -40,11 +40,6 @@ export enum Preset { export type ResizeMethod = "crop" | "scale"; -// TODO move to http-api after TSification -export interface IAbortablePromise extends Promise { - abort(): void; -} - export type IdServerUnbindResult = "no-support" | "success"; // Knock and private are reserved keywords which are not yet implemented. diff --git a/src/@types/requests.ts b/src/@types/requests.ts index 15e2faa0c15..c746be8e959 100644 --- a/src/@types/requests.ts +++ b/src/@types/requests.ts @@ -118,15 +118,6 @@ export interface IRoomDirectoryOptions { third_party_instance_id?: string; } -export interface IUploadOpts { - name?: string; - includeFilename?: boolean; - type?: string; - rawResponse?: boolean; - onlyContentUri?: boolean; - progressHandler?: (state: {loaded: number, total: number}) => void; -} - export interface IAddThreePidOnlyBody { auth?: { type: string; diff --git a/src/ToDeviceMessageQueue.ts b/src/ToDeviceMessageQueue.ts index 12827d8bbc8..18cd9b093d7 100644 --- a/src/ToDeviceMessageQueue.ts +++ b/src/ToDeviceMessageQueue.ts @@ -28,7 +28,7 @@ const MAX_BATCH_SIZE = 20; export class ToDeviceMessageQueue { private sending = false; private running = true; - private retryTimeout: number = null; + private retryTimeout: ReturnType = null; private retryAttempts = 0; constructor(private client: MatrixClient) { diff --git a/src/autodiscovery.ts b/src/autodiscovery.ts index 71cbd2105f9..90e9558c756 100644 --- a/src/autodiscovery.ts +++ b/src/autodiscovery.ts @@ -17,10 +17,9 @@ limitations under the License. /** @module auto-discovery */ -import { ServerResponse } from "http"; - import { IClientWellKnown, IWellKnownConfig } from "./client"; import { logger } from './logger'; +import { Method, timeoutSignal } from "./http-api"; // Dev note: Auto discovery is part of the spec. // See: https://matrix.org/docs/spec/client_server/r0.4.0.html#server-discovery @@ -395,6 +394,12 @@ export class AutoDiscovery { } } + private static fetch = global.fetch; + + public static setFetchFn(fetchFn: typeof global.fetch): void { + AutoDiscovery.fetch = fetchFn; + } + /** * Fetches a JSON object from a given URL, as expected by all .well-known * related lookups. If the server gives a 404 then the `action` will be @@ -411,45 +416,53 @@ export class AutoDiscovery { * @return {Promise} Resolves to the returned state. * @private */ - private static fetchWellKnownObject(uri: string): Promise { - return new Promise((resolve) => { - // eslint-disable-next-line - const request = require("./matrix").getRequest(); - if (!request) throw new Error("No request library available"); - request( - { method: "GET", uri, timeout: 5000 }, - (error: Error, response: ServerResponse, body: string) => { - if (error || response?.statusCode < 200 || response?.statusCode >= 300) { - const result = { error, raw: {} }; - return resolve(response?.statusCode === 404 - ? { - ...result, - action: AutoDiscoveryAction.IGNORE, - reason: AutoDiscovery.ERROR_MISSING_WELLKNOWN, - } : { - ...result, - action: AutoDiscoveryAction.FAIL_PROMPT, - reason: error?.message || "General failure", - }); - } - - try { - return resolve({ - raw: JSON.parse(body), - action: AutoDiscoveryAction.SUCCESS, - }); - } catch (err) { - return resolve({ - error: err, - raw: {}, - action: AutoDiscoveryAction.FAIL_PROMPT, - reason: err?.name === "SyntaxError" - ? AutoDiscovery.ERROR_INVALID_JSON - : AutoDiscovery.ERROR_INVALID, - }); - } - }, - ); - }); + private static async fetchWellKnownObject(url: string): Promise { + let response: Response; + + try { + response = await AutoDiscovery.fetch(url, { + method: Method.Get, + signal: timeoutSignal(5000), + }); + + if (response.status === 404) { + return { + raw: {}, + action: AutoDiscoveryAction.IGNORE, + reason: AutoDiscovery.ERROR_MISSING_WELLKNOWN, + }; + } + + if (!response.ok) { + return { + raw: {}, + action: AutoDiscoveryAction.FAIL_PROMPT, + reason: "General failure", + }; + } + } catch (error) { + return { + error, + raw: {}, + action: AutoDiscoveryAction.FAIL_PROMPT, + reason: error?.message || "General failure", + }; + } + + try { + return { + raw: await response.json(), + action: AutoDiscoveryAction.SUCCESS, + }; + } catch (err) { + return { + error: err, + raw: {}, + action: AutoDiscoveryAction.FAIL_PROMPT, + reason: err?.name === "SyntaxError" + ? AutoDiscovery.ERROR_INVALID_JSON + : AutoDiscovery.ERROR_INVALID, + }; + } } } diff --git a/src/browser-index.js b/src/browser-index.js index 3e3627fa9d8..86e887bd49f 100644 --- a/src/browser-index.js +++ b/src/browser-index.js @@ -14,25 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import request from "browser-request"; -import queryString from "qs"; - import * as matrixcs from "./matrix"; -if (matrixcs.getRequest()) { +if (global.__js_sdk_entrypoint) { throw new Error("Multiple matrix-js-sdk entrypoints detected!"); } - -matrixcs.request(function(opts, fn) { - // We manually fix the query string for browser-request because - // it doesn't correctly handle cases like ?via=one&via=two. Instead - // we mimic `request`'s query string interface to make it all work - // as expected. - // browser-request will happily take the constructed string as the - // query string without trying to modify it further. - opts.qs = queryString.stringify(opts.qs || {}, opts.qsStringifyOptions); - return request(opts, fn); -}); +global.__js_sdk_entrypoint = true; // just *accessing* indexedDB throws an exception in firefox with // indexeddb disabled. diff --git a/src/client.ts b/src/client.ts index f68e7c98313..6d65037c801 100644 --- a/src/client.ts +++ b/src/client.ts @@ -49,19 +49,17 @@ import { IRoomEncryption, RoomList } from './crypto/RoomList'; import { logger } from './logger'; import { SERVICE_TYPES } from './service-types'; import { - FileType, HttpApiEvent, HttpApiEventHandlerMap, - IHttpOpts, - IUpload, + Upload, + UploadOpts, MatrixError, MatrixHttpApi, Method, retryNetworkOperation, - UploadContentResponseType, ClientPrefix, MediaPrefix, - IdentityPrefix, + IdentityPrefix, IHttpOpts, FileType, } from "./http-api"; import { Crypto, @@ -151,7 +149,6 @@ import { IRoomDirectoryOptions, ISearchOpts, ISendEventResponse, - IUploadOpts, } from "./@types/requests"; import { EventType, @@ -165,7 +162,7 @@ import { UNSTABLE_MSC3088_PURPOSE, UNSTABLE_MSC3089_TREE_SUBTYPE, } from "./@types/event"; -import { IAbortablePromise, IdServerUnbindResult, IImageInfo, Preset, Visibility } from "./@types/partials"; +import { IdServerUnbindResult, IImageInfo, Preset, Visibility } from "./@types/partials"; import { EventMapper, eventMapperFor, MapperOpts } from "./event-mapper"; import { randomString } from "./randomstring"; import { BackupManager, IKeyBackup, IKeyBackupCheck, IPreparedKeyBackupVersion, TrustInfo } from "./crypto/backup"; @@ -251,12 +248,10 @@ export interface ICreateClientOpts { scheduler?: MatrixScheduler; /** - * The function to invoke for HTTP - * requests. The value of this property is typically require("request") - * as it returns a function which meets the required interface. See - * {@link requestFunction} for more information. + * The function to invoke for HTTP requests. + * Most supported environments have a global `fetch` registered to which this will fall back. */ - request?: IHttpOpts["request"]; + fetchFn?: typeof global.fetch; userId?: string; @@ -918,7 +913,7 @@ export class MatrixClient extends TypedEventEmitter } = {}; public identityServer: IIdentityServerProvider; - public http: MatrixHttpApi; // XXX: Intended private, used in code. + public http: MatrixHttpApi; // XXX: Intended private, used in code. public crypto?: Crypto; // XXX: Intended private, used in code. public cryptoCallbacks: ICryptoCallbacks; // XXX: Intended private, used in code. public callEventHandler: CallEventHandler; // XXX: Intended private, used in code. @@ -993,10 +988,10 @@ export class MatrixClient extends TypedEventEmitter[0], { + fetchFn: opts.fetchFn, baseUrl: opts.baseUrl, idBaseUrl: opts.idBaseUrl, accessToken: opts.accessToken, - request: opts.request, prefix: ClientPrefix.R0, onlyData: true, extraParams: opts.queryParams, @@ -3531,7 +3526,7 @@ export class MatrixClient extends TypedEventEmitter( - file: FileType, - opts?: O, - ): IAbortablePromise> { - return this.http.uploadContent(file, opts); + public uploadContent(file: FileType, opts?: UploadOpts): Upload { + return this.http.uploadContent(file, opts); } /** * Cancel a file upload in progress - * @param {Promise} promise The promise returned from uploadContent + * @param {Promise} upload The object returned from uploadContent * @return {boolean} true if canceled, otherwise false */ - public cancelUpload(promise: IAbortablePromise): boolean { - return this.http.cancelUpload(promise); + public cancelUpload(upload: Upload): boolean { + return this.http.cancelUpload(upload); } /** @@ -7637,7 +7627,7 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types - const params = { - sid: sid, - client_secret: clientSecret, - token: msisdnToken, - }; - - return this.http.requestOtherUrl(Method.Post, url, undefined, params); + const u = new URL(url); + u.searchParams.set("sid", sid); + u.searchParams.set("client_secret", clientSecret); + u.searchParams.set("token", msisdnToken); + return this.http.requestOtherUrl(Method.Post, u); } /** @@ -8651,10 +8639,13 @@ export class MatrixClient extends TypedEventEmitter { // TODO: Types const url = this.termsUrlForService(serviceType, baseUrl); + utils.encodeParams({ + user_accepts: termsUrls, + }, url.searchParams); const headers = { Authorization: "Bearer " + accessToken, }; - return this.http.requestOtherUrl(Method.Post, url, null, { user_accepts: termsUrls }, { headers }); + return this.http.requestOtherUrl(Method.Post, url, null, { headers }); } /** @@ -8792,7 +8783,7 @@ export class MatrixClient extends TypedEventEmitter { + ): Promise { const qps: Record = {}; if (req.pos) { qps.pos = req.pos; diff --git a/src/http-api.ts b/src/http-api.ts deleted file mode 100644 index ed0ae10435a..00000000000 --- a/src/http-api.ts +++ /dev/null @@ -1,1064 +0,0 @@ -/* -Copyright 2015, 2016 OpenMarket Ltd -Copyright 2019 - 2021 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -/** - * This is an internal module. See {@link MatrixHttpApi} for the public class. - * @module http-api - */ - -import { parse as parseContentType, ParsedMediaType } from "content-type"; - -import type { IncomingHttpHeaders, IncomingMessage } from "http"; -import type { Request as _Request, CoreOptions } from "request"; -// we use our own implementation of setTimeout, so that if we get suspended in -// the middle of a /sync, we cancel the sync as soon as we awake, rather than -// waiting for the delay to elapse. -import * as callbacks from "./realtime-callbacks"; -import { IUploadOpts } from "./@types/requests"; -import { IAbortablePromise, IUsageLimit } from "./@types/partials"; -import { IDeferred, sleep } from "./utils"; -import * as utils from "./utils"; -import { logger } from './logger'; -import { MediaPrefix } from "./http-api/prefix"; -import { TypedEventEmitter } from "./models/typed-event-emitter"; - -/* -TODO: -- CS: complete register function (doing stages) -- Identity server: linkEmail, authEmail, bindEmail, lookup3pid -*/ - -type RequestProps = "method" - | "withCredentials" - | "json" - | "headers" - | "qs" - | "body" - | "qsStringifyOptions" - | "useQuerystring" - | "timeout"; - -export interface IHttpOpts { - baseUrl: string; - idBaseUrl?: string; - prefix: string; - onlyData: boolean; - accessToken?: string; - extraParams?: Record; - localTimeoutMs?: number; - useAuthorizationHeader?: boolean; - request(opts: Pick & { - uri: string; - method: Method; - // eslint-disable-next-line camelcase - _matrix_opts: IHttpOpts; - }, callback: RequestCallback): IRequest; -} - -interface IRequest extends _Request { - onprogress?(e: unknown): void; -} - -interface IRequestOpts { - prefix?: string; - baseUrl?: string; - localTimeoutMs?: number; - headers?: Record; - json?: boolean; // defaults to true - qsStringifyOptions?: CoreOptions["qsStringifyOptions"]; - bodyParser?(body: string): T; - - // Set to true to prevent the request function from emitting - // a Session.logged_out event. This is intended for use on - // endpoints where M_UNKNOWN_TOKEN is a valid/notable error - // response, such as with token refreshes. - inhibitLogoutEmit?: boolean; -} - -export interface IUpload { - loaded: number; - total: number; - promise: IAbortablePromise; -} - -interface IContentUri { - base: string; - path: string; - params: { - // eslint-disable-next-line camelcase - access_token: string; - }; -} - -type ResponseType | void = void> = - O extends { bodyParser: (body: string) => T } ? T : - O extends { json: false } ? string : - T; - -interface IUploadResponse { - // eslint-disable-next-line camelcase - content_uri: string; -} - -// This type's defaults only work for the Browser -// in the Browser we default rawResponse = false & onlyContentUri = true -// in Node we default rawResponse = true & onlyContentUri = false -export type UploadContentResponseType = - O extends undefined ? string : - O extends { rawResponse: true } ? string : - O extends { onlyContentUri: true } ? string : - O extends { rawResponse: false } ? IUploadResponse : - O extends { onlyContentUri: false } ? IUploadResponse : - string; - -export enum Method { - Get = "GET", - Put = "PUT", - Post = "POST", - Delete = "DELETE", -} - -export * from "./http-api/prefix"; - -export type FileType = Document | XMLHttpRequestBodyInit; - -export enum HttpApiEvent { - SessionLoggedOut = "Session.logged_out", - NoConsent = "no_consent", -} - -export type HttpApiEventHandlerMap = { - [HttpApiEvent.SessionLoggedOut]: (err: MatrixError) => void; - [HttpApiEvent.NoConsent]: (message: string, consentUri: string) => void; -}; - -/** - * Construct a MatrixHttpApi. - * @constructor - * @param {EventEmitter} eventEmitter The event emitter to use for emitting events - * @param {Object} opts The options to use for this HTTP API. - * @param {string} opts.baseUrl Required. The base client-server URL e.g. - * 'http://localhost:8008'. - * @param {Function} opts.request Required. The function to call for HTTP - * requests. This function must look like function(opts, callback){ ... }. - * @param {string} opts.prefix Required. The matrix client prefix to use, e.g. - * '/_matrix/client/r0'. See PREFIX_R0 and PREFIX_UNSTABLE for constants. - * - * @param {boolean} opts.onlyData True to return only the 'data' component of the - * response (e.g. the parsed HTTP body). If false, requests will return an - * object with the properties code, headers and data. - * - * @param {string=} opts.accessToken The access_token to send with requests. Can be - * null to not send an access token. - * @param {Object=} opts.extraParams Optional. Extra query parameters to send on - * requests. - * @param {Number=} opts.localTimeoutMs The default maximum amount of time to wait - * before timing out the request. If not specified, there is no timeout. - * @param {boolean} [opts.useAuthorizationHeader = false] Set to true to use - * Authorization header instead of query param to send the access token to the server. - */ -export class MatrixHttpApi { - private uploads: IUpload[] = []; - - constructor( - private eventEmitter: TypedEventEmitter, - public readonly opts: IHttpOpts, - ) { - utils.checkObjectHasKeys(opts, ["baseUrl", "request", "prefix"]); - opts.onlyData = !!opts.onlyData; - opts.useAuthorizationHeader = opts.useAuthorizationHeader ?? true; - } - - /** - * Sets the base URL for the identity server - * @param {string} url The new base url - */ - public setIdBaseUrl(url: string): void { - this.opts.idBaseUrl = url; - } - - /** - * Get the content repository url with query parameters. - * @return {Object} An object with a 'base', 'path' and 'params' for base URL, - * path and query parameters respectively. - */ - public getContentUri(): IContentUri { - return { - base: this.opts.baseUrl, - path: "/_matrix/media/r0/upload", - params: { - access_token: this.opts.accessToken, - }, - }; - } - - /** - * Upload content to the homeserver - * - * @param {object} file The object to upload. On a browser, something that - * can be sent to XMLHttpRequest.send (typically a File). Under node.js, - * a Buffer, String or ReadStream. - * - * @param {object} opts options object - * - * @param {string=} opts.name Name to give the file on the server. Defaults - * to file.name. - * - * @param {boolean=} opts.includeFilename if false will not send the filename, - * e.g for encrypted file uploads where filename leaks are undesirable. - * Defaults to true. - * - * @param {string=} opts.type Content-type for the upload. Defaults to - * file.type, or applicaton/octet-stream. - * - * @param {boolean=} opts.rawResponse Return the raw body, rather than - * parsing the JSON. Defaults to false (except on node.js, where it - * defaults to true for backwards compatibility). - * - * @param {boolean=} opts.onlyContentUri Just return the content URI, - * rather than the whole body. Defaults to false (except on browsers, - * where it defaults to true for backwards compatibility). Ignored if - * opts.rawResponse is true. - * - * @param {Function=} opts.progressHandler Optional. Called when a chunk of - * data has been uploaded, with an object containing the fields `loaded` - * (number of bytes transferred) and `total` (total size, if known). - * - * @return {Promise} Resolves to response object, as - * determined by this.opts.onlyData, opts.rawResponse, and - * opts.onlyContentUri. Rejects with an error (usually a MatrixError). - */ - public uploadContent( - file: FileType, - opts: O = {} as O, - ): IAbortablePromise> { - // default opts.includeFilename to true (ignoring falsey values) - const includeFilename = opts.includeFilename !== false; - - // if the file doesn't have a mime type, use a default since - // the HS errors if we don't supply one. - const contentType = opts.type || (file as File).type || 'application/octet-stream'; - const fileName = opts.name || (file as File).name; - - // We used to recommend setting file.stream to the thing to upload on - // Node.js. As of 2019-06-11, this is still in widespread use in various - // clients, so we should preserve this for simple objects used in - // Node.js. File API objects (via either the File or Blob interfaces) in - // the browser now define a `stream` method, which leads to trouble - // here, so we also check the type of `stream`. - let body = file; - const bodyStream = (body as File | Blob).stream; // this type is wrong but for legacy reasons is good enough - if (bodyStream && typeof bodyStream !== "function") { - logger.warn( - "Using `file.stream` as the content to upload. Future " + - "versions of the js-sdk will change this to expect `file` to " + - "be the content directly.", - ); - body = bodyStream; - } - - // backwards-compatibility hacks where we used to do different things - // between browser and node. - let rawResponse = opts.rawResponse; - if (rawResponse === undefined) { - if (global.XMLHttpRequest) { - rawResponse = false; - } else { - logger.warn( - "Returning the raw JSON from uploadContent(). Future " + - "versions of the js-sdk will change this default, to " + - "return the parsed object. Set opts.rawResponse=false " + - "to change this behaviour now.", - ); - rawResponse = true; - } - } - - let onlyContentUri = opts.onlyContentUri; - if (!rawResponse && onlyContentUri === undefined) { - if (global.XMLHttpRequest) { - logger.warn( - "Returning only the content-uri from uploadContent(). " + - "Future versions of the js-sdk will change this " + - "default, to return the whole response object. Set " + - "opts.onlyContentUri=false to change this behaviour now.", - ); - onlyContentUri = true; - } else { - onlyContentUri = false; - } - } - - // browser-request doesn't support File objects because it deep-copies - // the options using JSON.parse(JSON.stringify(options)). Instead of - // loading the whole file into memory as a string and letting - // browser-request base64 encode and then decode it again, we just - // use XMLHttpRequest directly. - // (browser-request doesn't support progress either, which is also kind - // of important here) - - const upload = { loaded: 0, total: 0 } as IUpload; - let promise: IAbortablePromise>; - - // XMLHttpRequest doesn't parse JSON for us. request normally does, but - // we're setting opts.json=false so that it doesn't JSON-encode the - // request, which also means it doesn't JSON-decode the response. Either - // way, we have to JSON-parse the response ourselves. - let bodyParser: ((body: string) => any) | undefined; - if (!rawResponse) { - bodyParser = function(rawBody: string) { - let body = JSON.parse(rawBody); - if (onlyContentUri) { - body = body.content_uri; - if (body === undefined) { - throw Error('Bad response'); - } - } - return body; - }; - } - - if (global.XMLHttpRequest) { - const defer = utils.defer>(); - const xhr = new global.XMLHttpRequest(); - const cb = requestCallback(defer, this.opts.onlyData); - - const timeoutFn = function() { - xhr.abort(); - cb(new Error('Timeout')); - }; - - // set an initial timeout of 30s; we'll advance it each time we get a progress notification - let timeoutTimer = callbacks.setTimeout(timeoutFn, 30000); - - xhr.onreadystatechange = function() { - let resp: string; - switch (xhr.readyState) { - case global.XMLHttpRequest.DONE: - callbacks.clearTimeout(timeoutTimer); - try { - if (xhr.status === 0) { - throw new AbortError(); - } - if (!xhr.responseText) { - throw new Error('No response body.'); - } - resp = xhr.responseText; - if (bodyParser) { - resp = bodyParser(resp); - } - } catch (err) { - err.httpStatus = xhr.status; - cb(err); - return; - } - cb(undefined, xhr, resp); - break; - } - }; - xhr.upload.addEventListener("progress", function(ev) { - callbacks.clearTimeout(timeoutTimer); - upload.loaded = ev.loaded; - upload.total = ev.total; - timeoutTimer = callbacks.setTimeout(timeoutFn, 30000); - if (opts.progressHandler) { - opts.progressHandler({ - loaded: ev.loaded, - total: ev.total, - }); - } - }); - let url = this.opts.baseUrl + MediaPrefix.R0 + "/upload"; - - const queryArgs = []; - - if (includeFilename && fileName) { - queryArgs.push("filename=" + encodeURIComponent(fileName)); - } - - if (!this.opts.useAuthorizationHeader) { - queryArgs.push("access_token=" + encodeURIComponent(this.opts.accessToken)); - } - - if (queryArgs.length > 0) { - url += "?" + queryArgs.join("&"); - } - - xhr.open("POST", url); - if (this.opts.useAuthorizationHeader) { - xhr.setRequestHeader("Authorization", "Bearer " + this.opts.accessToken); - } - xhr.setRequestHeader("Content-Type", contentType); - xhr.send(body); - promise = defer.promise as IAbortablePromise>; - - // dirty hack (as per doRequest) to allow the upload to be cancelled. - promise.abort = xhr.abort.bind(xhr); - } else { - const queryParams: Record = {}; - - if (includeFilename && fileName) { - queryParams.filename = fileName; - } - - const headers: Record = { "Content-Type": contentType }; - - // authedRequest uses `request` which is no longer maintained. - // `request` has a bug where if the body is zero bytes then you get an error: `Argument error, options.body`. - // See https://github.com/request/request/issues/920 - // if body looks like a byte array and empty then set the Content-Length explicitly as a workaround: - if ((body as unknown as ArrayLike).length === 0) { - headers["Content-Length"] = "0"; - } - - promise = this.authedRequest>( - Method.Post, "/upload", queryParams, body, { - prefix: MediaPrefix.R0, - headers, - json: false, - bodyParser, - }, - ); - } - - // remove the upload from the list on completion - upload.promise = promise.finally(() => { - for (let i = 0; i < this.uploads.length; ++i) { - if (this.uploads[i] === upload) { - this.uploads.splice(i, 1); - return; - } - } - }) as IAbortablePromise>; - - // copy our dirty abort() method to the new promise - upload.promise.abort = promise.abort; - this.uploads.push(upload); - - return upload.promise as IAbortablePromise>; - } - - public cancelUpload(promise: IAbortablePromise): boolean { - if (promise.abort) { - promise.abort(); - return true; - } - return false; - } - - public getCurrentUploads(): IUpload[] { - return this.uploads; - } - - public idServerRequest( - method: Method, - path: string, - params: Record, - prefix: string, - accessToken: string, - ): Promise { - if (!this.opts.idBaseUrl) { - throw new Error("No identity server base URL set"); - } - - const fullUri = this.opts.idBaseUrl + prefix + path; - - const opts = { - uri: fullUri, - method, - withCredentials: false, - json: true, // we want a JSON response if we can - _matrix_opts: this.opts, - headers: {}, - } as Parameters[0]; - - if (method === Method.Get) { - opts.qs = params; - } else if (typeof params === "object") { - opts.json = params; - } - - if (accessToken) { - opts.headers['Authorization'] = `Bearer ${accessToken}`; - } - - const defer = utils.defer(); - this.opts.request(opts, requestCallback(defer, this.opts.onlyData)); - return defer.promise; - } - - /** - * Perform an authorised request to the homeserver. - * @param {string} method The HTTP method e.g. "GET". - * @param {string} path The HTTP path after the supplied prefix e.g. - * "/createRoom". - * - * @param {Object=} queryParams A dict of query params (these will NOT be - * urlencoded). If unspecified, there will be no query params. - * - * @param {Object} [data] The HTTP JSON body. - * - * @param {Object|Number=} opts additional options. If a number is specified, - * this is treated as `opts.localTimeoutMs`. - * - * @param {Number=} opts.localTimeoutMs The maximum amount of time to wait before - * timing out the request. If not specified, there is no timeout. - * - * @param {string=} opts.prefix The full prefix to use e.g. - * "/_matrix/client/v2_alpha". If not specified, uses this.opts.prefix. - * - * @param {string=} opts.baseUrl The alternative base url to use. - * If not specified, uses this.opts.baseUrl - * - * @param {Object=} opts.headers map of additional request headers - * - * @return {Promise} Resolves to {data: {Object}, - * headers: {Object}, code: {Number}}. - * If onlyData is set, this will resolve to the data - * object only. - * @return {module:http-api.MatrixError} Rejects with an error if a problem - * occurred. This includes network problems and Matrix-specific error JSON. - */ - public authedRequest = IRequestOpts>( - method: Method, - path: string, - queryParams?: Record, - data?: CoreOptions["body"], - opts?: O | number, // number is legacy - ): IAbortablePromise> { - if (!queryParams) queryParams = {}; - let requestOpts = (opts || {}) as O; - - if (this.opts.useAuthorizationHeader) { - if (isFinite(opts as number)) { - // opts used to be localTimeoutMs - requestOpts = { - localTimeoutMs: opts as number, - } as O; - } - - if (!requestOpts.headers) { - requestOpts.headers = {}; - } - if (!requestOpts.headers.Authorization) { - requestOpts.headers.Authorization = "Bearer " + this.opts.accessToken; - } - if (queryParams.access_token) { - delete queryParams.access_token; - } - } else if (!queryParams.access_token) { - queryParams.access_token = this.opts.accessToken; - } - - const requestPromise = this.request(method, path, queryParams, data, requestOpts); - - requestPromise.catch((err: MatrixError) => { - if (err.errcode == 'M_UNKNOWN_TOKEN' && !requestOpts?.inhibitLogoutEmit) { - this.eventEmitter.emit(HttpApiEvent.SessionLoggedOut, err); - } else if (err.errcode == 'M_CONSENT_NOT_GIVEN') { - this.eventEmitter.emit(HttpApiEvent.NoConsent, err.message, err.data.consent_uri); - } - }); - - // return the original promise, otherwise tests break due to it having to - // go around the event loop one more time to process the result of the request - return requestPromise; - } - - /** - * Perform a request to the homeserver without any credentials. - * @param {string} method The HTTP method e.g. "GET". - * @param {string} path The HTTP path after the supplied prefix e.g. - * "/createRoom". - * - * @param {Object=} queryParams A dict of query params (these will NOT be - * urlencoded). If unspecified, there will be no query params. - * - * @param {Object} [data] The HTTP JSON body. - * - * @param {Object=} opts additional options - * - * @param {Number=} opts.localTimeoutMs The maximum amount of time to wait before - * timing out the request. If not specified, there is no timeout. - * - * @param {string=} opts.prefix The full prefix to use e.g. - * "/_matrix/client/v2_alpha". If not specified, uses this.opts.prefix. - * - * @param {Object=} opts.headers map of additional request headers - * - * @return {Promise} Resolves to {data: {Object}, - * headers: {Object}, code: {Number}}. - * If onlyData is set, this will resolve to the data - * object only. - * @return {module:http-api.MatrixError} Rejects with an error if a problem - * occurred. This includes network problems and Matrix-specific error JSON. - */ - public request = IRequestOpts>( - method: Method, - path: string, - queryParams?: CoreOptions["qs"], - data?: CoreOptions["body"], - opts?: O, - ): IAbortablePromise> { - const prefix = opts?.prefix ?? this.opts.prefix; - const baseUrl = opts?.baseUrl ?? this.opts.baseUrl; - const fullUri = baseUrl + prefix + path; - - return this.requestOtherUrl(method, fullUri, queryParams, data, opts); - } - - /** - * Perform a request to an arbitrary URL. - * @param {string} method The HTTP method e.g. "GET". - * @param {string} uri The HTTP URI - * - * @param {Object=} queryParams A dict of query params (these will NOT be - * urlencoded). If unspecified, there will be no query params. - * - * @param {Object} [data] The HTTP JSON body. - * - * @param {Object=} opts additional options - * - * @param {Number=} opts.localTimeoutMs The maximum amount of time to wait before - * timing out the request. If not specified, there is no timeout. - * - * @param {string=} opts.prefix The full prefix to use e.g. - * "/_matrix/client/v2_alpha". If not specified, uses this.opts.prefix. - * - * @param {Object=} opts.headers map of additional request headers - * - * @return {Promise} Resolves to {data: {Object}, - * headers: {Object}, code: {Number}}. - * If onlyData is set, this will resolve to the data - * object only. - * @return {module:http-api.MatrixError} Rejects with an error if a problem - * occurred. This includes network problems and Matrix-specific error JSON. - */ - public requestOtherUrl = IRequestOpts>( - method: Method, - uri: string, - queryParams?: CoreOptions["qs"], - data?: CoreOptions["body"], - opts?: O | number, // number is legacy - ): IAbortablePromise> { - let requestOpts = (opts || {}) as O; - if (isFinite(opts as number)) { - // opts used to be localTimeoutMs - requestOpts = { - localTimeoutMs: opts as number, - } as O; - } - - return this.doRequest(method, uri, queryParams, data, requestOpts); - } - - /** - * Form and return a homeserver request URL based on the given path - * params and prefix. - * @param {string} path The HTTP path after the supplied prefix e.g. - * "/createRoom". - * @param {Object} queryParams A dict of query params (these will NOT be - * urlencoded). - * @param {string} prefix The full prefix to use e.g. - * "/_matrix/client/v2_alpha". - * @return {string} URL - */ - public getUrl(path: string, queryParams: CoreOptions["qs"], prefix: string): string { - let queryString = ""; - if (queryParams) { - queryString = "?" + utils.encodeParams(queryParams); - } - return this.opts.baseUrl + prefix + path + queryString; - } - - /** - * @private - * - * @param {string} method - * @param {string} uri - * @param {object} queryParams - * @param {object|string} data - * @param {object=} opts - * - * @param {boolean} [opts.json =true] Json-encode data before sending, and - * decode response on receipt. (We will still json-decode error - * responses, even if this is false.) - * - * @param {object=} opts.headers extra request headers - * - * @param {number=} opts.localTimeoutMs client-side timeout for the - * request. Default timeout if falsy. - * - * @param {function=} opts.bodyParser function to parse the body of the - * response before passing it to the promise and callback. - * - * @return {Promise} a promise which resolves to either the - * response object (if this.opts.onlyData is truthy), or the parsed - * body. Rejects - * - * Generic T is the callback/promise resolve type - * Generic O should be inferred - */ - private doRequest = IRequestOpts>( - method: Method, - uri: string, - queryParams?: Record, - data?: CoreOptions["body"], - opts?: O, - ): IAbortablePromise> { - if (this.opts.extraParams) { - queryParams = { - ...(queryParams || {}), - ...this.opts.extraParams, - }; - } - - const headers = Object.assign({}, opts.headers || {}); - if (!opts) opts = {} as O; - const json = opts.json ?? true; - let bodyParser = opts.bodyParser; - - // we handle the json encoding/decoding here, because request and - // browser-request make a mess of it. Specifically, they attempt to - // json-decode plain-text error responses, which in turn means that the - // actual error gets swallowed by a SyntaxError. - - if (json) { - if (data) { - data = JSON.stringify(data); - headers['content-type'] = 'application/json'; - } - - if (!headers['accept']) { - headers['accept'] = 'application/json'; - } - - if (bodyParser === undefined) { - bodyParser = function(rawBody: string) { - return JSON.parse(rawBody); - }; - } - } - - const defer = utils.defer(); - - let timeoutId: number; - let timedOut = false; - let req: IRequest; - const localTimeoutMs = opts.localTimeoutMs || this.opts.localTimeoutMs; - - const resetTimeout = () => { - if (localTimeoutMs) { - if (timeoutId) { - callbacks.clearTimeout(timeoutId); - } - timeoutId = callbacks.setTimeout(function() { - timedOut = true; - req?.abort?.(); - defer.reject(new MatrixError({ - error: "Locally timed out waiting for a response", - errcode: "ORG.MATRIX.JSSDK_TIMEOUT", - timeout: localTimeoutMs, - })); - }, localTimeoutMs); - } - }; - resetTimeout(); - - const reqPromise = defer.promise as IAbortablePromise>; - - try { - req = this.opts.request( - { - uri: uri, - method: method, - withCredentials: false, - qs: queryParams, - qsStringifyOptions: opts.qsStringifyOptions, - useQuerystring: true, - body: data, - json: false, - timeout: localTimeoutMs, - headers: headers || {}, - _matrix_opts: this.opts, - }, - (err, response, body) => { - if (localTimeoutMs) { - callbacks.clearTimeout(timeoutId); - if (timedOut) { - return; // already rejected promise - } - } - - const handlerFn = requestCallback(defer, this.opts.onlyData, bodyParser); - handlerFn(err, response, body); - }, - ); - if (req) { - // This will only work in a browser, where opts.request is the - // `browser-request` import. Currently, `request` does not support progress - // updates - see https://github.com/request/request/pull/2346. - // `browser-request` returns an XHRHttpRequest which exposes `onprogress` - if ('onprogress' in req) { - req.onprogress = (e) => { - // Prevent the timeout from rejecting the deferred promise if progress is - // seen with the request - resetTimeout(); - }; - } - - // FIXME: This is EVIL, but I can't think of a better way to expose - // abort() operations on underlying HTTP requests :( - if (req.abort) { - reqPromise.abort = req.abort.bind(req); - } - } - } catch (ex) { - defer.reject(ex); - } - return reqPromise; - } -} - -type RequestCallback = (err?: Error, response?: XMLHttpRequest | IncomingMessage, body?: string) => void; - -// if using onlyData=false then wrap your expected data type in this generic -export interface IResponse { - code: number; - data: T; - headers?: IncomingHttpHeaders; -} - -function getStatusCode(response: XMLHttpRequest | IncomingMessage): number { - return (response as XMLHttpRequest).status || (response as IncomingMessage).statusCode; -} - -/* - * Returns a callback that can be invoked by an HTTP request on completion, - * that will either resolve or reject the given defer as well as invoke the - * given userDefinedCallback (if any). - * - * HTTP errors are transformed into javascript errors and the deferred is rejected. - * - * If bodyParser is given, it is used to transform the body of the successful - * responses before passing to the defer/callback. - * - * If onlyData is true, the defer/callback is invoked with the body of the - * response, otherwise the result object (with `code` and `data` fields) - * - */ -function requestCallback( - defer: IDeferred, - onlyData = false, - bodyParser?: (body: string) => T, -): RequestCallback { - return function(err: Error, response: XMLHttpRequest | IncomingMessage, body: string): void { - if (err) { - // the unit tests use matrix-mock-request, which throw the string "aborted" when aborting a request. - // See https://github.com/matrix-org/matrix-mock-request/blob/3276d0263a561b5b8326b47bae720578a2c7473a/src/index.js#L48 - const aborted = err.name === "AbortError" || (err as any as string) === "aborted"; - if (!aborted && !(err instanceof MatrixError)) { - // browser-request just throws normal Error objects, - // not `TypeError`s like fetch does. So just assume any - // error is due to the connection. - err = new ConnectionError("request failed", err); - } - } - - let data: T | string = body; - - if (!err) { - try { - if (getStatusCode(response) >= 400) { - err = parseErrorResponse(response, body); - } else if (bodyParser) { - data = bodyParser(body); - } - } catch (e) { - err = new Error(`Error parsing server response: ${e}`); - } - } - - if (err) { - defer.reject(err); - } else if (onlyData) { - defer.resolve(data as T); - } else { - const res: IResponse = { - code: getStatusCode(response), - - // XXX: why do we bother with this? it doesn't work for - // XMLHttpRequest, so clearly we don't use it. - headers: (response as IncomingMessage).headers, - data: data as T, - }; - // XXX: the variations in caller-expected types here are horrible, - // typescript doesn't do conditional types based on runtime values - defer.resolve(res as any as T); - } - }; -} - -/** - * Attempt to turn an HTTP error response into a Javascript Error. - * - * If it is a JSON response, we will parse it into a MatrixError. Otherwise - * we return a generic Error. - * - * @param {XMLHttpRequest|http.IncomingMessage} response response object - * @param {String} body raw body of the response - * @returns {Error} - */ -function parseErrorResponse(response: XMLHttpRequest | IncomingMessage, body?: string) { - const httpStatus = getStatusCode(response); - const contentType = getResponseContentType(response); - - let err; - if (contentType) { - if (contentType.type === 'application/json') { - const jsonBody = typeof(body) === 'object' ? body : JSON.parse(body); - err = new MatrixError(jsonBody); - } else if (contentType.type === 'text/plain') { - err = new Error(`Server returned ${httpStatus} error: ${body}`); - } - } - - if (!err) { - err = new Error(`Server returned ${httpStatus} error`); - } - err.httpStatus = httpStatus; - return err; -} - -/** - * extract the Content-Type header from the response object, and - * parse it to a `{type, parameters}` object. - * - * returns null if no content-type header could be found. - * - * @param {XMLHttpRequest|http.IncomingMessage} response response object - * @returns {{type: String, parameters: Object}?} parsed content-type header, or null if not found - */ -function getResponseContentType(response: XMLHttpRequest | IncomingMessage): ParsedMediaType { - let contentType; - if ((response as XMLHttpRequest).getResponseHeader) { - // XMLHttpRequest provides getResponseHeader - contentType = (response as XMLHttpRequest).getResponseHeader("Content-Type"); - } else if ((response as IncomingMessage).headers) { - // request provides http.IncomingMessage which has a message.headers map - contentType = (response as IncomingMessage).headers['content-type'] || null; - } - - if (!contentType) { - return null; - } - - try { - return parseContentType(contentType); - } catch (e) { - throw new Error(`Error parsing Content-Type '${contentType}': ${e}`); - } -} - -interface IErrorJson extends Partial { - [key: string]: any; // extensible - errcode?: string; - error?: string; -} - -/** - * Construct a Matrix error. This is a JavaScript Error with additional - * information specific to the standard Matrix error response. - * @constructor - * @param {Object} errorJson The Matrix error JSON returned from the homeserver. - * @prop {string} errcode The Matrix 'errcode' value, e.g. "M_FORBIDDEN". - * @prop {string} name Same as MatrixError.errcode but with a default unknown string. - * @prop {string} message The Matrix 'error' value, e.g. "Missing token." - * @prop {Object} data The raw Matrix error JSON used to construct this object. - * @prop {number} httpStatus The numeric HTTP status code given - */ -export class MatrixError extends Error { - public readonly errcode: string; - public readonly data: IErrorJson; - public httpStatus?: number; // set by http-api - - constructor(errorJson: IErrorJson = {}) { - super(`MatrixError: ${errorJson.errcode}`); - this.errcode = errorJson.errcode; - this.name = errorJson.errcode || "Unknown error code"; - this.message = errorJson.error || "Unknown message"; - this.data = errorJson; - } -} - -/** - * Construct a ConnectionError. This is a JavaScript Error indicating - * that a request failed because of some error with the connection, either - * CORS was not correctly configured on the server, the server didn't response, - * the request timed out, or the internet connection on the client side went down. - * @constructor - */ -export class ConnectionError extends Error { - constructor(message: string, cause: Error = undefined) { - super(message + (cause ? `: ${cause.message}` : "")); - } - - get name() { - return "ConnectionError"; - } -} - -export class AbortError extends Error { - constructor() { - super("Operation aborted"); - } - - get name() { - return "AbortError"; - } -} - -/** - * Retries a network operation run in a callback. - * @param {number} maxAttempts maximum attempts to try - * @param {Function} callback callback that returns a promise of the network operation. If rejected with ConnectionError, it will be retried by calling the callback again. - * @return {any} the result of the network operation - * @throws {ConnectionError} If after maxAttempts the callback still throws ConnectionError - */ -export async function retryNetworkOperation(maxAttempts: number, callback: () => Promise): Promise { - let attempts = 0; - let lastConnectionError = null; - while (attempts < maxAttempts) { - try { - if (attempts > 0) { - const timeout = 1000 * Math.pow(2, attempts); - logger.log(`network operation failed ${attempts} times,` + - ` retrying in ${timeout}ms...`); - await sleep(timeout); - } - return callback(); - } catch (err) { - if (err instanceof ConnectionError) { - attempts += 1; - lastConnectionError = err; - } else { - throw err; - } - } - } - throw lastConnectionError; -} diff --git a/src/http-api/errors.ts b/src/http-api/errors.ts new file mode 100644 index 00000000000..e6004afe265 --- /dev/null +++ b/src/http-api/errors.ts @@ -0,0 +1,64 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { IUsageLimit } from "../@types/partials"; + +interface IErrorJson extends Partial { + [key: string]: any; // extensible + errcode?: string; + error?: string; +} + +/** + * Construct a Matrix error. This is a JavaScript Error with additional + * information specific to the standard Matrix error response. + * @constructor + * @param {Object} errorJson The Matrix error JSON returned from the homeserver. + * @prop {string} errcode The Matrix 'errcode' value, e.g. "M_FORBIDDEN". + * @prop {string} name Same as MatrixError.errcode but with a default unknown string. + * @prop {string} message The Matrix 'error' value, e.g. "Missing token." + * @prop {Object} data The raw Matrix error JSON used to construct this object. + * @prop {number} httpStatus The numeric HTTP status code given + */ +export class MatrixError extends Error { + public readonly errcode: string; + public readonly data: IErrorJson; + + constructor(errorJson: IErrorJson = {}, public httpStatus?: number) { + super(`MatrixError: ${errorJson.errcode}`); + this.errcode = errorJson.errcode; + this.name = errorJson.errcode || "Unknown error code"; + this.message = errorJson.error || "Unknown message"; + this.data = errorJson; + } +} + +/** + * Construct a ConnectionError. This is a JavaScript Error indicating + * that a request failed because of some error with the connection, either + * CORS was not correctly configured on the server, the server didn't response, + * the request timed out, or the internet connection on the client side went down. + * @constructor + */ +export class ConnectionError extends Error { + constructor(message: string, cause: Error = undefined) { + super(message + (cause ? `: ${cause.message}` : "")); + } + + get name() { + return "ConnectionError"; + } +} diff --git a/src/http-api/fetch.ts b/src/http-api/fetch.ts new file mode 100644 index 00000000000..54b043ff6b9 --- /dev/null +++ b/src/http-api/fetch.ts @@ -0,0 +1,308 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/** + * This is an internal module. See {@link MatrixHttpApi} for the public class. + * @module http-api + */ + +import * as utils from "../utils"; +import { TypedEventEmitter } from "../models/typed-event-emitter"; +import { Method } from "./method"; +import { MatrixError } from "./errors"; +import { HttpApiEvent, HttpApiEventHandlerMap, IHttpOpts, IRequestOpts } from "./interface"; +import { anySignal, timeoutSignal } from "./utils"; +import { QueryDict } from "../utils"; + +type Body = Record | BodyInit; + +interface TypedResponse extends Response { + json(): Promise; +} + +export type ResponseType = + O extends undefined ? T : + O extends { onlyData: true } ? T : + TypedResponse; + +export class FetchHttpApi { + private abortController = new AbortController(); + + constructor( + private eventEmitter: TypedEventEmitter, + public readonly opts: O, + ) { + utils.checkObjectHasKeys(opts, ["baseUrl", "prefix"]); + opts.onlyData = !!opts.onlyData; + opts.useAuthorizationHeader = opts.useAuthorizationHeader ?? true; + } + + public fetch(resource: URL | string, options?: RequestInit): ReturnType { + if (this.opts.fetchFn) { + return this.opts.fetchFn(resource, options); + } + return global.fetch(resource, options); + } + + /** + * Sets the base URL for the identity server + * @param {string} url The new base url + */ + public setIdBaseUrl(url: string): void { + this.opts.idBaseUrl = url; + } + + public idServerRequest( + method: Method, + path: string, + params: Record, + prefix: string, + accessToken: string, + ): Promise> { + if (!this.opts.idBaseUrl) { + throw new Error("No identity server base URL set"); + } + + let queryParams: QueryDict | undefined = undefined; + let body: Record | undefined = undefined; + if (method === Method.Get) { + queryParams = params; + } else if (typeof params === "object") { + body = params; + } + + const fullUri = this.getUrl(path, queryParams, prefix, this.opts.idBaseUrl); + + const opts: IRequestOpts = { + json: true, + }; + if (accessToken) { + opts.headers['Authorization'] = `Bearer ${accessToken}`; + } + + return this.requestOtherUrl(method, fullUri, body, opts); + } + + /** + * Perform an authorised request to the homeserver. + * @param {string} method The HTTP method e.g. "GET". + * @param {string} path The HTTP path after the supplied prefix e.g. + * "/createRoom". + * + * @param {Object=} queryParams A dict of query params (these will NOT be + * urlencoded). If unspecified, there will be no query params. + * + * @param {Object} [body] The HTTP JSON body. + * + * @param {Object|Number=} opts additional options. If a number is specified, + * this is treated as `opts.localTimeoutMs`. + * + * @param {Number=} opts.localTimeoutMs The maximum amount of time to wait before + * timing out the request. If not specified, there is no timeout. + * + * @param {string=} opts.prefix The full prefix to use e.g. + * "/_matrix/client/v2_alpha". If not specified, uses this.opts.prefix. + * + * @param {string=} opts.baseUrl The alternative base url to use. + * If not specified, uses this.opts.baseUrl + * + * @param {Object=} opts.headers map of additional request headers + * + * @return {Promise} Resolves to {data: {Object}, + * headers: {Object}, code: {Number}}. + * If onlyData is set, this will resolve to the data + * object only. + * @return {module:http-api.MatrixError} Rejects with an error if a problem + * occurred. This includes network problems and Matrix-specific error JSON. + */ + public authedRequest( + method: Method, + path: string, + queryParams?: QueryDict, + body?: Body, + opts: IRequestOpts = {}, + ): Promise> { + if (!queryParams) queryParams = {}; + + if (this.opts.useAuthorizationHeader) { + if (!opts.headers) { + opts.headers = {}; + } + if (!opts.headers.Authorization) { + opts.headers.Authorization = "Bearer " + this.opts.accessToken; + } + if (queryParams.access_token) { + delete queryParams.access_token; + } + } else if (!queryParams.access_token) { + queryParams.access_token = this.opts.accessToken; + } + + const requestPromise = this.request(method, path, queryParams, body, opts); + + requestPromise.catch((err: MatrixError) => { + if (err.errcode == 'M_UNKNOWN_TOKEN' && !opts?.inhibitLogoutEmit) { + this.eventEmitter.emit(HttpApiEvent.SessionLoggedOut, err); + } else if (err.errcode == 'M_CONSENT_NOT_GIVEN') { + this.eventEmitter.emit(HttpApiEvent.NoConsent, err.message, err.data.consent_uri); + } + }); + + // return the original promise, otherwise tests break due to it having to + // go around the event loop one more time to process the result of the request + return requestPromise; + } + + /** + * Perform a request to the homeserver without any credentials. + * @param {string} method The HTTP method e.g. "GET". + * @param {string} path The HTTP path after the supplied prefix e.g. + * "/createRoom". + * + * @param {Object=} queryParams A dict of query params (these will NOT be + * urlencoded). If unspecified, there will be no query params. + * + * @param {Object} [body] The HTTP JSON body. + * + * @param {Object=} opts additional options + * + * @param {Number=} opts.localTimeoutMs The maximum amount of time to wait before + * timing out the request. If not specified, there is no timeout. + * + * @param {string=} opts.prefix The full prefix to use e.g. + * "/_matrix/client/v2_alpha". If not specified, uses this.opts.prefix. + * + * @param {Object=} opts.headers map of additional request headers + * + * @return {Promise} Resolves to {data: {Object}, + * headers: {Object}, code: {Number}}. + * If onlyData is set, this will resolve to the data + * object only. + * @return {module:http-api.MatrixError} Rejects with an error if a problem + * occurred. This includes network problems and Matrix-specific error JSON. + */ + public request( + method: Method, + path: string, + queryParams?: QueryDict, + body?: Body, + opts?: IRequestOpts, + ): Promise> { + const fullUri = this.getUrl(path, queryParams, opts?.prefix, opts?.baseUrl); + return this.requestOtherUrl(method, fullUri, body, opts); + } + + /** + * Perform a request to an arbitrary URL. + * @param {string} method The HTTP method e.g. "GET". + * @param {string} url The HTTP URL object. + * + * @param {Object} [body] The HTTP JSON body. + * + * @param {Object=} opts additional options + * + * @param {Number=} opts.localTimeoutMs The maximum amount of time to wait before + * timing out the request. If not specified, there is no timeout. + * + * @param {Object=} opts.headers map of additional request headers + * + * @return {Promise} Resolves to data unless `onlyData` is specified as false, + * where the resolved value will be a fetch Response object. + * @return {module:http-api.MatrixError} Rejects with an error if a problem + * occurred. This includes network problems and Matrix-specific error JSON. + */ + public async requestOtherUrl( + method: Method, + url: URL | string, + body?: Body, + opts: Pick = {}, + ): Promise> { + const headers = Object.assign({}, opts.headers || {}); + const json = opts.json ?? true; + const jsonBody = json && body && Object.getPrototypeOf(body) === Object.prototype; + + if (json) { + if (jsonBody && !headers["Content-Type"]) { + headers["Content-Type"] = "application/json"; + } + + if (!headers["Accept"]) { + headers["Accept"] = "application/json"; + } + } + + const timeout = opts.localTimeoutMs ?? this.opts.localTimeoutMs; + const signals = [ + this.abortController.signal, + ]; + if (timeout !== undefined) { + signals.push(timeoutSignal(opts.localTimeoutMs ?? this.opts.localTimeoutMs)); + } + if (opts.abortSignal) { + signals.push(opts.abortSignal); + } + + let data: BodyInit; + if (jsonBody) { + data = JSON.stringify(body); + } else { + data = body as BodyInit; + } + + const res = await this.fetch(url, { + signal: anySignal(signals), + method, + body: data, + headers, + mode: "cors", + redirect: "follow", + referrer: "", + referrerPolicy: "no-referrer", + cache: "no-cache", + credentials: "omit", // we send credentials via headers + }); + + if (!res.ok) { + throw new MatrixError(await res.json(), res.status); + } + + if (this.opts.onlyData) { + return json ? res.json() : res.text(); + } + return res as ResponseType; + } + + /** + * Form and return a homeserver request URL based on the given path params and prefix. + * @param {string} path The HTTP path after the supplied prefix e.g. "/createRoom". + * @param {Object} queryParams A dict of query params (these will NOT be urlencoded). + * @param {string} prefix The full prefix to use e.g. "/_matrix/client/v2_alpha", defaulting to this.opts.prefix. + * @param {string} baseUrl The baseUrl to use e.g. "https://matrix.org/", defaulting to this.opts.baseUrl. + * @return {string} URL + */ + public getUrl( + path: string, + queryParams?: QueryDict, + prefix?: string, + baseUrl?: string, + ): URL { + const url = new URL((baseUrl ?? this.opts.baseUrl) + (prefix ?? this.opts.prefix) + path); + if (queryParams) { + utils.encodeParams(queryParams, url.searchParams); + } + return url; + } +} diff --git a/src/http-api/index.ts b/src/http-api/index.ts index 1027c76934c..65fc0d8c251 100644 --- a/src/http-api/index.ts +++ b/src/http-api/index.ts @@ -14,11 +14,191 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { FetchHttpApi } from "./fetch"; +import { FileType, IContentUri, IHttpOpts, Upload, UploadOpts, UploadResponse } from "./interface"; +import { MediaPrefix } from "./prefix"; +import * as utils from "../utils"; +import * as callbacks from "../realtime-callbacks"; +import { Method } from "./method"; + +export * from "./interface"; export * from "./prefix"; +export * from "./errors"; +export * from "./method"; +export * from "./utils"; + +export class MatrixHttpApi extends FetchHttpApi { + private uploads: Upload[] = []; + + /** + * Upload content to the homeserver + * + * @param {object} file The object to upload. On a browser, something that + * can be sent to XMLHttpRequest.send (typically a File). Under node.js, + * a Buffer, String or ReadStream. + * + * @param {object} opts options object + * + * @param {string=} opts.name Name to give the file on the server. Defaults + * to file.name. + * + * @param {boolean=} opts.includeFilename if false will not send the filename, + * e.g for encrypted file uploads where filename leaks are undesirable. + * Defaults to true. + * + * @param {string=} opts.type Content-type for the upload. Defaults to + * file.type, or application/octet-stream. + * + * @param {boolean=} opts.rawResponse Return the raw body, rather than + * parsing the JSON. Defaults to false (except on node.js, where it + * defaults to true for backwards compatibility). + * + * @param {boolean=} opts.onlyContentUri Just return the content URI, + * rather than the whole body. Defaults to false (except on browsers, + * where it defaults to true for backwards compatibility). Ignored if + * opts.rawResponse is true. + * + * @param {Function=} opts.progressHandler Optional. Called when a chunk of + * data has been uploaded, with an object containing the fields `loaded` + * (number of bytes transferred) and `total` (total size, if known). + * + * @return {Promise} Resolves to response object, as + * determined by this.opts.onlyData, opts.rawResponse, and + * opts.onlyContentUri. Rejects with an error (usually a MatrixError). + */ + public uploadContent(file: FileType, opts: UploadOpts = {}): Upload { + const includeFilename = opts.includeFilename ?? true; + + // If the file doesn't have a mime type, use a default since the HS errors if we don't supply one. + const contentType = opts.type ?? (file as File).type ?? 'application/octet-stream'; + const fileName = opts.name ?? (file as File).name; + + const abortController = new AbortController(); + const upload = { + loaded: 0, + total: 0, + abortController, + } as Upload; + const defer = utils.defer(); + + if (global.XMLHttpRequest) { + const xhr = new global.XMLHttpRequest(); + + const timeoutFn = function() { + xhr.abort(); + defer.reject(new Error("Timeout")); + }; + + // set an initial timeout of 30s; we'll advance it each time we get a progress notification + let timeoutTimer = callbacks.setTimeout(timeoutFn, 30000); + + xhr.onreadystatechange = function() { + switch (xhr.readyState) { + case global.XMLHttpRequest.DONE: + callbacks.clearTimeout(timeoutTimer); + try { + if (xhr.status === 0) { + throw new DOMException(xhr.statusText, "AbortError"); // mimic fetch API + } + if (!xhr.responseText) { + throw new Error('No response body.'); + } + defer.resolve(JSON.parse(xhr.responseText)); + } catch (err) { + err.httpStatus = xhr.status; + defer.reject(err); + } + break; + } + }; + + xhr.upload.onprogress = (ev: ProgressEvent) => { + callbacks.clearTimeout(timeoutTimer); + upload.loaded = ev.loaded; + upload.total = ev.total; + timeoutTimer = callbacks.setTimeout(timeoutFn, 30000); + opts.progressHandler?.({ + loaded: ev.loaded, + total: ev.total, + }); + }; + + const url = this.getUrl("/upload", undefined, MediaPrefix.R0); + + if (includeFilename && fileName) { + url.searchParams.set("filename", encodeURIComponent(fileName)); + } + + if (!this.opts.useAuthorizationHeader) { + url.searchParams.set("access_token", encodeURIComponent(this.opts.accessToken)); + } + + xhr.open(Method.Post, url.href); + if (this.opts.useAuthorizationHeader) { + xhr.setRequestHeader("Authorization", "Bearer " + this.opts.accessToken); + } + xhr.setRequestHeader("Content-Type", contentType); + xhr.send(file); + + abortController.signal.addEventListener("abort", () => { + xhr.abort(); + }); + } else { + const queryParams: utils.QueryDict = {}; + if (includeFilename && fileName) { + queryParams.filename = fileName; + } + + const headers: Record = { "Content-Type": contentType }; + + this.authedRequest( + Method.Post, "/upload", queryParams, file, { + prefix: MediaPrefix.R0, + headers, + abortSignal: abortController.signal, + }, + ).then(response => { + return this.opts.onlyData ? response : response.json(); + }).then(defer.resolve, defer.reject); + } + + // remove the upload from the list on completion + upload.promise = defer.promise.finally(() => { + utils.removeElement(this.uploads, elem => elem === upload); + }); + abortController.signal.addEventListener("abort", () => { + utils.removeElement(this.uploads, elem => elem === upload); + defer.reject(new Error("Aborted")); + }); + this.uploads.push(upload); + + return upload; + } + + public cancelUpload(upload: Upload): boolean { + if (this.uploads.includes(upload)) { + upload.abortController.abort(); + return true; + } + return false; + } + + public getCurrentUploads(): Upload[] { + return this.uploads; + } -export enum Method { - Get = "GET", - Put = "PUT", - Post = "POST", - Delete = "DELETE", + /** + * Get the content repository url with query parameters. + * @return {Object} An object with a 'base', 'path' and 'params' for base URL, + * path and query parameters respectively. + */ + public getContentUri(): IContentUri { + return { + base: this.opts.baseUrl, + path: MediaPrefix.R0 + "/upload", + params: { + access_token: this.opts.accessToken, + }, + }; + } } diff --git a/src/http-api/interface.ts b/src/http-api/interface.ts new file mode 100644 index 00000000000..e56fe67f54f --- /dev/null +++ b/src/http-api/interface.ts @@ -0,0 +1,92 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { MatrixError } from "./errors"; + +export interface IHttpOpts { + fetchFn?: typeof global.fetch; + + baseUrl: string; + idBaseUrl?: string; + prefix: string; + extraParams?: Record; + + accessToken?: string; + useAuthorizationHeader?: boolean; // defaults to true + + onlyData?: boolean; + localTimeoutMs?: number; +} + +export interface IRequestOpts { + baseUrl?: string; + prefix?: string; + + headers?: Record; + abortSignal?: AbortSignal; + localTimeoutMs?: number; + json?: boolean; // defaults to true + + // Set to true to prevent the request function from emitting a Session.logged_out event. + // This is intended for use on endpoints where M_UNKNOWN_TOKEN is a valid/notable error response, + // such as with token refreshes. + inhibitLogoutEmit?: boolean; +} + +export interface IContentUri { + base: string; + path: string; + params: { + // eslint-disable-next-line camelcase + access_token: string; + }; +} + +export enum HttpApiEvent { + SessionLoggedOut = "Session.logged_out", + NoConsent = "no_consent", +} + +export type HttpApiEventHandlerMap = { + [HttpApiEvent.SessionLoggedOut]: (err: MatrixError) => void; + [HttpApiEvent.NoConsent]: (message: string, consentUri: string) => void; +}; + +export interface UploadProgress { + loaded: number; + total: number; +} + +export interface UploadOpts { + name?: string; + type?: string; + includeFilename?: boolean; + progressHandler?(progress: UploadProgress): void; +} + +export interface Upload { + loaded: number; + total: number; + promise: Promise; + abortController: AbortController; +} + +export interface UploadResponse { + // eslint-disable-next-line camelcase + content_uri: string; +} + +export type FileType = XMLHttpRequestBodyInit; diff --git a/src/http-api/method.ts b/src/http-api/method.ts new file mode 100644 index 00000000000..1914360e3a3 --- /dev/null +++ b/src/http-api/method.ts @@ -0,0 +1,22 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export enum Method { + Get = "GET", + Put = "PUT", + Post = "POST", + Delete = "DELETE", +} diff --git a/src/http-api/utils.ts b/src/http-api/utils.ts new file mode 100644 index 00000000000..399c60756a1 --- /dev/null +++ b/src/http-api/utils.ts @@ -0,0 +1,145 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { parse as parseContentType, ParsedMediaType } from "content-type"; + +import { logger } from "../logger"; +import { sleep } from "../utils"; +import { ConnectionError, MatrixError } from "./errors"; + +// Ponyfill for https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout +export function timeoutSignal(ms: number): AbortSignal { + const controller = new AbortController(); + const timeoutId = setTimeout(() => { + controller.abort(); + }, ms); + + function onAbort() { + clearTimeout(timeoutId); + } + + controller.signal.addEventListener('abort', onAbort); + return controller.signal; +} + +export function anySignal(signals: AbortSignal[]): AbortSignal { + const controller = new AbortController(); + + function onAbort() { + controller.abort(); + + // Cleanup + for (const signal of signals) { + signal.removeEventListener('abort', onAbort); + } + } + + for (const signal of signals) { + if (signal.aborted) { + onAbort(); + break; + } + signal.addEventListener('abort', onAbort); + } + + return controller.signal; +} + +/** + * Attempt to turn an HTTP error response into a Javascript Error. + * + * If it is a JSON response, we will parse it into a MatrixError. Otherwise + * we return a generic Error. + * + * @param {XMLHttpRequest|Response} response response object + * @param {String} body raw body of the response + * @returns {Error} + */ +export function parseErrorResponse(response: XMLHttpRequest | Response, body?: string): Error { + const contentType = getResponseContentType(response); + + let err: Error; + if (contentType) { + if (contentType.type === "application/json") { + const jsonBody = typeof(body) === "object" ? body : JSON.parse(body); + err = new MatrixError(jsonBody, response.status); + } else if (contentType.type === "text/plain") { + err = new Error(`Server returned ${response.status} error: ${body}`); + } + } + + if (!err) { + err = new Error(`Server returned ${response.status} error`); + } + return err; +} + +/** + * extract the Content-Type header from the response object, and + * parse it to a `{type, parameters}` object. + * + * returns null if no content-type header could be found. + * + * @param {XMLHttpRequest|Response} response response object + * @returns {{type: String, parameters: Object}?} parsed content-type header, or null if not found + */ +function getResponseContentType(response: XMLHttpRequest | Response): ParsedMediaType | null { + let contentType: string; + if ((response as XMLHttpRequest).getResponseHeader) { + contentType = (response as XMLHttpRequest).getResponseHeader("Content-Type"); + } else if ((response as Response).headers) { + contentType = (response as Response).headers.get("Content-Type"); + } + + if (!contentType) return null; + + try { + return parseContentType(contentType); + } catch (e) { + throw new Error(`Error parsing Content-Type '${contentType}': ${e}`); + } +} + +/** + * Retries a network operation run in a callback. + * @param {number} maxAttempts maximum attempts to try + * @param {Function} callback callback that returns a promise of the network operation. If rejected with ConnectionError, it will be retried by calling the callback again. + * @return {any} the result of the network operation + * @throws {ConnectionError} If after maxAttempts the callback still throws ConnectionError + */ +export async function retryNetworkOperation(maxAttempts: number, callback: () => Promise): Promise { + let attempts = 0; + let lastConnectionError = null; + while (attempts < maxAttempts) { + try { + if (attempts > 0) { + const timeout = 1000 * Math.pow(2, attempts); + logger.log(`network operation failed ${attempts} times,` + + ` retrying in ${timeout}ms...`); + await sleep(timeout); + } + return callback(); + } catch (err) { + if (err instanceof ConnectionError) { + attempts += 1; + lastConnectionError = err; + } else { + throw err; + } + } + } + throw lastConnectionError; +} diff --git a/src/index.ts b/src/index.ts index c651438fb75..4b84224353f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,17 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import * as request from "request"; - import * as matrixcs from "./matrix"; import * as utils from "./utils"; import { logger } from './logger'; -if (matrixcs.getRequest()) { +if (global.__js_sdk_entrypoint) { throw new Error("Multiple matrix-js-sdk entrypoints detected!"); } - -matrixcs.request(request); +global.__js_sdk_entrypoint = true; try { // eslint-disable-next-line @typescript-eslint/no-var-requires diff --git a/src/matrix.ts b/src/matrix.ts index 6813655a995..eaa9b09e76b 100644 --- a/src/matrix.ts +++ b/src/matrix.ts @@ -55,41 +55,6 @@ export { createNewMatrixCall, } from "./webrtc/call"; -// expose the underlying request object so different environments can use -// different request libs (e.g. request or browser-request) -let requestInstance; - -/** - * The function used to perform HTTP requests. Only use this if you want to - * use a different HTTP library, e.g. Angular's $http. This should - * be set prior to calling {@link createClient}. - * @param {requestFunction} r The request function to use. - */ -export function request(r) { - requestInstance = r; -} - -/** - * Return the currently-set request function. - * @return {requestFunction} The current request function. - */ -export function getRequest() { - return requestInstance; -} - -/** - * Apply wrapping code around the request function. The wrapper function is - * installed as the new request handler, and when invoked it is passed the - * previous value, along with the options and callback arguments. - * @param {requestWrapperFunction} wrapper The wrapping function. - */ -export function wrapRequest(wrapper) { - const origRequest = requestInstance; - requestInstance = function(options, callback) { - return wrapper(origRequest, options, callback); - }; -} - let cryptoStoreFactory = () => new MemoryCryptoStore; /** @@ -128,15 +93,13 @@ export interface ICryptoCallbacks { /** * Construct a Matrix Client. Similar to {@link module:client.MatrixClient} * except that the 'request', 'store' and 'scheduler' dependencies are satisfied. - * @param {(Object|string)} opts The configuration options for this client. If + * @param {(Object)} opts The configuration options for this client. If * this is a string, it is assumed to be the base URL. These configuration * options will be passed directly to {@link module:client.MatrixClient}. * @param {Object} opts.store If not set, defaults to * {@link module:store/memory.MemoryStore}. * @param {Object} opts.scheduler If not set, defaults to * {@link module:scheduler~MatrixScheduler}. - * @param {requestFunction} opts.request If not set, defaults to the function - * supplied to {@link request} which defaults to the request module from NPM. * * @param {module:crypto.store.base~CryptoStore=} opts.cryptoStore * crypto store implementation. Calls the factory supplied to @@ -148,13 +111,7 @@ export interface ICryptoCallbacks { * @see {@link module:client.MatrixClient} for the full list of options for * opts. */ -export function createClient(opts: ICreateClientOpts | string) { - if (typeof opts === "string") { - opts = { - "baseUrl": opts, - }; - } - opts.request = opts.request || requestInstance; +export function createClient(opts: ICreateClientOpts) { opts.store = opts.store || new MemoryStore({ localStorage: global.localStorage, }); @@ -163,23 +120,6 @@ export function createClient(opts: ICreateClientOpts | string) { return new MatrixClient(opts); } -/** - * The request function interface for performing HTTP requests. This matches the - * API for the {@link https://github.com/request/request#requestoptions-callback| - * request NPM module}. The SDK will attempt to call this function in order to - * perform an HTTP request. - * @callback requestFunction - * @param {Object} opts The options for this HTTP request. - * @param {string} opts.uri The complete URI. - * @param {string} opts.method The HTTP method. - * @param {Object} opts.qs The query parameters to append to the URI. - * @param {Object} opts.body The JSON-serializable object. - * @param {boolean} opts.json True if this is a JSON request. - * @param {Object} opts._matrix_opts The underlying options set for - * {@link MatrixHttpApi}. - * @param {requestCallback} callback The request callback. - */ - /** * A wrapper for the request function interface. * @callback requestWrapperFunction diff --git a/src/models/MSC3089TreeSpace.ts b/src/models/MSC3089TreeSpace.ts index 0426d596e2e..c57bd4a90dc 100644 --- a/src/models/MSC3089TreeSpace.ts +++ b/src/models/MSC3089TreeSpace.ts @@ -476,11 +476,10 @@ export class MSC3089TreeSpace { info: Partial, additionalContent?: IContent, ): Promise { - const mxc = await this.client.uploadContent(encryptedContents, { + const upload = this.client.uploadContent(encryptedContents, { includeFilename: false, - onlyContentUri: true, - rawResponse: false, // make this explicit otherwise behaviour is different on browser vs NodeJS }); + const { content_uri: mxc } = await upload.promise; info.url = mxc; const fileContent = { diff --git a/src/sliding-sync-sdk.ts b/src/sliding-sync-sdk.ts index 21d2af63f0d..e1072f8daa9 100644 --- a/src/sliding-sync-sdk.ts +++ b/src/sliding-sync-sdk.ts @@ -674,7 +674,7 @@ export class SlidingSyncSdk { member._requestedProfileInfo = true; // try to get a cached copy first. const user = client.getUser(member.userId); - let promise; + let promise: ReturnType; if (user) { promise = Promise.resolve({ avatar_url: user.avatarUrl, diff --git a/src/sliding-sync.ts b/src/sliding-sync.ts index da6419c9676..b713a1ae7ab 100644 --- a/src/sliding-sync.ts +++ b/src/sliding-sync.ts @@ -15,10 +15,9 @@ limitations under the License. */ import { logger } from './logger'; -import { IAbortablePromise } from "./@types/partials"; import { MatrixClient } from "./client"; import { IRoomEvent, IStateEvent } from "./sync-accumulator"; -import { TypedEventEmitter } from "./models//typed-event-emitter"; +import { TypedEventEmitter } from "./models/typed-event-emitter"; import { sleep, IDeferred, defer } from "./utils"; // /sync requests allow you to set a timeout= but the request may continue @@ -353,7 +352,8 @@ export class SlidingSync extends TypedEventEmitter(); // the *desired* room subscriptions private confirmedRoomSubscriptions = new Set(); - private pendingReq?: IAbortablePromise; + private pendingReq?: Promise; + private abortController?: AbortController; /** * Create a new sliding sync instance @@ -700,7 +700,8 @@ export class SlidingSync extends TypedEventEmitter = T & { */ export class SyncApi { private _peekRoom: Optional = null; - private currentSyncRequest: Optional> = null; + private currentSyncRequest: Optional> = null; + private abortController?: AbortController; private syncState: Optional = null; private syncStateData: Optional = null; // additional data (eg. error object for failed sync) private catchingUp = false; @@ -296,7 +296,9 @@ export class SyncApi { getFilterName(client.credentials.userId, "LEFT_ROOMS"), filter, ).then(function(filterId) { qps.filter = filterId; - return client.http.authedRequest(Method.Get, "/sync", qps as any, undefined, localTimeoutMs); + return client.http.authedRequest(Method.Get, "/sync", qps as any, undefined, { + localTimeoutMs, + }); }).then(async (data) => { let leaveRooms = []; if (data.rooms?.leave) { @@ -433,7 +435,7 @@ export class SyncApi { room_id: peekRoom.roomId, timeout: String(30 * 1000), from: token, - }, undefined, 50 * 1000).then((res) => { + }, undefined, { localTimeoutMs: 50 * 1000 }).then((res) => { if (this._peekRoom !== peekRoom) { debuglog("Stopped peeking in room %s", peekRoom.roomId); return; @@ -644,6 +646,7 @@ export class SyncApi { */ public async sync(): Promise { this.running = true; + this.abortController = new AbortController(); global.window?.addEventListener?.("online", this.onOnline, false); @@ -730,7 +733,7 @@ export class SyncApi { // but do not have global.window.removeEventListener. global.window?.removeEventListener?.("online", this.onOnline, false); this.running = false; - this.currentSyncRequest?.abort(); + this.abortController.abort(); if (this.keepAliveTimer) { clearTimeout(this.keepAliveTimer); this.keepAliveTimer = null; @@ -894,12 +897,12 @@ export class SyncApi { } } - private doSyncRequest(syncOptions: ISyncOptions, syncToken: string): IAbortablePromise { + private doSyncRequest(syncOptions: ISyncOptions, syncToken: string): Promise { const qps = this.getSyncParams(syncOptions, syncToken); - return this.client.http.authedRequest( - Method.Get, "/sync", qps as any, undefined, - qps.timeout + BUFFER_PERIOD_MS, - ); + return this.client.http.authedRequest(Method.Get, "/sync", qps as any, undefined, { + localTimeoutMs: qps.timeout + BUFFER_PERIOD_MS, + abortSignal: this.abortController?.signal, + }); } private getSyncParams(syncOptions: ISyncOptions, syncToken: string): ISyncParams { diff --git a/src/utils.ts b/src/utils.ts index 2875cf3cfb0..8d869389f2a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -59,17 +59,23 @@ export function internaliseString(str: string): string { * {"foo": "bar", "baz": "taz"} * @return {string} The encoded string e.g. foo=bar&baz=taz */ -export function encodeParams(params: Record): string { - const searchParams = new URLSearchParams(); +export function encodeParams(params: QueryDict, urlSearchParams?: URLSearchParams): URLSearchParams { + const searchParams = urlSearchParams ?? new URLSearchParams(); for (const [key, val] of Object.entries(params)) { if (val !== undefined && val !== null) { - searchParams.set(key, String(val)); + if (Array.isArray(val)) { + val.forEach(v => { + searchParams.append(key, String(v)); + }); + } else { + searchParams.append(key, String(val)); + } } } - return searchParams.toString(); + return searchParams; } -export type QueryDict = Record; +export type QueryDict = Record; /** * Decode a query string in `application/x-www-form-urlencoded` format. @@ -80,8 +86,8 @@ export type QueryDict = Record; * This behaviour matches Node's qs.parse but is built on URLSearchParams * for native web compatibility */ -export function decodeParams(query: string): QueryDict { - const o: QueryDict = {}; +export function decodeParams(query: string): Record { + const o: Record = {}; const params = new URLSearchParams(query); for (const key of params.keys()) { const val = params.getAll(key); diff --git a/yarn.lock b/yarn.lock index b6869e6fb31..786e4a8c02b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,12 +3,11 @@ "@actions/core@^1.4.0": - version "1.9.1" - resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.9.1.tgz#97c0201b1f9856df4f7c3a375cdcdb0c2a2f750b" - integrity sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA== + version "1.8.2" + resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.8.2.tgz#67539d669ae9b751430469e9ae4d83e0525973ac" + integrity sha512-FXcBL7nyik8K5ODeCKlxi+vts7torOkoDAKfeh61EAkAy1HAvwn9uVzZBY0f15YcQTcZZ2/iSGBFHEuioZWfDA== dependencies: "@actions/http-client" "^2.0.1" - uuid "^8.3.2" "@actions/github@^5.0.0": version "5.0.3" @@ -36,48 +35,48 @@ "@jridgewell/trace-mapping" "^0.3.9" "@babel/cli@^7.12.10": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.18.10.tgz#4211adfc45ffa7d4f3cee6b60bb92e9fe68fe56a" - integrity sha512-dLvWH+ZDFAkd2jPBSghrsFBuXrREvFwjpDycXbmUoeochqKYe4zNSLEJYErpLg8dvxvZYe79/MkN461XCwpnGw== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.18.6.tgz#b1228eb9196b34d608155a47508011d9e47ab1f2" + integrity sha512-jXNHoYCbxZ8rKy+2lyy0VjcaGxS4NPbN0qc95DjIiGZQL/mTNx3o2/yI0TG+X0VrrTuwmO7zH52T9NcNdbF9Uw== dependencies: "@jridgewell/trace-mapping" "^0.3.8" commander "^4.0.1" convert-source-map "^1.1.0" fs-readdir-recursive "^1.1.0" - glob "^7.2.0" + glob "^7.0.0" make-dir "^2.1.0" slash "^2.0.0" optionalDependencies: "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3" chokidar "^3.4.0" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== dependencies: "@babel/highlight" "^7.18.6" -"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8", "@babel/compat-data@^7.19.1": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.19.1.tgz#72d647b4ff6a4f82878d184613353af1dd0290f9" - integrity sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg== +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.6.tgz#8b37d24e88e8e21c499d4328db80577d8882fa53" + integrity sha512-tzulrgDT0QD6U7BJ4TKVk2SDDg7wlP39P9yAx1RfLy7vP/7rsDRlWVfbWxElslu56+r7QOhB2NSDsabYYruoZQ== "@babel/core@^7.11.6", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.7.5": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.19.1.tgz#c8fa615c5e88e272564ace3d42fbc8b17bfeb22b" - integrity sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.6.tgz#54a107a3c298aee3fe5e1947a6464b9b6faca03d" + integrity sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ== dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.19.0" - "@babel/helper-compilation-targets" "^7.19.1" - "@babel/helper-module-transforms" "^7.19.0" - "@babel/helpers" "^7.19.0" - "@babel/parser" "^7.19.1" - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.19.1" - "@babel/types" "^7.19.0" + "@babel/generator" "^7.18.6" + "@babel/helper-compilation-targets" "^7.18.6" + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helpers" "^7.18.6" + "@babel/parser" "^7.18.6" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.6" + "@babel/types" "^7.18.6" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -85,39 +84,48 @@ semver "^6.3.0" "@babel/eslint-parser@^7.12.10": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz#4f68f6b0825489e00a24b41b6a1ae35414ecd2f4" - integrity sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ== + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.18.2.tgz#e14dee36c010edfb0153cf900c2b0815e82e3245" + integrity sha512-oFQYkE8SuH14+uR51JVAmdqwKYXGRjEXx7s+WiagVjqQ+HPE+nnwyF2qlVG8evUsUHmPcA+6YXMEDbIhEyQc5A== dependencies: - "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" + eslint-scope "^5.1.1" eslint-visitor-keys "^2.1.0" semver "^6.3.0" "@babel/eslint-plugin@^7.12.10": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/eslint-plugin/-/eslint-plugin-7.19.1.tgz#8bfde4b6e4380ea038e7947a765fe536c3057a4c" - integrity sha512-ElGPkQPapKMa3zVqXHkZYzuL7I5LbRw9UWBUArgWsdWDDb9XcACqOpBib5tRPA9XvbVZYrFUkoQPbiJ4BFvu4w== + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/eslint-plugin/-/eslint-plugin-7.17.7.tgz#4ee1d5b29b79130f3bb5a933358376bcbee172b8" + integrity sha512-JATUoJJXSgwI0T8juxWYtK1JSgoLpIGUsCHIv+NMXcUDA2vIe6nvAHR9vnuJgs/P1hOFw7vPwibixzfqBBLIVw== dependencies: eslint-rule-composer "^0.3.0" "@babel/generator@^7.12.11": - version "7.18.13" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.13.tgz#59550cbb9ae79b8def15587bdfbaa388c4abf212" - integrity sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ== + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.2.tgz#33873d6f89b21efe2da63fe554460f3df1c5880d" + integrity sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw== dependencies: - "@babel/types" "^7.18.13" - "@jridgewell/gen-mapping" "^0.3.2" + "@babel/types" "^7.18.2" + "@jridgewell/gen-mapping" "^0.3.0" jsesc "^2.5.1" -"@babel/generator@^7.18.13", "@babel/generator@^7.19.0", "@babel/generator@^7.7.2": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.19.0.tgz#785596c06425e59334df2ccee63ab166b738419a" - integrity sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg== +"@babel/generator@^7.18.2", "@babel/generator@^7.18.6": + version "7.18.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.7.tgz#2aa78da3c05aadfc82dbac16c99552fc802284bd" + integrity sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A== dependencies: - "@babel/types" "^7.19.0" + "@babel/types" "^7.18.7" "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" +"@babel/generator@^7.7.2": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.6.tgz#9ab2d46d3cbf631f0e80f72e72874a04c3fc12a9" + integrity sha512-AIwwoOS8axIC5MZbhNHRLKi3D+DMpvDf9XUcu3pIVAfOHFT45f4AoDAltRbHIQomCipkCZxrNkfpOEHhJz/VKw== + dependencies: + "@babel/types" "^7.18.6" + "@jridgewell/gen-mapping" "^0.3.0" + jsesc "^2.5.1" + "@babel/helper-annotate-as-pure@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" @@ -126,73 +134,62 @@ "@babel/types" "^7.18.6" "@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz#acd4edfd7a566d1d51ea975dff38fd52906981bb" - integrity sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.6.tgz#f14d640ed1ee9246fb33b8255f08353acfe70e6a" + integrity sha512-KT10c1oWEpmrIRYnthbzHgoOf6B+Xd6a5yhdbNtdhtG7aO1or5HViuf1TQR36xY/QprXA5nvxO6nAjhJ4y38jw== dependencies: "@babel/helper-explode-assignable-expression" "^7.18.6" - "@babel/types" "^7.18.9" + "@babel/types" "^7.18.6" -"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.19.0", "@babel/helper-compilation-targets@^7.19.1": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz#7f630911d83b408b76fe584831c98e5395d7a17c" - integrity sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg== +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz#18d35bfb9f83b1293c22c55b3d576c1315b6ed96" + integrity sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg== dependencies: - "@babel/compat-data" "^7.19.1" + "@babel/compat-data" "^7.18.6" "@babel/helper-validator-option" "^7.18.6" - browserslist "^4.21.3" + browserslist "^4.20.2" semver "^6.3.0" "@babel/helper-create-class-features-plugin@^7.18.6": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz#bfd6904620df4e46470bae4850d66be1054c404b" - integrity sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.19.0" - "@babel/helper-member-expression-to-functions" "^7.18.9" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/helper-replace-supers" "^7.18.9" - "@babel/helper-split-export-declaration" "^7.18.6" - -"@babel/helper-create-class-features-plugin@^7.18.9": - version "7.18.13" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.13.tgz#63e771187bd06d234f95fdf8bd5f8b6429de6298" - integrity sha512-hDvXp+QYxSRL+23mpAlSGxHMDyIGChm0/AwTfTAAK5Ufe40nCsyNdaYCGuK91phn/fVu9kqayImRDkvNAgdrsA== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.6.tgz#6f15f8459f3b523b39e00a99982e2c040871ed72" + integrity sha512-YfDzdnoxHGV8CzqHGyCbFvXg5QESPFkXlHtvdCkesLjjVMT2Adxe4FGUR5ChIb3DxSaXO12iIOCWoXdsUVwnqw== dependencies: "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.18.9" - "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-environment-visitor" "^7.18.6" + "@babel/helper-function-name" "^7.18.6" + "@babel/helper-member-expression-to-functions" "^7.18.6" "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/helper-replace-supers" "^7.18.9" + "@babel/helper-replace-supers" "^7.18.6" "@babel/helper-split-export-declaration" "^7.18.6" -"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.19.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz#7976aca61c0984202baca73d84e2337a5424a41b" - integrity sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw== +"@babel/helper-create-regexp-features-plugin@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz#3e35f4e04acbbf25f1b3534a657610a000543d3c" + integrity sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A== dependencies: "@babel/helper-annotate-as-pure" "^7.18.6" regexpu-core "^5.1.0" -"@babel/helper-define-polyfill-provider@^0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz#8612e55be5d51f0cd1f36b4a5a83924e89884b7a" - integrity sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww== +"@babel/helper-define-polyfill-provider@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz#52411b445bdb2e676869e5a74960d2d3826d2665" + integrity sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA== dependencies: - "@babel/helper-compilation-targets" "^7.17.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/traverse" "^7.13.0" debug "^4.1.1" lodash.debounce "^4.0.8" resolve "^1.14.2" semver "^6.1.2" -"@babel/helper-environment-visitor@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" - integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== +"@babel/helper-environment-visitor@^7.18.2", "@babel/helper-environment-visitor@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz#b7eee2b5b9d70602e59d1a6cad7dd24de7ca6cd7" + integrity sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q== "@babel/helper-explode-assignable-expression@^7.18.6": version "7.18.6" @@ -201,48 +198,48 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c" - integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w== +"@babel/helper-function-name@^7.17.9", "@babel/helper-function-name@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz#8334fecb0afba66e6d87a7e8c6bb7fed79926b83" + integrity sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw== dependencies: - "@babel/template" "^7.18.10" - "@babel/types" "^7.19.0" + "@babel/template" "^7.18.6" + "@babel/types" "^7.18.6" -"@babel/helper-hoist-variables@^7.18.6": +"@babel/helper-hoist-variables@^7.16.7", "@babel/helper-hoist-variables@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== dependencies: "@babel/types" "^7.18.6" -"@babel/helper-member-expression-to-functions@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815" - integrity sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg== +"@babel/helper-member-expression-to-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.6.tgz#44802d7d602c285e1692db0bad9396d007be2afc" + integrity sha512-CeHxqwwipekotzPDUuJOfIMtcIHBuc7WAzLmTYWctVigqS5RktNMQ5bEwQSuGewzYnCtTWa3BARXeiLxDTv+Ng== dependencies: - "@babel/types" "^7.18.9" + "@babel/types" "^7.18.6" -"@babel/helper-module-imports@^7.18.6": +"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== dependencies: "@babel/types" "^7.18.6" -"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.19.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz#309b230f04e22c58c6a2c0c0c7e50b216d350c30" - integrity sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ== +"@babel/helper-module-transforms@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.6.tgz#57e3ca669e273d55c3cda55e6ebf552f37f483c8" + integrity sha512-L//phhB4al5uucwzlimruukHB3jRd5JGClwRMD/ROrVjXfLqovYnvQrK/JK36WYyVwGGO7OD3kMyVTjx+WVPhw== dependencies: - "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-environment-visitor" "^7.18.6" "@babel/helper-module-imports" "^7.18.6" "@babel/helper-simple-access" "^7.18.6" "@babel/helper-split-export-declaration" "^7.18.6" "@babel/helper-validator-identifier" "^7.18.6" - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.19.0" - "@babel/types" "^7.19.0" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.6" + "@babel/types" "^7.18.6" "@babel/helper-optimise-call-expression@^7.18.6": version "7.18.6" @@ -251,31 +248,31 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz#4796bb14961521f0f8715990bee2fb6e51ce21bf" - integrity sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw== +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz#9448974dd4fb1d80fefe72e8a0af37809cd30d6d" + integrity sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg== -"@babel/helper-remap-async-to-generator@^7.18.6", "@babel/helper-remap-async-to-generator@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519" - integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA== +"@babel/helper-remap-async-to-generator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.6.tgz#fa1f81acd19daee9d73de297c0308783cd3cfc23" + integrity sha512-z5wbmV55TveUPZlCLZvxWHtrjuJd+8inFhk7DG0WW87/oJuGDcjDiu7HIvGcpf5464L6xKCg3vNkmlVVz9hwyQ== dependencies: "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-wrap-function" "^7.18.9" - "@babel/types" "^7.18.9" + "@babel/helper-environment-visitor" "^7.18.6" + "@babel/helper-wrap-function" "^7.18.6" + "@babel/types" "^7.18.6" -"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.18.9": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz#e1592a9b4b368aa6bdb8784a711e0bcbf0612b78" - integrity sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw== +"@babel/helper-replace-supers@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.18.6.tgz#efedf51cfccea7b7b8c0f00002ab317e7abfe420" + integrity sha512-fTf7zoXnUGl9gF25fXCWE26t7Tvtyn6H4hkLSYhATwJvw2uYxd3aoXplMSe0g9XbwK7bmxNes7+FGO0rB/xC0g== dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-environment-visitor" "^7.18.6" + "@babel/helper-member-expression-to-functions" "^7.18.6" "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/traverse" "^7.19.1" - "@babel/types" "^7.19.0" + "@babel/traverse" "^7.18.6" + "@babel/types" "^7.18.6" "@babel/helper-simple-access@^7.18.6": version "7.18.6" @@ -284,53 +281,48 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-skip-transparent-expression-wrappers@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz#778d87b3a758d90b471e7b9918f34a9a02eb5818" - integrity sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw== +"@babel/helper-skip-transparent-expression-wrappers@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.6.tgz#7dff00a5320ca4cf63270e5a0eca4b268b7380d9" + integrity sha512-4KoLhwGS9vGethZpAhYnMejWkX64wsnHPDwvOsKWU6Fg4+AlK2Jz3TyjQLMEPvz+1zemi/WBdkYxCD0bAfIkiw== dependencies: - "@babel/types" "^7.18.9" + "@babel/types" "^7.18.6" -"@babel/helper-split-export-declaration@^7.18.6": +"@babel/helper-split-export-declaration@^7.16.7", "@babel/helper-split-export-declaration@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== dependencies: "@babel/types" "^7.18.6" -"@babel/helper-string-parser@^7.18.10": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56" - integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw== - -"@babel/helper-validator-identifier@^7.18.6": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" - integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== +"@babel/helper-validator-identifier@^7.16.7", "@babel/helper-validator-identifier@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076" + integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== "@babel/helper-validator-option@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== -"@babel/helper-wrap-function@^7.18.9": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz#89f18335cff1152373222f76a4b37799636ae8b1" - integrity sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg== +"@babel/helper-wrap-function@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.18.6.tgz#ec44ea4ad9d8988b90c3e465ba2382f4de81a073" + integrity sha512-I5/LZfozwMNbwr/b1vhhuYD+J/mU+gfGAj5td7l5Rv9WYmH6i3Om69WGKNmlIpsVW/mF6O5bvTKbvDQZVgjqOw== dependencies: - "@babel/helper-function-name" "^7.19.0" - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.19.0" - "@babel/types" "^7.19.0" + "@babel/helper-function-name" "^7.18.6" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.6" + "@babel/types" "^7.18.6" -"@babel/helpers@^7.19.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.19.0.tgz#f30534657faf246ae96551d88dd31e9d1fa1fc18" - integrity sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg== +"@babel/helpers@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.6.tgz#4c966140eaa1fcaa3d5a8c09d7db61077d4debfd" + integrity sha512-vzSiiqbQOghPngUYt/zWGvK3LAsPhz55vc9XNN0xAl2gV4ieShI2OQli5duxWHD+72PZPTKAcfcZDE1Cwc5zsQ== dependencies: - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.19.0" - "@babel/types" "^7.19.0" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.6" + "@babel/types" "^7.18.6" "@babel/highlight@^7.18.6": version "7.18.6" @@ -341,15 +333,15 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.18.13", "@babel/parser@^7.19.1": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.1.tgz#6f6d6c2e621aad19a92544cc217ed13f1aac5b4c" - integrity sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.0", "@babel/parser@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.6.tgz#845338edecad65ebffef058d3be851f1d28a63bc" + integrity sha512-uQVSa9jJUe/G/304lXspfWVpKpK4euFLgGiMQFOCpM/bgcAdeoHwi/OQz23O9GK2osz26ZiXRRV9aV+Yl1O8tw== "@babel/parser@^7.2.3", "@babel/parser@^7.9.4": - version "7.18.13" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.13.tgz#5b2dd21cae4a2c5145f1fbd8ca103f9313d3b7e4" - integrity sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg== + version "7.18.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.4.tgz#6774231779dd700e0af29f6ad8d479582d7ce5ef" + integrity sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow== "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": version "7.18.6" @@ -358,23 +350,23 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz#a11af19aa373d68d561f08e0a57242350ed0ec50" - integrity sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg== +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.6.tgz#b4e4dbc2cd1acd0133479918f7c6412961c9adb8" + integrity sha512-Udgu8ZRgrBrttVz6A0EVL0SJ1z+RLbIeqsu632SA1hf0awEppD6TvdznoH+orIF8wtFFAV/Enmw9Y+9oV8TQcw== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" - "@babel/plugin-proposal-optional-chaining" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.6" + "@babel/plugin-proposal-optional-chaining" "^7.18.6" -"@babel/plugin-proposal-async-generator-functions@^7.19.1": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz#34f6f5174b688529342288cd264f80c9ea9fb4a7" - integrity sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q== +"@babel/plugin-proposal-async-generator-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz#aedac81e6fc12bb643374656dd5f2605bf743d17" + integrity sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w== dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-plugin-utils" "^7.19.0" - "@babel/helper-remap-async-to-generator" "^7.18.9" + "@babel/helper-environment-visitor" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-remap-async-to-generator" "^7.18.6" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-proposal-class-properties@^7.12.1", "@babel/plugin-proposal-class-properties@^7.18.6": @@ -402,12 +394,12 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-dynamic-import" "^7.8.3" -"@babel/plugin-proposal-export-namespace-from@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz#5f7313ab348cdb19d590145f9247540e94761203" - integrity sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA== +"@babel/plugin-proposal-export-namespace-from@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.6.tgz#1016f0aa5ab383bbf8b3a85a2dcaedf6c8ee7491" + integrity sha512-zr/QcUlUo7GPo6+X1wC98NJADqmy5QTFWWhqeQWiki4XHafJtLl/YMGkmRB2szDD2IYJCCdBTd4ElwhId9T7Xw== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" "@babel/plugin-proposal-json-strings@^7.18.6": @@ -418,12 +410,12 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-json-strings" "^7.8.3" -"@babel/plugin-proposal-logical-assignment-operators@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz#8148cbb350483bf6220af06fa6db3690e14b2e23" - integrity sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q== +"@babel/plugin-proposal-logical-assignment-operators@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.6.tgz#3b9cac6f1ffc2aa459d111df80c12020dfc6b665" + integrity sha512-zMo66azZth/0tVd7gmkxOkOjs2rpHyhpcFo565PUP37hSp6hSd9uUKIfTDFMz58BwqgQKhJ9YxtM5XddjXVn+Q== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": @@ -442,16 +434,16 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.12.1", "@babel/plugin-proposal-object-rest-spread@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz#f9434f6beb2c8cae9dfcf97d2a5941bbbf9ad4e7" - integrity sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q== +"@babel/plugin-proposal-object-rest-spread@^7.12.1", "@babel/plugin-proposal-object-rest-spread@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.6.tgz#ec93bba06bfb3e15ebd7da73e953d84b094d5daf" + integrity sha512-9yuM6wr4rIsKa1wlUAbZEazkCrgw2sMPEXCr4Rnwetu7cEW1NydkCWytLuYletbf8vFxdJxFhwEZqMpOx2eZyw== dependencies: - "@babel/compat-data" "^7.18.8" - "@babel/helper-compilation-targets" "^7.18.9" - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/compat-data" "^7.18.6" + "@babel/helper-compilation-targets" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.18.8" + "@babel/plugin-transform-parameters" "^7.18.6" "@babel/plugin-proposal-optional-catch-binding@^7.18.6": version "7.18.6" @@ -461,13 +453,13 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-proposal-optional-chaining@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz#e8e8fe0723f2563960e4bf5e9690933691915993" - integrity sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w== +"@babel/plugin-proposal-optional-chaining@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.6.tgz#46d4f2ffc20e87fad1d98bc4fa5d466366f6aa0b" + integrity sha512-PatI6elL5eMzoypFAiYDpYQyMtXTn+iMhuxxQt5mAXD4fEmKorpSI3PHd+i3JXBJN3xyA6MvJv7at23HffFHwA== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" - "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.6" "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-proposal-private-methods@^7.18.6": @@ -652,41 +644,40 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-block-scoping@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz#f9b7e018ac3f373c81452d6ada8bd5a18928926d" - integrity sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw== +"@babel/plugin-transform-block-scoping@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.6.tgz#b5f78318914615397d86a731ef2cc668796a726c" + integrity sha512-pRqwb91C42vs1ahSAWJkxOxU1RHWDn16XAa6ggQ72wjLlWyYeAcLvTtE0aM8ph3KNydy9CQF2nLYcjq1WysgxQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-classes@^7.19.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz#0e61ec257fba409c41372175e7c1e606dc79bb20" - integrity sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A== +"@babel/plugin-transform-classes@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.6.tgz#3501a8f3f4c7d5697c27a3eedbee71d68312669f" + integrity sha512-XTg8XW/mKpzAF3actL554Jl/dOYoJtv3l8fxaEczpgz84IeeVf+T1u2CSvPHuZbt0w3JkIx4rdn/MRQI7mo0HQ== dependencies: "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-compilation-targets" "^7.19.0" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.19.0" + "@babel/helper-environment-visitor" "^7.18.6" + "@babel/helper-function-name" "^7.18.6" "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/helper-plugin-utils" "^7.19.0" - "@babel/helper-replace-supers" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.6" "@babel/helper-split-export-declaration" "^7.18.6" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz#2357a8224d402dad623caf6259b611e56aec746e" - integrity sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw== +"@babel/plugin-transform-computed-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.6.tgz#5d15eb90e22e69604f3348344c91165c5395d032" + integrity sha512-9repI4BhNrR0KenoR9vm3/cIc1tSBIo+u1WVjKCAynahj25O8zfbiE6JtAtHPGQSs4yZ+bA8mRasRP+qc+2R5A== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-destructuring@^7.18.13": - version "7.18.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.13.tgz#9e03bc4a94475d62b7f4114938e6c5c33372cbf5" - integrity sha512-TodpQ29XekIsex2A+YJPj5ax2plkGa8YYY6mFjCohk/IG9IY42Rtuj1FuDeemfg2ipxIFLzPeA83SIBnlhSIow== +"@babel/plugin-transform-destructuring@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.6.tgz#a98b0e42c7ffbf5eefcbcf33280430f230895c6f" + integrity sha512-tgy3u6lRp17ilY8r1kP4i2+HDUwxlVqq3RTc943eAWSzGgpU1qhiKpqZ5CMyHReIYPHdo3Kg8v8edKtDqSVEyQ== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4": version "7.18.6" @@ -696,12 +687,12 @@ "@babel/helper-create-regexp-features-plugin" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-duplicate-keys@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz#687f15ee3cdad6d85191eb2a372c4528eaa0ae0e" - integrity sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw== +"@babel/plugin-transform-duplicate-keys@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.6.tgz#e6c94e8cd3c9dd8a88144f7b78ae22975a7ff473" + integrity sha512-NJU26U/208+sxYszf82nmGYqVF9QN8py2HFTblPT9hbawi8+1C5a9JubODLTGFuT0qlkqVinmkwOD13s0sZktg== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-exponentiation-operator@^7.18.6": version "7.18.6" @@ -711,28 +702,28 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-for-of@^7.18.8": - version "7.18.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz#6ef8a50b244eb6a0bdbad0c7c61877e4e30097c1" - integrity sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ== +"@babel/plugin-transform-for-of@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.6.tgz#e0fdb813be908e91ccc9ec87b30cc2eabf046f7c" + integrity sha512-WAjoMf4wIiSsy88KmG7tgj2nFdEK7E46tArVtcgED7Bkj6Fg/tG5SbvNIOKxbFS2VFgNh6+iaPswBeQZm4ox8w== dependencies: "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-function-name@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz#cc354f8234e62968946c61a46d6365440fc764e0" - integrity sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ== +"@babel/plugin-transform-function-name@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.6.tgz#6a7e4ae2893d336fd1b8f64c9f92276391d0f1b4" + integrity sha512-kJha/Gbs5RjzIu0CxZwf5e3aTTSlhZnHMT8zPWnJMjNpLOUgqevg+PN5oMH68nMCXnfiMo4Bhgxqj59KHTlAnA== dependencies: - "@babel/helper-compilation-targets" "^7.18.9" - "@babel/helper-function-name" "^7.18.9" - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-compilation-targets" "^7.18.6" + "@babel/helper-function-name" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-literals@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz#72796fdbef80e56fba3c6a699d54f0de557444bc" - integrity sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg== +"@babel/plugin-transform-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.6.tgz#9d6af353b5209df72960baf4492722d56f39a205" + integrity sha512-x3HEw0cJZVDoENXOp20HlypIHfl0zMIhMVZEBVTfmqbObIpsMxMbmU5nOEO8R7LYT+z5RORKPlTI5Hj4OsO9/Q== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-member-expression-literals@^7.18.6": version "7.18.6" @@ -760,14 +751,14 @@ "@babel/helper-simple-access" "^7.18.6" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-systemjs@^7.19.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.0.tgz#5f20b471284430f02d9c5059d9b9a16d4b085a1f" - integrity sha512-x9aiR0WXAWmOWsqcsnrzGR+ieaTMVyGyffPVA7F8cXAGt/UxefYv6uSHZLkAFChN5M5Iy1+wjE+xJuPt22H39A== +"@babel/plugin-transform-modules-systemjs@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.6.tgz#026511b7657d63bf5d4cf2fd4aeb963139914a54" + integrity sha512-UbPYpXxLjTw6w6yXX2BYNxF3p6QY225wcTkfQCy3OMnSlS/C3xGtwUjEzGkldb/sy6PWLiCQ3NbYfjWUTI3t4g== dependencies: "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-module-transforms" "^7.19.0" - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/helper-validator-identifier" "^7.18.6" babel-plugin-dynamic-import-node "^2.3.3" @@ -779,13 +770,13 @@ "@babel/helper-module-transforms" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-named-capturing-groups-regex@^7.19.1": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz#ec7455bab6cd8fb05c525a94876f435a48128888" - integrity sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw== +"@babel/plugin-transform-named-capturing-groups-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz#c89bfbc7cc6805d692f3a49bc5fc1b630007246d" + integrity sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.19.0" - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-new-target@^7.18.6": version "7.18.6" @@ -802,10 +793,10 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/helper-replace-supers" "^7.18.6" -"@babel/plugin-transform-parameters@^7.18.8": - version "7.18.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz#ee9f1a0ce6d78af58d0956a9378ea3427cccb48a" - integrity sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg== +"@babel/plugin-transform-parameters@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.6.tgz#cbe03d5a4c6385dd756034ac1baa63c04beab8dc" + integrity sha512-FjdqgMv37yVl/gwvzkcB+wfjRI8HQmc5EgOG9iGNvUY1ok+TjsoaMP7IqCDZBhkFcM5f3OPVMs6Dmp03C5k4/A== dependencies: "@babel/helper-plugin-utils" "^7.18.6" @@ -832,15 +823,15 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-runtime@^7.12.10": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.1.tgz#a3df2d7312eea624c7889a2dcd37fd1dfd25b2c6" - integrity sha512-2nJjTUFIzBMP/f/miLxEK9vxwW/KUXsdvN4sR//TmuDhe6yU2h57WmIOE12Gng3MDP/xpjUV/ToZRdcf8Yj4fA== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.6.tgz#77b14416015ea93367ca06979710f5000ff34ccb" + integrity sha512-8uRHk9ZmRSnWqUgyae249EJZ94b0yAGLBIqzZzl+0iEdbno55Pmlt/32JZsHwXD9k/uZj18Aqqk35wBX4CBTXA== dependencies: "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-plugin-utils" "^7.19.0" - babel-plugin-polyfill-corejs2 "^0.3.3" - babel-plugin-polyfill-corejs3 "^0.6.0" - babel-plugin-polyfill-regenerator "^0.4.1" + "@babel/helper-plugin-utils" "^7.18.6" + babel-plugin-polyfill-corejs2 "^0.3.1" + babel-plugin-polyfill-corejs3 "^0.5.2" + babel-plugin-polyfill-regenerator "^0.3.1" semver "^6.3.0" "@babel/plugin-transform-shorthand-properties@^7.18.6": @@ -850,13 +841,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-spread@^7.19.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz#dd60b4620c2fec806d60cfaae364ec2188d593b6" - integrity sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w== +"@babel/plugin-transform-spread@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.6.tgz#82b080241965f1689f0a60ecc6f1f6575dbdb9d6" + integrity sha512-ayT53rT/ENF8WWexIRg9AiV9h0aIteyWn5ptfZTZQrjk/+f3WdrJGCY4c9wcgl2+MKkKPhzbYp97FTsquZpDCw== dependencies: - "@babel/helper-plugin-utils" "^7.19.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.6" "@babel/plugin-transform-sticky-regex@^7.18.6": version "7.18.6" @@ -865,35 +856,35 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-template-literals@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz#04ec6f10acdaa81846689d63fae117dd9c243a5e" - integrity sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA== +"@babel/plugin-transform-template-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.6.tgz#b763f4dc9d11a7cce58cf9a490d82e80547db9c2" + integrity sha512-UuqlRrQmT2SWRvahW46cGSany0uTlcj8NYOS5sRGYi8FxPYPoLd5DDmMd32ZXEj2Jq+06uGVQKHxa/hJx2EzKw== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-typeof-symbol@^7.18.9": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz#c8cea68263e45addcd6afc9091429f80925762c0" - integrity sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw== +"@babel/plugin-transform-typeof-symbol@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.6.tgz#486bb39d5a18047358e0d04dc0d2f322f0b92e92" + integrity sha512-7m71iS/QhsPk85xSjFPovHPcH3H9qeyzsujhTc+vcdnsXavoWYJ74zx0lP5RhpC5+iDnVLO+PPMHzC11qels1g== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-typescript@^7.18.6": - version "7.18.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.18.12.tgz#712e9a71b9e00fde9f8c0238e0cceee86ab2f8fd" - integrity sha512-2vjjam0cum0miPkenUbQswKowuxs/NjMwIKEq0zwegRxXk12C9YOF9STXnaUptITOtOJHKHpzvvWYOjbm6tc0w== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.18.6.tgz#8f4ade1a9cf253e5cf7c7c20173082c2c08a50a7" + integrity sha512-ijHNhzIrLj5lQCnI6aaNVRtGVuUZhOXFLRVFs7lLrkXTHip4FKty5oAuQdk4tywG0/WjXmjTfQCWmuzrvFer1w== dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.9" - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-typescript" "^7.18.6" -"@babel/plugin-transform-unicode-escapes@^7.18.10": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz#1ecfb0eda83d09bbcb77c09970c2dd55832aa246" - integrity sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ== +"@babel/plugin-transform-unicode-escapes@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.6.tgz#0d01fb7fb2243ae1c033f65f6e3b4be78db75f27" + integrity sha512-XNRwQUXYMP7VLuy54cr/KS/WeL3AZeORhrmeZ7iewgu+X2eBqmpaLI/hzqr9ZxCeUoq0ASK4GUzSM0BDhZkLFw== dependencies: - "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-unicode-regex@^7.18.6": version "7.18.6" @@ -904,28 +895,28 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/preset-env@^7.12.11": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.19.1.tgz#9f04c916f9c0205a48ebe5cc1be7768eb1983f67" - integrity sha512-c8B2c6D16Lp+Nt6HcD+nHl0VbPKVnNPTpszahuxJJnurfMtKeZ80A+qUv48Y7wqvS+dTFuLuaM9oYxyNHbCLWA== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.18.6.tgz#953422e98a5f66bc56cd0b9074eaea127ec86ace" + integrity sha512-WrthhuIIYKrEFAwttYzgRNQ5hULGmwTj+D6l7Zdfsv5M7IWV/OZbUfbeL++Qrzx1nVJwWROIFhCHRYQV4xbPNw== dependencies: - "@babel/compat-data" "^7.19.1" - "@babel/helper-compilation-targets" "^7.19.1" - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/compat-data" "^7.18.6" + "@babel/helper-compilation-targets" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/helper-validator-option" "^7.18.6" "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9" - "@babel/plugin-proposal-async-generator-functions" "^7.19.1" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.6" + "@babel/plugin-proposal-async-generator-functions" "^7.18.6" "@babel/plugin-proposal-class-properties" "^7.18.6" "@babel/plugin-proposal-class-static-block" "^7.18.6" "@babel/plugin-proposal-dynamic-import" "^7.18.6" - "@babel/plugin-proposal-export-namespace-from" "^7.18.9" + "@babel/plugin-proposal-export-namespace-from" "^7.18.6" "@babel/plugin-proposal-json-strings" "^7.18.6" - "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9" + "@babel/plugin-proposal-logical-assignment-operators" "^7.18.6" "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6" "@babel/plugin-proposal-numeric-separator" "^7.18.6" - "@babel/plugin-proposal-object-rest-spread" "^7.18.9" + "@babel/plugin-proposal-object-rest-spread" "^7.18.6" "@babel/plugin-proposal-optional-catch-binding" "^7.18.6" - "@babel/plugin-proposal-optional-chaining" "^7.18.9" + "@babel/plugin-proposal-optional-chaining" "^7.18.6" "@babel/plugin-proposal-private-methods" "^7.18.6" "@babel/plugin-proposal-private-property-in-object" "^7.18.6" "@babel/plugin-proposal-unicode-property-regex" "^7.18.6" @@ -947,41 +938,41 @@ "@babel/plugin-transform-arrow-functions" "^7.18.6" "@babel/plugin-transform-async-to-generator" "^7.18.6" "@babel/plugin-transform-block-scoped-functions" "^7.18.6" - "@babel/plugin-transform-block-scoping" "^7.18.9" - "@babel/plugin-transform-classes" "^7.19.0" - "@babel/plugin-transform-computed-properties" "^7.18.9" - "@babel/plugin-transform-destructuring" "^7.18.13" + "@babel/plugin-transform-block-scoping" "^7.18.6" + "@babel/plugin-transform-classes" "^7.18.6" + "@babel/plugin-transform-computed-properties" "^7.18.6" + "@babel/plugin-transform-destructuring" "^7.18.6" "@babel/plugin-transform-dotall-regex" "^7.18.6" - "@babel/plugin-transform-duplicate-keys" "^7.18.9" + "@babel/plugin-transform-duplicate-keys" "^7.18.6" "@babel/plugin-transform-exponentiation-operator" "^7.18.6" - "@babel/plugin-transform-for-of" "^7.18.8" - "@babel/plugin-transform-function-name" "^7.18.9" - "@babel/plugin-transform-literals" "^7.18.9" + "@babel/plugin-transform-for-of" "^7.18.6" + "@babel/plugin-transform-function-name" "^7.18.6" + "@babel/plugin-transform-literals" "^7.18.6" "@babel/plugin-transform-member-expression-literals" "^7.18.6" "@babel/plugin-transform-modules-amd" "^7.18.6" "@babel/plugin-transform-modules-commonjs" "^7.18.6" - "@babel/plugin-transform-modules-systemjs" "^7.19.0" + "@babel/plugin-transform-modules-systemjs" "^7.18.6" "@babel/plugin-transform-modules-umd" "^7.18.6" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.19.1" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.18.6" "@babel/plugin-transform-new-target" "^7.18.6" "@babel/plugin-transform-object-super" "^7.18.6" - "@babel/plugin-transform-parameters" "^7.18.8" + "@babel/plugin-transform-parameters" "^7.18.6" "@babel/plugin-transform-property-literals" "^7.18.6" "@babel/plugin-transform-regenerator" "^7.18.6" "@babel/plugin-transform-reserved-words" "^7.18.6" "@babel/plugin-transform-shorthand-properties" "^7.18.6" - "@babel/plugin-transform-spread" "^7.19.0" + "@babel/plugin-transform-spread" "^7.18.6" "@babel/plugin-transform-sticky-regex" "^7.18.6" - "@babel/plugin-transform-template-literals" "^7.18.9" - "@babel/plugin-transform-typeof-symbol" "^7.18.9" - "@babel/plugin-transform-unicode-escapes" "^7.18.10" + "@babel/plugin-transform-template-literals" "^7.18.6" + "@babel/plugin-transform-typeof-symbol" "^7.18.6" + "@babel/plugin-transform-unicode-escapes" "^7.18.6" "@babel/plugin-transform-unicode-regex" "^7.18.6" "@babel/preset-modules" "^0.1.5" - "@babel/types" "^7.19.0" - babel-plugin-polyfill-corejs2 "^0.3.3" - babel-plugin-polyfill-corejs3 "^0.6.0" - babel-plugin-polyfill-regenerator "^0.4.1" - core-js-compat "^3.25.1" + "@babel/types" "^7.18.6" + babel-plugin-polyfill-corejs2 "^0.3.1" + babel-plugin-polyfill-corejs3 "^0.5.2" + babel-plugin-polyfill-regenerator "^0.3.1" + core-js-compat "^3.22.1" semver "^6.3.0" "@babel/preset-modules@^0.1.5": @@ -1005,9 +996,9 @@ "@babel/plugin-transform-typescript" "^7.18.6" "@babel/register@^7.12.10": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.18.9.tgz#1888b24bc28d5cc41c412feb015e9ff6b96e439c" - integrity sha512-ZlbnXDcNYHMR25ITwwNKT88JiaukkdVj/nG7r3wnuXkOTHc60Uy05PwMCPre0hSkY68E6zK3xz+vUJSP2jWmcw== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.18.6.tgz#48a4520f1b2a7d7ac861e8148caeb0cefe6c59db" + integrity sha512-tkYtONzaO8rQubZzpBnvZPFcHgh8D9F55IjOsYton4X2IBoyRn2ZSWQqySTZnUn2guZbxbQiAB27hJEbvXamhQ== dependencies: clone-deep "^4.0.1" find-cache-dir "^2.0.0" @@ -1016,71 +1007,77 @@ source-map-support "^0.5.16" "@babel/runtime@^7.12.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259" - integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580" + integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ== dependencies: regenerator-runtime "^0.13.4" -"@babel/template@^7.18.10", "@babel/template@^7.3.3": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" - integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== +"@babel/template@^7.18.6", "@babel/template@^7.3.3": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31" + integrity sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw== dependencies: "@babel/code-frame" "^7.18.6" - "@babel/parser" "^7.18.10" - "@babel/types" "^7.18.10" + "@babel/parser" "^7.18.6" + "@babel/types" "^7.18.6" "@babel/traverse@^7.1.6": - version "7.18.13" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.13.tgz#5ab59ef51a997b3f10c4587d648b9696b6cb1a68" - integrity sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA== - dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.18.13" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.18.9" - "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.18.13" - "@babel/types" "^7.18.13" + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.2.tgz#b77a52604b5cc836a9e1e08dca01cba67a12d2e8" + integrity sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.18.2" + "@babel/helper-environment-visitor" "^7.18.2" + "@babel/helper-function-name" "^7.17.9" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.18.0" + "@babel/types" "^7.18.2" debug "^4.1.0" globals "^11.1.0" -"@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.7.2": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.19.1.tgz#0fafe100a8c2a603b4718b1d9bf2568d1d193347" - integrity sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA== +"@babel/traverse@^7.13.0", "@babel/traverse@^7.18.6", "@babel/traverse@^7.7.2": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.6.tgz#a228562d2f46e89258efa4ddd0416942e2fd671d" + integrity sha512-zS/OKyqmD7lslOtFqbscH6gMLFYOfG1YPqCKfAW5KrTeolKqvB8UelR49Fpr6y93kYkW2Ik00mT1LOGiAGvizw== dependencies: "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.19.0" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.19.0" + "@babel/generator" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.6" + "@babel/helper-function-name" "^7.18.6" "@babel/helper-hoist-variables" "^7.18.6" "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.19.1" - "@babel/types" "^7.19.0" + "@babel/parser" "^7.18.6" + "@babel/types" "^7.18.6" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.13", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.0.tgz#75f21d73d73dc0351f3368d28db73465f4814600" - integrity sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA== +"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.6.tgz#5d781dd10a3f0c9f1f931bd19de5eb26ec31acf0" + integrity sha512-NdBNzPDwed30fZdDQtVR7ZgaO4UKjuaQFH9VArS+HMnurlOY0JWN+4ROlu/iapMFwjRQU4pOG4StZfDmulEwGA== dependencies: - "@babel/helper-string-parser" "^7.18.10" "@babel/helper-validator-identifier" "^7.18.6" to-fast-properties "^2.0.0" -"@babel/types@^7.2.0": - version "7.18.13" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.13.tgz#30aeb9e514f4100f7c1cb6e5ba472b30e48f519a" - integrity sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ== +"@babel/types@^7.18.2", "@babel/types@^7.18.6", "@babel/types@^7.18.7", "@babel/types@^7.4.4": + version "7.18.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.7.tgz#a4a2c910c15040ea52cdd1ddb1614a65c8041726" + integrity sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ== dependencies: - "@babel/helper-string-parser" "^7.18.10" "@babel/helper-validator-identifier" "^7.18.6" to-fast-properties "^2.0.0" +"@babel/types@^7.2.0": + version "7.18.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.4.tgz#27eae9b9fd18e9dccc3f9d6ad051336f307be354" + integrity sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -1102,9 +1099,9 @@ strip-json-comments "^3.1.1" "@humanwhocodes/config-array@^0.10.4": - version "0.10.4" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.10.4.tgz#01e7366e57d2ad104feea63e72248f22015c520c" - integrity sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw== + version "0.10.7" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.10.7.tgz#6d53769fd0c222767e6452e8ebda825c22e9f0dc" + integrity sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w== dependencies: "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" @@ -1141,28 +1138,28 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^29.0.3": - version "29.0.3" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.0.3.tgz#a222ab87e399317a89db88a58eaec289519e807a" - integrity sha512-cGg0r+klVHSYnfE977S9wmpuQ9L+iYuYgL+5bPXiUlUynLLYunRxswEmhBzvrSKGof5AKiHuTTmUKAqRcDY9dg== +"@jest/console@^29.1.2": + version "29.1.2" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.1.2.tgz#0ae975a70004696f8320490fcaa1a4152f7b62e4" + integrity sha512-ujEBCcYs82BTmRxqfHMQggSlkUZP63AE5YEaTPj7eFyJOzukkTorstOUC7L6nE3w5SYadGVAnTsQ/ZjTGL0qYQ== dependencies: - "@jest/types" "^29.0.3" + "@jest/types" "^29.1.2" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^29.0.3" - jest-util "^29.0.3" + jest-message-util "^29.1.2" + jest-util "^29.1.2" slash "^3.0.0" -"@jest/core@^29.0.3": - version "29.0.3" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.0.3.tgz#ba22a9cbd0c7ba36e04292e2093c547bf53ec1fd" - integrity sha512-1d0hLbOrM1qQE3eP3DtakeMbKTcXiXP3afWxqz103xPyddS2NhnNghS7MaXx1dcDt4/6p4nlhmeILo2ofgi8cQ== +"@jest/core@^29.1.2": + version "29.1.2" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.1.2.tgz#e5ce7a71e7da45156a96fb5eeed11d18b67bd112" + integrity sha512-sCO2Va1gikvQU2ynDN8V4+6wB7iVrD2CvT0zaRst4rglf56yLly0NQ9nuRRAWFeimRf+tCdFsb1Vk1N9LrrMPA== dependencies: - "@jest/console" "^29.0.3" - "@jest/reporters" "^29.0.3" - "@jest/test-result" "^29.0.3" - "@jest/transform" "^29.0.3" - "@jest/types" "^29.0.3" + "@jest/console" "^29.1.2" + "@jest/reporters" "^29.1.2" + "@jest/test-result" "^29.1.2" + "@jest/transform" "^29.1.2" + "@jest/types" "^29.1.2" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" @@ -1170,32 +1167,32 @@ exit "^0.1.2" graceful-fs "^4.2.9" jest-changed-files "^29.0.0" - jest-config "^29.0.3" - jest-haste-map "^29.0.3" - jest-message-util "^29.0.3" + jest-config "^29.1.2" + jest-haste-map "^29.1.2" + jest-message-util "^29.1.2" jest-regex-util "^29.0.0" - jest-resolve "^29.0.3" - jest-resolve-dependencies "^29.0.3" - jest-runner "^29.0.3" - jest-runtime "^29.0.3" - jest-snapshot "^29.0.3" - jest-util "^29.0.3" - jest-validate "^29.0.3" - jest-watcher "^29.0.3" + jest-resolve "^29.1.2" + jest-resolve-dependencies "^29.1.2" + jest-runner "^29.1.2" + jest-runtime "^29.1.2" + jest-snapshot "^29.1.2" + jest-util "^29.1.2" + jest-validate "^29.1.2" + jest-watcher "^29.1.2" micromatch "^4.0.4" - pretty-format "^29.0.3" + pretty-format "^29.1.2" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^29.0.3": - version "29.0.3" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.0.3.tgz#7745ec30a954e828e8cc6df6a13280d3b51d8f35" - integrity sha512-iKl272NKxYNQNqXMQandAIwjhQaGw5uJfGXduu8dS9llHi8jV2ChWrtOAVPnMbaaoDhnI3wgUGNDvZgHeEJQCA== +"@jest/environment@^29.1.2": + version "29.1.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.1.2.tgz#bb51a43fce9f960ba9a48f0b5b556f30618ebc0a" + integrity sha512-rG7xZ2UeOfvOVzoLIJ0ZmvPl4tBEQ2n73CZJSlzUjPw4or1oSWC0s0Rk0ZX+pIBJ04aVr6hLWFn1DFtrnf8MhQ== dependencies: - "@jest/fake-timers" "^29.0.3" - "@jest/types" "^29.0.3" + "@jest/fake-timers" "^29.1.2" + "@jest/types" "^29.1.2" "@types/node" "*" - jest-mock "^29.0.3" + jest-mock "^29.1.2" "@jest/expect-utils@^28.1.3": version "28.1.3" @@ -1204,53 +1201,53 @@ dependencies: jest-get-type "^28.0.2" -"@jest/expect-utils@^29.0.3": - version "29.0.3" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.0.3.tgz#f5bb86f5565bf2dacfca31ccbd887684936045b2" - integrity sha512-i1xUkau7K/63MpdwiRqaxgZOjxYs4f0WMTGJnYwUKubsNRZSeQbLorS7+I4uXVF9KQ5r61BUPAUMZ7Lf66l64Q== +"@jest/expect-utils@^29.1.2": + version "29.1.2" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.1.2.tgz#66dbb514d38f7d21456bc774419c9ae5cca3f88d" + integrity sha512-4a48bhKfGj/KAH39u0ppzNTABXQ8QPccWAFUFobWBaEMSMp+sB31Z2fK/l47c4a/Mu1po2ffmfAIPxXbVTXdtg== dependencies: jest-get-type "^29.0.0" -"@jest/expect@^29.0.3": - version "29.0.3" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.0.3.tgz#9dc7c46354eeb7a348d73881fba6402f5fdb2c30" - integrity sha512-6W7K+fsI23FQ01H/BWccPyDZFrnU9QlzDcKOjrNVU5L8yUORFAJJIpmyxWPW70+X624KUNqzZwPThPMX28aXEQ== +"@jest/expect@^29.1.2": + version "29.1.2" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.1.2.tgz#334a86395f621f1ab63ad95b06a588b9114d7b7a" + integrity sha512-FXw/UmaZsyfRyvZw3M6POgSNqwmuOXJuzdNiMWW9LCYo0GRoRDhg+R5iq5higmRTHQY7hx32+j7WHwinRmoILQ== dependencies: - expect "^29.0.3" - jest-snapshot "^29.0.3" + expect "^29.1.2" + jest-snapshot "^29.1.2" -"@jest/fake-timers@^29.0.3": - version "29.0.3" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.0.3.tgz#ad5432639b715d45a86a75c47fd75019bc36b22c" - integrity sha512-tmbUIo03x0TdtcZCESQ0oQSakPCpo7+s6+9mU19dd71MptkP4zCwoeZqna23//pgbhtT1Wq02VmA9Z9cNtvtCQ== +"@jest/fake-timers@^29.1.2": + version "29.1.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.1.2.tgz#f157cdf23b4da48ce46cb00fea28ed1b57fc271a" + integrity sha512-GppaEqS+QQYegedxVMpCe2xCXxxeYwQ7RsNx55zc8f+1q1qevkZGKequfTASI7ejmg9WwI+SJCrHe9X11bLL9Q== dependencies: - "@jest/types" "^29.0.3" + "@jest/types" "^29.1.2" "@sinonjs/fake-timers" "^9.1.2" "@types/node" "*" - jest-message-util "^29.0.3" - jest-mock "^29.0.3" - jest-util "^29.0.3" + jest-message-util "^29.1.2" + jest-mock "^29.1.2" + jest-util "^29.1.2" -"@jest/globals@^29.0.3": - version "29.0.3" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.0.3.tgz#681950c430fdc13ff9aa89b2d8d572ac0e4a1bf5" - integrity sha512-YqGHT65rFY2siPIHHFjuCGUsbzRjdqkwbat+Of6DmYRg5shIXXrLdZoVE/+TJ9O1dsKsFmYhU58JvIbZRU1Z9w== +"@jest/globals@^29.1.2": + version "29.1.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.1.2.tgz#826ede84bc280ae7f789cb72d325c48cd048b9d3" + integrity sha512-uMgfERpJYoQmykAd0ffyMq8wignN4SvLUG6orJQRe9WAlTRc9cdpCaE/29qurXixYJVZWUqIBXhSk8v5xN1V9g== dependencies: - "@jest/environment" "^29.0.3" - "@jest/expect" "^29.0.3" - "@jest/types" "^29.0.3" - jest-mock "^29.0.3" + "@jest/environment" "^29.1.2" + "@jest/expect" "^29.1.2" + "@jest/types" "^29.1.2" + jest-mock "^29.1.2" -"@jest/reporters@^29.0.3": - version "29.0.3" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.0.3.tgz#735f110e08b44b38729d8dbbb74063bdf5aba8a5" - integrity sha512-3+QU3d4aiyOWfmk1obDerie4XNCaD5Xo1IlKNde2yGEi02WQD+ZQD0i5Hgqm1e73sMV7kw6pMlCnprtEwEVwxw== +"@jest/reporters@^29.1.2": + version "29.1.2" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.1.2.tgz#5520898ed0a4ecf69d8b671e1dc8465d0acdfa6e" + integrity sha512-X4fiwwyxy9mnfpxL0g9DD0KcTmEIqP0jUdnc2cfa9riHy+I6Gwwp5vOZiwyg0vZxfSDxrOlK9S4+340W4d+DAA== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^29.0.3" - "@jest/test-result" "^29.0.3" - "@jest/transform" "^29.0.3" - "@jest/types" "^29.0.3" + "@jest/console" "^29.1.2" + "@jest/test-result" "^29.1.2" + "@jest/transform" "^29.1.2" + "@jest/types" "^29.1.2" "@jridgewell/trace-mapping" "^0.3.15" "@types/node" "*" chalk "^4.0.0" @@ -1263,9 +1260,9 @@ istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.1.3" - jest-message-util "^29.0.3" - jest-util "^29.0.3" - jest-worker "^29.0.3" + jest-message-util "^29.1.2" + jest-util "^29.1.2" + jest-worker "^29.1.2" slash "^3.0.0" string-length "^4.0.1" strip-ansi "^6.0.0" @@ -1295,42 +1292,42 @@ callsites "^3.0.0" graceful-fs "^4.2.9" -"@jest/test-result@^29.0.3": - version "29.0.3" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.0.3.tgz#b03d8ef4c58be84cd5d5d3b24d4b4c8cabbf2746" - integrity sha512-vViVnQjCgTmbhDKEonKJPtcFe9G/CJO4/Np4XwYJah+lF2oI7KKeRp8t1dFvv44wN2NdbDb/qC6pi++Vpp0Dlg== +"@jest/test-result@^29.1.2": + version "29.1.2" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.1.2.tgz#6a8d006eb2b31ce0287d1fc10d12b8ff8504f3c8" + integrity sha512-jjYYjjumCJjH9hHCoMhA8PCl1OxNeGgAoZ7yuGYILRJX9NjgzTN0pCT5qAoYR4jfOP8htIByvAlz9vfNSSBoVg== dependencies: - "@jest/console" "^29.0.3" - "@jest/types" "^29.0.3" + "@jest/console" "^29.1.2" + "@jest/types" "^29.1.2" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^29.0.3": - version "29.0.3" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.0.3.tgz#0681061ad21fb8e293b49c4fdf7e631ca79240ba" - integrity sha512-Hf4+xYSWZdxTNnhDykr8JBs0yBN/nxOXyUQWfotBUqqy0LF9vzcFB0jm/EDNZCx587znLWTIgxcokW7WeZMobQ== +"@jest/test-sequencer@^29.1.2": + version "29.1.2" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.1.2.tgz#10bfd89c08bfdba382eb05cc79c1d23a01238a93" + integrity sha512-fU6dsUqqm8sA+cd85BmeF7Gu9DsXVWFdGn9taxM6xN1cKdcP/ivSgXh5QucFRFz1oZxKv3/9DYYbq0ULly3P/Q== dependencies: - "@jest/test-result" "^29.0.3" + "@jest/test-result" "^29.1.2" graceful-fs "^4.2.9" - jest-haste-map "^29.0.3" + jest-haste-map "^29.1.2" slash "^3.0.0" -"@jest/transform@^29.0.3": - version "29.0.3" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.0.3.tgz#9eb1fed2072a0354f190569807d1250572fb0970" - integrity sha512-C5ihFTRYaGDbi/xbRQRdbo5ddGtI4VSpmL6AIcZxdhwLbXMa7PcXxxqyI91vGOFHnn5aVM3WYnYKCHEqmLVGzg== +"@jest/transform@^29.1.2": + version "29.1.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.1.2.tgz#20f814696e04f090421f6d505c14bbfe0157062a" + integrity sha512-2uaUuVHTitmkx1tHF+eBjb4p7UuzBG7SXIaA/hNIkaMP6K+gXYGxP38ZcrofzqN0HeZ7A90oqsOa97WU7WZkSw== dependencies: "@babel/core" "^7.11.6" - "@jest/types" "^29.0.3" + "@jest/types" "^29.1.2" "@jridgewell/trace-mapping" "^0.3.15" babel-plugin-istanbul "^6.1.1" chalk "^4.0.0" convert-source-map "^1.4.0" fast-json-stable-stringify "^2.1.0" graceful-fs "^4.2.9" - jest-haste-map "^29.0.3" + jest-haste-map "^29.1.2" jest-regex-util "^29.0.0" - jest-util "^29.0.3" + jest-util "^29.1.2" micromatch "^4.0.4" pirates "^4.0.4" slash "^3.0.0" @@ -1348,10 +1345,10 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@jest/types@^29.0.3": - version "29.0.3" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.0.3.tgz#0be78fdddb1a35aeb2041074e55b860561c8ef63" - integrity sha512-coBJmOQvurXjN1Hh5PzF7cmsod0zLIOXpP8KD161mqNlroMhLcwpODiEzi7ZsRl5Z/AIuxpeNm8DCl43F4kz8A== +"@jest/types@^29.1.2": + version "29.1.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.1.2.tgz#7442d32b16bcd7592d9614173078b8c334ec730a" + integrity sha512-DcXGtoTykQB5jiwCmVr8H4vdg2OJhQex3qPkG+ISyDO7xQXbt/4R6dowcRyPemRnkH7JoHvZuxPBdlq+9JxFCg== dependencies: "@jest/schemas" "^29.0.0" "@types/istanbul-lib-coverage" "^2.0.0" @@ -1378,9 +1375,9 @@ "@jridgewell/trace-mapping" "^0.3.9" "@jridgewell/resolve-uri@^3.0.3": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + version "3.0.8" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.8.tgz#687cc2bbf243f4e9a868ecf2262318e2658873a1" + integrity sha512-YK5G9LaddzGbcucK4c8h5tWFmMPBvRZ/uyWmN1/SbBdIvqGUdWGkJ5BAaccgs6XbzVLsqbPJrBSFwKv3kT9i7w== "@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": version "1.1.2" @@ -1400,7 +1397,15 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.15", "@jridgewell/trace-mapping@^0.3.8", "@jridgewell/trace-mapping@^0.3.9": +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.8", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.14" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/trace-mapping@^0.3.15": version "0.3.15" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774" integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g== @@ -1417,13 +1422,6 @@ resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== -"@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": - version "5.1.1-v1" - resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" - integrity sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg== - dependencies: - eslint-scope "5.1.1" - "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1483,17 +1481,17 @@ "@octokit/types" "^6.0.3" universal-user-agent "^6.0.0" -"@octokit/openapi-types@^12.11.0": - version "12.11.0" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-12.11.0.tgz#da5638d64f2b919bca89ce6602d059f1b52d3ef0" - integrity sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ== +"@octokit/openapi-types@^11.2.0": + version "11.2.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-11.2.0.tgz#b38d7fc3736d52a1e96b230c1ccd4a58a2f400a6" + integrity sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA== "@octokit/plugin-paginate-rest@^2.16.8", "@octokit/plugin-paginate-rest@^2.17.0": - version "2.21.3" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz#7f12532797775640dbb8224da577da7dc210c87e" - integrity sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw== + version "2.17.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz#32e9c7cab2a374421d3d0de239102287d791bce7" + integrity sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw== dependencies: - "@octokit/types" "^6.40.0" + "@octokit/types" "^6.34.0" "@octokit/plugin-request-log@^1.0.4": version "1.0.4" @@ -1501,11 +1499,11 @@ integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== "@octokit/plugin-rest-endpoint-methods@^5.12.0", "@octokit/plugin-rest-endpoint-methods@^5.13.0": - version "5.16.2" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz#7ee8bf586df97dd6868cf68f641354e908c25342" - integrity sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw== + version "5.13.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz#8c46109021a3412233f6f50d28786f8e552427ba" + integrity sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA== dependencies: - "@octokit/types" "^6.39.0" + "@octokit/types" "^6.34.0" deprecation "^2.3.1" "@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0": @@ -1539,12 +1537,12 @@ "@octokit/plugin-request-log" "^1.0.4" "@octokit/plugin-rest-endpoint-methods" "^5.12.0" -"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.39.0", "@octokit/types@^6.40.0": - version "6.41.0" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.41.0.tgz#e58ef78d78596d2fb7df9c6259802464b5f84a04" - integrity sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg== +"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.34.0": + version "6.34.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.34.0.tgz#c6021333334d1ecfb5d370a8798162ddf1ae8218" + integrity sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw== dependencies: - "@octokit/openapi-types" "^12.11.0" + "@octokit/openapi-types" "^11.2.0" "@pkgr/utils@^2.3.1": version "2.3.1" @@ -1559,9 +1557,9 @@ tslib "^2.4.0" "@sinclair/typebox@^0.24.1": - version "0.24.42" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.42.tgz#a74b608d494a1f4cc079738e050142a678813f52" - integrity sha512-d+2AtrHGyWek2u2ITF0lHRIv6Tt7X0dEHW+0rP+5aDCEjC3fiN2RBjrLD0yU0at52BcZbRGxLbAtXiR0hFCjYw== + version "0.24.44" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.44.tgz#0a0aa3bf4a155a678418527342a3ee84bd8caa5c" + integrity sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg== "@sinonjs/commons@^1.7.0": version "1.8.3" @@ -1609,9 +1607,9 @@ "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.18.1" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.18.1.tgz#ce5e2c8c272b99b7a9fd69fa39f0b4cd85028bd9" - integrity sha512-FSdLaZh2UxaMuLp9lixWaHq/golWTRWOnRsAXzDTDSDOQLuZb1nsdCt6pJSPWSEQt2eFZ2YVk3oYhn+1kLMeMA== + version "7.17.1" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.17.1.tgz#1a0e73e8c28c7e832656db372b779bfd2ef37314" + integrity sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA== dependencies: "@babel/types" "^7.3.0" @@ -1629,11 +1627,6 @@ dependencies: base-x "^3.0.6" -"@types/caseless@*": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" - integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w== - "@types/content-type@^1.1.5": version "1.1.5" resolved "https://registry.yarnpkg.com/@types/content-type/-/content-type-1.1.5.tgz#aa02dca40864749a9e2bf0161a6216da57e3ede5" @@ -1666,9 +1659,9 @@ "@types/istanbul-lib-report" "*" "@types/jest@^29.0.0": - version "29.0.3" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.0.3.tgz#b61a5ed100850686b8d3c5e28e3a1926b2001b59" - integrity sha512-F6ukyCTwbfsEX5F2YmVYmM5TcTHy1q9P5rWlRbrk56KyMh3v9xRGUO3aa8+SkvMi0SHXtASJv1283enXimC0Og== + version "29.1.1" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.1.1.tgz#cf21a0835a1ba9a30ea1966019f1261c6a114c92" + integrity sha512-U9Ey07dGWl6fUFaIaUQUKWG5NoKi/zizeVQCGV8s4nSU0jPgqphVZvS64+8BtWYvrc3ZGw6wo943NSYPxkrp/g== dependencies: expect "^29.0.0" pretty-format "^29.0.0" @@ -1702,29 +1695,19 @@ integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA== "@types/node@*": - version "18.7.18" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.18.tgz#633184f55c322e4fb08612307c274ee6d5ed3154" - integrity sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg== + version "18.0.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.0.tgz#67c7b724e1bcdd7a8821ce0d5ee184d3b4dd525a" + integrity sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA== "@types/node@16": - version "16.11.59" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.59.tgz#823f238b9063ccc3b3b7f13186f143a57926c4f6" - integrity sha512-6u+36Dj3aDzhfBVUf/mfmc92OEdzQ2kx2jcXGdigfl70E/neV21ZHE6UCz4MDzTRcVqGAM27fk+DLXvyDsn3Jw== + version "16.11.62" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.62.tgz#bab2e6208531321d147eda20c38e389548cd5ffc" + integrity sha512-K/ggecSdwAAy2NUW4WKmF4Rc03GKbsfP+k326UWgckoS+Rzd2PaWbjk76dSmqdLQvLTJAO9axiTUJ6488mFsYQ== "@types/prettier@^2.1.5": - version "2.7.0" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.0.tgz#ea03e9f0376a4446f44797ca19d9c46c36e352dc" - integrity sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A== - -"@types/request@^2.48.5": - version "2.48.8" - resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.8.tgz#0b90fde3b655ab50976cb8c5ac00faca22f5a82c" - integrity sha512-whjk1EDJPcAR2kYHRbFl/lKeeKYTi05A15K9bnLInCVroNDCtXce57xKdI0/rQaA3K+6q0eFyUBPmqfSndUZdQ== - dependencies: - "@types/caseless" "*" - "@types/node" "*" - "@types/tough-cookie" "*" - form-data "^2.5.0" + version "2.6.3" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.3.tgz#68ada76827b0010d0db071f739314fa429943d0a" + integrity sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg== "@types/retry@0.12.0": version "0.12.0" @@ -1736,101 +1719,96 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== -"@types/tough-cookie@*": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397" - integrity sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw== - "@types/yargs-parser@*": version "21.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== "@types/yargs@^17.0.8": - version "17.0.12" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.12.tgz#0745ff3e4872b4ace98616d4b7e37ccbd75f9526" - integrity sha512-Nz4MPhecOFArtm81gFQvQqdV7XYCrWKx5uUt6GNHredFHn1i2mtWqXTON7EPXMtNi1qjtjEM/VCHDhcHsAMLXQ== + version "17.0.10" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.10.tgz#591522fce85d8739bca7b8bb90d048e4478d186a" + integrity sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA== dependencies: "@types/yargs-parser" "*" "@typescript-eslint/eslint-plugin@^5.6.0": - version "5.38.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.38.0.tgz#ac919a199548861012e8c1fb2ec4899ac2bc22ae" - integrity sha512-GgHi/GNuUbTOeoJiEANi0oI6fF3gBQc3bGFYj40nnAPCbhrtEDf2rjBmefFadweBmO1Du1YovHeDP2h5JLhtTQ== + version "5.27.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.27.0.tgz#23d82a4f21aaafd8f69dbab7e716323bb6695cc8" + integrity sha512-DDrIA7GXtmHXr1VCcx9HivA39eprYBIFxbQEHI6NyraRDxCGpxAFiYQAT/1Y0vh1C+o2vfBiy4IuPoXxtTZCAQ== dependencies: - "@typescript-eslint/scope-manager" "5.38.0" - "@typescript-eslint/type-utils" "5.38.0" - "@typescript-eslint/utils" "5.38.0" + "@typescript-eslint/scope-manager" "5.27.0" + "@typescript-eslint/type-utils" "5.27.0" + "@typescript-eslint/utils" "5.27.0" debug "^4.3.4" + functional-red-black-tree "^1.0.1" ignore "^5.2.0" regexpp "^3.2.0" semver "^7.3.7" tsutils "^3.21.0" "@typescript-eslint/parser@^5.6.0": - version "5.38.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.38.0.tgz#5a59a1ff41a7b43aacd1bb2db54f6bf1c02b2ff8" - integrity sha512-/F63giJGLDr0ms1Cr8utDAxP2SPiglaD6V+pCOcG35P2jCqdfR7uuEhz1GIC3oy4hkUF8xA1XSXmd9hOh/a5EA== + version "5.27.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.27.0.tgz#62bb091ed5cf9c7e126e80021bb563dcf36b6b12" + integrity sha512-8oGjQF46c52l7fMiPPvX4It3u3V3JipssqDfHQ2hcR0AeR8Zge+OYyKUCm5b70X72N1qXt0qgHenwN6Gc2SXZA== dependencies: - "@typescript-eslint/scope-manager" "5.38.0" - "@typescript-eslint/types" "5.38.0" - "@typescript-eslint/typescript-estree" "5.38.0" + "@typescript-eslint/scope-manager" "5.27.0" + "@typescript-eslint/types" "5.27.0" + "@typescript-eslint/typescript-estree" "5.27.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.38.0": - version "5.38.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.38.0.tgz#8f0927024b6b24e28671352c93b393a810ab4553" - integrity sha512-ByhHIuNyKD9giwkkLqzezZ9y5bALW8VNY6xXcP+VxoH4JBDKjU5WNnsiD4HJdglHECdV+lyaxhvQjTUbRboiTA== +"@typescript-eslint/scope-manager@5.27.0": + version "5.27.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.27.0.tgz#a272178f613050ed62f51f69aae1e19e870a8bbb" + integrity sha512-VnykheBQ/sHd1Vt0LJ1JLrMH1GzHO+SzX6VTXuStISIsvRiurue/eRkTqSrG0CexHQgKG8shyJfR4o5VYioB9g== dependencies: - "@typescript-eslint/types" "5.38.0" - "@typescript-eslint/visitor-keys" "5.38.0" + "@typescript-eslint/types" "5.27.0" + "@typescript-eslint/visitor-keys" "5.27.0" -"@typescript-eslint/type-utils@5.38.0": - version "5.38.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.38.0.tgz#c8b7f681da825fcfc66ff2b63d70693880496876" - integrity sha512-iZq5USgybUcj/lfnbuelJ0j3K9dbs1I3RICAJY9NZZpDgBYXmuUlYQGzftpQA9wC8cKgtS6DASTvF3HrXwwozA== +"@typescript-eslint/type-utils@5.27.0": + version "5.27.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.27.0.tgz#36fd95f6747412251d79c795b586ba766cf0974b" + integrity sha512-vpTvRRchaf628Hb/Xzfek+85o//zEUotr1SmexKvTfs7czXfYjXVT/a5yDbpzLBX1rhbqxjDdr1Gyo0x1Fc64g== dependencies: - "@typescript-eslint/typescript-estree" "5.38.0" - "@typescript-eslint/utils" "5.38.0" + "@typescript-eslint/utils" "5.27.0" debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/types@5.38.0": - version "5.38.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.38.0.tgz#8cd15825e4874354e31800dcac321d07548b8a5f" - integrity sha512-HHu4yMjJ7i3Cb+8NUuRCdOGu2VMkfmKyIJsOr9PfkBVYLYrtMCK/Ap50Rpov+iKpxDTfnqvDbuPLgBE5FwUNfA== +"@typescript-eslint/types@5.27.0": + version "5.27.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.27.0.tgz#c3f44b9dda6177a9554f94a74745ca495ba9c001" + integrity sha512-lY6C7oGm9a/GWhmUDOs3xAVRz4ty/XKlQ2fOLr8GAIryGn0+UBOoJDWyHer3UgrHkenorwvBnphhP+zPmzmw0A== -"@typescript-eslint/typescript-estree@5.38.0": - version "5.38.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.38.0.tgz#89f86b2279815c6fb7f57d68cf9b813f0dc25d98" - integrity sha512-6P0RuphkR+UuV7Avv7MU3hFoWaGcrgOdi8eTe1NwhMp2/GjUJoODBTRWzlHpZh6lFOaPmSvgxGlROa0Sg5Zbyg== +"@typescript-eslint/typescript-estree@5.27.0": + version "5.27.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.27.0.tgz#7965f5b553c634c5354a47dcce0b40b94611e995" + integrity sha512-QywPMFvgZ+MHSLRofLI7BDL+UczFFHyj0vF5ibeChDAJgdTV8k4xgEwF0geFhVlPc1p8r70eYewzpo6ps+9LJQ== dependencies: - "@typescript-eslint/types" "5.38.0" - "@typescript-eslint/visitor-keys" "5.38.0" + "@typescript-eslint/types" "5.27.0" + "@typescript-eslint/visitor-keys" "5.27.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.38.0": - version "5.38.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.38.0.tgz#5b31f4896471818153790700eb02ac869a1543f4" - integrity sha512-6sdeYaBgk9Fh7N2unEXGz+D+som2QCQGPAf1SxrkEr+Z32gMreQ0rparXTNGRRfYUWk/JzbGdcM8NSSd6oqnTA== +"@typescript-eslint/utils@5.27.0": + version "5.27.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.27.0.tgz#d0021cbf686467a6a9499bd0589e19665f9f7e71" + integrity sha512-nZvCrkIJppym7cIbP3pOwIkAefXOmfGPnCM0LQfzNaKxJHI6VjI8NC662uoiPlaf5f6ymkTy9C3NQXev2mdXmA== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.38.0" - "@typescript-eslint/types" "5.38.0" - "@typescript-eslint/typescript-estree" "5.38.0" + "@typescript-eslint/scope-manager" "5.27.0" + "@typescript-eslint/types" "5.27.0" + "@typescript-eslint/typescript-estree" "5.27.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/visitor-keys@5.38.0": - version "5.38.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.38.0.tgz#60591ca3bf78aa12b25002c0993d067c00887e34" - integrity sha512-MxnrdIyArnTi+XyFLR+kt/uNAcdOnmT+879os7qDRI+EYySR4crXJq9BXPfRzzLGq0wgxkwidrCJ9WCAoacm1w== +"@typescript-eslint/visitor-keys@5.27.0": + version "5.27.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.27.0.tgz#97aa9a5d2f3df8215e6d3b77f9d214a24db269bd" + integrity sha512-46cYrteA2MrIAjv9ai44OQDUoCZyHeGIc4lsjCUX2WT6r4C+kidz1bNiR4017wHOPUythYeH+Sc7/cFP97KEAA== dependencies: - "@typescript-eslint/types" "5.38.0" + "@typescript-eslint/types" "5.27.0" eslint-visitor-keys "^3.3.0" JSONStream@^1.0.3: @@ -1842,9 +1820,9 @@ JSONStream@^1.0.3: through ">=2.2.7 <3" ace-builds@^1.4.13: - version "1.9.6" - resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.9.6.tgz#2d3721f90f0664b79be9288f6319dd57576ff1e7" - integrity sha512-M/Li4hPruMSbkkg35LgdbsIBq0WuwrV4ztP2pKaww47rC/MvDc1bOrYxwJrfgxdlzyLKrja5bn+9KwwuzqB2xQ== + version "1.5.3" + resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.5.3.tgz#05f81d3464a9ea19696e5e6fd0f924d37dab442f" + integrity sha512-WN5BKR2aTSuBmisO8jo3Fytk6sOmJGki82v/Boeic81IgYN8pFHNkXq2anDF0XkmfDWMqLbRoW9sjc/GtKzQbQ== acorn-globals@^3.0.0: version "3.1.0" @@ -1887,12 +1865,17 @@ acorn@^7.0.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.5.0, acorn@^8.8.0: +acorn@^8.5.0: + version "8.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== + +acorn@^8.8.0: version "8.8.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== -ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: +ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1912,9 +1895,9 @@ align-text@^0.1.1, align-text@^0.1.3: repeat-string "^1.5.2" allchange@^1.0.6: - version "1.1.0" - resolved "https://registry.yarnpkg.com/allchange/-/allchange-1.1.0.tgz#f8fa129e4b40c0b0a2c072c530f2324c6590e208" - integrity sha512-brDWf2feuL3FRyivSyC6AKOgpX+bYgs1Z7+ZmLti6PnBdZgIjRSnKvlc68N8+1UX2rCISx2I+XuUvE3/GJNG2A== + version "1.0.6" + resolved "https://registry.yarnpkg.com/allchange/-/allchange-1.0.6.tgz#f905918255541dc92d6a1f5cdf758db4597f569c" + integrity sha512-37a4J55oSxhLmlS/DeBOKjKn5dbjkyR4qMJ9is8+CKLPTe7NybcWBYvrPLr9kVLBa6aigWrdovRHrQj/4v6k4w== dependencies: "@actions/core" "^1.4.0" "@actions/github" "^5.0.0" @@ -2027,18 +2010,6 @@ asn1.js@^5.2.0: minimalistic-assert "^1.0.0" safer-buffer "^2.1.0" -asn1@~0.2.3: - version "0.2.6" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" - integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== - assert@^1.4.0: version "1.5.0" resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" @@ -2059,32 +2030,17 @@ ast-types@^0.14.2: dependencies: tslib "^2.0.1" -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - available-typed-arrays@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== - -aws4@^1.8.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" - integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== - -babel-jest@^29.0.0, babel-jest@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.0.3.tgz#64e156a47a77588db6a669a88dedff27ed6e260f" - integrity sha512-ApPyHSOhS/sVzwUOQIWJmdvDhBsMG01HX9z7ogtkp1TToHGGUWFlnXJUIzCgKPSfiYLn3ibipCYzsKSURHEwLg== +babel-jest@^29.0.0, babel-jest@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.1.2.tgz#540d3241925c55240fb0c742e3ffc5f33a501978" + integrity sha512-IuG+F3HTHryJb7gacC7SQ59A9kO56BctUsT67uJHp1mMCHUOMXpDwOHWGifWqdWVknN2WNkCVQELPjXx0aLJ9Q== dependencies: - "@jest/transform" "^29.0.3" + "@jest/transform" "^29.1.2" "@types/babel__core" "^7.1.14" babel-plugin-istanbul "^6.1.1" babel-preset-jest "^29.0.2" @@ -2120,29 +2076,29 @@ babel-plugin-jest-hoist@^29.0.2: "@types/babel__core" "^7.1.14" "@types/babel__traverse" "^7.0.6" -babel-plugin-polyfill-corejs2@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz#5d1bd3836d0a19e1b84bbf2d9640ccb6f951c122" - integrity sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q== +babel-plugin-polyfill-corejs2@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz#440f1b70ccfaabc6b676d196239b138f8a2cfba5" + integrity sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w== dependencies: - "@babel/compat-data" "^7.17.7" - "@babel/helper-define-polyfill-provider" "^0.3.3" + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.3.1" semver "^6.1.1" -babel-plugin-polyfill-corejs3@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz#56ad88237137eade485a71b52f72dbed57c6230a" - integrity sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA== +babel-plugin-polyfill-corejs3@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz#aabe4b2fa04a6e038b688c5e55d44e78cd3a5f72" + integrity sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ== dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.3" - core-js-compat "^3.25.1" + "@babel/helper-define-polyfill-provider" "^0.3.1" + core-js-compat "^3.21.0" -babel-plugin-polyfill-regenerator@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz#390f91c38d90473592ed43351e801a9d3e0fd747" - integrity sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw== +babel-plugin-polyfill-regenerator@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz#2c0678ea47c75c8cc2fbb1852278d8fb68233990" + integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A== dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.3" + "@babel/helper-define-polyfill-provider" "^0.3.1" babel-preset-current-node-syntax@^1.0.0: version "1.0.1" @@ -2225,13 +2181,6 @@ base64-js@^1.0.2: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== - dependencies: - tweetnacl "^0.14.3" - before-after-hook@^2.2.0: version "2.2.2" resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" @@ -2308,11 +2257,6 @@ browser-pack@^6.0.1: through2 "^2.0.0" umd "^3.0.0" -browser-request@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/browser-request/-/browser-request-0.3.3.tgz#9ece5b5aca89a29932242e18bf933def9876cc17" - integrity sha512-YyNI4qJJ+piQG6MMEuo7J3Bzaqssufx04zpEKYfSrl/1Op59HWali9zMtBpXnkmqMcOuWJPZvudrm9wISmnCbg== - browser-resolve@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-2.0.0.tgz#99b7304cb392f8d73dba741bb2d7da28c6d7842b" @@ -2435,15 +2379,15 @@ browserify@^17.0.0: vm-browserify "^1.0.0" xtend "^4.0.0" -browserslist@^4.21.3, browserslist@^4.21.4: - version "4.21.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987" - integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw== +browserslist@^4.20.2, browserslist@^4.21.0: + version "4.21.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.1.tgz#c9b9b0a54c7607e8dc3e01a0d311727188011a00" + integrity sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ== dependencies: - caniuse-lite "^1.0.30001400" - electron-to-chromium "^1.4.251" - node-releases "^2.0.6" - update-browserslist-db "^1.0.9" + caniuse-lite "^1.0.30001359" + electron-to-chromium "^1.4.172" + node-releases "^2.0.5" + update-browserslist-db "^1.0.4" bs58@^5.0.0: version "5.0.0" @@ -2483,9 +2427,9 @@ builtin-status-codes@^3.0.0: integrity sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ== c8@^7.6.0: - version "7.12.0" - resolved "https://registry.yarnpkg.com/c8/-/c8-7.12.0.tgz#402db1c1af4af5249153535d1c84ad70c5c96b14" - integrity sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A== + version "7.11.3" + resolved "https://registry.yarnpkg.com/c8/-/c8-7.11.3.tgz#88c8459c1952ed4f701b619493c9ae732b057163" + integrity sha512-6YBmsaNmqRm9OS3ZbIiL2EZgi1+Xc4O24jL3vMYGE6idixYuGdy76rIfIdltSKDj9DpLNrcXSonUTR1miBD0wA== dependencies: "@bcoe/v8-coverage" "^0.2.3" "@istanbuljs/schema" "^0.1.3" @@ -2533,15 +2477,10 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001400: - version "1.0.30001409" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001409.tgz#6135da9dcab34cd9761d9cdb12a68e6740c5e96e" - integrity sha512-V0mnJ5dwarmhYv8/MzhJ//aW68UpvnQBXv8lJ2QUsvn2pHcmAuNtu8hQEDz37XnA1iE+lRR9CIfGWWpgJ5QedQ== - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== +caniuse-lite@^1.0.30001359: + version "1.0.30001361" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001361.tgz#ba2adb2527566fb96f3ac7c67698ae7fc495a28d" + integrity sha512-ybhCrjNtkFji1/Wto6SSJKkWk6kZgVQsDq5QI83SafsF6FXv2JB4df9eEdH6g8sdGgqTXrFLjAxqBGgYoU3azQ== catharsis@^0.9.0: version "0.9.0" @@ -2603,9 +2542,9 @@ chokidar@^3.4.0: fsevents "~2.3.2" ci-info@^3.2.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.4.0.tgz#b28484fd436cbc267900364f096c9dc185efb251" - integrity sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug== + version "3.3.2" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.2.tgz#6d2967ffa407466481c6c90b6e16b3098f080128" + integrity sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg== cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" @@ -2628,12 +2567,12 @@ clean-css@^4.1.11: source-map "~0.6.0" cli-color@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-2.0.3.tgz#73769ba969080629670f3f2ef69a4bf4e7cc1879" - integrity sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ== + version "2.0.2" + resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-2.0.2.tgz#e295addbae470800def0254183c648531cdf4e3f" + integrity sha512-g4JYjrTW9MGtCziFNjkqp3IMpGhnJyeB0lOtRPjQkYhXzKYr6tYnXKyEVnMzITxhpbahsEW9KsxOYIDKwcsIBw== dependencies: d "^1.0.1" - es5-ext "^0.10.61" + es5-ext "^0.10.59" es6-iterator "^2.0.3" memoizee "^0.4.15" timers-ext "^0.1.7" @@ -2709,13 +2648,6 @@ combine-source-map@^0.8.0, combine-source-map@~0.8.0: lodash.memoize "~3.0.3" source-map "~0.5.3" -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - commander@^2.19.0, commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -2783,23 +2715,19 @@ convert-source-map@~1.1.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" integrity sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg== -core-js-compat@^3.25.1: - version "3.25.2" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.25.2.tgz#7875573586809909c69e03ef310810c1969ee138" - integrity sha512-TxfyECD4smdn3/CjWxczVtJqVLEEC2up7/82t7vC0AzNogr+4nQ8vyF7abxAuTXWvjTClSbvGhU0RgqA4ToQaQ== +core-js-compat@^3.21.0, core-js-compat@^3.22.1: + version "3.23.3" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.23.3.tgz#7d8503185be76bb6d8d592c291a4457a8e440aa9" + integrity sha512-WSzUs2h2vvmKsacLHNTdpyOC9k43AEhcGoFlVgCY4L7aw98oSBKtPL6vD0/TqZjRWRQYdDSLkzZIni4Crbbiqw== dependencies: - browserslist "^4.21.4" + browserslist "^4.21.0" + semver "7.0.0" core-js@^2.4.0: version "2.6.12" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== -core-util-is@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== - core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" @@ -2875,13 +2803,6 @@ dash-ast@^1.0.0: resolved "https://registry.yarnpkg.com/dash-ast/-/dash-ast-1.0.0.tgz#12029ba5fb2f8aa6f0a861795b23c1b4b6c27d37" integrity sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA== -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== - dependencies: - assert-plus "^1.0.0" - de-indent@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" @@ -2946,11 +2867,6 @@ defined@^1.0.0: resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" integrity sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ== -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - deprecation@^2.0.0, deprecation@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" @@ -3062,18 +2978,10 @@ duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2: dependencies: readable-stream "^2.0.2" -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -electron-to-chromium@^1.4.251: - version "1.4.256" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.256.tgz#c735032f412505e8e0482f147a8ff10cfca45bf4" - integrity sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw== +electron-to-chromium@^1.4.172: + version "1.4.173" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.173.tgz#48f128dda49cd7f6317e65ac0085bd3a6b9b6e3b" + integrity sha512-Qo3LnVW6JRNhD32viSdPebxKI7K+3WeBDjU1+Q2yZS83zAh8C2LyPpzTimlciv6U74KpY9n/0ESAhUByRke0jw== elliptic@^6.5.3: version "6.5.4" @@ -3163,10 +3071,10 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@^0.10.61, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: - version "0.10.62" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5" - integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== +es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@^0.10.59, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: + version "0.10.61" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.61.tgz#311de37949ef86b6b0dcea894d1ffedb909d3269" + integrity sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA== dependencies: es6-iterator "^2.0.3" es6-symbol "^3.1.3" @@ -3246,11 +3154,12 @@ eslint-import-resolver-typescript@^3.5.1: synckit "^0.8.3" eslint-module-utils@^2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974" - integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA== + version "2.7.3" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" + integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== dependencies: debug "^3.2.7" + find-up "^2.1.0" eslint-plugin-import@^2.26.0: version "2.26.0" @@ -3281,7 +3190,7 @@ eslint-rule-composer@^0.3.0: resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== -eslint-scope@5.1.1, eslint-scope@^5.1.1: +eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -3473,38 +3382,23 @@ expect@^28.1.0: jest-message-util "^28.1.3" jest-util "^28.1.3" -expect@^29.0.0, expect@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/expect/-/expect-29.0.3.tgz#6be65ddb945202f143c4e07c083f4f39f3bd326f" - integrity sha512-t8l5DTws3212VbmPL+tBFXhjRHLmctHB0oQbL8eUc6S7NzZtYUhycrFO9mkxA0ZUC6FAWdNi7JchJSkODtcu1Q== +expect@^29.0.0, expect@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.1.2.tgz#82f8f28d7d408c7c68da3a386a490ee683e1eced" + integrity sha512-AuAGn1uxva5YBbBlXb+2JPxJRuemZsmlGcapPXWNSBNsQtAULfjioREGBWuI0EOvYUKjDnrCy8PW5Zlr1md5mw== dependencies: - "@jest/expect-utils" "^29.0.3" + "@jest/expect-utils" "^29.1.2" jest-get-type "^29.0.0" - jest-matcher-utils "^29.0.3" - jest-message-util "^29.0.3" - jest-util "^29.0.3" + jest-matcher-utils "^29.1.2" + jest-message-util "^29.1.2" + jest-util "^29.1.2" ext@^1.1.2: - version "1.7.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" - integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== + version "1.6.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.6.0.tgz#3871d50641e874cc172e2b53f919842d19db4c52" + integrity sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg== dependencies: - type "^2.7.2" - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== - -extsprintf@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" - integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== + type "^2.5.0" fake-indexeddb@^4.0.0: version "4.0.0" @@ -3518,7 +3412,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.11, fast-glob@^3.2.9: +fast-glob@^3.2.11: version "3.2.12" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== @@ -3529,6 +3423,17 @@ fast-glob@^3.2.11, fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -3581,6 +3486,13 @@ find-cache-dir@^2.0.0: make-dir "^2.0.0" pkg-dir "^3.0.0" +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== + dependencies: + locate-path "^2.0.0" + find-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" @@ -3613,9 +3525,9 @@ flat-cache@^3.0.4: rimraf "^3.0.2" flatted@^3.1.0: - version "3.2.7" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" - integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + version "3.2.5" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" + integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== for-each@^0.3.3: version "0.3.3" @@ -3632,29 +3544,6 @@ foreground-child@^2.0.0: cross-spawn "^7.0.0" signal-exit "^3.0.2" -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== - -form-data@^2.5.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" - integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - fs-readdir-recursive@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" @@ -3685,6 +3574,11 @@ function.prototype.name@^1.1.5: es-abstract "^1.19.0" functions-have-names "^1.2.2" +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + functions-have-names@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" @@ -3706,22 +3600,22 @@ get-caller-file@^2.0.5: integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" - integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== + version "1.1.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598" + integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA== dependencies: function-bind "^1.1.1" has "^1.0.3" has-symbols "^1.0.3" get-intrinsic@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598" - integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA== + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== dependencies: function-bind "^1.1.1" has "^1.0.3" - has-symbols "^1.0.3" + has-symbols "^1.0.1" get-package-type@^0.1.0: version "0.1.0" @@ -3746,13 +3640,6 @@ get-tsconfig@^4.2.0: resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.2.0.tgz#ff368dd7104dab47bf923404eb93838245c66543" integrity sha512-X8u8fREiYOE6S8hLbq99PeykTDoLVnxvF4DjWKJmz9xy2nNRdUcV8ZN9tniJFeKyTU3qnC9lL8n4Chd6LmVKHg== -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== - dependencies: - assert-plus "^1.0.0" - glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -3767,7 +3654,7 @@ glob-parent@^6.0.1: dependencies: is-glob "^4.0.3" -glob@^7.1.0, glob@^7.1.3, glob@^7.1.4, glob@^7.2.0: +glob@^7.0.0, glob@^7.1.0, glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -3785,9 +3672,9 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.15.0: - version "13.17.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4" - integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw== + version "13.15.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.15.0.tgz#38113218c907d2f7e98658af246cef8b77e90bac" + integrity sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog== dependencies: type-fest "^0.20.2" @@ -3824,7 +3711,7 @@ globrex@^0.1.2: resolved "https://registry.yarnpkg.com/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== -graceful-fs@^4.1.9, graceful-fs@^4.2.4, graceful-fs@^4.2.9: +graceful-fs@^4.2.4, graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== @@ -3834,19 +3721,6 @@ grapheme-splitter@^1.0.4: resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== - -har-validator@~5.1.3: - version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" - integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" - has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -3869,7 +3743,7 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" -has-symbols@^1.0.2, has-symbols@^1.0.3: +has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== @@ -3910,7 +3784,7 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" -he@^1.2.0: +he@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== @@ -3934,15 +3808,6 @@ htmlescape@^1.1.0: resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351" integrity sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg== -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ== - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" @@ -4079,13 +3944,20 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.4: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== -is-core-module@^2.10.0, is-core-module@^2.8.1, is-core-module@^2.9.0: +is-core-module@^2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== dependencies: has "^1.0.3" +is-core-module@^2.8.1, is-core-module@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" + integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== + dependencies: + has "^1.0.3" + is-date-object@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" @@ -4214,11 +4086,6 @@ is-typed-array@^1.1.3, is-typed-array@^1.1.9: for-each "^0.3.3" has-tostringtag "^1.0.0" -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== - is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" @@ -4253,11 +4120,6 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== - istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" @@ -4293,9 +4155,9 @@ istanbul-lib-source-maps@^4.0.0: source-map "^0.6.1" istanbul-reports@^3.1.3, istanbul-reports@^3.1.4: - version "3.1.5" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" - integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + version "3.1.4" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c" + integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" @@ -4308,74 +4170,74 @@ jest-changed-files@^29.0.0: execa "^5.0.0" p-limit "^3.1.0" -jest-circus@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.0.3.tgz#90faebc90295291cfc636b27dbd82e3bfb9e7a48" - integrity sha512-QeGzagC6Hw5pP+df1+aoF8+FBSgkPmraC1UdkeunWh0jmrp7wC0Hr6umdUAOELBQmxtKAOMNC3KAdjmCds92Zg== +jest-circus@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.1.2.tgz#4551068e432f169a53167fe1aef420cf51c8a735" + integrity sha512-ajQOdxY6mT9GtnfJRZBRYS7toNIJayiiyjDyoZcnvPRUPwJ58JX0ci0PKAKUo2C1RyzlHw0jabjLGKksO42JGA== dependencies: - "@jest/environment" "^29.0.3" - "@jest/expect" "^29.0.3" - "@jest/test-result" "^29.0.3" - "@jest/types" "^29.0.3" + "@jest/environment" "^29.1.2" + "@jest/expect" "^29.1.2" + "@jest/test-result" "^29.1.2" + "@jest/types" "^29.1.2" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" dedent "^0.7.0" is-generator-fn "^2.0.0" - jest-each "^29.0.3" - jest-matcher-utils "^29.0.3" - jest-message-util "^29.0.3" - jest-runtime "^29.0.3" - jest-snapshot "^29.0.3" - jest-util "^29.0.3" + jest-each "^29.1.2" + jest-matcher-utils "^29.1.2" + jest-message-util "^29.1.2" + jest-runtime "^29.1.2" + jest-snapshot "^29.1.2" + jest-util "^29.1.2" p-limit "^3.1.0" - pretty-format "^29.0.3" + pretty-format "^29.1.2" slash "^3.0.0" stack-utils "^2.0.3" -jest-cli@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.0.3.tgz#fd8f0ef363a7a3d9c53ef62e0651f18eeffa77b9" - integrity sha512-aUy9Gd/Kut1z80eBzG10jAn6BgS3BoBbXyv+uXEqBJ8wnnuZ5RpNfARoskSrTIy1GY4a8f32YGuCMwibtkl9CQ== +jest-cli@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.1.2.tgz#423b9c5d3ea20a50b1354b8bf3f2a20e72110e89" + integrity sha512-vsvBfQ7oS2o4MJdAH+4u9z76Vw5Q8WBQF5MchDbkylNknZdrPTX1Ix7YRJyTlOWqRaS7ue/cEAn+E4V1MWyMzw== dependencies: - "@jest/core" "^29.0.3" - "@jest/test-result" "^29.0.3" - "@jest/types" "^29.0.3" + "@jest/core" "^29.1.2" + "@jest/test-result" "^29.1.2" + "@jest/types" "^29.1.2" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.9" import-local "^3.0.2" - jest-config "^29.0.3" - jest-util "^29.0.3" - jest-validate "^29.0.3" + jest-config "^29.1.2" + jest-util "^29.1.2" + jest-validate "^29.1.2" prompts "^2.0.1" yargs "^17.3.1" -jest-config@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.0.3.tgz#c2e52a8f5adbd18de79f99532d8332a19e232f13" - integrity sha512-U5qkc82HHVYe3fNu2CRXLN4g761Na26rWKf7CjM8LlZB3In1jadEkZdMwsE37rd9RSPV0NfYaCjHdk/gu3v+Ew== +jest-config@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.1.2.tgz#7d004345ca4c09f5d8f802355f54494e90842f4d" + integrity sha512-EC3Zi86HJUOz+2YWQcJYQXlf0zuBhJoeyxLM6vb6qJsVmpP7KcCP1JnyF0iaqTaXdBP8Rlwsvs7hnKWQWWLwwA== dependencies: "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^29.0.3" - "@jest/types" "^29.0.3" - babel-jest "^29.0.3" + "@jest/test-sequencer" "^29.1.2" + "@jest/types" "^29.1.2" + babel-jest "^29.1.2" chalk "^4.0.0" ci-info "^3.2.0" deepmerge "^4.2.2" glob "^7.1.3" graceful-fs "^4.2.9" - jest-circus "^29.0.3" - jest-environment-node "^29.0.3" + jest-circus "^29.1.2" + jest-environment-node "^29.1.2" jest-get-type "^29.0.0" jest-regex-util "^29.0.0" - jest-resolve "^29.0.3" - jest-runner "^29.0.3" - jest-util "^29.0.3" - jest-validate "^29.0.3" + jest-resolve "^29.1.2" + jest-runner "^29.1.2" + jest-util "^29.1.2" + jest-validate "^29.1.2" micromatch "^4.0.4" parse-json "^5.2.0" - pretty-format "^29.0.3" + pretty-format "^29.1.2" slash "^3.0.0" strip-json-comments "^3.1.1" @@ -4389,15 +4251,15 @@ jest-diff@^28.1.3: jest-get-type "^28.0.2" pretty-format "^28.1.3" -jest-diff@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.0.3.tgz#41cc02409ad1458ae1bf7684129a3da2856341ac" - integrity sha512-+X/AIF5G/vX9fWK+Db9bi9BQas7M9oBME7egU7psbn4jlszLFCu0dW63UgeE6cs/GANq4fLaT+8sGHQQ0eCUfg== +jest-diff@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.1.2.tgz#bb7aaf5353227d6f4f96c5e7e8713ce576a607dc" + integrity sha512-4GQts0aUopVvecIT4IwD/7xsBaMhKTYoM4/njE/aVw9wpw+pIUVp8Vab/KnSzSilr84GnLBkaP3JLDnQYCKqVQ== dependencies: chalk "^4.0.0" diff-sequences "^29.0.0" jest-get-type "^29.0.0" - pretty-format "^29.0.3" + pretty-format "^29.1.2" jest-docblock@^29.0.0: version "29.0.0" @@ -4406,28 +4268,28 @@ jest-docblock@^29.0.0: dependencies: detect-newline "^3.0.0" -jest-each@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.0.3.tgz#7ef3157580b15a609d7ef663dd4fc9b07f4e1299" - integrity sha512-wILhZfESURHHBNvPMJ0lZlYZrvOQJxAo3wNHi+ycr90V7M+uGR9Gh4+4a/BmaZF0XTyZsk4OiYEf3GJN7Ltqzg== +jest-each@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.1.2.tgz#d4c8532c07a846e79f194f7007ce7cb1987d1cd0" + integrity sha512-AmTQp9b2etNeEwMyr4jc0Ql/LIX/dhbgP21gHAizya2X6rUspHn2gysMXaj6iwWuOJ2sYRgP8c1P4cXswgvS1A== dependencies: - "@jest/types" "^29.0.3" + "@jest/types" "^29.1.2" chalk "^4.0.0" jest-get-type "^29.0.0" - jest-util "^29.0.3" - pretty-format "^29.0.3" + jest-util "^29.1.2" + pretty-format "^29.1.2" -jest-environment-node@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.0.3.tgz#293804b1e0fa5f0e354dacbe510655caa478a3b2" - integrity sha512-cdZqRCnmIlTXC+9vtvmfiY/40Cj6s2T0czXuq1whvQdmpzAnj4sbqVYuZ4zFHk766xTTJ+Ij3uUqkk8KCfXoyg== +jest-environment-node@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.1.2.tgz#005e05cc6ea4b9b5ba55906ab1ce53c82f6907a7" + integrity sha512-C59yVbdpY8682u6k/lh8SUMDJPbOyCHOTgLVVi1USWFxtNV+J8fyIwzkg+RJIVI30EKhKiAGNxYaFr3z6eyNhQ== dependencies: - "@jest/environment" "^29.0.3" - "@jest/fake-timers" "^29.0.3" - "@jest/types" "^29.0.3" + "@jest/environment" "^29.1.2" + "@jest/fake-timers" "^29.1.2" + "@jest/types" "^29.1.2" "@types/node" "*" - jest-mock "^29.0.3" - jest-util "^29.0.3" + jest-mock "^29.1.2" + jest-util "^29.1.2" jest-get-type@^28.0.2: version "28.0.2" @@ -4439,37 +4301,37 @@ jest-get-type@^29.0.0: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.0.0.tgz#843f6c50a1b778f7325df1129a0fd7aa713aef80" integrity sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw== -jest-haste-map@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.0.3.tgz#d7f3f7180f558d760eacc5184aac5a67f20ef939" - integrity sha512-uMqR99+GuBHo0RjRhOE4iA6LmsxEwRdgiIAQgMU/wdT2XebsLDz5obIwLZm/Psj+GwSEQhw9AfAVKGYbh2G55A== +jest-haste-map@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.1.2.tgz#93f3634aa921b6b654e7c94137b24e02e7ca6ac9" + integrity sha512-xSjbY8/BF11Jh3hGSPfYTa/qBFrm3TPM7WU8pU93m2gqzORVLkHFWvuZmFsTEBPRKndfewXhMOuzJNHyJIZGsw== dependencies: - "@jest/types" "^29.0.3" + "@jest/types" "^29.1.2" "@types/graceful-fs" "^4.1.3" "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.9" jest-regex-util "^29.0.0" - jest-util "^29.0.3" - jest-worker "^29.0.3" + jest-util "^29.1.2" + jest-worker "^29.1.2" micromatch "^4.0.4" walker "^1.0.8" optionalDependencies: fsevents "^2.3.2" -jest-leak-detector@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.0.3.tgz#e85cf3391106a7a250850b6766b508bfe9c7bc6f" - integrity sha512-YfW/G63dAuiuQ3QmQlh8hnqLDe25WFY3eQhuc/Ev1AGmkw5zREblTh7TCSKLoheyggu6G9gxO2hY8p9o6xbaRQ== +jest-leak-detector@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.1.2.tgz#4c846db14c58219430ccbc4f01a1ec52ebee4fc2" + integrity sha512-TG5gAZJpgmZtjb6oWxBLf2N6CfQ73iwCe6cofu/Uqv9iiAm6g502CAnGtxQaTfpHECBdVEMRBhomSXeLnoKjiQ== dependencies: jest-get-type "^29.0.0" - pretty-format "^29.0.3" + pretty-format "^29.1.2" jest-localstorage-mock@^2.4.6: - version "2.4.22" - resolved "https://registry.yarnpkg.com/jest-localstorage-mock/-/jest-localstorage-mock-2.4.22.tgz#9d70be92bfc591c0be289ee2f71de1b4b2a5ca9b" - integrity sha512-60PWSDFQOS5v7JzSmYLM3dPLg0JLl+2Vc4lIEz/rj2yrXJzegsFLn7anwc5IL0WzJbBa/Las064CHbFg491/DQ== + version "2.4.21" + resolved "https://registry.yarnpkg.com/jest-localstorage-mock/-/jest-localstorage-mock-2.4.21.tgz#920aa6fc8f8ab2f81e40433e48e2efdb2d81a6e0" + integrity sha512-IBXPBufnfPyr4VkoQeJ+zlfWlG84P0KbL4ejcV9j3xNI0v6OWznQlH6Ke9xjSarleR11090oSeWADSUow0PmFw== jest-matcher-utils@^28.1.3: version "28.1.3" @@ -4481,15 +4343,15 @@ jest-matcher-utils@^28.1.3: jest-get-type "^28.0.2" pretty-format "^28.1.3" -jest-matcher-utils@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.0.3.tgz#b8305fd3f9e27cdbc210b21fc7dbba92d4e54560" - integrity sha512-RsR1+cZ6p1hDV4GSCQTg+9qjeotQCgkaleIKLK7dm+U4V/H2bWedU3RAtLm8+mANzZ7eDV33dMar4pejd7047w== +jest-matcher-utils@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.1.2.tgz#e68c4bcc0266e70aa1a5c13fb7b8cd4695e318a1" + integrity sha512-MV5XrD3qYSW2zZSHRRceFzqJ39B2z11Qv0KPyZYxnzDHFeYZGJlgGi0SW+IXSJfOewgJp/Km/7lpcFT+cgZypw== dependencies: chalk "^4.0.0" - jest-diff "^29.0.3" + jest-diff "^29.1.2" jest-get-type "^29.0.0" - pretty-format "^29.0.3" + pretty-format "^29.1.2" jest-message-util@^28.1.3: version "28.1.3" @@ -4506,28 +4368,29 @@ jest-message-util@^28.1.3: slash "^3.0.0" stack-utils "^2.0.3" -jest-message-util@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.0.3.tgz#f0254e1ffad21890c78355726202cc91d0a40ea8" - integrity sha512-7T8JiUTtDfppojosORAflABfLsLKMLkBHSWkjNQrjIltGoDzNGn7wEPOSfjqYAGTYME65esQzMJxGDjuLBKdOg== +jest-message-util@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.1.2.tgz#c21a33c25f9dc1ebfcd0f921d89438847a09a501" + integrity sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ== dependencies: "@babel/code-frame" "^7.12.13" - "@jest/types" "^29.0.3" + "@jest/types" "^29.1.2" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" graceful-fs "^4.2.9" micromatch "^4.0.4" - pretty-format "^29.0.3" + pretty-format "^29.1.2" slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.0.3.tgz#4f0093f6a9cb2ffdb9c44a07a3912f0c098c8de9" - integrity sha512-ort9pYowltbcrCVR43wdlqfAiFJXBx8l4uJDsD8U72LgBcetvEp+Qxj1W9ZYgMRoeAo+ov5cnAGF2B6+Oth+ww== +jest-mock@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.1.2.tgz#de47807edbb9d4abf8423f1d8d308d670105678c" + integrity sha512-PFDAdjjWbjPUtQPkQufvniXIS3N9Tv7tbibePEjIIprzjgo0qQlyUiVMrT4vL8FaSJo1QXifQUOuPH3HQC/aMA== dependencies: - "@jest/types" "^29.0.3" + "@jest/types" "^29.1.2" "@types/node" "*" + jest-util "^29.1.2" jest-pnp-resolver@^1.2.2: version "1.2.2" @@ -4539,88 +4402,88 @@ jest-regex-util@^29.0.0: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.0.0.tgz#b442987f688289df8eb6c16fa8df488b4cd007de" integrity sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug== -jest-resolve-dependencies@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.0.3.tgz#f23a54295efc6374b86b198cf8efed5606d6b762" - integrity sha512-KzuBnXqNvbuCdoJpv8EanbIGObk7vUBNt/PwQPPx2aMhlv/jaXpUJsqWYRpP/0a50faMBY7WFFP8S3/CCzwfDw== +jest-resolve-dependencies@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.1.2.tgz#a6919e58a0c7465582cb8ec2d745b4e64ae8647f" + integrity sha512-44yYi+yHqNmH3OoWZvPgmeeiwKxhKV/0CfrzaKLSkZG9gT973PX8i+m8j6pDrTYhhHoiKfF3YUFg/6AeuHw4HQ== dependencies: jest-regex-util "^29.0.0" - jest-snapshot "^29.0.3" + jest-snapshot "^29.1.2" -jest-resolve@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.0.3.tgz#329a3431e3b9eb6629a2cd483e9bed95b26827b9" - integrity sha512-toVkia85Y/BPAjJasTC9zIPY6MmVXQPtrCk8SmiheC4MwVFE/CMFlOtMN6jrwPMC6TtNh8+sTMllasFeu1wMPg== +jest-resolve@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.1.2.tgz#9dd8c2fc83e59ee7d676b14bd45a5f89e877741d" + integrity sha512-7fcOr+k7UYSVRJYhSmJHIid3AnDBcLQX3VmT9OSbPWsWz1MfT7bcoerMhADKGvKCoMpOHUQaDHtQoNp/P9JMGg== dependencies: chalk "^4.0.0" graceful-fs "^4.2.9" - jest-haste-map "^29.0.3" + jest-haste-map "^29.1.2" jest-pnp-resolver "^1.2.2" - jest-util "^29.0.3" - jest-validate "^29.0.3" + jest-util "^29.1.2" + jest-validate "^29.1.2" resolve "^1.20.0" resolve.exports "^1.1.0" slash "^3.0.0" -jest-runner@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.0.3.tgz#2e47fe1e8777aea9b8970f37e8f83630b508fb87" - integrity sha512-Usu6VlTOZlCZoNuh3b2Tv/yzDpKqtiNAetG9t3kJuHfUyVMNW7ipCCJOUojzKkjPoaN7Bl1f7Buu6PE0sGpQxw== +jest-runner@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.1.2.tgz#f18b2b86101341e047de8c2f51a5fdc4e97d053a" + integrity sha512-yy3LEWw8KuBCmg7sCGDIqKwJlULBuNIQa2eFSVgVASWdXbMYZ9H/X0tnXt70XFoGf92W2sOQDOIFAA6f2BG04Q== dependencies: - "@jest/console" "^29.0.3" - "@jest/environment" "^29.0.3" - "@jest/test-result" "^29.0.3" - "@jest/transform" "^29.0.3" - "@jest/types" "^29.0.3" + "@jest/console" "^29.1.2" + "@jest/environment" "^29.1.2" + "@jest/test-result" "^29.1.2" + "@jest/transform" "^29.1.2" + "@jest/types" "^29.1.2" "@types/node" "*" chalk "^4.0.0" emittery "^0.10.2" graceful-fs "^4.2.9" jest-docblock "^29.0.0" - jest-environment-node "^29.0.3" - jest-haste-map "^29.0.3" - jest-leak-detector "^29.0.3" - jest-message-util "^29.0.3" - jest-resolve "^29.0.3" - jest-runtime "^29.0.3" - jest-util "^29.0.3" - jest-watcher "^29.0.3" - jest-worker "^29.0.3" + jest-environment-node "^29.1.2" + jest-haste-map "^29.1.2" + jest-leak-detector "^29.1.2" + jest-message-util "^29.1.2" + jest-resolve "^29.1.2" + jest-runtime "^29.1.2" + jest-util "^29.1.2" + jest-watcher "^29.1.2" + jest-worker "^29.1.2" p-limit "^3.1.0" source-map-support "0.5.13" -jest-runtime@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.0.3.tgz#5a823ec5902257519556a4e5a71a868e8fd788aa" - integrity sha512-12gZXRQ7ozEeEHKTY45a+YLqzNDR/x4c//X6AqwKwKJPpWM8FY4vwn4VQJOcLRS3Nd1fWwgP7LU4SoynhuUMHQ== +jest-runtime@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.1.2.tgz#dbcd57103d61115479108d5864bdcd661d9c6783" + integrity sha512-jr8VJLIf+cYc+8hbrpt412n5jX3tiXmpPSYTGnwcvNemY+EOuLNiYnHJ3Kp25rkaAcTWOEI4ZdOIQcwYcXIAZw== dependencies: - "@jest/environment" "^29.0.3" - "@jest/fake-timers" "^29.0.3" - "@jest/globals" "^29.0.3" + "@jest/environment" "^29.1.2" + "@jest/fake-timers" "^29.1.2" + "@jest/globals" "^29.1.2" "@jest/source-map" "^29.0.0" - "@jest/test-result" "^29.0.3" - "@jest/transform" "^29.0.3" - "@jest/types" "^29.0.3" + "@jest/test-result" "^29.1.2" + "@jest/transform" "^29.1.2" + "@jest/types" "^29.1.2" "@types/node" "*" chalk "^4.0.0" cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" glob "^7.1.3" graceful-fs "^4.2.9" - jest-haste-map "^29.0.3" - jest-message-util "^29.0.3" - jest-mock "^29.0.3" + jest-haste-map "^29.1.2" + jest-message-util "^29.1.2" + jest-mock "^29.1.2" jest-regex-util "^29.0.0" - jest-resolve "^29.0.3" - jest-snapshot "^29.0.3" - jest-util "^29.0.3" + jest-resolve "^29.1.2" + jest-snapshot "^29.1.2" + jest-util "^29.1.2" slash "^3.0.0" strip-bom "^4.0.0" -jest-snapshot@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.0.3.tgz#0a024706986a915a6eefae74d7343069d2fc8eef" - integrity sha512-52q6JChm04U3deq+mkQ7R/7uy7YyfVIrebMi6ZkBoDJ85yEjm/sJwdr1P0LOIEHmpyLlXrxy3QP0Zf5J2kj0ew== +jest-snapshot@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.1.2.tgz#7dd277e88c45f2d2ff5888de1612e63c7ceb575b" + integrity sha512-rYFomGpVMdBlfwTYxkUp3sjD6usptvZcONFYNqVlaz4EpHPnDvlWjvmOQ9OCSNKqYZqLM2aS3wq01tWujLg7gg== dependencies: "@babel/core" "^7.11.6" "@babel/generator" "^7.7.2" @@ -4628,23 +4491,23 @@ jest-snapshot@^29.0.3: "@babel/plugin-syntax-typescript" "^7.7.2" "@babel/traverse" "^7.7.2" "@babel/types" "^7.3.3" - "@jest/expect-utils" "^29.0.3" - "@jest/transform" "^29.0.3" - "@jest/types" "^29.0.3" + "@jest/expect-utils" "^29.1.2" + "@jest/transform" "^29.1.2" + "@jest/types" "^29.1.2" "@types/babel__traverse" "^7.0.6" "@types/prettier" "^2.1.5" babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^29.0.3" + expect "^29.1.2" graceful-fs "^4.2.9" - jest-diff "^29.0.3" + jest-diff "^29.1.2" jest-get-type "^29.0.0" - jest-haste-map "^29.0.3" - jest-matcher-utils "^29.0.3" - jest-message-util "^29.0.3" - jest-util "^29.0.3" + jest-haste-map "^29.1.2" + jest-matcher-utils "^29.1.2" + jest-message-util "^29.1.2" + jest-util "^29.1.2" natural-compare "^1.4.0" - pretty-format "^29.0.3" + pretty-format "^29.1.2" semver "^7.3.5" jest-sonar-reporter@^2.0.0: @@ -4666,62 +4529,63 @@ jest-util@^28.1.3: graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-util@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.0.3.tgz#06d1d77f9a1bea380f121897d78695902959fbc0" - integrity sha512-Q0xaG3YRG8QiTC4R6fHjHQPaPpz9pJBEi0AeOE4mQh/FuWOijFjGXMMOfQEaU9i3z76cNR7FobZZUQnL6IyfdQ== +jest-util@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.1.2.tgz#ac5798e93cb6a6703084e194cfa0898d66126df1" + integrity sha512-vPCk9F353i0Ymx3WQq3+a4lZ07NXu9Ca8wya6o4Fe4/aO1e1awMMprZ3woPFpKwghEOW+UXgd15vVotuNN9ONQ== dependencies: - "@jest/types" "^29.0.3" + "@jest/types" "^29.1.2" "@types/node" "*" chalk "^4.0.0" ci-info "^3.2.0" graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.0.3.tgz#f9521581d7344685428afa0a4d110e9c519aeeb6" - integrity sha512-OebiqqT6lK8cbMPtrSoS3aZP4juID762lZvpf1u+smZnwTEBCBInan0GAIIhv36MxGaJvmq5uJm7dl5gVt+Zrw== +jest-validate@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.1.2.tgz#83a728b8f6354da2e52346878c8bc7383516ca51" + integrity sha512-k71pOslNlV8fVyI+mEySy2pq9KdXdgZtm7NHrBX8LghJayc3wWZH0Yr0mtYNGaCU4F1OLPXRkwZR0dBm/ClshA== dependencies: - "@jest/types" "^29.0.3" + "@jest/types" "^29.1.2" camelcase "^6.2.0" chalk "^4.0.0" jest-get-type "^29.0.0" leven "^3.1.0" - pretty-format "^29.0.3" + pretty-format "^29.1.2" -jest-watcher@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.0.3.tgz#8e220d1cc4f8029875e82015d084cab20f33d57f" - integrity sha512-tQX9lU91A+9tyUQKUMp0Ns8xAcdhC9fo73eqA3LFxP2bSgiF49TNcc+vf3qgGYYK9qRjFpXW9+4RgF/mbxyOOw== +jest-watcher@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.1.2.tgz#de21439b7d889e2fcf62cc2a4779ef1a3f1f3c62" + integrity sha512-6JUIUKVdAvcxC6bM8/dMgqY2N4lbT+jZVsxh0hCJRbwkIEnbr/aPjMQ28fNDI5lB51Klh00MWZZeVf27KBUj5w== dependencies: - "@jest/test-result" "^29.0.3" - "@jest/types" "^29.0.3" + "@jest/test-result" "^29.1.2" + "@jest/types" "^29.1.2" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" emittery "^0.10.2" - jest-util "^29.0.3" + jest-util "^29.1.2" string-length "^4.0.1" -jest-worker@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.0.3.tgz#c2ba0aa7e41eec9eb0be8e8a322ae6518df72647" - integrity sha512-Tl/YWUugQOjoTYwjKdfJWkSOfhufJHO5LhXTSZC3TRoQKO+fuXnZAdoXXBlpLXKGODBL3OvdUasfDD4PcMe6ng== +jest-worker@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.1.2.tgz#a68302af61bce82b42a9a57285ca7499d29b2afc" + integrity sha512-AdTZJxKjTSPHbXT/AIOjQVmoFx0LHFcVabWu0sxI7PAy7rFf8c0upyvgBKgguVXdM4vY74JdwkyD4hSmpTW8jA== dependencies: "@types/node" "*" + jest-util "^29.1.2" merge-stream "^2.0.0" supports-color "^8.0.0" jest@^29.0.0: - version "29.0.3" - resolved "https://registry.yarnpkg.com/jest/-/jest-29.0.3.tgz#5227a0596d30791b2649eea347e4aa97f734944d" - integrity sha512-ElgUtJBLgXM1E8L6K1RW1T96R897YY/3lRYqq9uVcPWtP2AAl/nQ16IYDh/FzQOOQ12VEuLdcPU83mbhG2C3PQ== + version "29.1.2" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.1.2.tgz#f821a1695ffd6cd0efc3b59d2dfcc70a98582499" + integrity sha512-5wEIPpCezgORnqf+rCaYD1SK+mNN7NsstWzIsuvsnrhR/hSxXWd82oI7DkrbJ+XTD28/eG8SmxdGvukrGGK6Tw== dependencies: - "@jest/core" "^29.0.3" - "@jest/types" "^29.0.3" + "@jest/core" "^29.1.2" + "@jest/types" "^29.1.2" import-local "^3.0.2" - jest-cli "^29.0.3" + jest-cli "^29.1.2" js-sdsl@^4.1.4: version "4.1.4" @@ -4760,15 +4624,10 @@ js2xmlparser@^4.0.2: dependencies: xmlcreate "^2.0.4" -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== - jsdoc@^3.6.6: - version "3.6.11" - resolved "https://registry.yarnpkg.com/jsdoc/-/jsdoc-3.6.11.tgz#8bbb5747e6f579f141a5238cbad4e95e004458ce" - integrity sha512-8UCU0TYeIYD9KeLzEcAu2q8N/mx9O3phAGl32nmHlE0LpaJL71mMkP4d+QE5zWfNt50qheHtOZ0qoxVrsX5TUg== + version "3.6.10" + resolved "https://registry.yarnpkg.com/jsdoc/-/jsdoc-3.6.10.tgz#dc903c44763b78afa7d94d63da475d20bc224cc4" + integrity sha512-IdQ8ppSo5LKZ9o3M+LKIIK8i00DIe5msDvG3G81Km+1dhy0XrOWD0Ji8H61ElgyEj/O9KRLokgKbAM9XX9CJAg== dependencies: "@babel/parser" "^7.9.4" "@types/markdown-it" "^12.2.3" @@ -4776,7 +4635,7 @@ jsdoc@^3.6.6: catharsis "^0.9.0" escape-string-regexp "^2.0.0" js2xmlparser "^4.0.2" - klaw "^3.0.0" + klaw "^4.0.1" markdown-it "^12.3.2" markdown-it-anchor "^8.4.1" marked "^4.0.10" @@ -4806,21 +4665,11 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== -json-schema@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" - integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== - json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== - json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -4838,16 +4687,6 @@ jsonparse@^1.2.0: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== -jsprim@^1.2.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" - integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.4.0" - verror "1.10.0" - jstransformer@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/jstransformer/-/jstransformer-1.0.0.tgz#ed8bf0921e2f3f1ed4d5c1a44f68709ed24722c3" @@ -4868,12 +4707,10 @@ kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -klaw@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146" - integrity sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g== - dependencies: - graceful-fs "^4.1.9" +klaw@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-4.0.1.tgz#8dc6f5723f05894e8e931b516a8ff15c2976d368" + integrity sha512-pgsE40/SvC7st04AHiISNewaIMUbY5V/K8b21ekiPiFoYs/EYSdsGa+FJArB1d441uq4Q8zZyIxvAzkGNlBdRw== kleur@^3.0.3: version "3.0.3" @@ -4918,6 +4755,14 @@ linkify-it@^3.0.1: dependencies: uc.micro "^1.0.1" +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -5048,9 +4893,9 @@ markdown-it@^12.3.2: uc.micro "^1.0.5" marked@^4.0.10: - version "4.0.19" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.19.tgz#d36198d1ac1255525153c351c68c75bc1d7aee46" - integrity sha512-rgQF/OxOiLcvgUAj1Q1tAf4Bgxn5h5JZTp04Fx4XUkVhs7B+7YA9JEWJhJpoO8eJt8MkZMwqLCNeNqj1bCREZQ== + version "4.0.16" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.16.tgz#9ec18fc1a723032eb28666100344d9428cf7a264" + integrity sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA== matrix-events-sdk@^0.0.1-beta.7: version "0.0.1-beta.7" @@ -5118,18 +4963,6 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -5234,7 +5067,7 @@ next-tick@1, next-tick@^1.1.0: node-dir@^0.1.10: version "0.1.17" resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" - integrity sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg== + integrity sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU= dependencies: minimatch "^3.0.2" @@ -5250,10 +5083,10 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" - integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== +node-releases@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666" + integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -5267,15 +5100,10 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= object-inspect@^1.12.0, object-inspect@^1.9.0: version "1.12.2" @@ -5288,13 +5116,13 @@ object-keys@^1.1.1: integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== object.assign@^4.1.0, object.assign@^4.1.2: - version "4.1.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" - integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - has-symbols "^1.0.3" + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" object-keys "^1.1.1" object.values@^1.1.5: @@ -5344,7 +5172,14 @@ optionator@^0.9.1: os-browserify@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A== + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" p-limit@^2.0.0, p-limit@^2.2.0: version "2.3.0" @@ -5360,6 +5195,13 @@ p-limit@^3.0.2, p-limit@^3.1.0: dependencies: yocto-queue "^0.1.0" +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + p-locate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" @@ -5389,6 +5231,11 @@ p-retry@4: "@types/retry" "0.12.0" retry "^0.13.1" +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -5409,7 +5256,7 @@ parent-module@^1.0.0: parents@^1.0.0, parents@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/parents/-/parents-1.0.1.tgz#fedd4d2bf193a77745fe71e371d73c3307d9c751" - integrity sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg== + integrity sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E= dependencies: path-platform "~0.11.15" @@ -5427,7 +5274,7 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.5: parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ== + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= dependencies: error-ex "^1.2.0" @@ -5474,7 +5321,7 @@ path-parse@^1.0.7: path-platform@~0.11.15: version "0.11.15" resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" - integrity sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg== + integrity sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I= path-type@^4.0.0: version "4.0.0" @@ -5492,11 +5339,6 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== - picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -5546,10 +5388,10 @@ pretty-format@^28.1.3: ansi-styles "^5.0.0" react-is "^18.0.0" -pretty-format@^29.0.0, pretty-format@^29.0.3: - version "29.0.3" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.0.3.tgz#23d5f8cabc9cbf209a77d49409d093d61166a811" - integrity sha512-cHudsvQr1K5vNVLbvYF/nv3Qy/F/BcEKxGuIeMiVMRHxPOO1RxXooP8g/ZrwAp7Dx+KdMZoOc7NxLHhMrP2f9Q== +pretty-format@^29.0.0, pretty-format@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.1.2.tgz#b1f6b75be7d699be1a051f5da36e8ae9e76a8e6a" + integrity sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg== dependencies: "@jest/schemas" "^29.0.0" ansi-styles "^5.0.0" @@ -5568,7 +5410,7 @@ process-nextick-args@~2.0.0: process@~0.11.0: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= promise@^7.0.1: version "7.3.1" @@ -5597,12 +5439,7 @@ prop-types@^15.7.2: pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== - -psl@^1.1.28: - version "1.9.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" - integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= public-encrypt@^4.0.0: version "4.0.3" @@ -5724,12 +5561,12 @@ pug@^2.0.3: punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= punycode@^1.3.2: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" @@ -5743,20 +5580,15 @@ qs@^6.9.6: dependencies: side-channel "^1.0.4" -qs@~6.5.2: - version "6.5.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" - integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== - querystring-es3@~0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA== + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= queue-microtask@^1.2.2: version "1.2.3" @@ -5790,9 +5622,9 @@ react-ace@^9.5.0: prop-types "^15.7.2" react-docgen@^5.4.0: - version "5.4.3" - resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-5.4.3.tgz#7d297f73b977d0c7611402e5fc2a168acf332b26" - integrity sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA== + version "5.4.1" + resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-5.4.1.tgz#867168accce39e25095a23a922eaa90722e9d182" + integrity sha512-TZqD1aApirw86NV6tHrmDoxUn8wlinkVyutFarzbdwuhEurAzDN0y5sSj64o+BrHLPqjwpH9tunpfwgy+3Uyww== dependencies: "@babel/core" "^7.7.5" "@babel/generator" "^7.12.11" @@ -5823,7 +5655,7 @@ react-is@^18.0.0: read-only-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0" - integrity sha512-3ALe0bjBVZtkdWKIcThYpQCLbBMd/+Tbh2CDSrAIDO3UsZ4Xs+tnyjv2MjCOMMgBG+AsUOeuP1cgtY1INISc8w== + integrity sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A= dependencies: readable-stream "^2.0.2" @@ -5875,10 +5707,10 @@ recast@^0.17.3: private "^0.1.8" source-map "~0.6.1" -regenerate-unicode-properties@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" - integrity sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ== +regenerate-unicode-properties@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56" + integrity sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw== dependencies: regenerate "^1.4.2" @@ -5919,59 +5751,33 @@ regexpp@^3.2.0: integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== regexpu-core@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.2.1.tgz#a69c26f324c1e962e9ffd0b88b055caba8089139" - integrity sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ== + version "5.1.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.1.0.tgz#2f8504c3fd0ebe11215783a41541e21c79942c6d" + integrity sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA== dependencies: regenerate "^1.4.2" - regenerate-unicode-properties "^10.1.0" - regjsgen "^0.7.1" - regjsparser "^0.9.1" + regenerate-unicode-properties "^10.0.1" + regjsgen "^0.6.0" + regjsparser "^0.8.2" unicode-match-property-ecmascript "^2.0.0" unicode-match-property-value-ecmascript "^2.0.0" -regjsgen@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.7.1.tgz#ee5ef30e18d3f09b7c369b76e7c2373ed25546f6" - integrity sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA== +regjsgen@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d" + integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA== -regjsparser@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" - integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== +regjsparser@^0.8.2: + version "0.8.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.8.4.tgz#8a14285ffcc5de78c5b95d62bbf413b6bc132d5f" + integrity sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA== dependencies: jsesc "~0.5.0" repeat-string@^1.5.2: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== - -request@^2.88.2: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= require-directory@^2.1.1: version "2.1.1" @@ -6007,7 +5813,16 @@ resolve.exports@^1.1.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== -resolve@^1.1.4, resolve@^1.1.6, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.4.0: +resolve@^1.1.4, resolve@^1.1.6, resolve@^1.17.0, resolve@^1.22.0, resolve@^1.4.0: + version "1.22.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" + integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== + dependencies: + is-core-module "^2.8.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^1.14.2, resolve@^1.20.0: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -6029,7 +5844,7 @@ reusify@^1.0.4: right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" - integrity sha512-yqINtL/G7vs2v+dFIZmFUDbnVyFUJFKd6gK22Kgo6R4jfJGFtisKyncWDDULgjfqf4ASQuIQyjJ7XZ+3aWpsAg== + integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8= dependencies: align-text "^0.1.1" @@ -6065,11 +5880,16 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +safer-buffer@^2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -6189,28 +6009,13 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: source-map@~0.5.1, source-map@~0.5.3: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== -sshpk@^1.7.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" - integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - stack-utils@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" @@ -6229,7 +6034,7 @@ stream-browserify@^3.0.0: stream-combiner2@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe" - integrity sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw== + integrity sha1-+02KFCDqNidk4hrUeAOXvry0HL4= dependencies: duplexer2 "~0.1.0" readable-stream "^2.0.2" @@ -6311,14 +6116,14 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g== + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= dependencies: is-utf8 "^0.2.0" strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= strip-bom@^4.0.0: version "4.0.0" @@ -6340,7 +6145,7 @@ strip-indent@^3.0.0: strip-json-comments@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" @@ -6350,7 +6155,7 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: subarg@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" - integrity sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg== + integrity sha1-9izxdYHplrSPyWVpn1TAauJouNI= dependencies: minimist "^1.1.0" @@ -6376,9 +6181,9 @@ supports-color@^8.0.0: has-flag "^4.0.0" supports-hyperlinks@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" - integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== dependencies: has-flag "^4.0.0" supports-color "^7.0.0" @@ -6406,7 +6211,7 @@ syntax-error@^1.1.1: taffydb@2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/taffydb/-/taffydb-2.6.2.tgz#7cbcb64b5a141b6a2efc2c5d2c67b4e150b2a268" - integrity sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA== + integrity sha1-fLy2S1oUG2ou/CxdLGe04VCyomg= tapable@^2.2.0: version "2.2.1" @@ -6422,9 +6227,9 @@ terminal-link@^2.0.0: supports-hyperlinks "^2.0.0" terser@^5.5.1: - version "5.15.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.15.0.tgz#e16967894eeba6e1091509ec83f0c60e179f2425" - integrity sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA== + version "5.14.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.1.tgz#7c95eec36436cb11cf1902cc79ac564741d19eca" + integrity sha512-+ahUAE+iheqBTDxXhTisdA8hgvbEG1hHOQ9xmNjeUJSoi6DU/gMrKNcfZjHkyY6Alnuyc+ikYJaxxfHkT3+WuQ== dependencies: "@jridgewell/source-map" "^0.3.2" acorn "^8.5.0" @@ -6443,7 +6248,7 @@ test-exclude@^6.0.0: text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= through2@^2.0.0: version "2.0.5" @@ -6456,17 +6261,17 @@ through2@^2.0.0: "through@>=2.2.7 <3": version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= through@~2.2.7: version "2.2.7" resolved "https://registry.yarnpkg.com/through/-/through-2.2.7.tgz#6e8e21200191d4eb6a99f6f010df46aa1c6eb2bd" - integrity sha512-JIR0m0ybkmTcR8URann+HbwKmodP+OE8UCbsifQDYMLD5J3em1Cdn3MYPpbEd5elGDwmP98T+WbqP/tvzA5Mjg== + integrity sha1-bo4hIAGR1OtqmfbwEN9Gqhxusr0= timers-browserify@^1.0.1: version "1.4.2" resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" - integrity sha512-PIxwAupJZiYU4JmVZYwXp9FKsHMXb5h0ZEFyuXTAn8WLHOlcij+FEcbrvDsom1o5dr1YggEtFbECvGCW2sT53Q== + integrity sha1-ycWLV1voQHN1y14kYtrO50NZ9B0= dependencies: process "~0.11.0" @@ -6494,7 +6299,7 @@ tmpl@1.0.5: to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - integrity sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og== + integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= to-fast-properties@^2.0.0: version "2.0.0" @@ -6511,15 +6316,7 @@ to-regex-range@^5.0.1: token-stream@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/token-stream/-/token-stream-0.0.1.tgz#ceeefc717a76c4316f126d0b9dbaa55d7e7df01a" - integrity sha512-nfjOAu/zAWmX9tgwi5NRp7O7zTDUD1miHiB40klUnAh9qnL1iXdgzcz/i5dMaL5jahcBAaSfmNOBBJBLJW8TEg== - -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" + integrity sha1-zu78cXp2xDFvEm0LnbqlXX598Bo= tr46@^2.1.0: version "2.1.0" @@ -6531,7 +6328,7 @@ tr46@^2.1.0: tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= ts-map@^1.0.3: version "1.0.3" @@ -6551,7 +6348,7 @@ tsconfig-paths@^3.14.1: tsconfig@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-5.0.3.tgz#5f4278e701800967a8fc383fd19648878f2a6e3a" - integrity sha512-Cq65A3kVp6BbsUgg9DRHafaGmbMb9EhAc7fjWvudNWKjkbWrt43FnrtZt6awshH1R0ocfF2Z0uxock3lVqEgOg== + integrity sha1-X0J45wGACWeo/Dg/0ZZIh48qbjo= dependencies: any-promise "^1.3.0" parse-json "^2.2.0" @@ -6592,23 +6389,11 @@ tty-browserify@0.0.1: resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== - dependencies: - safe-buffer "^5.0.1" - tunnel@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -6636,15 +6421,15 @@ type@^1.0.1: resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== -type@^2.7.2: - version "2.7.2" - resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" - integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== +type@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/type/-/type-2.6.0.tgz#3ca6099af5981d36ca86b78442973694278a219f" + integrity sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ== typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= typescript@^3.2.2: version "3.9.10" @@ -6652,9 +6437,9 @@ typescript@^3.2.2: integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== typescript@^4.5.3, typescript@^4.5.4: - version "4.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.3.tgz#d59344522c4bc464a65a730ac695007fdb66dd88" - integrity sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig== + version "4.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== typeson-registry@^1.0.0-alpha.20: version "1.0.0-alpha.39" @@ -6678,7 +6463,7 @@ uc.micro@^1.0.1, uc.micro@^1.0.5: uglify-js@^2.6.1: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" - integrity sha512-qLq/4y2pjcU3vhlhseXGGJ7VbFO4pBANu0kwl8VCa9KEI0V8VfZIx2Fy3w01iSTA/pGwKZSmu/+I4etLNDdt5w== + integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0= dependencies: source-map "~0.5.1" yargs "~3.10.0" @@ -6688,7 +6473,7 @@ uglify-js@^2.6.1: uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" - integrity sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q== + integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc= umd@^3.0.0: version "3.0.3" @@ -6717,9 +6502,9 @@ undeclared-identifiers@^1.1.2: xtend "^4.0.1" underscore@^1.13.2, underscore@~1.13.2: - version "1.13.4" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.4.tgz#7886b46bbdf07f768e0052f1828e1dcab40c0dee" - integrity sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ== + version "1.13.3" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.3.tgz#54bc95f7648c5557897e5e968d0f76bc062c34ee" + integrity sha512-QvjkYpiD+dJJraRA8+dGAU4i7aBbb2s0S3jA45TFOvg2VgqvdCDd/3N6CqA8gluk1W91GLoXg5enMUx560QzuA== unhomoglyph@^1.0.6: version "1.0.6" @@ -6745,19 +6530,19 @@ unicode-match-property-value-ecmascript@^2.0.0: integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== unicode-property-aliases-ecmascript@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" - integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" + integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== universal-user-agent@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== -update-browserslist-db@^1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz#2924d3927367a38d5c555413a7ce138fc95fcb18" - integrity sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg== +update-browserslist-db@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.4.tgz#dbfc5a789caa26b1db8990796c2c8ebbce304824" + integrity sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA== dependencies: escalade "^3.1.1" picocolors "^1.0.0" @@ -6772,7 +6557,7 @@ uri-js@^4.2.2: url@~0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ== + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= dependencies: punycode "1.3.2" querystring "0.2.0" @@ -6780,12 +6565,12 @@ url@~0.11.0: util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= util@0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - integrity sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ== + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= dependencies: inherits "2.0.1" @@ -6801,16 +6586,6 @@ util@~0.12.0: safe-buffer "^5.1.2" which-typed-array "^1.1.2" -uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - -uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - v8-to-istanbul@^9.0.0, v8-to-istanbul@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4" @@ -6820,15 +6595,6 @@ v8-to-istanbul@^9.0.0, v8-to-istanbul@^9.0.1: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - vm-browserify@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" @@ -6837,7 +6603,7 @@ vm-browserify@^1.0.0: void-elements@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" - integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung== + integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= vue-docgen-api@^3.26.0: version "3.26.0" @@ -6856,12 +6622,12 @@ vue-docgen-api@^3.26.0: vue-template-compiler "^2.0.0" vue-template-compiler@^2.0.0: - version "2.7.10" - resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.10.tgz#9e20f35b2fdccacacf732dd7dedb49bf65f4556b" - integrity sha512-QO+8R9YRq1Gudm8ZMdo/lImZLJVUIAM8c07Vp84ojdDAf8HmPJc7XB556PcXV218k2AkKznsRz6xB5uOjAC4EQ== + version "2.6.14" + resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.14.tgz#a2f0e7d985670d42c9c9ee0d044fed7690f4f763" + integrity sha512-ODQS1SyMbjKoO1JBJZojSw6FE4qnh9rIpUZn2EUT86FKizx9uH5z6uXiIrm4/Nb/gwxTi/o17ZDEGWAXHvtC7g== dependencies: de-indent "^1.0.2" - he "^1.2.0" + he "^1.1.0" vue2-ace-editor@^0.0.15: version "0.0.15" @@ -6880,7 +6646,7 @@ walker@^1.0.8: webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= webidl-conversions@^4.0.2: version "4.0.2" @@ -6895,7 +6661,7 @@ webidl-conversions@^6.1.0: whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= dependencies: tr46 "~0.0.3" webidl-conversions "^3.0.0" @@ -6942,12 +6708,12 @@ which@^2.0.1: window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" - integrity sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg== + integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0= with@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/with/-/with-5.1.1.tgz#fa4daa92daf32c4ea94ed453c81f04686b575dfe" - integrity sha512-uAnSsFGfSpF6DNhBXStvlZILfHJfJu4eUkfbRGk94kGO1Ta7bg6FwfvoOhhyHAJuFbCw+0xk4uJ3u57jLvlCJg== + integrity sha1-+k2qktrzLE6pTtRTyB8EaGtXXf4= dependencies: acorn "^3.1.0" acorn-globals "^3.0.0" @@ -6960,7 +6726,7 @@ word-wrap@^1.2.3: wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" - integrity sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q== + integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8= wrap-ansi@^7.0.0: version "7.0.0" @@ -6977,9 +6743,9 @@ wrappy@1: integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== write-file-atomic@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" - integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + version "4.0.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.1.tgz#9faa33a964c1c85ff6f849b80b42a88c2c537c8f" + integrity sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ== dependencies: imurmurhash "^0.1.4" signal-exit "^3.0.7" @@ -6987,7 +6753,7 @@ write-file-atomic@^4.0.1: xml@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" - integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== + integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= xmlcreate@^2.0.4: version "2.0.4" @@ -7007,7 +6773,7 @@ y18n@^5.0.5: yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A== + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= yallist@^4.0.0: version "4.0.0" @@ -7020,9 +6786,9 @@ yargs-parser@^20.2.2, yargs-parser@^20.2.9: integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== yargs-parser@^21.0.0: - version "21.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + version "21.0.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" + integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== yargs@^16.2.0: version "16.2.0" @@ -7053,7 +6819,7 @@ yargs@^17.0.1, yargs@^17.3.1: yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" - integrity sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A== + integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E= dependencies: camelcase "^1.0.2" cliui "^2.1.0" From 5389fef47c2d105967d179149c1e1951991c570f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 12:49:58 +0100 Subject: [PATCH 05/38] Update matrix-mock-request --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d440c6f7bd0..dcd23f649b5 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "jest-localstorage-mock": "^2.4.6", "jest-sonar-reporter": "^2.0.0", "jsdoc": "^3.6.6", - "matrix-mock-request": "^2.1.2", + "matrix-mock-request": "^2.2.0", "rimraf": "^3.0.2", "terser": "^5.5.1", "tsify": "^5.0.2", diff --git a/yarn.lock b/yarn.lock index 31394da612a..73b05c50d51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4810,10 +4810,10 @@ matrix-events-sdk@^0.0.1-beta.7: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1-beta.7.tgz#5ffe45eba1f67cc8d7c2377736c728b322524934" integrity sha512-9jl4wtWanUFSy2sr2lCjErN/oC8KTAtaeaozJtrgot1JiQcEI4Rda9OLgQ7nLKaqb4Z/QUx/fR3XpDzm5Jy1JA== -matrix-mock-request@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/matrix-mock-request/-/matrix-mock-request-2.1.2.tgz#11e38ed1233dced88a6f2bfba1684d5c5b3aa2c2" - integrity sha512-/OXCIzDGSLPJ3fs+uzDrtaOHI/Sqp4iEuniRn31U8S06mPXbvAnXknHqJ4c6A/KVwJj/nPFbGXpK4wPM038I6A== +matrix-mock-request@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/matrix-mock-request/-/matrix-mock-request-2.2.0.tgz#27d25947e4146d6f7113f77d56d42c267e582c2d" + integrity sha512-L9UtYK+mXmSjoE6+jCbOzyZadvEB4PA4O6QrC3DUeoh+hxdOWLKn/oagTxnJmZpC/F1ACTDYd4Chr4nJQJOvoQ== dependencies: expect "^28.1.0" From 74d89f1f5b2f6b7fef7988f84894e78c0e781e79 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 15:04:31 +0100 Subject: [PATCH 06/38] Update matrix-mock-request --- package.json | 2 +- src/client.ts | 6 +++++- src/sliding-sync.ts | 2 +- yarn.lock | 8 ++++---- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index dcd23f649b5..90b81f7d5d5 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "jest-localstorage-mock": "^2.4.6", "jest-sonar-reporter": "^2.0.0", "jsdoc": "^3.6.6", - "matrix-mock-request": "^2.2.0", + "matrix-mock-request": "^2.3.0", "rimraf": "^3.0.2", "terser": "^5.5.1", "tsify": "^5.0.2", diff --git a/src/client.ts b/src/client.ts index 8f1c96ac20e..6dd5454eac9 100644 --- a/src/client.ts +++ b/src/client.ts @@ -8781,11 +8781,14 @@ export class MatrixClient extends TypedEventEmitter { const qps: Record = {}; if (req.pos) { @@ -8807,6 +8810,7 @@ export class MatrixClient extends TypedEventEmitter Date: Tue, 4 Oct 2022 15:44:41 +0100 Subject: [PATCH 07/38] Iterate fetch support --- package.json | 2 +- src/ToDeviceMessageQueue.ts | 2 +- src/autodiscovery.ts | 4 ++-- src/http-api/errors.ts | 4 ++-- src/http-api/fetch.ts | 9 +++++---- src/http-api/index.ts | 17 ++++++++++++----- src/http-api/utils.ts | 9 ++++----- src/sliding-sync.ts | 2 +- src/sync.ts | 2 +- src/webrtc/call.ts | 6 +++--- yarn.lock | 8 ++++---- 11 files changed, 36 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index 90b81f7d5d5..8857801d213 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "jest-localstorage-mock": "^2.4.6", "jest-sonar-reporter": "^2.0.0", "jsdoc": "^3.6.6", - "matrix-mock-request": "^2.3.0", + "matrix-mock-request": "^2.4.0", "rimraf": "^3.0.2", "terser": "^5.5.1", "tsify": "^5.0.2", diff --git a/src/ToDeviceMessageQueue.ts b/src/ToDeviceMessageQueue.ts index 18cd9b093d7..ffdecedacc7 100644 --- a/src/ToDeviceMessageQueue.ts +++ b/src/ToDeviceMessageQueue.ts @@ -28,7 +28,7 @@ const MAX_BATCH_SIZE = 20; export class ToDeviceMessageQueue { private sending = false; private running = true; - private retryTimeout: ReturnType = null; + private retryTimeout: ReturnType | null = null; private retryAttempts = 0; constructor(private client: MatrixClient) { diff --git a/src/autodiscovery.ts b/src/autodiscovery.ts index 90e9558c756..95dd543d03f 100644 --- a/src/autodiscovery.ts +++ b/src/autodiscovery.ts @@ -19,7 +19,7 @@ limitations under the License. import { IClientWellKnown, IWellKnownConfig } from "./client"; import { logger } from './logger'; -import { Method, timeoutSignal } from "./http-api"; +import { MatrixError, Method, timeoutSignal } from "./http-api"; // Dev note: Auto discovery is part of the spec. // See: https://matrix.org/docs/spec/client_server/r0.4.0.html#server-discovery @@ -459,7 +459,7 @@ export class AutoDiscovery { error: err, raw: {}, action: AutoDiscoveryAction.FAIL_PROMPT, - reason: err?.name === "SyntaxError" + reason: (err as MatrixError)?.name === "SyntaxError" ? AutoDiscovery.ERROR_INVALID_JSON : AutoDiscovery.ERROR_INVALID, }; diff --git a/src/http-api/errors.ts b/src/http-api/errors.ts index e6004afe265..d44b23e7a2e 100644 --- a/src/http-api/errors.ts +++ b/src/http-api/errors.ts @@ -34,7 +34,7 @@ interface IErrorJson extends Partial { * @prop {number} httpStatus The numeric HTTP status code given */ export class MatrixError extends Error { - public readonly errcode: string; + public readonly errcode?: string; public readonly data: IErrorJson; constructor(errorJson: IErrorJson = {}, public httpStatus?: number) { @@ -54,7 +54,7 @@ export class MatrixError extends Error { * @constructor */ export class ConnectionError extends Error { - constructor(message: string, cause: Error = undefined) { + constructor(message: string, cause?: Error) { super(message + (cause ? `: ${cause.message}` : "")); } diff --git a/src/http-api/fetch.ts b/src/http-api/fetch.ts index 54b043ff6b9..2902e61aa82 100644 --- a/src/http-api/fetch.ts +++ b/src/http-api/fetch.ts @@ -24,7 +24,7 @@ import { TypedEventEmitter } from "../models/typed-event-emitter"; import { Method } from "./method"; import { MatrixError } from "./errors"; import { HttpApiEvent, HttpApiEventHandlerMap, IHttpOpts, IRequestOpts } from "./interface"; -import { anySignal, timeoutSignal } from "./utils"; +import { anySignal, parseErrorResponse, timeoutSignal } from "./utils"; import { QueryDict } from "../utils"; type Body = Record | BodyInit; @@ -65,7 +65,7 @@ export class FetchHttpApi { this.opts.idBaseUrl = url; } - public idServerRequest( + public idServerRequest( method: Method, path: string, params: Record, @@ -88,6 +88,7 @@ export class FetchHttpApi { const opts: IRequestOpts = { json: true, + headers: {}, }; if (accessToken) { opts.headers['Authorization'] = `Bearer ${accessToken}`; @@ -249,7 +250,7 @@ export class FetchHttpApi { this.abortController.signal, ]; if (timeout !== undefined) { - signals.push(timeoutSignal(opts.localTimeoutMs ?? this.opts.localTimeoutMs)); + signals.push(timeoutSignal(timeout)); } if (opts.abortSignal) { signals.push(opts.abortSignal); @@ -276,7 +277,7 @@ export class FetchHttpApi { }); if (!res.ok) { - throw new MatrixError(await res.json(), res.status); + throw parseErrorResponse(res, await res.text()); } if (this.opts.onlyData) { diff --git a/src/http-api/index.ts b/src/http-api/index.ts index 65fc0d8c251..990d65bd3c1 100644 --- a/src/http-api/index.ts +++ b/src/http-api/index.ts @@ -20,6 +20,8 @@ import { MediaPrefix } from "./prefix"; import * as utils from "../utils"; import * as callbacks from "../realtime-callbacks"; import { Method } from "./method"; +import { MatrixError } from "./errors"; +import { parseErrorResponse } from "./utils"; export * from "./interface"; export * from "./prefix"; @@ -103,9 +105,14 @@ export class MatrixHttpApi extends FetchHttpApi { if (!xhr.responseText) { throw new Error('No response body.'); } - defer.resolve(JSON.parse(xhr.responseText)); + + if (xhr.status >= 400) { + defer.reject(parseErrorResponse(xhr, xhr.responseText)); + } else { + defer.resolve(JSON.parse(xhr.responseText)); + } } catch (err) { - err.httpStatus = xhr.status; + (err).httpStatus = xhr.status; defer.reject(err); } break; @@ -129,12 +136,12 @@ export class MatrixHttpApi extends FetchHttpApi { url.searchParams.set("filename", encodeURIComponent(fileName)); } - if (!this.opts.useAuthorizationHeader) { + if (!this.opts.useAuthorizationHeader && this.opts.accessToken) { url.searchParams.set("access_token", encodeURIComponent(this.opts.accessToken)); } xhr.open(Method.Post, url.href); - if (this.opts.useAuthorizationHeader) { + if (this.opts.useAuthorizationHeader && this.opts.accessToken) { xhr.setRequestHeader("Authorization", "Bearer " + this.opts.accessToken); } xhr.setRequestHeader("Content-Type", contentType); @@ -197,7 +204,7 @@ export class MatrixHttpApi extends FetchHttpApi { base: this.opts.baseUrl, path: MediaPrefix.R0 + "/upload", params: { - access_token: this.opts.accessToken, + access_token: this.opts.accessToken!, }, }; } diff --git a/src/http-api/utils.ts b/src/http-api/utils.ts index 399c60756a1..a597e8411e4 100644 --- a/src/http-api/utils.ts +++ b/src/http-api/utils.ts @@ -73,9 +73,8 @@ export function parseErrorResponse(response: XMLHttpRequest | Response, body?: s let err: Error; if (contentType) { - if (contentType.type === "application/json") { - const jsonBody = typeof(body) === "object" ? body : JSON.parse(body); - err = new MatrixError(jsonBody, response.status); + if (contentType.type === "application/json" && body) { + err = new MatrixError(JSON.parse(body), response.status); } else if (contentType.type === "text/plain") { err = new Error(`Server returned ${response.status} error: ${body}`); } @@ -97,7 +96,7 @@ export function parseErrorResponse(response: XMLHttpRequest | Response, body?: s * @returns {{type: String, parameters: Object}?} parsed content-type header, or null if not found */ function getResponseContentType(response: XMLHttpRequest | Response): ParsedMediaType | null { - let contentType: string; + let contentType = ""; if ((response as XMLHttpRequest).getResponseHeader) { contentType = (response as XMLHttpRequest).getResponseHeader("Content-Type"); } else if ((response as Response).headers) { @@ -122,7 +121,7 @@ function getResponseContentType(response: XMLHttpRequest | Response): ParsedMedi */ export async function retryNetworkOperation(maxAttempts: number, callback: () => Promise): Promise { let attempts = 0; - let lastConnectionError = null; + let lastConnectionError: ConnectionError | null = null; while (attempts < maxAttempts) { try { if (attempts > 0) { diff --git a/src/sliding-sync.ts b/src/sliding-sync.ts index 8414062bc3b..8918ab4ab1a 100644 --- a/src/sliding-sync.ts +++ b/src/sliding-sync.ts @@ -738,7 +738,7 @@ export class SlidingSync extends TypedEventEmitter; + private inviteTimeout?: ReturnType; // The logic of when & if a call is on hold is nontrivial and explained in is*OnHold // This flag represents whether we want the other party to be on hold @@ -1689,7 +1689,7 @@ export class MatrixCall extends TypedEventEmitter { - this.inviteTimeout = null; + this.inviteTimeout = undefined; if (this.state === CallState.InviteSent) { this.hangup(CallErrorCode.InviteTimeout, false); } @@ -2004,7 +2004,7 @@ export class MatrixCall extends TypedEventEmitter Date: Tue, 4 Oct 2022 16:47:31 +0100 Subject: [PATCH 08/38] Fix cleanup --- package.json | 2 +- src/client.ts | 1 + src/http-api/fetch.ts | 36 ++++++++++++++++++++++++------------ src/http-api/utils.ts | 26 +++++++++++++++++--------- yarn.lock | 8 ++++---- 5 files changed, 47 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 8857801d213..91a9e49e406 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "jest-localstorage-mock": "^2.4.6", "jest-sonar-reporter": "^2.0.0", "jsdoc": "^3.6.6", - "matrix-mock-request": "^2.4.0", + "matrix-mock-request": "^2.4.1", "rimraf": "^3.0.2", "terser": "^5.5.1", "tsify": "^5.0.2", diff --git a/src/client.ts b/src/client.ts index 6dd5454eac9..7c93d47e570 100644 --- a/src/client.ts +++ b/src/client.ts @@ -7055,6 +7055,7 @@ export class MatrixClient extends TypedEventEmitter { opts.useAuthorizationHeader = opts.useAuthorizationHeader ?? true; } + public abort(): void { + this.abortController.abort(); + this.abortController = new AbortController(); + } + public fetch(resource: URL | string, options?: RequestInit): ReturnType { if (this.opts.fetchFn) { return this.opts.fetchFn(resource, options); @@ -263,18 +268,25 @@ export class FetchHttpApi { data = body as BodyInit; } - const res = await this.fetch(url, { - signal: anySignal(signals), - method, - body: data, - headers, - mode: "cors", - redirect: "follow", - referrer: "", - referrerPolicy: "no-referrer", - cache: "no-cache", - credentials: "omit", // we send credentials via headers - }); + const { signal, cleanup } = anySignal(signals); + + let res: Response; + try { + res = await this.fetch(url, { + signal, + method, + body: data, + headers, + mode: "cors", + redirect: "follow", + referrer: "", + referrerPolicy: "no-referrer", + cache: "no-cache", + credentials: "omit", // we send credentials via headers + }); + } finally { + cleanup(); + } if (!res.ok) { throw parseErrorResponse(res, await res.text()); diff --git a/src/http-api/utils.ts b/src/http-api/utils.ts index a597e8411e4..25a418baba4 100644 --- a/src/http-api/utils.ts +++ b/src/http-api/utils.ts @@ -31,31 +31,39 @@ export function timeoutSignal(ms: number): AbortSignal { clearTimeout(timeoutId); } - controller.signal.addEventListener('abort', onAbort); + controller.signal.addEventListener("abort", onAbort); return controller.signal; } -export function anySignal(signals: AbortSignal[]): AbortSignal { +export function anySignal(signals: AbortSignal[]): { + signal: AbortSignal; + cleanup(): void; +} { const controller = new AbortController(); - function onAbort() { - controller.abort(); - - // Cleanup + function cleanup() { for (const signal of signals) { - signal.removeEventListener('abort', onAbort); + signal.removeEventListener("abort", onAbort); } } + function onAbort() { + controller.abort(); + cleanup(); + } + for (const signal of signals) { if (signal.aborted) { onAbort(); break; } - signal.addEventListener('abort', onAbort); + signal.addEventListener("abort", onAbort); } - return controller.signal; + return { + signal: controller.signal, + cleanup, + }; } /** diff --git a/yarn.lock b/yarn.lock index ce4dbca7bba..3d61b4d76e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4810,10 +4810,10 @@ matrix-events-sdk@^0.0.1-beta.7: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1-beta.7.tgz#5ffe45eba1f67cc8d7c2377736c728b322524934" integrity sha512-9jl4wtWanUFSy2sr2lCjErN/oC8KTAtaeaozJtrgot1JiQcEI4Rda9OLgQ7nLKaqb4Z/QUx/fR3XpDzm5Jy1JA== -matrix-mock-request@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/matrix-mock-request/-/matrix-mock-request-2.4.0.tgz#c91aa4b30cfdbef4fd7e544b2e55327710cd4310" - integrity sha512-PPeq2jaTOnmHU4WnnSQmMU2KVBT/AOQVZ06lqqocwgRdyg8LaaJcuU3wp4c8DweLEdxUwjdjMAGCUD86Egk26A== +matrix-mock-request@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/matrix-mock-request/-/matrix-mock-request-2.4.1.tgz#a9c7dbb6b466f582ba2ca21f17cf18ceb41c7657" + integrity sha512-QMNpKUeHS2RHovSKybUySFTXTJ11EQPkp3bgvEXmNqAc3TYM23gKYqgI288BoBDYwQrK3WJFT0d4bvMiNIS/vA== dependencies: expect "^28.1.0" From 835d79421f1454ac6dd1e9e5d8e1846085b5ce2e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 17:59:47 +0100 Subject: [PATCH 09/38] Iterate --- spec/browserify/sync-browserify.spec.ts | 17 +++++++++------- src/client.ts | 26 ++++++++++++------------- src/http-api/fetch.ts | 6 +++--- src/http-api/utils.ts | 18 ++++++----------- src/webrtc/call.ts | 4 ++-- 5 files changed, 34 insertions(+), 37 deletions(-) diff --git a/spec/browserify/sync-browserify.spec.ts b/spec/browserify/sync-browserify.spec.ts index 8a087c80722..c053ff5b7de 100644 --- a/spec/browserify/sync-browserify.spec.ts +++ b/spec/browserify/sync-browserify.spec.ts @@ -19,6 +19,7 @@ import "./setupTests"; import "../../dist/browser-matrix"; // uses browser-matrix instead of the src import * as utils from "../test-utils/test-utils"; import { TestClient } from "../TestClient"; +import { emitPromise } from "../test-utils/test-utils"; const USER_ID = "@user:test.server"; const DEVICE_ID = "device_id"; @@ -47,7 +48,7 @@ describe("Browserify Test", function() { httpBackend.stop(); }); - it("Sync", function() { + it("Sync", async () => { const event = utils.mkMembership({ room: ROOM_ID, mship: "join", @@ -71,11 +72,13 @@ describe("Browserify Test", function() { }; httpBackend.when("GET", "/sync").respond(200, syncData); - return Promise.race([ - httpBackend.flushAllExpected(), - new Promise((_, reject) => { - client.once("sync.unexpectedError", reject); - }), - ]); + + const syncPromise = emitPromise(client, "sync"); + const unexpectedErrorFn = jest.fn(); + client.once("sync.unexpectedError", unexpectedErrorFn); + + await httpBackend.flushAllExpected(); + await syncPromise; + expect(unexpectedErrorFn).not.toHaveBeenCalled(); }, 20000); // additional timeout as this test can take quite a while }); diff --git a/src/client.ts b/src/client.ts index 7c93d47e570..4a608176c0b 100644 --- a/src/client.ts +++ b/src/client.ts @@ -2850,7 +2850,7 @@ export class MatrixClient extends TypedEventEmitter { + public async deleteKeyBackupVersion(version: string): Promise { if (!this.crypto) { throw new Error("End-to-end encryption disabled"); } @@ -2866,7 +2866,7 @@ export class MatrixClient extends TypedEventEmitter; - public sendKeyBackup( + public async sendKeyBackup( roomId: string | undefined, sessionId: string | undefined, version: string | undefined, @@ -2931,7 +2931,7 @@ export class MatrixClient extends TypedEventEmitter; public deleteKeysFromBackup(roomId: string, sessionId: undefined, version?: string): Promise; public deleteKeysFromBackup(roomId: string, sessionId: string, version?: string): Promise; - public deleteKeysFromBackup(roomId?: string, sessionId?: string, version?: string): Promise { + public async deleteKeysFromBackup(roomId?: string, sessionId?: string, version?: string): Promise { if (!this.crypto) { throw new Error("End-to-end encryption disabled"); } const path = this.makeKeyBackupPath(roomId, sessionId, version); - return this.http.authedRequest( + await this.http.authedRequest( Method.Delete, path.path, path.queryData, undefined, { prefix: ClientPrefix.Unstable }, ); @@ -3524,7 +3524,7 @@ export class MatrixClient extends TypedEventEmitter = Promise.resolve(); if (opts.inviteSignUrl) { - signPromise = this.http.requestOtherUrl( + signPromise = this.http.requestOtherUrl( Method.Post, new URL(opts.inviteSignUrl), { mxid: this.credentials.userId }, ); @@ -3660,13 +3660,13 @@ export class MatrixClient extends TypedEventEmitter { + public async deleteRoomTag(roomId: string, tagName: string): Promise { const path = utils.encodeUri("/user/$userId/rooms/$roomId/tags/$tag", { $userId: this.credentials.userId, $roomId: roomId, $tag: tagName, }); - return this.http.authedRequest(Method.Delete, path); + await this.http.authedRequest(Method.Delete, path); } /** @@ -4883,7 +4883,7 @@ export class MatrixClient extends TypedEventEmitter { + public unban(roomId: string, userId: string): Promise<{}> { // unbanning != set their state to leave: this used to be // the case, but was then changed so that leaving was always // a revoking of privilege, otherwise two people racing to @@ -5029,7 +5029,7 @@ export class MatrixClient extends TypedEventEmitter { + public async setPresence(opts: IPresenceOpts): Promise { const path = utils.encodeUri("/presence/$userId/status", { $userId: this.credentials.userId, }); @@ -5042,7 +5042,7 @@ export class MatrixClient extends TypedEventEmitter | BodyInit; -interface TypedResponse extends Response { +interface TypedResponse extends Response { json(): Promise; } -export type ResponseType = +export type ResponseType = O extends undefined ? T : O extends { onlyData: true } ? T : TypedResponse; @@ -96,7 +96,7 @@ export class FetchHttpApi { headers: {}, }; if (accessToken) { - opts.headers['Authorization'] = `Bearer ${accessToken}`; + opts.headers!.Authorization = `Bearer ${accessToken}`; } return this.requestOtherUrl(method, fullUri, body, opts); diff --git a/src/http-api/utils.ts b/src/http-api/utils.ts index 25a418baba4..0f436451f2d 100644 --- a/src/http-api/utils.ts +++ b/src/http-api/utils.ts @@ -79,19 +79,13 @@ export function anySignal(signals: AbortSignal[]): { export function parseErrorResponse(response: XMLHttpRequest | Response, body?: string): Error { const contentType = getResponseContentType(response); - let err: Error; - if (contentType) { - if (contentType.type === "application/json" && body) { - err = new MatrixError(JSON.parse(body), response.status); - } else if (contentType.type === "text/plain") { - err = new Error(`Server returned ${response.status} error: ${body}`); - } + if (contentType?.type === "application/json" && body) { + return new MatrixError(JSON.parse(body), response.status); } - - if (!err) { - err = new Error(`Server returned ${response.status} error`); + if (contentType?.type === "text/plain") { + return new Error(`Server returned ${response.status} error: ${body}`); } - return err; + return new Error(`Server returned ${response.status} error`); } /** @@ -104,7 +98,7 @@ export function parseErrorResponse(response: XMLHttpRequest | Response, body?: s * @returns {{type: String, parameters: Object}?} parsed content-type header, or null if not found */ function getResponseContentType(response: XMLHttpRequest | Response): ParsedMediaType | null { - let contentType = ""; + let contentType: string | null = null; if ((response as XMLHttpRequest).getResponseHeader) { contentType = (response as XMLHttpRequest).getResponseHeader("Content-Type"); } else if ((response as Response).headers) { diff --git a/src/webrtc/call.ts b/src/webrtc/call.ts index c1e50f0c522..ad98e207910 100644 --- a/src/webrtc/call.ts +++ b/src/webrtc/call.ts @@ -322,7 +322,7 @@ export class MatrixCall extends TypedEventEmitter; + private callLengthInterval?: ReturnType; private callLength = 0; constructor(opts: CallOpts) { @@ -2008,7 +2008,7 @@ export class MatrixCall extends TypedEventEmitter Date: Tue, 4 Oct 2022 18:08:23 +0100 Subject: [PATCH 10/38] Test --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b149d2e1884..d01277b999b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,7 +26,7 @@ jobs: run: "yarn build" - name: Run tests with coverage - run: "yarn coverage --ci --reporters github-actions" + run: "yarn coverage --ci --detectOpenHandles --reporters github-actions" - name: Upload Artifact uses: actions/upload-artifact@v3 From 69c3d04e5eccf3843e1deb5d9c8038419c7505a2 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 19:09:44 +0100 Subject: [PATCH 11/38] Iterare --- spec/browserify/setupTests.js | 23 --------- spec/browserify/sync-browserify.spec.ts | 66 ++++++++++++++++--------- src/client.ts | 6 +-- 3 files changed, 46 insertions(+), 49 deletions(-) delete mode 100644 spec/browserify/setupTests.js diff --git a/spec/browserify/setupTests.js b/spec/browserify/setupTests.js deleted file mode 100644 index 16120f78aaf..00000000000 --- a/spec/browserify/setupTests.js +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright 2020 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// stub for browser-matrix browserify tests -global.XMLHttpRequest = jest.fn(); - -afterAll(() => { - // clean up XMLHttpRequest mock - global.XMLHttpRequest = undefined; -}); diff --git a/spec/browserify/sync-browserify.spec.ts b/spec/browserify/sync-browserify.spec.ts index c053ff5b7de..90e4db0b3de 100644 --- a/spec/browserify/sync-browserify.spec.ts +++ b/spec/browserify/sync-browserify.spec.ts @@ -14,47 +14,64 @@ See the License for the specific language governing permissions and limitations under the License. */ -// load XmlHttpRequest mock -import "./setupTests"; +import HttpBackend from "matrix-mock-request"; + import "../../dist/browser-matrix"; // uses browser-matrix instead of the src -import * as utils from "../test-utils/test-utils"; -import { TestClient } from "../TestClient"; -import { emitPromise } from "../test-utils/test-utils"; +import type { MatrixClient, ClientEvent } from "../../src"; const USER_ID = "@user:test.server"; const DEVICE_ID = "device_id"; const ACCESS_TOKEN = "access_token"; const ROOM_ID = "!room_id:server.test"; +declare global { + namespace NodeJS { + interface Global { + matrixcs: { + MatrixClient: typeof MatrixClient; + ClientEvent: typeof ClientEvent; + }; + } + } +} + describe("Browserify Test", function() { - let client; - let httpBackend; + let client: MatrixClient; + let httpBackend: HttpBackend; beforeEach(() => { - const testClient = new TestClient(USER_ID, DEVICE_ID, ACCESS_TOKEN); - - client = testClient.client; - httpBackend = testClient.httpBackend; + httpBackend = new HttpBackend(); + client = new global.matrixcs.MatrixClient({ + baseUrl: "http://test.server", + userId: USER_ID, + accessToken: ACCESS_TOKEN, + deviceId: DEVICE_ID, + fetchFn: httpBackend.fetchFn as typeof global.fetch, + }); httpBackend.when("GET", "/versions").respond(200, {}); httpBackend.when("GET", "/pushrules").respond(200, {}); httpBackend.when("POST", "/filter").respond(200, { filter_id: "fid" }); - - client.startClient(); }); afterEach(async () => { client.stopClient(); - httpBackend.stop(); + client.http.abort(); + httpBackend.verifyNoOutstandingRequests(); + httpBackend.verifyNoOutstandingExpectation(); + await httpBackend.stop(); }); it("Sync", async () => { - const event = utils.mkMembership({ - room: ROOM_ID, - mship: "join", - user: "@other_user:server.test", - name: "Displayname", - }); + const event = { + type: "m.room.member", + room_id: ROOM_ID, + content: { + membership: "join", + name: "Displayname", + }, + event_id: "$foobar", + }; const syncData = { next_batch: "batch1", @@ -71,13 +88,16 @@ describe("Browserify Test", function() { }, }; + httpBackend.when("GET", "/sync").respond(200, syncData); httpBackend.when("GET", "/sync").respond(200, syncData); - const syncPromise = emitPromise(client, "sync"); + const syncPromise = new Promise(r => client.once(global.matrixcs.ClientEvent.Sync, r)); const unexpectedErrorFn = jest.fn(); - client.once("sync.unexpectedError", unexpectedErrorFn); + client.once(global.matrixcs.ClientEvent.SyncUnexpectedError, unexpectedErrorFn); + + client.startClient(); - await httpBackend.flushAllExpected(); + await httpBackend.flushAllExpected({ timeout: 1 }); await syncPromise; expect(unexpectedErrorFn).not.toHaveBeenCalled(); }, 20000); // additional timeout as this test can take quite a while diff --git a/src/client.ts b/src/client.ts index 98b5a260fd9..46936fb5b3f 100644 --- a/src/client.ts +++ b/src/client.ts @@ -3664,16 +3664,16 @@ export class MatrixClient extends TypedEventEmitter { + public deleteRoomTag(roomId: string, tagName: string): Promise<{}> { const path = utils.encodeUri("/user/$userId/rooms/$roomId/tags/$tag", { $userId: this.credentials.userId, $roomId: roomId, $tag: tagName, }); - await this.http.authedRequest(Method.Delete, path); + return this.http.authedRequest(Method.Delete, path); } /** From 924925c21fad261c50a5bcf057c28b8d025a3049 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 19:27:51 +0100 Subject: [PATCH 12/38] Iterate --- spec/browserify/sync-browserify.spec.ts | 3 ++- spec/unit/crypto/backup.spec.ts | 2 +- src/ToDeviceMessageQueue.ts | 4 ++-- src/autodiscovery.ts | 10 ++++++---- src/client.ts | 6 +++--- src/store/index.ts | 2 +- src/store/indexeddb-backend.ts | 2 +- src/store/indexeddb-remote-backend.ts | 2 +- src/store/indexeddb.ts | 2 +- 9 files changed, 18 insertions(+), 15 deletions(-) diff --git a/spec/browserify/sync-browserify.spec.ts b/spec/browserify/sync-browserify.spec.ts index 90e4db0b3de..ea589165894 100644 --- a/spec/browserify/sync-browserify.spec.ts +++ b/spec/browserify/sync-browserify.spec.ts @@ -25,6 +25,7 @@ const ACCESS_TOKEN = "access_token"; const ROOM_ID = "!room_id:server.test"; declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace namespace NodeJS { interface Global { matrixcs: { @@ -97,7 +98,7 @@ describe("Browserify Test", function() { client.startClient(); - await httpBackend.flushAllExpected({ timeout: 1 }); + await httpBackend.flushAllExpected(); await syncPromise; expect(unexpectedErrorFn).not.toHaveBeenCalled(); }, 20000); // additional timeout as this test can take quite a while diff --git a/spec/unit/crypto/backup.spec.ts b/spec/unit/crypto/backup.spec.ts index d54f871d42b..ca4c09c532c 100644 --- a/spec/unit/crypto/backup.spec.ts +++ b/spec/unit/crypto/backup.spec.ts @@ -197,7 +197,7 @@ describe("MegolmBackup", function() { // to tick the clock between the first try and the retry. const realSetTimeout = global.setTimeout; jest.spyOn(global, 'setTimeout').mockImplementation(function(f, n) { - return realSetTimeout(f, n/100); + return realSetTimeout(f!, n/100); }); }); diff --git a/src/ToDeviceMessageQueue.ts b/src/ToDeviceMessageQueue.ts index ffdecedacc7..aaff912de69 100644 --- a/src/ToDeviceMessageQueue.ts +++ b/src/ToDeviceMessageQueue.ts @@ -68,7 +68,7 @@ export class ToDeviceMessageQueue { logger.debug("Attempting to send queued to-device messages"); this.sending = true; - let headBatch; + let headBatch: IndexedToDeviceBatch; try { while (this.running) { headBatch = await this.client.store.getOldestToDeviceBatch(); @@ -92,7 +92,7 @@ export class ToDeviceMessageQueue { // bored and giving up for now if (Math.floor(e.httpStatus / 100) === 4) { logger.error("Fatal error when sending to-device message - dropping to-device batch!", e); - await this.client.store.removeToDeviceBatch(headBatch.id); + await this.client.store.removeToDeviceBatch(headBatch!.id); } else { logger.info("Automatic retry limit reached for to-device messages."); } diff --git a/src/autodiscovery.ts b/src/autodiscovery.ts index 95dd543d03f..e4e560e4a41 100644 --- a/src/autodiscovery.ts +++ b/src/autodiscovery.ts @@ -440,12 +440,13 @@ export class AutoDiscovery { reason: "General failure", }; } - } catch (error) { + } catch (err) { + const error = err as Error | string | undefined; return { error, raw: {}, action: AutoDiscoveryAction.FAIL_PROMPT, - reason: error?.message || "General failure", + reason: (error)?.message || "General failure", }; } @@ -455,11 +456,12 @@ export class AutoDiscovery { action: AutoDiscoveryAction.SUCCESS, }; } catch (err) { + const error = err as Error | string | undefined; return { - error: err, + error, raw: {}, action: AutoDiscoveryAction.FAIL_PROMPT, - reason: (err as MatrixError)?.name === "SyntaxError" + reason: (error as MatrixError)?.name === "SyntaxError" ? AutoDiscovery.ERROR_INVALID_JSON : AutoDiscovery.ERROR_INVALID, }; diff --git a/src/client.ts b/src/client.ts index 46936fb5b3f..eb4e6d028ec 100644 --- a/src/client.ts +++ b/src/client.ts @@ -912,9 +912,9 @@ export class MatrixClient extends TypedEventEmitter; + getOldestToDeviceBatch(): Promise; /** * Removes a specific batch of to-device messages from the queue diff --git a/src/store/indexeddb-backend.ts b/src/store/indexeddb-backend.ts index 3a14fed7dee..f7547d6e531 100644 --- a/src/store/indexeddb-backend.ts +++ b/src/store/indexeddb-backend.ts @@ -33,7 +33,7 @@ export interface IIndexedDBBackend { getClientOptions(): Promise; storeClientOptions(options: IStartClientOpts): Promise; saveToDeviceBatches(batches: ToDeviceBatchWithTxnId[]): Promise; - getOldestToDeviceBatch(): Promise; + getOldestToDeviceBatch(): Promise; removeToDeviceBatch(id: number): Promise; } diff --git a/src/store/indexeddb-remote-backend.ts b/src/store/indexeddb-remote-backend.ts index 8be023f2bc6..d36404b90df 100644 --- a/src/store/indexeddb-remote-backend.ts +++ b/src/store/indexeddb-remote-backend.ts @@ -138,7 +138,7 @@ export class RemoteIndexedDBStoreBackend implements IIndexedDBBackend { return this.doCmd('saveToDeviceBatches', [batches]); } - public async getOldestToDeviceBatch(): Promise { + public async getOldestToDeviceBatch(): Promise { return this.doCmd('getOldestToDeviceBatch'); } diff --git a/src/store/indexeddb.ts b/src/store/indexeddb.ts index 44f684bdf8f..2bc4f28f6e5 100644 --- a/src/store/indexeddb.ts +++ b/src/store/indexeddb.ts @@ -357,7 +357,7 @@ export class IndexedDBStore extends MemoryStore { return this.backend.saveToDeviceBatches(batches); } - public getOldestToDeviceBatch(): Promise { + public getOldestToDeviceBatch(): Promise { return this.backend.getOldestToDeviceBatch(); } From 65b6935fbb394f4e4cfe09453eb6fe3acfcc12b8 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 19:35:21 +0100 Subject: [PATCH 13/38] Revert tests tweak --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d01277b999b..b149d2e1884 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,7 +26,7 @@ jobs: run: "yarn build" - name: Run tests with coverage - run: "yarn coverage --ci --detectOpenHandles --reporters github-actions" + run: "yarn coverage --ci --reporters github-actions" - name: Upload Artifact uses: actions/upload-artifact@v3 From a8ecb36f2a0aeb8d8451b44c3aac83eab50407c5 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 20:05:15 +0100 Subject: [PATCH 14/38] Add test coverage --- spec/http-api/utils.spec.ts | 122 ++++++++++++++++++++++++++++++++++++ spec/unit/utils.spec.ts | 7 +++ src/http-api/fetch.ts | 4 +- src/http-api/index.ts | 4 +- src/http-api/utils.ts | 7 +-- 5 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 spec/http-api/utils.spec.ts diff --git a/spec/http-api/utils.spec.ts b/spec/http-api/utils.spec.ts new file mode 100644 index 00000000000..db78ac5420d --- /dev/null +++ b/spec/http-api/utils.spec.ts @@ -0,0 +1,122 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { anySignal, MatrixError, parseErrorResponse, timeoutSignal } from "../../src"; + +describe("timeoutSignal", () => { + jest.useFakeTimers(); + + it("should fire abort signal after specified timeout", () => { + const signal = timeoutSignal(3000); + const onabort = jest.fn(); + signal.onabort = onabort; + expect(signal.aborted).toBeFalsy(); + expect(onabort).not.toHaveBeenCalled(); + + jest.advanceTimersByTime(3000); + expect(signal.aborted).toBeTruthy(); + expect(onabort).toHaveBeenCalled(); + }); +}); + +describe("anySignal", () => { + jest.useFakeTimers(); + + it("should fire when any signal fires", () => { + const { signal } = anySignal([ + timeoutSignal(3000), + timeoutSignal(2000), + ]); + + const onabort = jest.fn(); + signal.onabort = onabort; + expect(signal.aborted).toBeFalsy(); + expect(onabort).not.toHaveBeenCalled(); + + jest.advanceTimersByTime(2000); + expect(signal.aborted).toBeTruthy(); + expect(onabort).toHaveBeenCalled(); + }); + + it("should cleanup when instructed", () => { + const { signal, cleanup } = anySignal([ + timeoutSignal(3000), + timeoutSignal(2000), + ]); + + const onabort = jest.fn(); + signal.onabort = onabort; + expect(signal.aborted).toBeFalsy(); + expect(onabort).not.toHaveBeenCalled(); + + cleanup(); + jest.advanceTimersByTime(2000); + expect(signal.aborted).toBeFalsy(); + expect(onabort).not.toHaveBeenCalled(); + }); +}); + +describe("parseErrorResponse", () => { + it("should resolve Matrix Errors from XHR", () => { + expect(parseErrorResponse({ + getResponseHeader(name: string): string | null { + return name === "Content-Type" ? "application/json" : null; + }, + status: 500, + } as XMLHttpRequest, '{"errcode": "TEST"}')).toStrictEqual(new MatrixError({ + errcode: "TEST", + }, 500)); + }); + + it("should resolve Matrix Errors from fetch", () => { + expect(parseErrorResponse({ + headers: { + get(name: string): string | null { + return name === "Content-Type" ? "application/json" : null; + }, + }, + status: 500, + } as Response, '{"errcode": "TEST"}')).toStrictEqual(new MatrixError({ + errcode: "TEST", + }, 500)); + }); + + it("should handle unknown type gracefully", () => { + expect(parseErrorResponse({ + headers: { + get(name: string): string | null { + return name === "Content-Type" ? "application/x-foo" : null; + }, + }, + status: 500, + } as Response, '{"errcode": "TEST"}')).toStrictEqual(new Error("Server returned 500 error")); + }); + + it("should handle plaintext errors", () => { + expect(parseErrorResponse({ + headers: { + get(name: string): string | null { + return name === "Content-Type" ? "text/plain" : null; + }, + }, + status: 418, + } as Response, "I'm a teapot")).toStrictEqual(new Error("Server returned 418 error: I'm a teapot")); + }); +}); + +describe("retryNetworkOperation", () => { + +}); diff --git a/spec/unit/utils.spec.ts b/spec/unit/utils.spec.ts index 117f4c88c96..d9d8b819dde 100644 --- a/spec/unit/utils.spec.ts +++ b/spec/unit/utils.spec.ts @@ -37,6 +37,13 @@ describe("utils", function() { }; expect(utils.encodeParams(params).toString()).toEqual("string=foobar&number=12345&boolean=false"); }); + + it("should handle string arrays", () => { + const params = { + via: ["one", "two", "three"], + }; + expect(utils.encodeParams(params).toString()).toEqual("via=one&via=two&via=three"); + }); }); describe("encodeUri", function() { diff --git a/src/http-api/fetch.ts b/src/http-api/fetch.ts index 468e613439b..9fefd82bdda 100644 --- a/src/http-api/fetch.ts +++ b/src/http-api/fetch.ts @@ -22,7 +22,7 @@ limitations under the License. import * as utils from "../utils"; import { TypedEventEmitter } from "../models/typed-event-emitter"; import { Method } from "./method"; -import { MatrixError } from "./errors"; +import { ConnectionError, MatrixError } from "./errors"; import { HttpApiEvent, HttpApiEventHandlerMap, IHttpOpts, IRequestOpts } from "./interface"; import { anySignal, parseErrorResponse, timeoutSignal } from "./utils"; import { QueryDict } from "../utils"; @@ -284,6 +284,8 @@ export class FetchHttpApi { cache: "no-cache", credentials: "omit", // we send credentials via headers }); + } catch (e) { + throw new ConnectionError("fetch failed", e); } finally { cleanup(); } diff --git a/src/http-api/index.ts b/src/http-api/index.ts index 990d65bd3c1..9d4edd6becd 100644 --- a/src/http-api/index.ts +++ b/src/http-api/index.ts @@ -20,7 +20,7 @@ import { MediaPrefix } from "./prefix"; import * as utils from "../utils"; import * as callbacks from "../realtime-callbacks"; import { Method } from "./method"; -import { MatrixError } from "./errors"; +import { ConnectionError, MatrixError } from "./errors"; import { parseErrorResponse } from "./utils"; export * from "./interface"; @@ -113,7 +113,7 @@ export class MatrixHttpApi extends FetchHttpApi { } } catch (err) { (err).httpStatus = xhr.status; - defer.reject(err); + defer.reject(new ConnectionError("request failed", err)); } break; } diff --git a/src/http-api/utils.ts b/src/http-api/utils.ts index 0f436451f2d..06f7e1881c5 100644 --- a/src/http-api/utils.ts +++ b/src/http-api/utils.ts @@ -23,15 +23,10 @@ import { ConnectionError, MatrixError } from "./errors"; // Ponyfill for https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout export function timeoutSignal(ms: number): AbortSignal { const controller = new AbortController(); - const timeoutId = setTimeout(() => { + setTimeout(() => { controller.abort(); }, ms); - function onAbort() { - clearTimeout(timeoutId); - } - - controller.signal.addEventListener("abort", onAbort); return controller.signal; } From 6289875ca44a882c68365145059ca15eabac11fa Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 20:12:31 +0100 Subject: [PATCH 15/38] Fix tests --- spec/integ/matrix-client-opts.spec.js | 2 +- spec/integ/matrix-client-room-timeline.spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/integ/matrix-client-opts.spec.js b/spec/integ/matrix-client-opts.spec.js index 31d4b592951..0902091976b 100644 --- a/spec/integ/matrix-client-opts.spec.js +++ b/spec/integ/matrix-client-opts.spec.js @@ -141,7 +141,7 @@ describe("MatrixClient opts", function() { }); it("shouldn't retry sending events", function(done) { - httpBackend.when("PUT", "/txn1").fail(500, new MatrixError({ + httpBackend.when("PUT", "/txn1").respond(500, new MatrixError({ errcode: "M_SOMETHING", error: "Ruh roh", })); diff --git a/spec/integ/matrix-client-room-timeline.spec.js b/spec/integ/matrix-client-room-timeline.spec.js index 33f53f2185b..9d720f91cee 100644 --- a/spec/integ/matrix-client-room-timeline.spec.js +++ b/spec/integ/matrix-client-room-timeline.spec.js @@ -797,7 +797,7 @@ describe("MatrixClient room timelines", function() { httpBackend.when("GET", contextUrl).check(() => { // The timeline should be cleared at this point in the refresh expect(room.timeline.length).toEqual(0); - }).fail(500, new MatrixError({ + }).respond(500, new MatrixError({ errcode: 'TEST_FAKE_ERROR', error: 'We purposely intercepted this /context request to make it fail ' + 'in order to test whether the refresh timeline code is resilient', From 064469c21ba5bed2b0156e7a9c7b0c93b4b95ad9 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 21:10:52 +0100 Subject: [PATCH 16/38] Add tests and fix `retryNetworkOperation` --- spec/{ => unit}/http-api/utils.spec.ts | 66 ++++++++++++++++++++++++-- src/http-api/utils.ts | 15 +++--- 2 files changed, 72 insertions(+), 9 deletions(-) rename spec/{ => unit}/http-api/utils.spec.ts (60%) diff --git a/spec/http-api/utils.spec.ts b/spec/unit/http-api/utils.spec.ts similarity index 60% rename from spec/http-api/utils.spec.ts rename to spec/unit/http-api/utils.spec.ts index db78ac5420d..5226440933b 100644 --- a/spec/http-api/utils.spec.ts +++ b/spec/unit/http-api/utils.spec.ts @@ -14,7 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { anySignal, MatrixError, parseErrorResponse, timeoutSignal } from "../../src"; +import { mocked } from "jest-mock"; + +import { + anySignal, + ConnectionError, + MatrixError, + parseErrorResponse, + retryNetworkOperation, + timeoutSignal, +} from "../../../src"; +import { sleep } from "../../../src/utils"; + +jest.mock("../../../src/utils"); describe("timeoutSignal", () => { jest.useFakeTimers(); @@ -67,6 +79,13 @@ describe("anySignal", () => { expect(signal.aborted).toBeFalsy(); expect(onabort).not.toHaveBeenCalled(); }); + + it("should abort immediately if passed an aborted signal", () => { + const controller = new AbortController(); + controller.abort(); + const { signal } = anySignal([controller.signal]); + expect(signal.aborted).toBeTruthy(); + }); }); describe("parseErrorResponse", () => { @@ -94,11 +113,22 @@ describe("parseErrorResponse", () => { }, 500)); }); - it("should handle unknown type gracefully", () => { + it("should handle no type gracefully", () => { + expect(parseErrorResponse({ + headers: { + get(name: string): string | null { + return null; + }, + }, + status: 500, + } as Response, '{"errcode": "TEST"}')).toStrictEqual(new Error("Server returned 500 error")); + }); + + it("should handle invalid type gracefully", () => { expect(parseErrorResponse({ headers: { get(name: string): string | null { - return name === "Content-Type" ? "application/x-foo" : null; + return name === "Content-Type" ? "application/x-foo;fff=dad12%%" : null; }, }, status: 500, @@ -118,5 +148,35 @@ describe("parseErrorResponse", () => { }); describe("retryNetworkOperation", () => { + it("should retry given number of times with exponential sleeps", async () => { + const err = new ConnectionError("test"); + const fn = jest.fn().mockRejectedValue(err); + mocked(sleep).mockResolvedValue(undefined); + await expect(retryNetworkOperation(4, fn)).rejects.toThrow(err); + expect(fn).toHaveBeenCalledTimes(4); + expect(mocked(sleep)).toHaveBeenCalledTimes(3); + expect(mocked(sleep).mock.calls[0][0]).toBe(2000); + expect(mocked(sleep).mock.calls[1][0]).toBe(4000); + expect(mocked(sleep).mock.calls[2][0]).toBe(8000); + }); + + it("should bail out on errors other than ConnectionError", async () => { + const err = new TypeError("invalid JSON"); + const fn = jest.fn().mockRejectedValue(err); + mocked(sleep).mockResolvedValue(undefined); + await expect(retryNetworkOperation(3, fn)).rejects.toThrow(err); + expect(fn).toHaveBeenCalledTimes(1); + }); + it("should return newest ConnectionError when giving up", async () => { + const err1 = new ConnectionError("test1"); + const err2 = new ConnectionError("test2"); + const err3 = new ConnectionError("test3"); + const errors = [err1, err2, err3]; + const fn = jest.fn().mockImplementation(() => { + throw errors.shift(); + }); + mocked(sleep).mockResolvedValue(undefined); + await expect(retryNetworkOperation(3, fn)).rejects.toThrow(err3); + }); }); diff --git a/src/http-api/utils.ts b/src/http-api/utils.ts index 06f7e1881c5..8373a7504e3 100644 --- a/src/http-api/utils.ts +++ b/src/http-api/utils.ts @@ -83,6 +83,10 @@ export function parseErrorResponse(response: XMLHttpRequest | Response, body?: s return new Error(`Server returned ${response.status} error`); } +function isXhr(response: XMLHttpRequest | Response): response is XMLHttpRequest { + return "getResponseHeader" in response; +} + /** * extract the Content-Type header from the response object, and * parse it to a `{type, parameters}` object. @@ -93,10 +97,10 @@ export function parseErrorResponse(response: XMLHttpRequest | Response, body?: s * @returns {{type: String, parameters: Object}?} parsed content-type header, or null if not found */ function getResponseContentType(response: XMLHttpRequest | Response): ParsedMediaType | null { - let contentType: string | null = null; - if ((response as XMLHttpRequest).getResponseHeader) { + let contentType: string | null; + if (isXhr(response)) { contentType = (response as XMLHttpRequest).getResponseHeader("Content-Type"); - } else if ((response as Response).headers) { + } else { contentType = (response as Response).headers.get("Content-Type"); } @@ -123,11 +127,10 @@ export async function retryNetworkOperation(maxAttempts: number, callback: () try { if (attempts > 0) { const timeout = 1000 * Math.pow(2, attempts); - logger.log(`network operation failed ${attempts} times,` + - ` retrying in ${timeout}ms...`); + logger.log(`network operation failed ${attempts} times, retrying in ${timeout}ms...`); await sleep(timeout); } - return callback(); + return await callback(); } catch (err) { if (err instanceof ConnectionError) { attempts += 1; From d2d2e0595853ac21c2b24361ecdb7060a4572cb2 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 21:37:02 +0100 Subject: [PATCH 17/38] Improve coverage --- spec/unit/http-api/utils.spec.ts | 5 +++-- src/http-api/utils.ts | 11 ++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/spec/unit/http-api/utils.spec.ts b/spec/unit/http-api/utils.spec.ts index 5226440933b..1a266c8423c 100644 --- a/spec/unit/http-api/utils.spec.ts +++ b/spec/unit/http-api/utils.spec.ts @@ -128,11 +128,12 @@ describe("parseErrorResponse", () => { expect(parseErrorResponse({ headers: { get(name: string): string | null { - return name === "Content-Type" ? "application/x-foo;fff=dad12%%" : null; + return name === "Content-Type" ? " " : null; }, }, status: 500, - } as Response, '{"errcode": "TEST"}')).toStrictEqual(new Error("Server returned 500 error")); + } as Response, '{"errcode": "TEST"}')) + .toStrictEqual(new Error("Error parsing Content-Type ' ': TypeError: invalid media type")); }); it("should handle plaintext errors", () => { diff --git a/src/http-api/utils.ts b/src/http-api/utils.ts index 8373a7504e3..220e0300b05 100644 --- a/src/http-api/utils.ts +++ b/src/http-api/utils.ts @@ -72,7 +72,12 @@ export function anySignal(signals: AbortSignal[]): { * @returns {Error} */ export function parseErrorResponse(response: XMLHttpRequest | Response, body?: string): Error { - const contentType = getResponseContentType(response); + let contentType: ParsedMediaType; + try { + contentType = getResponseContentType(response); + } catch (e) { + return e; + } if (contentType?.type === "application/json" && body) { return new MatrixError(JSON.parse(body), response.status); @@ -99,9 +104,9 @@ function isXhr(response: XMLHttpRequest | Response): response is XMLHttpRequest function getResponseContentType(response: XMLHttpRequest | Response): ParsedMediaType | null { let contentType: string | null; if (isXhr(response)) { - contentType = (response as XMLHttpRequest).getResponseHeader("Content-Type"); + contentType = response.getResponseHeader("Content-Type"); } else { - contentType = (response as Response).headers.get("Content-Type"); + contentType = response.headers.get("Content-Type"); } if (!contentType) return null; From 271ea3c6b74b3c351612014dae560e729e31d6d2 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 22:15:56 +0100 Subject: [PATCH 18/38] Add more coverage --- spec/unit/http-api/fetch.spec.ts | 102 +++++++++++++++++++++++++++++++ src/http-api/fetch.ts | 6 +- 2 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 spec/unit/http-api/fetch.spec.ts diff --git a/spec/unit/http-api/fetch.spec.ts b/spec/unit/http-api/fetch.spec.ts new file mode 100644 index 00000000000..65828fad08b --- /dev/null +++ b/spec/unit/http-api/fetch.spec.ts @@ -0,0 +1,102 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { FetchHttpApi } from "../../../src/http-api/fetch"; +import { TypedEventEmitter } from "../../../src/models/typed-event-emitter"; +import { ClientPrefix, IdentityPrefix, IHttpOpts, Method } from "../../../src"; + +describe("FetchHttpApi", () => { + const baseUrl = "http://baseUrl"; + const idBaseUrl = "http://idBaseUrl"; + const prefix = ClientPrefix.V3; + + it("should support aborting multiple times", () => { + const fetchFn = jest.fn().mockResolvedValue({ ok: true }); + const api = new FetchHttpApi(new TypedEventEmitter(), { baseUrl, prefix, fetchFn }); + + api.request(Method.Get, "/foo"); + api.request(Method.Get, "/baz"); + expect(fetchFn.mock.calls[0][0].href.endsWith("/foo")).toBeTruthy(); + expect(fetchFn.mock.calls[0][1].signal.aborted).toBeFalsy(); + expect(fetchFn.mock.calls[1][0].href.endsWith("/baz")).toBeTruthy(); + expect(fetchFn.mock.calls[1][1].signal.aborted).toBeFalsy(); + + api.abort(); + expect(fetchFn.mock.calls[0][1].signal.aborted).toBeTruthy(); + expect(fetchFn.mock.calls[1][1].signal.aborted).toBeTruthy(); + + api.request(Method.Get, "/bar"); + expect(fetchFn.mock.calls[2][0].href.endsWith("/bar")).toBeTruthy(); + expect(fetchFn.mock.calls[2][1].signal.aborted).toBeFalsy(); + + api.abort(); + expect(fetchFn.mock.calls[2][1].signal.aborted).toBeTruthy(); + }); + + it("should fall back to global fetch if fetchFn not provided", () => { + global.fetch = jest.fn(); + expect(global.fetch).not.toHaveBeenCalled(); + const api = new FetchHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); + api.fetch("test"); + expect(global.fetch).toHaveBeenCalled(); + }); + + it("should update identity server base url", () => { + const api = new FetchHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); + expect(api.opts.idBaseUrl).toBeUndefined(); + api.setIdBaseUrl("https://id.foo.bar"); + expect(api.opts.idBaseUrl).toBe("https://id.foo.bar"); + }); + + describe("idServerRequest", () => { + it("should throw if no idBaseUrl", () => { + const api = new FetchHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); + expect(() => api.idServerRequest(Method.Get, "/test", {}, IdentityPrefix.V2)) + .toThrow("No identity server base URL set"); + }); + + it("should send params as query string for GET requests", () => { + const fetchFn = jest.fn().mockResolvedValue({ ok: true }); + const api = new FetchHttpApi(new TypedEventEmitter(), { baseUrl, idBaseUrl, prefix, fetchFn }); + api.idServerRequest(Method.Get, "/test", { foo: "bar", via: ["a", "b"] }, IdentityPrefix.V2); + expect(fetchFn.mock.calls[0][0].searchParams.get("foo")).toBe("bar"); + expect(fetchFn.mock.calls[0][0].searchParams.getAll("via")).toEqual(["a", "b"]); + }); + + it("should send params as body for non-GET requests", () => { + const fetchFn = jest.fn().mockResolvedValue({ ok: true }); + const api = new FetchHttpApi(new TypedEventEmitter(), { baseUrl, idBaseUrl, prefix, fetchFn }); + const params = { foo: "bar", via: ["a", "b"] }; + api.idServerRequest(Method.Post, "/test", params, IdentityPrefix.V2); + expect(fetchFn.mock.calls[0][0].searchParams.get("foo")).not.toBe("bar"); + expect(JSON.parse(fetchFn.mock.calls[0][1].body)).toStrictEqual(params); + }); + + it("should add Authorization header if token provided", () => { + const fetchFn = jest.fn().mockResolvedValue({ ok: true }); + const api = new FetchHttpApi(new TypedEventEmitter(), { baseUrl, idBaseUrl, prefix, fetchFn }); + api.idServerRequest(Method.Post, "/test", {}, IdentityPrefix.V2, "token"); + expect(fetchFn.mock.calls[0][1].headers.Authorization).toBe("Bearer token"); + }); + }); + + it("should return the Response object if onlyData=false", async () => { + const res = { ok: true }; + const fetchFn = jest.fn().mockResolvedValue(res); + const api = new FetchHttpApi(new TypedEventEmitter(), { baseUrl, prefix, fetchFn, onlyData: false }); + await expect(api.requestOtherUrl(Method.Get, "http://url")).resolves.toBe(res); + }); +}); diff --git a/src/http-api/fetch.ts b/src/http-api/fetch.ts index 9fefd82bdda..83a5e9565bf 100644 --- a/src/http-api/fetch.ts +++ b/src/http-api/fetch.ts @@ -75,7 +75,7 @@ export class FetchHttpApi { path: string, params: Record, prefix: string, - accessToken: string, + accessToken?: string, ): Promise> { if (!this.opts.idBaseUrl) { throw new Error("No identity server base URL set"); @@ -85,7 +85,7 @@ export class FetchHttpApi { let body: Record | undefined = undefined; if (method === Method.Get) { queryParams = params; - } else if (typeof params === "object") { + } else { body = params; } @@ -96,7 +96,7 @@ export class FetchHttpApi { headers: {}, }; if (accessToken) { - opts.headers!.Authorization = `Bearer ${accessToken}`; + opts.headers.Authorization = `Bearer ${accessToken}`; } return this.requestOtherUrl(method, fullUri, body, opts); From c9e45c0b9bc4aa0dc3257ecdbdbe7ecf09f0e60e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 22:38:00 +0100 Subject: [PATCH 19/38] Add tests --- spec/unit/http-api/fetch.spec.ts | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/spec/unit/http-api/fetch.spec.ts b/spec/unit/http-api/fetch.spec.ts index 65828fad08b..00d2f83278b 100644 --- a/spec/unit/http-api/fetch.spec.ts +++ b/spec/unit/http-api/fetch.spec.ts @@ -99,4 +99,42 @@ describe("FetchHttpApi", () => { const api = new FetchHttpApi(new TypedEventEmitter(), { baseUrl, prefix, fetchFn, onlyData: false }); await expect(api.requestOtherUrl(Method.Get, "http://url")).resolves.toBe(res); }); + + it("should send token via query params if useAuthorizationHeader=false", () => { + const fetchFn = jest.fn().mockResolvedValue({ ok: true }); + const api = new FetchHttpApi(new TypedEventEmitter(), { + baseUrl, + prefix, + fetchFn, + accessToken: "token", + useAuthorizationHeader: false, + }); + api.authedRequest(Method.Get, "/path"); + expect(fetchFn.mock.calls[0][0].searchParams.get("access_token")).toBe("token"); + }); + + it("should send token via headers by default", () => { + const fetchFn = jest.fn().mockResolvedValue({ ok: true }); + const api = new FetchHttpApi(new TypedEventEmitter(), { + baseUrl, + prefix, + fetchFn, + accessToken: "token", + }); + api.authedRequest(Method.Get, "/path"); + expect(fetchFn.mock.calls[0][1].headers["Authorization"]).toBe("Bearer token"); + }); + + it("should not send a token if not calling `authedRequest`", () => { + const fetchFn = jest.fn().mockResolvedValue({ ok: true }); + const api = new FetchHttpApi(new TypedEventEmitter(), { + baseUrl, + prefix, + fetchFn, + accessToken: "token", + }); + api.request(Method.Get, "/path"); + expect(fetchFn.mock.calls[0][0].searchParams.get("access_token")).toBeFalsy(); + expect(fetchFn.mock.calls[0][1].headers["Authorization"]).toBeFalsy(); + }); }); From 27ca4791059d7c27db5cb89997142ff5dcc6e9d1 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 23:15:32 +0100 Subject: [PATCH 20/38] Iterate --- spec/unit/http-api/fetch.spec.ts | 60 ++++++++++++++++++++++++++++++++ src/http-api/index.ts | 2 +- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/spec/unit/http-api/fetch.spec.ts b/spec/unit/http-api/fetch.spec.ts index 00d2f83278b..13d937daa30 100644 --- a/spec/unit/http-api/fetch.spec.ts +++ b/spec/unit/http-api/fetch.spec.ts @@ -100,6 +100,15 @@ describe("FetchHttpApi", () => { await expect(api.requestOtherUrl(Method.Get, "http://url")).resolves.toBe(res); }); + it("should return text if json=false", async () => { + const text = "418 I'm a teapot"; + const fetchFn = jest.fn().mockResolvedValue({ ok: true, text: jest.fn().mockResolvedValue(text) }); + const api = new FetchHttpApi(new TypedEventEmitter(), { baseUrl, prefix, fetchFn, onlyData: true }); + await expect(api.requestOtherUrl(Method.Get, "http://url", undefined, { + json: false, + })).resolves.toBe(text); + }); + it("should send token via query params if useAuthorizationHeader=false", () => { const fetchFn = jest.fn().mockResolvedValue({ ok: true }); const api = new FetchHttpApi(new TypedEventEmitter(), { @@ -137,4 +146,55 @@ describe("FetchHttpApi", () => { expect(fetchFn.mock.calls[0][0].searchParams.get("access_token")).toBeFalsy(); expect(fetchFn.mock.calls[0][1].headers["Authorization"]).toBeFalsy(); }); + + it("should ensure no token is leaked out via query params if sending via headers", () => { + const fetchFn = jest.fn().mockResolvedValue({ ok: true }); + const api = new FetchHttpApi(new TypedEventEmitter(), { + baseUrl, + prefix, + fetchFn, + accessToken: "token", + useAuthorizationHeader: true, + }); + api.authedRequest(Method.Get, "/path", { access_token: "123" }); + expect(fetchFn.mock.calls[0][0].searchParams.get("access_token")).toBeFalsy(); + expect(fetchFn.mock.calls[0][1].headers["Authorization"]).toBe("Bearer token"); + }); + + it("should not override manually specified access token via query params", () => { + const fetchFn = jest.fn().mockResolvedValue({ ok: true }); + const api = new FetchHttpApi(new TypedEventEmitter(), { + baseUrl, + prefix, + fetchFn, + accessToken: "token", + useAuthorizationHeader: false, + }); + api.authedRequest(Method.Get, "/path", { access_token: "RealToken" }); + expect(fetchFn.mock.calls[0][0].searchParams.get("access_token")).toBe("RealToken"); + }); + + it("should not override manually specified access token via header", () => { + const fetchFn = jest.fn().mockResolvedValue({ ok: true }); + const api = new FetchHttpApi(new TypedEventEmitter(), { + baseUrl, + prefix, + fetchFn, + accessToken: "token", + useAuthorizationHeader: true, + }); + api.authedRequest(Method.Get, "/path", undefined, undefined, { + headers: { Authorization: "Bearer RealToken" }, + }); + expect(fetchFn.mock.calls[0][1].headers["Authorization"]).toBe("Bearer RealToken"); + }); + + it("should not override Accept header", () => { + const fetchFn = jest.fn().mockResolvedValue({ ok: true }); + const api = new FetchHttpApi(new TypedEventEmitter(), { baseUrl, prefix, fetchFn }); + api.authedRequest(Method.Get, "/path", undefined, undefined, { + headers: { Accept: "text/html" }, + }); + expect(fetchFn.mock.calls[0][1].headers["Accept"]).toBe("text/html"); + }); }); diff --git a/src/http-api/index.ts b/src/http-api/index.ts index 9d4edd6becd..75872b476ac 100644 --- a/src/http-api/index.ts +++ b/src/http-api/index.ts @@ -204,7 +204,7 @@ export class MatrixHttpApi extends FetchHttpApi { base: this.opts.baseUrl, path: MediaPrefix.R0 + "/upload", params: { - access_token: this.opts.accessToken!, + access_token: this.opts.accessToken, }, }; } From d2fb428e06528a0397f18c15ac314ecc908c6405 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 23:46:21 +0100 Subject: [PATCH 21/38] Write moar tests --- spec/unit/http-api/index.spec.ts | 100 +++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 spec/unit/http-api/index.spec.ts diff --git a/spec/unit/http-api/index.spec.ts b/spec/unit/http-api/index.spec.ts new file mode 100644 index 00000000000..edd13927bd3 --- /dev/null +++ b/spec/unit/http-api/index.spec.ts @@ -0,0 +1,100 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { ClientPrefix, MatrixHttpApi, Method } from "../../../src"; +import { TypedEventEmitter } from "../../../src/models/typed-event-emitter"; + +describe("MatrixHttpApi", () => { + const baseUrl = "http://baseUrl"; + const prefix = ClientPrefix.V3; + + const open = jest.fn(); + const send = jest.fn(); + const abort = jest.fn(); + const setRequestHeader = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + global.XMLHttpRequest = jest.fn().mockReturnValue({ + upload: {}, + open, + send, + abort, + setRequestHeader, + }); + }); + + it("should fall back to `fetch` where xhr is unavailable", () => { + global.XMLHttpRequest = undefined; + const fetchFn = jest.fn().mockResolvedValue({ ok: true, json: jest.fn().mockResolvedValue({}) }); + const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix, fetchFn }); + api.uploadContent({} as File); + expect(fetchFn).toHaveBeenCalled(); + }); + + it("should prefer xhr where available", () => { + const fetchFn = jest.fn().mockResolvedValue({ ok: true }); + const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix, fetchFn }); + api.uploadContent({} as File); + expect(fetchFn).not.toHaveBeenCalled(); + expect(open).toHaveBeenCalled(); + }); + + it("should send access token in query params if header disabled", () => { + const api = new MatrixHttpApi(new TypedEventEmitter(), { + baseUrl, + prefix, + accessToken: "token", + useAuthorizationHeader: false, + }); + api.uploadContent({} as File); + expect(open) + .toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload?access_token=token"); + expect(setRequestHeader).not.toHaveBeenCalledWith("Authorization"); + }); + + it("should send access token in header by default", () => { + const api = new MatrixHttpApi(new TypedEventEmitter(), { + baseUrl, + prefix, + accessToken: "token", + }); + api.uploadContent({} as File); + expect(open).toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload"); + expect(setRequestHeader).toHaveBeenCalledWith("Authorization", "Bearer token"); + }); + + it("should include filename by default", () => { + const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); + api.uploadContent({} as File, { name: "name" }); + expect(open) + .toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload?filename=name"); + }); + + it("should allow not sending the filename", () => { + const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); + api.uploadContent({} as File, { name: "name", includeFilename: false }); + expect(open).toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload"); + }); + + it("should abort xhr when the upload is aborted", () => { + const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); + const upload = api.uploadContent({} as File); + upload.abortController.abort(); + expect(abort).toHaveBeenCalled(); + return expect(upload.promise).rejects.toThrow("Aborted"); + }); +}); From fd72edad2cdc528006eb498fdf03b8e8aee76e37 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 4 Oct 2022 23:50:07 +0100 Subject: [PATCH 22/38] Fix typing --- spec/unit/http-api/index.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/unit/http-api/index.spec.ts b/spec/unit/http-api/index.spec.ts index edd13927bd3..3f256814fab 100644 --- a/spec/unit/http-api/index.spec.ts +++ b/spec/unit/http-api/index.spec.ts @@ -28,6 +28,7 @@ describe("MatrixHttpApi", () => { beforeEach(() => { jest.clearAllMocks(); + // @ts-ignore global.XMLHttpRequest = jest.fn().mockReturnValue({ upload: {}, open, From 6781d53de12c4cc8f5bc3f1cb28954e0a84e403a Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 5 Oct 2022 10:39:00 +0100 Subject: [PATCH 23/38] Iterate tests --- package.json | 2 ++ spec/unit/http-api/index.spec.ts | 48 ++++++++++++++++++++++++-------- yarn.lock | 24 ++++++++++++++++ 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 91a9e49e406..1e96f874f2b 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.12.tgz", "@types/bs58": "^4.0.1", "@types/content-type": "^1.1.5", + "@types/domexception": "^4.0.0", "@types/jest": "^29.0.0", "@types/node": "16", "@typescript-eslint/eslint-plugin": "^5.6.0", @@ -89,6 +90,7 @@ "better-docs": "^2.4.0-beta.9", "browserify": "^17.0.0", "docdash": "^1.2.0", + "domexception": "^4.0.0", "eslint": "8.23.1", "eslint-config-google": "^0.14.0", "eslint-import-resolver-typescript": "^3.5.1", diff --git a/spec/unit/http-api/index.spec.ts b/spec/unit/http-api/index.spec.ts index 3f256814fab..9835aad2c58 100644 --- a/spec/unit/http-api/index.spec.ts +++ b/spec/unit/http-api/index.spec.ts @@ -14,42 +14,66 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ClientPrefix, MatrixHttpApi, Method } from "../../../src"; +import DOMException from "domexception"; + +import { ClientPrefix, MatrixHttpApi, Method, Upload } from "../../../src"; import { TypedEventEmitter } from "../../../src/models/typed-event-emitter"; +type Writeable = { -readonly [P in keyof T]: T[P] }; + describe("MatrixHttpApi", () => { const baseUrl = "http://baseUrl"; const prefix = ClientPrefix.V3; + let xhr: Partial>; + let upload: Upload; const open = jest.fn(); const send = jest.fn(); const abort = jest.fn(); const setRequestHeader = jest.fn(); + const DONE = 0; + + global.DOMException = DOMException; + beforeEach(() => { jest.clearAllMocks(); - // @ts-ignore - global.XMLHttpRequest = jest.fn().mockReturnValue({ - upload: {}, + xhr = { + upload: {} as XMLHttpRequestUpload, open, send, abort, setRequestHeader, - }); + onreadystatechange: undefined, + }; + // We stub out XHR here as it is not available in JSDOM + // @ts-ignore + global.XMLHttpRequest = jest.fn().mockReturnValue(xhr); + // @ts-ignore + global.XMLHttpRequest.DONE = DONE; + }); + + afterEach(() => { + upload?.promise.catch(() => {}); + // Abort any remaining requests + xhr.readyState = DONE; + xhr.status = 0; + // @ts-ignore + xhr.onreadystatechange?.(new Event("test")); }); it("should fall back to `fetch` where xhr is unavailable", () => { global.XMLHttpRequest = undefined; const fetchFn = jest.fn().mockResolvedValue({ ok: true, json: jest.fn().mockResolvedValue({}) }); const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix, fetchFn }); - api.uploadContent({} as File); + upload = api.uploadContent({} as File); expect(fetchFn).toHaveBeenCalled(); }); it("should prefer xhr where available", () => { const fetchFn = jest.fn().mockResolvedValue({ ok: true }); const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix, fetchFn }); - api.uploadContent({} as File); + upload = api.uploadContent({} as File); expect(fetchFn).not.toHaveBeenCalled(); expect(open).toHaveBeenCalled(); }); @@ -61,7 +85,7 @@ describe("MatrixHttpApi", () => { accessToken: "token", useAuthorizationHeader: false, }); - api.uploadContent({} as File); + upload = api.uploadContent({} as File); expect(open) .toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload?access_token=token"); expect(setRequestHeader).not.toHaveBeenCalledWith("Authorization"); @@ -73,27 +97,27 @@ describe("MatrixHttpApi", () => { prefix, accessToken: "token", }); - api.uploadContent({} as File); + upload = api.uploadContent({} as File); expect(open).toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload"); expect(setRequestHeader).toHaveBeenCalledWith("Authorization", "Bearer token"); }); it("should include filename by default", () => { const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); - api.uploadContent({} as File, { name: "name" }); + upload = api.uploadContent({} as File, { name: "name" }); expect(open) .toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload?filename=name"); }); it("should allow not sending the filename", () => { const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); - api.uploadContent({} as File, { name: "name", includeFilename: false }); + upload = api.uploadContent({} as File, { name: "name", includeFilename: false }); expect(open).toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload"); }); it("should abort xhr when the upload is aborted", () => { const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); - const upload = api.uploadContent({} as File); + upload = api.uploadContent({} as File); upload.abortController.abort(); expect(abort).toHaveBeenCalled(); return expect(upload.promise).rejects.toThrow("Aborted"); diff --git a/yarn.lock b/yarn.lock index 3d61b4d76e3..26afd3a8368 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1582,6 +1582,13 @@ resolved "https://registry.yarnpkg.com/@types/content-type/-/content-type-1.1.5.tgz#aa02dca40864749a9e2bf0161a6216da57e3ede5" integrity sha512-dgMN+syt1xb7Hk8LU6AODOfPlvz5z1CbXpPuJE5ZrX9STfBOIXF09pEB8N7a97WT9dbngt3ksDCm6GW6yMrxfQ== +"@types/domexception@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/domexception/-/domexception-4.0.0.tgz#bb19c920c81c3f1408b46d021fb79467ff2d32fd" + integrity sha512-vD9eLiVhgDrsVtUIiHBaToW/lfhCUYzmb81Sc0a0kJ4qEN2ZJyhz4wVyAmum4hAVDuBMUDE4yAeeF7fPHKCujw== + dependencies: + "@types/webidl-conversions" "*" + "@types/graceful-fs@^4.1.3": version "4.1.5" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" @@ -1669,6 +1676,11 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== +"@types/webidl-conversions@*": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz#2b8e60e33906459219aa587e9d1a612ae994cfe7" + integrity sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog== + "@types/yargs-parser@*": version "21.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" @@ -2924,6 +2936,13 @@ domexception@^1.0.1: dependencies: webidl-conversions "^4.0.2" +domexception@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-4.0.0.tgz#4ad1be56ccadc86fc76d033353999a8037d03673" + integrity sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw== + dependencies: + webidl-conversions "^7.0.0" + duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" @@ -6547,6 +6566,11 @@ webidl-conversions@^6.1.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" From 0f16233d033ba59c54ff68eaa8207eaaeb8400e7 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 5 Oct 2022 11:00:09 +0100 Subject: [PATCH 24/38] Additional coverage --- spec/unit/http-api/index.spec.ts | 88 ++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 17 deletions(-) diff --git a/spec/unit/http-api/index.spec.ts b/spec/unit/http-api/index.spec.ts index 9835aad2c58..080b4ecc98f 100644 --- a/spec/unit/http-api/index.spec.ts +++ b/spec/unit/http-api/index.spec.ts @@ -15,36 +15,35 @@ limitations under the License. */ import DOMException from "domexception"; +import { mocked } from "jest-mock"; import { ClientPrefix, MatrixHttpApi, Method, Upload } from "../../../src"; import { TypedEventEmitter } from "../../../src/models/typed-event-emitter"; type Writeable = { -readonly [P in keyof T]: T[P] }; +jest.useFakeTimers(); + describe("MatrixHttpApi", () => { const baseUrl = "http://baseUrl"; const prefix = ClientPrefix.V3; let xhr: Partial>; let upload: Upload; - const open = jest.fn(); - const send = jest.fn(); - const abort = jest.fn(); - const setRequestHeader = jest.fn(); const DONE = 0; global.DOMException = DOMException; beforeEach(() => { - jest.clearAllMocks(); xhr = { upload: {} as XMLHttpRequestUpload, - open, - send, - abort, - setRequestHeader, + open: jest.fn(), + send: jest.fn(), + abort: jest.fn(), + setRequestHeader: jest.fn(), onreadystatechange: undefined, + getResponseHeader: jest.fn(), }; // We stub out XHR here as it is not available in JSDOM // @ts-ignore @@ -75,7 +74,7 @@ describe("MatrixHttpApi", () => { const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix, fetchFn }); upload = api.uploadContent({} as File); expect(fetchFn).not.toHaveBeenCalled(); - expect(open).toHaveBeenCalled(); + expect(xhr.open).toHaveBeenCalled(); }); it("should send access token in query params if header disabled", () => { @@ -86,9 +85,9 @@ describe("MatrixHttpApi", () => { useAuthorizationHeader: false, }); upload = api.uploadContent({} as File); - expect(open) + expect(xhr.open) .toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload?access_token=token"); - expect(setRequestHeader).not.toHaveBeenCalledWith("Authorization"); + expect(xhr.setRequestHeader).not.toHaveBeenCalledWith("Authorization"); }); it("should send access token in header by default", () => { @@ -98,28 +97,83 @@ describe("MatrixHttpApi", () => { accessToken: "token", }); upload = api.uploadContent({} as File); - expect(open).toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload"); - expect(setRequestHeader).toHaveBeenCalledWith("Authorization", "Bearer token"); + expect(xhr.open).toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload"); + expect(xhr.setRequestHeader).toHaveBeenCalledWith("Authorization", "Bearer token"); }); it("should include filename by default", () => { const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); upload = api.uploadContent({} as File, { name: "name" }); - expect(open) + expect(xhr.open) .toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload?filename=name"); }); it("should allow not sending the filename", () => { const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); upload = api.uploadContent({} as File, { name: "name", includeFilename: false }); - expect(open).toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload"); + expect(xhr.open).toHaveBeenCalledWith(Method.Post, baseUrl.toLowerCase() + "/_matrix/media/r0/upload"); }); it("should abort xhr when the upload is aborted", () => { const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); upload = api.uploadContent({} as File); upload.abortController.abort(); - expect(abort).toHaveBeenCalled(); + expect(xhr.abort).toHaveBeenCalled(); return expect(upload.promise).rejects.toThrow("Aborted"); }); + + it("should timeout if no progress in 30s", () => { + const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); + upload = api.uploadContent({} as File); + jest.advanceTimersByTime(25000); + // @ts-ignore + xhr.upload.onprogress(new Event("progress", { loaded: 1, total: 100 })); + jest.advanceTimersByTime(25000); + expect(xhr.abort).not.toHaveBeenCalled(); + jest.advanceTimersByTime(5000); + expect(xhr.abort).toHaveBeenCalled(); + }); + + it("should call progressHandler", () => { + const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); + const progressHandler = jest.fn(); + upload = api.uploadContent({} as File, { progressHandler }); + const progressEvent = new Event("progress") as ProgressEvent; + Object.assign(progressEvent, { loaded: 1, total: 100 }); + // @ts-ignore + xhr.upload.onprogress(progressEvent); + expect(progressHandler).toHaveBeenCalledWith({ loaded: 1, total: 100 }); + + Object.assign(progressEvent, { loaded: 95, total: 100 }); + // @ts-ignore + xhr.upload.onprogress(progressEvent); + expect(progressHandler).toHaveBeenCalledWith({ loaded: 95, total: 100 }); + }); + + it("should error when no response body", () => { + const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); + upload = api.uploadContent({} as File); + + xhr.readyState = DONE; + xhr.responseText = ""; + xhr.status = 200; + // @ts-ignore + xhr.onreadystatechange?.(new Event("test")); + + return expect(upload.promise).rejects.toThrow("No response body."); + }); + + it("should error on a 400-code", () => { + const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); + upload = api.uploadContent({} as File); + + xhr.readyState = DONE; + xhr.responseText = '{"errcode": "M_NOT_FOUND", "error": "Not found"}'; + xhr.status = 404; + mocked(xhr.getResponseHeader).mockReturnValue("application/json"); + // @ts-ignore + xhr.onreadystatechange?.(new Event("test")); + + return expect(upload.promise).rejects.toThrow("Not found"); + }); }); From 01387304cc29a48efb4d7e4b5a7b42fa0f1ba257 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 5 Oct 2022 11:25:43 +0100 Subject: [PATCH 25/38] Please hit 80% --- .../http-api/__snapshots__/index.spec.ts.snap | 11 +++++ spec/unit/http-api/fetch.spec.ts | 25 +++++++++- spec/unit/http-api/index.spec.ts | 49 +++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 spec/unit/http-api/__snapshots__/index.spec.ts.snap diff --git a/spec/unit/http-api/__snapshots__/index.spec.ts.snap b/spec/unit/http-api/__snapshots__/index.spec.ts.snap new file mode 100644 index 00000000000..e6487ddeb0f --- /dev/null +++ b/spec/unit/http-api/__snapshots__/index.spec.ts.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MatrixHttpApi should return expected object from \`getContentUri\` 1`] = ` +{ + "base": "http://baseUrl", + "params": { + "access_token": "token", + }, + "path": "/_matrix/media/r0/upload", +} +`; diff --git a/spec/unit/http-api/fetch.spec.ts b/spec/unit/http-api/fetch.spec.ts index 13d937daa30..e100f2d9387 100644 --- a/spec/unit/http-api/fetch.spec.ts +++ b/spec/unit/http-api/fetch.spec.ts @@ -16,7 +16,8 @@ limitations under the License. import { FetchHttpApi } from "../../../src/http-api/fetch"; import { TypedEventEmitter } from "../../../src/models/typed-event-emitter"; -import { ClientPrefix, IdentityPrefix, IHttpOpts, Method } from "../../../src"; +import { ClientPrefix, HttpApiEvent, HttpApiEventHandlerMap, IdentityPrefix, IHttpOpts, Method } from "../../../src"; +import { emitPromise } from "../../test-utils/test-utils"; describe("FetchHttpApi", () => { const baseUrl = "http://baseUrl"; @@ -197,4 +198,26 @@ describe("FetchHttpApi", () => { }); expect(fetchFn.mock.calls[0][1].headers["Accept"]).toBe("text/html"); }); + + it("should emit NoConsent when given errcode=M_CONTENT_NOT_GIVEN", async () => { + const fetchFn = jest.fn().mockResolvedValue({ + ok: false, + headers: { + get(name: string): string | null { + return name === "Content-Type" ? "application/json" : null; + }, + }, + text: jest.fn().mockResolvedValue(JSON.stringify({ + errcode: "M_CONSENT_NOT_GIVEN", + error: "Ye shall ask for consent", + })), + }); + const emitter = new TypedEventEmitter(); + const api = new FetchHttpApi(emitter, { baseUrl, prefix, fetchFn }); + + await Promise.all([ + emitPromise(emitter, HttpApiEvent.NoConsent), + expect(api.authedRequest(Method.Get, "/path")).rejects.toThrow("Ye shall ask for consent"), + ]); + }); }); diff --git a/spec/unit/http-api/index.spec.ts b/spec/unit/http-api/index.spec.ts index 080b4ecc98f..291dccfd228 100644 --- a/spec/unit/http-api/index.spec.ts +++ b/spec/unit/http-api/index.spec.ts @@ -176,4 +176,53 @@ describe("MatrixHttpApi", () => { return expect(upload.promise).rejects.toThrow("Not found"); }); + + it("should return response on successful upload", () => { + const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); + upload = api.uploadContent({} as File); + + xhr.readyState = DONE; + xhr.responseText = '{"content_uri": "mxc://server/foobar"}'; + xhr.status = 200; + mocked(xhr.getResponseHeader).mockReturnValue("application/json"); + // @ts-ignore + xhr.onreadystatechange?.(new Event("test")); + + return expect(upload.promise).resolves.toStrictEqual({ content_uri: "mxc://server/foobar" }); + }); + + it("should abort xhr when calling `cancelUpload`", () => { + const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); + upload = api.uploadContent({} as File); + expect(api.cancelUpload(upload)).toBeTruthy(); + expect(xhr.abort).toHaveBeenCalled(); + }); + + it("should return false when `cancelUpload` is called but unsuccessful", async () => { + const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); + upload = api.uploadContent({} as File); + + xhr.readyState = DONE; + xhr.status = 500; + mocked(xhr.getResponseHeader).mockReturnValue("application/json"); + // @ts-ignore + xhr.onreadystatechange?.(new Event("test")); + await upload.promise.catch(() => {}); + + expect(api.cancelUpload(upload)).toBeFalsy(); + expect(xhr.abort).not.toHaveBeenCalled(); + }); + + it("should return active uploads in `getCurrentUploads`", () => { + const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); + upload = api.uploadContent({} as File); + expect(api.getCurrentUploads()).toContain(upload); + api.cancelUpload(upload); + expect(api.getCurrentUploads()).not.toContain(upload); + }); + + it("should return expected object from `getContentUri`", () => { + const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix, accessToken: "token" }); + expect(api.getContentUri()).toMatchSnapshot(); + }); }); From fc2c7224ecf1444e025aff3ec0546b3af3a3123d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 5 Oct 2022 11:56:18 +0100 Subject: [PATCH 26/38] Additional coverage --- spec/unit/autodiscovery.spec.ts | 81 ++++++++++++++++++++++++++++++--- spec/unit/utils.spec.ts | 10 ++++ 2 files changed, 85 insertions(+), 6 deletions(-) diff --git a/spec/unit/autodiscovery.spec.ts b/spec/unit/autodiscovery.spec.ts index 38058c93cc7..13688c25b25 100644 --- a/spec/unit/autodiscovery.spec.ts +++ b/spec/unit/autodiscovery.spec.ts @@ -175,8 +175,7 @@ describe("AutoDiscovery", function() { ]); }); - it("should return FAIL_PROMPT when .well-known does not have a base_url for " + - "m.homeserver (empty string)", function() { + it("should return FAIL_PROMPT when .well-known does not have a base_url for m.homeserver (empty string)", () => { const httpBackend = getHttpBackend(); httpBackend.when("GET", "/.well-known/matrix/client").respond(200, { "m.homeserver": { @@ -204,8 +203,7 @@ describe("AutoDiscovery", function() { ]); }); - it("should return FAIL_PROMPT when .well-known does not have a base_url for " + - "m.homeserver (no property)", function() { + it("should return FAIL_PROMPT when .well-known does not have a base_url for m.homeserver (no property)", () => { const httpBackend = getHttpBackend(); httpBackend.when("GET", "/.well-known/matrix/client").respond(200, { "m.homeserver": {}, @@ -231,8 +229,7 @@ describe("AutoDiscovery", function() { ]); }); - it("should return FAIL_ERROR when .well-known has an invalid base_url for " + - "m.homeserver (disallowed scheme)", function() { + it("should return FAIL_ERROR when .well-known has an invalid base_url for m.homeserver (disallowed scheme)", () => { const httpBackend = getHttpBackend(); httpBackend.when("GET", "/.well-known/matrix/client").respond(200, { "m.homeserver": { @@ -678,4 +675,76 @@ describe("AutoDiscovery", function() { }), ]); }); + + it("should return FAIL_PROMPT for connection errors", () => { + const httpBackend = getHttpBackend(); + httpBackend.when("GET", "/.well-known/matrix/client").fail(0, undefined); + return Promise.all([ + httpBackend.flushAllExpected(), + AutoDiscovery.findClientConfig("example.org").then((conf) => { + const expected = { + "m.homeserver": { + state: "FAIL_PROMPT", + error: AutoDiscovery.ERROR_INVALID, + base_url: null, + }, + "m.identity_server": { + state: "PROMPT", + error: null, + base_url: null, + }, + }; + + expect(conf).toEqual(expected); + }), + ]); + }); + + it("should return FAIL_PROMPT for fetch errors", () => { + const httpBackend = getHttpBackend(); + httpBackend.when("GET", "/.well-known/matrix/client").fail(0, new Error("CORS or something")); + return Promise.all([ + httpBackend.flushAllExpected(), + AutoDiscovery.findClientConfig("example.org").then((conf) => { + const expected = { + "m.homeserver": { + state: "FAIL_PROMPT", + error: AutoDiscovery.ERROR_INVALID, + base_url: null, + }, + "m.identity_server": { + state: "PROMPT", + error: null, + base_url: null, + }, + }; + + expect(conf).toEqual(expected); + }), + ]); + }); + + it("should return FAIL_PROMPT for invalid JSON", () => { + const httpBackend = getHttpBackend(); + httpBackend.when("GET", "/.well-known/matrix/client").respond(200, "", true); + return Promise.all([ + httpBackend.flushAllExpected(), + AutoDiscovery.findClientConfig("example.org").then((conf) => { + const expected = { + "m.homeserver": { + state: "FAIL_PROMPT", + error: AutoDiscovery.ERROR_INVALID, + base_url: null, + }, + "m.identity_server": { + state: "PROMPT", + error: null, + base_url: null, + }, + }; + + expect(conf).toEqual(expected); + }), + ]); + }); }); diff --git a/spec/unit/utils.spec.ts b/spec/unit/utils.spec.ts index d9d8b819dde..1b11f2a7cd3 100644 --- a/spec/unit/utils.spec.ts +++ b/spec/unit/utils.spec.ts @@ -46,6 +46,16 @@ describe("utils", function() { }); }); + describe("decodeParams", () => { + it("should be able to decode multiple values into an array", () => { + const params = "foo=bar&via=a&via=b&via=c"; + expect(utils.decodeParams(params)).toEqual({ + foo: "bar", + via: ["a", "b", "c"], + }); + }); + }); + describe("encodeUri", function() { it("should replace based on object keys and url encode", function() { const path = "foo/bar/%something/%here"; From abc68e788251f79aceb0ab09815088c69b09d157 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 5 Oct 2022 13:25:09 +0100 Subject: [PATCH 27/38] Remove browser-request some more --- src/scheduler.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/scheduler.ts b/src/scheduler.ts index 271982b745a..2131e95c253 100644 --- a/src/scheduler.ts +++ b/src/scheduler.ts @@ -24,7 +24,7 @@ import { logger } from './logger'; import { MatrixEvent } from "./models/event"; import { EventType } from "./@types/event"; import { IDeferred } from "./utils"; -import { MatrixError } from "./http-api"; +import { ConnectionError, MatrixError } from "./http-api"; import { ISendEventResponse } from "./@types/requests"; const DEBUG = false; // set true to enable console logging. @@ -68,9 +68,7 @@ export class MatrixScheduler { // client error; no amount of retrying with save you now. return -1; } - // we ship with browser-request which returns { cors: rejected } when trying - // with no connection, so if we match that, give up since they have no conn. - if (err["cors"] === "rejected") { + if (err instanceof ConnectionError) { return -1; } From ac43f33330586610dfa4319811b683ae57c134e6 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 5 Oct 2022 14:15:22 +0100 Subject: [PATCH 28/38] Yet more tests --- package.json | 3 ++ spec/integ/matrix-client-methods.spec.js | 45 +++++++++++++++++++++++- spec/setupTests.ts | 19 ++++++++++ src/http-api/fetch.ts | 3 ++ src/http-api/index.ts | 7 +++- src/scheduler.ts | 2 ++ src/sliding-sync.ts | 6 ++-- 7 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 spec/setupTests.ts diff --git a/package.json b/package.json index cec9b3e1b29..132ff578736 100644 --- a/package.json +++ b/package.json @@ -114,6 +114,9 @@ "testMatch": [ "/spec/**/*.spec.{js,ts}" ], + "setupFilesAfterEnv": [ + "/spec/setupTests.ts" + ], "collectCoverageFrom": [ "/src/**/*.{js,ts}" ], diff --git a/spec/integ/matrix-client-methods.spec.js b/spec/integ/matrix-client-methods.spec.js index 1943ed5962a..ce484d2b473 100644 --- a/spec/integ/matrix-client-methods.spec.js +++ b/spec/integ/matrix-client-methods.spec.js @@ -17,7 +17,7 @@ limitations under the License. import * as utils from "../test-utils/test-utils"; import { CRYPTO_ENABLED } from "../../src/client"; import { MatrixEvent } from "../../src/models/event"; -import { Filter, MemoryStore, Room } from "../../src/matrix"; +import { ConnectionError, Filter, MemoryStore, Method, Room } from "../../src/matrix"; import { TestClient } from "../TestClient"; import { THREAD_RELATION_TYPE } from "../../src/models/thread"; @@ -1060,6 +1060,49 @@ describe("MatrixClient", function() { expect(await prom).toStrictEqual(response); }); }); + + describe("logout", () => { + it("should abort pending requests when called with stopClient=true", async () => { + httpBackend.when("POST", "/logout").respond(200, {}); + const fn = jest.fn(); + client.http.request(Method.Get, "/test").catch(fn); + client.logout(true); + await httpBackend.flush(); + expect(fn).toHaveBeenCalled(); + }); + }); + + describe("sendHtmlEmote", () => { + it("should send valid html emote", async () => { + httpBackend.when("PUT", "/send").check(req => { + expect(req.data).toStrictEqual({ + "msgtype": "m.emote", + "body": "Body", + "formatted_body": "

Body

", + "format": "org.matrix.custom.html", + "org.matrix.msc1767.message": expect.anything(), + }); + }).respond(200, { event_id: "$foobar" }); + const prom = client.sendHtmlEmote("!room:server", "Body", "

Body

"); + await httpBackend.flush(); + await expect(prom).resolves.toStrictEqual({ event_id: "$foobar" }); + }); + }); + + describe("forget", () => { + it("should remove from store by default", async () => { + const room = new Room("!roomId:server", client, userId); + client.store.storeRoom(room); + expect(client.store.getRooms()).toContain(room); + + httpBackend.when("POST", "/forget").respond(200, {}); + await Promise.all([ + client.forget(room.roomId), + httpBackend.flushAllExpected(), + ]); + expect(client.store.getRooms()).not.toContain(room); + }); + }); }); function withThreadId(event, newThreadId) { diff --git a/spec/setupTests.ts b/spec/setupTests.ts new file mode 100644 index 00000000000..bbd70fe3d97 --- /dev/null +++ b/spec/setupTests.ts @@ -0,0 +1,19 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import DOMException from "domexception"; + +global.DOMException = DOMException; diff --git a/src/http-api/fetch.ts b/src/http-api/fetch.ts index 83a5e9565bf..60c4d9f86df 100644 --- a/src/http-api/fetch.ts +++ b/src/http-api/fetch.ts @@ -285,6 +285,9 @@ export class FetchHttpApi { credentials: "omit", // we send credentials via headers }); } catch (e) { + if (e.name === "AbortError") { + throw e; + } throw new ConnectionError("fetch failed", e); } finally { cleanup(); diff --git a/src/http-api/index.ts b/src/http-api/index.ts index 75872b476ac..533ba929c9e 100644 --- a/src/http-api/index.ts +++ b/src/http-api/index.ts @@ -112,6 +112,11 @@ export class MatrixHttpApi extends FetchHttpApi { defer.resolve(JSON.parse(xhr.responseText)); } } catch (err) { + if (err.name === "AbortError") { + defer.reject(err); + return; + } + (err).httpStatus = xhr.status; defer.reject(new ConnectionError("request failed", err)); } @@ -175,7 +180,7 @@ export class MatrixHttpApi extends FetchHttpApi { }); abortController.signal.addEventListener("abort", () => { utils.removeElement(this.uploads, elem => elem === upload); - defer.reject(new Error("Aborted")); + defer.reject(new DOMException("Aborted", "AbortError")); }); this.uploads.push(upload); diff --git a/src/scheduler.ts b/src/scheduler.ts index 2131e95c253..d4c69af5906 100644 --- a/src/scheduler.ts +++ b/src/scheduler.ts @@ -68,6 +68,8 @@ export class MatrixScheduler { // client error; no amount of retrying with save you now. return -1; } + // we ship with browser-request which returns { cors: rejected } when trying + // with no connection, so if we match that, give up since they have no conn. if (err instanceof ConnectionError) { return -1; } diff --git a/src/sliding-sync.ts b/src/sliding-sync.ts index 8918ab4ab1a..5297ebd14b4 100644 --- a/src/sliding-sync.ts +++ b/src/sliding-sync.ts @@ -19,6 +19,7 @@ import { MatrixClient } from "./client"; import { IRoomEvent, IStateEvent } from "./sync-accumulator"; import { TypedEventEmitter } from "./models/typed-event-emitter"; import { sleep, IDeferred, defer } from "./utils"; +import { ConnectionError } from "./http-api"; // /sync requests allow you to set a timeout= but the request may continue // beyond that and wedge forever, so we need to track how long we are willing @@ -824,10 +825,7 @@ export class SlidingSync extends TypedEventEmitter Date: Wed, 5 Oct 2022 14:22:55 +0100 Subject: [PATCH 29/38] Iterate --- package.json | 2 +- spec/integ/matrix-client-methods.spec.js | 2 +- yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 132ff578736..e027d089c47 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "jest-mock": "^27.5.1", "jest-sonar-reporter": "^2.0.0", "jsdoc": "^3.6.6", - "matrix-mock-request": "^2.4.1", + "matrix-mock-request": "^2.5.0", "rimraf": "^3.0.2", "terser": "^5.5.1", "tsify": "^5.0.2", diff --git a/spec/integ/matrix-client-methods.spec.js b/spec/integ/matrix-client-methods.spec.js index ce484d2b473..1b737f41051 100644 --- a/spec/integ/matrix-client-methods.spec.js +++ b/spec/integ/matrix-client-methods.spec.js @@ -17,7 +17,7 @@ limitations under the License. import * as utils from "../test-utils/test-utils"; import { CRYPTO_ENABLED } from "../../src/client"; import { MatrixEvent } from "../../src/models/event"; -import { ConnectionError, Filter, MemoryStore, Method, Room } from "../../src/matrix"; +import { Filter, MemoryStore, Method, Room } from "../../src/matrix"; import { TestClient } from "../TestClient"; import { THREAD_RELATION_TYPE } from "../../src/models/thread"; diff --git a/yarn.lock b/yarn.lock index c7d33a83e6c..eb59f97feb9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4855,10 +4855,10 @@ matrix-events-sdk@^0.0.1-beta.7: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1-beta.7.tgz#5ffe45eba1f67cc8d7c2377736c728b322524934" integrity sha512-9jl4wtWanUFSy2sr2lCjErN/oC8KTAtaeaozJtrgot1JiQcEI4Rda9OLgQ7nLKaqb4Z/QUx/fR3XpDzm5Jy1JA== -matrix-mock-request@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/matrix-mock-request/-/matrix-mock-request-2.4.1.tgz#a9c7dbb6b466f582ba2ca21f17cf18ceb41c7657" - integrity sha512-QMNpKUeHS2RHovSKybUySFTXTJ11EQPkp3bgvEXmNqAc3TYM23gKYqgI288BoBDYwQrK3WJFT0d4bvMiNIS/vA== +matrix-mock-request@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/matrix-mock-request/-/matrix-mock-request-2.5.0.tgz#78da2590e82be2e31edcf9814833af5e5f8d2f1a" + integrity sha512-7T3gklpW+4rfHsTnp/FDML7aWoBrXhAh8+1ltinQfAh9TDj6y382z/RUMR7i03d1WDzt/ed1UTihqO5GDoOq9Q== dependencies: expect "^28.1.0" From 50cb85437effb25bd78e3e7a3c0faead34bb96d9 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 5 Oct 2022 14:55:09 +0100 Subject: [PATCH 30/38] Stash --- src/scheduler.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/scheduler.ts b/src/scheduler.ts index d4c69af5906..2131e95c253 100644 --- a/src/scheduler.ts +++ b/src/scheduler.ts @@ -68,8 +68,6 @@ export class MatrixScheduler { // client error; no amount of retrying with save you now. return -1; } - // we ship with browser-request which returns { cors: rejected } when trying - // with no connection, so if we match that, give up since they have no conn. if (err instanceof ConnectionError) { return -1; } From ffd26bd287503ddc31b682c4e89be5c1b4a526fb Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 6 Oct 2022 10:46:42 +0100 Subject: [PATCH 31/38] Write moar tests --- spec/integ/matrix-client-methods.spec.ts | 59 ++++++++++++++++++++---- spec/integ/matrix-client-opts.spec.ts | 5 +- src/client.ts | 4 +- 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/spec/integ/matrix-client-methods.spec.ts b/spec/integ/matrix-client-methods.spec.ts index e1789a1388b..901405423de 100644 --- a/spec/integ/matrix-client-methods.spec.ts +++ b/spec/integ/matrix-client-methods.spec.ts @@ -22,7 +22,6 @@ import { Filter, MemoryStore, Method, Room } from "../../src/matrix"; import { TestClient } from "../TestClient"; import { THREAD_RELATION_TYPE } from "../../src/models/thread"; import { IFilterDefinition } from "../../src/filter"; -import { FileType } from "../../src/http-api"; import { ISearchResults } from "../../src/@types/search"; import { IStore } from "../../src/store"; @@ -163,6 +162,30 @@ describe("MatrixClient", function() { client!.joinRoom(roomId); httpBackend!.verifyNoOutstandingRequests(); }); + + it("should send request to inviteSignUrl if specified", async () => { + const roomId = "!roomId:server"; + const inviteSignUrl = "https://id.server/sign/this/for/me"; + const viaServers = ["a", "b", "c"]; + const signature = { + sender: "sender", + mxid: "@sender:foo", + token: "token", + signatures: {}, + }; + + httpBackend!.when("POST", inviteSignUrl).respond(200, signature); + httpBackend!.when("POST", "/join/" + encodeURIComponent(roomId)).check(request => { + expect(request.data.third_party_signed).toEqual(signature); + }).respond(200, { room_id: roomId }); + + const prom = client.joinRoom(roomId, { + inviteSignUrl, + viaServers, + }); + await httpBackend!.flushAllExpected(); + expect((await prom).roomId).toBe(roomId); + }); }); describe("getFilter", function() { @@ -637,7 +660,7 @@ describe("MatrixClient", function() { // The vote event has been copied into the thread const eventRefWithThreadId = withThreadId( eventPollResponseReference, eventPollStartThreadRoot.getId()); - expect(eventRefWithThreadId.threadId).toBeTruthy(); + expect(eventRefWithThreadId.threadRootId).toBeTruthy(); expect(threaded).toEqual([ eventPollStartThreadRoot, @@ -1146,7 +1169,7 @@ describe("MatrixClient", function() { const fn = jest.fn(); client.http.request(Method.Get, "/test").catch(fn); client.logout(true); - await httpBackend.flush(); + await httpBackend.flush(undefined); expect(fn).toHaveBeenCalled(); }); }); @@ -1163,7 +1186,7 @@ describe("MatrixClient", function() { }); }).respond(200, { event_id: "$foobar" }); const prom = client.sendHtmlEmote("!room:server", "Body", "

Body

"); - await httpBackend.flush(); + await httpBackend.flush(undefined); await expect(prom).resolves.toStrictEqual({ event_id: "$foobar" }); }); }); @@ -1182,15 +1205,31 @@ describe("MatrixClient", function() { expect(client.store.getRooms()).not.toContain(room); }); }); + + describe("getCapabilities", () => { + it("should cache by default", async () => { + httpBackend!.when("GET", "/capabilities").respond(200, { + capabilities: { + "m.change_password": false, + }, + }); + const prom = httpBackend!.flushAllExpected(); + const capabilities1 = await client!.getCapabilities(); + const capabilities2 = await client!.getCapabilities(); + await prom; + + expect(capabilities1).toStrictEqual(capabilities2); + }); + }); }); -function withThreadId(event, newThreadId) { +function withThreadId(event: MatrixEvent, newThreadId: string): MatrixEvent { const ret = event.toSnapshot(); ret.setThreadId(newThreadId); return ret; } -const buildEventMessageInThread = (root) => new MatrixEvent({ +const buildEventMessageInThread = (root: MatrixEvent) => new MatrixEvent({ "age": 80098509, "content": { "algorithm": "m.megolm.v1.aes-sha2", @@ -1237,7 +1276,7 @@ const buildEventPollResponseReference = () => new MatrixEvent({ "user_id": "@andybalaam-test1:matrix.org", }); -const buildEventReaction = (event) => new MatrixEvent({ +const buildEventReaction = (event: MatrixEvent) => new MatrixEvent({ "content": { "m.relates_to": { "event_id": event.getId(), @@ -1256,7 +1295,7 @@ const buildEventReaction = (event) => new MatrixEvent({ "room_id": "!STrMRsukXHtqQdSeHa:matrix.org", }); -const buildEventRedaction = (event) => new MatrixEvent({ +const buildEventRedaction = (event: MatrixEvent) => new MatrixEvent({ "content": { }, @@ -1290,7 +1329,7 @@ const buildEventPollStartThreadRoot = () => new MatrixEvent({ "user_id": "@andybalaam-test1:matrix.org", }); -const buildEventReply = (target) => new MatrixEvent({ +const buildEventReply = (target: MatrixEvent) => new MatrixEvent({ "age": 80098509, "content": { "algorithm": "m.megolm.v1.aes-sha2", @@ -1456,7 +1495,7 @@ const buildEventCreate = () => new MatrixEvent({ "user_id": "@andybalaam-test1:matrix.org", }); -function assertObjectContains(obj, expected) { +function assertObjectContains(obj: object, expected: any): void { for (const k in expected) { if (expected.hasOwnProperty(k)) { expect(obj[k]).toEqual(expected[k]); diff --git a/spec/integ/matrix-client-opts.spec.ts b/spec/integ/matrix-client-opts.spec.ts index 6417559a0f8..5ea4fba7718 100644 --- a/spec/integ/matrix-client-opts.spec.ts +++ b/spec/integ/matrix-client-opts.spec.ts @@ -5,7 +5,6 @@ import { MatrixClient } from "../../src/matrix"; import { MatrixScheduler } from "../../src/scheduler"; import { MemoryStore } from "../../src/store/memory"; import { MatrixError } from "../../src/http-api"; -import { ICreateClientOpts } from "../../src/client"; import { IStore } from "../../src/store"; describe("MatrixClient opts", function() { @@ -69,7 +68,7 @@ describe("MatrixClient opts", function() { let client; beforeEach(function() { client = new MatrixClient({ - fetchFn: httpBackend.fetchFn, + fetchFn: httpBackend.fetchFn as typeof global.fetch, store: undefined, baseUrl: baseUrl, userId: userId, @@ -129,7 +128,7 @@ describe("MatrixClient opts", function() { let client; beforeEach(function() { client = new MatrixClient({ - fetchFn: httpBackend.fetchFn, + fetchFn: httpBackend.fetchFn as typeof global.fetch, store: new MemoryStore() as IStore, baseUrl: baseUrl, userId: userId, diff --git a/src/client.ts b/src/client.ts index 9f5408830f4..5bdd535124f 100644 --- a/src/client.ts +++ b/src/client.ts @@ -2248,7 +2248,7 @@ export class MatrixClient extends TypedEventEmitter} Resolves to the number of sessions requiring backup + * @returns {Promise} Resolves to the number of sessions requiring backup */ public countSessionsNeedingBackup(): Promise { if (!this.crypto) { @@ -2933,7 +2933,7 @@ export class MatrixClient extends TypedEventEmitter} Resolves to the number of sessions requiring a backup. + * @returns {Promise} Resolves to the number of sessions requiring a backup. */ public flagAllGroupSessionsForBackup(): Promise { if (!this.crypto) { From 52345e274a1a0cdb599c7eb05c01c5454ea16a92 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 6 Oct 2022 11:18:12 +0100 Subject: [PATCH 32/38] Additional coverage --- spec/integ/matrix-client-methods.spec.ts | 61 +++++++++++++++++++++++- spec/unit/read-receipt.spec.ts | 18 +++++++ src/client.ts | 19 ++++---- 3 files changed, 85 insertions(+), 13 deletions(-) diff --git a/spec/integ/matrix-client-methods.spec.ts b/spec/integ/matrix-client-methods.spec.ts index 901405423de..f53e80fbf9f 100644 --- a/spec/integ/matrix-client-methods.spec.ts +++ b/spec/integ/matrix-client-methods.spec.ts @@ -16,9 +16,9 @@ limitations under the License. import HttpBackend from "matrix-mock-request"; import * as utils from "../test-utils/test-utils"; -import { CRYPTO_ENABLED, MatrixClient, IStoredClientOpts } from "../../src/client"; +import { CRYPTO_ENABLED, IStoredClientOpts, MatrixClient } from "../../src/client"; import { MatrixEvent } from "../../src/models/event"; -import { Filter, MemoryStore, Method, Room } from "../../src/matrix"; +import { Filter, MemoryStore, Method, Room, SERVICE_TYPES } from "../../src/matrix"; import { TestClient } from "../TestClient"; import { THREAD_RELATION_TYPE } from "../../src/models/thread"; import { IFilterDefinition } from "../../src/filter"; @@ -1191,6 +1191,23 @@ describe("MatrixClient", function() { }); }); + describe("sendHtmlMessage", () => { + it("should send valid html message", async () => { + httpBackend.when("PUT", "/send").check(req => { + expect(req.data).toStrictEqual({ + "msgtype": "m.text", + "body": "Body", + "formatted_body": "

Body

", + "format": "org.matrix.custom.html", + "org.matrix.msc1767.message": expect.anything(), + }); + }).respond(200, { event_id: "$foobar" }); + const prom = client.sendHtmlMessage("!room:server", "Body", "

Body

"); + await httpBackend.flush(undefined); + await expect(prom).resolves.toStrictEqual({ event_id: "$foobar" }); + }); + }); + describe("forget", () => { it("should remove from store by default", async () => { const room = new Room("!roomId:server", client, userId); @@ -1221,6 +1238,46 @@ describe("MatrixClient", function() { expect(capabilities1).toStrictEqual(capabilities2); }); }); + + describe("getTerms", () => { + it("should return Identity Server terms", async () => { + httpBackend!.when("GET", "/terms").respond(200, { foo: "bar" }); + const prom = client!.getTerms(SERVICE_TYPES.IS, "http://identity.server"); + await httpBackend!.flushAllExpected(); + await expect(prom).resolves.toEqual({ foo: "bar" }); + }); + + it("should return Integrations Manager terms", async () => { + httpBackend!.when("GET", "/terms").respond(200, { foo: "bar" }); + const prom = client!.getTerms(SERVICE_TYPES.IM, "http://im.server"); + await httpBackend!.flushAllExpected(); + await expect(prom).resolves.toEqual({ foo: "bar" }); + }); + }); + + describe("publicRooms", () => { + it("should use GET request if no server or filter is specified", () => { + httpBackend!.when("GET", "/publicRooms").respond(200, {}); + client!.publicRooms({}); + return httpBackend!.flushAllExpected(); + }); + + it("should use GET request if only server is specified", () => { + httpBackend!.when("GET", "/publicRooms").check(request => { + expect(request.queryParams.server).toBe("server1"); + }).respond(200, {}); + client!.publicRooms({ server: "server1" }); + return httpBackend!.flushAllExpected(); + }); + + it("should use POST request if filter is specified", () => { + httpBackend!.when("POST", "/publicRooms").check(request => { + expect(request.data.filter.generic_search_term).toBe("foobar"); + }).respond(200, {}); + client!.publicRooms({ filter: { generic_search_term: "foobar" } }); + return httpBackend!.flushAllExpected(); + }); + }); }); function withThreadId(event: MatrixEvent, newThreadId: string): MatrixEvent { diff --git a/spec/unit/read-receipt.spec.ts b/spec/unit/read-receipt.spec.ts index f5345ca558f..07acaa184dd 100644 --- a/spec/unit/read-receipt.spec.ts +++ b/spec/unit/read-receipt.spec.ts @@ -145,5 +145,23 @@ describe("Read receipt", () => { await httpBackend.flushAllExpected(); await flushPromises(); }); + + it("sends a valid room read receipt even when body omitted", async () => { + httpBackend.when( + "POST", encodeUri("/rooms/$roomId/receipt/$receiptType/$eventId", { + $roomId: ROOM_ID, + $receiptType: ReceiptType.Read, + $eventId: threadEvent.getId(), + }), + ).check((request) => { + expect(request.data).toEqual({}); + }).respond(200, {}); + + mockServerSideSupport(client, false); + client.sendReceipt(threadEvent, ReceiptType.Read, undefined); + + await httpBackend.flushAllExpected(); + await flushPromises(); + }); }); }); diff --git a/src/client.ts b/src/client.ts index 5bdd535124f..aa402dbcb83 100644 --- a/src/client.ts +++ b/src/client.ts @@ -36,7 +36,7 @@ import { CallEvent, CallEventHandlerMap, createNewMatrixCall, MatrixCall, suppor import { Filter, IFilterDefinition, IRoomEventFilter } from "./filter"; import { CallEventHandlerEvent, CallEventHandler, CallEventHandlerEventHandlerMap } from './webrtc/callEventHandler'; import * as utils from './utils'; -import { sleep } from './utils'; +import { QueryDict, sleep } from './utils'; import { Direction, EventTimeline } from "./models/event-timeline"; import { IActionsObject, PushProcessor } from "./pushprocessor"; import { AutoDiscovery, AutoDiscoveryAction } from "./autodiscovery"; @@ -7514,18 +7514,15 @@ export class MatrixClient extends TypedEventEmitter { - const queryParams: any = {}; - if (options.server) { - queryParams.server = options.server; - delete options.server; - } - - if (Object.keys(options).length === 0 && Object.keys(queryParams).length === 0) { - return this.http.authedRequest(Method.Get, "/publicRooms"); + public publicRooms( + { server, limit, since, ...options }: IRoomDirectoryOptions = {}, + ): Promise { + const queryParams: QueryDict = { server, limit, since }; + if (Object.keys(options).length === 0) { + return this.http.authedRequest(Method.Get, "/publicRooms", queryParams); } else { return this.http.authedRequest(Method.Post, "/publicRooms", queryParams, options); } From 511afeeae8b7e275af8fe9f720478fde7edb34ff Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 6 Oct 2022 11:27:59 +0100 Subject: [PATCH 33/38] Update README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c1721e11b70..cb3b9f8110e 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ In Node.js ---------- Ensure you have the latest LTS version of Node.js installed. +This library relies on `fetch` which is available in Node from v18.0.0 - it should work fine also with polyfills. +If you wish to use a ponyfill or adapter of some sort then pass it as `fetchFn` to the MatrixClient constructor options. Using `yarn` instead of `npm` is recommended. Please see the Yarn [install guide](https://classic.yarnpkg.com/en/docs/install) if you do not have it already. From b57651d4040f44394dafe843430b6ee214aecf9e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 6 Oct 2022 11:30:31 +0100 Subject: [PATCH 34/38] Update types --- src/@types/global.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 679a6afba6e..6b512434902 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -30,6 +30,8 @@ declare global { namespace NodeJS { interface Global { localStorage: Storage; + // marker variable used to detect both the browser & node entrypoints being used at once + __js_sdk_entrypoint: unknown; } } From 88bbeb2378cce7c6b15386f5dd7b0dc4a12989d4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 6 Oct 2022 11:57:16 +0100 Subject: [PATCH 35/38] Fix login method --- spec/integ/matrix-client-methods.spec.ts | 19 +++++++++++++++++++ src/client.ts | 1 + 2 files changed, 20 insertions(+) diff --git a/spec/integ/matrix-client-methods.spec.ts b/spec/integ/matrix-client-methods.spec.ts index f53e80fbf9f..ba7e32a49cb 100644 --- a/spec/integ/matrix-client-methods.spec.ts +++ b/spec/integ/matrix-client-methods.spec.ts @@ -1278,6 +1278,25 @@ describe("MatrixClient", function() { return httpBackend!.flushAllExpected(); }); }); + + describe("login", () => { + it("should persist values to the client opts", async () => { + const token = "!token&"; + const userId = "@m:t"; + + httpBackend!.when("POST", "/login").respond(200, { + access_token: token, + user_id: userId, + }); + const prom = client!.login("fake.login", {}); + await httpBackend!.flushAllExpected(); + const resp = await prom; + expect(resp.access_token).toBe(token); + expect(resp.user_id).toBe(userId); + expect(client.getUserId()).toBe(userId); + expect(client.http.opts.accessToken).toBe(token); + }); + }); }); function withThreadId(event: MatrixEvent, newThreadId: string): MatrixEvent { diff --git a/src/client.ts b/src/client.ts index aa402dbcb83..fd8b483852a 100644 --- a/src/client.ts +++ b/src/client.ts @@ -7059,6 +7059,7 @@ export class MatrixClient extends TypedEventEmitter Date: Thu, 6 Oct 2022 13:20:49 +0100 Subject: [PATCH 36/38] Iterate everything --- src/autodiscovery.ts | 11 +++++++++-- src/http-api/fetch.ts | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/autodiscovery.ts b/src/autodiscovery.ts index e4e560e4a41..8bf87e5177e 100644 --- a/src/autodiscovery.ts +++ b/src/autodiscovery.ts @@ -394,10 +394,17 @@ export class AutoDiscovery { } } - private static fetch = global.fetch; + private static fetch(resource: URL | string, options?: RequestInit): ReturnType { + if (this.fetchFn) { + return this.fetchFn(resource, options); + } + return global.fetch(resource, options); + } + + private static fetchFn?: typeof global.fetch; public static setFetchFn(fetchFn: typeof global.fetch): void { - AutoDiscovery.fetch = fetchFn; + AutoDiscovery.fetchFn = fetchFn; } /** diff --git a/src/http-api/fetch.ts b/src/http-api/fetch.ts index 60c4d9f86df..4fecaaecf8d 100644 --- a/src/http-api/fetch.ts +++ b/src/http-api/fetch.ts @@ -238,7 +238,8 @@ export class FetchHttpApi { ): Promise> { const headers = Object.assign({}, opts.headers || {}); const json = opts.json ?? true; - const jsonBody = json && body && Object.getPrototypeOf(body) === Object.prototype; + // We can't use getPrototypeOf here as objects made in other contexts e.g. over postMessage won't have same ref + const jsonBody = json && body?.constructor?.name === Object.name; if (json) { if (jsonBody && !headers["Content-Type"]) { From 17fc2bd72a29fac19ae5af687bc11b9cad171f35 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 7 Oct 2022 15:59:06 +0100 Subject: [PATCH 37/38] Iterate uploadContent signature --- spec/integ/matrix-client-methods.spec.ts | 9 ++++----- spec/unit/http-api/index.spec.ts | 22 +++++++++++----------- spec/unit/models/MSC3089TreeSpace.spec.ts | 4 ++-- src/client.ts | 6 +++--- src/http-api/index.ts | 12 ++++++------ src/http-api/interface.ts | 1 + src/models/MSC3089TreeSpace.ts | 3 +-- 7 files changed, 28 insertions(+), 29 deletions(-) diff --git a/spec/integ/matrix-client-methods.spec.ts b/spec/integ/matrix-client-methods.spec.ts index ba7e32a49cb..5bec405cbdd 100644 --- a/spec/integ/matrix-client-methods.spec.ts +++ b/spec/integ/matrix-client-methods.spec.ts @@ -84,7 +84,7 @@ describe("MatrixClient", function() { expect(req.opts.timeout).toBe(undefined); }).respond(200, '{"content_uri": "content"}', true); - const prom = client!.uploadContent(file, opts).promise; + const prom = client!.uploadContent(file, opts); expect(prom).toBeTruthy(); @@ -116,7 +116,7 @@ describe("MatrixClient", function() { "error": "broken", }); - const prom = client!.uploadContent(file, opts).promise.then(function(response) { + const prom = client!.uploadContent(file, opts).then(function(response) { throw Error("request not failed"); }, function(error) { expect(error.httpStatus).toEqual(400); @@ -129,15 +129,14 @@ describe("MatrixClient", function() { }); it("should return a promise which can be cancelled", async () => { - const upload = client!.uploadContent(file, opts); - const prom = upload.promise; + const prom = client!.uploadContent(file, opts); const uploads = client!.getCurrentUploads(); expect(uploads.length).toEqual(1); expect(uploads[0].promise).toBe(prom); expect(uploads[0].loaded).toEqual(0); - const r = client!.cancelUpload(upload); + const r = client!.cancelUpload(prom); expect(r).toBe(true); await expect(prom).rejects.toThrow("Aborted"); expect(client.getCurrentUploads()).toHaveLength(0); diff --git a/spec/unit/http-api/index.spec.ts b/spec/unit/http-api/index.spec.ts index 291dccfd228..89e122452f6 100644 --- a/spec/unit/http-api/index.spec.ts +++ b/spec/unit/http-api/index.spec.ts @@ -17,7 +17,7 @@ limitations under the License. import DOMException from "domexception"; import { mocked } from "jest-mock"; -import { ClientPrefix, MatrixHttpApi, Method, Upload } from "../../../src"; +import { ClientPrefix, MatrixHttpApi, Method, UploadResponse } from "../../../src"; import { TypedEventEmitter } from "../../../src/models/typed-event-emitter"; type Writeable = { -readonly [P in keyof T]: T[P] }; @@ -29,7 +29,7 @@ describe("MatrixHttpApi", () => { const prefix = ClientPrefix.V3; let xhr: Partial>; - let upload: Upload; + let upload: Promise; const DONE = 0; @@ -53,7 +53,7 @@ describe("MatrixHttpApi", () => { }); afterEach(() => { - upload?.promise.catch(() => {}); + upload?.catch(() => {}); // Abort any remaining requests xhr.readyState = DONE; xhr.status = 0; @@ -117,9 +117,9 @@ describe("MatrixHttpApi", () => { it("should abort xhr when the upload is aborted", () => { const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); upload = api.uploadContent({} as File); - upload.abortController.abort(); + api.cancelUpload(upload); expect(xhr.abort).toHaveBeenCalled(); - return expect(upload.promise).rejects.toThrow("Aborted"); + return expect(upload).rejects.toThrow("Aborted"); }); it("should timeout if no progress in 30s", () => { @@ -160,7 +160,7 @@ describe("MatrixHttpApi", () => { // @ts-ignore xhr.onreadystatechange?.(new Event("test")); - return expect(upload.promise).rejects.toThrow("No response body."); + return expect(upload).rejects.toThrow("No response body."); }); it("should error on a 400-code", () => { @@ -174,7 +174,7 @@ describe("MatrixHttpApi", () => { // @ts-ignore xhr.onreadystatechange?.(new Event("test")); - return expect(upload.promise).rejects.toThrow("Not found"); + return expect(upload).rejects.toThrow("Not found"); }); it("should return response on successful upload", () => { @@ -188,7 +188,7 @@ describe("MatrixHttpApi", () => { // @ts-ignore xhr.onreadystatechange?.(new Event("test")); - return expect(upload.promise).resolves.toStrictEqual({ content_uri: "mxc://server/foobar" }); + return expect(upload).resolves.toStrictEqual({ content_uri: "mxc://server/foobar" }); }); it("should abort xhr when calling `cancelUpload`", () => { @@ -207,7 +207,7 @@ describe("MatrixHttpApi", () => { mocked(xhr.getResponseHeader).mockReturnValue("application/json"); // @ts-ignore xhr.onreadystatechange?.(new Event("test")); - await upload.promise.catch(() => {}); + await upload.catch(() => {}); expect(api.cancelUpload(upload)).toBeFalsy(); expect(xhr.abort).not.toHaveBeenCalled(); @@ -216,9 +216,9 @@ describe("MatrixHttpApi", () => { it("should return active uploads in `getCurrentUploads`", () => { const api = new MatrixHttpApi(new TypedEventEmitter(), { baseUrl, prefix }); upload = api.uploadContent({} as File); - expect(api.getCurrentUploads()).toContain(upload); + expect(api.getCurrentUploads().find(u => u.promise === upload)).toBeTruthy(); api.cancelUpload(upload); - expect(api.getCurrentUploads()).not.toContain(upload); + expect(api.getCurrentUploads().find(u => u.promise === upload)).toBeFalsy(); }); it("should return expected object from `getContentUri`", () => { diff --git a/spec/unit/models/MSC3089TreeSpace.spec.ts b/spec/unit/models/MSC3089TreeSpace.spec.ts index 2e72d44be8a..ef099fede78 100644 --- a/spec/unit/models/MSC3089TreeSpace.spec.ts +++ b/spec/unit/models/MSC3089TreeSpace.spec.ts @@ -891,7 +891,7 @@ describe("MSC3089TreeSpace", () => { expect(opts).toMatchObject({ includeFilename: false, }); - return { promise: Promise.resolve({ content_uri: mxc }) }; + return Promise.resolve({ content_uri: mxc }); }); client.uploadContent = uploadFn; @@ -950,7 +950,7 @@ describe("MSC3089TreeSpace", () => { expect(opts).toMatchObject({ includeFilename: false, }); - return { promise: Promise.resolve({ content_uri: mxc }) }; + return Promise.resolve({ content_uri: mxc }); }); client.uploadContent = uploadFn; diff --git a/src/client.ts b/src/client.ts index fd8b483852a..07e26c7ab39 100644 --- a/src/client.ts +++ b/src/client.ts @@ -59,7 +59,7 @@ import { retryNetworkOperation, ClientPrefix, MediaPrefix, - IdentityPrefix, IHttpOpts, FileType, + IdentityPrefix, IHttpOpts, FileType, UploadResponse, } from "./http-api"; import { Crypto, @@ -7710,7 +7710,7 @@ export class MatrixClient extends TypedEventEmitter { return this.http.uploadContent(file, opts); } @@ -7719,7 +7719,7 @@ export class MatrixClient extends TypedEventEmitter): boolean { return this.http.cancelUpload(upload); } diff --git a/src/http-api/index.ts b/src/http-api/index.ts index 533ba929c9e..62e4b478e4a 100644 --- a/src/http-api/index.ts +++ b/src/http-api/index.ts @@ -68,14 +68,14 @@ export class MatrixHttpApi extends FetchHttpApi { * determined by this.opts.onlyData, opts.rawResponse, and * opts.onlyContentUri. Rejects with an error (usually a MatrixError). */ - public uploadContent(file: FileType, opts: UploadOpts = {}): Upload { + public uploadContent(file: FileType, opts: UploadOpts = {}): Promise { const includeFilename = opts.includeFilename ?? true; + const abortController = opts.abortController ?? new AbortController(); // If the file doesn't have a mime type, use a default since the HS errors if we don't supply one. const contentType = opts.type ?? (file as File).type ?? 'application/octet-stream'; const fileName = opts.name ?? (file as File).name; - const abortController = new AbortController(); const upload = { loaded: 0, total: 0, @@ -183,12 +183,12 @@ export class MatrixHttpApi extends FetchHttpApi { defer.reject(new DOMException("Aborted", "AbortError")); }); this.uploads.push(upload); - - return upload; + return upload.promise; } - public cancelUpload(upload: Upload): boolean { - if (this.uploads.includes(upload)) { + public cancelUpload(promise: Promise): boolean { + const upload = this.uploads.find(u => u.promise === promise); + if (upload) { upload.abortController.abort(); return true; } diff --git a/src/http-api/interface.ts b/src/http-api/interface.ts index e56fe67f54f..c798bec0d6c 100644 --- a/src/http-api/interface.ts +++ b/src/http-api/interface.ts @@ -75,6 +75,7 @@ export interface UploadOpts { type?: string; includeFilename?: boolean; progressHandler?(progress: UploadProgress): void; + abortController?: AbortController; } export interface Upload { diff --git a/src/models/MSC3089TreeSpace.ts b/src/models/MSC3089TreeSpace.ts index c57bd4a90dc..9a9deec68ac 100644 --- a/src/models/MSC3089TreeSpace.ts +++ b/src/models/MSC3089TreeSpace.ts @@ -476,10 +476,9 @@ export class MSC3089TreeSpace { info: Partial, additionalContent?: IContent, ): Promise { - const upload = this.client.uploadContent(encryptedContents, { + const { content_uri: mxc } = await this.client.uploadContent(encryptedContents, { includeFilename: false, }); - const { content_uri: mxc } = await upload.promise; info.url = mxc; const fileContent = { From 3ca37785abd764201a51902fd271aa8320e4df56 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 10 Oct 2022 14:19:41 +0100 Subject: [PATCH 38/38] Increase test coverage --- src/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.ts b/src/client.ts index 07e26c7ab39..2648c135225 100644 --- a/src/client.ts +++ b/src/client.ts @@ -611,7 +611,7 @@ export interface IUploadKeysRequest { "org.matrix.msc2732.fallback_keys"?: Record; } -interface IOpenIDToken { +export interface IOpenIDToken { access_token: string; token_type: "Bearer" | string; matrix_server_name: string;