should work on both localhost and outside.

This commit is contained in:
pulipakaa24
2026-03-19 13:48:19 -05:00
parent 6026e4dda6
commit 8c2f8fa7b1
11 changed files with 157 additions and 61 deletions

2
.gitignore vendored
View File

@@ -31,3 +31,5 @@ Thumbs.db
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
package-lock.json

View File

@@ -47,7 +47,7 @@ export default function App() {
<Button <Button
variant="outline" variant="outline"
className="w-full flex items-center gap-3" className="w-full flex items-center gap-3"
onClick={() => signIn.social({ provider: "google", callbackURL: "/" })} onClick={() => signIn.social({ provider: "google", callbackURL: window.location.origin })}
> >
<svg viewBox="0 0 24 24" className="h-4 w-4" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 24 24" className="h-4 w-4" xmlns="http://www.w3.org/2000/svg">
<path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" fill="#4285F4"/> <path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" fill="#4285F4"/>

73
package-lock.json generated
View File

@@ -34,11 +34,11 @@
"@radix-ui/react-toggle": "^1.1.2", "@radix-ui/react-toggle": "^1.1.2",
"@radix-ui/react-toggle-group": "^1.1.2", "@radix-ui/react-toggle-group": "^1.1.2",
"@radix-ui/react-tooltip": "^1.1.8", "@radix-ui/react-tooltip": "^1.1.8",
"@tailwindcss/oxide-linux-x64-gnu": "^4.2.2",
"better-auth": "^1.0.0", "better-auth": "^1.0.0",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cmdk": "^1.1.1", "cmdk": "^1.1.1",
"dotenv": "^17.3.1",
"embla-carousel-react": "^8.6.0", "embla-carousel-react": "^8.6.0",
"input-otp": "^1.4.2", "input-otp": "^1.4.2",
"lucide-react": "^0.487.0", "lucide-react": "^0.487.0",
@@ -3188,7 +3188,9 @@
"cpu": [ "cpu": [
"x64" "x64"
], ],
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true,
"os": [ "os": [
"linux" "linux"
], ],
@@ -3435,9 +3437,9 @@
"peer": true "peer": true
}, },
"node_modules/@types/whatwg-url": { "node_modules/@types/whatwg-url": {
"version": "11.0.5", "version": "13.0.0",
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-13.0.0.tgz",
"integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", "integrity": "sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==",
"license": "MIT", "license": "MIT",
"peer": true, "peer": true,
"dependencies": { "dependencies": {
@@ -3504,9 +3506,9 @@
} }
}, },
"node_modules/baseline-browser-mapping": { "node_modules/baseline-browser-mapping": {
"version": "2.10.8", "version": "2.10.9",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.8.tgz", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.9.tgz",
"integrity": "sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ==", "integrity": "sha512-OZd0e2mU11ClX8+IdXe3r0dbqMEznRiT4TfbhYIbcRPZkqJ7Qwer8ij3GZAmLsRKa+II9V1v5czCkvmHH3XZBg==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
@@ -3676,13 +3678,13 @@
} }
}, },
"node_modules/bson": { "node_modules/bson": {
"version": "6.10.4", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz", "resolved": "https://registry.npmjs.org/bson/-/bson-7.2.0.tgz",
"integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==", "integrity": "sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true, "peer": true,
"engines": { "engines": {
"node": ">=16.20.1" "node": ">=20.19.0"
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
@@ -4039,6 +4041,18 @@
"csstype": "^3.0.2" "csstype": "^3.0.2"
} }
}, },
"node_modules/dotenv": {
"version": "17.3.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz",
"integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.321", "version": "1.5.321",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.321.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.321.tgz",
@@ -4646,27 +4660,27 @@
"peer": true "peer": true
}, },
"node_modules/mongodb": { "node_modules/mongodb": {
"version": "6.21.0", "version": "7.1.0",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.21.0.tgz", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.1.0.tgz",
"integrity": "sha512-URyb/VXMjJ4da46OeSXg+puO39XH9DeQpWCslifrRn9JWugy0D+DvvBvkm2WxmHe61O/H19JM66p1z7RHVkZ6A==", "integrity": "sha512-kMfnKunbolQYwCIyrkxNJFB4Ypy91pYqua5NargS/f8ODNSJxT03ZU3n1JqL4mCzbSih8tvmMEMLpKTT7x5gCg==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true, "peer": true,
"dependencies": { "dependencies": {
"@mongodb-js/saslprep": "^1.3.0", "@mongodb-js/saslprep": "^1.3.0",
"bson": "^6.10.4", "bson": "^7.1.1",
"mongodb-connection-string-url": "^3.0.2" "mongodb-connection-string-url": "^7.0.0"
}, },
"engines": { "engines": {
"node": ">=16.20.1" "node": ">=20.19.0"
}, },
"peerDependencies": { "peerDependencies": {
"@aws-sdk/credential-providers": "^3.188.0", "@aws-sdk/credential-providers": "^3.806.0",
"@mongodb-js/zstd": "^1.1.0 || ^2.0.0", "@mongodb-js/zstd": "^7.0.0",
"gcp-metadata": "^5.2.0", "gcp-metadata": "^7.0.1",
"kerberos": "^2.0.1", "kerberos": "^7.0.0",
"mongodb-client-encryption": ">=6.0.0 <7", "mongodb-client-encryption": ">=7.0.0 <7.1.0",
"snappy": "^7.3.2", "snappy": "^7.3.2",
"socks": "^2.7.1" "socks": "^2.8.6"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@aws-sdk/credential-providers": { "@aws-sdk/credential-providers": {
@@ -4693,14 +4707,17 @@
} }
}, },
"node_modules/mongodb-connection-string-url": { "node_modules/mongodb-connection-string-url": {
"version": "3.0.2", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-7.0.1.tgz",
"integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", "integrity": "sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true, "peer": true,
"dependencies": { "dependencies": {
"@types/whatwg-url": "^11.0.2", "@types/whatwg-url": "^13.0.0",
"whatwg-url": "^14.1.0 || ^13.0.0" "whatwg-url": "^14.1.0"
},
"engines": {
"node": ">=20.19.0"
} }
}, },
"node_modules/ms": { "node_modules/ms": {

View File

@@ -36,10 +36,11 @@
"@radix-ui/react-toggle": "^1.1.2", "@radix-ui/react-toggle": "^1.1.2",
"@radix-ui/react-toggle-group": "^1.1.2", "@radix-ui/react-toggle-group": "^1.1.2",
"@radix-ui/react-tooltip": "^1.1.8", "@radix-ui/react-tooltip": "^1.1.8",
"@tailwindcss/oxide-linux-x64-gnu": "^4.2.2", "better-auth": "^1.0.0",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cmdk": "^1.1.1", "cmdk": "^1.1.1",
"dotenv": "^17.3.1",
"embla-carousel-react": "^8.6.0", "embla-carousel-react": "^8.6.0",
"input-otp": "^1.4.2", "input-otp": "^1.4.2",
"lucide-react": "^0.487.0", "lucide-react": "^0.487.0",
@@ -52,17 +53,16 @@
"recharts": "^2.15.2", "recharts": "^2.15.2",
"sonner": "^2.0.3", "sonner": "^2.0.3",
"tailwind-merge": "^2.6.0", "tailwind-merge": "^2.6.0",
"vaul": "^1.1.2", "vaul": "^1.1.2"
"better-auth": "^1.0.0"
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/vite": "^4.0.0", "@tailwindcss/vite": "^4.0.0",
"@types/react": "^19.0.0", "@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0", "@types/react-dom": "^19.0.0",
"@vitejs/plugin-react": "^4.3.4", "@vitejs/plugin-react": "^4.3.4",
"concurrently": "^9.1.2",
"tailwindcss": "^4.0.0", "tailwindcss": "^4.0.0",
"typescript": "^5.7.2", "typescript": "^5.7.2",
"vite": "^6.2.0", "vite": "^6.2.0"
"concurrently": "^9.1.2"
} }
} }

22
readme.md Normal file
View File

@@ -0,0 +1,22 @@
# LabWise
Lab inventory management service
## How to run on localhost
```bash
# 1
npm install
# 2
psql CREATE USER labwise WITH PASSWORD 'labwise_dev_pw';
psql CREATE DATABASE labwise_db OWNER labwise;
psql GRANT ALL PRIVILEGES ON DATABASE labwise_db TO labwise;
psql postgresql://labwise:labwise_dev_pw@localhost:5432/labwise_db -f server/src/db/schema.sql
# 3
cd server && npm install && npm run db:migrate
cd ..
# 4
npm run dev
```

View File

@@ -761,9 +761,9 @@
"peer": true "peer": true
}, },
"node_modules/@types/whatwg-url": { "node_modules/@types/whatwg-url": {
"version": "11.0.5", "version": "13.0.0",
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-13.0.0.tgz",
"integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", "integrity": "sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==",
"license": "MIT", "license": "MIT",
"peer": true, "peer": true,
"dependencies": { "dependencies": {
@@ -945,13 +945,13 @@
} }
}, },
"node_modules/bson": { "node_modules/bson": {
"version": "6.10.4", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz", "resolved": "https://registry.npmjs.org/bson/-/bson-7.2.0.tgz",
"integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==", "integrity": "sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true, "peer": true,
"engines": { "engines": {
"node": ">=16.20.1" "node": ">=20.19.0"
} }
}, },
"node_modules/buffer-from": { "node_modules/buffer-from": {
@@ -1609,27 +1609,27 @@
} }
}, },
"node_modules/mongodb": { "node_modules/mongodb": {
"version": "6.21.0", "version": "7.1.0",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.21.0.tgz", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.1.0.tgz",
"integrity": "sha512-URyb/VXMjJ4da46OeSXg+puO39XH9DeQpWCslifrRn9JWugy0D+DvvBvkm2WxmHe61O/H19JM66p1z7RHVkZ6A==", "integrity": "sha512-kMfnKunbolQYwCIyrkxNJFB4Ypy91pYqua5NargS/f8ODNSJxT03ZU3n1JqL4mCzbSih8tvmMEMLpKTT7x5gCg==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true, "peer": true,
"dependencies": { "dependencies": {
"@mongodb-js/saslprep": "^1.3.0", "@mongodb-js/saslprep": "^1.3.0",
"bson": "^6.10.4", "bson": "^7.1.1",
"mongodb-connection-string-url": "^3.0.2" "mongodb-connection-string-url": "^7.0.0"
}, },
"engines": { "engines": {
"node": ">=16.20.1" "node": ">=20.19.0"
}, },
"peerDependencies": { "peerDependencies": {
"@aws-sdk/credential-providers": "^3.188.0", "@aws-sdk/credential-providers": "^3.806.0",
"@mongodb-js/zstd": "^1.1.0 || ^2.0.0", "@mongodb-js/zstd": "^7.0.0",
"gcp-metadata": "^5.2.0", "gcp-metadata": "^7.0.1",
"kerberos": "^2.0.1", "kerberos": "^7.0.0",
"mongodb-client-encryption": ">=6.0.0 <7", "mongodb-client-encryption": ">=7.0.0 <7.1.0",
"snappy": "^7.3.2", "snappy": "^7.3.2",
"socks": "^2.7.1" "socks": "^2.8.6"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@aws-sdk/credential-providers": { "@aws-sdk/credential-providers": {
@@ -1656,14 +1656,17 @@
} }
}, },
"node_modules/mongodb-connection-string-url": { "node_modules/mongodb-connection-string-url": {
"version": "3.0.2", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-7.0.1.tgz",
"integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", "integrity": "sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true, "peer": true,
"dependencies": { "dependencies": {
"@types/whatwg-url": "^11.0.2", "@types/whatwg-url": "^13.0.0",
"whatwg-url": "^14.1.0 || ^13.0.0" "whatwg-url": "^14.1.0"
},
"engines": {
"node": ">=20.19.0"
} }
}, },
"node_modules/ms": { "node_modules/ms": {

View File

@@ -3,7 +3,7 @@
"version": "1.0.0", "version": "1.0.0",
"type": "commonjs", "type": "commonjs",
"scripts": { "scripts": {
"dev": "tsx watch --env-file=.env src/index.ts", "dev": "tsx watch src/index.ts",
"build": "tsc", "build": "tsc",
"start": "node dist/index.js", "start": "node dist/index.js",
"db:migrate": "tsx src/db/migrate.ts" "db:migrate": "tsx src/db/migrate.ts"

View File

@@ -1,3 +1,50 @@
-- Better Auth tables
CREATE TABLE IF NOT EXISTS "user" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"email" TEXT NOT NULL UNIQUE,
"emailVerified" BOOLEAN NOT NULL,
"image" TEXT,
"createdAt" TIMESTAMP NOT NULL,
"updatedAt" TIMESTAMP NOT NULL
);
CREATE TABLE IF NOT EXISTS "session" (
"id" TEXT NOT NULL PRIMARY KEY,
"expiresAt" TIMESTAMP NOT NULL,
"token" TEXT NOT NULL UNIQUE,
"createdAt" TIMESTAMP NOT NULL,
"updatedAt" TIMESTAMP NOT NULL,
"ipAddress" TEXT,
"userAgent" TEXT,
"userId" TEXT NOT NULL REFERENCES "user"("id") ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS "account" (
"id" TEXT NOT NULL PRIMARY KEY,
"accountId" TEXT NOT NULL,
"providerId" TEXT NOT NULL,
"userId" TEXT NOT NULL REFERENCES "user"("id") ON DELETE CASCADE,
"accessToken" TEXT,
"refreshToken" TEXT,
"idToken" TEXT,
"accessTokenExpiresAt" TIMESTAMP,
"refreshTokenExpiresAt" TIMESTAMP,
"scope" TEXT,
"password" TEXT,
"createdAt" TIMESTAMP NOT NULL,
"updatedAt" TIMESTAMP NOT NULL
);
CREATE TABLE IF NOT EXISTS "verification" (
"id" TEXT NOT NULL PRIMARY KEY,
"identifier" TEXT NOT NULL,
"value" TEXT NOT NULL,
"expiresAt" TIMESTAMP NOT NULL,
"createdAt" TIMESTAMP,
"updatedAt" TIMESTAMP
);
-- Chemical inventory, scoped per user -- Chemical inventory, scoped per user
CREATE TABLE IF NOT EXISTS chemicals ( CREATE TABLE IF NOT EXISTS chemicals (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(), id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

View File

@@ -1,3 +1,4 @@
import 'dotenv/config';
import express from 'express'; import express from 'express';
import cors from 'cors'; import cors from 'cors';
import { toNodeHandler } from 'better-auth/node'; import { toNodeHandler } from 'better-auth/node';
@@ -8,6 +9,7 @@ import protocolsRouter from './routes/protocols';
import path from 'path'; import path from 'path';
const app = express(); const app = express();
console.log(process.env.BETTER_AUTH_URL, process.env.BETTER_AUTH_SECRET);
const PORT = process.env.PORT || 3001; const PORT = process.env.PORT || 3001;
const UPLOADS_DIR = process.env.UPLOADS_DIR || path.join(__dirname, '../uploads'); const UPLOADS_DIR = process.env.UPLOADS_DIR || path.join(__dirname, '../uploads');
@@ -41,4 +43,6 @@ app.get('/api/health', (_req, res) => res.json({ ok: true }));
app.listen(PORT, () => { app.listen(PORT, () => {
console.log(`LabWise API running on http://localhost:${PORT}`); console.log(`LabWise API running on http://localhost:${PORT}`);
console.log('BETTER_AUTH_URL:', process.env.BETTER_AUTH_URL);
console.log('BETTER_AUTH_SECRET:', process.env.BETTER_AUTH_SECRET);
}); });

View File

@@ -8,7 +8,8 @@
"strict": true, "strict": true,
"esModuleInterop": true, "esModuleInterop": true,
"skipLibCheck": true, "skipLibCheck": true,
"resolveJsonModule": true "resolveJsonModule": true,
"types": ["node"]
}, },
"include": ["src/**/*"], "include": ["src/**/*"],
"exclude": ["node_modules", "dist"] "exclude": ["node_modules", "dist"]

View File

@@ -6,7 +6,7 @@ export default defineConfig({
plugins: [react(), tailwindcss()], plugins: [react(), tailwindcss()],
server: { server: {
host: true, host: true,
allowedHosts: ["labwise.wahwa.com"], allowedHosts: ["localhost"],
proxy: { proxy: {
'/api': { target: 'http://localhost:3001', changeOrigin: true }, '/api': { target: 'http://localhost:3001', changeOrigin: true },
'/uploads': { target: 'http://localhost:3001', changeOrigin: true }, '/uploads': { target: 'http://localhost:3001', changeOrigin: true },