refactor(all): refactoring to remove monorepo taking to long to get it wokring as intended

This commit is contained in:
2025-02-19 10:06:43 -06:00
parent 5f7a3dd182
commit b15f1d8ae8
28 changed files with 736 additions and 112 deletions

View File

@@ -11,5 +11,5 @@ get {
}
auth:bearer {
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImlhdCI6MTczOTgyMTgyNiwiZXhwIjoxNzM5ODI1NDI2fQ.N5pn4PaPDhM_AXAOTGwd-_TOP9UOU1wK0vmICVE7vEc
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImlhdCI6MTczOTgyNjEwNiwiZXhwIjoxNzM5ODI2MTY2fQ.y8wm4PuduJdXp_fPnRohQ8VOlNRMeYszzcPdOLRwzic
}

View File

@@ -7,13 +7,14 @@ meta {
get {
url: http://localhost:4000/api/auth/session
body: none
auth: bearer
auth: basic
}
headers {
:
}
auth:bearer {
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImlhdCI6MTczOTgyNzE1NiwiZXhwIjoxNzM5ODI3MjE2fQ.VE9URMrRI_5_wc8CEmj-VEVeP01LL412vKhNwWRRHRM
auth:basic {
username: admin
password: pass123
}

View File

@@ -9,5 +9,8 @@
},
"devDependencies": {
"typescript": "^5.7.3"
},
"dependencies": {
"@scalar/hono-api-reference": "^0.5.174"
}
}

View File

@@ -1,15 +1,16 @@
import {Hono} from "hono";
import {serveStatic} from "hono/bun";
import {logger} from "hono/logger";
import {ocmeService} from "./services/ocmeServer";
import {authMiddleware} from "lst-auth";
import {cors} from "hono/cors";
import {OpenAPIHono} from "@hono/zod-openapi";
//import { expensesRoute } from "./routes/expenses";
import login from "./route/auth/login";
import session from "./route/auth/session";
//routes
import auth from "./services/auth/authService";
import scalar from "./route/scalar";
// services
import {ocmeService} from "./services/ocme/ocmeServer";
const app = new Hono();
const app = new OpenAPIHono();
app.use("*", logger());
app.use(
@@ -24,24 +25,32 @@ app.use(
})
);
app.doc("/api", {
openapi: "3.0.0",
info: {
version: "1.0.0",
title: "LST API",
},
});
// as we dont want to change ocme again well use a proxy to this
app.all("/ocme/*", async (c) => {
return ocmeService(c);
});
app.basePath("/api/auth").route("/login", login).route("/session", session);
const routes = [scalar, auth] as const;
routes.forEach((route) => {
app.route("/", route);
});
//app.basePath("/api/auth").route("/login", login).route("/session", session).route("/register", register);
//auth stuff
app.get("/api/protected", authMiddleware, (c) => {
return c.json({success: true, message: "is authenticated"});
});
app.get("/api/test", (c) => {
return c.json({success: true, message: "hello from bun"});
});
// const authRoute = app.basePath("/api/auth").route("*", )
//const apiRoute = app.basePath("/api").route("/expenses", expensesRoute);
app.get("*", serveStatic({root: "../frontend/dist"}));
app.get("*", serveStatic({path: "../frontend/dist/index.html"}));

View File

@@ -1,54 +0,0 @@
import { Context } from "hono";
import { authHandler, initAuthConfig, verifyAuth } from "@hono/auth-js";
import Credentials from "@auth/core/providers/credentials";
import { AuthConfig } from "@auth/core/types";
export const authConfig: AuthConfig = {
secret: process.env.AUTH_SECRET,
providers: [
Credentials({
name: "Credentials",
credentials: {
username: { label: "Username", type: "text" },
password: { label: "Password", type: "password" },
},
async authorize(credentials) {
// Add your authentication logic here
const user = { id: "1", name: "John Doe", email: "john@example.com" };
if (
credentials?.username === "john" &&
credentials?.password === "password"
) {
return user;
}
return null;
},
}),
],
session: {
strategy: "jwt",
},
callbacks: {
// async session({ session, token }) {
// session.user.id = token.sub;
// return session;
// },
async jwt({ token, user }) {
if (user) {
token.sub = user.id;
}
return token;
},
},
};
// auth.use("/api/auth/*", authHandler());
// auth.use("/api/*", verifyAuth());
// auth.get("/api/protected", (c) => {
// const auth = c.get("authUser");
// return c.json(auth);
// });
// export default auth;

View File

@@ -0,0 +1,13 @@
import {OpenAPIHono} from "@hono/zod-openapi";
const app = new OpenAPIHono();
// the doc endpoint
app.doc("/api", {
openapi: "3.0.0",
info: {
version: "1.0.0",
title: "LST API",
},
});
export default app;

View File

@@ -1,28 +0,0 @@
import {Hono} from "hono";
import {login} from "lst-auth";
const router = new Hono().post("/", async (c) => {
let body = {username: "", password: "", error: ""};
try {
body = await c.req.json();
} catch (error) {
return c.json({success: false, message: "Username and password required"}, 400);
}
if (!body?.username || !body?.password) {
return c.json({message: "Username and password required"}, 400);
}
try {
const {token, user} = login(body?.username, body?.password);
// Set the JWT as an HTTP-only cookie
c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Secure; Path=/; SameSite=None; Max-Age=3600`);
return c.json({message: "Login successful", user});
} catch (err) {
// console.log(err);
return c.json({message: err}, 401);
}
});
export default router;

View File

@@ -0,0 +1,79 @@
import {OpenAPIHono} from "@hono/zod-openapi";
import {apiReference} from "@scalar/hono-api-reference";
const app = new OpenAPIHono();
app.get(
"/api/docs",
apiReference({
theme: "kepler",
layout: "classic",
defaultHttpClient: {targetKey: "node", clientKey: "axios"},
pageTitle: "Lst API Reference",
hiddenClients: [
"libcurl",
"clj_http",
"httpclient",
"restsharp",
"native",
"http1.1",
"asynchttp",
"nethttp",
"okhttp",
"unirest",
"xhr",
"fetch",
"jquery",
"okhttp",
"native",
"request",
"unirest",
"nsurlsession",
"cohttp",
"curl",
"guzzle",
"http1",
"http2",
"webrequest",
"restmethod",
"python3",
"requests",
"httr",
"native",
"curl",
"httpie",
"wget",
"nsurlsession",
"undici",
],
spec: {
url: "/api",
},
baseServerURL: "https://scalar.com",
servers: [
{
url: "http://usday1vms006:3000",
description: "Production",
},
{
url: "http://localhost:4000",
description: "dev server",
},
],
// authentication: {
// preferredSecurityScheme: {'bearerAuth'},
// },
// metaData: {
// title: "Page title",
// description: "My page page",
// ogDescription: "Still about my my page",
// ogTitle: "Page title",
// ogImage: "https://example.com/image.png",
// twitterCard: "summary_large_image",
// // Add more...
// },
})
);
export default app;

View File

@@ -0,0 +1,12 @@
import {OpenAPIHono} from "@hono/zod-openapi";
import login from "./routes/login";
import register from "./routes/register";
import session from "./routes/session";
const app = new OpenAPIHono();
app.route("api/auth/login", login);
app.route("api/auth//register", register);
app.route("api/auth/session", session);
export default app;

View File

@@ -0,0 +1 @@
export const registerUser = async () => {};

View File

@@ -0,0 +1,17 @@
import bcrypt from "bcrypt";
export const passwordUpdate = (password: string) => {
// encypt password
let pass: string = process.env.SECRET;
let salt: string = process.env.SALTING;
if (!pass || !salt) {
pass = "error";
} else {
pass = bcrypt.hashSync(process.env.SECRET + password, parseInt(process.env.SALTING));
pass = btoa(pass);
}
return pass;
};

View File

@@ -0,0 +1,112 @@
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
import {login} from "lst-auth";
const app = new OpenAPIHono();
const UserSchema = z
.object({
username: z.string().min(3).openapi({example: "smith002"}),
password: z.string().openapi({example: "password123"}),
})
.openapi("User");
// Define the response schema for the login endpoint
const LoginResponseSchema = z
.object({
message: z.string().openapi({example: "Login successful"}),
user: z.object({
username: z.string().openapi({example: "smith002"}),
// Add other user fields as needed
}),
})
.openapi("LoginResponse");
const route = createRoute({
tags: ["Auth"],
summary: "Login as user",
description: "Login as a user to get a JWT token",
method: "post",
path: "/",
request: {body: {content: {"application/json": {schema: UserSchema}}}},
responses: {
200: {
content: {
"application/json": {
schema: LoginResponseSchema,
},
},
description: "Login successful",
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: false}),
message: z.string().openapi({example: "Username and password required"}),
}),
},
},
description: "Bad request",
},
401: {
content: {
"application/json": {
schema: z.object({
message: z.string().openapi({example: "Invalid credentials"}),
}),
},
},
description: "Unauthorized",
},
},
});
app.openapi(route, async (c) => {
let body: {username: string; password: string};
try {
body = await c.req.json();
} catch (error) {
return c.json({success: false, message: "Username and password required"}, 400);
}
if (!body?.username || !body?.password) {
return c.json({success: false, message: "Username and password required"}, 400);
}
try {
const {token, user} = login(body.username, body.password);
// Set the JWT as an HTTP-only cookie
c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Path=/; SameSite=None; Max-Age=3600`);
return c.json({message: "Login successful", user});
} catch (err) {
return c.json({message: err instanceof Error ? err.message : "Invalid credentials"}, 401);
}
});
/*
let body = {username: "", password: "", error: ""};
try {
body = await c.req.json();
} catch (error) {
return c.json({success: false, message: "Username and password required"}, 400);
}
if (!body?.username || !body?.password) {
return c.json({message: "Username and password required"}, 400);
}
try {
const {token, user} = login(body?.username, body?.password);
// Set the JWT as an HTTP-only cookie
c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Secure; Path=/; SameSite=None; Max-Age=3600`);
return c.json({message: "Login successful", user});
} catch (err) {
// console.log(err);
return c.json({message: err}, 401);
}
*/
export default app;

View File

@@ -0,0 +1,33 @@
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
const app = new OpenAPIHono();
const UserSchema = z
.object({
id: z.string().openapi({example: "123"}),
name: z.string().min(3).openapi({example: "John Doe"}),
age: z.number().openapi({example: 42}),
})
.openapi("User");
app.openapi(
createRoute({
tags: ["Auth"],
summary: "Register a new user",
method: "post",
path: "/",
request: {params: UserSchema},
responses: {
200: {
content: {"application/json": {schema: UserSchema}},
description: "Retrieve the user",
},
},
}),
(c) => {
const {id} = c.req.valid("param");
return c.json({id, age: 20, name: "Ultra-man"});
}
);
export default app;

View File

@@ -1,11 +1,29 @@
import {Hono} from "hono";
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
import {verify} from "hono/jwt";
const app = new Hono();
const session = new OpenAPIHono();
const tags = ["Auth"];
const JWT_SECRET = "your-secret-key";
app.get("/", async (c) => {
const route = createRoute({
tags: ["Auth"],
summary: "Checks a user session based on there token",
description: "Can post there via Authentiaction header or cookies",
method: "get",
path: "/",
request: {body: {content: {"application/json": {schema: {username: "", password: ""}}}}},
responses: {
200: {
content: {
"application/json": {
schema: {session: ""},
},
},
description: "Login successful",
},
},
});
session.openapi(route, async (c) => {
const authHeader = c.req.header("Authorization");
const cookies = c.req.header("cookie");
@@ -17,13 +35,6 @@ app.get("/", async (c) => {
if (!authHeader && !cookies) {
return c.json({error: "Unauthorized"}, 401);
}
// if (!cookies || !cookies.startsWith("Bearer ")) {
// return c.json({error: "Unauthorized"}, 401);
// }
// if (!authHeader || !authHeader.startsWith("Bearer ")) {
// return c.json({error: "Unauthorized"}, 401);
// }
const token = cookies?.split("auth_token=")[1].split(";")[0] || authHeader?.split("Bearer ")[1] || "";
@@ -35,4 +46,4 @@ app.get("/", async (c) => {
}
});
export default app;
export default session;

10
load-env.ts Normal file
View File

@@ -0,0 +1,10 @@
const path = require("path");
const dotenv = require("dotenv");
const dotenvExpand = require("dotenv-expand");
// Load the root .env file
const envPath = path.resolve(__dirname, ".env");
const envConfig = dotenv.config({path: envPath});
// Expand variables (e.g., `${VAR}`) in the .env file
dotenvExpand.expand(envConfig);

View File

@@ -29,9 +29,14 @@
"@hono/zod-openapi": "^0.18.4",
"@shared/lib": "*",
"@types/bun": "^1.2.2",
"axios": "^1.7.9",
"bcrypt": "^5.1.1",
"compression": "^1.8.0",
"concurrently": "^9.1.2",
"cookie": "^1.0.2",
"date-fns": "^4.1.0",
"dotenv": "^16.4.7",
"dotenv-expand": "^12.0.1",
"hono": "^4.7.1",
"http-proxy-middleware": "^3.0.3",
"jsonwebtoken": "^9.0.2",

175
packages/database/.gitignore vendored Normal file
View File

@@ -0,0 +1,175 @@
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
# Logs
logs
_.log
npm-debug.log_
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Caches
.cache
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# Runtime data
pids
_.pid
_.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# IntelliJ based IDEs
.idea
# Finder (MacOS) folder config
.DS_Store

View File

@@ -0,0 +1,15 @@
# database
To install dependencies:
```bash
bun install
```
To run:
```bash
bun run index.ts
```
This project was created using `bun init` in bun v1.2.2. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.

View File

@@ -0,0 +1,8 @@
import {defineConfig} from "drizzle-kit";
export default defineConfig({
dialect: "postgresql", // 'mysql' | 'sqlite' | 'turso'
schema: "./schema",
dbCredentials: {
url: "postgresql://postgres:nova0511@localhost:5432/lst_db",
},
});

View File

@@ -0,0 +1,12 @@
CREATE TABLE "users" (
"id" serial PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"title" text NOT NULL,
"passwordToken" text NOT NULL,
"passwordTokenExpires" timestamp,
"active" boolean DEFAULT true NOT NULL,
"pingcode" numeric,
"add_Date" timestamp DEFAULT now(),
"add_User" text DEFAULT 'LST_System' NOT NULL,
"upd_date" timestamp DEFAULT now()
);

View File

@@ -0,0 +1,96 @@
{
"id": "d0e2effa-c6ac-4f81-b546-ef6b10037eca",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.users": {
"name": "users",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": true
},
"passwordToken": {
"name": "passwordToken",
"type": "text",
"primaryKey": false,
"notNull": true
},
"passwordTokenExpires": {
"name": "passwordTokenExpires",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"active": {
"name": "active",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"pingcode": {
"name": "pingcode",
"type": "numeric",
"primaryKey": false,
"notNull": false
},
"add_Date": {
"name": "add_Date",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"add_User": {
"name": "add_User",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'LST_System'"
},
"upd_date": {
"name": "upd_date",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -0,0 +1,13 @@
{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1739914245651,
"tag": "0000_stormy_thunderbolt",
"breakpoints": true
}
]
}

View File

@@ -0,0 +1,7 @@
import {drizzle} from "drizzle-orm/postgres-js";
import postgres from "postgres";
import "../../load-env";
const queryClient = postgres("postgresql://postgres:nova0511@localhost:5432/lst_db");
export const db = drizzle(queryClient);

View File

@@ -0,0 +1,20 @@
{
"name": "database",
"module": "index.ts",
"type": "module",
"devDependencies": {
"@types/bun": "latest",
"@types/pg": "^8.11.11",
"drizzle-kit": "^0.30.4",
"tsx": "^4.19.2"
},
"peerDependencies": {
"typescript": "^5.0.0"
},
"dependencies": {
"drizzle-orm": "^0.39.3",
"drizzle-zod": "^0.7.0",
"pg": "^8.13.3",
"postgres": "^3.4.5"
}
}

View File

@@ -0,0 +1,27 @@
import {text, pgTable, serial, numeric, index, timestamp, boolean} from "drizzle-orm/pg-core";
import {createInsertSchema, createSelectSchema} from "drizzle-zod";
import {z} from "zod";
export const users = pgTable("users", {
user_id: serial("id").primaryKey(),
username: text("user_id").notNull(),
email: text("title").notNull(),
passwordToken: text("passwordToken").notNull(),
passwordTokenExpires: timestamp("passwordTokenExpires"),
acitve: boolean("active").default(true).notNull(),
pinCode: numeric("pingcode"),
lastLogin: timestamp("add_Date").defaultNow(),
add_User: text("add_User").default("LST_System").notNull(),
add_Date: timestamp("add_Date").defaultNow(),
upd_user: text("add_User").default("LST_System").notNull(),
upd_date: timestamp("upd_date").defaultNow(),
});
// Schema for inserting a user - can be used to validate API requests
export const insertUsersSchema = createInsertSchema(users, {
username: z.string().min(3, {message: "Username must be at least 3 characters"}),
email: z.string().email({message: "Invalid email"}),
passwordToken: z.string().min(8, {message: "Password must be at least 8 characters"}),
});
// Schema for selecting a Expenses - can be used to validate API responses
export const selectExpensesSchema = createSelectSchema(users);

View File

@@ -0,0 +1,27 @@
{
"compilerOptions": {
// Enable latest features
"lib": ["ESNext", "DOM"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}