/*! * This Source Code Form is subject to the terms of the Mozilla Public License, * v. 2.0. If a copy of the MPL was not distributed with this file, You can * obtain one at http://mozilla.org/MPL/2.0/. */ import { Schema as S } from "@effect/schema"; import * as Api from "@make-api/api/Api"; import * as Query from "@make-api/api/Query"; import * as RequestBody from "@make-api/api/RequestBody"; import * as Route from "@make-api/api/Route"; import { Array as A, Effect, Match, Option as O, Record as R, pipe } from "effect"; const getUsers = pipe( Api.make("GET", "/users"), Api.responseBodyJson(200, S.Array(S.Struct({ userId: S.UUID, username: S.String, email: S.String, }))), Api.responseBodyJson(500, S.Struct({ error: S.String, stackTrace: S.optional(S.String, { exact: true }), })), ); type RouteParams = { readonly [_: string]: unknown }; // TODO const matchesRoute = (route: T, pathComponents: readonly string[]): boolean => { if (route.length !== pathComponents.length) return false; return pipe( A.zip(route, pathComponents), A.every(([token, pathComponent]) => token._tag !== "Literal" || token.literal === pathComponent), ); }; const parseRoute = (route: T) => { const decoder = pipe( route, A.filterMap((r) => r._tag === "Param" ? O.some([r.name, r.schema] as const) : O.none()), R.fromEntries, S.Struct, (_) => S.decode(_, { errors: "all" }), ); return (pathComponents: readonly string[]) => pipe( pathComponents, A.filterMap((c, i) => { const r = route[i]; return r._tag === "Param" ? O.some([r.name, c] as const) : O.none(); }), R.fromEntries, decoder, ); }; const parseQuery = (query: T) => { const decoder = pipe(); return (searchParams: URLSearchParams) => pipe(); }; const parseBody = (requestBody: T) => { const decoder = pipe( Match.value(requestBody), Match.tags({ None: () => {}, Text: () => {}, Json: () => {}, UrlEncoded: () => {}, Multipart: () => {}, File: () => {}, }), ); return (req: Request) => pipe(); }; const routeParser = parseRoute(getUsers.props.route); const queryParser = parseQuery(getUsers.props.query); const bodyParser = parseBody(getUsers.props.request); Bun.serve({ fetch: (req) => { const url = new URL(req.url); const pathname = url.pathname; const pathComponents = pathname.replaceAll(/^\/|\/$/g, "").split("/"); const searchParams = url.searchParams; if (matchesRoute(getUsers.props.route, pathComponents)) { const paramsEffect = routeParser(pathComponents); const queryEffect = queryParser(searchParams); const bodyEffect = bodyParser(req); const effect = Effect.all({ params: paramsEffect, query: queryEffect, body: bodyEffect, }); } }, websocket: { message: (ws, message) => {} }, });