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
+29
View File
@@ -0,0 +1,29 @@
import { env } from '$src/config/env';
export * from './rate-limiter';
const {
CLOUDFLARE_BUCKET_DOMAIN,
CLOUDFLARE_ACCESS_KEY,
CLOUDFLARE_SECRET_ACCESS_KEY,
CLOUDFLARE_ACCOUNT_ID,
CLOUDFLARE_RENDERING_API_KEY
} = env;
export const CLOUDFLARE = {
CONFIGS: {
BUCKET_DOMAIN: CLOUDFLARE_BUCKET_DOMAIN!,
ACCESS_KEY: CLOUDFLARE_ACCESS_KEY!,
RENDERING_API_KEY: CLOUDFLARE_RENDERING_API_KEY!,
SECRET_ACCESS_KEY: CLOUDFLARE_SECRET_ACCESS_KEY!,
ACCOUNT_ID: CLOUDFLARE_ACCOUNT_ID!
},
R2: {
BUCKET: 'videos',
BUCKET_DOMAIN: CLOUDFLARE_ACCOUNT_ID
? `https://${CLOUDFLARE_ACCOUNT_ID}.r2.cloudflarestorage.com`
: CLOUDFLARE_BUCKET_DOMAIN!,
PRESIGN_EXPIRATION_TIME: 60 * 60, // 1 hour
DOWNLOAD_EXPIRATION_TIME: 60 * 60 // 1 hour
}
} as const;
+32
View File
@@ -0,0 +1,32 @@
// Default time window for rate limiting (1 minute in milliseconds)
export const DEFAULT_WINDOW_MS = 60 * 1000;
export const DEFAULT_MAX_REQUESTS = 100;
export const RATE_LIMIT_KEY_PREFIX = 'rate_limit:';
export const DEFAULT_RATE_LIMITER_OPTIONS = {
windowMs: DEFAULT_WINDOW_MS,
maxRequests: DEFAULT_MAX_REQUESTS,
skipSuccessfulRequests: false,
skipFailedRequests: false,
message: 'Rate limit exceeded. Please try again later.',
standardHeaders: true,
legacyHeaders: false
} as const;
export const HTTP_STATUS = {
TOO_MANY_REQUESTS: 429
} as const;
export const ERROR_MESSAGES = {
RATE_LIMIT_EXCEEDED: 'Too Many Requests',
REDIS_PIPELINE_FAILED: 'Redis pipeline execution failed'
} as const;
export const RATE_LIMIT_HEADERS = {
LIMIT: 'X-RateLimit-Limit',
REMAINING: 'X-RateLimit-Remaining',
RESET: 'X-RateLimit-Reset',
RETRY_AFTER: 'Retry-After'
} as const;
+20
View File
@@ -0,0 +1,20 @@
export const ALLOWED_CONTENT_TYPES = [
'video/mp4',
'video/quicktime',
'video/x-msvideo',
'video/x-matroska'
] as const;
export const ALLOWED_DOCUMENT_TYPES = [
'application/pdf',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
'application/msword' // .doc
] as const;
export const MAX_FILE_SIZE = 500 * 1024 * 1024; // 500MB
export const MAX_DOCUMENT_SIZE = 5 * 1024 * 1024; // 5MB
export const BUCKET_NAME = {
VIDEOS: 'videos',
DOCUMENTS: 'documents'
} as const;