From 1ef0eda13e250d184f560e63d0cf34da3e7a43f0 Mon Sep 17 00:00:00 2001 From: cy Date: Sun, 3 Nov 2024 14:15:25 +0700 Subject: [PATCH 1/7] =?UTF-8?q?change=20structure=20to=20mod=20?= =?UTF-8?q?=F0=9F=8E=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/config/container.ts | 4 ++-- .../user.service.ts => mod/auth/service.ts} | 2 +- .../vocabulary/repository.ts} | 21 ++++++++++++++----- .../vocabulary/service.ts} | 11 +++++++--- main.ts | 11 +++++----- 5 files changed, 33 insertions(+), 16 deletions(-) rename libs/{service/user.service.ts => mod/auth/service.ts} (91%) rename libs/{repository/vocabulary.repo.ts => mod/vocabulary/repository.ts} (77%) rename libs/{service/vocabulary.service.ts => mod/vocabulary/service.ts} (85%) diff --git a/libs/config/container.ts b/libs/config/container.ts index f9e2b0e..b64a24e 100644 --- a/libs/config/container.ts +++ b/libs/config/container.ts @@ -2,12 +2,12 @@ import { Container } from "inversify"; import { VocabularyRepository, type IVocabularyRepository, -} from "../repository/vocabulary.repo.ts"; +} from "../mod/vocabulary/repository.ts"; import { OpenAIAPI } from "../api/openai.api.ts"; import { VocabularyService, type IVocabularyService, -} from "../service/vocabulary.service.ts"; +} from "../mod/vocabulary/service.ts"; enum Instances { OpenAIAPI = "OpenAIAPI", diff --git a/libs/service/user.service.ts b/libs/mod/auth/service.ts similarity index 91% rename from libs/service/user.service.ts rename to libs/mod/auth/service.ts index af6f4a5..dc30b48 100644 --- a/libs/service/user.service.ts +++ b/libs/mod/auth/service.ts @@ -1,4 +1,4 @@ -import { supabase } from './../db/index.ts'; +import { supabase } from '../../db/index.ts'; import type { SupabaseClient } from "@supabase/supabase-js"; type User = { diff --git a/libs/repository/vocabulary.repo.ts b/libs/mod/vocabulary/repository.ts similarity index 77% rename from libs/repository/vocabulary.repo.ts rename to libs/mod/vocabulary/repository.ts index b6930f7..0a5f250 100644 --- a/libs/repository/vocabulary.repo.ts +++ b/libs/mod/vocabulary/repository.ts @@ -1,7 +1,7 @@ import type { SupabaseClient } from "@supabase/supabase-js"; import { injectable } from "inversify"; -import { Env } from "../config/index.ts"; -import { supabase } from "../db/index.ts"; +import { Env } from "../../config/index.ts"; +import { supabase } from "../../db/index.ts"; import "reflect-metadata"; @@ -15,6 +15,7 @@ export interface IVocabularyRepository { findAll(): Promise; findByWord(word: string): Promise; insert(v: TVocabulary): Promise; + auth(): Promise; } const TableName = "vocabulary"; @@ -45,12 +46,22 @@ export class VocabularyRepository implements IVocabularyRepository { return data; } - public async insert(v: TVocabulary) { - const auth = await this._db.auth.signInWithPassword({ + public async auth() { + const res = await this._db.auth.signInWithPassword({ email: Env.supabaseUser!, password: Env.supabasePass!, }); - console.log("auth", auth); + + return res; + } + + public async insert(v: TVocabulary) { + // const auth = await this._db.auth.signInWithPassword({ + // email: Env.supabaseUser!, + // password: Env.supabasePass!, + // }); + + // console.log("auth", auth); const { data, error } = await this._db.from(TableName).insert([{ ...v }]); if (error) { console.error(error); diff --git a/libs/service/vocabulary.service.ts b/libs/mod/vocabulary/service.ts similarity index 85% rename from libs/service/vocabulary.service.ts rename to libs/mod/vocabulary/service.ts index 9c85fa2..8465771 100644 --- a/libs/service/vocabulary.service.ts +++ b/libs/mod/vocabulary/service.ts @@ -1,14 +1,14 @@ import { injectable, inject } from "inversify"; -import type { IVocabularyRepository, VocabularyRepository } from "../repository/vocabulary.repo.ts"; -import { OpenAIAPI } from "./../api/openai.api.ts"; +import type { IVocabularyRepository, VocabularyRepository } from "./repository.ts"; +import { OpenAIAPI } from "../../api/openai.api.ts"; import "reflect-metadata"; export interface IVocabularyService { insert(word: string): Promise; + auth(): Promise; } - @injectable() export class VocabularyService implements IVocabularyService { // constructor(private _repo: VocabularyRepository, private _openai: OpenAIAPI) {} @@ -23,6 +23,11 @@ export class VocabularyService implements IVocabularyService { this._openai = openai; } + public async auth() { + const res = await this._repo.auth(); + return res; + } + public async insert(word: string) { let vocabulary; vocabulary = await this._repo.findByWord(word); diff --git a/main.ts b/main.ts index ef708b8..ffd0c66 100644 --- a/main.ts +++ b/main.ts @@ -1,7 +1,7 @@ import { Hono } from "hono"; import { bearerAuth } from "hono/bearer-auth"; import { container, Instances } from "./libs/config/container.ts"; -import type { IVocabularyService } from "./libs/service/vocabulary.service.ts"; +import type { IVocabularyService } from "./libs/mod/vocabulary/service.ts"; const readToken = "read"; const prvilegedToekn = "read+write"; @@ -19,10 +19,11 @@ app.on(privilegedMethods, "/api/*", (c, next) => { return bearer(c, next); }); -// app.get("/api/page/x", async (c) => { -// // const res = await translate("antecedent") -// // return c.json(res); -// }); +app.get("/api/auth", async (c) => { + const srv = container.get(Instances.VocabularyService); + const res = await srv.auth(); + return c.json(res); +}); app.post("/api/vocabulary", async (c) => { const body = await c.req.json<{ word: string }>(); From bbf745653d71eb02c5eafb09e7caaa218f352695 Mon Sep 17 00:00:00 2001 From: cy Date: Sun, 3 Nov 2024 14:54:44 +0700 Subject: [PATCH 2/7] =?UTF-8?q?test=20supabase=20auth=20&=20get=20user=20?= =?UTF-8?q?=F0=9F=91=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deno.json | 6 ++++-- deno.lock | 17 +++++++++++++++-- libs/middleware/zodValidator.middleware.ts | 0 libs/mod/vocabulary/repository.ts | 8 ++++++++ libs/mod/vocabulary/service.ts | 7 +++++++ main.ts | 7 +++++++ 6 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 libs/middleware/zodValidator.middleware.ts diff --git a/deno.json b/deno.json index bbd91ab..a281744 100644 --- a/deno.json +++ b/deno.json @@ -4,7 +4,9 @@ "hono": "npm:hono@^4.6.7", "inversify": "npm:inversify@^6.0.3", "openai": "npm:openai@^4.68.4", - "reflect-metadata": "npm:reflect-metadata@^0.2.2" + "reflect-metadata": "npm:reflect-metadata@^0.2.2", + "zod": "npm:zod@^3.23.8", + "zod-validation-error": "npm:zod-validation-error@^3.4.0" }, "tasks": { "start": "deno run --allow-env --allow-net main.ts", @@ -13,6 +15,6 @@ "compilerOptions": { "jsx": "precompile", "jsxImportSource": "hono/jsx", - "experimentalDecorators": true + "experimentalDecorators": true } } diff --git a/deno.lock b/deno.lock index c34edfa..bbe510d 100644 --- a/deno.lock +++ b/deno.lock @@ -14,7 +14,9 @@ "npm:hono@^4.6.7": "4.6.7", "npm:inversify@^6.0.3": "6.0.3", "npm:openai@^4.68.4": "4.68.4", - "npm:reflect-metadata@~0.2.2": "0.2.2" + "npm:reflect-metadata@~0.2.2": "0.2.2", + "npm:zod-validation-error@^3.4.0": "3.4.0_zod@3.23.8", + "npm:zod@^3.23.8": "3.23.8" }, "jsr": { "@std/dotenv@0.225.2": { @@ -217,6 +219,15 @@ }, "ws@8.18.0": { "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==" + }, + "zod-validation-error@3.4.0_zod@3.23.8": { + "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", + "dependencies": [ + "zod" + ] + }, + "zod@3.23.8": { + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==" } }, "workspace": { @@ -225,7 +236,9 @@ "npm:hono@^4.6.7", "npm:inversify@^6.0.3", "npm:openai@^4.68.4", - "npm:reflect-metadata@~0.2.2" + "npm:reflect-metadata@~0.2.2", + "npm:zod-validation-error@^3.4.0", + "npm:zod@^3.23.8" ] } } diff --git a/libs/middleware/zodValidator.middleware.ts b/libs/middleware/zodValidator.middleware.ts new file mode 100644 index 0000000..e69de29 diff --git a/libs/mod/vocabulary/repository.ts b/libs/mod/vocabulary/repository.ts index 0a5f250..15a760b 100644 --- a/libs/mod/vocabulary/repository.ts +++ b/libs/mod/vocabulary/repository.ts @@ -15,7 +15,10 @@ export interface IVocabularyRepository { findAll(): Promise; findByWord(word: string): Promise; insert(v: TVocabulary): Promise; + // TODO: move to auth service file auth(): Promise; + getUser(token: string): Promise; + } const TableName = "vocabulary"; @@ -55,6 +58,11 @@ export class VocabularyRepository implements IVocabularyRepository { return res; } + public async getUser(token: string) { + const res = await this._db.auth.getUser(token); + return res; + } + public async insert(v: TVocabulary) { // const auth = await this._db.auth.signInWithPassword({ // email: Env.supabaseUser!, diff --git a/libs/mod/vocabulary/service.ts b/libs/mod/vocabulary/service.ts index 8465771..373a03f 100644 --- a/libs/mod/vocabulary/service.ts +++ b/libs/mod/vocabulary/service.ts @@ -6,7 +6,9 @@ import "reflect-metadata"; export interface IVocabularyService { insert(word: string): Promise; + // TODO: move to auth service file auth(): Promise; + getUser(token: string): Promise; } @injectable() @@ -28,6 +30,11 @@ export class VocabularyService implements IVocabularyService { return res; } + public async getUser(token: string) { + const res = await this._repo.getUser(token); + return res; + } + public async insert(word: string) { let vocabulary; vocabulary = await this._repo.findByWord(word); diff --git a/main.ts b/main.ts index ffd0c66..5ae23d6 100644 --- a/main.ts +++ b/main.ts @@ -25,6 +25,13 @@ app.get("/api/auth", async (c) => { return c.json(res); }); +app.post("/api/get-user", async (c) => { + const body = await c.req.json<{ token: string }>(); + const srv = container.get(Instances.VocabularyService); + const res = await srv.getUser(body.token); + return c.json(res); +}) + app.post("/api/vocabulary", async (c) => { const body = await c.req.json<{ word: string }>(); console.log("body", body.word); From 7e09d5f2fb5a2b6886d1997c51a9ae538fab8d1b Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 4 Nov 2024 17:32:08 +0700 Subject: [PATCH 3/7] - --- deno.json | 2 +- deno.lock | 8 ++-- libs/middleware/zodValidator.middleware.ts | 43 ++++++++++++++++++++++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/deno.json b/deno.json index a281744..029bd52 100644 --- a/deno.json +++ b/deno.json @@ -1,7 +1,7 @@ { "imports": { "@supabase/supabase-js": "jsr:@supabase/supabase-js@^2.45.6", - "hono": "npm:hono@^4.6.7", + "hono": "npm:hono@^4.6.9", "inversify": "npm:inversify@^6.0.3", "openai": "npm:openai@^4.68.4", "reflect-metadata": "npm:reflect-metadata@^0.2.2", diff --git a/deno.lock b/deno.lock index bbe510d..60caf6a 100644 --- a/deno.lock +++ b/deno.lock @@ -11,7 +11,7 @@ "npm:@supabase/realtime-js@2.10.7": "2.10.7", "npm:@supabase/storage-js@2.7.1": "2.7.1", "npm:@types/node@*": "22.5.4", - "npm:hono@^4.6.7": "4.6.7", + "npm:hono@^4.6.9": "4.6.9", "npm:inversify@^6.0.3": "6.0.3", "npm:openai@^4.68.4": "4.68.4", "npm:reflect-metadata@~0.2.2": "0.2.2", @@ -147,8 +147,8 @@ "web-streams-polyfill" ] }, - "hono@4.6.7": { - "integrity": "sha512-wX4ZbOnzfNO61hUjuQbJ7OPGs1fWXXVVJ8VTPDb2Ls/x9HjCbVTm80Je6VTHMz5n5RGDtBgV9d9ZFZxBqx56ng==" + "hono@4.6.9": { + "integrity": "sha512-p/pN5yZLuZaHzyAOT2nw2/Ud6HhJHYmDNGH6Ck1OWBhPMVeM1r74jbCRwNi0gyFRjjbsGgoHbOyj7mT1PDNbTw==" }, "humanize-ms@1.2.1": { "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", @@ -233,7 +233,7 @@ "workspace": { "dependencies": [ "jsr:@supabase/supabase-js@^2.45.6", - "npm:hono@^4.6.7", + "npm:hono@^4.6.9", "npm:inversify@^6.0.3", "npm:openai@^4.68.4", "npm:reflect-metadata@~0.2.2", diff --git a/libs/middleware/zodValidator.middleware.ts b/libs/middleware/zodValidator.middleware.ts index e69de29..9e97ae0 100644 --- a/libs/middleware/zodValidator.middleware.ts +++ b/libs/middleware/zodValidator.middleware.ts @@ -0,0 +1,43 @@ +import type { Context, Env, MiddlewareHandler, TypedResponse } from "hono"; +import type { ZodError, ZodSchema } from "zod"; + +import { ValidationTargets } from "hono"; +import { validator } from "hono/validator"; +import { z } from "zod"; + +export type Hook = ( + result: + | { susscess: true; data: T } + | { success: false; error: ZodError; data: T }, + c: Context +) => + | Response + | Promise + | void + | Promise>; + +type HasUndefined = T extends undefined ? true : false; + +export const zValidator = < + T extends ZodSchema, + Target extends keyof ValidationTargets, + E extends Env, + P extends string, + I = z.input, + O = z.output, + V extends { + in: HasUndefined extends true + ? { [K in Target]?: I } + : { [K in Target]: I }; + out: { [K in Target]: O }; + } = { + in: HasUndefined extends true + ? { [K in Target]?: I } + : { [K in Target]: I }; + out: { [K in Target]: O }; + } +>( + target: Target, + schema: T, + hook?: Hook, E, P> +): MiddlewareHandler => validator(); From db69b65876d535fe5af1e311ba2a6f6e2059b246 Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 4 Nov 2024 19:02:12 +0700 Subject: [PATCH 4/7] Fix type error of zod x hono validate --- libs/middleware/zodValidator.middleware.ts | 39 +++++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/libs/middleware/zodValidator.middleware.ts b/libs/middleware/zodValidator.middleware.ts index 9e97ae0..eb5e5e9 100644 --- a/libs/middleware/zodValidator.middleware.ts +++ b/libs/middleware/zodValidator.middleware.ts @@ -5,9 +5,14 @@ import { ValidationTargets } from "hono"; import { validator } from "hono/validator"; import { z } from "zod"; -export type Hook = ( +export type Hook< + T, + E extends Env, + P extends string, + O = Record +> = ( result: - | { susscess: true; data: T } + | { success: true; data: T } | { success: false; error: ZodError; data: T }, c: Context ) => @@ -26,18 +31,34 @@ export const zValidator = < I = z.input, O = z.output, V extends { - in: HasUndefined extends true - ? { [K in Target]?: I } - : { [K in Target]: I }; + in: { + [K in Target]: K extends "json" + ? I + : { + [x: string]: ValidationTargets[K][string]; + }; + }; out: { [K in Target]: O }; } = { - in: HasUndefined extends true - ? { [K in Target]?: I } - : { [K in Target]: I }; + in: { + [K in Target]: K extends "json" + ? I + : { + [x: string]: ValidationTargets[K][string]; + }; + }; out: { [K in Target]: O }; } >( target: Target, schema: T, hook?: Hook, E, P> -): MiddlewareHandler => validator(); +): MiddlewareHandler => + validator(target, async (v, c) => { + const result = await schema.safeParseAsync(v); + if (hook) { +// const hookResult = hook({ ...result }, c); + } + + return {} as any; + }); From 9d1ec3cf211f6ffc9f2c4d745a2cacb1770aa392 Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 4 Nov 2024 20:05:41 +0700 Subject: [PATCH 5/7] =?UTF-8?q?auth=20=E2=9C=8D=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/config/container.ts | 9 ++++- libs/middleware/zodValidator.middleware.ts | 38 ++++++++++++++++++---- libs/mod/auth/repository.ts | 33 +++++++++++++++++++ libs/mod/auth/service.ts | 37 +++++++++++++-------- libs/mod/vocabulary/repository.ts | 18 ---------- libs/mod/vocabulary/routes.ts | 24 ++++++++++++++ libs/mod/vocabulary/service.ts | 20 ++++++------ main.ts | 27 ++++++++------- 8 files changed, 146 insertions(+), 60 deletions(-) create mode 100644 libs/mod/auth/repository.ts create mode 100644 libs/mod/vocabulary/routes.ts diff --git a/libs/config/container.ts b/libs/config/container.ts index b64a24e..fb6d815 100644 --- a/libs/config/container.ts +++ b/libs/config/container.ts @@ -1,3 +1,4 @@ +import { IUserRepository } from "./../mod/auth/repository.ts"; import { Container } from "inversify"; import { VocabularyRepository, @@ -8,11 +9,15 @@ import { VocabularyService, type IVocabularyService, } from "../mod/vocabulary/service.ts"; +import { UserRepository } from "../mod/auth/repository.ts"; +import { UserService, type IUserService } from "../mod/auth/service.ts"; enum Instances { OpenAIAPI = "OpenAIAPI", VocabularyRepository = "VocabularyRepository", VocabularyService = "VocabularyService", + UserRepository = "UserRepository", + UserService = "UserService", } const container = new Container(); @@ -23,5 +28,7 @@ container.bind(Instances.OpenAIAPI).toConstantValue(new OpenAIAPI()); container .bind(Instances.VocabularyService) .to(VocabularyService); +container.bind(Instances.UserRepository).to(UserRepository); +container.bind(Instances.UserService).to(UserService); - export {Instances, container} \ No newline at end of file +export { Instances, container }; diff --git a/libs/middleware/zodValidator.middleware.ts b/libs/middleware/zodValidator.middleware.ts index eb5e5e9..081082a 100644 --- a/libs/middleware/zodValidator.middleware.ts +++ b/libs/middleware/zodValidator.middleware.ts @@ -2,6 +2,8 @@ import type { Context, Env, MiddlewareHandler, TypedResponse } from "hono"; import type { ZodError, ZodSchema } from "zod"; import { ValidationTargets } from "hono"; +import { fromZodError } from "zod-validation-error"; + import { validator } from "hono/validator"; import { z } from "zod"; @@ -11,9 +13,10 @@ export type Hook< P extends string, O = Record > = ( - result: - | { success: true; data: T } - | { success: false; error: ZodError; data: T }, + result: { success: boolean; data: T; error?: ZodError }, + // result: + // | { success: true; data: T } + // | { success: false; error: ZodError; data: T }, c: Context ) => | Response @@ -55,10 +58,33 @@ export const zValidator = < hook?: Hook, E, P> ): MiddlewareHandler => validator(target, async (v, c) => { - const result = await schema.safeParseAsync(v); + const { success, data, error } = await schema.safeParseAsync(v); if (hook) { -// const hookResult = hook({ ...result }, c); + const hookResult = hook({ success, data, error }, c); + if (hookResult) { + if ( + (hookResult && hookResult instanceof Response) || + hookResult instanceof Promise + ) { + return hookResult; + } + if ("response" in hookResult) { + return hookResult["response"]; + } + + if (!success) { + const validationError = fromZodError(error); + + return c.json( + { + message: validationError.message, + errors: validationError.details, + }, + 400 + ); + } + } } - return {} as any; + return data; }); diff --git a/libs/mod/auth/repository.ts b/libs/mod/auth/repository.ts new file mode 100644 index 0000000..a624ed6 --- /dev/null +++ b/libs/mod/auth/repository.ts @@ -0,0 +1,33 @@ +import type { SupabaseClient } from "@supabase/supabase-js"; + +import { injectable } from "inversify"; +import { supabase } from "../../db/index.ts"; + +export interface IUserRepository { +// auth(): Promise; + signIn(username: string, password: string): Promise; +// getUser(token: string): Promise; +} + +@injectable() +export class UserRepository implements IUserRepository { + private _db: SupabaseClient = supabase; + + constructor() {} + +// public async auth() { +// return; +// } + + public async signIn(username: string, password: string) { + const res = await this._db.auth.signInWithPassword({ + email: username, + password, + }); + return res; + } + +// public async getUser(token: string) { +// return; +// } +} diff --git a/libs/mod/auth/service.ts b/libs/mod/auth/service.ts index dc30b48..1fd245b 100644 --- a/libs/mod/auth/service.ts +++ b/libs/mod/auth/service.ts @@ -1,23 +1,34 @@ -import { supabase } from '../../db/index.ts'; -import type { SupabaseClient } from "@supabase/supabase-js"; +import { IUserRepository } from './repository.ts'; +import { inject, injectable } from "inversify"; type User = { username: string; password: string; }; -class UserService { - constructor(private _db: SupabaseClient) {} +export interface IUserService { + signIn(username: string, password: string): Promise; +} + +@injectable() +export class UserService implements IUserService { + + private _repo: IUserRepository; - public async insert(u: User) { - const { data, error } = await this._db.from("users").insert([u]); - if (error) { - console.error(error); - throw new Error(`Failed to insert user: ${error.message}`); - } - return data; + constructor(@inject("UserRepository") repo: IUserRepository) { + this._repo = repo; } -} + public async signIn(username: string, password: string) { + return await this._repo.signIn(username, password); + } -export default new UserService(supabase); \ No newline at end of file + // public async insert(u: User) { + // const { data, error } = await this._db.from("users").insert([u]); + // if (error) { + // console.error(error); + // throw new Error(`Failed to insert user: ${error.message}`); + // } + // return data; + // } +} diff --git a/libs/mod/vocabulary/repository.ts b/libs/mod/vocabulary/repository.ts index 15a760b..728c5c0 100644 --- a/libs/mod/vocabulary/repository.ts +++ b/libs/mod/vocabulary/repository.ts @@ -15,9 +15,6 @@ export interface IVocabularyRepository { findAll(): Promise; findByWord(word: string): Promise; insert(v: TVocabulary): Promise; - // TODO: move to auth service file - auth(): Promise; - getUser(token: string): Promise; } @@ -48,21 +45,6 @@ export class VocabularyRepository implements IVocabularyRepository { } return data; } - - public async auth() { - const res = await this._db.auth.signInWithPassword({ - email: Env.supabaseUser!, - password: Env.supabasePass!, - }); - - return res; - } - - public async getUser(token: string) { - const res = await this._db.auth.getUser(token); - return res; - } - public async insert(v: TVocabulary) { // const auth = await this._db.auth.signInWithPassword({ // email: Env.supabaseUser!, diff --git a/libs/mod/vocabulary/routes.ts b/libs/mod/vocabulary/routes.ts new file mode 100644 index 0000000..4ba1d29 --- /dev/null +++ b/libs/mod/vocabulary/routes.ts @@ -0,0 +1,24 @@ +import { IUserService } from "./../auth/service.ts"; +import { Hono } from "hono"; +import { zValidator } from "../../middleware/zodValidator.middleware.ts"; +import { z } from "zod"; +import { container, Instances } from "../../config/container.ts"; + +const authRoutes = new Hono().post( + "/sign-in", + zValidator( + "json", + z.object({ + email: z.string(), + password: z.string(), + }) + ), + async (c) => { + const { email, password } = await c.req.valid("json"); + const srv = container.get(Instances.UserService); + + return await srv.signIn(email, password); + } +); + +export default authRoutes; \ No newline at end of file diff --git a/libs/mod/vocabulary/service.ts b/libs/mod/vocabulary/service.ts index 373a03f..59f4c01 100644 --- a/libs/mod/vocabulary/service.ts +++ b/libs/mod/vocabulary/service.ts @@ -7,8 +7,8 @@ import "reflect-metadata"; export interface IVocabularyService { insert(word: string): Promise; // TODO: move to auth service file - auth(): Promise; - getUser(token: string): Promise; + // auth(): Promise; + // getUser(token: string): Promise; } @injectable() @@ -25,15 +25,15 @@ export class VocabularyService implements IVocabularyService { this._openai = openai; } - public async auth() { - const res = await this._repo.auth(); - return res; - } + // public async auth() { + // const res = await this._repo.auth(); + // return res; + // } - public async getUser(token: string) { - const res = await this._repo.getUser(token); - return res; - } + // public async getUser(token: string) { + // const res = await this._repo.getUser(token); + // return res; + // } public async insert(word: string) { let vocabulary; diff --git a/main.ts b/main.ts index 5ae23d6..d73abcc 100644 --- a/main.ts +++ b/main.ts @@ -2,6 +2,7 @@ import { Hono } from "hono"; import { bearerAuth } from "hono/bearer-auth"; import { container, Instances } from "./libs/config/container.ts"; import type { IVocabularyService } from "./libs/mod/vocabulary/service.ts"; +import authRoutes from "./libs/mod/vocabulary/routes.ts"; const readToken = "read"; const prvilegedToekn = "read+write"; @@ -19,23 +20,25 @@ app.on(privilegedMethods, "/api/*", (c, next) => { return bearer(c, next); }); -app.get("/api/auth", async (c) => { - const srv = container.get(Instances.VocabularyService); - const res = await srv.auth(); - return c.json(res); -}); +// app.get("/api/auth", async (c) => { +// const srv = container.get(Instances.VocabularyService); +// const res = await srv.auth(); +// return c.json(res); +// }); -app.post("/api/get-user", async (c) => { - const body = await c.req.json<{ token: string }>(); - const srv = container.get(Instances.VocabularyService); - const res = await srv.getUser(body.token); - return c.json(res); -}) +// app.post("/api/get-user", async (c) => { +// const body = await c.req.json<{ token: string }>(); +// const srv = container.get(Instances.VocabularyService); +// const res = await srv.getUser(body.token); +// return c.json(res); +// }) + +app.route("/auth", authRoutes); app.post("/api/vocabulary", async (c) => { const body = await c.req.json<{ word: string }>(); console.log("body", body.word); - const srv = container.get(Instances.VocabularyService); + const srv = container.get(Instances.VocabularyService); // const srv = new VocabularyService( // new VocabularyRepository(), // new OpenAIAPI() From 29b7d75fd153f7c12863a21d264caad1d2bf9a82 Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 4 Nov 2024 20:31:11 +0700 Subject: [PATCH 6/7] =?UTF-8?q?=F0=9F=94=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/middleware/auth.middleware.ts | 5 +++++ libs/mod/auth/repository.ts | 4 ++-- libs/mod/{vocabulary => auth}/routes.ts | 13 ++++++++++--- libs/mod/auth/service.ts | 3 ++- main.ts | 26 ++++++++++++------------- 5 files changed, 32 insertions(+), 19 deletions(-) create mode 100644 libs/middleware/auth.middleware.ts rename libs/mod/{vocabulary => auth}/routes.ts (59%) diff --git a/libs/middleware/auth.middleware.ts b/libs/middleware/auth.middleware.ts new file mode 100644 index 0000000..7122671 --- /dev/null +++ b/libs/middleware/auth.middleware.ts @@ -0,0 +1,5 @@ +import { MiddlewareHandler } from 'hono'; + +const authMiddleware: MiddlewareHandler = async (c, next) => { + +} \ No newline at end of file diff --git a/libs/mod/auth/repository.ts b/libs/mod/auth/repository.ts index a624ed6..03275cb 100644 --- a/libs/mod/auth/repository.ts +++ b/libs/mod/auth/repository.ts @@ -1,11 +1,11 @@ -import type { SupabaseClient } from "@supabase/supabase-js"; +import type { AuthTokenResponsePassword, SupabaseClient } from "@supabase/supabase-js"; import { injectable } from "inversify"; import { supabase } from "../../db/index.ts"; export interface IUserRepository { // auth(): Promise; - signIn(username: string, password: string): Promise; + signIn(username: string, password: string): Promise; // getUser(token: string): Promise; } diff --git a/libs/mod/vocabulary/routes.ts b/libs/mod/auth/routes.ts similarity index 59% rename from libs/mod/vocabulary/routes.ts rename to libs/mod/auth/routes.ts index 4ba1d29..2ee1f4f 100644 --- a/libs/mod/vocabulary/routes.ts +++ b/libs/mod/auth/routes.ts @@ -1,5 +1,6 @@ -import { IUserService } from "./../auth/service.ts"; +import { IUserService } from "./service.ts"; import { Hono } from "hono"; +import { setCookie } from "hono/cookie"; import { zValidator } from "../../middleware/zodValidator.middleware.ts"; import { z } from "zod"; import { container, Instances } from "../../config/container.ts"; @@ -16,9 +17,15 @@ const authRoutes = new Hono().post( async (c) => { const { email, password } = await c.req.valid("json"); const srv = container.get(Instances.UserService); + const { data, error } = await srv.signIn(email, password); - return await srv.signIn(email, password); + if (error) { + return c.json({ error: error.message }, 500); + } + setCookie(c, "access_token", data.session.access_token); + + return c.json(data.user); } ); -export default authRoutes; \ No newline at end of file +export default authRoutes; diff --git a/libs/mod/auth/service.ts b/libs/mod/auth/service.ts index 1fd245b..928c4e1 100644 --- a/libs/mod/auth/service.ts +++ b/libs/mod/auth/service.ts @@ -1,3 +1,4 @@ +import type { AuthTokenResponsePassword } from "@supabase/supabase-js"; import { IUserRepository } from './repository.ts'; import { inject, injectable } from "inversify"; @@ -7,7 +8,7 @@ type User = { }; export interface IUserService { - signIn(username: string, password: string): Promise; + signIn(username: string, password: string): Promise; } @injectable() diff --git a/main.ts b/main.ts index d73abcc..0ab5d14 100644 --- a/main.ts +++ b/main.ts @@ -1,24 +1,24 @@ import { Hono } from "hono"; -import { bearerAuth } from "hono/bearer-auth"; +// import { bearerAuth } from "hono/bearer-auth"; import { container, Instances } from "./libs/config/container.ts"; import type { IVocabularyService } from "./libs/mod/vocabulary/service.ts"; -import authRoutes from "./libs/mod/vocabulary/routes.ts"; +import authRoutes from "./libs/mod/auth/routes.ts"; -const readToken = "read"; -const prvilegedToekn = "read+write"; -const privilegedMethods = ["POST", "PUT", "PATCH", "DELETE"]; +// const readToken = "read"; +// const prvilegedToekn = "read+write"; +// const privilegedMethods = ["POST", "PUT", "PATCH", "DELETE"]; const app = new Hono(); -const brearer = bearerAuth({ token: [readToken, prvilegedToekn] }); -app.on("GET", "/api/*", (c, next) => { - return brearer(c, next); -}); +// const brearer = bearerAuth({ token: [readToken, prvilegedToekn] }); +// app.on("GET", "/api/*", (c, next) => { +// return brearer(c, next); +// }); -app.on(privilegedMethods, "/api/*", (c, next) => { - const bearer = bearerAuth({ token: prvilegedToekn }); - return bearer(c, next); -}); +// app.on(privilegedMethods, "/api/*", (c, next) => { +// const bearer = bearerAuth({ token: prvilegedToekn }); +// return bearer(c, next); +// }); // app.get("/api/auth", async (c) => { // const srv = container.get(Instances.VocabularyService); From 516de4b7805f84d2bafb6456d0d9ca75f94296cc Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 4 Nov 2024 21:07:06 +0700 Subject: [PATCH 7/7] provide auth middleware --- libs/middleware/auth.middleware.ts | 22 +++++++++++++++++++--- libs/mod/auth/repository.ts | 13 ++++++------- libs/mod/auth/routes.ts | 2 +- libs/mod/auth/service.ts | 7 ++++++- libs/mod/vocabulary/routes.ts | 15 +++++++++++++++ main.ts | 17 +++-------------- 6 files changed, 50 insertions(+), 26 deletions(-) create mode 100644 libs/mod/vocabulary/routes.ts diff --git a/libs/middleware/auth.middleware.ts b/libs/middleware/auth.middleware.ts index 7122671..f3de1c1 100644 --- a/libs/middleware/auth.middleware.ts +++ b/libs/middleware/auth.middleware.ts @@ -1,5 +1,21 @@ -import { MiddlewareHandler } from 'hono'; +import { IUserService } from "./../mod/auth/service.ts"; +import { MiddlewareHandler } from "hono"; +import { getCookie } from "hono/cookie"; +import { container, Instances } from "../config/container.ts"; const authMiddleware: MiddlewareHandler = async (c, next) => { - -} \ No newline at end of file + const accessToken = getCookie(c, "access_token"); + if (accessToken) { + const srv = container.get(Instances.UserService); + const { data, error } = await srv.getUser(accessToken); + if (data.user) { + c.set("user", { ...data }); + } + if (error) { + return c.json({ error: error.message }, 401); + } + } + await next(); +}; + +export default authMiddleware; diff --git a/libs/mod/auth/repository.ts b/libs/mod/auth/repository.ts index 03275cb..b97e66d 100644 --- a/libs/mod/auth/repository.ts +++ b/libs/mod/auth/repository.ts @@ -1,4 +1,4 @@ -import type { AuthTokenResponsePassword, SupabaseClient } from "@supabase/supabase-js"; +import type { AuthTokenResponsePassword, SupabaseClient, UserResponse } from "@supabase/supabase-js"; import { injectable } from "inversify"; import { supabase } from "../../db/index.ts"; @@ -6,7 +6,7 @@ import { supabase } from "../../db/index.ts"; export interface IUserRepository { // auth(): Promise; signIn(username: string, password: string): Promise; -// getUser(token: string): Promise; + getUser(token: string): Promise; } @injectable() @@ -20,14 +20,13 @@ export class UserRepository implements IUserRepository { // } public async signIn(username: string, password: string) { - const res = await this._db.auth.signInWithPassword({ + return await this._db.auth.signInWithPassword({ email: username, password, }); - return res; } -// public async getUser(token: string) { -// return; -// } + public async getUser(token: string) { + return await this._db.auth.getUser(token); + } } diff --git a/libs/mod/auth/routes.ts b/libs/mod/auth/routes.ts index 2ee1f4f..85e6d10 100644 --- a/libs/mod/auth/routes.ts +++ b/libs/mod/auth/routes.ts @@ -24,7 +24,7 @@ const authRoutes = new Hono().post( } setCookie(c, "access_token", data.session.access_token); - return c.json(data.user); + return c.json(data); } ); diff --git a/libs/mod/auth/service.ts b/libs/mod/auth/service.ts index 928c4e1..11c3c68 100644 --- a/libs/mod/auth/service.ts +++ b/libs/mod/auth/service.ts @@ -1,4 +1,4 @@ -import type { AuthTokenResponsePassword } from "@supabase/supabase-js"; +import type { AuthTokenResponsePassword, UserResponse } from "@supabase/supabase-js"; import { IUserRepository } from './repository.ts'; import { inject, injectable } from "inversify"; @@ -9,6 +9,7 @@ type User = { export interface IUserService { signIn(username: string, password: string): Promise; + getUser(token: string): Promise; } @injectable() @@ -24,6 +25,10 @@ export class UserService implements IUserService { return await this._repo.signIn(username, password); } + public async getUser(token: string) { + return await this._repo.getUser(token); + } + // public async insert(u: User) { // const { data, error } = await this._db.from("users").insert([u]); // if (error) { diff --git a/libs/mod/vocabulary/routes.ts b/libs/mod/vocabulary/routes.ts new file mode 100644 index 0000000..fe33818 --- /dev/null +++ b/libs/mod/vocabulary/routes.ts @@ -0,0 +1,15 @@ +import { Hono } from "hono"; +import { container, Instances } from "../../config/container.ts"; +import type { IVocabularyService } from "./service.ts"; +import authMiddleware from "../../middleware/auth.middleware.ts"; + +const vocabularyRoutes = new Hono() +.use("*", authMiddleware) +.post("/create", async (c) => { + const body = await c.req.json<{ word: string }>(); + const srv = container.get(Instances.VocabularyService); + const res = await srv.insert(body.word); + return c.json(res); +}); + +export default vocabularyRoutes; diff --git a/main.ts b/main.ts index 0ab5d14..049c410 100644 --- a/main.ts +++ b/main.ts @@ -3,6 +3,7 @@ import { Hono } from "hono"; import { container, Instances } from "./libs/config/container.ts"; import type { IVocabularyService } from "./libs/mod/vocabulary/service.ts"; import authRoutes from "./libs/mod/auth/routes.ts"; +import vocabularyRoutes from "./libs/mod/vocabulary/routes.ts"; // const readToken = "read"; // const prvilegedToekn = "read+write"; @@ -33,20 +34,8 @@ const app = new Hono(); // return c.json(res); // }) -app.route("/auth", authRoutes); - -app.post("/api/vocabulary", async (c) => { - const body = await c.req.json<{ word: string }>(); - console.log("body", body.word); - const srv = container.get(Instances.VocabularyService); - // const srv = new VocabularyService( - // new VocabularyRepository(), - // new OpenAIAPI() - // ); - const res = await srv.insert(body.word); - console.log("res", res); - return c.json(res); -}); +app.route("api/auth", authRoutes); +app.route("/api/vocabulary", vocabularyRoutes); // app.use( // bodyLimit({