// @effect-diagnostics-next-line nodeBuiltinImport:off - NodeHttpServer.layer takes `NodeHttp.createServer` as argimport * as NodeHttp from "node:http"; import { NodeHttpServer, NodeRuntime, NodeServices } from "@effect/platform-node";import * as Config from "effect/Config";import * as Effect from "effect/Effect";import * as FileSystem from "effect/FileSystem";import * as Layer from "effect/Layer";import * as Path from "effect/Path";import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/unstable/http"; interface MockUpdateServerConfig { readonly port: number; readonly rootRealPath: string;} const resolveMockUpdateServerConfig = Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; const path = yield* Path.Path; const config = yield* Config.all({ port: Config.port("T3CODE_DESKTOP_MOCK_UPDATE_SERVER_PORT").pipe(Config.withDefault(3000)), root: Config.string("T3CODE_DESKTOP_MOCK_UPDATE_SERVER_ROOT").pipe( Config.withDefault("../release-mock"), ), }); const resolvedRoot = path.resolve(import.meta.dirname, config.root); return { port: config.port, rootRealPath: yield* fileSystem.realPath(resolvedRoot), } satisfies MockUpdateServerConfig;}); const isOutsideRoot = (rootRealPath: string, filePath: string) => Effect.gen(function* () { const path = yield* Path.Path; const relativePath = path.relative(rootRealPath, filePath); return ( relativePath === ".." || relativePath.startsWith("../") || relativePath.startsWith("..\\") ); }); const isWithinRoot = (rootRealPath: string, filePath: string) => Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; const resolvedFilePath = yield* fileSystem.realPath(filePath).pipe( Effect.match({ onFailure: () => undefined, onSuccess: (resolvedPath) => resolvedPath, }), ); return ( resolvedFilePath !== undefined && !(yield* isOutsideRoot(rootRealPath, resolvedFilePath)) ); }); const resolveRequestedFilePath = (rootRealPath: string, requestUrl: string | undefined) => Effect.gen(function* () { const path = yield* Path.Path; const rawPath = (requestUrl ?? "/").split("?", 1)[0] ?? "/"; const decodedPath = yield* Effect.try({ try: () => decodeURIComponent(rawPath), catch: () => null, }).pipe( Effect.match({ onFailure: () => undefined, onSuccess: (value) => value, }), ); if (!decodedPath) { return undefined; } if (decodedPath.includes("\0")) { return undefined; } const filePath = path.resolve( rootRealPath, `.${decodedPath.startsWith("/") ? decodedPath : `/${decodedPath}`}`, ); return (yield* isOutsideRoot(rootRealPath, filePath)) ? undefined : filePath; }); const isServableFile = (rootRealPath: string, filePath: string) => Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; const stat = yield* fileSystem.stat(filePath).pipe( Effect.match({ onFailure: () => undefined, onSuccess: (info) => info, }), ); if (stat?.type !== "File") { return false; } return yield* isWithinRoot(rootRealPath, filePath); }); export const makeMockUpdateRouteLayer = (rootRealPath: string) => { return HttpRouter.add( "*", "*", Effect.gen(function* () { const request = yield* HttpServerRequest.HttpServerRequest; const requestPath = (request.url ?? "/").split("?", 1)[0] ?? "/"; yield* Effect.logInfo(`Request received for path: ${requestPath}`); const filePath = yield* resolveRequestedFilePath(rootRealPath, request.url); if (!filePath) { yield* Effect.logWarning(`Attempted to access file outside of root: ${request.url ?? "/"}`); return HttpServerResponse.text("Not Found", { status: 404 }); } if (!(yield* isServableFile(rootRealPath, filePath))) { yield* Effect.logWarning(`Attempted to access invalid file: ${filePath}`); return HttpServerResponse.text("Not Found", { status: 404 }); } yield* Effect.logInfo(`Serving file: ${filePath}`); return yield* HttpServerResponse.file(filePath, { status: 200 }); }).pipe( Effect.catchCause((cause) => Effect.gen(function* () { yield* Effect.logError(`Unhandled mock update request failure: ${cause}`); return HttpServerResponse.text("Internal Server Error", { status: 500 }); }), ), ), );}; const makeMockUpdateServerLayer = (config: MockUpdateServerConfig) => HttpRouter.serve(makeMockUpdateRouteLayer(config.rootRealPath)).pipe( Layer.provideMerge( NodeHttpServer.layer(NodeHttp.createServer, { host: "localhost", port: config.port, }), ), Layer.provideMerge(NodeServices.layer), ); if (import.meta.main) { resolveMockUpdateServerConfig.pipe( Effect.map(makeMockUpdateServerLayer), Layer.unwrap, Layer.launch, Effect.provide(NodeServices.layer), NodeRuntime.runMain, );}
// @effect-diagnostics-next-line nodeBuiltinImport:off - NodeHttpServer.layer takes `NodeHttp.createServer` as arg
import * as NodeHttp from "node:http";
import { NodeHttpServer, NodeRuntime, NodeServices } from "@effect/platform-node";
import * as Config from "effect/Config";
import * as Effect from "effect/Effect";
import * as FileSystem from "effect/FileSystem";
import * as Layer from "effect/Layer";
import * as Path from "effect/Path";
import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
interface MockUpdateServerConfig {
readonly port: number;
readonly rootRealPath: string;
}
const resolveMockUpdateServerConfig = Effect.gen(function* () {
const fileSystem = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const config = yield* Config.all({
port: Config.port("T3CODE_DESKTOP_MOCK_UPDATE_SERVER_PORT").pipe(Config.withDefault(3000)),
root: Config.string("T3CODE_DESKTOP_MOCK_UPDATE_SERVER_ROOT").pipe(
Config.withDefault("../release-mock"),
),
});
const resolvedRoot = path.resolve(import.meta.dirname, config.root);
return {
port: config.port,
rootRealPath: yield* fileSystem.realPath(resolvedRoot),
} satisfies MockUpdateServerConfig;
});
const isOutsideRoot = (rootRealPath: string, filePath: string) =>
Effect.gen(function* () {
const path = yield* Path.Path;
const relativePath = path.relative(rootRealPath, filePath);
return (
relativePath === ".." || relativePath.startsWith("../") || relativePath.startsWith("..\\")
);
});
const isWithinRoot = (rootRealPath: string, filePath: string) =>
Effect.gen(function* () {
const fileSystem = yield* FileSystem.FileSystem;
const resolvedFilePath = yield* fileSystem.realPath(filePath).pipe(
Effect.match({
onFailure: () => undefined,
onSuccess: (resolvedPath) => resolvedPath,
}),
);
return (
resolvedFilePath !== undefined && !(yield* isOutsideRoot(rootRealPath, resolvedFilePath))
);
});
const resolveRequestedFilePath = (rootRealPath: string, requestUrl: string | undefined) =>
Effect.gen(function* () {
const path = yield* Path.Path;
const rawPath = (requestUrl ?? "/").split("?", 1)[0] ?? "/";
const decodedPath = yield* Effect.try({
try: () => decodeURIComponent(rawPath),
catch: () => null,
}).pipe(
Effect.match({
onFailure: () => undefined,
onSuccess: (value) => value,
}),
);
if (!decodedPath) {
return undefined;
}
if (decodedPath.includes("\0")) {
return undefined;
}
const filePath = path.resolve(
rootRealPath,
`.${decodedPath.startsWith("/") ? decodedPath : `/${decodedPath}`}`,
);
return (yield* isOutsideRoot(rootRealPath, filePath)) ? undefined : filePath;
});
const isServableFile = (rootRealPath: string, filePath: string) =>
Effect.gen(function* () {
const fileSystem = yield* FileSystem.FileSystem;
const stat = yield* fileSystem.stat(filePath).pipe(
Effect.match({
onFailure: () => undefined,
onSuccess: (info) => info,
}),
);
if (stat?.type !== "File") {
return false;
}
return yield* isWithinRoot(rootRealPath, filePath);
});
export const makeMockUpdateRouteLayer = (rootRealPath: string) => {
return HttpRouter.add(
"*",
"*",
Effect.gen(function* () {
const request = yield* HttpServerRequest.HttpServerRequest;
const requestPath = (request.url ?? "/").split("?", 1)[0] ?? "/";
yield* Effect.logInfo(`Request received for path: ${requestPath}`);
const filePath = yield* resolveRequestedFilePath(rootRealPath, request.url);
if (!filePath) {
yield* Effect.logWarning(`Attempted to access file outside of root: ${request.url ?? "/"}`);
return HttpServerResponse.text("Not Found", { status: 404 });
}
if (!(yield* isServableFile(rootRealPath, filePath))) {
yield* Effect.logWarning(`Attempted to access invalid file: ${filePath}`);
return HttpServerResponse.text("Not Found", { status: 404 });
}
yield* Effect.logInfo(`Serving file: ${filePath}`);
return yield* HttpServerResponse.file(filePath, { status: 200 });
}).pipe(
Effect.catchCause((cause) =>
Effect.gen(function* () {
yield* Effect.logError(`Unhandled mock update request failure: ${cause}`);
return HttpServerResponse.text("Internal Server Error", { status: 500 });
}),
),
),
);
};
const makeMockUpdateServerLayer = (config: MockUpdateServerConfig) =>
HttpRouter.serve(makeMockUpdateRouteLayer(config.rootRealPath)).pipe(
Layer.provideMerge(
NodeHttpServer.layer(NodeHttp.createServer, {
host: "localhost",
port: config.port,
}),
),
Layer.provideMerge(NodeServices.layer),
);
if (import.meta.main) {
resolveMockUpdateServerConfig.pipe(
Effect.map(makeMockUpdateServerLayer),
Layer.unwrap,
Layer.launch,
Effect.provide(NodeServices.layer),
NodeRuntime.runMain,
);
}