1import { EnvironmentId, type ExecutionEnvironmentDescriptor } from "@t3tools/contracts";
2import * as Effect from "effect/Effect";
3import { afterEach, beforeEach, describe, expect, it, vi } from "vite-plus/test";
4
5import {
6 getPrimaryKnownEnvironment,
7 isDesktopEnvironmentBootstrapIncompleteError,
8 isPrimaryEnvironmentProtocolUnsupportedError,
9 isPrimaryEnvironmentUrlInvalidError,
10 readPrimaryEnvironmentTarget,
11 resolvePrimaryEnvironmentHttpUrl,
12 resolveInitialPrimaryEnvironmentDescriptor,
13 resetPrimaryEnvironmentDescriptorForTests,
14 writePrimaryEnvironmentDescriptor,
15} from ".";
16import { installEnvironmentHttpTest } from "../../../test/environmentHttpTest";
17
18const BASE_ENVIRONMENT = {
19 environmentId: EnvironmentId.make("environment-local"),
20 label: "Local environment",
21 platform: {
22 os: "darwin",
23 arch: "arm64",
24 },
25 serverVersion: "0.0.0-test",
26 capabilities: {
27 repositoryIdentity: true,
28 },
29} satisfies ExecutionEnvironmentDescriptor;
30
31let disposeHttpTest: (() => Promise<void>) | undefined;
32
33async function installDescriptorApi() {
34 const testApi = await installEnvironmentHttpTest({
35 descriptor: () => Effect.succeed(BASE_ENVIRONMENT),
36 });
37 disposeHttpTest = testApi.dispose;
38 return testApi;
39}
40
41function installTestBrowser(url: string) {
42 vi.stubGlobal("window", {
43 location: new URL(url),
44 history: {
45 replaceState: vi.fn(),
46 },
47 });
48}
49
50function captureThrown(run: () => unknown): unknown {
51 try {
52 run();
53 } catch (error) {
54 return error;
55 }
56 throw new Error("Expected the operation to throw.");
57}
58
59describe("environmentBootstrap", () => {
60 beforeEach(() => {
61 vi.restoreAllMocks();
62 vi.useRealTimers();
63 installTestBrowser("http://localhost/");
64 });
65
66 afterEach(async () => {
67 await disposeHttpTest?.();
68 disposeHttpTest = undefined;
69 resetPrimaryEnvironmentDescriptorForTests();
70 vi.unstubAllEnvs();
71 vi.useRealTimers();
72 vi.restoreAllMocks();
73 vi.unstubAllGlobals();
74 });
75
76 it("attaches the bootstrapped environment descriptor to the primary environment", () => {
77 vi.stubGlobal("window", {
78 location: {
79 origin: "http://localhost:3773",
80 },
81 desktopBridge: undefined,
82 });
83 writePrimaryEnvironmentDescriptor({
84 environmentId: EnvironmentId.make("environment-local"),
85 label: "Bootstrapped environment",
86 platform: {
87 os: "darwin",
88 arch: "arm64",
89 },
90 serverVersion: "0.0.0-test",
91 capabilities: {
92 repositoryIdentity: true,
93 },
94 });
95
96 expect(getPrimaryKnownEnvironment()).toEqual({
97 id: "environment-local",
98 label: "Bootstrapped environment",
99 source: "window-origin",
100 environmentId: "environment-local",
101 target: {
102 httpBaseUrl: "http://localhost:3773/",
103 wsBaseUrl: "ws://localhost:3773/",
104 },
105 });
106 });
107
108 it("reuses an in-flight descriptor bootstrap request", async () => {
109 const testApi = await installDescriptorApi();
110
111 await Promise.all([
112 resolveInitialPrimaryEnvironmentDescriptor(),
113 resolveInitialPrimaryEnvironmentDescriptor(),
114 ]);
115
116 expect(testApi.calls.descriptor).toBe(1);
117 });
118
119 it("uses https descriptor urls when the primary environment uses wss", async () => {
120 vi.stubEnv("VITE_HTTP_URL", "https://remote.example.com");
121 vi.stubEnv("VITE_WS_URL", "wss://remote.example.com");
122 await installDescriptorApi();
123
124 await expect(resolveInitialPrimaryEnvironmentDescriptor()).resolves.toEqual(BASE_ENVIRONMENT);
125 expect(resolvePrimaryEnvironmentHttpUrl("/.well-known/t3/environment")).toBe(
126 "https://remote.example.com/.well-known/t3/environment",
127 );
128 });
129
130 it("keeps configured environment paths in primary descriptor and auth URLs", async () => {
131 vi.stubEnv("VITE_HTTP_URL", "https://hub.example/prefix/environments/one/?old=1#fragment");
132 await installDescriptorApi();
133 await expect(resolveInitialPrimaryEnvironmentDescriptor()).resolves.toEqual(BASE_ENVIRONMENT);
134 expect(resolvePrimaryEnvironmentHttpUrl("/.well-known/t3/environment")).toBe(
135 "https://hub.example/prefix/environments/one/.well-known/t3/environment",
136 );
137 expect(readPrimaryEnvironmentTarget()?.target.wsBaseUrl).toBe(
138 "wss://hub.example/prefix/environments/one/",
139 );
140 expect(resolvePrimaryEnvironmentHttpUrl("/api/auth/session", { token: "ticket" })).toBe(
141 "https://hub.example/prefix/environments/one/api/auth/session?token=ticket",
142 );
143 });
144
145 it("derives the websocket url when only VITE_HTTP_URL is configured", async () => {
146 vi.stubEnv("VITE_HTTP_URL", "https://remote.example.com");
147 await installDescriptorApi();
148
149 await expect(resolveInitialPrimaryEnvironmentDescriptor()).resolves.toEqual(BASE_ENVIRONMENT);
150 expect(resolvePrimaryEnvironmentHttpUrl("/.well-known/t3/environment")).toBe(
151 "https://remote.example.com/.well-known/t3/environment",
152 );
153 expect(getPrimaryKnownEnvironment()?.target).toEqual({
154 httpBaseUrl: "https://remote.example.com/",
155 wsBaseUrl: "wss://remote.example.com/",
156 });
157 });
158
159 it("derives the http url when only VITE_WS_URL is configured", async () => {
160 vi.stubEnv("VITE_WS_URL", "wss://remote.example.com");
161 await installDescriptorApi();
162
163 await expect(resolveInitialPrimaryEnvironmentDescriptor()).resolves.toEqual(BASE_ENVIRONMENT);
164 expect(resolvePrimaryEnvironmentHttpUrl("/.well-known/t3/environment")).toBe(
165 "https://remote.example.com/.well-known/t3/environment",
166 );
167 expect(getPrimaryKnownEnvironment()?.target).toEqual({
168 httpBaseUrl: "https://remote.example.com/",
169 wsBaseUrl: "wss://remote.example.com/",
170 });
171 });
172
173 it.each(["wss://hub.example/prefix/ws", "wss://hub.example/prefix/"])(
174 "derives HTTP base paths from a configured WebSocket address: %s",
175 (wsBaseUrl) => {
176 vi.stubEnv("VITE_WS_URL", wsBaseUrl);
177 expect(resolvePrimaryEnvironmentHttpUrl("/api/auth/session")).toBe(
178 "https://hub.example/prefix/api/auth/session",
179 );
180 },
181 );
182
183 it("keeps an uppercase wss scheme secure when deriving the http url", () => {
184 vi.stubEnv("VITE_WS_URL", "WSS://remote.example.com");
185
186 expect(readPrimaryEnvironmentTarget()?.target).toEqual({
187 httpBaseUrl: "https://remote.example.com/",
188 wsBaseUrl: "wss://remote.example.com/",
189 });
190 });
191
192 it("keeps an uppercase https scheme secure when deriving the websocket url", () => {
193 vi.stubEnv("VITE_HTTP_URL", "HTTPS://remote.example.com");
194
195 expect(readPrimaryEnvironmentTarget()?.target).toEqual({
196 httpBaseUrl: "https://remote.example.com/",
197 wsBaseUrl: "wss://remote.example.com/",
198 });
199 });
200
201 it("uses the current origin as the descriptor base for local dev environments", async () => {
202 installTestBrowser("http://localhost:5735/");
203 await installDescriptorApi();
204
205 await expect(resolveInitialPrimaryEnvironmentDescriptor()).resolves.toEqual(BASE_ENVIRONMENT);
206 expect(resolvePrimaryEnvironmentHttpUrl("/.well-known/t3/environment")).toBe(
207 "http://localhost:5735/.well-known/t3/environment",
208 );
209 });
210
211 it("uses the vite proxy for desktop-managed loopback descriptor requests during local dev", async () => {
212 vi.stubEnv("VITE_DEV_SERVER_URL", "http://127.0.0.1:5733");
213 vi.stubGlobal("window", {
214 location: new URL("http://127.0.0.1:5733/"),
215 history: {
216 replaceState: vi.fn(),
217 },
218 desktopBridge: {
219 getLocalEnvironmentBootstraps: () => [
220 {
221 id: "primary",
222 label: "Windows",
223 httpBaseUrl: "http://127.0.0.1:3773",
224 wsBaseUrl: "ws://127.0.0.1:3773",
225 bootstrapToken: "desktop-bootstrap-token",
226 },
227 ],
228 },
229 });
230 await installDescriptorApi();
231
232 await expect(resolveInitialPrimaryEnvironmentDescriptor()).resolves.toEqual(BASE_ENVIRONMENT);
233 expect(resolvePrimaryEnvironmentHttpUrl("/.well-known/t3/environment")).toBe(
234 "http://127.0.0.1:5733/.well-known/t3/environment",
235 );
236 });
237
238 it("retains the URL parser cause without exposing the configured URL in its message", () => {
239 vi.stubEnv("VITE_HTTP_URL", "http://[");
240
241 const error = captureThrown(readPrimaryEnvironmentTarget);
242
243 expect(isPrimaryEnvironmentUrlInvalidError(error)).toBe(true);
244 if (!isPrimaryEnvironmentUrlInvalidError(error)) {
245 throw new Error("Expected a structured primary environment URL error.");
246 }
247 expect(error).toMatchObject({
248 source: "configured",
249 urlKind: "http-base-url",
250 message: "Could not parse http-base-url for the configured primary environment target.",
251 });
252 expect(error.cause).toBeInstanceOf(TypeError);
253 expect(error.message).not.toContain("http://[");
254 });
255
256 it("describes which desktop bootstrap endpoint is missing", () => {
257 vi.stubGlobal("window", {
258 location: new URL("http://127.0.0.1:5733/"),
259 history: { replaceState: vi.fn() },
260 desktopBridge: {
261 getLocalEnvironmentBootstraps: () => [
262 {
263 id: "primary",
264 label: "Local environment",
265 httpBaseUrl: "http://127.0.0.1:3773",
266 bootstrapToken: "desktop-bootstrap-token",
267 },
268 ],
269 },
270 });
271
272 const error = captureThrown(readPrimaryEnvironmentTarget);
273
274 expect(isDesktopEnvironmentBootstrapIncompleteError(error)).toBe(true);
275 if (!isDesktopEnvironmentBootstrapIncompleteError(error)) {
276 throw new Error("Expected a structured desktop bootstrap error.");
277 }
278 expect(error).toMatchObject({
279 hasHttpBaseUrl: true,
280 hasWsBaseUrl: false,
281 message: "Desktop bootstrap is missing wsBaseUrl for the local environment.",
282 });
283 });
284
285 it("has no primary target when the desktop local environment is disabled", () => {
286 vi.stubGlobal("window", {
287 location: new URL("t3code://app/"),
288 desktopBridge: {
289 getLocalEnvironmentEnabled: () => false,
290 getLocalEnvironmentBootstraps: () => [],
291 },
292 });
293
294 expect(readPrimaryEnvironmentTarget()).toBeNull();
295 expect(getPrimaryKnownEnvironment()).toBeNull();
296 expect(() => resolvePrimaryEnvironmentHttpUrl("/api/auth/session")).toThrow(
297 "The local environment is disabled.",
298 );
299 });
300
301 it("preserves an unsupported window-origin protocol", () => {
302 vi.stubGlobal("window", {
303 location: { origin: "file:///tmp/t3code/" },
304 history: { replaceState: vi.fn() },
305 });
306
307 const error = captureThrown(readPrimaryEnvironmentTarget);
308
309 expect(isPrimaryEnvironmentProtocolUnsupportedError(error)).toBe(true);
310 if (!isPrimaryEnvironmentProtocolUnsupportedError(error)) {
311 throw new Error("Expected a structured primary environment protocol error.");
312 }
313 expect(error).toMatchObject({
314 source: "window-origin",
315 protocol: "file:",
316 message: "The window-origin primary environment target uses unsupported protocol file:.",
317 });
318 });
319});