From 874e1572298531dde9bc1d3ccdb704af0a045605 Mon Sep 17 00:00:00 2001 From: ivar Date: Fri, 19 Dec 2025 22:00:06 +0100 Subject: Migrate schema to pg --- app/bun.lock | 2 -- app/src/lib/server/db/index.ts | 3 --- app/src/lib/server/db/schema.ts | 12 ++++++------ app/src/lib/server/sb1.ts | 36 ++++++++++++++++-------------------- app/src/lib/ui/button.svelte | 3 +-- 5 files changed, 23 insertions(+), 33 deletions(-) (limited to 'app') diff --git a/app/bun.lock b/app/bun.lock index aca8589..af2e7fd 100644 --- a/app/bun.lock +++ b/app/bun.lock @@ -5,7 +5,6 @@ "name": "app", "dependencies": { "@ivars/ueb": "^0.1.0", - "better-sqlite3": "^12.5.0", "pg": "^8.16.3", }, "devDependencies": { @@ -13,7 +12,6 @@ "@sveltejs/adapter-node": "^5.4.0", "@sveltejs/kit": "^2.49.2", "@sveltejs/vite-plugin-svelte": "^6.2.1", - "@types/better-sqlite3": "^7.6.13", "@types/node": "^25.0.3", "@types/pg": "^8.16.0", "drizzle-kit": "^0.31.8", diff --git a/app/src/lib/server/db/index.ts b/app/src/lib/server/db/index.ts index 3168d01..e477388 100644 --- a/app/src/lib/server/db/index.ts +++ b/app/src/lib/server/db/index.ts @@ -1,9 +1,6 @@ import { drizzle } from 'drizzle-orm/node-postgres'; -import Database from 'better-sqlite3'; import { env } from '$env/dynamic/private'; if (!env.DATABASE_URL) throw new Error('DATABASE_URL is not set'); -const client = new Database(env.DATABASE_URL); - export const db = drizzle(env.DATABASE_URL); \ No newline at end of file diff --git a/app/src/lib/server/db/schema.ts b/app/src/lib/server/db/schema.ts index 150d970..bb57703 100644 --- a/app/src/lib/server/db/schema.ts +++ b/app/src/lib/server/db/schema.ts @@ -1,17 +1,17 @@ -import { relations } from 'drizzle-orm'; -import { numeric, text, pgTable } from "drizzle-orm/pg-core"; - +import { relations, sql } from 'drizzle-orm'; +import { numeric, text, pgTable, uuid, json } from "drizzle-orm/pg-core"; +import type { Sb1Tokens } from '../sb1'; export const syncSession = pgTable("session", { - id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()), + id: uuid('id').primaryKey().default(sql`uuidv7()`), authzState: text("authzState"), accessTokenCreated: numeric("accessTokenCreated"), refreshTokenCreated: numeric("refreshTokenCreated"), - tokens: text("tokens") + tokens: json("tokens").$type() }) export const syncLog = pgTable("session_log", { - id: text("id").primaryKey(), + id: uuid('id').primaryKey().default(sql`uuidv7()`), sessionId: text("session_id"), dateTime: text("date_time"), msg: text("msg") diff --git a/app/src/lib/server/sb1.ts b/app/src/lib/server/sb1.ts index b456609..a7cad3e 100644 --- a/app/src/lib/server/sb1.ts +++ b/app/src/lib/server/sb1.ts @@ -5,7 +5,7 @@ import { randomUUID } from "node:crypto"; import { db } from "./db"; import { syncSession } from "./db/schema"; -type Sb1Tokens = { +export type Sb1Tokens = { access_token: string expires_in: number refresh_token_expires_in: number @@ -65,10 +65,8 @@ const auth = { if (!entity[0]) return undefined const { tokens, accessTokenCreated, refreshTokenCreated } = entity[0] if (!tokens) return undefined - const tokensParsed = JSON.parse(tokens) - if (!tokensParsed) return undefined - const refreshTokenExpires = Temporal.Instant.fromEpochMilliseconds(Number(refreshTokenCreated)).add({ seconds: tokensParsed?.refresh_token_expires_in }) - const accessTokenExpires = Temporal.Instant.fromEpochMilliseconds(Number(accessTokenCreated)).add({ seconds: tokensParsed?.expires_in }) + const refreshTokenExpires = Temporal.Instant.fromEpochMilliseconds(Number(refreshTokenCreated)).add({ seconds: tokens.refresh_token_expires_in }) + const accessTokenExpires = Temporal.Instant.fromEpochMilliseconds(Number(accessTokenCreated)).add({ seconds: tokens.expires_in }) return { refreshTokenExpires, accessTokenExpires @@ -95,15 +93,16 @@ const auth = { refreshTokenCreated: syncSession.refreshTokenCreated, accessTokenCreated: syncSession.accessTokenCreated }).from(syncSession) - const { tokens: _tokens, accessTokenCreated, refreshTokenCreated } = result[0] - let tokens = JSON.parse(_tokens ?? "") as Sb1Tokens + if (!result[0]) return undefined + const { tokens, accessTokenCreated, refreshTokenCreated } = result[0] + if (!tokens) return undefined const nowInstant = Temporal.Now.instant() - const accessTokenExpiredInstant = Temporal.Instant.fromEpochMilliseconds(accessTokenCreated ?? 0).add({ seconds: tokens.expires_in }) + const accessTokenExpiredInstant = Temporal.Instant.fromEpochMilliseconds(Number(accessTokenCreated)).add({ seconds: tokens.expires_in }) if (Temporal.Instant.compare(nowInstant, accessTokenExpiredInstant) >= 0) { const refreshedTokens = await this.refresh_token() if (refreshedTokens) return refreshedTokens.access_token } - const refreshTokenExpiredInstant = Temporal.Instant.fromEpochMilliseconds(refreshTokenCreated ?? 0).add({ seconds: tokens.refresh_token_expires_in }) + const refreshTokenExpiredInstant = Temporal.Instant.fromEpochMilliseconds(Number(refreshTokenCreated)).add({ seconds: tokens.refresh_token_expires_in }) if (Temporal.Instant.compare(nowInstant, refreshTokenExpiredInstant) >= 0) { return undefined } @@ -117,19 +116,16 @@ const auth = { id: syncSession.id }).from(syncSession) - const { tokens, id } = entity[0] - - if (!tokens) return null - - const parsed = JSON.parse(tokens) as Sb1Tokens + const { tokens: currentTokens, id } = entity[0] - if (!parsed.refresh_token) throw new Error("No refresh token"); + if (!currentTokens) return null + if (!currentTokens.refresh_token) throw new Error("No refresh token"); const params = new URLSearchParams(); params.set("client_id", SB1_ID); params.set("client_secret", SB1_SECRET); - params.set("refresh_token", parsed.refresh_token); + params.set("refresh_token", currentTokens.refresh_token); params.set("grant_type", "refresh_token"); const res = await fetch("https://api.sparebank1.no/oauth/token", { @@ -139,13 +135,13 @@ const auth = { method: "POST", body: params, }); - const text = await res.text() + const tokens = await res.json() as Sb1Tokens const epoch = Temporal.Now.instant().epochMilliseconds if (res.ok) { - await db.update(syncSession).set({ tokens: text, accessTokenCreated: epoch, refreshTokenCreated: epoch }).where(eq(syncSession.id, id)) - return JSON.parse(text) as Sb1Tokens + await db.update(syncSession).set({ tokens, accessTokenCreated: epoch.toString(), refreshTokenCreated: epoch.toString() }).where(eq(syncSession.id, id)) + return tokens } else { - console.error("Failed to refresh tokens", text) + console.error("Failed to refresh tokens", tokens) return null } diff --git a/app/src/lib/ui/button.svelte b/app/src/lib/ui/button.svelte index 8c66bd2..37b1c97 100644 --- a/app/src/lib/ui/button.svelte +++ b/app/src/lib/ui/button.svelte @@ -1,6 +1,5 @@