using firebase auth

This commit is contained in:
2026-01-15 17:36:26 +07:00
parent 27bcb8bbef
commit 2c66126ac9
14 changed files with 375 additions and 214 deletions

View File

@@ -1,5 +1,6 @@
import 'uno.css';
import createVueApp from '@/shared/createVueApp';
import 'uno.css';
async function render() {
const { app, router } = createVueApp();
router.isReady().then(() => {

View File

@@ -0,0 +1,46 @@
import { initializeApp } from "firebase/app";
import { createUserWithEmailAndPassword, getAuth, GoogleAuthProvider, sendPasswordResetEmail, signInWithEmailAndPassword, signInWithPopup } from "firebase/auth";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: "AIzaSyBTr0L5qxdrVEtWuP2oAicJXQvVyeXkMts",
authDomain: "trello-7ea39.firebaseapp.com",
projectId: "trello-7ea39",
storageBucket: "trello-7ea39.firebasestorage.app",
messagingSenderId: "321067890572",
appId: "1:321067890572:web:e34e1e657125d37be688a9"
};
// Initialize Firebase
const appFirebase = initializeApp(firebaseConfig);
const provider = new GoogleAuthProvider();
const auth = getAuth(appFirebase);
export const googleAuth = signInWithPopup(auth, provider).then((result) => {
console.log('User signed in:', result.user);
})
export const emailAuth = (username: string, password: string) => {
return signInWithEmailAndPassword(auth, username, password)
}
export const forgotPassword = (email: string) => {
return sendPasswordResetEmail(auth, email)
.then(() => {
console.log('Password reset email sent');
})
.catch((error) => {
console.error('Error sending password reset email:', error);
throw error;
});
}
export const signUp = (email: string, password: string) => {
return createUserWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
console.log('User signed up:', userCredential.user);
return userCredential.user;
})
.catch((error) => {
console.error('Error signing up:', error);
throw error;
});
}

View File

@@ -1,14 +1,9 @@
import { defineStore } from 'pinia';
import { useRouter } from 'vue-router';
import { client } from '@/client/api/rpcclient';
import { User } from 'firebase/auth';
import { defineStore } from 'pinia';
import { ref } from 'vue';
interface User {
id: string;
username: string;
email: string;
name: string;
}
import { useRouter } from 'vue-router';
import { emailAuth, signUp } from '../lib/firebase';
export const useAuthStore = defineStore('auth', () => {
const user = ref<User | null>(null);
@@ -22,31 +17,31 @@ export const useAuthStore = defineStore('auth', () => {
async function init() {
if (initialized.value) return;
try {
const response = await client.checkAuth();
if (response.authenticated && response.user) {
user.value = response.user;
// Get CSRF token if authenticated
try {
const csrfResponse = await client.getCSRFToken();
csrfToken.value = csrfResponse.csrfToken;
} catch (e) {
// CSRF token might not be available yet
}
}
} catch (e) {
// Not authenticated, that's fine
} finally {
initialized.value = true;
}
// try {
// const response = await client.checkAuth();
// if (response.authenticated && response.user) {
// user.value = response.user;
// // Get CSRF token if authenticated
// try {
// const csrfResponse = await client.getCSRFToken();
// csrfToken.value = csrfResponse.csrfToken;
// } catch (e) {
// // CSRF token might not be available yet
// }
// }
// } catch (e) {
// // Not authenticated, that's fine
// } finally {
// initialized.value = true;
// }
}
async function login(username: string, password: string) {
loading.value = true;
error.value = null;
return client.login(username, password).then((response) => {
user.value = response.user;
csrfToken.value = response.csrfToken;
return emailAuth(username, password).then((userCredential) => {
user.value = userCredential.user;
// csrfToken.value = userCredential.csrfToken;
router.push('/');
}).catch((e: any) => {
// error.value = e.message || 'Login failed';
@@ -60,7 +55,7 @@ export const useAuthStore = defineStore('auth', () => {
async function register(username: string, email: string, password: string) {
loading.value = true;
error.value = null;
return client.register({ username, email, password }).then((response) => {
return signUp(email, password).then((response) => {
user.value = response.user;
csrfToken.value = response.csrfToken;
router.push('/');

View File

@@ -5,13 +5,28 @@ import { contextStorage } from "hono/context-storage";
import isMobile from "is-mobile";
import { AppModule } from "./server/app.module";
import { HonoAdapter, NestHonoApplication } from "./server/common/adapter/hono";
import { CustomZodValidationPipe } from "./server/common/pipes/CustomZodValidation.pipe";
import { ssrRender } from "./server/HonoAdapter/ssrRender";
import { TransformInterceptor } from "./server/common/interceptor/transform.interceptor";
import { ZodValidationPipe } from "nestjs-zod";
declare global {
var __APP__: {
app?: NestHonoApplication;
hono?: Hono;
server?: Bun.Server<any>;
} | undefined;
}
if (!globalThis.__APP__) {
globalThis.__APP__ = {};
}
if (globalThis.__APP__.app) {
await globalThis.__APP__.app.close();
}
let serve: Bun.Server<undefined> | any = {
stop: async () => {},
}
const hono = new Hono();
globalThis.__APP__.hono = hono;
const app = await NestFactory.create<NestHonoApplication>(
AppModule,
new HonoAdapter({
@@ -34,11 +49,16 @@ const app = await NestFactory.create<NestHonoApplication>(
},
})
);
globalThis.__APP__.app = app;
app.setGlobalPrefix("api");
app.enableShutdownHooks();
app.useGlobalPipes(new CustomZodValidationPipe());
// Validation Pipe (Zod) and Transform Interceptor
app.useGlobalInterceptors(new TransformInterceptor());
app.useGlobalPipes(new ZodValidationPipe());
app.useStaticAssets("/*", { root: "./dist/client" });
await app.init();
// Hono Zone Middleware
hono.use(async (c, next) => {
c.set("fetch", hono.request.bind(hono));
const ua = c.req.header("User-Agent");
@@ -48,9 +68,6 @@ hono.use(async (c, next) => {
c.set("isMobile", isMobile({ ua }));
await next();
}, contextStorage());
app.useStaticAssets("/*", { root: "./dist/client" });
await app.init();
hono.get("/.well-known/*", (c) => {
return c.json({ ok: true });
});

View File

@@ -2,10 +2,8 @@ import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common";
import { APP_FILTER } from "@nestjs/core";
import { HttpExceptionFilter } from "./common/filter/http-exception.filter";
import { LoggerMiddleware } from "./middleware";
import { AuthModule } from "./modules/auth/auth.module";
@Module({
imports: [AuthModule],
providers: [
{
provide: APP_FILTER,

View File

@@ -1,24 +1,18 @@
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
} from '@nestjs/common';
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Response } from '../interfaces/response.interface';
import { InternalHonoRes } from '../adapter/hono/_util';
@Injectable()
export class TransformInterceptor<T>
implements NestInterceptor<T, any>
{
intercept(
context: ExecutionContext,
next: CallHandler,
) {
return next.handle().pipe(
map((data) => ({
success: true,
data,
})),
);
}
export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
return next.handle().pipe(
map(data => ({
statusCode: context.switchToHttp().getResponse<InternalHonoRes>().res.status,
message: 'Success',
data,
})),
);
}
}

View File

@@ -0,0 +1,12 @@
// import { ApiProperty } from '@nestjs/swagger';
export class Response<T> {
// @ApiProperty()
statusCode: number = 200;
// @ApiProperty()
message: string = 'Success';
// @ApiProperty()
data: T = {} as T;
}

View File

@@ -1,13 +0,0 @@
import { Controller, Get } from "@nestjs/common";
@Controller('auth')
export class AuthController {
constructor() {}
@Get('/')
index() {
return { message: 'Auth Controller is working' };
// throw new Error('Not implemented');
// return 'Hello Auth';
}
}

View File

@@ -1,16 +0,0 @@
import { Module } from '@nestjs/common';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
@Module({
imports: [
// hono-di:imports
],
controllers: [
AuthController, // hono-di:controllers
],
providers: [
AuthService, // hono-di:providers
],
})
export class AuthModule {}

View File

@@ -1,6 +0,0 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class AuthService {
constructor() {}
}

9
src/type.d.ts vendored
View File

@@ -7,4 +7,11 @@ declare module "@httpClientAdapter" {
url: string;
pathsForGET?: string[];
}): TinyRpcClientAdapter;
}
}
declare global {
var __APP__: {
app?: NestHonoApplication;
hono?: Hono;
server?: Bun.Server;
} | undefined;
}