diff --git a/docs/channels/matrix.md b/docs/channels/matrix.md index 68a5ac50509..0aeb9429c99 100644 --- a/docs/channels/matrix.md +++ b/docs/channels/matrix.md @@ -12,7 +12,7 @@ on any homeserver, so you need a Matrix account for the bot. Once it is logged i the bot directly or invite it to rooms (Matrix "groups"). Beeper is a valid client option too, but it requires E2EE to be enabled. -Status: supported via plugin (@vector-im/matrix-bot-sdk). Direct messages, rooms, threads, media, reactions, +Status: supported via plugin (`matrix-js-sdk`). Direct messages, rooms, threads, media, reactions, polls (send + poll-start as text), location, and E2EE (with crypto support). ## Plugin required diff --git a/extensions/matrix/package.json b/extensions/matrix/package.json index b388e50b4aa..adf4a947fc3 100644 --- a/extensions/matrix/package.json +++ b/extensions/matrix/package.json @@ -5,8 +5,8 @@ "type": "module", "dependencies": { "@matrix-org/matrix-sdk-crypto-nodejs": "^0.4.0", - "@vector-im/matrix-bot-sdk": "0.8.0-element.3", "markdown-it": "14.1.0", + "matrix-js-sdk": "^40.1.0", "music-metadata": "^11.11.2", "zod": "^4.3.6" }, diff --git a/extensions/matrix/src/matrix/actions/messages.ts b/extensions/matrix/src/matrix/actions/messages.ts index d9cfe372259..5af279e565f 100644 --- a/extensions/matrix/src/matrix/actions/messages.ts +++ b/extensions/matrix/src/matrix/actions/messages.ts @@ -101,7 +101,7 @@ export async function readMatrixMessages( : 20; const token = opts.before?.trim() || opts.after?.trim() || undefined; const dir = opts.after ? "f" : "b"; - // @vector-im/matrix-bot-sdk uses doRequest for room messages + // Room history is queried via the low-level endpoint for compatibility. const res = (await client.doRequest( "GET", `/_matrix/client/v3/rooms/${encodeURIComponent(resolvedRoom)}/messages`, diff --git a/extensions/matrix/src/matrix/actions/reactions.ts b/extensions/matrix/src/matrix/actions/reactions.ts index fe802396093..5be6642169f 100644 --- a/extensions/matrix/src/matrix/actions/reactions.ts +++ b/extensions/matrix/src/matrix/actions/reactions.ts @@ -21,7 +21,7 @@ export async function listMatrixReactions( typeof opts.limit === "number" && Number.isFinite(opts.limit) ? Math.max(1, Math.floor(opts.limit)) : 100; - // @vector-im/matrix-bot-sdk uses doRequest for relations + // Relations are queried via the low-level endpoint for compatibility. const res = (await client.doRequest( "GET", `/_matrix/client/v1/rooms/${encodeURIComponent(resolvedRoom)}/relations/${encodeURIComponent(messageId)}/${RelationType.Annotation}/${EventType.Reaction}`, diff --git a/extensions/matrix/src/matrix/actions/room.ts b/extensions/matrix/src/matrix/actions/room.ts index e1770c7bc8d..75e67b97383 100644 --- a/extensions/matrix/src/matrix/actions/room.ts +++ b/extensions/matrix/src/matrix/actions/room.ts @@ -9,10 +9,8 @@ export async function getMatrixMemberInfo( const { client, stopOnDone } = await resolveActionClient(opts); try { const roomId = opts.roomId ? await resolveMatrixRoomId(client, opts.roomId) : undefined; - // @vector-im/matrix-bot-sdk uses getUserProfile const profile = await client.getUserProfile(userId); - // Note: @vector-im/matrix-bot-sdk doesn't have getRoom().getMember() like matrix-js-sdk - // We'd need to fetch room state separately if needed + // Membership and power levels are not included in profile calls; fetch state separately if needed. return { userId, profile: { @@ -35,7 +33,6 @@ export async function getMatrixRoomInfo(roomId: string, opts: MatrixActionClient const { client, stopOnDone } = await resolveActionClient(opts); try { const resolvedRoom = await resolveMatrixRoomId(client, roomId); - // @vector-im/matrix-bot-sdk uses getRoomState for state events let name: string | null = null; let topic: string | null = null; let canonicalAlias: string | null = null; @@ -43,21 +40,21 @@ export async function getMatrixRoomInfo(roomId: string, opts: MatrixActionClient try { const nameState = await client.getRoomStateEvent(resolvedRoom, "m.room.name", ""); - name = nameState?.name ?? null; + name = typeof nameState?.name === "string" ? nameState.name : null; } catch { // ignore } try { const topicState = await client.getRoomStateEvent(resolvedRoom, EventType.RoomTopic, ""); - topic = topicState?.topic ?? null; + topic = typeof topicState?.topic === "string" ? topicState.topic : null; } catch { // ignore } try { const aliasState = await client.getRoomStateEvent(resolvedRoom, "m.room.canonical_alias", ""); - canonicalAlias = aliasState?.alias ?? null; + canonicalAlias = typeof aliasState?.alias === "string" ? aliasState.alias : null; } catch { // ignore } diff --git a/extensions/matrix/src/matrix/actions/summary.ts b/extensions/matrix/src/matrix/actions/summary.ts index d200e992737..5e5e839c8bf 100644 --- a/extensions/matrix/src/matrix/actions/summary.ts +++ b/extensions/matrix/src/matrix/actions/summary.ts @@ -1,4 +1,4 @@ -import type { MatrixClient } from "@vector-im/matrix-bot-sdk"; +import type { MatrixClient } from "../sdk.js"; import { EventType, type MatrixMessageSummary, diff --git a/extensions/matrix/src/matrix/actions/types.ts b/extensions/matrix/src/matrix/actions/types.ts index 75fddbd9cf9..f10e4223d30 100644 --- a/extensions/matrix/src/matrix/actions/types.ts +++ b/extensions/matrix/src/matrix/actions/types.ts @@ -1,4 +1,4 @@ -import type { MatrixClient } from "@vector-im/matrix-bot-sdk"; +import type { MatrixClient } from "../sdk.js"; export const MsgType = { Text: "m.text", diff --git a/extensions/matrix/src/matrix/active-client.ts b/extensions/matrix/src/matrix/active-client.ts index 5ff54092673..dbb04ea347b 100644 --- a/extensions/matrix/src/matrix/active-client.ts +++ b/extensions/matrix/src/matrix/active-client.ts @@ -1,4 +1,4 @@ -import type { MatrixClient } from "@vector-im/matrix-bot-sdk"; +import type { MatrixClient } from "./sdk.js"; let activeClient: MatrixClient | null = null; diff --git a/extensions/matrix/src/matrix/client.test.ts b/extensions/matrix/src/matrix/client.test.ts index 69de112dbd5..0a28dd65638 100644 --- a/extensions/matrix/src/matrix/client.test.ts +++ b/extensions/matrix/src/matrix/client.test.ts @@ -1,6 +1,16 @@ -import { describe, expect, it } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import type { CoreConfig } from "../types.js"; -import { resolveMatrixConfig } from "./client.js"; +import { resolveMatrixAuth, resolveMatrixConfig } from "./client.js"; +import * as sdkModule from "./sdk.js"; + +const saveMatrixCredentialsMock = vi.fn(); + +vi.mock("./credentials.js", () => ({ + loadMatrixCredentials: vi.fn(() => null), + saveMatrixCredentials: (...args: unknown[]) => saveMatrixCredentialsMock(...args), + credentialsMatchConfig: vi.fn(() => false), + touchMatrixCredentials: vi.fn(), +})); describe("resolveMatrixConfig", () => { it("prefers config over env", () => { @@ -54,3 +64,59 @@ describe("resolveMatrixConfig", () => { expect(resolved.encryption).toBe(false); }); }); + +describe("resolveMatrixAuth", () => { + afterEach(() => { + vi.restoreAllMocks(); + vi.unstubAllGlobals(); + saveMatrixCredentialsMock.mockReset(); + }); + + it("uses the hardened client request path for password login and persists deviceId", async () => { + const doRequestSpy = vi.spyOn(sdkModule.MatrixClient.prototype, "doRequest").mockResolvedValue({ + access_token: "tok-123", + user_id: "@bot:example.org", + device_id: "DEVICE123", + }); + + const cfg = { + channels: { + matrix: { + homeserver: "https://matrix.example.org", + userId: "@bot:example.org", + password: "secret", + encryption: true, + }, + }, + } as CoreConfig; + + const auth = await resolveMatrixAuth({ + cfg, + env: {} as NodeJS.ProcessEnv, + }); + + expect(doRequestSpy).toHaveBeenCalledWith( + "POST", + "/_matrix/client/v3/login", + undefined, + expect.objectContaining({ + type: "m.login.password", + }), + ); + expect(auth).toMatchObject({ + homeserver: "https://matrix.example.org", + userId: "@bot:example.org", + accessToken: "tok-123", + deviceId: "DEVICE123", + encryption: true, + }); + expect(saveMatrixCredentialsMock).toHaveBeenCalledWith( + expect.objectContaining({ + homeserver: "https://matrix.example.org", + userId: "@bot:example.org", + accessToken: "tok-123", + deviceId: "DEVICE123", + }), + ); + }); +}); diff --git a/extensions/matrix/src/matrix/client/config.ts b/extensions/matrix/src/matrix/client/config.ts index 3c6c0da66b5..ea595f5414f 100644 --- a/extensions/matrix/src/matrix/client/config.ts +++ b/extensions/matrix/src/matrix/client/config.ts @@ -1,7 +1,7 @@ -import { MatrixClient } from "@vector-im/matrix-bot-sdk"; import type { CoreConfig } from "../types.js"; import type { MatrixAuth, MatrixResolvedConfig } from "./types.js"; import { getMatrixRuntime } from "../../runtime.js"; +import { MatrixClient } from "../sdk.js"; import { ensureMatrixSdkLoggingConfigured } from "./logging.js"; function clean(value?: string): string { @@ -65,6 +65,10 @@ export async function resolveMatrixAuth(params?: { // If we have an access token, we can fetch userId via whoami if not provided if (resolved.accessToken) { let userId = resolved.userId; + const knownDeviceId = + cachedCredentials && cachedCredentials.accessToken === resolved.accessToken + ? cachedCredentials.deviceId + : undefined; if (!userId) { // Fetch userId from access token via whoami ensureMatrixSdkLoggingConfigured(); @@ -76,6 +80,7 @@ export async function resolveMatrixAuth(params?: { homeserver: resolved.homeserver, userId, accessToken: resolved.accessToken, + deviceId: knownDeviceId, }); } else if (cachedCredentials && cachedCredentials.accessToken === resolved.accessToken) { touchMatrixCredentials(env); @@ -84,6 +89,7 @@ export async function resolveMatrixAuth(params?: { homeserver: resolved.homeserver, userId, accessToken: resolved.accessToken, + deviceId: knownDeviceId, deviceName: resolved.deviceName, initialSyncLimit: resolved.initialSyncLimit, encryption: resolved.encryption, @@ -96,6 +102,7 @@ export async function resolveMatrixAuth(params?: { homeserver: cachedCredentials.homeserver, userId: cachedCredentials.userId, accessToken: cachedCredentials.accessToken, + deviceId: cachedCredentials.deviceId, deviceName: resolved.deviceName, initialSyncLimit: resolved.initialSyncLimit, encryption: resolved.encryption, @@ -112,24 +119,15 @@ export async function resolveMatrixAuth(params?: { ); } - // Login with password using HTTP API - const loginResponse = await fetch(`${resolved.homeserver}/_matrix/client/v3/login`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - type: "m.login.password", - identifier: { type: "m.id.user", user: resolved.userId }, - password: resolved.password, - initial_device_display_name: resolved.deviceName ?? "OpenClaw Gateway", - }), - }); - - if (!loginResponse.ok) { - const errorText = await loginResponse.text(); - throw new Error(`Matrix login failed: ${errorText}`); - } - - const login = (await loginResponse.json()) as { + // Login with password using the same hardened request path as other Matrix HTTP calls. + ensureMatrixSdkLoggingConfigured(); + const loginClient = new MatrixClient(resolved.homeserver, ""); + const login = (await loginClient.doRequest("POST", "/_matrix/client/v3/login", undefined, { + type: "m.login.password", + identifier: { type: "m.id.user", user: resolved.userId }, + password: resolved.password, + initial_device_display_name: resolved.deviceName ?? "OpenClaw Gateway", + })) as { access_token?: string; user_id?: string; device_id?: string; @@ -144,6 +142,7 @@ export async function resolveMatrixAuth(params?: { homeserver: resolved.homeserver, userId: login.user_id ?? resolved.userId, accessToken, + deviceId: login.device_id, deviceName: resolved.deviceName, initialSyncLimit: resolved.initialSyncLimit, encryption: resolved.encryption, diff --git a/extensions/matrix/src/matrix/client/create-client.ts b/extensions/matrix/src/matrix/client/create-client.ts index d2dc7eaf84a..06b9ea8a6b0 100644 --- a/extensions/matrix/src/matrix/client/create-client.ts +++ b/extensions/matrix/src/matrix/client/create-client.ts @@ -1,11 +1,5 @@ -import type { IStorageProvider, ICryptoStorageProvider } from "@vector-im/matrix-bot-sdk"; -import { - LogService, - MatrixClient, - SimpleFsStorageProvider, - RustSdkCryptoStorageProvider, -} from "@vector-im/matrix-bot-sdk"; import fs from "node:fs"; +import { MatrixClient } from "../sdk.js"; import { ensureMatrixSdkLoggingConfigured } from "./logging.js"; import { maybeMigrateLegacyStorage, @@ -13,41 +7,19 @@ import { writeStorageMeta, } from "./storage.js"; -function sanitizeUserIdList(input: unknown, label: string): string[] { - if (input == null) { - return []; - } - if (!Array.isArray(input)) { - LogService.warn( - "MatrixClientLite", - `Expected ${label} list to be an array, got ${typeof input}`, - ); - return []; - } - const filtered = input.filter( - (entry): entry is string => typeof entry === "string" && entry.trim().length > 0, - ); - if (filtered.length !== input.length) { - LogService.warn( - "MatrixClientLite", - `Dropping ${input.length - filtered.length} invalid ${label} entries from sync payload`, - ); - } - return filtered; -} - export async function createMatrixClient(params: { homeserver: string; userId: string; accessToken: string; + deviceId?: string; encryption?: boolean; localTimeoutMs?: number; + initialSyncLimit?: number; accountId?: string | null; }): Promise { ensureMatrixSdkLoggingConfigured(); const env = process.env; - // Create storage provider const storagePaths = resolveMatrixStoragePaths({ homeserver: params.homeserver, userId: params.userId, @@ -57,24 +29,6 @@ export async function createMatrixClient(params: { }); maybeMigrateLegacyStorage({ storagePaths, env }); fs.mkdirSync(storagePaths.rootDir, { recursive: true }); - const storage: IStorageProvider = new SimpleFsStorageProvider(storagePaths.storagePath); - - // Create crypto storage if encryption is enabled - let cryptoStorage: ICryptoStorageProvider | undefined; - if (params.encryption) { - fs.mkdirSync(storagePaths.cryptoPath, { recursive: true }); - - try { - const { StoreType } = await import("@matrix-org/matrix-sdk-crypto-nodejs"); - cryptoStorage = new RustSdkCryptoStorageProvider(storagePaths.cryptoPath, StoreType.Sqlite); - } catch (err) { - LogService.warn( - "MatrixClientLite", - "Failed to initialize crypto storage, E2EE disabled:", - err, - ); - } - } writeStorageMeta({ storagePaths, @@ -83,41 +37,11 @@ export async function createMatrixClient(params: { accountId: params.accountId, }); - const client = new MatrixClient(params.homeserver, params.accessToken, storage, cryptoStorage); - - if (client.crypto) { - const originalUpdateSyncData = client.crypto.updateSyncData.bind(client.crypto); - client.crypto.updateSyncData = async ( - toDeviceMessages, - otkCounts, - unusedFallbackKeyAlgs, - changedDeviceLists, - leftDeviceLists, - ) => { - const safeChanged = sanitizeUserIdList(changedDeviceLists, "changed device list"); - const safeLeft = sanitizeUserIdList(leftDeviceLists, "left device list"); - try { - return await originalUpdateSyncData( - toDeviceMessages, - otkCounts, - unusedFallbackKeyAlgs, - safeChanged, - safeLeft, - ); - } catch (err) { - const message = typeof err === "string" ? err : err instanceof Error ? err.message : ""; - if (message.includes("Expect value to be String")) { - LogService.warn( - "MatrixClientLite", - "Ignoring malformed device list entries during crypto sync", - message, - ); - return; - } - throw err; - } - }; - } - - return client; + return new MatrixClient(params.homeserver, params.accessToken, undefined, undefined, { + userId: params.userId, + deviceId: params.deviceId, + encryption: params.encryption, + localTimeoutMs: params.localTimeoutMs, + initialSyncLimit: params.initialSyncLimit, + }); } diff --git a/extensions/matrix/src/matrix/client/logging.ts b/extensions/matrix/src/matrix/client/logging.ts index c5ef702b019..f125a38ac2f 100644 --- a/extensions/matrix/src/matrix/client/logging.ts +++ b/extensions/matrix/src/matrix/client/logging.ts @@ -1,4 +1,4 @@ -import { ConsoleLogger, LogService } from "@vector-im/matrix-bot-sdk"; +import { ConsoleLogger, LogService } from "../sdk.js"; let matrixSdkLoggingConfigured = false; const matrixSdkBaseLogger = new ConsoleLogger(); diff --git a/extensions/matrix/src/matrix/client/shared.ts b/extensions/matrix/src/matrix/client/shared.ts index 201eb5bbdb2..2c745102ff0 100644 --- a/extensions/matrix/src/matrix/client/shared.ts +++ b/extensions/matrix/src/matrix/client/shared.ts @@ -1,7 +1,7 @@ -import type { MatrixClient } from "@vector-im/matrix-bot-sdk"; -import { LogService } from "@vector-im/matrix-bot-sdk"; +import type { MatrixClient } from "../sdk.js"; import type { CoreConfig } from "../types.js"; import type { MatrixAuth } from "./types.js"; +import { LogService } from "../sdk.js"; import { resolveMatrixAuth } from "./config.js"; import { createMatrixClient } from "./create-client.js"; import { DEFAULT_ACCOUNT_KEY } from "./storage.js"; @@ -36,8 +36,10 @@ async function createSharedMatrixClient(params: { homeserver: params.auth.homeserver, userId: params.auth.userId, accessToken: params.auth.accessToken, + deviceId: params.auth.deviceId, encryption: params.auth.encryption, localTimeoutMs: params.timeoutMs, + initialSyncLimit: params.auth.initialSyncLimit, accountId: params.accountId, }); return { @@ -158,7 +160,7 @@ export async function waitForMatrixSync(_params: { timeoutMs?: number; abortSignal?: AbortSignal; }): Promise { - // @vector-im/matrix-bot-sdk handles sync internally in start() + // matrix-js-sdk handles sync lifecycle in start() for this integration. // This is kept for API compatibility but is essentially a no-op now } diff --git a/extensions/matrix/src/matrix/client/types.ts b/extensions/matrix/src/matrix/client/types.ts index ec1b3002bc7..c41c8e371fc 100644 --- a/extensions/matrix/src/matrix/client/types.ts +++ b/extensions/matrix/src/matrix/client/types.ts @@ -2,6 +2,7 @@ export type MatrixResolvedConfig = { homeserver: string; userId: string; accessToken?: string; + deviceId?: string; password?: string; deviceName?: string; initialSyncLimit?: number; @@ -19,6 +20,7 @@ export type MatrixAuth = { homeserver: string; userId: string; accessToken: string; + deviceId?: string; deviceName?: string; initialSyncLimit?: number; encryption?: boolean; diff --git a/extensions/matrix/src/matrix/deps.ts b/extensions/matrix/src/matrix/deps.ts index 67fb5244a11..e0f3201ee40 100644 --- a/extensions/matrix/src/matrix/deps.ts +++ b/extensions/matrix/src/matrix/deps.ts @@ -5,7 +5,7 @@ import path from "node:path"; import { fileURLToPath } from "node:url"; import { getMatrixRuntime } from "../runtime.js"; -const MATRIX_SDK_PACKAGE = "@vector-im/matrix-bot-sdk"; +const MATRIX_SDK_PACKAGE = "matrix-js-sdk"; export function isMatrixSdkAvailable(): boolean { try { @@ -31,9 +31,9 @@ export async function ensureMatrixSdkInstalled(params: { } const confirm = params.confirm; if (confirm) { - const ok = await confirm("Matrix requires @vector-im/matrix-bot-sdk. Install now?"); + const ok = await confirm("Matrix requires matrix-js-sdk. Install now?"); if (!ok) { - throw new Error("Matrix requires @vector-im/matrix-bot-sdk (install dependencies first)."); + throw new Error("Matrix requires matrix-js-sdk (install dependencies first)."); } } @@ -53,8 +53,6 @@ export async function ensureMatrixSdkInstalled(params: { ); } if (!isMatrixSdkAvailable()) { - throw new Error( - "Matrix dependency install completed but @vector-im/matrix-bot-sdk is still missing.", - ); + throw new Error("Matrix dependency install completed but matrix-js-sdk is still missing."); } } diff --git a/extensions/matrix/src/matrix/monitor/auto-join.test.ts b/extensions/matrix/src/matrix/monitor/auto-join.test.ts new file mode 100644 index 00000000000..1c42af12572 --- /dev/null +++ b/extensions/matrix/src/matrix/monitor/auto-join.test.ts @@ -0,0 +1,127 @@ +import type { PluginRuntime } from "openclaw/plugin-sdk"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import type { CoreConfig } from "../../types.js"; +import { setMatrixRuntime } from "../../runtime.js"; +import { registerMatrixAutoJoin } from "./auto-join.js"; + +type InviteHandler = (roomId: string, inviteEvent: unknown) => Promise; + +function createClientStub() { + let inviteHandler: InviteHandler | null = null; + const client = { + on: vi.fn((eventName: string, listener: unknown) => { + if (eventName === "room.invite") { + inviteHandler = listener as InviteHandler; + } + return client; + }), + joinRoom: vi.fn(async () => {}), + getRoomStateEvent: vi.fn(async () => ({})), + } as unknown as import("../sdk.js").MatrixClient; + + return { + client, + getInviteHandler: () => inviteHandler, + joinRoom: (client as unknown as { joinRoom: ReturnType }).joinRoom, + getRoomStateEvent: (client as unknown as { getRoomStateEvent: ReturnType }) + .getRoomStateEvent, + }; +} + +describe("registerMatrixAutoJoin", () => { + beforeEach(() => { + setMatrixRuntime({ + logging: { + shouldLogVerbose: () => false, + }, + } as unknown as PluginRuntime); + }); + + it("joins all invites when autoJoin=always", async () => { + const { client, getInviteHandler, joinRoom } = createClientStub(); + const cfg: CoreConfig = { + channels: { + matrix: { + autoJoin: "always", + }, + }, + }; + + registerMatrixAutoJoin({ + client, + cfg, + runtime: { + log: vi.fn(), + error: vi.fn(), + } as unknown as import("openclaw/plugin-sdk").RuntimeEnv, + }); + + const inviteHandler = getInviteHandler(); + expect(inviteHandler).toBeTruthy(); + await inviteHandler!("!room:example.org", {}); + + expect(joinRoom).toHaveBeenCalledWith("!room:example.org"); + }); + + it("ignores invites outside allowlist when autoJoin=allowlist", async () => { + const { client, getInviteHandler, joinRoom, getRoomStateEvent } = createClientStub(); + getRoomStateEvent.mockResolvedValue({ + alias: "#other:example.org", + alt_aliases: ["#else:example.org"], + }); + const cfg: CoreConfig = { + channels: { + matrix: { + autoJoin: "allowlist", + autoJoinAllowlist: ["#allowed:example.org"], + }, + }, + }; + + registerMatrixAutoJoin({ + client, + cfg, + runtime: { + log: vi.fn(), + error: vi.fn(), + } as unknown as import("openclaw/plugin-sdk").RuntimeEnv, + }); + + const inviteHandler = getInviteHandler(); + expect(inviteHandler).toBeTruthy(); + await inviteHandler!("!room:example.org", {}); + + expect(joinRoom).not.toHaveBeenCalled(); + }); + + it("joins invite when alias matches allowlist", async () => { + const { client, getInviteHandler, joinRoom, getRoomStateEvent } = createClientStub(); + getRoomStateEvent.mockResolvedValue({ + alias: "#allowed:example.org", + alt_aliases: ["#backup:example.org"], + }); + const cfg: CoreConfig = { + channels: { + matrix: { + autoJoin: "allowlist", + autoJoinAllowlist: [" #allowed:example.org "], + }, + }, + }; + + registerMatrixAutoJoin({ + client, + cfg, + runtime: { + log: vi.fn(), + error: vi.fn(), + } as unknown as import("openclaw/plugin-sdk").RuntimeEnv, + }); + + const inviteHandler = getInviteHandler(); + expect(inviteHandler).toBeTruthy(); + await inviteHandler!("!room:example.org", {}); + + expect(joinRoom).toHaveBeenCalledWith("!room:example.org"); + }); +}); diff --git a/extensions/matrix/src/matrix/monitor/auto-join.ts b/extensions/matrix/src/matrix/monitor/auto-join.ts index 6fb36b93f17..2185d53d161 100644 --- a/extensions/matrix/src/matrix/monitor/auto-join.ts +++ b/extensions/matrix/src/matrix/monitor/auto-join.ts @@ -1,7 +1,6 @@ -import type { MatrixClient } from "@vector-im/matrix-bot-sdk"; import type { RuntimeEnv } from "openclaw/plugin-sdk"; -import { AutojoinRoomsMixin } from "@vector-im/matrix-bot-sdk"; import type { CoreConfig } from "../../types.js"; +import type { MatrixClient } from "../sdk.js"; import { getMatrixRuntime } from "../../runtime.js"; export function registerMatrixAutoJoin(params: { @@ -18,47 +17,52 @@ export function registerMatrixAutoJoin(params: { runtime.log?.(message); }; const autoJoin = cfg.channels?.matrix?.autoJoin ?? "always"; - const autoJoinAllowlist = cfg.channels?.matrix?.autoJoinAllowlist ?? []; + const autoJoinAllowlist = new Set( + (cfg.channels?.matrix?.autoJoinAllowlist ?? []) + .map((entry) => String(entry).trim()) + .filter(Boolean), + ); if (autoJoin === "off") { return; } if (autoJoin === "always") { - // Use the built-in autojoin mixin for "always" mode - AutojoinRoomsMixin.setupOnClient(client); logVerbose("matrix: auto-join enabled for all invites"); - return; + } else { + logVerbose("matrix: auto-join enabled for allowlist invites"); } - // For "allowlist" mode, handle invites manually + // Handle invites directly so both "always" and "allowlist" modes share the same path. client.on("room.invite", async (roomId: string, _inviteEvent: unknown) => { - if (autoJoin !== "allowlist") { - return; - } + if (autoJoin === "allowlist") { + let alias: string | undefined; + let altAliases: string[] = []; + try { + const aliasState = await client + .getRoomStateEvent(roomId, "m.room.canonical_alias", "") + .catch(() => null); + alias = aliasState && typeof aliasState.alias === "string" ? aliasState.alias : undefined; + altAliases = + aliasState && Array.isArray(aliasState.alt_aliases) + ? aliasState.alt_aliases + .map((entry) => (typeof entry === "string" ? entry.trim() : "")) + .filter(Boolean) + : []; + } catch { + // Ignore errors + } - // Get room alias if available - let alias: string | undefined; - let altAliases: string[] = []; - try { - const aliasState = await client - .getRoomStateEvent(roomId, "m.room.canonical_alias", "") - .catch(() => null); - alias = aliasState?.alias; - altAliases = Array.isArray(aliasState?.alt_aliases) ? aliasState.alt_aliases : []; - } catch { - // Ignore errors - } + const allowed = + autoJoinAllowlist.has("*") || + autoJoinAllowlist.has(roomId) || + (alias ? autoJoinAllowlist.has(alias) : false) || + altAliases.some((value) => autoJoinAllowlist.has(value)); - const allowed = - autoJoinAllowlist.includes("*") || - autoJoinAllowlist.includes(roomId) || - (alias ? autoJoinAllowlist.includes(alias) : false) || - altAliases.some((value) => autoJoinAllowlist.includes(value)); - - if (!allowed) { - logVerbose(`matrix: invite ignored (not in allowlist) room=${roomId}`); - return; + if (!allowed) { + logVerbose(`matrix: invite ignored (not in allowlist) room=${roomId}`); + return; + } } try { diff --git a/extensions/matrix/src/matrix/monitor/direct.ts b/extensions/matrix/src/matrix/monitor/direct.ts index 5cd6e88758e..de767e1db08 100644 --- a/extensions/matrix/src/matrix/monitor/direct.ts +++ b/extensions/matrix/src/matrix/monitor/direct.ts @@ -1,4 +1,4 @@ -import type { MatrixClient } from "@vector-im/matrix-bot-sdk"; +import type { MatrixClient } from "../sdk.js"; type DirectMessageCheck = { roomId: string; diff --git a/extensions/matrix/src/matrix/monitor/events.ts b/extensions/matrix/src/matrix/monitor/events.ts index 1faeffc819d..3608991da16 100644 --- a/extensions/matrix/src/matrix/monitor/events.ts +++ b/extensions/matrix/src/matrix/monitor/events.ts @@ -1,6 +1,6 @@ -import type { MatrixClient } from "@vector-im/matrix-bot-sdk"; import type { PluginRuntime } from "openclaw/plugin-sdk"; import type { MatrixAuth } from "../client.js"; +import type { MatrixClient } from "../sdk.js"; import type { MatrixRawEvent } from "./types.js"; import { EventType } from "./types.js"; diff --git a/extensions/matrix/src/matrix/monitor/handler.ts b/extensions/matrix/src/matrix/monitor/handler.ts index a9a4e373ca4..f2090247d15 100644 --- a/extensions/matrix/src/matrix/monitor/handler.ts +++ b/extensions/matrix/src/matrix/monitor/handler.ts @@ -1,4 +1,3 @@ -import type { LocationMessageEventContent, MatrixClient } from "@vector-im/matrix-bot-sdk"; import { createReplyPrefixOptions, createTypingCallbacks, @@ -9,6 +8,7 @@ import { type RuntimeEnv, } from "openclaw/plugin-sdk"; import type { CoreConfig, ReplyToMode } from "../../types.js"; +import type { LocationMessageEventContent, MatrixClient } from "../sdk.js"; import type { MatrixRawEvent, RoomMessageEventContent } from "./types.js"; import { formatPollAsText, @@ -116,7 +116,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam try { const eventType = event.type; if (eventType === EventType.RoomMessageEncrypted) { - // Encrypted messages are decrypted automatically by @vector-im/matrix-bot-sdk with crypto enabled + // Encrypted payloads are emitted separately after decryption. return; } @@ -446,7 +446,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam threadReplies, messageId, threadRootId, - isThreadRoot: false, // @vector-im/matrix-bot-sdk doesn't have this info readily available + isThreadRoot: false, // Raw event payload does not carry explicit thread-root metadata. }); const route = core.channel.routing.resolveAgentRoute({ diff --git a/extensions/matrix/src/matrix/monitor/index.ts b/extensions/matrix/src/matrix/monitor/index.ts index aae5f00d585..2b526aeef30 100644 --- a/extensions/matrix/src/matrix/monitor/index.ts +++ b/extensions/matrix/src/matrix/monitor/index.ts @@ -300,7 +300,7 @@ export async function monitorMatrixProvider(opts: MonitorMatrixOpts = {}): Promi }); logVerboseMessage("matrix: client started"); - // @vector-im/matrix-bot-sdk client is already started via resolveSharedMatrixClient + // Shared client is already started via resolveSharedMatrixClient. logger.info(`matrix: logged in as ${auth.userId}`); // If E2EE is enabled, trigger device verification diff --git a/extensions/matrix/src/matrix/monitor/location.ts b/extensions/matrix/src/matrix/monitor/location.ts index 41c91aecc16..7380ec215b4 100644 --- a/extensions/matrix/src/matrix/monitor/location.ts +++ b/extensions/matrix/src/matrix/monitor/location.ts @@ -1,9 +1,9 @@ -import type { LocationMessageEventContent } from "@vector-im/matrix-bot-sdk"; import { formatLocationText, toLocationContext, type NormalizedLocation, } from "openclaw/plugin-sdk"; +import type { LocationMessageEventContent } from "../sdk.js"; import { EventType } from "./types.js"; export type MatrixLocationPayload = { diff --git a/extensions/matrix/src/matrix/monitor/media.test.ts b/extensions/matrix/src/matrix/monitor/media.test.ts index 590dd5148a5..dcf7af8ad69 100644 --- a/extensions/matrix/src/matrix/monitor/media.test.ts +++ b/extensions/matrix/src/matrix/monitor/media.test.ts @@ -28,7 +28,7 @@ describe("downloadMatrixMedia", () => { const client = { crypto: { decryptMedia }, mxcToHttp: vi.fn().mockReturnValue("https://example/mxc"), - } as unknown as import("@vector-im/matrix-bot-sdk").MatrixClient; + } as unknown as import("../sdk.js").MatrixClient; const file = { url: "mxc://example/file", @@ -69,7 +69,7 @@ describe("downloadMatrixMedia", () => { const client = { crypto: { decryptMedia }, mxcToHttp: vi.fn().mockReturnValue("https://example/mxc"), - } as unknown as import("@vector-im/matrix-bot-sdk").MatrixClient; + } as unknown as import("../sdk.js").MatrixClient; const file = { url: "mxc://example/file", diff --git a/extensions/matrix/src/matrix/monitor/media.ts b/extensions/matrix/src/matrix/monitor/media.ts index c88bfc0613b..89b3d4b9159 100644 --- a/extensions/matrix/src/matrix/monitor/media.ts +++ b/extensions/matrix/src/matrix/monitor/media.ts @@ -1,4 +1,4 @@ -import type { MatrixClient } from "@vector-im/matrix-bot-sdk"; +import type { MatrixClient } from "../sdk.js"; import { getMatrixRuntime } from "../../runtime.js"; // Type for encrypted file info @@ -21,7 +21,7 @@ async function fetchMatrixMediaBuffer(params: { mxcUrl: string; maxBytes: number; }): Promise<{ buffer: Buffer; headerType?: string } | null> { - // @vector-im/matrix-bot-sdk provides mxcToHttp helper + // The client wrapper exposes mxcToHttp for Matrix media URIs. const url = params.client.mxcToHttp(params.mxcUrl); if (!url) { return null; @@ -41,7 +41,7 @@ async function fetchMatrixMediaBuffer(params: { /** * Download and decrypt encrypted media from a Matrix room. - * Uses @vector-im/matrix-bot-sdk's decryptMedia which handles both download and decryption. + * Uses the Matrix crypto adapter's decryptMedia helper. */ async function fetchEncryptedMediaBuffer(params: { client: MatrixClient; diff --git a/extensions/matrix/src/matrix/monitor/replies.ts b/extensions/matrix/src/matrix/monitor/replies.ts index 1193d59f80d..dc931e7b05c 100644 --- a/extensions/matrix/src/matrix/monitor/replies.ts +++ b/extensions/matrix/src/matrix/monitor/replies.ts @@ -1,5 +1,5 @@ -import type { MatrixClient } from "@vector-im/matrix-bot-sdk"; import type { MarkdownTableMode, ReplyPayload, RuntimeEnv } from "openclaw/plugin-sdk"; +import type { MatrixClient } from "../sdk.js"; import { getMatrixRuntime } from "../../runtime.js"; import { sendMessageMatrix } from "../send.js"; diff --git a/extensions/matrix/src/matrix/monitor/room-info.ts b/extensions/matrix/src/matrix/monitor/room-info.ts index 764147d3539..4a7624d7c10 100644 --- a/extensions/matrix/src/matrix/monitor/room-info.ts +++ b/extensions/matrix/src/matrix/monitor/room-info.ts @@ -1,4 +1,4 @@ -import type { MatrixClient } from "@vector-im/matrix-bot-sdk"; +import type { MatrixClient } from "../sdk.js"; export type MatrixRoomInfo = { name?: string; diff --git a/extensions/matrix/src/matrix/monitor/threads.ts b/extensions/matrix/src/matrix/monitor/threads.ts index a384957166b..1a2f260f243 100644 --- a/extensions/matrix/src/matrix/monitor/threads.ts +++ b/extensions/matrix/src/matrix/monitor/threads.ts @@ -1,4 +1,4 @@ -// Type for raw Matrix event from @vector-im/matrix-bot-sdk +// Type for raw Matrix event payload consumed by thread helpers. type MatrixRawEvent = { event_id: string; sender: string; diff --git a/extensions/matrix/src/matrix/monitor/types.ts b/extensions/matrix/src/matrix/monitor/types.ts index c910f931fa9..0a619d3b121 100644 --- a/extensions/matrix/src/matrix/monitor/types.ts +++ b/extensions/matrix/src/matrix/monitor/types.ts @@ -1,4 +1,4 @@ -import type { EncryptedFile, MessageEventContent } from "@vector-im/matrix-bot-sdk"; +import type { EncryptedFile, MessageEventContent } from "../sdk.js"; export const EventType = { RoomMessage: "m.room.message", diff --git a/extensions/matrix/src/matrix/probe.ts b/extensions/matrix/src/matrix/probe.ts index 7bd54bdc400..fdde4a1f49e 100644 --- a/extensions/matrix/src/matrix/probe.ts +++ b/extensions/matrix/src/matrix/probe.ts @@ -49,7 +49,7 @@ export async function probeMatrix(params: { accessToken: params.accessToken, localTimeoutMs: params.timeoutMs, }); - // @vector-im/matrix-bot-sdk uses getUserId() which calls whoami internally + // The client wrapper resolves user ID via whoami when needed. const userId = await client.getUserId(); result.ok = true; result.userId = userId ?? null; diff --git a/extensions/matrix/src/matrix/sdk.test.ts b/extensions/matrix/src/matrix/sdk.test.ts new file mode 100644 index 00000000000..394f5593685 --- /dev/null +++ b/extensions/matrix/src/matrix/sdk.test.ts @@ -0,0 +1,313 @@ +import { EventEmitter } from "node:events"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +class FakeMatrixEvent extends EventEmitter { + private readonly roomId: string; + private readonly eventId: string; + private readonly sender: string; + private readonly type: string; + private readonly ts: number; + private readonly content: Record; + private readonly stateKey?: string; + private readonly unsigned?: { + age?: number; + redacted_because?: unknown; + }; + private readonly decryptionFailure: boolean; + + constructor(params: { + roomId: string; + eventId: string; + sender: string; + type: string; + ts: number; + content: Record; + stateKey?: string; + unsigned?: { + age?: number; + redacted_because?: unknown; + }; + decryptionFailure?: boolean; + }) { + super(); + this.roomId = params.roomId; + this.eventId = params.eventId; + this.sender = params.sender; + this.type = params.type; + this.ts = params.ts; + this.content = params.content; + this.stateKey = params.stateKey; + this.unsigned = params.unsigned; + this.decryptionFailure = params.decryptionFailure === true; + } + + getRoomId(): string { + return this.roomId; + } + + getId(): string { + return this.eventId; + } + + getSender(): string { + return this.sender; + } + + getType(): string { + return this.type; + } + + getTs(): number { + return this.ts; + } + + getContent(): Record { + return this.content; + } + + getUnsigned(): { age?: number; redacted_because?: unknown } { + return this.unsigned ?? {}; + } + + getStateKey(): string | undefined { + return this.stateKey; + } + + isDecryptionFailure(): boolean { + return this.decryptionFailure; + } +} + +type MatrixJsClientStub = EventEmitter & { + startClient: ReturnType; + stopClient: ReturnType; + initRustCrypto: ReturnType; + getUserId: ReturnType; + getJoinedRooms: ReturnType; + getJoinedRoomMembers: ReturnType; + getStateEvent: ReturnType; + getAccountData: ReturnType; + setAccountData: ReturnType; + getRoomIdForAlias: ReturnType; + sendMessage: ReturnType; + sendEvent: ReturnType; + sendStateEvent: ReturnType; + redactEvent: ReturnType; + getProfileInfo: ReturnType; + joinRoom: ReturnType; + mxcUrlToHttp: ReturnType; + uploadContent: ReturnType; + fetchRoomEvent: ReturnType; + sendTyping: ReturnType; + getRoom: ReturnType; + getCrypto: ReturnType; +}; + +function createMatrixJsClientStub(): MatrixJsClientStub { + const client = new EventEmitter() as MatrixJsClientStub; + client.startClient = vi.fn(async () => {}); + client.stopClient = vi.fn(); + client.initRustCrypto = vi.fn(async () => {}); + client.getUserId = vi.fn(() => "@bot:example.org"); + client.getJoinedRooms = vi.fn(async () => ({ joined_rooms: [] })); + client.getJoinedRoomMembers = vi.fn(async () => ({ joined: {} })); + client.getStateEvent = vi.fn(async () => ({})); + client.getAccountData = vi.fn(() => undefined); + client.setAccountData = vi.fn(async () => {}); + client.getRoomIdForAlias = vi.fn(async () => ({ room_id: "!resolved:example.org" })); + client.sendMessage = vi.fn(async () => ({ event_id: "$sent" })); + client.sendEvent = vi.fn(async () => ({ event_id: "$sent-event" })); + client.sendStateEvent = vi.fn(async () => ({ event_id: "$state" })); + client.redactEvent = vi.fn(async () => ({ event_id: "$redact" })); + client.getProfileInfo = vi.fn(async () => ({})); + client.joinRoom = vi.fn(async () => ({})); + client.mxcUrlToHttp = vi.fn(() => null); + client.uploadContent = vi.fn(async () => ({ content_uri: "mxc://example/file" })); + client.fetchRoomEvent = vi.fn(async () => ({})); + client.sendTyping = vi.fn(async () => {}); + client.getRoom = vi.fn(() => ({ hasEncryptionStateEvent: () => false })); + client.getCrypto = vi.fn(() => undefined); + return client; +} + +let matrixJsClient = createMatrixJsClientStub(); + +vi.mock("matrix-js-sdk", () => ({ + ClientEvent: { Event: "event" }, + MatrixEventEvent: { Decrypted: "decrypted" }, + createClient: vi.fn(() => matrixJsClient), +})); + +import { MatrixClient } from "./sdk.js"; + +describe("MatrixClient request hardening", () => { + beforeEach(() => { + matrixJsClient = createMatrixJsClientStub(); + vi.useRealTimers(); + vi.unstubAllGlobals(); + }); + + afterEach(() => { + vi.useRealTimers(); + vi.unstubAllGlobals(); + }); + + it("blocks cross-protocol redirects", async () => { + const fetchMock = vi.fn(async () => { + return new Response("", { + status: 302, + headers: { + location: "http://evil.example.org/next", + }, + }); + }); + vi.stubGlobal("fetch", fetchMock as unknown as typeof fetch); + + const client = new MatrixClient("https://matrix.example.org", "token"); + + await expect(client.doRequest("GET", "https://matrix.example.org/start")).rejects.toThrow( + "Blocked cross-protocol redirect", + ); + }); + + it("strips authorization when redirect crosses origin", async () => { + const calls: Array<{ url: string; headers: Headers }> = []; + const fetchMock = vi.fn(async (url: URL | string, init?: RequestInit) => { + calls.push({ + url: String(url), + headers: new Headers(init?.headers), + }); + if (calls.length === 1) { + return new Response("", { + status: 302, + headers: { location: "https://cdn.example.org/next" }, + }); + } + return new Response("{}", { + status: 200, + headers: { "content-type": "application/json" }, + }); + }); + vi.stubGlobal("fetch", fetchMock as unknown as typeof fetch); + + const client = new MatrixClient("https://matrix.example.org", "token"); + await client.doRequest("GET", "https://matrix.example.org/start"); + + expect(calls).toHaveLength(2); + expect(calls[0]?.url).toBe("https://matrix.example.org/start"); + expect(calls[0]?.headers.get("authorization")).toBe("Bearer token"); + expect(calls[1]?.url).toBe("https://cdn.example.org/next"); + expect(calls[1]?.headers.get("authorization")).toBeNull(); + }); + + it("aborts requests after timeout", async () => { + vi.useFakeTimers(); + const fetchMock = vi.fn((_: URL | string, init?: RequestInit) => { + return new Promise((_, reject) => { + init?.signal?.addEventListener("abort", () => { + reject(new Error("aborted")); + }); + }); + }); + vi.stubGlobal("fetch", fetchMock as unknown as typeof fetch); + + const client = new MatrixClient("https://matrix.example.org", "token", undefined, undefined, { + localTimeoutMs: 25, + }); + + const pending = client.doRequest("GET", "/_matrix/client/v3/account/whoami"); + const assertion = expect(pending).rejects.toThrow("aborted"); + await vi.advanceTimersByTimeAsync(30); + + await assertion; + }); +}); + +describe("MatrixClient event bridge", () => { + beforeEach(() => { + matrixJsClient = createMatrixJsClientStub(); + }); + + it("emits room.message only after encrypted events decrypt", async () => { + const client = new MatrixClient("https://matrix.example.org", "token"); + const messageEvents: Array<{ roomId: string; type: string }> = []; + + client.on("room.message", (roomId, event) => { + messageEvents.push({ roomId, type: event.type }); + }); + + await client.start(); + + const encrypted = new FakeMatrixEvent({ + roomId: "!room:example.org", + eventId: "$event", + sender: "@alice:example.org", + type: "m.room.encrypted", + ts: Date.now(), + content: {}, + }); + const decrypted = new FakeMatrixEvent({ + roomId: "!room:example.org", + eventId: "$event", + sender: "@alice:example.org", + type: "m.room.message", + ts: Date.now(), + content: { + msgtype: "m.text", + body: "hello", + }, + }); + + matrixJsClient.emit("event", encrypted); + expect(messageEvents).toHaveLength(0); + + encrypted.emit("decrypted", decrypted); + expect(messageEvents).toEqual([ + { + roomId: "!room:example.org", + type: "m.room.message", + }, + ]); + }); + + it("emits room.failed_decryption when decrypting fails", async () => { + const client = new MatrixClient("https://matrix.example.org", "token"); + const failed: string[] = []; + const delivered: string[] = []; + + client.on("room.failed_decryption", (_roomId, _event, error) => { + failed.push(error.message); + }); + client.on("room.message", (_roomId, event) => { + delivered.push(event.type); + }); + + await client.start(); + + const encrypted = new FakeMatrixEvent({ + roomId: "!room:example.org", + eventId: "$event", + sender: "@alice:example.org", + type: "m.room.encrypted", + ts: Date.now(), + content: {}, + }); + const decrypted = new FakeMatrixEvent({ + roomId: "!room:example.org", + eventId: "$event", + sender: "@alice:example.org", + type: "m.room.message", + ts: Date.now(), + content: { + msgtype: "m.text", + body: "hello", + }, + }); + + matrixJsClient.emit("event", encrypted); + encrypted.emit("decrypted", decrypted, new Error("decrypt failed")); + + expect(failed).toEqual(["decrypt failed"]); + expect(delivered).toHaveLength(0); + }); +}); diff --git a/extensions/matrix/src/matrix/sdk.ts b/extensions/matrix/src/matrix/sdk.ts new file mode 100644 index 00000000000..323b5af2fec --- /dev/null +++ b/extensions/matrix/src/matrix/sdk.ts @@ -0,0 +1,862 @@ +import { Attachment, EncryptedAttachment } from "@matrix-org/matrix-sdk-crypto-nodejs"; +import { + ClientEvent, + MatrixEventEvent, + createClient as createMatrixJsClient, + type MatrixClient as MatrixJsClient, + type MatrixEvent, +} from "matrix-js-sdk"; +import { EventEmitter } from "node:events"; + +type Logger = { + trace: (module: string, ...messageOrObject: unknown[]) => void; + debug: (module: string, ...messageOrObject: unknown[]) => void; + info: (module: string, ...messageOrObject: unknown[]) => void; + warn: (module: string, ...messageOrObject: unknown[]) => void; + error: (module: string, ...messageOrObject: unknown[]) => void; +}; + +type HttpMethod = "GET" | "POST" | "PUT" | "DELETE"; + +type QueryValue = + | string + | number + | boolean + | null + | undefined + | Array; + +type QueryParams = Record | null | undefined; + +type MatrixRawEvent = { + event_id: string; + sender: string; + type: string; + origin_server_ts: number; + content: Record; + unsigned?: { + age?: number; + redacted_because?: unknown; + }; + state_key?: string; +}; + +type MatrixClientEventMap = { + "room.event": [roomId: string, event: MatrixRawEvent]; + "room.message": [roomId: string, event: MatrixRawEvent]; + "room.encrypted_event": [roomId: string, event: MatrixRawEvent]; + "room.decrypted_event": [roomId: string, event: MatrixRawEvent]; + "room.failed_decryption": [roomId: string, event: MatrixRawEvent, error: Error]; + "room.invite": [roomId: string, event: MatrixRawEvent]; + "room.join": [roomId: string, event: MatrixRawEvent]; +}; + +function noop(): void { + // no-op +} + +export class ConsoleLogger { + trace(module: string, ...messageOrObject: unknown[]): void { + console.debug(`[${module}]`, ...messageOrObject); + } + + debug(module: string, ...messageOrObject: unknown[]): void { + console.debug(`[${module}]`, ...messageOrObject); + } + + info(module: string, ...messageOrObject: unknown[]): void { + console.info(`[${module}]`, ...messageOrObject); + } + + warn(module: string, ...messageOrObject: unknown[]): void { + console.warn(`[${module}]`, ...messageOrObject); + } + + error(module: string, ...messageOrObject: unknown[]): void { + console.error(`[${module}]`, ...messageOrObject); + } +} + +const defaultLogger = new ConsoleLogger(); +let activeLogger: Logger = defaultLogger; + +export const LogService = { + setLogger(logger: Logger): void { + activeLogger = logger; + }, + trace(module: string, ...messageOrObject: unknown[]): void { + activeLogger.trace(module, ...messageOrObject); + }, + debug(module: string, ...messageOrObject: unknown[]): void { + activeLogger.debug(module, ...messageOrObject); + }, + info(module: string, ...messageOrObject: unknown[]): void { + activeLogger.info(module, ...messageOrObject); + }, + warn(module: string, ...messageOrObject: unknown[]): void { + activeLogger.warn(module, ...messageOrObject); + }, + error(module: string, ...messageOrObject: unknown[]): void { + activeLogger.error(module, ...messageOrObject); + }, +}; + +export type EncryptedFile = { + url: string; + key: { + kty: string; + key_ops: string[]; + alg: string; + k: string; + ext: boolean; + }; + iv: string; + hashes: Record; + v: string; +}; + +export type FileWithThumbnailInfo = { + size?: number; + mimetype?: string; + thumbnail_url?: string; + thumbnail_info?: { + w?: number; + h?: number; + mimetype?: string; + size?: number; + }; +}; + +export type DimensionalFileInfo = FileWithThumbnailInfo & { + w?: number; + h?: number; +}; + +export type TimedFileInfo = FileWithThumbnailInfo & { + duration?: number; +}; + +export type VideoFileInfo = DimensionalFileInfo & + TimedFileInfo & { + duration?: number; + }; + +export type MessageEventContent = { + msgtype?: string; + body?: string; + format?: string; + formatted_body?: string; + filename?: string; + url?: string; + file?: EncryptedFile; + info?: Record; + "m.relates_to"?: Record; + "m.new_content"?: unknown; + "m.mentions"?: { + user_ids?: string[]; + room?: boolean; + }; + [key: string]: unknown; +}; + +export type TextualMessageEventContent = MessageEventContent & { + msgtype: string; + body: string; +}; + +export type LocationMessageEventContent = MessageEventContent & { + msgtype?: string; + geo_uri?: string; +}; + +type MatrixCryptoFacade = { + prepare: (joinedRooms: string[]) => Promise; + updateSyncData: ( + toDeviceMessages: unknown, + otkCounts: unknown, + unusedFallbackKeyAlgs: unknown, + changedDeviceLists: unknown, + leftDeviceLists: unknown, + ) => Promise; + isRoomEncrypted: (roomId: string) => Promise; + requestOwnUserVerification: () => Promise; + encryptMedia: (buffer: Buffer) => Promise<{ buffer: Buffer; file: Omit }>; + decryptMedia: (file: EncryptedFile) => Promise; +}; + +export class MatrixClient { + private readonly client: MatrixJsClient; + private readonly emitter = new EventEmitter(); + private readonly homeserver: string; + private readonly accessToken: string; + private readonly localTimeoutMs: number; + private readonly initialSyncLimit?: number; + private readonly encryptionEnabled: boolean; + private bridgeRegistered = false; + private started = false; + private selfUserId: string | null; + private readonly dmRoomIds = new Set(); + private cryptoInitialized = false; + + readonly dms = { + update: async (): Promise => { + await this.refreshDmCache(); + }, + isDm: (roomId: string): boolean => this.dmRoomIds.has(roomId), + }; + + crypto?: MatrixCryptoFacade; + + constructor( + homeserver: string, + accessToken: string, + _storage?: unknown, + _cryptoStorage?: unknown, + opts: { + userId?: string; + deviceId?: string; + localTimeoutMs?: number; + encryption?: boolean; + initialSyncLimit?: number; + } = {}, + ) { + this.homeserver = homeserver; + this.accessToken = accessToken; + this.localTimeoutMs = Math.max(1, opts.localTimeoutMs ?? 60_000); + this.initialSyncLimit = opts.initialSyncLimit; + this.encryptionEnabled = opts.encryption === true; + this.selfUserId = opts.userId?.trim() || null; + this.client = createMatrixJsClient({ + baseUrl: homeserver, + accessToken, + userId: opts.userId, + deviceId: opts.deviceId, + localTimeoutMs: this.localTimeoutMs, + }); + + if (this.encryptionEnabled) { + this.crypto = this.createCryptoFacade(); + } + } + + on( + eventName: TEvent, + listener: (...args: MatrixClientEventMap[TEvent]) => void, + ): this; + on(eventName: string, listener: (...args: unknown[]) => void): this; + on(eventName: string, listener: (...args: unknown[]) => void): this { + this.emitter.on(eventName, listener as (...args: unknown[]) => void); + return this; + } + + off( + eventName: TEvent, + listener: (...args: MatrixClientEventMap[TEvent]) => void, + ): this; + off(eventName: string, listener: (...args: unknown[]) => void): this; + off(eventName: string, listener: (...args: unknown[]) => void): this { + this.emitter.off(eventName, listener as (...args: unknown[]) => void); + return this; + } + + async start(): Promise { + if (this.started) { + return; + } + + this.registerBridge(); + + if (this.encryptionEnabled && !this.cryptoInitialized) { + try { + await this.client.initRustCrypto(); + this.cryptoInitialized = true; + } catch (err) { + LogService.warn("MatrixClientLite", "Failed to initialize rust crypto:", err); + } + } + + await this.client.startClient({ + initialSyncLimit: this.initialSyncLimit, + }); + this.started = true; + await this.refreshDmCache().catch(noop); + } + + stop(): void { + this.client.stopClient(); + this.started = false; + } + + async getUserId(): Promise { + const fromClient = this.client.getUserId(); + if (fromClient) { + this.selfUserId = fromClient; + return fromClient; + } + if (this.selfUserId) { + return this.selfUserId; + } + const whoami = (await this.doRequest("GET", "/_matrix/client/v3/account/whoami")) as { + user_id?: string; + }; + const resolved = whoami.user_id?.trim(); + if (!resolved) { + throw new Error("Matrix whoami did not return user_id"); + } + this.selfUserId = resolved; + return resolved; + } + + async getJoinedRooms(): Promise { + const joined = await this.client.getJoinedRooms(); + return Array.isArray(joined.joined_rooms) ? joined.joined_rooms : []; + } + + async getJoinedRoomMembers(roomId: string): Promise { + const members = await this.client.getJoinedRoomMembers(roomId); + const joined = members?.joined; + if (!joined || typeof joined !== "object") { + return []; + } + return Object.keys(joined); + } + + async getRoomStateEvent( + roomId: string, + eventType: string, + stateKey = "", + ): Promise> { + const state = await this.client.getStateEvent(roomId, eventType, stateKey); + return (state ?? {}) as Record; + } + + async getAccountData(eventType: string): Promise | undefined> { + const event = this.client.getAccountData(eventType); + return (event?.getContent() as Record | undefined) ?? undefined; + } + + async setAccountData(eventType: string, content: Record): Promise { + await this.client.setAccountData(eventType as never, content as never); + await this.refreshDmCache().catch(noop); + } + + async resolveRoom(aliasOrRoomId: string): Promise { + if (aliasOrRoomId.startsWith("!")) { + return aliasOrRoomId; + } + if (!aliasOrRoomId.startsWith("#")) { + return aliasOrRoomId; + } + try { + const resolved = await this.client.getRoomIdForAlias(aliasOrRoomId); + return resolved.room_id ?? null; + } catch { + return null; + } + } + + async sendMessage(roomId: string, content: MessageEventContent): Promise { + const sent = await this.client.sendMessage(roomId, content as never); + return sent.event_id; + } + + async sendEvent( + roomId: string, + eventType: string, + content: Record, + ): Promise { + const sent = await this.client.sendEvent(roomId, eventType as never, content as never); + return sent.event_id; + } + + async sendStateEvent( + roomId: string, + eventType: string, + stateKey: string, + content: Record, + ): Promise { + const sent = await this.client.sendStateEvent( + roomId, + eventType as never, + content as never, + stateKey, + ); + return sent.event_id; + } + + async redactEvent(roomId: string, eventId: string, reason?: string): Promise { + const sent = await this.client.redactEvent( + roomId, + eventId, + undefined, + reason?.trim() ? { reason } : undefined, + ); + return sent.event_id; + } + + async doRequest( + method: HttpMethod, + endpoint: string, + qs?: QueryParams, + body?: unknown, + ): Promise { + return await this.requestJson({ + method, + endpoint, + qs, + body, + timeoutMs: this.localTimeoutMs, + }); + } + + async getUserProfile(userId: string): Promise<{ displayname?: string; avatar_url?: string }> { + return await this.client.getProfileInfo(userId); + } + + async joinRoom(roomId: string): Promise { + await this.client.joinRoom(roomId); + } + + mxcToHttp(mxcUrl: string): string | null { + return this.client.mxcUrlToHttp(mxcUrl, undefined, undefined, undefined, true, false, true); + } + + async downloadContent(mxcUrl: string, allowRemote = true): Promise { + const parsed = parseMxc(mxcUrl); + if (!parsed) { + throw new Error(`Invalid Matrix content URI: ${mxcUrl}`); + } + const endpoint = `/_matrix/media/v3/download/${encodeURIComponent(parsed.server)}/${encodeURIComponent(parsed.mediaId)}`; + const response = await this.requestRaw({ + method: "GET", + endpoint, + qs: { allow_remote: allowRemote }, + timeoutMs: this.localTimeoutMs, + }); + return response; + } + + async uploadContent(file: Buffer, contentType?: string, filename?: string): Promise { + const uploaded = await this.client.uploadContent(file, { + type: contentType || "application/octet-stream", + name: filename, + includeFilename: Boolean(filename), + }); + return uploaded.content_uri; + } + + async getEvent(roomId: string, eventId: string): Promise> { + return (await this.client.fetchRoomEvent(roomId, eventId)) as Record; + } + + async setTyping(roomId: string, typing: boolean, timeoutMs: number): Promise { + await this.client.sendTyping(roomId, typing, timeoutMs); + } + + async sendReadReceipt(roomId: string, eventId: string): Promise { + await this.requestJson({ + method: "POST", + endpoint: `/_matrix/client/v3/rooms/${encodeURIComponent(roomId)}/receipt/m.read/${encodeURIComponent( + eventId, + )}`, + body: {}, + timeoutMs: this.localTimeoutMs, + }); + } + + private registerBridge(): void { + if (this.bridgeRegistered) { + return; + } + this.bridgeRegistered = true; + + this.client.on(ClientEvent.Event, (event: MatrixEvent) => { + const roomId = event.getRoomId(); + if (!roomId) { + return; + } + + const raw = matrixEventToRaw(event); + const isEncryptedEvent = raw.type === "m.room.encrypted"; + this.emitter.emit("room.event", roomId, raw); + if (isEncryptedEvent) { + this.emitter.emit("room.encrypted_event", roomId, raw); + } else { + this.emitter.emit("room.message", roomId, raw); + } + + const stateKey = raw.state_key ?? ""; + const selfUserId = this.client.getUserId() ?? this.selfUserId ?? ""; + const membership = + raw.type === "m.room.member" + ? (raw.content as { membership?: string }).membership + : undefined; + if (stateKey && selfUserId && stateKey === selfUserId) { + if (membership === "invite") { + this.emitter.emit("room.invite", roomId, raw); + } else if (membership === "join") { + this.emitter.emit("room.join", roomId, raw); + } + } + + if (isEncryptedEvent) { + event.on(MatrixEventEvent.Decrypted, (decryptedEvent: MatrixEvent, err?: Error) => { + const decryptedRoomId = decryptedEvent.getRoomId() || roomId; + const decryptedRaw = matrixEventToRaw(decryptedEvent); + if (err) { + this.emitter.emit("room.failed_decryption", decryptedRoomId, decryptedRaw, err); + return; + } + const failed = + typeof (decryptedEvent as { isDecryptionFailure?: () => boolean }) + .isDecryptionFailure === "function" && + (decryptedEvent as { isDecryptionFailure: () => boolean }).isDecryptionFailure(); + if (failed) { + this.emitter.emit( + "room.failed_decryption", + decryptedRoomId, + decryptedRaw, + new Error("Matrix event failed to decrypt"), + ); + return; + } + this.emitter.emit("room.decrypted_event", decryptedRoomId, decryptedRaw); + this.emitter.emit("room.message", decryptedRoomId, decryptedRaw); + }); + } + }); + } + + private createCryptoFacade(): MatrixCryptoFacade { + return { + prepare: async (_joinedRooms: string[]) => { + // matrix-js-sdk performs crypto prep during startup; no extra work required here. + }, + updateSyncData: async ( + _toDeviceMessages: unknown, + _otkCounts: unknown, + _unusedFallbackKeyAlgs: unknown, + _changedDeviceLists: unknown, + _leftDeviceLists: unknown, + ) => { + // compatibility no-op + }, + isRoomEncrypted: async (roomId: string): Promise => { + const room = this.client.getRoom(roomId); + if (room?.hasEncryptionStateEvent()) { + return true; + } + try { + const event = await this.getRoomStateEvent(roomId, "m.room.encryption", ""); + return typeof event.algorithm === "string" && event.algorithm.length > 0; + } catch { + return false; + } + }, + requestOwnUserVerification: async (): Promise => { + const crypto = this.client.getCrypto(); + if (!crypto) { + return null; + } + return await crypto.requestOwnUserVerification(); + }, + encryptMedia: async ( + buffer: Buffer, + ): Promise<{ buffer: Buffer; file: Omit }> => { + const encrypted = Attachment.encrypt(new Uint8Array(buffer)); + const mediaInfoJson = encrypted.mediaEncryptionInfo; + if (!mediaInfoJson) { + throw new Error("Matrix media encryption failed: missing media encryption info"); + } + const parsed = JSON.parse(mediaInfoJson) as EncryptedFile; + return { + buffer: Buffer.from(encrypted.encryptedData), + file: { + key: parsed.key, + iv: parsed.iv, + hashes: parsed.hashes, + v: parsed.v, + }, + }; + }, + decryptMedia: async (file: EncryptedFile): Promise => { + const encrypted = await this.downloadContent(file.url); + const metadata: EncryptedFile = { + url: file.url, + key: file.key, + iv: file.iv, + hashes: file.hashes, + v: file.v, + }; + const attachment = new EncryptedAttachment( + new Uint8Array(encrypted), + JSON.stringify(metadata), + ); + const decrypted = Attachment.decrypt(attachment); + return Buffer.from(decrypted); + }, + }; + } + + private async refreshDmCache(): Promise { + const direct = await this.getAccountData("m.direct"); + this.dmRoomIds.clear(); + if (!direct || typeof direct !== "object") { + return; + } + for (const value of Object.values(direct)) { + if (!Array.isArray(value)) { + continue; + } + for (const roomId of value) { + if (typeof roomId === "string" && roomId.trim()) { + this.dmRoomIds.add(roomId); + } + } + } + } + + private async requestJson(params: { + method: HttpMethod; + endpoint: string; + qs?: QueryParams; + body?: unknown; + timeoutMs: number; + }): Promise { + const { response, text } = await this.performRequest({ + method: params.method, + endpoint: params.endpoint, + qs: params.qs, + body: params.body, + timeoutMs: params.timeoutMs, + }); + if (!response.ok) { + throw buildHttpError(response.status, text); + } + const contentType = response.headers.get("content-type") ?? ""; + if (contentType.includes("application/json")) { + if (!text.trim()) { + return {}; + } + return JSON.parse(text); + } + return text; + } + + private async requestRaw(params: { + method: HttpMethod; + endpoint: string; + qs?: QueryParams; + timeoutMs: number; + }): Promise { + const { response, buffer } = await this.performRequest({ + method: params.method, + endpoint: params.endpoint, + qs: params.qs, + timeoutMs: params.timeoutMs, + raw: true, + }); + if (!response.ok) { + throw buildHttpError(response.status, buffer.toString("utf8")); + } + return buffer; + } + + private async performRequest(params: { + method: HttpMethod; + endpoint: string; + qs?: QueryParams; + body?: unknown; + timeoutMs: number; + raw?: boolean; + }): Promise<{ response: Response; text: string; buffer: Buffer }> { + const baseUrl = + params.endpoint.startsWith("http://") || params.endpoint.startsWith("https://") + ? new URL(params.endpoint) + : new URL(normalizeEndpoint(params.endpoint), this.homeserver); + applyQuery(baseUrl, params.qs); + + const headers = new Headers(); + headers.set("Accept", params.raw ? "*/*" : "application/json"); + if (this.accessToken) { + headers.set("Authorization", `Bearer ${this.accessToken}`); + } + + let body: BodyInit | undefined; + if (params.body !== undefined) { + if ( + params.body instanceof Uint8Array || + params.body instanceof ArrayBuffer || + typeof params.body === "string" + ) { + body = params.body as BodyInit; + } else { + headers.set("Content-Type", "application/json"); + body = JSON.stringify(params.body); + } + } + + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), params.timeoutMs); + try { + const response = await fetchWithSafeRedirects(baseUrl, { + method: params.method, + headers, + body, + signal: controller.signal, + }); + if (params.raw) { + const bytes = Buffer.from(await response.arrayBuffer()); + return { + response, + text: bytes.toString("utf8"), + buffer: bytes, + }; + } + const text = await response.text(); + return { + response, + text, + buffer: Buffer.from(text, "utf8"), + }; + } finally { + clearTimeout(timeoutId); + } + } +} + +function matrixEventToRaw(event: MatrixEvent): MatrixRawEvent { + const unsigned = (event.getUnsigned?.() ?? {}) as { + age?: number; + redacted_because?: unknown; + }; + const raw: MatrixRawEvent = { + event_id: event.getId() ?? "", + sender: event.getSender() ?? "", + type: event.getType() ?? "", + origin_server_ts: event.getTs() ?? 0, + content: ((event.getContent?.() ?? {}) as Record) || {}, + unsigned, + }; + const stateKey = event.getStateKey?.(); + if (typeof stateKey === "string" && stateKey.length > 0) { + raw.state_key = stateKey; + } + return raw; +} + +function normalizeEndpoint(endpoint: string): string { + if (!endpoint) { + return "/"; + } + return endpoint.startsWith("/") ? endpoint : `/${endpoint}`; +} + +function applyQuery(url: URL, qs: QueryParams): void { + if (!qs) { + return; + } + for (const [key, rawValue] of Object.entries(qs)) { + if (rawValue === undefined || rawValue === null) { + continue; + } + if (Array.isArray(rawValue)) { + for (const item of rawValue) { + if (item === undefined || item === null) { + continue; + } + url.searchParams.append(key, String(item)); + } + continue; + } + url.searchParams.set(key, String(rawValue)); + } +} + +function parseMxc(url: string): { server: string; mediaId: string } | null { + const match = /^mxc:\/\/([^/]+)\/(.+)$/.exec(url.trim()); + if (!match) { + return null; + } + return { + server: match[1], + mediaId: match[2], + }; +} + +function buildHttpError(statusCode: number, bodyText: string): Error & { statusCode: number } { + let message = `Matrix HTTP ${statusCode}`; + if (bodyText.trim()) { + try { + const parsed = JSON.parse(bodyText) as { error?: string }; + if (typeof parsed.error === "string" && parsed.error.trim()) { + message = parsed.error.trim(); + } else { + message = bodyText.slice(0, 500); + } + } catch { + message = bodyText.slice(0, 500); + } + } + return Object.assign(new Error(message), { statusCode }); +} + +function isRedirectStatus(statusCode: number): boolean { + return statusCode >= 300 && statusCode < 400; +} + +async function fetchWithSafeRedirects(url: URL, init: RequestInit): Promise { + let currentUrl = new URL(url.toString()); + let method = (init.method ?? "GET").toUpperCase(); + let body = init.body; + let headers = new Headers(init.headers ?? {}); + const maxRedirects = 5; + + for (let redirectCount = 0; redirectCount <= maxRedirects; redirectCount += 1) { + const response = await fetch(currentUrl, { + ...init, + method, + body, + headers, + redirect: "manual", + }); + + if (!isRedirectStatus(response.status)) { + return response; + } + + const location = response.headers.get("location"); + if (!location) { + throw new Error(`Matrix redirect missing location header (${currentUrl.toString()})`); + } + + const nextUrl = new URL(location, currentUrl); + if (nextUrl.protocol !== currentUrl.protocol) { + throw new Error( + `Blocked cross-protocol redirect (${currentUrl.protocol} -> ${nextUrl.protocol})`, + ); + } + + if (nextUrl.origin !== currentUrl.origin) { + headers = new Headers(headers); + headers.delete("authorization"); + } + + if ( + response.status === 303 || + ((response.status === 301 || response.status === 302) && + method !== "GET" && + method !== "HEAD") + ) { + method = "GET"; + body = undefined; + headers = new Headers(headers); + headers.delete("content-type"); + headers.delete("content-length"); + } + + currentUrl = nextUrl; + } + + throw new Error(`Too many redirects while requesting ${url.toString()}`); +} diff --git a/extensions/matrix/src/matrix/send.test.ts b/extensions/matrix/src/matrix/send.test.ts index 0ebfc826f80..b31d73fd5a8 100644 --- a/extensions/matrix/src/matrix/send.test.ts +++ b/extensions/matrix/src/matrix/send.test.ts @@ -2,22 +2,6 @@ import type { PluginRuntime } from "openclaw/plugin-sdk"; import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { setMatrixRuntime } from "../runtime.js"; -vi.mock("@vector-im/matrix-bot-sdk", () => ({ - ConsoleLogger: class { - trace = vi.fn(); - debug = vi.fn(); - info = vi.fn(); - warn = vi.fn(); - error = vi.fn(); - }, - LogService: { - setLogger: vi.fn(), - }, - MatrixClient: vi.fn(), - SimpleFsStorageProvider: vi.fn(), - RustSdkCryptoStorageProvider: vi.fn(), -})); - const loadWebMediaMock = vi.fn().mockResolvedValue({ buffer: Buffer.from("media"), fileName: "photo.png", @@ -59,7 +43,7 @@ const makeClient = () => { sendMessage, uploadContent, getUserId: vi.fn().mockResolvedValue("@bot:example.org"), - } as unknown as import("@vector-im/matrix-bot-sdk").MatrixClient; + } as unknown as import("./sdk.js").MatrixClient; return { client, sendMessage, uploadContent }; }; diff --git a/extensions/matrix/src/matrix/send.ts b/extensions/matrix/src/matrix/send.ts index b9bfae4fe00..d8ae72f4137 100644 --- a/extensions/matrix/src/matrix/send.ts +++ b/extensions/matrix/src/matrix/send.ts @@ -1,5 +1,5 @@ -import type { MatrixClient } from "@vector-im/matrix-bot-sdk"; import type { PollInput } from "openclaw/plugin-sdk"; +import type { MatrixClient } from "./sdk.js"; import { getMatrixRuntime } from "../runtime.js"; import { buildPollStartContent, M_POLL_START } from "./poll-types.js"; import { resolveMatrixClient, resolveMediaMaxBytes } from "./send/client.js"; @@ -71,7 +71,6 @@ export async function sendMessageMatrix( ? buildThreadRelation(threadId, opts.replyToId) : buildReplyRelation(opts.replyToId); const sendContent = async (content: MatrixOutboundContent) => { - // @vector-im/matrix-bot-sdk uses sendMessage differently const eventId = await client.sendMessage(roomId, content); return eventId; }; @@ -175,7 +174,6 @@ export async function sendPollMatrix( const pollPayload = threadId ? { ...pollContent, "m.relates_to": buildThreadRelation(threadId) } : pollContent; - // @vector-im/matrix-bot-sdk sendEvent returns eventId string directly const eventId = await client.sendEvent(roomId, M_POLL_START, pollPayload); return { diff --git a/extensions/matrix/src/matrix/send/client.ts b/extensions/matrix/src/matrix/send/client.ts index aa0f3badb79..f23276abda4 100644 --- a/extensions/matrix/src/matrix/send/client.ts +++ b/extensions/matrix/src/matrix/send/client.ts @@ -1,4 +1,4 @@ -import type { MatrixClient } from "@vector-im/matrix-bot-sdk"; +import type { MatrixClient } from "../sdk.js"; import type { CoreConfig } from "../types.js"; import { getMatrixRuntime } from "../../runtime.js"; import { getActiveMatrixClient } from "../active-client.js"; @@ -60,7 +60,6 @@ export async function resolveMatrixClient(opts: { // Ignore crypto prep failures for one-off sends; normal sync will retry. } } - // @vector-im/matrix-bot-sdk uses start() instead of startClient() await client.start(); return { client, stopOnDone: true }; } diff --git a/extensions/matrix/src/matrix/send/media.ts b/extensions/matrix/src/matrix/send/media.ts index c4339d90057..1852c961c9c 100644 --- a/extensions/matrix/src/matrix/send/media.ts +++ b/extensions/matrix/src/matrix/send/media.ts @@ -1,3 +1,4 @@ +import { parseBuffer, type IFileInfo } from "music-metadata"; import type { DimensionalFileInfo, EncryptedFile, @@ -5,8 +6,7 @@ import type { MatrixClient, TimedFileInfo, VideoFileInfo, -} from "@vector-im/matrix-bot-sdk"; -import { parseBuffer, type IFileInfo } from "music-metadata"; +} from "../sdk.js"; import { getMatrixRuntime } from "../../runtime.js"; import { applyMatrixFormatting } from "./formatting.js"; import { diff --git a/extensions/matrix/src/matrix/send/targets.test.ts b/extensions/matrix/src/matrix/send/targets.test.ts index 0bc90327cc8..3e3610cd300 100644 --- a/extensions/matrix/src/matrix/send/targets.test.ts +++ b/extensions/matrix/src/matrix/send/targets.test.ts @@ -1,5 +1,5 @@ -import type { MatrixClient } from "@vector-im/matrix-bot-sdk"; import { beforeEach, describe, expect, it, vi } from "vitest"; +import type { MatrixClient } from "../sdk.js"; import { EventType } from "./types.js"; let resolveMatrixRoomId: typeof import("./targets.js").resolveMatrixRoomId; diff --git a/extensions/matrix/src/matrix/send/targets.ts b/extensions/matrix/src/matrix/send/targets.ts index 460559798f2..5cf67ff7c84 100644 --- a/extensions/matrix/src/matrix/send/targets.ts +++ b/extensions/matrix/src/matrix/send/targets.ts @@ -1,4 +1,4 @@ -import type { MatrixClient } from "@vector-im/matrix-bot-sdk"; +import type { MatrixClient } from "../sdk.js"; import { EventType, type MatrixDirectAccountData } from "./types.js"; function normalizeTarget(raw: string): string { diff --git a/extensions/matrix/src/matrix/send/types.ts b/extensions/matrix/src/matrix/send/types.ts index 2b91327aadb..a423294ee0e 100644 --- a/extensions/matrix/src/matrix/send/types.ts +++ b/extensions/matrix/src/matrix/send/types.ts @@ -6,7 +6,7 @@ import type { TextualMessageEventContent, TimedFileInfo, VideoFileInfo, -} from "@vector-im/matrix-bot-sdk"; +} from "../sdk.js"; // Message types export const MsgType = { @@ -85,7 +85,7 @@ export type MatrixSendResult = { }; export type MatrixSendOpts = { - client?: import("@vector-im/matrix-bot-sdk").MatrixClient; + client?: import("../sdk.js").MatrixClient; mediaUrl?: string; accountId?: string; replyToId?: string; diff --git a/extensions/matrix/src/onboarding.ts b/extensions/matrix/src/onboarding.ts index 1a9ed014c81..d66ebcd6be0 100644 --- a/extensions/matrix/src/onboarding.ts +++ b/extensions/matrix/src/onboarding.ts @@ -192,11 +192,7 @@ export const matrixOnboardingAdapter: ChannelOnboardingAdapter = { statusLines: [ `Matrix: ${configured ? "configured" : "needs homeserver + access token or password"}`, ], - selectionHint: !sdkReady - ? "install @vector-im/matrix-bot-sdk" - : configured - ? "configured" - : "needs auth", + selectionHint: !sdkReady ? "install matrix-js-sdk" : configured ? "configured" : "needs auth", }; }, configure: async ({ cfg, runtime, prompter, forceAllowFrom }) => { diff --git a/extensions/matrix/src/types.ts b/extensions/matrix/src/types.ts index c316c24bd5c..9d598575382 100644 --- a/extensions/matrix/src/types.ts +++ b/extensions/matrix/src/types.ts @@ -53,7 +53,7 @@ export type MatrixConfig = { password?: string; /** Optional device name when logging in via password. */ deviceName?: string; - /** Initial sync limit for startup (default: @vector-im/matrix-bot-sdk default). */ + /** Initial sync limit for startup (defaults to matrix-js-sdk behavior). */ initialSyncLimit?: number; /** Enable end-to-end encryption (E2EE). Default: false. */ encryption?: boolean; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 92b7e5ab59f..b6ad6d162e5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -370,12 +370,12 @@ importers: '@matrix-org/matrix-sdk-crypto-nodejs': specifier: ^0.4.0 version: 0.4.0 - '@vector-im/matrix-bot-sdk': - specifier: 0.8.0-element.3 - version: 0.8.0-element.3 markdown-it: specifier: 14.1.0 version: 14.1.0 + matrix-js-sdk: + specifier: ^40.1.0 + version: 40.1.0 music-metadata: specifier: ^11.11.2 version: 11.11.2 @@ -1471,6 +1471,10 @@ packages: resolution: {integrity: sha512-+qqgpn39XFSbsD0dFjssGO9vHEP7sTyfs8yTpt8vuqWpUpF20QMwpCZi0jpYw7GxjErNTsMshopuo8677DfGEA==} engines: {node: '>= 22'} + '@matrix-org/matrix-sdk-crypto-wasm@17.1.0': + resolution: {integrity: sha512-yKPqBvKlHSqkt/UJh+Z+zLKQP8bd19OxokXYXh3VkKbW0+C44nPHsidSwd3SH+RxT+Ck2PDRwVcVXEnUft+/2g==} + engines: {node: '>= 18'} + '@microsoft/agents-activity@1.2.3': resolution: {integrity: sha512-XRQF+AVn6f9sGDUsfDQFiwLtmqqWNhM9JIwZRzK9XQLPTQmoWwjoWz8KMKc5fuvj5Ybly3974VrqYUbDOeMyTg==} engines: {node: '>=20.0.0'} @@ -2427,9 +2431,6 @@ packages: '@scure/bip39@2.0.1': resolution: {integrity: sha512-PsxdFj/d2AcJcZDX1FXN3dDgitDDTmwf78rKZq1a6c1P1Nan1X/Sxc7667zU3U+AN60g7SxxP0YCVw2H/hBycg==} - '@selderee/plugin-htmlparser2@0.11.0': - resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==} - '@silvia-odwyer/photon-node@0.3.4': resolution: {integrity: sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==} @@ -2713,9 +2714,6 @@ packages: '@types/bun@1.3.6': resolution: {integrity: sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA==} - '@types/caseless@0.12.5': - resolution: {integrity: sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==} - '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -2734,15 +2732,12 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/express-serve-static-core@4.19.8': - resolution: {integrity: sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==} + '@types/events@3.0.3': + resolution: {integrity: sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==} '@types/express-serve-static-core@5.1.1': resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==} - '@types/express@4.17.25': - resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==} - '@types/express@5.0.6': resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==} @@ -2770,9 +2765,6 @@ packages: '@types/mime-types@2.1.4': resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==} - '@types/mime@1.3.5': - resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} @@ -2800,30 +2792,18 @@ packages: '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - '@types/request@2.48.13': - resolution: {integrity: sha512-FGJ6udDNUCjd19pp0Q3iTiDkwhYup7J8hpMW9c4k53NrccQFFWKRho6hvtPPEhnXWKvukfwAlB6DbDz4yhH5Gg==} - '@types/retry@0.12.0': resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} '@types/retry@0.12.5': resolution: {integrity: sha512-3xSjTp3v03X/lSQLkczaN9UIEwJMoMCA1+Nb5HfbJEQWogdeQIyVtTvxPXDQjZ5zws8rFQfVfRdz03ARihPJgw==} - '@types/send@0.17.6': - resolution: {integrity: sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==} - '@types/send@1.2.1': resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} - '@types/serve-static@1.15.10': - resolution: {integrity: sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==} - '@types/serve-static@2.2.0': resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} - '@types/tough-cookie@4.0.5': - resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} - '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -2880,10 +2860,6 @@ packages: '@urbit/http-api@3.0.0': resolution: {integrity: sha512-EmyPbWHWXhfYQ/9wWFcLT53VvCn8ct9ljd6QEe+UBjNPEhUPOFBLpDsDp3iPLQgg8ykSU8JMMHxp95LHCorExA==} - '@vector-im/matrix-bot-sdk@0.8.0-element.3': - resolution: {integrity: sha512-2FFo/Kz2vTnOZDv59Q0s803LHf7KzuQ2EwOYYAtO0zUKJ8pV5CPsVC/IHyFb+Fsxl3R9XWFiX529yhslb4v9cQ==} - engines: {node: '>=22.0.0'} - '@vitest/browser-playwright@4.0.18': resolution: {integrity: sha512-gfajTHVCiwpxRj1qh0Sh/5bbGLG4F/ZH/V9xvFVoFddpITfMta9YGow0W6ZpTTORv2vdJuz9TnrNSmjKvpOf4g==} peerDependencies: @@ -2961,18 +2937,14 @@ packages: link-preview-js: optional: true - '@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67': - resolution: {tarball: https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67} + '@whiskeysockets/libsignal-node@git+https://github.com/whiskeysockets/libsignal-node.git#1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67': + resolution: {commit: 1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67, repo: https://github.com/whiskeysockets/libsignal-node.git, type: git} version: 2.0.1 abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} - accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} - accepts@2.0.0: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} @@ -2999,9 +2971,6 @@ packages: ajv: optional: true - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} @@ -3058,16 +3027,6 @@ packages: resolution: {integrity: sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==} engines: {node: '>=12.17'} - array-flatten@1.1.1: - resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - - asn1@0.2.6: - resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} - - assert-plus@1.0.0: - resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} - engines: {node: '>=0.8'} - assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -3083,9 +3042,6 @@ packages: ast-v8-to-istanbul@0.3.11: resolution: {integrity: sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==} - async-lock@1.4.1: - resolution: {integrity: sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==} - async-mutex@0.5.0: resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==} @@ -3109,32 +3065,22 @@ packages: resolution: {integrity: sha512-En9AY6EG1qYqEy5L/quryzbA4akBpJrnBZNxeKTqGHC2xT9Qc4aZ8b7CcbOMFTTc/MGdoNyp+SN4zInZNKxMYA==} engines: {node: '>=14'} - aws-sign2@0.7.0: - resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} - - aws4@1.13.2: - resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} - axios@1.13.4: resolution: {integrity: sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + base-x@5.0.1: + resolution: {integrity: sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - basic-auth@2.0.1: - resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} - engines: {node: '>= 0.8'} - basic-ftp@5.1.0: resolution: {integrity: sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==} engines: {node: '>=10.0.0'} - bcrypt-pbkdf@1.0.2: - resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} - before-after-hook@4.0.0: resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} @@ -3144,13 +3090,6 @@ packages: birpc@4.0.0: resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} - bluebird@3.7.2: - resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} - - body-parser@1.20.4: - resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - body-parser@2.2.2: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} @@ -3170,6 +3109,9 @@ packages: browser-or-node@1.3.0: resolution: {integrity: sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg==} + bs58@6.0.0: + resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==} + buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} @@ -3198,9 +3140,6 @@ packages: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} - caseless@0.12.0: - resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} - chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} @@ -3297,10 +3236,6 @@ packages: console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} - content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} - content-disposition@1.0.1: resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} engines: {node: '>=18'} @@ -3309,9 +3244,6 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - cookie-signature@1.0.7: - resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} - cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} @@ -3323,9 +3255,6 @@ packages: core-js@3.48.0: resolution: {integrity: sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==} - core-util-is@1.0.2: - resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} - core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -3350,10 +3279,6 @@ packages: curve25519-js@0.0.4: resolution: {integrity: sha512-axn2UMEnkhyDUPWOwVKBMVIzSQy2ejH2xRGy1wq81dqRwApXfIzfbE3hIX0ZRFBIihf/KDqK158DLwESu4AK1w==} - dashdash@1.14.1: - resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} - engines: {node: '>=0.10'} - data-uri-to-buffer@4.0.1: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} @@ -3362,14 +3287,6 @@ packages: resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} engines: {node: '>= 14'} - debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -3383,10 +3300,6 @@ packages: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} @@ -3405,10 +3318,6 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} - destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -3459,9 +3368,6 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - ecc-jsbn@0.1.2: - resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} - ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} @@ -3528,10 +3434,6 @@ packages: escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - escodegen@2.1.0: resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} engines: {node: '>=6.0'} @@ -3567,14 +3469,14 @@ packages: eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + expect-type@1.3.0: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} - express@4.22.1: - resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} - engines: {node: '>= 0.10.0'} - express@5.2.1: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} @@ -3582,19 +3484,12 @@ packages: extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - extsprintf@1.3.0: - resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} - engines: {'0': node >=0.6.0} - fast-content-type-parse@3.0.0: resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} @@ -3627,10 +3522,6 @@ packages: resolution: {integrity: sha512-vqIlNogKeyD3yzrm0yhRMQg8hOVwYcYRfjEoODd49iCprMn4HL85gK3HcykQE53EPIpX3HcAbGA5ELQv216dAQ==} engines: {node: '>=16'} - finalhandler@1.3.2: - resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} - engines: {node: '>= 0.8'} - finalhandler@2.1.1: resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} engines: {node: '>= 18.0.0'} @@ -3655,9 +3546,6 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - forever-agent@0.6.1: - resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} - form-data@2.5.4: resolution: {integrity: sha512-Y/3MmRiR8Nd+0CUtrbvcKtKzLWiUfpQ7DFVggH8PwmGt/0r7RSy32GuP4hpCJlQNEBusisSx1DLtD8uD386HJQ==} engines: {node: '>= 0.12'} @@ -3671,10 +3559,6 @@ packages: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} - fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - fresh@2.0.0: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} @@ -3732,12 +3616,6 @@ packages: resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} engines: {node: '>= 14'} - getpass@0.1.7: - resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} - - glob-to-regexp@0.4.1: - resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me @@ -3770,15 +3648,6 @@ packages: resolution: {integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==} engines: {node: '>=18'} - har-schema@2.0.0: - resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} - engines: {node: '>=4'} - - har-validator@5.1.5: - resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==} - engines: {node: '>=6'} - deprecated: this library is no longer supported - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -3798,9 +3667,6 @@ packages: has-unicode@2.0.1: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} - hash.js@1.1.7: - resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} - hashery@1.4.0: resolution: {integrity: sha512-Wn2i1In6XFxl8Az55kkgnFRiAlIAushzh26PTjL2AKtQcEfXrcLa7Hn5QOWGZEf3LU057P9TwwZjFyxfS1VuvQ==} engines: {node: '>=20'} @@ -3832,19 +3698,9 @@ packages: html-escaper@3.0.3: resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} - html-to-text@9.0.5: - resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==} - engines: {node: '>=14'} - - htmlencode@0.0.4: - resolution: {integrity: sha512-0uDvNVpzj/E2TfvLLyyXhKBRvF1y84aZsyRxRXFsQobnHaL4pcaXk+Y9cnFlvnxrBLeXDNq/VJBD+ngdBgQG1w==} - htmlparser2@10.1.0: resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} - htmlparser2@8.0.2: - resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} - http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} @@ -3853,18 +3709,10 @@ packages: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} - http-signature@1.2.0: - resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} - engines: {node: '>=0.8', npm: '>=1.3.7'} - https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - iconv-lite@0.7.2: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} @@ -3923,12 +3771,9 @@ packages: resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} engines: {node: '>=12'} - is-plain-object@5.0.0: - resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} - engines: {node: '>=0.10.0'} - - is-promise@2.2.2: - resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} + is-network-error@1.3.0: + resolution: {integrity: sha512-6oIwpsgRfnDiyEDLMay/GqCl3HoAtH5+RUKW29gYkL0QA+ipzpDLA16yQs7/RHCSu+BwgbJaOUqa4A99qNVQVw==} + engines: {node: '>=16'} is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} @@ -3937,9 +3782,6 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - is-typedarray@1.0.0: - resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - is-unicode-supported@1.3.0: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} @@ -3958,9 +3800,6 @@ packages: resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} engines: {node: '>=16'} - isstream@0.1.2: - resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} - istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -3986,9 +3825,6 @@ packages: js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} - jsbn@0.1.1: - resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} - jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -4005,18 +3841,9 @@ packages: resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} engines: {node: '>=16'} - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} - - json-stringify-safe@5.0.1: - resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -4029,10 +3856,6 @@ packages: resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} engines: {node: '>=12', npm: '>=6'} - jsprim@1.4.2: - resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} - engines: {node: '>=0.6.0'} - jszip@3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} @@ -4046,6 +3869,10 @@ packages: jws@4.0.1: resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + jwt-decode@4.0.0: + resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} + engines: {node: '>=18'} + keyv@5.6.0: resolution: {integrity: sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==} @@ -4053,9 +3880,6 @@ packages: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} - leac@0.6.0: - resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} - lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} @@ -4198,9 +4022,6 @@ packages: lodash.pickby@4.6.0: resolution: {integrity: sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==} - lodash@4.17.23: - resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} - log-symbols@6.0.0: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} engines: {node: '>=18'} @@ -4209,16 +4030,16 @@ packages: resolution: {integrity: sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==} engines: {node: '>=18'} + loglevel@1.9.2: + resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} + engines: {node: '>= 0.6.0'} + long@4.0.0: resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} long@5.3.2: resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} - lowdb@1.0.0: - resolution: {integrity: sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ==} - engines: {node: '>=4'} - lowdb@7.0.1: resolution: {integrity: sha512-neJAj8GwF0e8EpycYIDFqEPcx9Qz4GUho20jWFR7YiFeXzF1YMLdxB36PypcTSPMA+4+LvgyMacYhlr18Zlymw==} engines: {node: '>=18'} @@ -4269,13 +4090,19 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + matrix-events-sdk@0.0.1: + resolution: {integrity: sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==} + + matrix-js-sdk@40.1.0: + resolution: {integrity: sha512-BuCCcA97j5r4S4YY6ECFduQjlkD03jtH/X52R/mmuVuP3hYBbHS3BYl4gOTiwTwFK4eoYNIhY90E6d6XneMnRg==} + engines: {node: '>=22.0.0'} + + matrix-widget-api@1.17.0: + resolution: {integrity: sha512-5FHoo3iEP3Bdlv5jsYPWOqj+pGdFQNLWnJLiB0V7Ygne7bb+Gsj3ibyFyHWC6BVw+Z+tSW4ljHpO17I9TwStwQ==} + mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} - media-typer@1.1.0: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} @@ -4283,17 +4110,10 @@ packages: memory-stream@1.0.0: resolution: {integrity: sha512-Wm13VcsPIMdG96dzILfij09PvuS3APtcKNh7M28FsCA/w6+1mjR7hhPmfFNoilX9xU7wTdhsH5lJAm6XNzdtww==} - merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} - merge-descriptors@2.0.0: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} - methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} - mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -4310,18 +4130,10 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} - mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - mimic-function@5.0.1: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} - minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - minimatch@10.1.2: resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==} engines: {node: 20 || >=22} @@ -4341,18 +4153,9 @@ packages: resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} engines: {node: '>= 18'} - mkdirp@3.0.1: - resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} - engines: {node: '>=10'} - hasBin: true - module-details-from-path@1.0.4: resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} - morgan@1.10.1: - resolution: {integrity: sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==} - engines: {node: '>= 0.8.0'} - mpg123-decoder@1.0.3: resolution: {integrity: sha512-+fjxnWigodWJm3+4pndi+KUg9TBojgn31DPk85zEsim7C6s0X5Ztc/hQYdytXkwuGXH+aB0/aEkG40Emukv6oQ==} @@ -4360,9 +4163,6 @@ packages: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} engines: {node: '>=10'} - ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -4383,10 +4183,6 @@ packages: engines: {node: ^18 || >=20} hasBin: true - negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} - negotiator@1.0.0: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} @@ -4465,9 +4261,6 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - oauth-sign@0.9.0: - resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} - object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -4490,6 +4283,10 @@ packages: ogg-opus-decoder@1.7.3: resolution: {integrity: sha512-w47tiZpkLgdkpa+34VzYD8mHUj8I9kfWVZa82mBbNwDvB1byfLXSSzW/HxA4fI3e9kVlICSpXGFwMLV1LPdjwg==} + oidc-client-ts@3.4.1: + resolution: {integrity: sha512-jNdst/U28Iasukx/L5MP6b274Vr7ftQs6qAhPBCvz6Wt5rPCA+Q/tUmCzfCHHWweWw5szeMy2Gfrm1rITwUKrw==} + engines: {node: '>=18'} + ollama@0.6.3: resolution: {integrity: sha512-KEWEhIqE5wtfzEIZbDCLH51VFZ6Z3ZSa6sIOg/E/tBV8S51flyqBOXi+bRxlOYKDf8i327zG9eSTb8IJxvm3Zg==} @@ -4497,18 +4294,10 @@ packages: resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} engines: {node: '>=14.0.0'} - on-finished@2.3.0: - resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} - engines: {node: '>= 0.8'} - on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} - on-headers@1.1.0: - resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} - engines: {node: '>= 0.8'} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -4586,6 +4375,10 @@ packages: resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} engines: {node: '>=8'} + p-retry@7.1.1: + resolution: {integrity: sha512-J5ApzjyRkkf601HpEeykoiCvzHQjWxPAHhyjFcEUP2SWq0+35NKh8TLhpLw+Dkq5TZBFvUM6UigdE9hIVYTl5w==} + engines: {node: '>=20'} + p-timeout@3.2.0: resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} engines: {node: '>=8'} @@ -4616,9 +4409,6 @@ packages: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} - parse-srcset@1.0.2: - resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==} - parse5-htmlparser2-tree-adapter@6.0.1: resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} @@ -4628,9 +4418,6 @@ packages: parse5@6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} - parseley@0.12.1: - resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==} - parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -4650,9 +4437,6 @@ packages: resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} engines: {node: 20 || >=22} - path-to-regexp@0.1.12: - resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} - path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} @@ -4663,12 +4447,6 @@ packages: resolution: {integrity: sha512-sm6TxKTtWv1Oh6n3C6J6a8odejb5uO4A4zo/2dgkHuC0iu8ZMAXOezEODkVaoVp8nX1Xzr+0WxFJJmUr45hQzg==} engines: {node: '>=20.16.0 || >=22.3.0'} - peberminta@0.9.0: - resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==} - - performance-now@2.1.0: - resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -4676,10 +4454,6 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} - pify@3.0.0: - resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} - engines: {node: '>=4'} - pino-abstract-transport@2.0.0: resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} @@ -4712,10 +4486,6 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} - postgres@3.4.8: - resolution: {integrity: sha512-d+JFcLM17njZaOLkv6SCev7uoLaBtfK86vMUXhW1Z4glPWh4jozno9APvW/XKFJ3CCxVoC7OL38BqRydtu5nGg==} - engines: {node: '>=12'} - pretty-bytes@6.1.1: resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} engines: {node: ^14.13.1 || >=16.0.0} @@ -4777,17 +4547,10 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - psl@1.15.0: - resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} - punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - qified@0.6.0: resolution: {integrity: sha512-tsSGN1x3h569ZSU1u6diwhltLyfUWDp3YbFHedapTmpBl0B3P6U3+Qptg7xu+v+1io1EwhdPyyRHYbEw0KN2FA==} engines: {node: '>=20'} @@ -4806,9 +4569,6 @@ packages: quansync@1.0.0: resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} - querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} - quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} @@ -4816,10 +4576,6 @@ packages: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} - raw-body@2.5.3: - resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} - engines: {node: '>= 0.8'} - raw-body@3.0.2: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} @@ -4846,24 +4602,6 @@ packages: reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} - request-promise-core@1.1.4: - resolution: {integrity: sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==} - engines: {node: '>=0.10.0'} - peerDependencies: - request: ^2.34 - - request-promise@4.2.6: - resolution: {integrity: sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==} - engines: {node: '>=0.10.0'} - deprecated: request-promise has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142 - peerDependencies: - request: ^2.34 - - request@2.88.2: - resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} - engines: {node: '>= 6'} - deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -4876,9 +4614,6 @@ packages: resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==} engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'} - requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -4944,11 +4679,9 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sanitize-html@2.17.0: - resolution: {integrity: sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA==} - - selderee@0.11.0: - resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==} + sdp-transform@3.0.0: + resolution: {integrity: sha512-gfYVRGxjHkGF2NPeUWHw5u6T/KGFtS5/drPms73gaSuMaVHKCY3lpLnGDfswVQO0kddeePoti09AwhYP4zA8dQ==} + hasBin: true semver@7.7.3: resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} @@ -4960,18 +4693,10 @@ packages: engines: {node: '>=10'} hasBin: true - send@0.19.2: - resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} - engines: {node: '>= 0.8.0'} - send@1.2.1: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} - serve-static@1.16.3: - resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} - engines: {node: '>= 0.8.0'} - serve-static@2.2.1: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} @@ -5109,11 +4834,6 @@ packages: sqlite-vec@0.1.7-alpha.2: resolution: {integrity: sha512-rNgRCv+4V4Ed3yc33Qr+nNmjhtrMnnHzXfLVPeGb28Dx5mmDL3Ngw/Wk8vhCGjj76+oC6gnkmMG8y73BZWGBwQ==} - sshpk@1.18.0: - resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} - engines: {node: '>=0.10.0'} - hasBin: true - stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -5132,13 +4852,6 @@ packages: resolution: {integrity: sha512-wiS21Jthlvl1to+oorePvcyrIkiG/6M3D3VTmDUlJm7Cy6SbFhKkAvX+YBuHLxck/tO3mrdpC/cNesigQc3+UQ==} engines: {node: '>=16.0.0'} - stealthy-require@1.1.1: - resolution: {integrity: sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==} - engines: {node: '>=0.10.0'} - - steno@0.4.4: - resolution: {integrity: sha512-EEHMVYHNXFHfGtgjNITnka0aHhiAlo93F7z2/Pwd+g0teG9CnM3JIINM7hVVB5/rhw9voufD7Wukwgtw2uqh6w==} - steno@4.0.2: resolution: {integrity: sha512-yhPIQXjrlt1xv7dyPQg2P17URmXbuM5pdGkpiMB3RenprfiBlvK415Lctfe0eshk90oA7/tNq7WEiMK8RSP39A==} engines: {node: '>=18'} @@ -5237,10 +4950,6 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - tough-cookie@4.1.3: - resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} - engines: {node: '>=6'} - tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -5292,16 +5001,6 @@ packages: engines: {node: '>=18.0.0'} hasBin: true - tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - - tweetnacl@0.14.5: - resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} - - type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} - type-is@2.0.1: resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} engines: {node: '>= 0.6'} @@ -5342,16 +5041,15 @@ packages: resolution: {integrity: sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==} engines: {node: '>=20.18.1'} + unhomoglyph@1.0.6: + resolution: {integrity: sha512-7uvcWI3hWshSADBu4JpnyYbTVc7YlhF5GDW/oPD5AxIxl34k4wXR3WDkPnzLxkN32LiTCTKMQLtKVZiwki3zGg==} + universal-github-app-jwt@2.2.2: resolution: {integrity: sha512-dcmbeSrOdTnsjGjUfAlqNDJrhxXizjAz94ija9Qw8YkZ1uu0d+GoZzyH+Jb9tIIqvGsadUfwg+22k5aDqqwzbw==} universal-user-agent@7.0.3: resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} - universalify@0.2.0: - resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} - engines: {node: '>= 4.0.0'} - universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -5370,29 +5068,18 @@ packages: synckit: optional: true - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - url-join@4.0.1: resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} - url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - uuid@11.1.0: resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true - uuid@3.4.0: - resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} - deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + uuid@13.0.0: + resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==} hasBin: true uuid@8.3.2: @@ -5407,10 +5094,6 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - verror@1.10.0: - resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} - engines: {'0': node >=0.6.0} - vite@7.3.1: resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -6587,7 +6270,7 @@ snapshots: '@larksuiteoapi/node-sdk@1.58.0': dependencies: - axios: 1.13.4 + axios: 1.13.4(debug@4.4.3) lodash.identity: 3.0.0 lodash.merge: 4.6.2 lodash.pickby: 4.6.0 @@ -6603,7 +6286,7 @@ snapshots: dependencies: '@types/node': 24.10.11 optionalDependencies: - axios: 1.13.4 + axios: 1.13.4(debug@4.4.3) transitivePeerDependencies: - debug @@ -6778,6 +6461,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@matrix-org/matrix-sdk-crypto-wasm@17.1.0': {} + '@microsoft/agents-activity@1.2.3': dependencies: debug: 4.4.3 @@ -6806,7 +6491,7 @@ snapshots: '@azure/core-auth': 1.10.1 '@azure/msal-node': 3.8.6 '@microsoft/agents-activity': 1.2.3 - axios: 1.13.4 + axios: 1.13.4(debug@4.4.3) jsonwebtoken: 9.0.3 jwks-rsa: 3.2.2 object-path: 0.11.8 @@ -7624,11 +7309,6 @@ snapshots: '@noble/hashes': 2.0.1 '@scure/base': 2.0.0 - '@selderee/plugin-htmlparser2@0.11.0': - dependencies: - domhandler: 5.0.3 - selderee: 0.11.0 - '@silvia-odwyer/photon-node@0.3.4': {} '@sinclair/typebox@0.34.48': {} @@ -7641,7 +7321,7 @@ snapshots: '@slack/types': 2.19.0 '@slack/web-api': 7.13.0 '@types/express': 5.0.6 - axios: 1.13.4 + axios: 1.13.4(debug@4.4.3) express: 5.2.1 path-to-regexp: 8.3.0 raw-body: 3.0.2 @@ -7687,7 +7367,7 @@ snapshots: '@slack/types': 2.19.0 '@types/node': 25.2.1 '@types/retry': 0.12.0 - axios: 1.13.4 + axios: 1.13.4(debug@4.4.3) eventemitter3: 5.0.4 form-data: 2.5.4 is-electron: 2.2.2 @@ -8097,8 +7777,6 @@ snapshots: bun-types: 1.3.6 optional: true - '@types/caseless@0.12.5': {} - '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 @@ -8116,12 +7794,7 @@ snapshots: '@types/estree@1.0.8': {} - '@types/express-serve-static-core@4.19.8': - dependencies: - '@types/node': 25.2.1 - '@types/qs': 6.14.0 - '@types/range-parser': 1.2.7 - '@types/send': 1.2.1 + '@types/events@3.0.3': {} '@types/express-serve-static-core@5.1.1': dependencies: @@ -8130,13 +7803,6 @@ snapshots: '@types/range-parser': 1.2.7 '@types/send': 1.2.1 - '@types/express@4.17.25': - dependencies: - '@types/body-parser': 1.19.6 - '@types/express-serve-static-core': 4.19.8 - '@types/qs': 6.14.0 - '@types/serve-static': 1.15.10 - '@types/express@5.0.6': dependencies: '@types/body-parser': 1.19.6 @@ -8165,8 +7831,6 @@ snapshots: '@types/mime-types@2.1.4': {} - '@types/mime@1.3.5': {} - '@types/ms@2.1.0': {} '@types/node@10.17.60': {} @@ -8193,39 +7857,19 @@ snapshots: '@types/range-parser@1.2.7': {} - '@types/request@2.48.13': - dependencies: - '@types/caseless': 0.12.5 - '@types/node': 25.2.1 - '@types/tough-cookie': 4.0.5 - form-data: 2.5.4 - '@types/retry@0.12.0': {} '@types/retry@0.12.5': {} - '@types/send@0.17.6': - dependencies: - '@types/mime': 1.3.5 - '@types/node': 25.2.1 - '@types/send@1.2.1': dependencies: '@types/node': 25.2.1 - '@types/serve-static@1.15.10': - dependencies: - '@types/http-errors': 2.0.5 - '@types/node': 25.2.1 - '@types/send': 0.17.6 - '@types/serve-static@2.2.0': dependencies: '@types/http-errors': 2.0.5 '@types/node': 25.2.1 - '@types/tough-cookie@4.0.5': {} - '@types/trusted-types@2.0.7': {} '@types/ws@8.18.1': @@ -8279,30 +7923,6 @@ snapshots: browser-or-node: 1.3.0 core-js: 3.48.0 - '@vector-im/matrix-bot-sdk@0.8.0-element.3': - dependencies: - '@matrix-org/matrix-sdk-crypto-nodejs': 0.4.0 - '@types/express': 4.17.25 - '@types/request': 2.48.13 - another-json: 0.2.0 - async-lock: 1.4.1 - chalk: 4.1.2 - express: 4.22.1 - glob-to-regexp: 0.4.1 - hash.js: 1.1.7 - html-to-text: 9.0.5 - htmlencode: 0.0.4 - lowdb: 1.0.0 - lru-cache: 10.4.3 - mkdirp: 3.0.1 - morgan: 1.10.1 - postgres: 3.4.8 - request: 2.88.2 - request-promise: 4.2.6(request@2.88.2) - sanitize-html: 2.17.0 - transitivePeerDependencies: - - supports-color - '@vitest/browser-playwright@4.0.18(playwright@1.58.2)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18)': dependencies: '@vitest/browser': 4.0.18(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18) @@ -8416,7 +8036,7 @@ snapshots: '@cacheable/node-cache': 1.7.6 '@hapi/boom': 9.1.4 async-mutex: 0.5.0 - libsignal: '@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67' + libsignal: '@whiskeysockets/libsignal-node@git+https://github.com/whiskeysockets/libsignal-node.git#1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67' lru-cache: 11.2.5 music-metadata: 11.11.2 p-queue: 9.1.0 @@ -8431,7 +8051,7 @@ snapshots: - supports-color - utf-8-validate - '@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67': + '@whiskeysockets/libsignal-node@git+https://github.com/whiskeysockets/libsignal-node.git#1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67': dependencies: curve25519-js: 0.0.4 protobufjs: 6.8.8 @@ -8440,11 +8060,6 @@ snapshots: dependencies: event-target-shim: 5.0.1 - accepts@1.3.8: - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - accepts@2.0.0: dependencies: mime-types: 3.0.2 @@ -8462,13 +8077,6 @@ snapshots: optionalDependencies: ajv: 8.17.1 - ajv@6.12.6: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - ajv@8.17.1: dependencies: fast-deep-equal: 3.1.3 @@ -8519,14 +8127,6 @@ snapshots: array-back@6.2.2: {} - array-flatten@1.1.1: {} - - asn1@0.2.6: - dependencies: - safer-buffer: 2.1.2 - - assert-plus@1.0.0: {} - assertion-error@2.0.1: {} ast-kit@3.0.0-beta.1: @@ -8545,8 +8145,6 @@ snapshots: estree-walker: 3.0.3 js-tokens: 10.0.0 - async-lock@1.4.1: {} - async-mutex@0.5.0: dependencies: tslib: 2.8.1 @@ -8577,18 +8175,6 @@ snapshots: audio-type@2.2.1: optional: true - aws-sign2@0.7.0: {} - - aws4@1.13.2: {} - - axios@1.13.4: - dependencies: - follow-redirects: 1.15.11 - form-data: 2.5.4 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - axios@1.13.4(debug@4.4.3): dependencies: follow-redirects: 1.15.11(debug@4.4.3) @@ -8599,43 +8185,18 @@ snapshots: balanced-match@1.0.2: {} + base-x@5.0.1: {} + base64-js@1.5.1: {} - basic-auth@2.0.1: - dependencies: - safe-buffer: 5.1.2 - basic-ftp@5.1.0: {} - bcrypt-pbkdf@1.0.2: - dependencies: - tweetnacl: 0.14.5 - before-after-hook@4.0.0: {} bignumber.js@9.3.1: {} birpc@4.0.0: {} - bluebird@3.7.2: {} - - body-parser@1.20.4: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.1 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.14.1 - raw-body: 2.5.3 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - body-parser@2.2.2: dependencies: bytes: 3.1.2 @@ -8662,6 +8223,10 @@ snapshots: browser-or-node@1.3.0: {} + bs58@6.0.0: + dependencies: + base-x: 5.0.1 + buffer-equal-constant-time@1.0.1: {} buffer-from@1.1.2: {} @@ -8693,8 +8258,6 @@ snapshots: call-bind-apply-helpers: 1.0.2 get-intrinsic: 1.3.0 - caseless@0.12.0: {} - chai@6.2.2: {} chalk-template@0.4.0: @@ -8799,24 +8362,16 @@ snapshots: console-control-strings@1.1.0: {} - content-disposition@0.5.4: - dependencies: - safe-buffer: 5.2.1 - content-disposition@1.0.1: {} content-type@1.0.5: {} - cookie-signature@1.0.7: {} - cookie-signature@1.2.2: {} cookie@0.7.2: {} core-js@3.48.0: {} - core-util-is@1.0.2: {} - core-util-is@1.0.3: {} croner@10.0.1: {} @@ -8841,26 +8396,16 @@ snapshots: curve25519-js@0.0.4: {} - dashdash@1.14.1: - dependencies: - assert-plus: 1.0.0 - data-uri-to-buffer@4.0.1: {} data-uri-to-buffer@6.0.2: {} - debug@2.6.9: - dependencies: - ms: 2.0.0 - debug@4.4.3: dependencies: ms: 2.1.3 deep-extend@0.6.0: {} - deepmerge@4.3.1: {} - defu@6.1.4: {} degenerator@5.0.1: @@ -8875,8 +8420,6 @@ snapshots: depd@2.0.0: {} - destroy@1.2.0: {} - detect-libc@2.1.2: {} diff@8.0.3: {} @@ -8919,11 +8462,6 @@ snapshots: eastasianwidth@0.2.0: {} - ecc-jsbn@0.1.2: - dependencies: - jsbn: 0.1.1 - safer-buffer: 2.1.2 - ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer: 5.2.1 @@ -8996,8 +8534,6 @@ snapshots: escape-html@1.0.3: {} - escape-string-regexp@4.0.0: {} - escodegen@2.1.0: dependencies: esprima: 4.0.1 @@ -9024,43 +8560,9 @@ snapshots: eventemitter3@5.0.4: {} - expect-type@1.3.0: {} + events@3.3.0: {} - express@4.22.1: - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.4 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.0.7 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.3.2 - fresh: 0.5.2 - http-errors: 2.0.1 - merge-descriptors: 1.0.3 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.12 - proxy-addr: 2.0.7 - qs: 6.14.1 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.19.2 - serve-static: 1.16.3 - setprototypeof: 1.2.0 - statuses: 2.0.2 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color + expect-type@1.3.0: {} express@5.2.1: dependencies: @@ -9097,14 +8599,10 @@ snapshots: extend@3.0.2: {} - extsprintf@1.3.0: {} - fast-content-type-parse@3.0.0: {} fast-deep-equal@3.1.3: {} - fast-json-stable-stringify@2.1.0: {} - fast-uri@3.1.0: {} fast-xml-parser@5.3.4: @@ -9135,18 +8633,6 @@ snapshots: dependencies: filename-reserved-regex: 3.0.0 - finalhandler@1.3.2: - dependencies: - debug: 2.6.9 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.2 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - finalhandler@2.1.1: dependencies: debug: 4.4.3 @@ -9164,8 +8650,6 @@ snapshots: flatbuffers@24.12.23: {} - follow-redirects@1.15.11: {} - follow-redirects@1.15.11(debug@4.4.3): optionalDependencies: debug: 4.4.3 @@ -9175,8 +8659,6 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - forever-agent@0.6.1: {} - form-data@2.5.4: dependencies: asynckit: 0.4.0 @@ -9192,8 +8674,6 @@ snapshots: forwarded@0.2.0: {} - fresh@0.5.2: {} - fresh@2.0.0: {} fs-extra@11.3.3: @@ -9272,12 +8752,6 @@ snapshots: transitivePeerDependencies: - supports-color - getpass@0.1.7: - dependencies: - assert-plus: 1.0.0 - - glob-to-regexp@0.4.1: {} - glob@10.5.0: dependencies: foreground-child: 3.3.1 @@ -9328,13 +8802,6 @@ snapshots: transitivePeerDependencies: - supports-color - har-schema@2.0.0: {} - - har-validator@5.1.5: - dependencies: - ajv: 6.12.6 - har-schema: 2.0.0 - has-flag@4.0.0: {} has-own@1.0.1: {} @@ -9347,11 +8814,6 @@ snapshots: has-unicode@2.0.1: {} - hash.js@1.1.7: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - hashery@1.4.0: dependencies: hookified: 1.15.1 @@ -9376,16 +8838,6 @@ snapshots: html-escaper@3.0.3: {} - html-to-text@9.0.5: - dependencies: - '@selderee/plugin-htmlparser2': 0.11.0 - deepmerge: 4.3.1 - dom-serializer: 2.0.0 - htmlparser2: 8.0.2 - selderee: 0.11.0 - - htmlencode@0.0.4: {} - htmlparser2@10.1.0: dependencies: domelementtype: 2.3.0 @@ -9393,13 +8845,6 @@ snapshots: domutils: 3.2.2 entities: 7.0.1 - htmlparser2@8.0.2: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.2.2 - entities: 4.5.0 - http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -9415,12 +8860,6 @@ snapshots: transitivePeerDependencies: - supports-color - http-signature@1.2.0: - dependencies: - assert-plus: 1.0.0 - jsprim: 1.4.2 - sshpk: 1.18.0 - https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 @@ -9428,10 +8867,6 @@ snapshots: transitivePeerDependencies: - supports-color - iconv-lite@0.4.24: - dependencies: - safer-buffer: 2.1.2 - iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 @@ -9506,16 +8941,12 @@ snapshots: is-interactive@2.0.0: {} - is-plain-object@5.0.0: {} - - is-promise@2.2.2: {} + is-network-error@1.3.0: {} is-promise@4.0.0: {} is-stream@2.0.1: {} - is-typedarray@1.0.0: {} - is-unicode-supported@1.3.0: {} is-unicode-supported@2.1.0: {} @@ -9526,8 +8957,6 @@ snapshots: isexe@3.1.1: {} - isstream@0.1.2: {} - istanbul-lib-coverage@3.2.2: {} istanbul-lib-report@3.0.1: @@ -9553,8 +8982,6 @@ snapshots: js-tokens@10.0.0: {} - jsbn@0.1.1: {} - jsesc@3.1.0: {} json-bigint@1.0.0: @@ -9568,14 +8995,8 @@ snapshots: '@babel/runtime': 7.28.6 ts-algebra: 2.0.0 - json-schema-traverse@0.4.1: {} - json-schema-traverse@1.0.0: {} - json-schema@0.4.0: {} - - json-stringify-safe@5.0.1: {} - json5@2.2.3: {} jsonfile@6.2.0: @@ -9597,13 +9018,6 @@ snapshots: ms: 2.1.3 semver: 7.7.4 - jsprim@1.4.2: - dependencies: - assert-plus: 1.0.0 - extsprintf: 1.3.0 - json-schema: 0.4.0 - verror: 1.10.0 - jszip@3.10.1: dependencies: lie: 3.3.0 @@ -9632,14 +9046,14 @@ snapshots: jwa: 2.0.1 safe-buffer: 5.2.1 + jwt-decode@4.0.0: {} + keyv@5.6.0: dependencies: '@keyv/serialize': 1.1.1 klona@2.0.6: {} - leac@0.6.0: {} - lie@3.3.0: dependencies: immediate: 3.0.6 @@ -9754,8 +9168,6 @@ snapshots: lodash.pickby@4.6.0: {} - lodash@4.17.23: {} - log-symbols@6.0.0: dependencies: chalk: 5.6.2 @@ -9766,18 +9178,12 @@ snapshots: is-unicode-supported: 2.1.0 yoctocolors: 2.1.2 + loglevel@1.9.2: {} + long@4.0.0: {} long@5.3.2: {} - lowdb@1.0.0: - dependencies: - graceful-fs: 4.2.11 - is-promise: 2.2.2 - lodash: 4.17.23 - pify: 3.0.0 - steno: 0.4.4 - lowdb@7.0.1: dependencies: steno: 4.0.2 @@ -9826,9 +9232,31 @@ snapshots: math-intrinsics@1.1.0: {} - mdurl@2.0.0: {} + matrix-events-sdk@0.0.1: {} - media-typer@0.3.0: {} + matrix-js-sdk@40.1.0: + dependencies: + '@babel/runtime': 7.28.6 + '@matrix-org/matrix-sdk-crypto-wasm': 17.1.0 + another-json: 0.2.0 + bs58: 6.0.0 + content-type: 1.0.5 + jwt-decode: 4.0.0 + loglevel: 1.9.2 + matrix-events-sdk: 0.0.1 + matrix-widget-api: 1.17.0 + oidc-client-ts: 3.4.1 + p-retry: 7.1.1 + sdp-transform: 3.0.0 + unhomoglyph: 1.0.6 + uuid: 13.0.0 + + matrix-widget-api@1.17.0: + dependencies: + '@types/events': 3.0.3 + events: 3.3.0 + + mdurl@2.0.0: {} media-typer@1.1.0: {} @@ -9836,12 +9264,8 @@ snapshots: dependencies: readable-stream: 3.6.2 - merge-descriptors@1.0.3: {} - merge-descriptors@2.0.0: {} - methods@1.1.2: {} - mime-db@1.52.0: {} mime-db@1.54.0: {} @@ -9854,12 +9278,8 @@ snapshots: dependencies: mime-db: 1.54.0 - mime@1.6.0: {} - mimic-function@5.0.1: {} - minimalistic-assert@1.0.1: {} - minimatch@10.1.2: dependencies: '@isaacs/brace-expansion': 5.0.1 @@ -9876,20 +9296,8 @@ snapshots: dependencies: minipass: 7.1.2 - mkdirp@3.0.1: {} - module-details-from-path@1.0.4: {} - morgan@1.10.1: - dependencies: - basic-auth: 2.0.1 - debug: 2.6.9 - depd: 2.0.0 - on-finished: 2.3.0 - on-headers: 1.1.0 - transitivePeerDependencies: - - supports-color - mpg123-decoder@1.0.3: dependencies: '@wasm-audio-decoders/common': 9.0.7 @@ -9897,8 +9305,6 @@ snapshots: mrmime@2.0.1: {} - ms@2.0.0: {} - ms@2.1.3: {} music-metadata@11.11.2: @@ -9926,8 +9332,6 @@ snapshots: nanoid@5.1.6: {} - negotiator@0.6.3: {} - negotiator@1.0.0: {} netmask@2.0.2: {} @@ -10040,8 +9444,6 @@ snapshots: dependencies: boolbase: 1.0.0 - oauth-sign@0.9.0: {} - object-assign@4.1.1: {} object-inspect@1.13.4: {} @@ -10072,22 +9474,20 @@ snapshots: opus-decoder: 0.7.11 optional: true + oidc-client-ts@3.4.1: + dependencies: + jwt-decode: 4.0.0 + ollama@0.6.3: dependencies: whatwg-fetch: 3.6.20 on-exit-leak-free@2.1.2: {} - on-finished@2.3.0: - dependencies: - ee-first: 1.1.1 - on-finished@2.4.1: dependencies: ee-first: 1.1.1 - on-headers@1.1.0: {} - once@1.4.0: dependencies: wrappy: 1.0.2 @@ -10176,6 +9576,10 @@ snapshots: '@types/retry': 0.12.0 retry: 0.13.1 + p-retry@7.1.1: + dependencies: + is-network-error: 1.3.0 + p-timeout@3.2.0: dependencies: p-finally: 1.0.0 @@ -10208,8 +9612,6 @@ snapshots: parse-ms@4.0.0: {} - parse-srcset@1.0.2: {} - parse5-htmlparser2-tree-adapter@6.0.1: dependencies: parse5: 6.0.1 @@ -10218,11 +9620,6 @@ snapshots: parse5@6.0.1: {} - parseley@0.12.1: - dependencies: - leac: 0.6.0 - peberminta: 0.9.0 - parseurl@1.3.3: {} partial-json@0.1.7: {} @@ -10239,8 +9636,6 @@ snapshots: lru-cache: 11.2.5 minipass: 7.1.2 - path-to-regexp@0.1.12: {} - path-to-regexp@8.3.0: {} pathe@2.0.3: {} @@ -10250,16 +9645,10 @@ snapshots: '@napi-rs/canvas': 0.1.90 node-readable-to-web-readable-stream: 0.4.2 - peberminta@0.9.0: {} - - performance-now@2.1.0: {} - picocolors@1.1.1: {} picomatch@4.0.3: {} - pify@3.0.0: {} - pino-abstract-transport@2.0.0: dependencies: split2: 4.2.0 @@ -10300,8 +9689,6 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postgres@3.4.8: {} - pretty-bytes@6.1.1: {} pretty-ms@8.0.0: @@ -10391,14 +9778,8 @@ snapshots: proxy-from-env@1.1.0: {} - psl@1.15.0: - dependencies: - punycode: 2.3.1 - punycode.js@2.3.1: {} - punycode@2.3.1: {} - qified@0.6.0: dependencies: hookified: 1.15.1 @@ -10416,19 +9797,10 @@ snapshots: quansync@1.0.0: {} - querystringify@2.2.0: {} - quick-format-unescaped@4.0.4: {} range-parser@1.2.1: {} - raw-body@2.5.3: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.1 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - raw-body@3.0.2: dependencies: bytes: 3.1.2 @@ -10465,42 +9837,6 @@ snapshots: reflect-metadata@0.2.2: {} - request-promise-core@1.1.4(request@2.88.2): - dependencies: - lodash: 4.17.23 - request: 2.88.2 - - request-promise@4.2.6(request@2.88.2): - dependencies: - bluebird: 3.7.2 - request: 2.88.2 - request-promise-core: 1.1.4(request@2.88.2) - stealthy-require: 1.1.1 - tough-cookie: 4.1.3 - - request@2.88.2: - dependencies: - aws-sign2: 0.7.0 - aws4: 1.13.2 - caseless: 0.12.0 - combined-stream: 1.0.8 - extend: 3.0.2 - forever-agent: 0.6.1 - form-data: 2.5.4 - har-validator: 5.1.5 - http-signature: 1.2.0 - is-typedarray: 1.0.0 - isstream: 0.1.2 - json-stringify-safe: 5.0.1 - mime-types: 2.1.35 - oauth-sign: 0.9.0 - performance-now: 2.1.0 - qs: 6.14.1 - safe-buffer: 5.2.1 - tough-cookie: 4.1.3 - tunnel-agent: 0.6.0 - uuid: 3.4.0 - require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -10512,8 +9848,6 @@ snapshots: transitivePeerDependencies: - supports-color - requires-port@1.0.0: {} - resolve-pkg-maps@1.0.0: {} restore-cursor@5.1.0: @@ -10615,41 +9949,12 @@ snapshots: safer-buffer@2.1.2: {} - sanitize-html@2.17.0: - dependencies: - deepmerge: 4.3.1 - escape-string-regexp: 4.0.0 - htmlparser2: 8.0.2 - is-plain-object: 5.0.0 - parse-srcset: 1.0.2 - postcss: 8.5.6 - - selderee@0.11.0: - dependencies: - parseley: 0.12.1 + sdp-transform@3.0.0: {} semver@7.7.3: {} semver@7.7.4: {} - send@0.19.2: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.1 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - send@1.2.1: dependencies: debug: 4.4.3 @@ -10666,15 +9971,6 @@ snapshots: transitivePeerDependencies: - supports-color - serve-static@1.16.3: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.19.2 - transitivePeerDependencies: - - supports-color - serve-static@2.2.1: dependencies: encodeurl: 2.0.0 @@ -10846,18 +10142,6 @@ snapshots: sqlite-vec-linux-x64: 0.1.7-alpha.2 sqlite-vec-windows-x64: 0.1.7-alpha.2 - sshpk@1.18.0: - dependencies: - asn1: 0.2.6 - assert-plus: 1.0.0 - bcrypt-pbkdf: 1.0.2 - dashdash: 1.14.1 - ecc-jsbn: 0.1.2 - getpass: 0.1.7 - jsbn: 0.1.1 - safer-buffer: 2.1.2 - tweetnacl: 0.14.5 - stackback@0.0.2: {} statuses@2.0.2: {} @@ -10873,12 +10157,6 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.1.2 - stealthy-require@1.1.1: {} - - steno@0.4.4: - dependencies: - graceful-fs: 4.2.11 - steno@4.0.2: {} string-width@4.2.3: @@ -10977,13 +10255,6 @@ snapshots: totalist@3.0.1: {} - tough-cookie@4.1.3: - dependencies: - psl: 1.15.0 - punycode: 2.3.1 - universalify: 0.2.0 - url-parse: 1.5.10 - tr46@0.0.3: {} tree-kill@1.2.2: {} @@ -11030,17 +10301,6 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - tunnel-agent@0.6.0: - dependencies: - safe-buffer: 5.2.1 - - tweetnacl@0.14.5: {} - - type-is@1.6.18: - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 - type-is@2.0.1: dependencies: content-type: 1.0.5 @@ -11070,12 +10330,12 @@ snapshots: undici@7.21.0: {} + unhomoglyph@1.0.6: {} + universal-github-app-jwt@2.2.2: {} universal-user-agent@7.0.3: {} - universalify@0.2.0: {} - universalify@2.0.1: {} unpipe@1.0.0: {} @@ -11084,24 +10344,13 @@ snapshots: dependencies: rolldown: 1.0.0-rc.3 - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - url-join@4.0.1: {} - url-parse@1.5.10: - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - util-deprecate@1.0.2: {} - utils-merge@1.0.1: {} - uuid@11.1.0: {} - uuid@3.4.0: {} + uuid@13.0.0: {} uuid@8.3.2: {} @@ -11109,12 +10358,6 @@ snapshots: vary@1.1.2: {} - verror@1.10.0: - dependencies: - assert-plus: 1.0.0 - core-util-is: 1.0.2 - extsprintf: 1.3.0 - vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2): dependencies: esbuild: 0.27.3