| ... | @@ -1,18 +1,7 @@ | ... | @@ -1,18 +1,7 @@ |
| 1 | import net from "node:net"; | 1 | import net from "node:net"; |
| 2 | import os from "node:os"; | 2 | import os from "node:os"; |
| 3 | | 3 | |
| 4 | import { | 4 | import { ServiceMap, Data, Effect, Layer, Option, Config, Path, Schema, FileSystem } from "effect"; |
| 5 | ServiceMap, | | |
| 6 | Data, | | |
| 7 | Effect, | | |
| 8 | Layer, | | |
| 9 | Option, | | |
| 10 | Config, | | |
| 11 | Path, | | |
| 12 | Schema, | | |
| 13 | FileSystem, | | |
| 14 | PlatformError, | | |
| 15 | } from "effect"; | | |
| 16 | import { Command, Flag } from "effect/unstable/cli"; | 5 | import { Command, Flag } from "effect/unstable/cli"; |
| 17 | | 6 | |
| 18 | import { fixPath } from "./fixPath"; | 7 | import { fixPath } from "./fixPath"; |
| ... | @@ -37,7 +26,7 @@ export interface CliConfigShape { | ... | @@ -37,7 +26,7 @@ export interface CliConfigShape { |
| 37 | readonly cwd: string; | 26 | readonly cwd: string; |
| 38 | readonly fixPath: Effect.Effect<unknown, never>; | 27 | readonly fixPath: Effect.Effect<unknown, never>; |
| 39 | readonly findAvailablePort: (preferred: number) => Effect.Effect<number, StartupError>; | 28 | readonly findAvailablePort: (preferred: number) => Effect.Effect<number, StartupError>; |
| 40 | readonly resolveStaticDir: () => Effect.Effect<string | undefined, PlatformError.PlatformError>; | 29 | readonly resolveStaticDir: () => Effect.Effect<string | undefined>; |
| 41 | } | 30 | } |
| 42 | | 31 | |
| 43 | export class CliConfig extends ServiceMap.Service<CliConfig, CliConfigShape>()( | 32 | export class CliConfig extends ServiceMap.Service<CliConfig, CliConfigShape>()( |
| ... | @@ -87,11 +76,11 @@ const resolveStateDir = Effect.fn(function* (raw: string | undefined) { | ... | @@ -87,11 +76,11 @@ const resolveStateDir = Effect.fn(function* (raw: string | undefined) { |
| 87 | return resolve(yield* expandHomePath(raw.trim())); | 76 | return resolve(yield* expandHomePath(raw.trim())); |
| 88 | }); | 77 | }); |
| 89 | | 78 | |
| 90 | async function findAvailablePort(preferred: number): Promise<number> { | 79 | const findAvailablePort = (preferred: number) => |
| 91 | return new Promise((resolve, reject) => { | 80 | Effect.callback<number, StartupError>((resume) => { |
| 92 | const server = net.createServer(); | 81 | const server = net.createServer(); |
| 93 | server.listen(preferred, () => { | 82 | server.listen(preferred, () => { |
| 94 | server.close(() => resolve(preferred)); | 83 | server.close(() => resume(Effect.succeed(preferred))); |
| 95 | }); | 84 | }); |
| 96 | server.on("error", () => { | 85 | server.on("error", () => { |
| 97 | const fallback = net.createServer(); | 86 | const fallback = net.createServer(); |
| ... | @@ -99,14 +88,20 @@ async function findAvailablePort(preferred: number): Promise<number> { | ... | @@ -99,14 +88,20 @@ async function findAvailablePort(preferred: number): Promise<number> { |
| 99 | const addr = fallback.address(); | 88 | const addr = fallback.address(); |
| 100 | const port = typeof addr === "object" && addr !== null ? addr.port : 0; | 89 | const port = typeof addr === "object" && addr !== null ? addr.port : 0; |
| 101 | fallback.close(() => { | 90 | fallback.close(() => { |
| 102 | if (port > 0) resolve(port); | 91 | resume( |
| 103 | else reject(new Error("Could not find an available port.")); | 92 | port > 0 |
| | 93 | ? Effect.succeed(port) |
| | 94 | : Effect.fail(new StartupError({ message: "Could not find an available port." })), |
| | 95 | ); |
| 104 | }); | 96 | }); |
| 105 | }); | 97 | }); |
| 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 | }); |
| 107 | }); | 103 | }); |
| 108 | }); | 104 | }); |
| 109 | } | | |
| 110 | | 105 | |
| 111 | const resolveStaticDir = Effect.fn(function* () { | 106 | const resolveStaticDir = Effect.fn(function* () { |
| 112 | const { join, resolve } = yield* Path.Path; | 107 | const { join, resolve } = yield* Path.Path; |
| ... | @@ -249,12 +244,7 @@ export const CliConfigLive = Layer.effect( | ... | @@ -249,12 +244,7 @@ export const CliConfigLive = Layer.effect( |
| 249 | return { | 244 | return { |
| 250 | cwd: process.cwd(), | 245 | cwd: process.cwd(), |
| 251 | fixPath: Effect.sync(fixPath), | 246 | fixPath: Effect.sync(fixPath), |
| 252 | findAvailablePort: (preferred) => | 247 | findAvailablePort, |
| 253 | Effect.tryPromise({ | | |
| 254 | try: () => findAvailablePort(preferred), | | |
| 255 | catch: (cause) => | | |
| 256 | new StartupError({ message: "Failed to discover an available port", cause }), | | |
| 257 | }), | | |
| 258 | resolveStaticDir: () => | 248 | resolveStaticDir: () => |
| 259 | resolveStaticDir().pipe( | 249 | resolveStaticDir().pipe( |
| 260 | Effect.provideService(FileSystem.FileSystem, fileSystem), | 250 | Effect.provideService(FileSystem.FileSystem, fileSystem), |