diff --git a/apps/web/src/speech/browserVoiceInput.ts b/apps/web/src/speech/browserVoiceInput.ts index 1d04f96bba0e2..95460cc39877a 100644 --- a/apps/web/src/speech/browserVoiceInput.ts +++ b/apps/web/src/speech/browserVoiceInput.ts @@ -11,7 +11,7 @@ import { import type { PreparedConnection } from "@t3tools/client-runtime/connection"; import type { SpeechTranscriptionOptions, SpeechStreamText } from "@t3tools/contracts"; -import { runtime } from "../lib/runtime"; +import { speechRuntime as runtime } from "./runtime"; import { createBrowserPcmCapture } from "./browserPcmCapture"; export function createBrowserVoiceInputPlatform(input: { diff --git a/apps/web/src/speech/runtime.browser.test.ts b/apps/web/src/speech/runtime.browser.test.ts new file mode 100644 index 0000000000000..0e4de55e8bdde --- /dev/null +++ b/apps/web/src/speech/runtime.browser.test.ts @@ -0,0 +1,25 @@ +import { RelayConnectionTarget, type PreparedConnection } from "@t3tools/client-runtime/connection"; +import { getEnvironmentSpeechStatus } from "@t3tools/client-runtime/voice-input"; +import { EnvironmentId } from "@t3tools/contracts"; +import { expect, it } from "vite-plus/test"; + +import { speechRuntime } from "./runtime"; + +it("authorizes relay speech requests through the connection session", async () => { + const target = new RelayConnectionTarget({ + environmentId: EnvironmentId.make("speech-relay-test"), + label: "Speech destination", + }); + const prepared: PreparedConnection = { + target, + environmentId: target.environmentId, + label: target.label, + httpBaseUrl: "https://speech.example.test", + socketUrl: "wss://speech.example.test/ws", + httpAuthorization: { _tag: "Dpop", accessToken: "expired", expiresAtEpochMs: 0 }, + }; + // No account is signed in: renewal must reach the authorizer rather than fail on a missing service. + await expect(speechRuntime.runPromise(getEnvironmentSpeechStatus(prepared))).rejects.toThrow( + "Could not authorize the environment request.", + ); +}); diff --git a/apps/web/src/speech/runtime.ts b/apps/web/src/speech/runtime.ts new file mode 100644 index 0000000000000..22c338d7138e2 --- /dev/null +++ b/apps/web/src/speech/runtime.ts @@ -0,0 +1,17 @@ +import * as Effect from "effect/Effect"; +import type { HttpClient } from "effect/http"; +import { AtomRegistry } from "effect/reactivity"; + +import { connectionAtomRuntime } from "../connection/runtime"; +import { appAtomRegistry } from "../rpc/atomRegistry"; + +export const speechRuntime = { + runPromise: ( + effect: Effect.Effect, + options?: { signal?: AbortSignal }, + ) => + Effect.runPromise( + AtomRegistry.getResult(appAtomRegistry, connectionAtomRuntime.atom(effect)), + options, + ), +}; diff --git a/apps/web/src/speech/useEnvironmentSpeechInput.browser.test.tsx b/apps/web/src/speech/useEnvironmentSpeechInput.browser.test.tsx index a41f359f68ef4..6d51191e31814 100644 --- a/apps/web/src/speech/useEnvironmentSpeechInput.browser.test.tsx +++ b/apps/web/src/speech/useEnvironmentSpeechInput.browser.test.tsx @@ -88,7 +88,7 @@ vi.mock("../hooks/useSettings", () => ({ ), }), })); -vi.mock("../lib/runtime", () => ({ runtime: { runPromise: Effect.runPromise } })); +vi.mock("./runtime", () => ({ speechRuntime: { runPromise: Effect.runPromise } })); vi.mock("../components/ui/toast", () => ({ toastManager: { add: vi.fn() } })); vi.mock("@t3tools/client-runtime/voice-input", async (importOriginal) => ({ ...(await importOriginal()), diff --git a/apps/web/src/speech/useEnvironmentSpeechInput.ts b/apps/web/src/speech/useEnvironmentSpeechInput.ts index 644edb303aef2..353779c5d0919 100644 --- a/apps/web/src/speech/useEnvironmentSpeechInput.ts +++ b/apps/web/src/speech/useEnvironmentSpeechInput.ts @@ -33,7 +33,7 @@ import { useClientSettingsHydrated, useEnvironmentSettings, } from "../hooks/useSettings"; -import { runtime } from "../lib/runtime"; +import { speechRuntime as runtime } from "./runtime"; import { useEnvironment } from "../state/environments"; import { useEnvironmentScope, usePreparedConnection } from "../state/session"; import { createBrowserVoiceInputPlatform } from "./browserVoiceInput";