feat(app): added better auth for better auth stuff vs my home written broken one
This commit is contained in:
33
app/main.ts
33
app/main.ts
@@ -13,7 +13,10 @@ import { returnFunc } from "./src/pkg/utils/return.js";
|
||||
import { initializeProdPool } from "./src/pkg/prodSql/prodSqlConnect.js";
|
||||
import { tryCatch } from "./src/pkg/utils/tryCatch.js";
|
||||
import os from "os";
|
||||
import cors from "cors";
|
||||
import { sendNotify } from "./src/pkg/utils/notify.js";
|
||||
import { toNodeHandler } from "better-auth/node";
|
||||
import { auth } from "./src/pkg/auth/auth.js";
|
||||
|
||||
const main = async () => {
|
||||
const env = validateEnv(process.env);
|
||||
@@ -59,9 +62,6 @@ const main = async () => {
|
||||
// express app
|
||||
const app = express();
|
||||
|
||||
// global middleware
|
||||
app.use(express.json());
|
||||
|
||||
// global env that run only in dev
|
||||
if (process.env.NODE_ENV?.trim() !== "production") {
|
||||
app.use(morgan("tiny"));
|
||||
@@ -73,6 +73,33 @@ const main = async () => {
|
||||
);
|
||||
}
|
||||
|
||||
// global middleware
|
||||
app.all(basePath + "/api/auth/*splat", toNodeHandler(auth)); // sign-in sign-out
|
||||
app.use(express.json());
|
||||
|
||||
const allowedOrigins = [
|
||||
"http://localhost:5173", // dev
|
||||
"http://localhost:4200",
|
||||
env.BETTER_AUTH_URL, // prod
|
||||
];
|
||||
|
||||
app.use(
|
||||
cors({
|
||||
origin: (origin, callback) => {
|
||||
// allow requests with no origin (like curl, service workers, PWAs)
|
||||
if (!origin) return callback(null, true);
|
||||
|
||||
if (allowedOrigins.includes(origin)) {
|
||||
return callback(null, true);
|
||||
} else {
|
||||
return callback(new Error("Not allowed by CORS"));
|
||||
}
|
||||
},
|
||||
methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
|
||||
credentials: true,
|
||||
})
|
||||
);
|
||||
|
||||
// docs and api stuff
|
||||
app.use(
|
||||
basePath + "/d",
|
||||
|
||||
15
app/src/internal/auth/routes/me.ts
Normal file
15
app/src/internal/auth/routes/me.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Router } from "express";
|
||||
import { auth } from "../../../pkg/auth/auth.js";
|
||||
import { fromNodeHeaders } from "better-auth/node";
|
||||
|
||||
const router = Router();
|
||||
|
||||
// GET /health
|
||||
router.get("/", async (req, res) => {
|
||||
const session = await auth.api.getSession({
|
||||
headers: fromNodeHeaders(req.headers),
|
||||
});
|
||||
return res.json(session);
|
||||
});
|
||||
|
||||
export default router;
|
||||
44
app/src/internal/auth/routes/register.ts
Normal file
44
app/src/internal/auth/routes/register.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { Router } from "express";
|
||||
import type { Request, Response } from "express";
|
||||
import z from "zod";
|
||||
import { auth } from "../../../pkg/auth/auth.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
const registerSchema = z.object({
|
||||
email: z.email(),
|
||||
name: z.string().min(2).max(100),
|
||||
password: z.string().min(8, "Password must be at least 8 characters"),
|
||||
username: z
|
||||
.string()
|
||||
.min(3)
|
||||
.max(32)
|
||||
.regex(/^[a-zA-Z0-9_]+$/, "Only alphanumeric + underscores"),
|
||||
displayUsername: z.string().min(2).max(100).optional(), // optional in your API, but supported
|
||||
});
|
||||
|
||||
router.post("/", async (req: Request, res: Response) => {
|
||||
try {
|
||||
// Parse + validate incoming JSON against Zod schema
|
||||
const validated = registerSchema.parse(req.body);
|
||||
|
||||
// Call Better Auth signUp
|
||||
const user = await auth.api.signUpEmail({
|
||||
body: validated,
|
||||
});
|
||||
|
||||
return res.status(201).json(user);
|
||||
} catch (err) {
|
||||
if (err instanceof z.ZodError) {
|
||||
const flattened = z.flattenError(err);
|
||||
return res.status(400).json({
|
||||
error: "Validation failed",
|
||||
details: flattened,
|
||||
});
|
||||
}
|
||||
console.error(err);
|
||||
return res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
8
app/src/internal/auth/routes/routes.ts
Normal file
8
app/src/internal/auth/routes/routes.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { Express, Request, Response } from "express";
|
||||
import me from "./me.js";
|
||||
import register from "./register.js";
|
||||
|
||||
export const setupAuthRoutes = (app: Express, basePath: string) => {
|
||||
app.use(basePath + "/api/me", me);
|
||||
app.use(basePath + "/api/auth/register", register);
|
||||
};
|
||||
@@ -1,10 +1,14 @@
|
||||
import type { Express, Request, Response } from "express";
|
||||
|
||||
import healthRoutes from "./routes/healthRoutes.js";
|
||||
import { setupAuthRoutes } from "../auth/routes/routes.js";
|
||||
|
||||
export const setupRoutes = (app: Express, basePath: string) => {
|
||||
// Root / health check
|
||||
app.use(basePath + "/health", healthRoutes);
|
||||
app.use(basePath + "/api/system/health", healthRoutes);
|
||||
|
||||
// all routes
|
||||
setupAuthRoutes(app, basePath);
|
||||
|
||||
// always try to go to the app weather we are in dev or in production.
|
||||
app.get(basePath + "/", (req: Request, res: Response) => {
|
||||
|
||||
19
app/src/pkg/auth/auth-client.ts
Normal file
19
app/src/pkg/auth/auth-client.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { createAuthClient } from "better-auth/client";
|
||||
|
||||
import {
|
||||
inferAdditionalFields,
|
||||
usernameClient,
|
||||
adminClient,
|
||||
apiKeyClient,
|
||||
} from "better-auth/client/plugins";
|
||||
import type { auth } from "./auth.js";
|
||||
|
||||
export const authClient = createAuthClient({
|
||||
baseURL: "http://localhost:3000",
|
||||
plugins: [
|
||||
inferAdditionalFields<typeof auth>(),
|
||||
usernameClient(),
|
||||
adminClient(),
|
||||
apiKeyClient(),
|
||||
],
|
||||
});
|
||||
52
app/src/pkg/auth/auth.ts
Normal file
52
app/src/pkg/auth/auth.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
||||
import { db } from "../db/db.js";
|
||||
import { username, admin, apiKey, jwt } from "better-auth/plugins";
|
||||
import { betterAuth } from "better-auth";
|
||||
import * as rawSchema from "../db/schema/auth-schema.js";
|
||||
import type { User } from "better-auth/types";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
export const schema = {
|
||||
user: rawSchema.user,
|
||||
session: rawSchema.session,
|
||||
account: rawSchema.account,
|
||||
verification: rawSchema.verification,
|
||||
jwks: rawSchema.jwks,
|
||||
apiKey: rawSchema.apikey, // 🔑 rename to apiKey
|
||||
};
|
||||
|
||||
export const auth = betterAuth({
|
||||
database: drizzleAdapter(db, {
|
||||
provider: "pg",
|
||||
schema,
|
||||
}),
|
||||
appName: "lst",
|
||||
emailAndPassword: {
|
||||
enabled: true,
|
||||
minPasswordLength: 8, // optional config
|
||||
},
|
||||
plugins: [
|
||||
jwt({ jwt: { expirationTime: "1h" } }),
|
||||
apiKey(),
|
||||
admin(),
|
||||
username(),
|
||||
],
|
||||
session: {
|
||||
expiresIn: 60 * 60,
|
||||
updateAge: 60 * 1,
|
||||
cookieCache: {
|
||||
enabled: true,
|
||||
maxAge: 5 * 60, // Cache duration in seconds
|
||||
},
|
||||
},
|
||||
events: {
|
||||
async onSignInSuccess({ user }: { user: User }) {
|
||||
await db
|
||||
.update(schema.user)
|
||||
.set({ lastLogin: new Date() })
|
||||
.where(eq(schema.user.id, user.id));
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export type Auth = typeof auth;
|
||||
108
app/src/pkg/db/schema/auth-schema.ts
Normal file
108
app/src/pkg/db/schema/auth-schema.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import {
|
||||
pgTable,
|
||||
text,
|
||||
timestamp,
|
||||
boolean,
|
||||
integer,
|
||||
} from "drizzle-orm/pg-core";
|
||||
|
||||
export const user = pgTable("user", {
|
||||
id: text("id").primaryKey(),
|
||||
name: text("name").notNull(),
|
||||
email: text("email").notNull().unique(),
|
||||
emailVerified: boolean("email_verified").default(false).notNull(),
|
||||
image: text("image"),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at")
|
||||
.defaultNow()
|
||||
.$onUpdate(() => /* @__PURE__ */ new Date())
|
||||
.notNull(),
|
||||
role: text("role"),
|
||||
banned: boolean("banned").default(false),
|
||||
banReason: text("ban_reason"),
|
||||
banExpires: timestamp("ban_expires"),
|
||||
username: text("username").unique(),
|
||||
displayUsername: text("display_username"),
|
||||
lastLogin: timestamp("last_login"),
|
||||
});
|
||||
|
||||
export const session = pgTable("session", {
|
||||
id: text("id").primaryKey(),
|
||||
expiresAt: timestamp("expires_at").notNull(),
|
||||
token: text("token").notNull().unique(),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at")
|
||||
.$onUpdate(() => /* @__PURE__ */ new Date())
|
||||
.notNull(),
|
||||
ipAddress: text("ip_address"),
|
||||
userAgent: text("user_agent"),
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id, { onDelete: "cascade" }),
|
||||
impersonatedBy: text("impersonated_by"),
|
||||
});
|
||||
|
||||
export const account = pgTable("account", {
|
||||
id: text("id").primaryKey(),
|
||||
accountId: text("account_id").notNull(),
|
||||
providerId: text("provider_id").notNull(),
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id, { onDelete: "cascade" }),
|
||||
accessToken: text("access_token"),
|
||||
refreshToken: text("refresh_token"),
|
||||
idToken: text("id_token"),
|
||||
accessTokenExpiresAt: timestamp("access_token_expires_at"),
|
||||
refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
|
||||
scope: text("scope"),
|
||||
password: text("password"),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at")
|
||||
.$onUpdate(() => /* @__PURE__ */ new Date())
|
||||
.notNull(),
|
||||
});
|
||||
|
||||
export const verification = pgTable("verification", {
|
||||
id: text("id").primaryKey(),
|
||||
identifier: text("identifier").notNull(),
|
||||
value: text("value").notNull(),
|
||||
expiresAt: timestamp("expires_at").notNull(),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at")
|
||||
.defaultNow()
|
||||
.$onUpdate(() => /* @__PURE__ */ new Date())
|
||||
.notNull(),
|
||||
});
|
||||
|
||||
export const jwks = pgTable("jwks", {
|
||||
id: text("id").primaryKey(),
|
||||
publicKey: text("public_key").notNull(),
|
||||
privateKey: text("private_key").notNull(),
|
||||
createdAt: timestamp("created_at").notNull(),
|
||||
});
|
||||
|
||||
export const apikey = pgTable("apikey", {
|
||||
id: text("id").primaryKey(),
|
||||
name: text("name"),
|
||||
start: text("start"),
|
||||
prefix: text("prefix"),
|
||||
key: text("key").notNull(),
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id, { onDelete: "cascade" }),
|
||||
refillInterval: integer("refill_interval"),
|
||||
refillAmount: integer("refill_amount"),
|
||||
lastRefillAt: timestamp("last_refill_at"),
|
||||
enabled: boolean("enabled").default(true),
|
||||
rateLimitEnabled: boolean("rate_limit_enabled").default(true),
|
||||
rateLimitTimeWindow: integer("rate_limit_time_window").default(86400000),
|
||||
rateLimitMax: integer("rate_limit_max").default(10),
|
||||
requestCount: integer("request_count").default(0),
|
||||
remaining: integer("remaining"),
|
||||
lastRequest: timestamp("last_request"),
|
||||
expiresAt: timestamp("expires_at"),
|
||||
createdAt: timestamp("created_at").notNull(),
|
||||
updatedAt: timestamp("updated_at").notNull(),
|
||||
permissions: text("permissions"),
|
||||
metadata: text("metadata"),
|
||||
});
|
||||
17
app/src/pkg/db/schema/user_roles.ts
Normal file
17
app/src/pkg/db/schema/user_roles.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { pgTable, text, uuid, uniqueIndex } from "drizzle-orm/pg-core";
|
||||
import { user } from "./auth-schema.js";
|
||||
|
||||
export const userRole = pgTable(
|
||||
"user_role",
|
||||
{
|
||||
userRoleId: uuid("user_role_id").defaultRandom().primaryKey(),
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id, { onDelete: "cascade" }),
|
||||
module: text("module").notNull(), // e.g. "siloAdjustments"
|
||||
role: text("role").notNull(), // e.g. "admin" | "manager" | "viewer"
|
||||
},
|
||||
(table) => [
|
||||
uniqueIndex("unique_user_module").on(table.userId, table.module),
|
||||
]
|
||||
);
|
||||
@@ -18,6 +18,10 @@ const envSchema = z.object({
|
||||
PROD_USER: z.string(),
|
||||
PROD_PASSWORD: z.string(),
|
||||
|
||||
// auth stuff
|
||||
BETTER_AUTH_URL: z.string(),
|
||||
BETTER_AUTH_SECRET: z.string(),
|
||||
|
||||
// docker specifc
|
||||
RUNNING_IN_DOCKER: z.string().default("false"),
|
||||
});
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# What type of deploy ment do we have for the frontend
|
||||
|
||||
NODE_ENV=dev
|
||||
APP_MODE=dev
|
||||
|
||||
@@ -78,8 +78,10 @@
|
||||
<button id="USMCD1VMS036">USMCD1VMS036</button>
|
||||
<button id="USBET1VMS006">USBET1VMS006</button>
|
||||
<button id="USBOW1VMS006">USBOW1VMS006</button>
|
||||
<button id="USKSC1VMS006">USKSC1VMS006</button>
|
||||
<button id="USSLC1VMS006">USSLC1VMS006</button>
|
||||
<button id="USSTP1VMS006">USSTP1VMS006</button>
|
||||
<button id="USDAY1VMS006">USDAY1VMS006</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@@ -168,23 +170,23 @@
|
||||
const updateServerButton =
|
||||
document.getElementById("updateServerButton");
|
||||
|
||||
button.onclick = () => {
|
||||
const fromMyInput = input.value;
|
||||
if (!fromMyInput) return;
|
||||
// button.onclick = () => {
|
||||
// const fromMyInput = input.value;
|
||||
// if (!fromMyInput) return;
|
||||
|
||||
// Emit to backend (adjust event name as required)
|
||||
socket.emit("update", {
|
||||
action: "copy",
|
||||
target: fromMyInput,
|
||||
});
|
||||
// // Emit to backend (adjust event name as required)
|
||||
// socket.emit("update", {
|
||||
// action: "copy",
|
||||
// target: fromMyInput,
|
||||
// });
|
||||
|
||||
// You can define your own logMessage function
|
||||
logMessage("info", `Copying to ${fromMyInput}`);
|
||||
// // You can define your own logMessage function
|
||||
// logMessage("info", `Copying to ${fromMyInput}`);
|
||||
|
||||
input.value = "";
|
||||
// input.value = "";
|
||||
|
||||
input.focus();
|
||||
};
|
||||
// input.focus();
|
||||
// };
|
||||
|
||||
updateServerButton.onclick = () => {
|
||||
const fromMyInput = updateServerInput.value;
|
||||
@@ -246,7 +248,23 @@
|
||||
target: "USSTP1VMS006",
|
||||
drive: "d",
|
||||
}); // "frontend" = payload target
|
||||
logMessage("info", "Copying to USSLC1VMS006");
|
||||
logMessage("info", "Copying to USSTP1VMS006");
|
||||
};
|
||||
document.getElementById("USKSC1VMS006").onclick = () => {
|
||||
socket.emit("update", {
|
||||
action: "copy",
|
||||
target: "USksc1VMS006",
|
||||
drive: "e",
|
||||
}); // "frontend" = payload target
|
||||
logMessage("info", "Copying to USKSC1VMS006");
|
||||
};
|
||||
document.getElementById("USDAY1VMS006").onclick = () => {
|
||||
socket.emit("update", {
|
||||
action: "copy",
|
||||
target: "USDAY1VMS006",
|
||||
drive: "e",
|
||||
}); // "frontend" = payload target
|
||||
logMessage("info", "Copying to USDAY1VMS006");
|
||||
};
|
||||
|
||||
socket.on("logs", (msg) => logMessage("logs", msg));
|
||||
|
||||
@@ -4,7 +4,7 @@ const dbURL = `postgres://${process.env.DATABASE_USER}:${process.env.DATABASE_PA
|
||||
|
||||
export default defineConfig({
|
||||
dialect: "postgresql",
|
||||
schema: "./app/src/pkg/db/schema",
|
||||
schema: "./dist/src/pkg/db/schema",
|
||||
out: "./migrations",
|
||||
dbCredentials: { url: dbURL },
|
||||
// verbose: true, // optional, logs more details
|
||||
|
||||
302
package-lock.json
generated
302
package-lock.json
generated
@@ -10,6 +10,9 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@dotenvx/dotenvx": "^1.49.0",
|
||||
"@types/cors": "^2.8.19",
|
||||
"better-auth": "^1.3.9",
|
||||
"cors": "^2.8.5",
|
||||
"drizzle-kit": "^0.31.4",
|
||||
"drizzle-orm": "^0.44.5",
|
||||
"drizzle-zod": "^0.8.3",
|
||||
@@ -318,6 +321,20 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@better-auth/utils": {
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.2.6.tgz",
|
||||
"integrity": "sha512-3y/vaL5Ox33dBwgJ6ub3OPkVqr6B5xL2kgxNHG8eHZuryLyG/4JSPGqjbdRSgjuy9kALUZYDFl+ORIAxlWMSuA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"uncrypto": "^0.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@better-fetch/fetch": {
|
||||
"version": "1.1.18",
|
||||
"resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.18.tgz",
|
||||
"integrity": "sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA=="
|
||||
},
|
||||
"node_modules/@commitlint/config-validator": {
|
||||
"version": "19.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.8.1.tgz",
|
||||
@@ -1339,6 +1356,12 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@hexagon/base64": {
|
||||
"version": "1.1.28",
|
||||
"resolved": "https://registry.npmjs.org/@hexagon/base64/-/base64-1.1.28.tgz",
|
||||
"integrity": "sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@hutson/parse-repository-url": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz",
|
||||
@@ -1377,6 +1400,12 @@
|
||||
"integrity": "sha512-3zwefSMwHpu8iVUW8YYz227sIv6UFqO31p1Bf1ZH/Vom7CmNyUsXjDBlnNzcuhmOL1XfxZ3nvND42kR23XlbcQ==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@levischuck/tiny-cbor": {
|
||||
"version": "0.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@levischuck/tiny-cbor/-/tiny-cbor-0.2.11.tgz",
|
||||
"integrity": "sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@noble/ciphers": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz",
|
||||
@@ -1416,6 +1445,88 @@
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@peculiar/asn1-android": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.5.0.tgz",
|
||||
"integrity": "sha512-t8A83hgghWQkcneRsgGs2ebAlRe54ns88p7ouv8PW2tzF1nAW4yHcL4uZKrFpIU+uszIRzTkcCuie37gpkId0A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@peculiar/asn1-schema": "^2.5.0",
|
||||
"asn1js": "^3.0.6",
|
||||
"tslib": "^2.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@peculiar/asn1-ecc": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.5.0.tgz",
|
||||
"integrity": "sha512-t4eYGNhXtLRxaP50h3sfO6aJebUCDGQACoeexcelL4roMFRRVgB20yBIu2LxsPh/tdW9I282gNgMOyg3ywg/mg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@peculiar/asn1-schema": "^2.5.0",
|
||||
"@peculiar/asn1-x509": "^2.5.0",
|
||||
"asn1js": "^3.0.6",
|
||||
"tslib": "^2.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@peculiar/asn1-rsa": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.5.0.tgz",
|
||||
"integrity": "sha512-qMZ/vweiTHy9syrkkqWFvbT3eLoedvamcUdnnvwyyUNv5FgFXA3KP8td+ATibnlZ0EANW5PYRm8E6MJzEB/72Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@peculiar/asn1-schema": "^2.5.0",
|
||||
"@peculiar/asn1-x509": "^2.5.0",
|
||||
"asn1js": "^3.0.6",
|
||||
"tslib": "^2.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@peculiar/asn1-schema": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.5.0.tgz",
|
||||
"integrity": "sha512-YM/nFfskFJSlHqv59ed6dZlLZqtZQwjRVJ4bBAiWV08Oc+1rSd5lDZcBEx0lGDHfSoH3UziI2pXt2UM33KerPQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asn1js": "^3.0.6",
|
||||
"pvtsutils": "^1.3.6",
|
||||
"tslib": "^2.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@peculiar/asn1-x509": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.5.0.tgz",
|
||||
"integrity": "sha512-CpwtMCTJvfvYTFMuiME5IH+8qmDe3yEWzKHe7OOADbGfq7ohxeLaXwQo0q4du3qs0AII3UbLCvb9NF/6q0oTKQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@peculiar/asn1-schema": "^2.5.0",
|
||||
"asn1js": "^3.0.6",
|
||||
"pvtsutils": "^1.3.6",
|
||||
"tslib": "^2.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@simplewebauthn/browser": {
|
||||
"version": "13.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.1.2.tgz",
|
||||
"integrity": "sha512-aZnW0KawAM83fSBUgglP5WofbrLbLyr7CoPqYr66Eppm7zO86YX6rrCjRB3hQKPrL7ATvY4FVXlykZ6w6FwYYw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@simplewebauthn/server": {
|
||||
"version": "13.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@simplewebauthn/server/-/server-13.1.2.tgz",
|
||||
"integrity": "sha512-VwoDfvLXSCaRiD+xCIuyslU0HLxVggeE5BL06+GbsP2l1fGf5op8e0c3ZtKoi+vSg1q4ikjtAghC23ze2Q3H9g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@hexagon/base64": "^1.1.27",
|
||||
"@levischuck/tiny-cbor": "^0.2.2",
|
||||
"@peculiar/asn1-android": "^2.3.10",
|
||||
"@peculiar/asn1-ecc": "^2.3.8",
|
||||
"@peculiar/asn1-rsa": "^2.3.8",
|
||||
"@peculiar/asn1-schema": "^2.3.8",
|
||||
"@peculiar/asn1-x509": "^2.3.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tediousjs/connection-string": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@tediousjs/connection-string/-/connection-string-0.5.0.tgz",
|
||||
@@ -1470,6 +1581,15 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cors": {
|
||||
"version": "2.8.19",
|
||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
|
||||
"integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/express": {
|
||||
"version": "5.0.3",
|
||||
"dev": true,
|
||||
@@ -1764,6 +1884,20 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/asn1js": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.6.tgz",
|
||||
"integrity": "sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"pvtsutils": "^1.3.6",
|
||||
"pvutils": "^1.1.3",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/at-least-node": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
||||
@@ -1822,6 +1956,77 @@
|
||||
"version": "5.1.2",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/better-auth": {
|
||||
"version": "1.3.9",
|
||||
"resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.3.9.tgz",
|
||||
"integrity": "sha512-Ty6BHzuShlqSs7I4RMlBRQ3duOWNB7WWriIu2FJVGjQAOtTVvamzFCR4/j5ROFLoNkpvNTRF7BJozsrMICL1gw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@better-auth/utils": "0.2.6",
|
||||
"@better-fetch/fetch": "^1.1.18",
|
||||
"@noble/ciphers": "^2.0.0",
|
||||
"@noble/hashes": "^2.0.0",
|
||||
"@simplewebauthn/browser": "^13.1.2",
|
||||
"@simplewebauthn/server": "^13.1.2",
|
||||
"better-call": "1.0.18",
|
||||
"defu": "^6.1.4",
|
||||
"jose": "^6.1.0",
|
||||
"kysely": "^0.28.5",
|
||||
"nanostores": "^0.11.4",
|
||||
"zod": "^4.1.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@lynx-js/react": "*",
|
||||
"react": "^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@lynx-js/react": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/better-auth/node_modules/@noble/ciphers": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.0.0.tgz",
|
||||
"integrity": "sha512-j/l6jpnpaIBM87cAYPJzi/6TgqmBv9spkqPyCXvRYsu5uxqh6tPJZDnD85yo8VWqzTuTQPgfv7NgT63u7kbwAQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/better-auth/node_modules/@noble/hashes": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.0.tgz",
|
||||
"integrity": "sha512-h8VUBlE8R42+XIDO229cgisD287im3kdY6nbNZJFjc6ZvKIXPYXe6Vc/t+kyjFdMFyt5JpapzTsEg8n63w5/lw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/better-call": {
|
||||
"version": "1.0.18",
|
||||
"resolved": "https://registry.npmjs.org/better-call/-/better-call-1.0.18.tgz",
|
||||
"integrity": "sha512-Ojyck3P3fs/egBmCW50tvfbCJorNV5KphfPOKrkCxPfOr8Brth1ruDtAJuhHVHEUiWrXv+vpEgWQk7m7FzhbbQ==",
|
||||
"dependencies": {
|
||||
"@better-fetch/fetch": "^1.1.4",
|
||||
"rou3": "^0.5.1",
|
||||
"set-cookie-parser": "^2.7.1",
|
||||
"uncrypto": "^0.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.3.0",
|
||||
"dev": true,
|
||||
@@ -2730,6 +2935,19 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"object-assign": "^4",
|
||||
"vary": "^1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/cosmiconfig": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz",
|
||||
@@ -2970,6 +3188,12 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/defu": {
|
||||
"version": "6.1.4",
|
||||
"resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
|
||||
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/depd": {
|
||||
"version": "2.0.0",
|
||||
"license": "MIT",
|
||||
@@ -4729,6 +4953,15 @@
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/jose": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-6.1.0.tgz",
|
||||
"integrity": "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/panva"
|
||||
}
|
||||
},
|
||||
"node_modules/joycon": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz",
|
||||
@@ -4887,6 +5120,15 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/kysely": {
|
||||
"version": "0.28.5",
|
||||
"resolved": "https://registry.npmjs.org/kysely/-/kysely-0.28.5.tgz",
|
||||
"integrity": "sha512-rlB0I/c6FBDWPcQoDtkxi9zIvpmnV5xoIalfCMSMCa7nuA6VGA3F54TW9mEgX4DVf10sXAWCF5fDbamI/5ZpKA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
@@ -5557,6 +5799,21 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/nanostores": {
|
||||
"version": "0.11.4",
|
||||
"resolved": "https://registry.npmjs.org/nanostores/-/nanostores-0.11.4.tgz",
|
||||
"integrity": "sha512-k1oiVNN4hDK8NcNERSZLQiMfRzEGtfnvZvdBvey3SQbgn8Dcrk0h1I6vpxApjb10PFUflZrgJ2WEZyJQ+5v7YQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/native-duplexpair": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/native-duplexpair/-/native-duplexpair-1.0.0.tgz",
|
||||
@@ -5613,6 +5870,15 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.4",
|
||||
"license": "MIT",
|
||||
@@ -6284,6 +6550,24 @@
|
||||
"once": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/pvtsutils": {
|
||||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz",
|
||||
"integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/pvutils": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz",
|
||||
"integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/q": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
|
||||
@@ -6631,6 +6915,12 @@
|
||||
"rimraf": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/rou3": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/rou3/-/rou3-0.5.1.tgz",
|
||||
"integrity": "sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/router": {
|
||||
"version": "2.2.0",
|
||||
"license": "MIT",
|
||||
@@ -6769,6 +7059,12 @@
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/set-cookie-parser": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
|
||||
"integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"license": "ISC"
|
||||
@@ -7446,6 +7742,12 @@
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uncrypto": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz",
|
||||
"integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.10.0",
|
||||
"license": "MIT"
|
||||
|
||||
10
package.json
10
package.json
@@ -8,8 +8,8 @@
|
||||
"dev:app": "dotenvx run -f .env -- tsx watch app/main.ts",
|
||||
"dev:docs": "npm run translateDocs && cd lstDocs && npm start",
|
||||
"dev:front": "cd frontend && npm run dev",
|
||||
"dev:db:migrate": "npx drizzle-kit push --config=drizzle-dev.config.ts",
|
||||
"dev:db:generate": "npx drizzle-kit generate --config=drizzle-dev.config.ts",
|
||||
"dev:db:migrate": "npx drizzle-kit push",
|
||||
"dev:db:generate": "tsc && npx drizzle-kit generate --config=drizzle-dev.config.ts",
|
||||
"dev": "concurrently -n \"server,frontend,docs\" -c \"#007755,#2f6da3,#DB4FE0\" \"npm run dev:app\" \"npm run dev:front\" \"npm run dev:docs\"",
|
||||
"copy:docs": "node scripts/lstDocCopy.mjs",
|
||||
"build:app": "rimraf dist && npx tsc",
|
||||
@@ -29,7 +29,8 @@
|
||||
"deploy": "standard-version --conventional-commits && npm run translateDocs && npm run build",
|
||||
"db:migrate": "npx drizzle-kit push",
|
||||
"db:generate": "npx drizzle-kit generate",
|
||||
"translateDocs": "cd scripts && node translateScript.js"
|
||||
"translateDocs": "cd scripts && node translateScript.js",
|
||||
"auth:generate": "npx @better-auth/cli generate --config ./app/src/pkg/auth/auth.ts"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -41,6 +42,9 @@
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@dotenvx/dotenvx": "^1.49.0",
|
||||
"@types/cors": "^2.8.19",
|
||||
"better-auth": "^1.3.9",
|
||||
"cors": "^2.8.5",
|
||||
"drizzle-kit": "^0.31.4",
|
||||
"drizzle-orm": "^0.44.5",
|
||||
"drizzle-zod": "^0.8.3",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"strict": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"skipLibCheck": true,
|
||||
"types": ["node"],
|
||||
"types": ["node", "better-auth"],
|
||||
"jsx": "react-jsx",
|
||||
"outDir": "./dist",
|
||||
"removeComments": true,
|
||||
@@ -18,7 +18,8 @@
|
||||
"app/src",
|
||||
"database/testFiles/test-tiPostOrders.ts",
|
||||
"scripts/translateScript.js",
|
||||
"app/main.ts"
|
||||
"app/main.ts",
|
||||
"app/src/types"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
|
||||
Reference in New Issue
Block a user