mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
Merge main into dev (toolchain upgrades #1401)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -125,7 +125,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||
|
||||
@@ -183,7 +183,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||
|
||||
@@ -270,7 +270,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||
|
||||
@@ -329,7 +329,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||
|
||||
@@ -371,7 +371,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||
|
||||
@@ -463,7 +463,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||
|
||||
@@ -106,7 +106,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||
|
||||
@@ -296,7 +296,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||
|
||||
@@ -463,7 +463,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||
|
||||
|
||||
@@ -14,10 +14,10 @@ Rust backend in `src-tauri/` for native APIs only. LiveKit handles voice/video.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **On Node 22+ you must run `NODE_OPTIONS=--no-experimental-webstorage npm test`.**
|
||||
Native Web Storage shadows jsdom's `localStorage` and fails ~478 tests that
|
||||
have nothing to do with your change. That is a local toolchain artifact, not
|
||||
a regression — do not "fix" those failures. CI pins Node 20.
|
||||
- Node's native Web Storage (Node 22+) shadows jsdom's `localStorage`;
|
||||
`tests/setup.ts` replaces it with an in-memory shim, so the suite runs on
|
||||
modern Node without `--no-experimental-webstorage`. If storage tests fail
|
||||
en masse, suspect that shim before your change. CI pins Node 24.
|
||||
- `src/lib/dispatcher.ts` is the single WS-event entry point **into the
|
||||
stores**: server events reach domain stores only through a `ws.on(...)`
|
||||
subscription registered there. Other modules do register their own
|
||||
|
||||
Generated
+1319
-1840
File diff suppressed because it is too large
Load Diff
@@ -34,24 +34,24 @@
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@playwright/test": "^1",
|
||||
"@stryker-mutator/api": "^9.6.1",
|
||||
"@stryker-mutator/core": "^9.6.1",
|
||||
"@stryker-mutator/typescript-checker": "^9.6.1",
|
||||
"@stryker-mutator/vitest-runner": "^9.6.1",
|
||||
"@stryker-mutator/api": "^10.0.0",
|
||||
"@stryker-mutator/core": "^10.0.0",
|
||||
"@stryker-mutator/typescript-checker": "^10.0.0",
|
||||
"@stryker-mutator/vitest-runner": "^10.0.0",
|
||||
"@tauri-apps/cli": "^2",
|
||||
"@types/node": "^20.19.43",
|
||||
"@vitest/browser": "^3.2.4",
|
||||
"@vitest/coverage-v8": "^3",
|
||||
"eslint": "^10.8.1",
|
||||
"@types/node": "^24.13.3",
|
||||
"@vitest/browser-playwright": "^4.1.11",
|
||||
"@vitest/coverage-v8": "^4.1.11",
|
||||
"eslint": "^10.9.0",
|
||||
"fast-check": "^4.9.0",
|
||||
"jsdom": "^29.1.1",
|
||||
"jsdom": "^30.0.1",
|
||||
"knip": "^6.32.2",
|
||||
"oxlint": "^1.78.0",
|
||||
"oxlint": "^1.79.0",
|
||||
"prettier": "^3.9.6",
|
||||
"typescript": "^5.7",
|
||||
"typescript": "^6.0.3",
|
||||
"typescript-eslint": "^8.67.0",
|
||||
"vite": "^6",
|
||||
"vitest": "^3"
|
||||
"vite": "^8.2.2",
|
||||
"vitest": "^4.1.11"
|
||||
},
|
||||
"prettier": {
|
||||
"singleQuote": false,
|
||||
@@ -73,7 +73,7 @@
|
||||
"@tauri-apps/plugin-notification": "^2",
|
||||
"@tauri-apps/plugin-opener": "^2.5.3",
|
||||
"@tauri-apps/plugin-process": "^2.3.1",
|
||||
"livekit-client": "^2.21.0"
|
||||
"livekit-client": "^2.22.0"
|
||||
},
|
||||
"overrides": {
|
||||
"qs": "^6.15.3",
|
||||
|
||||
Generated
+776
-1117
File diff suppressed because it is too large
Load Diff
@@ -47,7 +47,7 @@ tauri-plugin-fs = "2"
|
||||
tauri-plugin-updater = "2.10"
|
||||
tauri-plugin-process = "2"
|
||||
url = "2"
|
||||
tokio-tungstenite = { version = "0.28.0", features = ["rustls-tls-webpki-roots"] }
|
||||
tokio-tungstenite = { version = "0.30.0", features = ["rustls-tls-webpki-roots"] }
|
||||
futures-util = "0.3.32"
|
||||
tokio = { version = "1", features = ["sync", "net", "io-util", "rt", "macros"] }
|
||||
tokio-rustls = { version = "0.26", default-features = false }
|
||||
|
||||
@@ -32,7 +32,9 @@ describe("AccessibilityTab — reduced-motion arbitration (OC-0232)", () => {
|
||||
beforeEach(() => {
|
||||
matchMediaListeners = new Map();
|
||||
|
||||
vi.spyOn(window, "matchMedia").mockImplementation((query: string) => {
|
||||
// jsdom does not implement matchMedia, and vitest 4's spyOn refuses to spy
|
||||
// on undefined, so stub the global instead.
|
||||
vi.stubGlobal("matchMedia", (query: string) => {
|
||||
const mql = {
|
||||
matches: matchMediaMatches,
|
||||
media: query,
|
||||
@@ -62,6 +64,7 @@ describe("AccessibilityTab — reduced-motion arbitration (OC-0232)", () => {
|
||||
document.documentElement.classList.remove("reduced-motion");
|
||||
localStorage.clear();
|
||||
vi.restoreAllMocks();
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it("keeps reduced-motion applied when OS sync is on and the OS still prefers it, even after a manual Reduce Motion toggle is switched off", () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from "vitest";
|
||||
|
||||
// Mock the Tauri HTTP plugin — vi.hoisted ensures the fn is available when
|
||||
// vi.mock's factory runs (hoisted above all imports).
|
||||
@@ -19,7 +19,7 @@ vi.mock("../../src/lib/httpProxy", () => ({
|
||||
stopHttpProxy: () => Promise.resolve(),
|
||||
}));
|
||||
|
||||
import { createApiClient, ApiClientError } from "../../src/lib/api";
|
||||
import { createApiClient, ApiClientError, type OnUnauthorized } from "../../src/lib/api";
|
||||
|
||||
function jsonResponse(data: unknown, status = 200): Response {
|
||||
return {
|
||||
@@ -54,11 +54,11 @@ function brokenJsonErrorResponse(status: number, statusText: string): Response {
|
||||
|
||||
describe("API Client", () => {
|
||||
let api: ReturnType<typeof createApiClient>;
|
||||
let onUnauthorized: ReturnType<typeof vi.fn>;
|
||||
let onUnauthorized: Mock<OnUnauthorized>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockFetch.mockReset();
|
||||
onUnauthorized = vi.fn();
|
||||
onUnauthorized = vi.fn<OnUnauthorized>();
|
||||
api = createApiClient({ host: "localhost:8443", token: "test-token" }, onUnauthorized);
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const { fetchMock, putSpy } = vi.hoisted(() => ({
|
||||
fetchMock: vi.fn<any>(),
|
||||
putSpy: vi.fn<any>(),
|
||||
putSpy: vi.fn<(value: string, key: string) => void>(),
|
||||
}));
|
||||
|
||||
vi.mock("@tauri-apps/plugin-http", () => ({
|
||||
|
||||
@@ -279,10 +279,17 @@ describe("AudioPipeline", () => {
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no worklet")) },
|
||||
};
|
||||
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
mockRoom = {
|
||||
@@ -458,7 +465,7 @@ describe("AudioPipeline", () => {
|
||||
it("handles AudioContext constructor failure gracefully", () => {
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(() => {
|
||||
vi.fn(function () {
|
||||
throw new Error("AudioContext not supported");
|
||||
}),
|
||||
);
|
||||
@@ -591,10 +598,17 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no worklet")) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation((tracks: unknown) => ({ tracks })),
|
||||
vi.fn(function (tracks: unknown) {
|
||||
return { tracks };
|
||||
}),
|
||||
);
|
||||
return { mockSender };
|
||||
}
|
||||
@@ -676,7 +690,10 @@ describe("AudioPipeline", () => {
|
||||
});
|
||||
|
||||
it("creates AudioContext with sampleRate 48000", () => {
|
||||
const AudioContextSpy = vi.fn().mockReturnValue({
|
||||
const AudioContextSpy = vi.fn(function () {
|
||||
return audioCtxForSpy;
|
||||
});
|
||||
const audioCtxForSpy = {
|
||||
resume: vi.fn().mockResolvedValue(undefined),
|
||||
createMediaStreamSource: vi.fn().mockReturnValue({ connect: vi.fn() }),
|
||||
createAnalyser: vi.fn().mockReturnValue({
|
||||
@@ -699,11 +716,13 @@ describe("AudioPipeline", () => {
|
||||
close: vi.fn().mockResolvedValue(undefined),
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||
});
|
||||
};
|
||||
vi.stubGlobal("AudioContext", AudioContextSpy);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
const mockRoom = {
|
||||
@@ -749,10 +768,17 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
const mockRoom = {
|
||||
@@ -798,10 +824,17 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
const mockRoom = {
|
||||
@@ -846,10 +879,17 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
const mockRoom = {
|
||||
@@ -911,10 +951,17 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
const mockRoom = {
|
||||
@@ -968,10 +1015,17 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
const mockRoom = {
|
||||
@@ -1046,7 +1100,9 @@ describe("AudioPipeline", () => {
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
pipeline.setRoom(mockRoom);
|
||||
@@ -1114,7 +1170,9 @@ describe("AudioPipeline", () => {
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
pipeline.setRoom(mockRoom);
|
||||
|
||||
@@ -234,10 +234,17 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -88,10 +88,17 @@ describe("AudioPipeline", () => {
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no worklet")) },
|
||||
};
|
||||
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||
@@ -164,10 +171,17 @@ describe("AudioPipeline", () => {
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no worklet")) },
|
||||
};
|
||||
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||
@@ -246,10 +260,17 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||
@@ -340,10 +361,17 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||
@@ -412,10 +440,17 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||
@@ -480,10 +515,17 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||
@@ -559,10 +601,17 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||
|
||||
@@ -81,19 +81,28 @@ describe("AudioPipeline VAD worklet teardown (OC-0231)", () => {
|
||||
|
||||
vi.stubGlobal(
|
||||
"AudioWorkletNode",
|
||||
vi.fn().mockImplementation(() => ({
|
||||
port: {
|
||||
postMessage: vi.fn(),
|
||||
onmessage: null as ((event: MessageEvent) => void) | null,
|
||||
},
|
||||
connect: vi.fn(),
|
||||
disconnect: vi.fn(),
|
||||
})),
|
||||
vi.fn(function () {
|
||||
return {
|
||||
port: {
|
||||
postMessage: vi.fn(),
|
||||
onmessage: null as ((event: MessageEvent) => void) | null,
|
||||
},
|
||||
connect: vi.fn(),
|
||||
disconnect: vi.fn(),
|
||||
};
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
mockRoom = {
|
||||
|
||||
@@ -123,19 +123,28 @@ describe("AudioPipeline", () => {
|
||||
// Mock AudioWorkletNode
|
||||
vi.stubGlobal(
|
||||
"AudioWorkletNode",
|
||||
vi.fn().mockImplementation(() => ({
|
||||
port: {
|
||||
postMessage: vi.fn(),
|
||||
onmessage: null as ((event: MessageEvent) => void) | null,
|
||||
},
|
||||
connect: vi.fn(),
|
||||
disconnect: vi.fn(),
|
||||
})),
|
||||
vi.fn(function () {
|
||||
return {
|
||||
port: {
|
||||
postMessage: vi.fn(),
|
||||
onmessage: null as ((event: MessageEvent) => void) | null,
|
||||
},
|
||||
connect: vi.fn(),
|
||||
disconnect: vi.fn(),
|
||||
};
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
mockRoom = {
|
||||
@@ -297,10 +306,17 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||
@@ -408,18 +424,27 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockReturnValue(addModulePromise) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"AudioWorkletNode",
|
||||
vi.fn().mockImplementation(() => ({
|
||||
port: { postMessage: vi.fn(), onmessage: null },
|
||||
connect: vi.fn(),
|
||||
disconnect: vi.fn(),
|
||||
})),
|
||||
vi.fn(function () {
|
||||
return {
|
||||
port: { postMessage: vi.fn(), onmessage: null },
|
||||
connect: vi.fn(),
|
||||
disconnect: vi.fn(),
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||
@@ -493,18 +518,27 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockReturnValue(addModulePromise) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"AudioWorkletNode",
|
||||
vi.fn().mockImplementation(() => ({
|
||||
port: { postMessage: vi.fn(), onmessage: null },
|
||||
connect: vi.fn(),
|
||||
disconnect: vi.fn(),
|
||||
})),
|
||||
vi.fn(function () {
|
||||
return {
|
||||
port: { postMessage: vi.fn(), onmessage: null },
|
||||
connect: vi.fn(),
|
||||
disconnect: vi.fn(),
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||
@@ -577,18 +611,27 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockResolvedValue(undefined) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"AudioWorkletNode",
|
||||
vi.fn().mockImplementation(() => ({
|
||||
port: { postMessage: vi.fn(), onmessage: null },
|
||||
connect: vi.fn(),
|
||||
disconnect: vi.fn(),
|
||||
})),
|
||||
vi.fn(function () {
|
||||
return {
|
||||
port: { postMessage: vi.fn(), onmessage: null },
|
||||
connect: vi.fn(),
|
||||
disconnect: vi.fn(),
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||
@@ -668,18 +711,27 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockResolvedValue(undefined) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"AudioWorkletNode",
|
||||
vi.fn().mockImplementation(() => ({
|
||||
port: { postMessage: postMessageSpy, onmessage: null },
|
||||
connect: vi.fn(),
|
||||
disconnect: vi.fn(),
|
||||
})),
|
||||
vi.fn(function () {
|
||||
return {
|
||||
port: { postMessage: postMessageSpy, onmessage: null },
|
||||
connect: vi.fn(),
|
||||
disconnect: vi.fn(),
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||
@@ -747,10 +799,17 @@ describe("AudioPipeline", () => {
|
||||
state: "running",
|
||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||
};
|
||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
||||
vi.stubGlobal(
|
||||
"AudioContext",
|
||||
vi.fn(function () {
|
||||
return mockAudioCtx;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal(
|
||||
"MediaStream",
|
||||
vi.fn().mockImplementation(() => ({})),
|
||||
vi.fn(function () {
|
||||
return {};
|
||||
}),
|
||||
);
|
||||
|
||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
||||
import { describe, it, expect, beforeEach, afterEach, vi, type Mock } from "vitest";
|
||||
|
||||
// Mock livekitSession (required by streamPreview). rePinPeerIdentity is hoisted
|
||||
// so the mock factory can reference it and tests can assert re-pin was invoked.
|
||||
@@ -183,15 +183,15 @@ function setAdminUser(): void {
|
||||
describe("ChannelSidebar", () => {
|
||||
let container: HTMLDivElement;
|
||||
let sidebar: ReturnType<typeof createChannelSidebar>;
|
||||
let onVoiceJoin: ReturnType<typeof vi.fn>;
|
||||
let onVoiceLeave: ReturnType<typeof vi.fn>;
|
||||
let onVoiceJoin: Mock<(channelId: number) => void>;
|
||||
let onVoiceLeave: Mock<() => void>;
|
||||
|
||||
beforeEach(() => {
|
||||
resetStores();
|
||||
container = document.createElement("div");
|
||||
document.body.appendChild(container);
|
||||
onVoiceJoin = vi.fn();
|
||||
onVoiceLeave = vi.fn();
|
||||
onVoiceJoin = vi.fn<(channelId: number) => void>();
|
||||
onVoiceLeave = vi.fn<() => void>();
|
||||
sidebar = createChannelSidebar({ onVoiceJoin, onVoiceLeave });
|
||||
});
|
||||
|
||||
@@ -2346,15 +2346,15 @@ describe("ChannelSidebar identity-mismatch modal lifetime (OC-0281)", () => {
|
||||
describe("ChannelSidebar channel feature flags", () => {
|
||||
let container: HTMLDivElement;
|
||||
let sidebar: ReturnType<typeof createChannelSidebar>;
|
||||
let onVoiceJoin: ReturnType<typeof vi.fn>;
|
||||
let onVoiceLeave: ReturnType<typeof vi.fn>;
|
||||
let onVoiceJoin: Mock<(channelId: number) => void>;
|
||||
let onVoiceLeave: Mock<() => void>;
|
||||
|
||||
beforeEach(() => {
|
||||
resetStores();
|
||||
container = document.createElement("div");
|
||||
document.body.appendChild(container);
|
||||
onVoiceJoin = vi.fn();
|
||||
onVoiceLeave = vi.fn();
|
||||
onVoiceJoin = vi.fn<(channelId: number) => void>();
|
||||
onVoiceLeave = vi.fn<() => void>();
|
||||
sidebar = createChannelSidebar({ onVoiceJoin, onVoiceLeave });
|
||||
});
|
||||
|
||||
|
||||
@@ -247,7 +247,7 @@ describe("CreateChannelModal", () => {
|
||||
|
||||
it("disables submit button and shows 'Creating...' while creating", async () => {
|
||||
let resolveCreate: (() => void) | undefined;
|
||||
const onCreate = vi.fn<any>(
|
||||
const onCreate = vi.fn<NonNullable<CreateChannelModalOptions["onCreate"]>>(
|
||||
() =>
|
||||
new Promise<void>((resolve) => {
|
||||
resolveCreate = resolve;
|
||||
|
||||
@@ -148,7 +148,7 @@ describe("DeleteChannelModal", () => {
|
||||
|
||||
it("disables button and shows 'Deleting...' during delete", async () => {
|
||||
let resolveDelete: (() => void) | undefined;
|
||||
const onConfirm = vi.fn<any>(
|
||||
const onConfirm = vi.fn<() => Promise<void>>(
|
||||
() =>
|
||||
new Promise<void>((resolve) => {
|
||||
resolveDelete = resolve;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* channels for every member of the server.
|
||||
*/
|
||||
|
||||
import { beforeEach, afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, afterEach, describe, expect, it, vi, type Mock } from "vitest";
|
||||
|
||||
import {
|
||||
attachDragHandlers,
|
||||
@@ -60,7 +60,7 @@ interface Rig {
|
||||
container: HTMLElement;
|
||||
items: Map<number, HTMLElement>;
|
||||
channels: Channel[];
|
||||
onReorder: ReturnType<typeof vi.fn>;
|
||||
onReorder: Mock<(reorders: readonly ChannelReorderData[]) => void>;
|
||||
abort: AbortController;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ function buildRig(channels: Channel[]): Rig {
|
||||
document.body.appendChild(container);
|
||||
|
||||
const items = new Map<number, HTMLElement>();
|
||||
const onReorder = vi.fn();
|
||||
const onReorder = vi.fn<(reorders: readonly ChannelReorderData[]) => void>();
|
||||
const abort = new AbortController();
|
||||
rigAborts.push(abort);
|
||||
|
||||
|
||||
@@ -259,7 +259,7 @@ describe("EditChannelModal", () => {
|
||||
|
||||
it("disables save button and shows 'Saving...' during save", async () => {
|
||||
let resolveSave: (() => void) | undefined;
|
||||
const onSave = vi.fn<any>(
|
||||
const onSave = vi.fn<(data: EditChannelData) => Promise<void>>(
|
||||
() =>
|
||||
new Promise<void>((resolve) => {
|
||||
resolveSave = resolve;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* how it shares the composer with the @-mention popup).
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
||||
import { describe, it, expect, beforeEach, afterEach, vi, type Mock } from "vitest";
|
||||
|
||||
vi.mock("@lib/livekitSession", () => ({
|
||||
leaveVoice: vi.fn(),
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
MIN_EMOJI_QUERY,
|
||||
} from "../../src/components/EmojiAutocomplete";
|
||||
import { createMessageInput } from "../../src/components/MessageInput";
|
||||
import type { MessageInputOptions } from "../../src/components/MessageInput";
|
||||
import { emojiStore, setCustomEmoji, clearCustomEmoji } from "../../src/stores/emoji.store";
|
||||
import { membersStore } from "../../src/stores/members.store";
|
||||
|
||||
@@ -336,12 +337,12 @@ describe("createEmojiAutocomplete combobox wiring", () => {
|
||||
describe("composer :shortcode integration", () => {
|
||||
let container: HTMLDivElement;
|
||||
let input: ReturnType<typeof createMessageInput>;
|
||||
let onSend: ReturnType<typeof vi.fn>;
|
||||
let onSend: Mock<MessageInputOptions["onSend"]>;
|
||||
|
||||
beforeEach(() => {
|
||||
container = document.createElement("div");
|
||||
document.body.appendChild(container);
|
||||
onSend = vi.fn();
|
||||
onSend = vi.fn<MessageInputOptions["onSend"]>();
|
||||
input = createMessageInput({
|
||||
channelId: 1,
|
||||
channelName: "general",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from "vitest";
|
||||
|
||||
const { mockVoiceGetState } = vi.hoisted(() => ({
|
||||
mockVoiceGetState: vi.fn(() => ({ currentChannelId: null as number | null })),
|
||||
@@ -20,18 +20,18 @@ vi.mock("@stores/voice.store", () => ({
|
||||
const { attachGlobalKeybinds } = await import("../../src/pages/main-page/GlobalKeybinds");
|
||||
|
||||
function makeHandlers(): {
|
||||
onSearch: ReturnType<typeof vi.fn>;
|
||||
onToggleMute: ReturnType<typeof vi.fn>;
|
||||
onToggleDeafen: ReturnType<typeof vi.fn>;
|
||||
onToggleCamera: ReturnType<typeof vi.fn>;
|
||||
onUploadFile: ReturnType<typeof vi.fn>;
|
||||
onSearch: Mock<() => void>;
|
||||
onToggleMute: Mock<() => void>;
|
||||
onToggleDeafen: Mock<() => void>;
|
||||
onToggleCamera: Mock<() => void>;
|
||||
onUploadFile: Mock<() => void>;
|
||||
} {
|
||||
return {
|
||||
onSearch: vi.fn(),
|
||||
onToggleMute: vi.fn(),
|
||||
onToggleDeafen: vi.fn(),
|
||||
onToggleCamera: vi.fn(),
|
||||
onUploadFile: vi.fn(),
|
||||
onSearch: vi.fn<() => void>(),
|
||||
onToggleMute: vi.fn<() => void>(),
|
||||
onToggleDeafen: vi.fn<() => void>(),
|
||||
onToggleCamera: vi.fn<() => void>(),
|
||||
onUploadFile: vi.fn<() => void>(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,13 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
const mockSetKey = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("livekit-client", () => ({
|
||||
ExternalE2EEKeyProvider: vi.fn(() => ({
|
||||
setKey: mockSetKey,
|
||||
getKeys: vi.fn().mockReturnValue([]),
|
||||
})),
|
||||
// vitest 4 mocks honor construct semantics — `new` needs a real function, not an arrow.
|
||||
ExternalE2EEKeyProvider: vi.fn(function () {
|
||||
return {
|
||||
setKey: mockSetKey,
|
||||
getKeys: vi.fn().mockReturnValue([]),
|
||||
};
|
||||
}),
|
||||
}));
|
||||
|
||||
const mockKeyPair = vi.hoisted(() => ({
|
||||
|
||||
@@ -47,7 +47,10 @@ const mockRoom = vi.hoisted(() => ({
|
||||
}));
|
||||
|
||||
vi.mock("livekit-client", () => ({
|
||||
Room: vi.fn(() => mockRoom),
|
||||
// vitest 4 mocks honor construct semantics — `new` needs a real function, not an arrow.
|
||||
Room: vi.fn(function () {
|
||||
return mockRoom;
|
||||
}),
|
||||
RoomEvent: {
|
||||
TrackSubscribed: "trackSubscribed",
|
||||
TrackUnsubscribed: "trackUnsubscribed",
|
||||
@@ -77,11 +80,14 @@ vi.mock("livekit-client", () => ({
|
||||
h1080fps30: { resolution: { width: 1920, height: 1080 } },
|
||||
},
|
||||
DisconnectReason: { CLIENT_INITIATED: 0 },
|
||||
ExternalE2EEKeyProvider: vi.fn(() => ({
|
||||
setKey: vi.fn(),
|
||||
getKeys: vi.fn().mockReturnValue([]),
|
||||
removeAllListeners: vi.fn(),
|
||||
})),
|
||||
// vitest 4 mocks honor construct semantics — `new` needs a real function, not an arrow.
|
||||
ExternalE2EEKeyProvider: vi.fn(function () {
|
||||
return {
|
||||
setKey: vi.fn(),
|
||||
getKeys: vi.fn().mockReturnValue([]),
|
||||
removeAllListeners: vi.fn(),
|
||||
};
|
||||
}),
|
||||
createLocalVideoTrack: vi.fn(async () => ({
|
||||
kind: "video",
|
||||
mediaStreamTrack: new MediaStreamTrack(),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { describe, it, expect, vi, beforeEach, type Mock } from "vitest";
|
||||
|
||||
// clearAuth pulls in voice/livekit/notification teardown; stub it so this test
|
||||
// stays a pure unit test of the best-effort revoke-then-teardown ordering.
|
||||
@@ -9,7 +9,7 @@ vi.mock("@stores/auth.store", () => ({
|
||||
|
||||
import { logout } from "../../src/lib/logout";
|
||||
|
||||
function makeApi(logoutImpl: () => Promise<void>): { logout: ReturnType<typeof vi.fn> } {
|
||||
function makeApi(logoutImpl: () => Promise<void>): { logout: Mock<() => Promise<void>> } {
|
||||
return { logout: vi.fn(logoutImpl) };
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,9 @@ describe("LogsTab", () => {
|
||||
let controller: AbortController;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
// vitest 4's restoreAllMocks no longer resets vi.fn() state — reset
|
||||
// explicitly so call counts don't accumulate across tests.
|
||||
vi.resetAllMocks();
|
||||
controller = new AbortController();
|
||||
mockGetLogBuffer.mockReturnValue([]);
|
||||
mockAddLogListener.mockReturnValue(() => {});
|
||||
|
||||
@@ -16,6 +16,7 @@ const disconnectMock = vi.fn();
|
||||
class MockIntersectionObserver implements IntersectionObserver {
|
||||
readonly root: Element | null = null;
|
||||
readonly rootMargin: string = "0px";
|
||||
readonly scrollMargin: string = "0px";
|
||||
readonly thresholds: readonly number[] = [0];
|
||||
constructor(callback: IntersectionObserverCallback) {
|
||||
observerCallback = callback;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* entries, keyboard navigation, and composer integration.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
||||
import { describe, it, expect, beforeEach, afterEach, vi, type Mock } from "vitest";
|
||||
|
||||
vi.mock("@lib/livekitSession", () => ({
|
||||
leaveVoice: vi.fn(),
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
MAX_MENTION_SUGGESTIONS,
|
||||
} from "../../src/components/MentionAutocomplete";
|
||||
import { createMessageInput } from "../../src/components/MessageInput";
|
||||
import type { MessageInputOptions } from "../../src/components/MessageInput";
|
||||
import { membersStore } from "../../src/stores/members.store";
|
||||
import { authStore } from "../../src/stores/auth.store";
|
||||
import { channelsStore, setRoles } from "../../src/stores/channels.store";
|
||||
@@ -132,13 +133,13 @@ describe("filterMentionSuggestions", () => {
|
||||
});
|
||||
|
||||
describe("createMentionAutocomplete", () => {
|
||||
let onSelect: ReturnType<typeof vi.fn>;
|
||||
let onClose: ReturnType<typeof vi.fn>;
|
||||
let onSelect: Mock<(token: string) => void>;
|
||||
let onClose: Mock<() => void>;
|
||||
let popup: ReturnType<typeof createMentionAutocomplete>;
|
||||
|
||||
beforeEach(() => {
|
||||
onSelect = vi.fn();
|
||||
onClose = vi.fn();
|
||||
onSelect = vi.fn<(token: string) => void>();
|
||||
onClose = vi.fn<() => void>();
|
||||
popup = createMentionAutocomplete({ onSelect, onClose });
|
||||
document.body.appendChild(popup.element);
|
||||
});
|
||||
@@ -317,12 +318,12 @@ describe("createMentionAutocomplete combobox wiring", () => {
|
||||
describe("composer integration", () => {
|
||||
let container: HTMLDivElement;
|
||||
let input: ReturnType<typeof createMessageInput>;
|
||||
let onSend: ReturnType<typeof vi.fn>;
|
||||
let onSend: Mock<MessageInputOptions["onSend"]>;
|
||||
|
||||
beforeEach(() => {
|
||||
container = document.createElement("div");
|
||||
document.body.appendChild(container);
|
||||
onSend = vi.fn();
|
||||
onSend = vi.fn<MessageInputOptions["onSend"]>();
|
||||
input = createMessageInput({
|
||||
channelId: 1,
|
||||
channelName: "general",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from "vitest";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mocks
|
||||
@@ -72,11 +72,11 @@ function makeAbort(): { signal: AbortSignal; abort: () => void } {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe("createMessageController", () => {
|
||||
let showError: ReturnType<typeof vi.fn>;
|
||||
let showError: Mock<(msg: string) => void>;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
showError = vi.fn();
|
||||
showError = vi.fn<(msg: string) => void>();
|
||||
mockIsChannelLoaded.mockReturnValue(false);
|
||||
mockGetChannelMessages.mockReturnValue([]);
|
||||
});
|
||||
|
||||
@@ -9,22 +9,27 @@ describe("syncOsMotionListener", () => {
|
||||
matchMediaListeners = new Map();
|
||||
matchMediaMatches = false;
|
||||
|
||||
// Mock matchMedia to return a controllable MediaQueryList
|
||||
vi.spyOn(window, "matchMedia").mockImplementation((_query: string) => {
|
||||
const mql = {
|
||||
matches: matchMediaMatches,
|
||||
media: _query,
|
||||
onchange: null,
|
||||
addListener: vi.fn(),
|
||||
removeListener: vi.fn(),
|
||||
addEventListener: vi.fn((type: string, handler: Function, _opts?: any) => {
|
||||
matchMediaListeners.set(type, handler);
|
||||
}),
|
||||
removeEventListener: vi.fn(),
|
||||
dispatchEvent: vi.fn(() => true),
|
||||
} as unknown as MediaQueryList;
|
||||
return mql;
|
||||
});
|
||||
// Mock matchMedia to return a controllable MediaQueryList. jsdom does not
|
||||
// implement matchMedia, and vitest 4's spyOn refuses to spy on undefined,
|
||||
// so stub the global instead.
|
||||
vi.stubGlobal(
|
||||
"matchMedia",
|
||||
vi.fn((_query: string) => {
|
||||
const mql = {
|
||||
matches: matchMediaMatches,
|
||||
media: _query,
|
||||
onchange: null,
|
||||
addListener: vi.fn(),
|
||||
removeListener: vi.fn(),
|
||||
addEventListener: vi.fn((type: string, handler: Function, _opts?: any) => {
|
||||
matchMediaListeners.set(type, handler);
|
||||
}),
|
||||
removeEventListener: vi.fn(),
|
||||
dispatchEvent: vi.fn(() => true),
|
||||
} as unknown as MediaQueryList;
|
||||
return mql;
|
||||
}),
|
||||
);
|
||||
|
||||
// Clean up any leftover class/storage from previous tests
|
||||
document.documentElement.classList.remove("reduced-motion");
|
||||
@@ -35,6 +40,7 @@ describe("syncOsMotionListener", () => {
|
||||
// Disable the listener to clean up internal state
|
||||
syncOsMotionListener(false);
|
||||
document.documentElement.classList.remove("reduced-motion");
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it("adds reduced-motion class when OS prefers reduced motion", () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from "vitest";
|
||||
import { createQuickSwitcher } from "@components/QuickSwitcher";
|
||||
import type { QuickSwitcherOptions } from "@components/QuickSwitcher";
|
||||
import { channelsStore, setChannels } from "@stores/channels.store";
|
||||
@@ -24,16 +24,16 @@ const testChannels: ReadyChannel[] = [
|
||||
describe("QuickSwitcher", () => {
|
||||
let container: HTMLDivElement;
|
||||
let switcher: ReturnType<typeof createQuickSwitcher>;
|
||||
let onSelectChannel: ReturnType<typeof vi.fn>;
|
||||
let onClose: ReturnType<typeof vi.fn>;
|
||||
let onSelectChannel: Mock<(channelId: number) => void>;
|
||||
let onClose: Mock<() => void>;
|
||||
|
||||
beforeEach(() => {
|
||||
resetStore();
|
||||
setChannels(testChannels);
|
||||
container = document.createElement("div");
|
||||
document.body.appendChild(container);
|
||||
onSelectChannel = vi.fn();
|
||||
onClose = vi.fn();
|
||||
onSelectChannel = vi.fn<(channelId: number) => void>();
|
||||
onClose = vi.fn<() => void>();
|
||||
switcher = createQuickSwitcher({ onSelectChannel, onClose });
|
||||
});
|
||||
|
||||
|
||||
@@ -369,8 +369,12 @@ describe("attachReactionTooltip", () => {
|
||||
);
|
||||
}
|
||||
|
||||
// Exactly two registrations regardless of chip count: the module's own
|
||||
// guarded listener plus the single internal bookkeeping listener jsdom
|
||||
// registers per signal for `{ signal }`-scoped DOM listeners. A per-chip
|
||||
// leak would register one per chip (50+).
|
||||
const abortRegistrations = addEventListenerSpy.mock.calls.filter(([type]) => type === "abort");
|
||||
expect(abortRegistrations).toHaveLength(1);
|
||||
expect(abortRegistrations).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("hides every currently-hovering chip on a signal when it aborts, not just the first attached", () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from "vitest";
|
||||
|
||||
const mockRetryMicPermission = vi.fn().mockResolvedValue(undefined);
|
||||
vi.mock("@lib/livekitSession", () => ({
|
||||
@@ -101,11 +101,11 @@ describe("Screen Share Button in VoiceWidget", () => {
|
||||
let container: HTMLDivElement;
|
||||
let comp: ReturnType<typeof createVoiceWidget>;
|
||||
let handlers: {
|
||||
onDisconnect: ReturnType<typeof vi.fn>;
|
||||
onMuteToggle: ReturnType<typeof vi.fn>;
|
||||
onDeafenToggle: ReturnType<typeof vi.fn>;
|
||||
onCameraToggle: ReturnType<typeof vi.fn>;
|
||||
onScreenshareToggle: ReturnType<typeof vi.fn>;
|
||||
onDisconnect: Mock<() => void>;
|
||||
onMuteToggle: Mock<() => void>;
|
||||
onDeafenToggle: Mock<() => void>;
|
||||
onCameraToggle: Mock<() => void>;
|
||||
onScreenshareToggle: Mock<() => void>;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -113,11 +113,11 @@ describe("Screen Share Button in VoiceWidget", () => {
|
||||
container = document.createElement("div");
|
||||
document.body.appendChild(container);
|
||||
handlers = {
|
||||
onDisconnect: vi.fn(),
|
||||
onMuteToggle: vi.fn(),
|
||||
onDeafenToggle: vi.fn(),
|
||||
onCameraToggle: vi.fn(),
|
||||
onScreenshareToggle: vi.fn(),
|
||||
onDisconnect: vi.fn<() => void>(),
|
||||
onMuteToggle: vi.fn<() => void>(),
|
||||
onDeafenToggle: vi.fn<() => void>(),
|
||||
onCameraToggle: vi.fn<() => void>(),
|
||||
onScreenshareToggle: vi.fn<() => void>(),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* test would sail straight past.
|
||||
*/
|
||||
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi, type Mock } from "vitest";
|
||||
import { Track } from "livekit-client";
|
||||
import type { LocalTrack, LocalVideoTrack, Room } from "livekit-client";
|
||||
import type { WsClient } from "@lib/ws";
|
||||
@@ -114,16 +114,16 @@ function fakeDeps(
|
||||
hasWs = true,
|
||||
): VideoTrackDeps & {
|
||||
wsSend: ReturnType<typeof vi.fn>;
|
||||
onError: ReturnType<typeof vi.fn>;
|
||||
reapplyAudioPipeline: ReturnType<typeof vi.fn>;
|
||||
onError: Mock<(message: string) => void>;
|
||||
reapplyAudioPipeline: Mock<() => void>;
|
||||
} {
|
||||
const wsSend = vi.fn();
|
||||
const ws = hasWs ? ({ send: wsSend } as unknown as WsClient) : null;
|
||||
return {
|
||||
getRoom: () => room,
|
||||
getWs: () => ws,
|
||||
onError: vi.fn(),
|
||||
reapplyAudioPipeline: vi.fn(),
|
||||
onError: vi.fn<(message: string) => void>(),
|
||||
reapplyAudioPipeline: vi.fn<() => void>(),
|
||||
wsSend,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -361,8 +361,12 @@ describe("streamPreview", () => {
|
||||
// A re-render re-attaches the same row to the same sidebar-lifetime signal.
|
||||
attachStreamPreview(row1, 1, "Alice", false, true, ac.signal);
|
||||
|
||||
// Exactly two registrations regardless of attach count: the module's own
|
||||
// guarded listener plus the single internal bookkeeping listener jsdom
|
||||
// registers per signal for `{ signal }`-scoped DOM listeners. A
|
||||
// per-attach leak would register one per attach call.
|
||||
const abortCalls = addSpy.mock.calls.filter(([type]) => type === "abort");
|
||||
expect(abortCalls).toHaveLength(1);
|
||||
expect(abortCalls).toHaveLength(2);
|
||||
});
|
||||
|
||||
// v091: a structural re-render (clearChildren + rebuild) detaches the old
|
||||
|
||||
@@ -443,7 +443,7 @@ describe("TOTP Settings", () => {
|
||||
// Simulate MainPage's onConfirmTotp: it calls updateUser after API success
|
||||
const options = makeOptions({
|
||||
onConfirmTotp: vi.fn().mockImplementation(async () => {
|
||||
(updateUser as ReturnType<typeof vi.fn>)({ totp_enabled: true });
|
||||
updateUser({ totp_enabled: true });
|
||||
}),
|
||||
});
|
||||
const overlay = createSettingsOverlay(options);
|
||||
@@ -659,7 +659,7 @@ describe("TOTP Settings", () => {
|
||||
// Simulate MainPage's onDisableTotp: it calls updateUser after API success
|
||||
const options = makeOptions({
|
||||
onDisableTotp: vi.fn().mockImplementation(async () => {
|
||||
(updateUser as ReturnType<typeof vi.fn>)({ totp_enabled: false });
|
||||
updateUser({ totp_enabled: false });
|
||||
}),
|
||||
});
|
||||
const overlay = createSettingsOverlay(options);
|
||||
@@ -706,7 +706,7 @@ describe("TOTP Settings", () => {
|
||||
const options = makeOptions({
|
||||
onConfirmTotp: vi.fn().mockImplementation(async () => {
|
||||
// MainPage calls updateUser here — this is the single owner
|
||||
(updateUser as ReturnType<typeof vi.fn>)({ totp_enabled: true });
|
||||
updateUser({ totp_enabled: true });
|
||||
}),
|
||||
});
|
||||
const overlay = createSettingsOverlay(options);
|
||||
@@ -751,7 +751,7 @@ describe("TOTP Settings", () => {
|
||||
mockTotpEnabled = true;
|
||||
const options = makeOptions({
|
||||
onDisableTotp: vi.fn().mockImplementation(async () => {
|
||||
(updateUser as ReturnType<typeof vi.fn>)({ totp_enabled: false });
|
||||
updateUser({ totp_enabled: false });
|
||||
}),
|
||||
});
|
||||
const overlay = createSettingsOverlay(options);
|
||||
|
||||
@@ -913,7 +913,12 @@ describe("VoiceAudioTab UI structure", () => {
|
||||
addEventListenerSpy.mock.calls.filter(([type]) => type === "abort").length;
|
||||
|
||||
const tab = createVoiceAudioTab(ac.signal);
|
||||
const afterCreate = abortListenerCount();
|
||||
|
||||
// The first build may add jsdom's single internal bookkeeping listener
|
||||
// for `{ signal }`-scoped DOM listeners; snapshot after it so the
|
||||
// assertion isolates listener growth caused by rebuilds.
|
||||
tab.build();
|
||||
const afterFirstBuild = abortListenerCount();
|
||||
|
||||
tab.build();
|
||||
tab.build();
|
||||
@@ -922,7 +927,7 @@ describe("VoiceAudioTab UI structure", () => {
|
||||
// Rebuilding the tab three times must not add three more permanent
|
||||
// "abort" listeners to the overlay-lifetime signal — only the single
|
||||
// listener the factory registers once at creation should exist.
|
||||
expect(abortListenerCount()).toBe(afterCreate);
|
||||
expect(abortListenerCount()).toBe(afterFirstBuild);
|
||||
|
||||
ac.abort();
|
||||
});
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
// App code is browser-only: reset the "types": ["node"] the dev config
|
||||
// needs for unit tests, so Node globals stay unavailable in src/.
|
||||
"compilerOptions": {
|
||||
"types": []
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": []
|
||||
}
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
// the app graph. "exclude": [] is required to clear the inherited
|
||||
// "tests/e2e" exclusion — same trick tsconfig.build.json uses.
|
||||
"extends": "./tsconfig.json",
|
||||
// TypeScript 6 defaults "types" to [] instead of every installed @types
|
||||
// package, so the Node globals (process, Buffer) used by the Playwright
|
||||
// layer must be pulled in explicitly.
|
||||
"compilerOptions": {
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": [
|
||||
"tests/e2e",
|
||||
"playwright.config.ts",
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"lib": ["ES2023", "DOM", "DOM.Iterable"],
|
||||
// TypeScript 6 defaults "types" to [] and vitest 4 no longer references
|
||||
// @types/node itself, so the Node globals (node:fs, __dirname) used by
|
||||
// unit tests must be pulled in explicitly. tsconfig.build.json resets
|
||||
// this to [] so app code cannot use Node globals.
|
||||
"types": ["node"],
|
||||
"paths": {
|
||||
"@lib/*": ["./src/lib/*"],
|
||||
"@stores/*": ["./src/stores/*"],
|
||||
|
||||
@@ -20,20 +20,22 @@ export default defineConfig({
|
||||
cssCodeSplit: false,
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
// Keep the ~1.3 MB LiveKit SDK in its own chunk, out of the entry.
|
||||
livekit: ["livekit-client"],
|
||||
// Keep the ~1.3 MB LiveKit SDK in its own chunk, out of the entry.
|
||||
// Rolldown (Vite 8) only supports the function form of manualChunks.
|
||||
manualChunks(id) {
|
||||
if (id.includes("node_modules/livekit-client/")) return "livekit";
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
"@lib": resolve(__dirname, "src/lib"),
|
||||
"@stores": resolve(__dirname, "src/stores"),
|
||||
"@components": resolve(__dirname, "src/components"),
|
||||
"@pages": resolve(__dirname, "src/pages"),
|
||||
"@styles": resolve(__dirname, "src/styles"),
|
||||
"@lib": resolve(import.meta.dirname, "src/lib"),
|
||||
"@stores": resolve(import.meta.dirname, "src/stores"),
|
||||
"@components": resolve(import.meta.dirname, "src/components"),
|
||||
"@pages": resolve(import.meta.dirname, "src/pages"),
|
||||
"@styles": resolve(import.meta.dirname, "src/styles"),
|
||||
},
|
||||
},
|
||||
clearScreen: false,
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
import { playwright } from "@vitest/browser-playwright";
|
||||
import { resolve } from "path";
|
||||
|
||||
export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
"@lib": resolve(__dirname, "src/lib"),
|
||||
"@stores": resolve(__dirname, "src/stores"),
|
||||
"@components": resolve(__dirname, "src/components"),
|
||||
"@pages": resolve(__dirname, "src/pages"),
|
||||
"@styles": resolve(__dirname, "src/styles"),
|
||||
"@lib": resolve(import.meta.dirname, "src/lib"),
|
||||
"@stores": resolve(import.meta.dirname, "src/stores"),
|
||||
"@components": resolve(import.meta.dirname, "src/components"),
|
||||
"@pages": resolve(import.meta.dirname, "src/pages"),
|
||||
"@styles": resolve(import.meta.dirname, "src/styles"),
|
||||
},
|
||||
},
|
||||
test: {
|
||||
browser: {
|
||||
enabled: true,
|
||||
provider: "playwright",
|
||||
provider: playwright(),
|
||||
instances: [{ browser: "chromium" }],
|
||||
},
|
||||
include: ["tests/browser/**/*.test.ts"],
|
||||
|
||||
@@ -4,11 +4,11 @@ import { resolve } from "path";
|
||||
export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
"@lib": resolve(__dirname, "src/lib"),
|
||||
"@stores": resolve(__dirname, "src/stores"),
|
||||
"@components": resolve(__dirname, "src/components"),
|
||||
"@pages": resolve(__dirname, "src/pages"),
|
||||
"@styles": resolve(__dirname, "src/styles"),
|
||||
"@lib": resolve(import.meta.dirname, "src/lib"),
|
||||
"@stores": resolve(import.meta.dirname, "src/stores"),
|
||||
"@components": resolve(import.meta.dirname, "src/components"),
|
||||
"@pages": resolve(import.meta.dirname, "src/pages"),
|
||||
"@styles": resolve(import.meta.dirname, "src/styles"),
|
||||
},
|
||||
},
|
||||
test: {
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@ module github.com/owncord/server
|
||||
|
||||
go 1.26
|
||||
|
||||
toolchain go1.26.6
|
||||
toolchain go1.26.7
|
||||
|
||||
require (
|
||||
aead.dev/minisign v0.3.0
|
||||
@@ -10,7 +10,7 @@ require (
|
||||
github.com/coder/websocket v1.8.15
|
||||
github.com/corazawaf/coraza-coreruleset/v4 v4.25.0
|
||||
github.com/corazawaf/coraza/v3 v3.7.0
|
||||
github.com/go-chi/chi/v5 v5.3.1
|
||||
github.com/go-chi/chi/v5 v5.3.2
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/knadh/koanf/parsers/yaml v1.1.1
|
||||
github.com/knadh/koanf/providers/env v1.1.0
|
||||
@@ -38,7 +38,7 @@ require (
|
||||
golang.org/x/sync v0.22.0
|
||||
google.golang.org/protobuf v1.36.12
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
modernc.org/sqlite v1.56.0
|
||||
modernc.org/sqlite v1.57.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
+4
-4
@@ -72,8 +72,8 @@ github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx5
|
||||
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||
github.com/gammazero/deque v1.2.1 h1:9fnQVFCCZ9/NOc7ccTNqzoKd1tCWOqeI05/lPqFPMGQ=
|
||||
github.com/gammazero/deque v1.2.1/go.mod h1:5nSFkzVm+afG9+gy0VIowlqVAW4N8zNcMne+CMQVD2g=
|
||||
github.com/go-chi/chi/v5 v5.3.1 h1:3j4HZLGZQ3JpMCrPJF/Jl3mYJfWLKBfNJ6quurUGCf8=
|
||||
github.com/go-chi/chi/v5 v5.3.1/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
|
||||
github.com/go-chi/chi/v5 v5.3.2 h1:5YQkICvTCSZ25hoRsyJazN0scjzKGiu4VAUc7H1o1nY=
|
||||
github.com/go-chi/chi/v5 v5.3.2/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
|
||||
github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
@@ -375,8 +375,8 @@ modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg=
|
||||
modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.56.0 h1:/D8e2RfFqoy/Zc6PuC76U28zFwmI/sYx1Kjm4yEn9e0=
|
||||
modernc.org/sqlite v1.56.0/go.mod h1:yCJ2cmAaIkHQ25oXWrF8H4O1lIfPYPR26yCEDj2P3pQ=
|
||||
modernc.org/sqlite v1.57.0 h1:qNQP6xnx5M0ISNtlnxoOX0+cD5bJ0/gr9aMmndFczzg=
|
||||
modernc.org/sqlite v1.57.0/go.mod h1:yCJ2cmAaIkHQ25oXWrF8H4O1lIfPYPR26yCEDj2P3pQ=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
|
||||
Reference in New Issue
Block a user