- Prefer `T3CODE_STATE_DIR` from env when `--state-dir` is unset or blank - Throw on invalid `T3CODE_PORT` overrides and always recompute `VITE_WS_URL` - Add tests for env/state-dir precedence, blank overrides, and invalid ports
Unified · Split
| @@ -151,8 +151,18 @@ export function parseDevRunnerArgs(rawArgs) { · 150 unmodified lines | |||
| 151 | }; | 151 | }; |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | function resolveStateDir(envOverrides) { | 154 | function resolveStateDir(env, envOverrides) { |
| 155 | return envOverrides.T3CODE_STATE_DIR ?? DEFAULT_DEV_STATE_DIR; | 155 | const overrideValue = envOverrides?.T3CODE_STATE_DIR?.trim(); |
| 156 | if (overrideValue) { | ||
| 157 | return overrideValue; | ||
| 158 | } | ||
| 159 | |||
| 160 | const envValue = env?.T3CODE_STATE_DIR?.trim(); | ||
| 161 | if (envValue) { | ||
| 162 | return envValue; | ||
| 163 | } | ||
| 164 | |||
| 165 | return DEFAULT_DEV_STATE_DIR; | ||
| 156 | } | 166 | } |
| 157 | 167 | ||
| 158 | export function createDevRunnerEnv({ mode, env, offset, envOverrides }) { | 168 | export function createDevRunnerEnv({ mode, env, offset, envOverrides }) { |
| @@ -169,12 +179,15 @@ export function createDevRunnerEnv({ mode, env, offset, envOverrides }) { · 10 unmodified lines | |||
| 169 | ...envOverrides, | 179 | ...envOverrides, |
| 170 | }; | 180 | }; |
| 171 | 181 | ||
| 172 | output.T3CODE_STATE_DIR = resolveStateDir(envOverrides); | 182 | output.T3CODE_STATE_DIR = resolveStateDir(env, envOverrides); |
| 173 | 183 | ||
| 174 | const parsedServerPort = Number(output.T3CODE_PORT); | 184 | const parsedServerPort = Number(output.T3CODE_PORT); |
| 175 | if (Number.isInteger(parsedServerPort) && parsedServerPort > 0 && parsedServerPort <= 65535) { | 185 | if (!Number.isInteger(parsedServerPort) || parsedServerPort < 1 || parsedServerPort > 65535) { |
| 176 | output.VITE_WS_URL = `ws://localhost:${parsedServerPort}`; | 186 | throw new Error( |
| 187 | `Invalid T3CODE_PORT override: '${String(output.T3CODE_PORT)}'. Expected an integer between 1 and 65535.`, | ||
| 188 | ); | ||
| 177 | } | 189 | } |
| 190 | output.VITE_WS_URL = `ws://localhost:${parsedServerPort}`; | ||
| 178 | 191 | ||
| 179 | if (mode === "dev" || mode === "dev:server" || mode === "dev:web") { | 192 | if (mode === "dev" || mode === "dev:server" || mode === "dev:web") { |
| 180 | // Running server/web in browser mode should not inherit desktop launcher state. | 193 | // Running server/web in browser mode should not inherit desktop launcher state. |
| @@ -42,7 +42,7 @@ describe("createDevRunnerEnv", () => { · 41 unmodified lines | |||
| 42 | it("defaults state dir to ~/.t3/dev when not provided", () => { | 42 | it("defaults state dir to ~/.t3/dev when not provided", () => { |
| 43 | const env = createDevRunnerEnv({ | 43 | const env = createDevRunnerEnv({ |
| 44 | mode: "dev", | 44 | mode: "dev", |
| 45 | env: { T3CODE_STATE_DIR: "/tmp/prod-state" }, | 45 | env: {}, |
| 46 | offset: 0, | 46 | offset: 0, |
| 47 | envOverrides: {}, | 47 | envOverrides: {}, |
| 48 | }); | 48 | }); |
| @@ -50,6 +50,17 @@ describe("createDevRunnerEnv", () => { · 1 unmodified line | |||
| 50 | expect(env.T3CODE_STATE_DIR).toBe(DEFAULT_DEV_STATE_DIR); | 50 | expect(env.T3CODE_STATE_DIR).toBe(DEFAULT_DEV_STATE_DIR); |
| 51 | }); | 51 | }); |
| 52 | 52 | ||
| 53 | it("uses existing env state dir when --state-dir is not provided", () => { | ||
| 54 | const env = createDevRunnerEnv({ | ||
| 55 | mode: "dev:server", | ||
| 56 | env: { T3CODE_STATE_DIR: "/tmp/existing-state" }, | ||
| 57 | offset: 0, | ||
| 58 | envOverrides: {}, | ||
| 59 | }); | ||
| 60 | |||
| 61 | expect(env.T3CODE_STATE_DIR).toBe("/tmp/existing-state"); | ||
| 62 | }); | ||
| 63 | |||
| 53 | it("lets --state-dir override existing env state dir", () => { | 64 | it("lets --state-dir override existing env state dir", () => { |
| 54 | const env = createDevRunnerEnv({ | 65 | const env = createDevRunnerEnv({ |
| 55 | mode: "dev:server", | 66 | mode: "dev:server", |
| @@ -61,6 +72,17 @@ describe("createDevRunnerEnv", () => { · 5 unmodified lines | |||
| 61 | expect(env.T3CODE_STATE_DIR).toBe("/tmp/override-state"); | 72 | expect(env.T3CODE_STATE_DIR).toBe("/tmp/override-state"); |
| 62 | }); | 73 | }); |
| 63 | 74 | ||
| 75 | it("treats whitespace-only --state-dir as missing and falls back to env/default", () => { | ||
| 76 | const env = createDevRunnerEnv({ | ||
| 77 | mode: "dev:server", | ||
| 78 | env: { T3CODE_STATE_DIR: "/tmp/existing-state" }, | ||
| 79 | offset: 0, | ||
| 80 | envOverrides: { T3CODE_STATE_DIR: " " }, | ||
| 81 | }); | ||
| 82 | |||
| 83 | expect(env.T3CODE_STATE_DIR).toBe("/tmp/existing-state"); | ||
| 84 | }); | ||
| 85 | |||
| 64 | it("recomputes websocket url when port is overridden", () => { | 86 | it("recomputes websocket url when port is overridden", () => { |
| 65 | const env = createDevRunnerEnv({ | 87 | const env = createDevRunnerEnv({ |
| 66 | mode: "dev", | 88 | mode: "dev", |
| @@ -89,4 +111,15 @@ describe("createDevRunnerEnv", () => { · 22 unmodified lines | |||
| 89 | expect(env.T3CODE_NO_BROWSER).toBe("1"); | 111 | expect(env.T3CODE_NO_BROWSER).toBe("1"); |
| 90 | expect(env.T3CODE_AUTH_TOKEN).toBe("cli-token"); | 112 | expect(env.T3CODE_AUTH_TOKEN).toBe("cli-token"); |
| 91 | }); | 113 | }); |
| 114 | |||
| 115 | it("fails fast for invalid port overrides", () => { | ||
| 116 | expect(() => | ||
| 117 | createDevRunnerEnv({ | ||
| 118 | mode: "dev", | ||
| 119 | env: {}, | ||
| 120 | offset: 0, | ||
| 121 | envOverrides: { T3CODE_PORT: "not-a-port" }, | ||
| 122 | }), | ||
| 123 | ).toThrow("Invalid T3CODE_PORT override"); | ||
| 124 | }); | ||
| 92 | }); | 125 | }); |