kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
pull/715/head
rodzic
ce86808d35
commit
ee658f8d81
|
@ -0,0 +1,123 @@
|
|||
import { assert } from '@agentic/platform-core'
|
||||
import {
|
||||
cors,
|
||||
errorHandler,
|
||||
init,
|
||||
responseTime,
|
||||
sentry
|
||||
} from '@agentic/platform-hono'
|
||||
import { Hono } from 'hono'
|
||||
|
||||
import type { GatewayHonoEnv } from './lib/types'
|
||||
import { createAgenticClient } from './lib/agentic-client'
|
||||
import { fetchCache } from './lib/fetch-cache'
|
||||
import { getRequestCacheKey } from './lib/get-request-cache-key'
|
||||
import { resolveOriginRequest } from './lib/resolve-origin-request'
|
||||
|
||||
export const app = new Hono<GatewayHonoEnv>()
|
||||
|
||||
app.onError(errorHandler)
|
||||
app.use(sentry())
|
||||
|
||||
// TODO: Compression is causing a weird bug on dev even for simple responses.
|
||||
// I think it's because wrangler is changing the response to be streamed
|
||||
// with `transfer-encoding: chunked`, which is not compatible with
|
||||
// `hono/compress`.
|
||||
// app.use(compress())
|
||||
|
||||
app.use(
|
||||
cors({
|
||||
origin: '*',
|
||||
allowHeaders: ['Content-Type', 'Authorization'],
|
||||
allowMethods: ['POST', 'GET', 'OPTIONS'],
|
||||
exposeHeaders: ['Content-Length'],
|
||||
maxAge: 600,
|
||||
credentials: true
|
||||
})
|
||||
)
|
||||
app.use(init)
|
||||
|
||||
// Wrangler does this for us. TODO: Does this happen on prod?
|
||||
// app.use(accessLogger)
|
||||
|
||||
app.use(responseTime)
|
||||
|
||||
app.all(async (ctx) => {
|
||||
ctx.set('cache', caches.default)
|
||||
ctx.set('client', createAgenticClient(ctx))
|
||||
|
||||
const resolvedOriginRequest = await resolveOriginRequest(ctx)
|
||||
|
||||
const originStartTime = Date.now()
|
||||
let originResponse: Response | undefined
|
||||
|
||||
switch (resolvedOriginRequest.deployment.originAdapter.type) {
|
||||
case 'openapi':
|
||||
case 'raw': {
|
||||
assert(
|
||||
resolvedOriginRequest.originRequest,
|
||||
500,
|
||||
'Origin request is required'
|
||||
)
|
||||
|
||||
const cacheKey = await getRequestCacheKey(
|
||||
ctx,
|
||||
resolvedOriginRequest.originRequest
|
||||
)
|
||||
|
||||
originResponse = await fetchCache(ctx, {
|
||||
cacheKey,
|
||||
fetchResponse: () => fetch(resolvedOriginRequest.originRequest!)
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
case 'mcp':
|
||||
throw new Error('MCP not yet supported')
|
||||
}
|
||||
|
||||
assert(originResponse, 500, 'Origin response is required')
|
||||
const res = new Response(originResponse.body, originResponse)
|
||||
|
||||
// Record the time it took for both the origin and gateway to respond
|
||||
const now = Date.now()
|
||||
const originTimespan = now - originStartTime
|
||||
res.headers.set('x-origin-response-time', `${originTimespan}ms`)
|
||||
|
||||
// Reset server to agentic because Cloudflare likes to override things
|
||||
res.headers.set('server', 'agentic')
|
||||
|
||||
res.headers.delete('x-powered-by')
|
||||
res.headers.delete('via')
|
||||
res.headers.delete('nel')
|
||||
res.headers.delete('report-to')
|
||||
res.headers.delete('server-timing')
|
||||
res.headers.delete('reporting-endpoints')
|
||||
|
||||
// const id: DurableObjectId = env.DO_RATE_LIMITER.idFromName('foo')
|
||||
// const stub = env.DO_RATE_LIMITER.get(id)
|
||||
// const greeting = await stub.sayHello('world')
|
||||
|
||||
// return new Response(greeting)
|
||||
|
||||
return res
|
||||
|
||||
// TODO: move this `finally` blockto a middleware handler
|
||||
// const now = Date.now()
|
||||
// Report usage.
|
||||
// Note that we are not awaiting the results of this on purpose so we can
|
||||
// return the response to the client immediately.
|
||||
// TODO
|
||||
// ctx.waitUntil(
|
||||
// reportUsage(ctx, {
|
||||
// ...call,
|
||||
// cache: res!.headers.get('cf-cache-status'),
|
||||
// status: res!.status,
|
||||
// timestamp: Math.ceil(now / 1000),
|
||||
// computeTime: originTimespan!,
|
||||
// gatewayTime: gatewayTimespan!,
|
||||
// // TODO: record correct bandwidth of request + response content-length
|
||||
// bandwidth: 0
|
||||
// })
|
||||
// )
|
||||
})
|
|
@ -1,30 +0,0 @@
|
|||
const allowedMethods = 'GET, HEAD, POST, PUT, DELETE, TRACE, PATCH, OPTIONS'
|
||||
|
||||
// TODO: Remove; currently unused in favor of hono/cors
|
||||
export function handleOptions(req: Request) {
|
||||
// Make sure the necessary headers are present for this to be a valid pre-
|
||||
// flight request
|
||||
if (
|
||||
req.headers.get('Origin') &&
|
||||
req.headers.get('Access-Control-req-Method') &&
|
||||
req.headers.get('Access-Control-Request-Headers')
|
||||
) {
|
||||
// Handle CORS pre-flight request.
|
||||
return new Response(null, {
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': allowedMethods,
|
||||
'Access-Control-Allow-Headers':
|
||||
req.headers.get('Access-Control-Request-Headers') ?? '*'
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// Handle standard OPTIONS request.
|
||||
// If you want to allow other HTTP Methods, you can do that here.
|
||||
return new Response(null, {
|
||||
headers: {
|
||||
Allow: allowedMethods
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,131 +1,9 @@
|
|||
import { assert } from '@agentic/platform-core'
|
||||
import {
|
||||
cors,
|
||||
errorHandler,
|
||||
init,
|
||||
responseTime,
|
||||
sentry
|
||||
} from '@agentic/platform-hono'
|
||||
import { Hono } from 'hono'
|
||||
|
||||
import type { GatewayHonoEnv } from './lib/types'
|
||||
import { createAgenticClient } from './lib/agentic-client'
|
||||
import { app } from './app'
|
||||
import { type Env, parseEnv } from './lib/env'
|
||||
import { fetchCache } from './lib/fetch-cache'
|
||||
import { getRequestCacheKey } from './lib/get-request-cache-key'
|
||||
import { resolveOriginRequest } from './lib/resolve-origin-request'
|
||||
|
||||
// Export Durable Objects for cloudflare
|
||||
export { DurableObjectRateLimiter } from './durable-object'
|
||||
|
||||
export const app = new Hono<GatewayHonoEnv>()
|
||||
|
||||
app.onError(errorHandler)
|
||||
app.use(sentry())
|
||||
|
||||
// TODO: Compression is causing a weird bug on dev even for simple responses.
|
||||
// I think it's because wrangler is changing the response to be streamed
|
||||
// with `transfer-encoding: chunked`, which is not compatible with
|
||||
// `hono/compress`.
|
||||
// app.use(compress())
|
||||
|
||||
app.use(
|
||||
cors({
|
||||
origin: '*',
|
||||
allowHeaders: ['Content-Type', 'Authorization'],
|
||||
allowMethods: ['POST', 'GET', 'OPTIONS'],
|
||||
exposeHeaders: ['Content-Length'],
|
||||
maxAge: 600,
|
||||
credentials: true
|
||||
})
|
||||
)
|
||||
app.use(init)
|
||||
|
||||
// Wrangler does this for us. TODO: Does this happen on prod?
|
||||
// app.use(accessLogger)
|
||||
|
||||
app.use(responseTime)
|
||||
|
||||
app.all(async (ctx) => {
|
||||
ctx.set('cache', caches.default)
|
||||
ctx.set('client', createAgenticClient(ctx))
|
||||
|
||||
const resolvedOriginRequest = await resolveOriginRequest(ctx)
|
||||
|
||||
const originStartTime = Date.now()
|
||||
let originResponse: Response | undefined
|
||||
|
||||
switch (resolvedOriginRequest.deployment.originAdapter.type) {
|
||||
case 'openapi':
|
||||
case 'raw': {
|
||||
assert(
|
||||
resolvedOriginRequest.originRequest,
|
||||
500,
|
||||
'Origin request is required'
|
||||
)
|
||||
|
||||
const cacheKey = await getRequestCacheKey(
|
||||
ctx,
|
||||
resolvedOriginRequest.originRequest
|
||||
)
|
||||
|
||||
originResponse = await fetchCache(ctx, {
|
||||
cacheKey,
|
||||
fetchResponse: () => fetch(resolvedOriginRequest.originRequest!)
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
case 'mcp':
|
||||
throw new Error('MCP not yet supported')
|
||||
}
|
||||
|
||||
assert(originResponse, 500, 'Origin response is required')
|
||||
const res = new Response(originResponse.body, originResponse)
|
||||
|
||||
// Record the time it took for both the origin and gateway to respond
|
||||
const now = Date.now()
|
||||
const originTimespan = now - originStartTime
|
||||
res.headers.set('x-origin-response-time', `${originTimespan}ms`)
|
||||
|
||||
// Reset server to agentic because Cloudflare likes to override things
|
||||
res.headers.set('server', 'agentic')
|
||||
|
||||
res.headers.delete('x-powered-by')
|
||||
res.headers.delete('via')
|
||||
res.headers.delete('nel')
|
||||
res.headers.delete('report-to')
|
||||
res.headers.delete('server-timing')
|
||||
res.headers.delete('reporting-endpoints')
|
||||
|
||||
// const id: DurableObjectId = env.DO_RATE_LIMITER.idFromName('foo')
|
||||
// const stub = env.DO_RATE_LIMITER.get(id)
|
||||
// const greeting = await stub.sayHello('world')
|
||||
|
||||
// return new Response(greeting)
|
||||
|
||||
return res
|
||||
|
||||
// TODO: move this `finally` blockto a middleware handler
|
||||
// const now = Date.now()
|
||||
// Report usage.
|
||||
// Note that we are not awaiting the results of this on purpose so we can
|
||||
// return the response to the client immediately.
|
||||
// TODO
|
||||
// ctx.waitUntil(
|
||||
// reportUsage(ctx, {
|
||||
// ...call,
|
||||
// cache: res!.headers.get('cf-cache-status'),
|
||||
// status: res!.status,
|
||||
// timestamp: Math.ceil(now / 1000),
|
||||
// computeTime: originTimespan!,
|
||||
// gatewayTime: gatewayTimespan!,
|
||||
// // TODO: record correct bandwidth of request + response content-length
|
||||
// bandwidth: 0
|
||||
// })
|
||||
// )
|
||||
})
|
||||
|
||||
export default {
|
||||
async fetch(
|
||||
request: Request,
|
||||
|
|
Ładowanie…
Reference in New Issue