Rhys Sullivangoogle oauth works2e328ab8 months agoHistory
123 lines · 3.6 KB · TypeScript
RawDownload
/** * Dev entry point for @hono/vite-dev-server. * * Exports `{ fetch }` so Vite can forward API requests to the executor * control-plane handler. Everything else (frontend assets, HMR) is * handled by Vite itself. */import { join } from "node:path";import * as Cause from "effect/Cause";import * as Effect from "effect/Effect";import * as Exit from "effect/Exit";import * as Runtime from "effect/Runtime";import * as Scope from "effect/Scope";import {  createLocalExecutorRequestHandler,  DEFAULT_EXECUTOR_DATA_DIR,} from "@executor/server"; const MAX_LOGGED_ERROR_BODY_LENGTH = 4_000;const EXECUTOR_WEB_DEV_LOCAL_DATA_DIR_ENV = "EXECUTOR_WEB_DEV_LOCAL_DATA_DIR";const DEFAULT_WEB_DEV_LOCAL_DATA_DIR = join(  DEFAULT_EXECUTOR_DATA_DIR,  "control-plane-web-dev",); const truncateForLog = (value: string): string =>  value.length > MAX_LOGGED_ERROR_BODY_LENGTH    ? `${value.slice(0, MAX_LOGGED_ERROR_BODY_LENGTH)}... [truncated]`    : value; const resolveWebDevLocalDataDir = (): string => {  const configured = process.env[EXECUTOR_WEB_DEV_LOCAL_DATA_DIR_ENV]?.trim();  return configured && configured.length > 0    ? configured    : DEFAULT_WEB_DEV_LOCAL_DATA_DIR;}; /** * Extract a detailed, human-readable description from an error. * * When Effect rejects via `runPromise`, the thrown value is a * `FiberFailure` wrapping a `Cause`. `Cause.pretty` renders the full * failure tree (defects, interrupts, tagged errors, etc.) rather than the * opaque fallback message ("An error has occurred"). */const formatErrorForLog = (error: unknown): string => {  if (Runtime.isFiberFailure(error)) {    const cause = error[Runtime.FiberFailureCauseId];    return Cause.pretty(cause);  }   if (error instanceof Error) {    return error.stack ?? error.message;  }   return String(error);}; // Create a long-lived scope that stays open for the lifetime of the process.const handlerPromise = (async () => {  const exit = await Effect.runPromiseExit(    Effect.gen(function* () {      const scope = yield* Scope.make();      const handler = yield* createLocalExecutorRequestHandler({        localDataDir: resolveWebDevLocalDataDir(),      }).pipe(        Effect.provideService(Scope.Scope, scope),      );      return handler;    }),  );   if (Exit.isSuccess(exit)) {    return exit.value;  }   // Log the full Cause tree — this captures typed errors, defects (uncaught  // throws), and interrupts with their original stack traces.  console.error(    "[executor dev api] failed to initialize request handler\n\n" +      Cause.pretty(exit.cause),  );   // Re-throw so every subsequent request sees the init failure.  throw Cause.squash(exit.cause);})(); export default {  async fetch(request: Request) {    const url = new URL(request.url);     try {      const handler = await handlerPromise;      handler.setBaseUrl(url.origin);       const response = await handler.handleApiRequest(request);       if (url.pathname.startsWith("/v1/") && response.status >= 500) {        let bodyText = "<unavailable>";        try {          bodyText = truncateForLog(await response.clone().text());        } catch {}         console.error("[executor dev api] request failed", {          method: request.method,          url: url.toString(),          status: response.status,          contentType: response.headers.get("content-type"),          body: bodyText,        });      }       return response;    } catch (error) {      console.error("[executor dev api] unhandled request error", {        method: request.method,        url: url.toString(),        error: formatErrorForLog(error),      });      throw error;    }  },};