detached 802df95

refactor(server): update page loaders to use Convex

commit
802df9564c545543e3174cde474a6a6166e1ac0c
author
bnema · · 2026-01-18 18:35 UTC
parent
c624865
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +15 -69
M src/lib/utils/chat.server.ts +12 -43
@@ -1,56 +1,25 @@
1-import type { LibSQLDatabase } from 'drizzle-orm/libsql';
21 import { createLogger } from '$lib/utils/logger.server';
3-import schema, { chatRooms } from '$lib/db/schema';
4-import { eq } from 'drizzle-orm';
5-import { env } from '$env/dynamic/public';
2+import { chatRooms } from '$lib/db/convex.server';
63
74 const log = createLogger('chat-utils');
85
9-// Default chat room ID from environment variable
10-export const DEFAULT_CHAT_ROOM_ID =
11- env.PUBLIC_DEFAULT_CHAT_ROOM_ID || '00000000-0000-0000-0000-000000000001';
6+// Default chat room ID - will be fetched/created on startup
7+let defaultChatRoomId: string | null = null;
128
13-// Type guard for LibSQL errors
14-interface LibSQLError {
15- code: string;
16- message: string;
9+// Function to get the default chat room ID
10+export function getDefaultChatRoomId(): string | null {
11+ return defaultChatRoomId;
1712 }
1813
19-function isLibSQLError(error: unknown): error is LibSQLError {
20- return typeof error === 'object' && error !== null && 'code' in error;
21-}
22-
23-// Function to ensure default chat room exists
24-export async function ensureDefaultChatRoom(db: LibSQLDatabase<typeof schema>) {
14+// Function to ensure default chat room exists (using Convex)
15+export async function ensureDefaultChatRoom(): Promise<string> {
2516 log.debug('Ensuring default chat room exists...');
2617 try {
27- // Use a transaction to handle concurrent creation attempts
28- await db.transaction(async (tx) => {
29- const defaultRoom = await tx
30- .select()
31- .from(chatRooms)
32- .where(eq(chatRooms.id, DEFAULT_CHAT_ROOM_ID))
33- .get();
34-
35- if (!defaultRoom) {
36- log.debug('Creating default chat room...');
37- await tx.insert(chatRooms).values({
38- id: DEFAULT_CHAT_ROOM_ID,
39- name: 'General',
40- type: 'group',
41- createdAt: Date.now()
42- });
43- log.debug('Default chat room created successfully');
44- } else {
45- log.debug('Default chat room already exists');
46- }
47- });
18+ const room = await chatRooms.getOrCreateDefault();
19+ defaultChatRoomId = room._id;
20+ log.debug('Default chat room ready', { id: defaultChatRoomId });
21+ return defaultChatRoomId;
4822 } catch (error: unknown) {
49- // If the error is a unique constraint violation, another process probably created the room
50- if (isLibSQLError(error) && error.code === 'SQLITE_CONSTRAINT') {
51- log.debug('Default chat room was created by another process');
52- return;
53- }
5423 log.error('Error ensuring default chat room:', {
5524 error: error instanceof Error ? error.message : 'Unknown error'
5625 });
@@ -1,56 +1,25 @@
1-import type { LibSQLDatabase } from 'drizzle-orm/libsql';
2 import { createLogger } from '$lib/utils/logger.server';1 import { createLogger } from '$lib/utils/logger.server';
3-import schema, { chatRooms } from '$lib/db/schema';2+import { chatRooms } from '$lib/db/convex.server';
4-import { eq } from 'drizzle-orm';
5-import { env } from '$env/dynamic/public';
6 3
7 const log = createLogger('chat-utils');4 const log = createLogger('chat-utils');
8 5
9-// Default chat room ID from environment variable6+// Default chat room ID - will be fetched/created on startup
10-export const DEFAULT_CHAT_ROOM_ID =7+let defaultChatRoomId: string | null = null;
11- env.PUBLIC_DEFAULT_CHAT_ROOM_ID || '00000000-0000-0000-0000-000000000001';
12 8
13-// Type guard for LibSQL errors9+// Function to get the default chat room ID
14-interface LibSQLError {10+export function getDefaultChatRoomId(): string | null {
15- code: string;11+ return defaultChatRoomId;
16- message: string;
17 }12 }
18 13
19-function isLibSQLError(error: unknown): error is LibSQLError {14+// Function to ensure default chat room exists (using Convex)
20- return typeof error === 'object' && error !== null && 'code' in error;15+export async function ensureDefaultChatRoom(): Promise<string> {
21-}
22-
23-// Function to ensure default chat room exists
24-export async function ensureDefaultChatRoom(db: LibSQLDatabase<typeof schema>) {
25 log.debug('Ensuring default chat room exists...');16 log.debug('Ensuring default chat room exists...');
26 try {17 try {
27- // Use a transaction to handle concurrent creation attempts18+ const room = await chatRooms.getOrCreateDefault();
28- await db.transaction(async (tx) => {19+ defaultChatRoomId = room._id;
29- const defaultRoom = await tx20+ log.debug('Default chat room ready', { id: defaultChatRoomId });
30- .select()21+ return defaultChatRoomId;
31- .from(chatRooms)
32- .where(eq(chatRooms.id, DEFAULT_CHAT_ROOM_ID))
33- .get();
34-
35- if (!defaultRoom) {
36- log.debug('Creating default chat room...');
37- await tx.insert(chatRooms).values({
38- id: DEFAULT_CHAT_ROOM_ID,
39- name: 'General',
40- type: 'group',
41- createdAt: Date.now()
42- });
43- log.debug('Default chat room created successfully');
44- } else {
45- log.debug('Default chat room already exists');
46- }
47- });
48 } catch (error: unknown) {22 } catch (error: unknown) {
49- // If the error is a unique constraint violation, another process probably created the room
50- if (isLibSQLError(error) && error.code === 'SQLITE_CONSTRAINT') {
51- log.debug('Default chat room was created by another process');
52- return;
53- }
54 log.error('Error ensuring default chat room:', {23 log.error('Error ensuring default chat room:', {
55 error: error instanceof Error ? error.message : 'Unknown error'24 error: error instanceof Error ? error.message : 'Unknown error'
56 });25 });
M src/routes/+page.server.ts +3 -26
@@ -1,8 +1,5 @@
11 import type { PageServerLoad } from './$types';
22 import { validateSessionToken } from '$lib/api/session.server';
3-import db from '$lib/db/db.server';
4-import { messages } from '$lib/db/schema';
5-import { eq, desc } from 'drizzle-orm';
63 import { DEFAULT_TEXT_STYLE, type TextStyle } from '$lib/types/text-formatting';
74
85 export const load: PageServerLoad = async ({ cookies }) => {
@@ -25,29 +22,9 @@ export const load: PageServerLoad = async ({ cookies }) => {
2522 };
2623 }
2724
28- // Get user's last used text styling from their most recent message
29- const lastMessage = await db.query.messages.findFirst({
30- where: eq(messages.senderId, user.id),
31- orderBy: [desc(messages.timestamp)],
32- columns: {
33- styleData: true
34- }
35- });
36-
37- let lastTextStyle: TextStyle = DEFAULT_TEXT_STYLE;
38-
39- if (lastMessage?.styleData) {
40- try {
41- const parsedStyle = JSON.parse(lastMessage.styleData);
42- // Merge with default style to ensure all required properties
43- lastTextStyle = {
44- ...DEFAULT_TEXT_STYLE,
45- ...parsedStyle
46- };
47- } catch (error) {
48- console.warn('Failed to parse last text style:', error);
49- }
50- }
25+ // For now, return default text style
26+ // TODO: Fetch user's last text style from Convex if needed
27+ const lastTextStyle: TextStyle = DEFAULT_TEXT_STYLE;
5128
5229 return {
5330 user,
@@ -1,8 +1,5 @@
1 import type { PageServerLoad } from './$types';1 import type { PageServerLoad } from './$types';
2 import { validateSessionToken } from '$lib/api/session.server';2 import { validateSessionToken } from '$lib/api/session.server';
3-import db from '$lib/db/db.server';
4-import { messages } from '$lib/db/schema';
5-import { eq, desc } from 'drizzle-orm';
6 import { DEFAULT_TEXT_STYLE, type TextStyle } from '$lib/types/text-formatting';3 import { DEFAULT_TEXT_STYLE, type TextStyle } from '$lib/types/text-formatting';
7 4
8 export const load: PageServerLoad = async ({ cookies }) => {5 export const load: PageServerLoad = async ({ cookies }) => {
@@ -25,29 +22,9 @@ export const load: PageServerLoad = async ({ cookies }) => {
25 };22 };
26 }23 }
27 24
28- // Get user's last used text styling from their most recent message25+ // For now, return default text style
29- const lastMessage = await db.query.messages.findFirst({26+ // TODO: Fetch user's last text style from Convex if needed
30- where: eq(messages.senderId, user.id),27+ const lastTextStyle: TextStyle = DEFAULT_TEXT_STYLE;
31- orderBy: [desc(messages.timestamp)],
32- columns: {
33- styleData: true
34- }
35- });
36-
37- let lastTextStyle: TextStyle = DEFAULT_TEXT_STYLE;
38-
39- if (lastMessage?.styleData) {
40- try {
41- const parsedStyle = JSON.parse(lastMessage.styleData);
42- // Merge with default style to ensure all required properties
43- lastTextStyle = {
44- ...DEFAULT_TEXT_STYLE,
45- ...parsedStyle
46- };
47- } catch (error) {
48- console.warn('Failed to parse last text style:', error);
49- }
50- }
51 28
52 return {29 return {
53 user,30 user,

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 3

Tags 8

↑↓ moveenter openesc close