mirror of
https://github.com/geoffsee/open-gsio.git
synced 2025-09-08 22:56:46 +00:00
100 lines
3.6 KiB
TypeScript
100 lines
3.6 KiB
TypeScript
import { readdir } from 'node:fs/promises';
|
|
|
|
import { config } from 'dotenv';
|
|
import type { RequestLike } from 'itty-router';
|
|
|
|
import ServerCoordinator from './durable-objects/ServerCoordinatorBun';
|
|
import { BunSqliteKVNamespace } from './storage/BunSqliteKVNamespace';
|
|
|
|
import Server from '.';
|
|
|
|
const router = Server.Router();
|
|
|
|
config({
|
|
path: '.env',
|
|
debug: true,
|
|
// defaults: {
|
|
// EVENTSOURCE_HOST: "https://eventsource.seemueller.io",
|
|
// }
|
|
});
|
|
|
|
export default {
|
|
port: 3003,
|
|
fetch: async (request: RequestLike, env: { [key: string]: any }, ctx: any) => {
|
|
// console.log("[trace] request: ", request.method, request.url, "headers: ", request.headers.get("referer"), "body: ", request.body, "env: ", env, "ctx: ", ctx, "")
|
|
|
|
env['SERVER_COORDINATOR'] = ServerCoordinator;
|
|
env['ASSETS'] = assetHandler.ASSETS;
|
|
env['EVENTSOURCE_HOST'] = process.env.EVENTSOURCE_HOST;
|
|
env['GROQ_API_KEY'] = process.env.GROQ_API_KEY;
|
|
env['ANTHROPIC_API_KEY'] = process.env.ANTHROPIC_API_KEY;
|
|
env['FIREWORKS_API_KEY'] = process.env.FIREWORKS_API_KEY;
|
|
env['XAI_API_KEY'] = process.env.XAI_API_KEY;
|
|
env['CEREBRAS_API_KEY'] = process.env.CEREBRAS_API_KEY;
|
|
env['CLOUDFLARE_API_KEY'] = process.env.CLOUDFLARE_API_KEY;
|
|
env['CLOUDFLARE_ACCOUNT_ID'] = process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
env['MLX_API_KEY'] = process.env.MLX_API_KEY;
|
|
env['OLLAMA_API_KEY'] = process.env.OLLAMA_API_KEY;
|
|
env['KV_STORAGE'] = new BunSqliteKVNamespace({ namespace: 'open-gsio' });
|
|
|
|
try {
|
|
const controller = new AbortController();
|
|
const timeout = new Promise((_, reject) =>
|
|
setTimeout(() => {
|
|
controller.abort();
|
|
reject(new Error('Request timeout after 5s'));
|
|
}, 5000),
|
|
);
|
|
|
|
return await Promise.race([router.fetch(request, env, ctx), timeout]);
|
|
} catch (e) {
|
|
console.error('Error handling request:', e);
|
|
return new Response('Server Error', { status: 500 });
|
|
}
|
|
},
|
|
};
|
|
|
|
export const assetHandler = {
|
|
ASSETS: {
|
|
/**
|
|
* Fetches the requested static asset from local dist
|
|
*
|
|
* @param {Request} request - The incoming Fetch API Request object.
|
|
* @returns {Promise<Response>} A Promise that resolves with the Response for the requested asset,
|
|
* or a 404 Response if the asset is not found or an error occurs.
|
|
*/
|
|
async fetch(request: Request): Promise<Response> {
|
|
// Serialize incoming request URL
|
|
const originalUrl = new URL(request.url);
|
|
const url = new URL(request.url);
|
|
|
|
// List all files in the public directory
|
|
const PUBLIC_DIR = new URL('../client/public/', import.meta.url).pathname;
|
|
const publicFiles = await readdir(PUBLIC_DIR, { recursive: true });
|
|
|
|
// Get the filename from pathname and remove any path traversal attempts
|
|
const filename = url.pathname.split('/').pop()?.replace(/\.\./g, '') || '';
|
|
|
|
const isStatic = publicFiles.some(file => file === filename);
|
|
|
|
if (url.pathname === '/') {
|
|
url.pathname = '/index.html';
|
|
} else if (isStatic && !url.pathname.startsWith('/static')) {
|
|
// leave it alone
|
|
} else if (isStatic) {
|
|
url.pathname = `/static${url.pathname}`;
|
|
}
|
|
|
|
const dist = new URL('../client/dist/client', import.meta.url).pathname;
|
|
|
|
try {
|
|
return new Response(Bun.file(`${dist}${url.pathname}`));
|
|
} catch (error) {
|
|
// Log the error with the original requested path
|
|
console.error(`Error reading asset from path ${originalUrl.pathname}:`, error);
|
|
return new Response(null, { status: 404 });
|
|
}
|
|
},
|
|
},
|
|
};
|