adding home page
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
function escapeHtml(value) {
|
||||
return value
|
||||
.replaceAll('&', '&')
|
||||
.replaceAll('<', '<')
|
||||
.replaceAll('>', '>')
|
||||
.replaceAll('"', '"')
|
||||
.replaceAll("'", ''');
|
||||
}
|
||||
|
||||
function inlineMarkdown(value) {
|
||||
let html = escapeHtml(value);
|
||||
html = html.replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, '<a href="$2">$1</a>');
|
||||
html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
|
||||
html = html.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
||||
return html;
|
||||
}
|
||||
|
||||
export function renderMarkdown(markdown) {
|
||||
const lines = markdown.replaceAll('\r\n', '\n').split('\n');
|
||||
const output = [];
|
||||
let paragraph = [];
|
||||
let list = [];
|
||||
let code = null;
|
||||
|
||||
const flushParagraph = () => {
|
||||
if (paragraph.length) {
|
||||
output.push(`<p>${inlineMarkdown(paragraph.join(' '))}</p>`);
|
||||
paragraph = [];
|
||||
}
|
||||
};
|
||||
const flushList = () => {
|
||||
if (list.length) {
|
||||
output.push(`<ul>${list.map((item) => `<li>${inlineMarkdown(item)}</li>`).join('')}</ul>`);
|
||||
list = [];
|
||||
}
|
||||
};
|
||||
|
||||
for (const line of lines) {
|
||||
if (code) {
|
||||
if (line.startsWith('```')) {
|
||||
output.push(`<pre><code>${escapeHtml(code.join('\n'))}</code></pre>`);
|
||||
code = null;
|
||||
} else {
|
||||
code.push(line);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.startsWith('```')) {
|
||||
flushParagraph();
|
||||
flushList();
|
||||
code = [];
|
||||
} else if (/^#{1,6} /.test(line)) {
|
||||
flushParagraph();
|
||||
flushList();
|
||||
const [, hashes, heading] = line.match(/^(#{1,6}) (.+)$/);
|
||||
output.push(`<h${hashes.length}>${inlineMarkdown(heading)}</h${hashes.length}>`);
|
||||
} else if (/^- /.test(line)) {
|
||||
flushParagraph();
|
||||
list.push(line.slice(2));
|
||||
} else if (line.trim() === '') {
|
||||
flushParagraph();
|
||||
flushList();
|
||||
} else {
|
||||
flushList();
|
||||
paragraph.push(line.trim());
|
||||
}
|
||||
}
|
||||
|
||||
if (code) output.push(`<pre><code>${escapeHtml(code.join('\n'))}</code></pre>`);
|
||||
flushParagraph();
|
||||
flushList();
|
||||
return output.join('\n');
|
||||
}
|
||||
|
||||
export function renderPage(markdown, { title = 'OpenCode Go Proxy' } = {}) {
|
||||
return `<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>${escapeHtml(title)}</title>
|
||||
<style>
|
||||
:root { color-scheme: dark; font-family: system-ui, sans-serif; }
|
||||
body { max-width: 50rem; margin: 0 auto; padding: 3rem 1.25rem; background: #101114; color: #f1f3f5; line-height: 1.6; }
|
||||
a { color: #8ab4ff; } code { padding: .15rem .35rem; background: #252830; border-radius: .25rem; }
|
||||
pre { overflow-x: auto; padding: 1rem; background: #191b21; border-radius: .5rem; }
|
||||
</style>
|
||||
</head>
|
||||
<body>${renderMarkdown(markdown)}</body>
|
||||
</html>`;
|
||||
}
|
||||
+15
-1
@@ -1,5 +1,9 @@
|
||||
import { Readable } from 'node:stream';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import express from 'express';
|
||||
import { renderPage } from './markdown.js';
|
||||
import { createKeyRotator } from './key-store.js';
|
||||
import { clientIp, createRateLimiter, numericCost, rateLimitError } from './rate-limit.js';
|
||||
import {
|
||||
@@ -26,6 +30,7 @@ async function forwardError(upstream, response) {
|
||||
}
|
||||
|
||||
export const DEFAULT_MAX_CONTEXT_TOKENS = 262144;
|
||||
const defaultPagesDirectory = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'pages');
|
||||
|
||||
function maxContextFromEnv(value = process.env.MAX_CONTEXT_TOKENS) {
|
||||
if (value === undefined) return DEFAULT_MAX_CONTEXT_TOKENS;
|
||||
@@ -54,11 +59,20 @@ function withContextLimit(payload, maxContextTokens) {
|
||||
};
|
||||
}
|
||||
|
||||
export function createProxyApp({ keys, fetchImpl = globalThis.fetch, upstreamBaseUrl = DEFAULT_UPSTREAM_BASE_URL, maxContextTokens = maxContextFromEnv(), rateLimiter = createRateLimiter() } = {}) {
|
||||
export function createProxyApp({ keys, fetchImpl = globalThis.fetch, upstreamBaseUrl = DEFAULT_UPSTREAM_BASE_URL, maxContextTokens = maxContextFromEnv(), rateLimiter = createRateLimiter(), pagesDirectory = defaultPagesDirectory } = {}) {
|
||||
const rotator = createKeyRotator(keys);
|
||||
const app = express();
|
||||
app.use(express.json({ limit: '10mb' }));
|
||||
|
||||
app.get('/', (_request, response) => {
|
||||
try {
|
||||
const markdown = fs.readFileSync(path.join(pagesDirectory, 'index.md'), 'utf8');
|
||||
response.type('html').send(renderPage(markdown));
|
||||
} catch (error) {
|
||||
response.status(404).send('Page not found');
|
||||
}
|
||||
});
|
||||
|
||||
async function fetchWithKeyRetries(url, options = {}) {
|
||||
let lastError;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user