-
Notifications
You must be signed in to change notification settings - Fork 323
fix: route tinfoil sends to the assigned enclave and cut GLM latency #1170
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9b8cfb7
a590cf2
9c75bd1
26e1d0f
bdc7c86
b63bb1d
de1842f
b9bb619
9df0157
54b427b
62a12e1
b4b5cc8
082acd0
85eff11
950743f
f2c56f5
ef89e1a
1a853b8
a9c1645
a7acaf3
ff96cb0
2981c27
295d0ff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
|
||
| import { getCorsOriginsList, isOriginAllowed, type Settings } from '@/config/settings' | ||
| import cors from '@elysiajs/cors' | ||
| import { Elysia } from 'elysia' | ||
|
|
||
| type CorsSettings = Pick<Settings, 'corsOrigins' | 'corsAllowCredentials' | 'corsAllowMethods' | 'corsExposeHeaders'> | ||
|
|
||
| /** Resolve a request origin using the configured exact-origin CORS policy. */ | ||
| const resolveCorsOrigin = ( | ||
| request: Request, | ||
| settings: Pick<Settings, 'corsOrigins'>, | ||
| allowsAnyOrigin: boolean, | ||
| allowCredentials: boolean, | ||
| ): string | null => { | ||
| if (allowsAnyOrigin) { | ||
| // Browsers reject wildcard ACAO with credentials, so credentialed wildcard policies must echo Origin. | ||
| return allowCredentials ? request.headers.get('Origin') : '*' | ||
| } | ||
|
|
||
| const origin = request.headers.get('Origin') | ||
| if (origin === null || !isOriginAllowed(origin, settings)) { | ||
| return null | ||
| } | ||
| return origin | ||
| } | ||
|
|
||
| /** Configure CORS and grant Resource Timing access to the origin CORS resolved for the request. */ | ||
| export const createCorsMiddleware = (settings: CorsSettings) => { | ||
| const corsOrigins = getCorsOriginsList(settings) | ||
| const allowsAnyOrigin = corsOrigins.includes('*') | ||
| const resolveRequestOrigin = (request: Request) => | ||
| resolveCorsOrigin(request, settings, allowsAnyOrigin, settings.corsAllowCredentials) | ||
| const corsOrigin = | ||
| allowsAnyOrigin && !settings.corsAllowCredentials | ||
| ? '*' | ||
| : (request: Request) => resolveRequestOrigin(request) !== null | ||
|
|
||
| return new Elysia({ name: 'cors-with-resource-timing' }) | ||
| .onRequest(({ request, set }) => { | ||
| const allowedOrigin = resolveRequestOrigin(request) | ||
| if (allowedOrigin === null) { | ||
| return | ||
| } | ||
|
|
||
| // Resource Timing consumes TAO without CORS exposure; timing is revealed only to the CORS-allowed origin. | ||
| set.headers['Timing-Allow-Origin'] = allowedOrigin | ||
| }) | ||
| .use( | ||
| cors({ | ||
| origin: corsOrigin, | ||
| credentials: settings.corsAllowCredentials, | ||
| methods: settings.corsAllowMethods, | ||
| // Echo back the client's Access-Control-Request-Headers. The universal | ||
| // proxy forwards arbitrary upstream headers as X-Proxy-Passthrough-*. | ||
| allowedHeaders: true, | ||
| exposeHeaders: settings.corsExposeHeaders, | ||
| // Preflights cost ~195ms measured. 10 minutes covers back-to-back chat sends while keeping a | ||
| // CORS policy change from lingering in browser caches (Safari caps around this value anyway). | ||
| maxAge: 600, | ||
| }), | ||
| ) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ import { createMicrosoftAuthRoutes } from '@/auth/microsoft' | |
| import { createOidcConfigRoutes } from '@/auth/oidc' | ||
| import { createSsoDesktopCallbackRoutes } from '@/auth/sso-desktop-callback' | ||
| import { createLoggerMiddleware, createStandaloneLogger } from '@/config/logger' | ||
| import { createCorsMiddleware } from '@/config/cors' | ||
| import { getCorsOriginsList, getSettings } from '@/config/settings' | ||
| import { runMigrations } from '@/db/client' | ||
| import { createInferenceRoutes } from '@/inference/routes' | ||
|
|
@@ -22,6 +23,7 @@ import { createSearchRoutes } from '@/api/search' | |
| import { createPreviewRoutes } from '@/api/preview' | ||
| import { createPostHogRoutes } from '@/posthog/routes' | ||
| import { createProToolsRoutes } from '@/pro/routes' | ||
| import { createTinfoilKeepWarm } from '@/tinfoil/keep-warm' | ||
| import { createTinfoilRoutes } from '@/tinfoil/routes' | ||
| import { createWaitlistRoutes } from '@/waitlist/routes' | ||
| import { createAccountRoutes } from '@/api/account' | ||
|
|
@@ -31,7 +33,6 @@ import { createConfigRoutes } from '@/api/config' | |
| import { createEncryptionRoutes } from '@/api/encryption' | ||
| import { createPowerSyncRoutes } from '@/api/powersync' | ||
| import type { AppDeps } from '@/types' | ||
| import { cors } from '@elysiajs/cors' | ||
| import { Elysia } from 'elysia' | ||
|
|
||
| /** | ||
|
|
@@ -83,31 +84,20 @@ export const createApp = async (deps?: AppDeps) => { | |
| ) | ||
| const auth = deps?.auth ?? createdAuth | ||
|
|
||
| const appLogger = createStandaloneLogger(settings) | ||
|
|
||
| // Build the production observability recorder unless tests injected their own. | ||
| // Proxy events go to Pino + OTel only — not PostHog (proxy traffic is infra | ||
| // plumbing, not product analytics). | ||
| const proxyObservability = | ||
| deps?.proxyObservability ?? | ||
| createObservabilityRecorder({ | ||
| logger: createStandaloneLogger(settings), | ||
| logger: appLogger, | ||
| }) | ||
|
|
||
| return ( | ||
| configuredApp | ||
| .use( | ||
| cors({ | ||
| origin: getCorsOriginsList(settings), | ||
| credentials: settings.corsAllowCredentials, | ||
| methods: settings.corsAllowMethods, | ||
| // Echo back the client's Access-Control-Request-Headers. The universal | ||
| // proxy at /v1/proxy forwards arbitrary upstream headers as | ||
| // X-Proxy-Passthrough-* (provider SDKs add x-api-key, x-stainless-*, | ||
| // openai-organization, anthropic-beta, …). A static allowlist can't | ||
| // enumerate every upstream's header set without breaking preflight. | ||
| allowedHeaders: true, | ||
| exposeHeaders: settings.corsExposeHeaders, | ||
| }), | ||
| ) | ||
| .use(createCorsMiddleware(settings)) | ||
| .use(createLoggerMiddleware(settings)) | ||
| .use(createHttpLoggingMiddleware(settings.trustedProxy)) | ||
| .use(createErrorHandlingMiddleware()) | ||
|
|
@@ -129,7 +119,7 @@ export const createApp = async (deps?: AppDeps) => { | |
| dnsLookup: deps?.dnsLookup, | ||
| }), | ||
| ) | ||
| .use(createTinfoilRoutes({ auth, fetchFn, rateLimit: proRateLimit })) | ||
| .use(createTinfoilRoutes({ auth, fetchFn, logger: appLogger, rateLimit: proRateLimit })) | ||
| .use( | ||
| createUniversalProxyWsRoutes({ | ||
| auth, | ||
|
|
@@ -140,7 +130,14 @@ export const createApp = async (deps?: AppDeps) => { | |
| ) | ||
| .use(createSearchRoutes(auth, proRateLimit, { exaClient: deps?.searchExaClient })) | ||
| .use(createPreviewRoutes({ auth, fetchFn, rateLimit: proRateLimit, dnsLookup: deps?.dnsLookup })) | ||
| .use(createInferenceRoutes(auth, createInferenceRateLimit(database, rateLimitSettings))) | ||
| .use( | ||
| createInferenceRoutes({ | ||
| auth, | ||
| fetchFn: deps?.fetchFn, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Convention — Inference gets raw Every other route is handed the resolved |
||
| logger: appLogger, | ||
| rateLimit: createInferenceRateLimit(database, rateLimitSettings), | ||
| }), | ||
| ) | ||
| .use(createConfigRoutes(settings)) | ||
| .use(createPostHogRoutes(fetchFn)) | ||
| .use( | ||
|
|
@@ -166,6 +163,7 @@ export const createApp = async (deps?: AppDeps) => { | |
| const startServer = async () => { | ||
| const settings = getSettings() | ||
| const log = createStandaloneLogger(settings) | ||
| const tinfoilKeepWarm = createTinfoilKeepWarm(settings, { logger: log }) | ||
|
|
||
| // Set up logging | ||
| log.info('Starting Thunderbolt Server...') | ||
|
|
@@ -196,6 +194,9 @@ const startServer = async () => { | |
| hostname, | ||
| port: settings.port, | ||
| reusePort: process.env.NODE_ENV === 'production', | ||
| // Must stay strictly above the ALB idle timeout (60s) — see deploy/pulumi; Bun cap is 255. | ||
| // If the server closes first, the ALB reuses a dead connection and returns 502. | ||
| idleTimeout: 120, | ||
| }, | ||
| () => { | ||
| log.info( | ||
|
|
@@ -206,6 +207,7 @@ const startServer = async () => { | |
| }, | ||
| '🦊 Elysia server started', | ||
| ) | ||
| tinfoilKeepWarm.start() | ||
|
|
||
| if (settings.swaggerEnabled) { | ||
| log.info( | ||
|
|
@@ -220,11 +222,13 @@ const startServer = async () => { | |
|
|
||
| // Graceful shutdown | ||
| process.on('SIGINT', async () => { | ||
| tinfoilKeepWarm.stop() | ||
| log.info('Received SIGINT, shutting down gracefully...') | ||
| process.exit(0) | ||
| }) | ||
|
|
||
| process.on('SIGTERM', async () => { | ||
| tinfoilKeepWarm.stop() | ||
| log.info('Received SIGTERM, shutting down gracefully...') | ||
| process.exit(0) | ||
| }) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.