Add make-api package
This commit is contained in:
@@ -1,19 +1,28 @@
|
||||
import { Schema as S } from "@effect/schema";
|
||||
import { DateTime, Duration, Effect, Option as O, pipe } from "effect";
|
||||
import { DateTime, Duration, Either as E, Effect, Option as O, pipe } from "effect";
|
||||
import { RequestError } from "./RequestError";
|
||||
import { Database } from "./services/database";
|
||||
import { Request } from "./services/request";
|
||||
import { brotliCompress } from "node:zlib";
|
||||
import { Match } from "effect";
|
||||
import { Api } from "make-api";
|
||||
import { Login } from "common/api";
|
||||
import { AccessLog } from "common/db";
|
||||
import { LoginRequest, LoginResponse } from "common/api";
|
||||
import { brotliCompress } from "node:zlib";
|
||||
|
||||
const match = (method: string, ...pattern: readonly string[]) => Effect.gen(function* () {
|
||||
const match = (api: Api.Api.Any) => Effect.gen(function* () {
|
||||
|
||||
const req = yield* Request;
|
||||
|
||||
return req.method === method
|
||||
&& req.path.length === pattern.length
|
||||
&& pattern.every((x, i) => x === "*" || x === req.path[i]);
|
||||
return req.method === api.method
|
||||
&& req.path.length === api.props.route.length
|
||||
&& api.props.route.every((token, i) => pipe(
|
||||
Match.value(token),
|
||||
Match.tags({
|
||||
Literal: ({ literal }) => req.path[i] === literal,
|
||||
Param: ({ schema }) => E.isRight(S.decodeUnknownEither(schema)(req.path[i])),
|
||||
}),
|
||||
Match.exhaustive,
|
||||
));
|
||||
});
|
||||
|
||||
const WEIGHTED_TOKEN_REGEX = /^([!#$%'*+.^_`|~a-z0-9-])\s*(?:;\s*q=(0(?:\.[0-9]{0,3})?|1(?:\.0{0,3})?))?$/i;
|
||||
@@ -81,23 +90,23 @@ export const app = pipe(
|
||||
|
||||
console.log(JSON.stringify(accessLog));
|
||||
|
||||
if (yield* match("POST", "login")) {
|
||||
if (yield* match(Login)) {
|
||||
|
||||
const body = yield* requestJson(LoginRequest);
|
||||
const body = yield* requestJson(Login.props.request.schema);
|
||||
|
||||
const user = yield* pipe(
|
||||
db.getUserByUsername(body.username),
|
||||
Effect.catchTag("NoSuchElementException", () => new RequestError({ status: 404, body: "Invalid username or password" })),
|
||||
Effect.catchTag("NoSuchElementException", () => new RequestError({ status: 401, body: "Invalid username or password" })),
|
||||
);
|
||||
|
||||
const valid = yield* Effect.promise(() => Bun.password.verify(body.password, user.password));
|
||||
if (!valid) {
|
||||
return yield* new RequestError({ status: 404, body: "Invalid username or password" });
|
||||
return yield* new RequestError({ status: 401, body: "Invalid username or password" });
|
||||
}
|
||||
|
||||
const sessionId = yield* db.createSession(user.userId);
|
||||
|
||||
const responseData = LoginResponse.make({
|
||||
const responseData = Login.props.response[200].schema.make({
|
||||
userId: user.userId,
|
||||
username: user.username,
|
||||
admin: user.admin,
|
||||
@@ -105,7 +114,7 @@ export const app = pipe(
|
||||
|
||||
const responseJson = yield* pipe(
|
||||
responseData,
|
||||
S.encode(LoginResponse),
|
||||
S.encode(Login.props.response[200].schema),
|
||||
Effect.map(JSON.stringify),
|
||||
);
|
||||
const responseArray = new TextEncoder().encode(responseJson);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Schema as S } from "@effect/schema";
|
||||
import { Database as SqliteDatabase } from "bun:sqlite";
|
||||
import { SessionId, User, UserId } from "common";
|
||||
import { SessionId, UserId } from "common";
|
||||
import { User } from "common/db";
|
||||
import { Context, Effect, Layer, pipe } from "effect";
|
||||
import { NoSuchElementException } from "effect/Cause";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user