authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-02-24 14:16:29-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-02-26 13:20:36-08:00
log33ca29c2656ec6acd8986c210516f66b4a898fa9
treecddc3098e5d201ea569deb498697938e06d4b038
parent915083fae41e9dc8f68624fc4a1067d18c09c2f9

nice


1 files changed, 16 insertions(+), 26 deletions(-)

apps/server/src/main.ts+16-26
......@@ -1,18 +1,7 @@
11import net from "node:net";
22import os from "node:os";
33
4import {
5 ServiceMap,
6 Data,
7 Effect,
8 Layer,
9 Option,
10 Config,
11 Path,
12 Schema,
13 FileSystem,
14 PlatformError,
15} from "effect";
4import { ServiceMap, Data, Effect, Layer, Option, Config, Path, Schema, FileSystem } from "effect";
165import { Command, Flag } from "effect/unstable/cli";
176
187import { fixPath } from "./fixPath";
......@@ -37,7 +26,7 @@ export interface CliConfigShape {
3726 readonly cwd: string;
3827 readonly fixPath: Effect.Effect<unknown, never>;
3928 readonly findAvailablePort: (preferred: number) => Effect.Effect<number, StartupError>;
40 readonly resolveStaticDir: () => Effect.Effect<string | undefined, PlatformError.PlatformError>;
29 readonly resolveStaticDir: () => Effect.Effect<string | undefined>;
4130}
4231
4332export class CliConfig extends ServiceMap.Service<CliConfig, CliConfigShape>()(
......@@ -87,11 +76,11 @@ const resolveStateDir = Effect.fn(function* (raw: string | undefined) {
8776 return resolve(yield* expandHomePath(raw.trim()));
8877});
8978
90async function findAvailablePort(preferred: number): Promise<number> {
91 return new Promise((resolve, reject) => {
79const findAvailablePort = (preferred: number) =>
80 Effect.callback<number, StartupError>((resume) => {
9281 const server = net.createServer();
9382 server.listen(preferred, () => {
94 server.close(() => resolve(preferred));
83 server.close(() => resume(Effect.succeed(preferred)));
9584 });
9685 server.on("error", () => {
9786 const fallback = net.createServer();
......@@ -99,14 +88,20 @@ async function findAvailablePort(preferred: number): Promise<number> {
9988 const addr = fallback.address();
10089 const port = typeof addr === "object" && addr !== null ? addr.port : 0;
10190 fallback.close(() => {
102 if (port > 0) resolve(port);
103 else reject(new Error("Could not find an available port."));
91 resume(
92 port > 0
93 ? Effect.succeed(port)
94 : Effect.fail(new StartupError({ message: "Could not find an available port." })),
95 );
10496 });
10597 });
106 fallback.on("error", reject);
98 fallback.on("error", (cause) => {
99 resume(
100 Effect.fail(new StartupError({ message: "Failed to find an available port", cause })),
101 );
102 });
107103 });
108104 });
109}
110105
111106const resolveStaticDir = Effect.fn(function* () {
112107 const { join, resolve } = yield* Path.Path;
......@@ -249,12 +244,7 @@ export const CliConfigLive = Layer.effect(
249244 return {
250245 cwd: process.cwd(),
251246 fixPath: Effect.sync(fixPath),
252 findAvailablePort: (preferred) =>
253 Effect.tryPromise({
254 try: () => findAvailablePort(preferred),
255 catch: (cause) =>
256 new StartupError({ message: "Failed to discover an available port", cause }),
257 }),
247 findAvailablePort,
258248 resolveStaticDir: () =>
259249 resolveStaticDir().pipe(
260250 Effect.provideService(FileSystem.FileSystem, fileSystem),