no longer initializes embeddings model on startup

This commit is contained in:
George Powell
2026-02-28 02:48:46 -05:00
parent 1ae2b2ac6c
commit 6e74fffb65
12 changed files with 243 additions and 97 deletions

View File

@@ -32,4 +32,4 @@ export const handle: Handle = handleAuth;
// Initialize embeddings on server start (runs once on module load)
const verses = getAllNKJVVerses();
await initializeEmbeddings(verses);
// await initializeEmbeddings(verses);

View File

@@ -1,5 +1,3 @@
import { encodeBase64url } from '@oslojs/encoding';
const APPLE_AUTH_URL = 'https://appleid.apple.com/auth/authorize';
const APPLE_TOKEN_URL = 'https://appleid.apple.com/auth/token';
@@ -26,8 +24,8 @@ export async function generateAppleClientSecret(): Promise<string> {
sub: Bun.env.APPLE_ID!
};
const encodedHeader = encodeBase64url(new TextEncoder().encode(JSON.stringify(header)));
const encodedPayload = encodeBase64url(new TextEncoder().encode(JSON.stringify(payload)));
const encodedHeader = Buffer.from(JSON.stringify(header)).toString('base64url');
const encodedPayload = Buffer.from(JSON.stringify(payload)).toString('base64url');
const signingInput = `${encodedHeader}.${encodedPayload}`;
// Import PEM private key
@@ -55,7 +53,7 @@ export async function generateAppleClientSecret(): Promise<string> {
// crypto.subtle may return DER or raw (IEEE P1363) format depending on runtime
// Raw format is exactly 64 bytes (32-byte r + 32-byte s)
const rawSignature = signature.length === 64 ? signature : derToRaw(signature);
const encodedSignature = encodeBase64url(rawSignature);
const encodedSignature = Buffer.from(rawSignature).toString('base64url');
return `${signingInput}.${encodedSignature}`;
}

View File

@@ -1,7 +1,5 @@
import type { RequestEvent } from '@sveltejs/kit';
import { eq } from 'drizzle-orm';
import { sha256 } from '@oslojs/crypto/sha2';
import { encodeBase64url, encodeHexLowerCase } from '@oslojs/encoding';
import { testDb as db } from '$lib/server/db/test';
import * as table from '$lib/server/db/schema';
@@ -11,12 +9,11 @@ export const sessionCookieName = 'auth-session';
export function generateSessionToken() {
const bytes = crypto.getRandomValues(new Uint8Array(18));
const token = encodeBase64url(bytes);
return token;
return Buffer.from(bytes).toString('base64url');
}
export async function createSession(token: string, userId: string) {
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
const sessionId = new Bun.CryptoHasher('sha256').update(token).digest('hex');
const session: table.Session = {
id: sessionId,
userId,
@@ -27,7 +24,7 @@ export async function createSession(token: string, userId: string) {
}
export async function validateSessionToken(token: string) {
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
const sessionId = new Bun.CryptoHasher('sha256').update(token).digest('hex');
const [result] = await db
.select({
// Adjust user table here to tweak returned data

View File

@@ -1,7 +1,5 @@
import type { RequestEvent } from '@sveltejs/kit';
import { eq } from 'drizzle-orm';
import { sha256 } from '@oslojs/crypto/sha2';
import { encodeBase64url, encodeHexLowerCase } from '@oslojs/encoding';
import { db } from '$lib/server/db';
import * as table from '$lib/server/db/schema';
@@ -11,12 +9,11 @@ export const sessionCookieName = 'auth-session';
export function generateSessionToken() {
const bytes = crypto.getRandomValues(new Uint8Array(18));
const token = encodeBase64url(bytes);
return token;
return Buffer.from(bytes).toString('base64url');
}
export async function createSession(token: string, userId: string) {
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
const sessionId = new Bun.CryptoHasher('sha256').update(token).digest('hex');
const session: table.Session = {
id: sessionId,
userId,
@@ -27,7 +24,7 @@ export async function createSession(token: string, userId: string) {
}
export async function validateSessionToken(token: string) {
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
const sessionId = new Bun.CryptoHasher('sha256').update(token).digest('hex');
const [result] = await db
.select({
// Adjust user table here to tweak returned data

View File

@@ -12,7 +12,7 @@ export const GET: RequestHandler = async ({ url }) => {
error(400, 'Missing anonymousId or localDate');
}
// Fetch all completion dates for this user, newest first
// Fetch all completion dates for this user (stored as the user's local date)
const rows = await db
.select({ date: dailyCompletions.date })
.from(dailyCompletions)
@@ -21,15 +21,21 @@ export const GET: RequestHandler = async ({ url }) => {
const completedDates = new Set(rows.map((r) => r.date));
// Walk backwards from localDate, counting consecutive completed days
let streak = 0;
let cursor = new Date(`${localDate}T00:00:00`);
// Subtract one calendar day from a YYYY-MM-DD string using UTC arithmetic —
// this avoids any dependence on the server's local timezone or DST offsets.
function prevDay(dateStr: string): string {
const d = new Date(dateStr + 'T00:00:00Z');
d.setUTCDate(d.getUTCDate() - 1);
return d.toISOString().slice(0, 10);
}
while (true) {
const dateStr = cursor.toLocaleDateString('en-CA'); // YYYY-MM-DD
if (!completedDates.has(dateStr)) break;
// Walk backwards from the user's local date, counting consecutive completed days
let streak = 0;
let cursor = localDate;
while (completedDates.has(cursor)) {
streak++;
cursor.setDate(cursor.getDate() - 1);
cursor = prevDay(cursor);
}
return json({ streak: streak < 2 ? 0 : streak });

View File

@@ -1,7 +1,6 @@
import { redirect } from '@sveltejs/kit';
import type { Actions } from './$types';
import { getAppleAuthUrl } from '$lib/server/apple-auth';
import { encodeBase64url } from '@oslojs/encoding';
export const actions: Actions = {
default: async ({ cookies, request }) => {
@@ -10,7 +9,7 @@ export const actions: Actions = {
// Generate CSRF state
const stateBytes = crypto.getRandomValues(new Uint8Array(16));
const state = encodeBase64url(stateBytes);
const state = Buffer.from(stateBytes).toString('base64url');
// Store state + anonymousId in a short-lived cookie
// sameSite 'none' + secure required because Apple POSTs cross-origin

View File

@@ -27,9 +27,9 @@ export const load: PageServerLoad = async ({ url, locals }) => {
};
}
// Get user's current date from timezone query param
const timezone = url.searchParams.get('tz') || 'UTC';
const userToday = new Date().toLocaleDateString('en-CA', { timeZone: timezone });
// Note: userToday is used only for the initial server-side streak estimate.
// The client overrides this with a precise local-date calculation via /api/streak.
const userToday = new Date().toISOString().slice(0, 10); // UTC date as safe fallback
try {
// Get all completions for this user
@@ -85,7 +85,7 @@ export const load: PageServerLoad = async ({ url, locals }) => {
'C': completions.filter((c: DailyCompletion) => c.guessCount > 15).length
};
// Calculate streaks
// Calculate streaks — dates are stored as the user's local date
const sortedDates = completions
.map((c: DailyCompletion) => c.date)
.sort();

View File

@@ -8,6 +8,7 @@
formatDate,
type UserStats,
} from "$lib/utils/stats";
import { fetchStreak } from "$lib/utils/streak";
interface PageData {
stats: UserStats | null;
@@ -22,6 +23,7 @@
let anonymousId = $state("");
let loading = $state(true);
let currentStreak = $state(0);
function getOrCreateAnonymousId(): string {
if (!browser) return "";
@@ -36,6 +38,12 @@
onMount(async () => {
anonymousId = getOrCreateAnonymousId();
if (data.user?.id) {
const localDate = new Date().toLocaleDateString("en-CA");
currentStreak = await fetchStreak(data.user.id, localDate);
} else {
currentStreak = data.stats?.currentStreak ?? 0;
}
loading = false;
});
@@ -151,7 +159,7 @@
<div
class="text-2xl md:text-3xl font-bold text-orange-400 mb-1"
>
{stats.currentStreak}
{currentStreak}
</div>
<div
class="text-xs md:text-sm text-gray-300 font-medium"