Skip to content

Commit 1291f41

Browse files
committed
Fix port validation in bootstrap schema and readiness timeout recovery
- Use PortSchema (Int, 1-65535) for port and tailscaleServePort in DesktopBackendBootstrap instead of Schema.Number, restoring the range and integer validation that was present in the old BootstrapEnvelopeSchema. Extract PortSchema to contracts/baseSchemas.ts for shared use. - Create a window as fallback when the backend readiness probe times out, so the user isn't left with no UI and no recovery path. The web app will show a reconnection state until the backend becomes available.
1 parent b5c8ea4 commit 1291f41

4 files changed

Lines changed: 12 additions & 4 deletions

File tree

apps/desktop/src/main.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,12 @@ function startBackend(): void {
14961496
`bootstrap backend readiness warning message=${formatErrorMessage(error)}`,
14971497
);
14981498
console.warn("[desktop] backend readiness check failed during bootstrap", error);
1499+
1500+
if (isDevelopment) return;
1501+
const existingWindow = mainWindow ?? BrowserWindow.getAllWindows()[0] ?? null;
1502+
if (existingWindow !== null) return;
1503+
mainWindow = createWindow();
1504+
writeDesktopLogHeader("bootstrap main window created (readiness timeout fallback)");
14991505
}),
15001506
onOutput: (streamName, chunk) =>
15011507
Effect.sync(() => {

apps/server/src/cli.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
CommandId,
66
DesktopBackendBootstrap,
77
OrchestrationReadModel,
8+
PortSchema,
89
ProjectId,
910
type ClientOrchestrationCommand,
1011
} from "@t3tools/contracts";
@@ -67,8 +68,6 @@ import {
6768
import { WorkspacePaths } from "./workspace/Services/WorkspacePaths.ts";
6869
import { WorkspacePathsLive } from "./workspace/Layers/WorkspacePaths.ts";
6970

70-
const PortSchema = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 65535 }));
71-
7271
const modeFlag = Flag.choice("mode", RuntimeMode.literals).pipe(
7372
Flag.withDescription("Runtime mode. `desktop` keeps loopback defaults unless overridden."),
7473
Flag.optional,

packages/contracts/src/baseSchemas.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export const TrimmedNonEmptyString = TrimmedString.check(Schema.isNonEmpty());
55

66
export const NonNegativeInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
77
export const PositiveInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1));
8+
export const PortSchema = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 65535 }));
89

910
export const IsoDateTime = Schema.String;
1011
export type IsoDateTime = typeof IsoDateTime.Type;

packages/contracts/src/desktopBootstrap.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import { Schema } from "effect";
22

3+
import { PortSchema } from "./baseSchemas.ts";
4+
35
export const DesktopBackendBootstrap = Schema.Struct({
46
mode: Schema.Literal("desktop"),
57
noBrowser: Schema.Boolean,
6-
port: Schema.Number,
8+
port: PortSchema,
79
t3Home: Schema.String,
810
host: Schema.String,
911
desktopBootstrapToken: Schema.String,
1012
tailscaleServeEnabled: Schema.Boolean,
11-
tailscaleServePort: Schema.Number,
13+
tailscaleServePort: PortSchema,
1214
otlpTracesUrl: Schema.optional(Schema.String),
1315
otlpMetricsUrl: Schema.optional(Schema.String),
1416
});

0 commit comments

Comments
 (0)