feat: end to end api type safety with redis rate limiting (#573)

* feat: support hono rpc

* add wrangler file

* update name of wrangler file

* add wrangler as a dependency

* add compatibility_flags

* trigger ci

* core: add health check to docker file

* expose port 80

* update custom healthcheck

* feat: implement openapi

* install dependencies in root

* debug yml

* update yml

* update port

* update dockerfile with envs

* completely move away from apiClient

* rename backend to api

* refactor: update server descriptions and comment out local spec saving

* update lock file

* use api.classroomio.com

* add support for redis

* fix: add missing line break in WelcomeModal.svelte

* refactor: remove wrangler configuration and update Vite config for API integration
This commit is contained in:
Rotimi Best
2025-09-21 19:35:41 +01:00
committed by GitHub
parent a6880f1b54
commit 6d68351a46
102 changed files with 2938 additions and 1633 deletions
@@ -11,9 +11,9 @@ import type {
} from '$lib/utils/types';
import type { PostgrestError, PostgrestSingleResponse } from '@supabase/supabase-js';
import { GenericUploader } from './presign';
import { QUESTION_TYPE } from '$lib/components/Question/constants';
import { STATUS } from '$lib/utils/constants/course';
import { apiClient } from '$lib/utils/services/api';
import { get } from 'svelte/store';
import { isOrgAdmin } from '$lib/utils/store/org';
import { isUUID } from '$lib/utils/functions/isUUID';
@@ -53,12 +53,10 @@ export async function fetchProfileCourseProgress(
data: ProfileCourseProgress[] | null;
error: PostgrestError | null;
}> {
const { data, error } = await supabase
.rpc('get_course_progress', {
course_id_arg: courseId,
profile_id_arg: profileId
})
.returns<ProfileCourseProgress[]>();
const { data, error } = await supabase.rpc('get_course_progress', {
course_id_arg: courseId,
profile_id_arg: profileId
});
return { data, error };
}
@@ -286,23 +284,30 @@ export async function fetchLesson(lessonId: Lesson['id']) {
.single();
if (data) {
const keys = data.videos.filter((video) => video.type === 'upload').map((video) => video.key);
const videoKeys =
data.videos?.filter((video) => video.type === 'upload')?.map((video) => video.key) || [];
if (!keys.length) {
return { data, error };
}
const docKeys = data.documents?.map((doc) => doc.key) || [];
try {
const response = await apiClient.post('/course/presign/download', { keys });
// Get presigned URLs for videos and documents
const genericUploader = new GenericUploader('generic');
const urls = await genericUploader.getAllDownloadPresignedUrl(videoKeys, docKeys);
data.videos = data.videos.map((video) => {
if (video.type === 'upload') {
video.link = response.data.urls[video.key];
if (urls.videos[video.key]) {
video.link = urls.videos[video.key];
}
return video;
});
data.documents = data.documents.map((doc) => {
doc.link = urls.documents[doc.key];
return doc;
});
} catch (error) {
console.error('Error retrieving videos:', error);
console.error('Error retrieving presigned assets (videos and documents):', error);
}
}