feat(web): db client, operator helper, IPC notify, logger
This commit is contained in:
parent
7238369503
commit
2f7313b9ac
@ -16,6 +16,7 @@
|
|||||||
"@hookform/resolvers": "^5.2.2",
|
"@hookform/resolvers": "^5.2.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"drizzle-orm": "^0.36.0",
|
||||||
"geist": "^1.7.0",
|
"geist": "^1.7.0",
|
||||||
"lucide-react": "^1.14.0",
|
"lucide-react": "^1.14.0",
|
||||||
"next": "^16.0.0",
|
"next": "^16.0.0",
|
||||||
@ -28,6 +29,7 @@
|
|||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-hook-form": "^7.75.0",
|
"react-hook-form": "^7.75.0",
|
||||||
|
"server-only": "^0.0.1",
|
||||||
"shadcn": "^4.7.0",
|
"shadcn": "^4.7.0",
|
||||||
"sonner": "^2.0.7",
|
"sonner": "^2.0.7",
|
||||||
"tailwind-merge": "^3.5.0",
|
"tailwind-merge": "^3.5.0",
|
||||||
|
|||||||
8
apps/web/src/lib/db.ts
Normal file
8
apps/web/src/lib/db.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import "server-only";
|
||||||
|
import { createClient, type DB } from "@cmbot/db";
|
||||||
|
import { env } from "@/env";
|
||||||
|
|
||||||
|
const { db, pool } = createClient(env.DATABASE_URL);
|
||||||
|
|
||||||
|
export { db, pool };
|
||||||
|
export type { DB };
|
||||||
9
apps/web/src/lib/logger.ts
Normal file
9
apps/web/src/lib/logger.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import "server-only";
|
||||||
|
import pino from "pino";
|
||||||
|
|
||||||
|
export const logger = pino({
|
||||||
|
level: process.env.NODE_ENV === "production" ? "info" : "debug",
|
||||||
|
...(process.env.NODE_ENV !== "production"
|
||||||
|
? { transport: { target: "pino-pretty", options: { colorize: true } } }
|
||||||
|
: {}),
|
||||||
|
});
|
||||||
15
apps/web/src/lib/notify.ts
Normal file
15
apps/web/src/lib/notify.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import "server-only";
|
||||||
|
import { sql } from "drizzle-orm";
|
||||||
|
import { db } from "./db";
|
||||||
|
|
||||||
|
export type BotCommand =
|
||||||
|
| { type: "account.start_pairing"; accountId: string }
|
||||||
|
| { type: "account.unpair"; accountId: string }
|
||||||
|
| { type: "account.sync_groups"; accountId: string }
|
||||||
|
| { type: "group.send_test"; groupId: string; text: string }
|
||||||
|
| { type: "reminder.schedule"; reminderId: string; scheduledAtIso: string };
|
||||||
|
|
||||||
|
export async function pgNotifyBot(cmd: BotCommand): Promise<void> {
|
||||||
|
const json = JSON.stringify(cmd);
|
||||||
|
await db.execute(sql`SELECT pg_notify('bot.command', ${json})`);
|
||||||
|
}
|
||||||
16
apps/web/src/lib/operator.ts
Normal file
16
apps/web/src/lib/operator.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import "server-only";
|
||||||
|
import { db } from "./db";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the single seeded operator row. Since the app has no auth,
|
||||||
|
* every action is attributed to this operator.
|
||||||
|
*/
|
||||||
|
export async function getSeededOperator() {
|
||||||
|
const op = await db.query.operators.findFirst({
|
||||||
|
orderBy: (o, { asc }) => [asc(o.createdAt)],
|
||||||
|
});
|
||||||
|
if (!op) {
|
||||||
|
throw new Error("No operator row seeded. Run scripts/db.sh seed.");
|
||||||
|
}
|
||||||
|
return op;
|
||||||
|
}
|
||||||
11
pnpm-lock.yaml
generated
11
pnpm-lock.yaml
generated
@ -90,6 +90,9 @@ importers:
|
|||||||
clsx:
|
clsx:
|
||||||
specifier: ^2.1.1
|
specifier: ^2.1.1
|
||||||
version: 2.1.1
|
version: 2.1.1
|
||||||
|
drizzle-orm:
|
||||||
|
specifier: ^0.36.0
|
||||||
|
version: 0.36.4(@types/pg@8.20.0)(@types/react@19.2.14)(pg@8.20.0)(react@19.2.6)
|
||||||
geist:
|
geist:
|
||||||
specifier: ^1.7.0
|
specifier: ^1.7.0
|
||||||
version: 1.7.0(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))
|
version: 1.7.0(next@16.2.6(@babel/core@7.29.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))
|
||||||
@ -126,6 +129,9 @@ importers:
|
|||||||
react-hook-form:
|
react-hook-form:
|
||||||
specifier: ^7.75.0
|
specifier: ^7.75.0
|
||||||
version: 7.75.0(react@19.2.6)
|
version: 7.75.0(react@19.2.6)
|
||||||
|
server-only:
|
||||||
|
specifier: ^0.0.1
|
||||||
|
version: 0.0.1
|
||||||
shadcn:
|
shadcn:
|
||||||
specifier: ^4.7.0
|
specifier: ^4.7.0
|
||||||
version: 4.7.0(@types/node@22.19.18)(typescript@5.9.3)
|
version: 4.7.0(@types/node@22.19.18)(typescript@5.9.3)
|
||||||
@ -3963,6 +3969,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==}
|
resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==}
|
||||||
engines: {node: '>= 18'}
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
server-only@0.0.1:
|
||||||
|
resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==}
|
||||||
|
|
||||||
set-blocking@2.0.0:
|
set-blocking@2.0.0:
|
||||||
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
||||||
|
|
||||||
@ -8005,6 +8014,8 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
server-only@0.0.1: {}
|
||||||
|
|
||||||
set-blocking@2.0.0: {}
|
set-blocking@2.0.0: {}
|
||||||
|
|
||||||
set-cookie-parser@3.1.0: {}
|
set-cookie-parser@3.1.0: {}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user