kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: add cache-control to key api endpoints
rodzic
1150299056
commit
4d2674fc2d
|
@ -1,6 +1,7 @@
|
|||
import type { RawConsumer } from '@/db'
|
||||
import type { AuthenticatedHonoContext } from '@/lib/types'
|
||||
import { setPublicCacheControl } from '@/lib/cache-control'
|
||||
import { env } from '@/lib/env'
|
||||
|
||||
export function setAdminCacheControlForConsumer(
|
||||
c: AuthenticatedHonoContext,
|
||||
|
@ -11,8 +12,15 @@ export function setAdminCacheControlForConsumer(
|
|||
!consumer.activated ||
|
||||
!consumer.isStripeSubscriptionActive
|
||||
) {
|
||||
setPublicCacheControl(c.res, '10s')
|
||||
// TODO: should we cache free-tier consumers for longer on prod?
|
||||
// We really don't want free tier customers to cause our backend API so
|
||||
// much traffic, but we'd also like for customers upgrading to a paid tier
|
||||
// to have a snappy, smooth experience – without having to wait for their
|
||||
// free tier subscription to expire from the cache.
|
||||
setPublicCacheControl(c.res, env.isProd ? '30s' : '10s')
|
||||
} else {
|
||||
setPublicCacheControl(c.res, '1m')
|
||||
// We don't want the gateway hitting our API too often, so cache active
|
||||
// customer subscriptions for longer in production
|
||||
setPublicCacheControl(c.res, env.isProd ? '30m' : '1m')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@ import type { AuthenticatedHonoEnv } from '@/lib/types'
|
|||
import { schema } from '@/db'
|
||||
import { acl } from '@/lib/acl'
|
||||
import { aclAdmin } from '@/lib/acl-admin'
|
||||
import { setPublicCacheControl } from '@/lib/cache-control'
|
||||
import { tryGetDeploymentByIdentifier } from '@/lib/deployments/try-get-deployment-by-identifier'
|
||||
import { env } from '@/lib/env'
|
||||
import {
|
||||
openapiAuthenticatedSecuritySchemas,
|
||||
openapiErrorResponse404,
|
||||
|
@ -66,6 +68,13 @@ export function registerV1AdminGetDeploymentByIdentifier(
|
|||
|
||||
const hasPopulateProject = populate.includes('project')
|
||||
|
||||
if (env.isProd) {
|
||||
// Published deployments are immutable, so cache them for longer in production
|
||||
setPublicCacheControl(c.res, deployment.published ? '1h' : '5m')
|
||||
} else {
|
||||
setPublicCacheControl(c.res, '10s')
|
||||
}
|
||||
|
||||
return c.json(
|
||||
parseZodSchema(schema.deploymentAdminSelectSchema, {
|
||||
...deployment,
|
||||
|
|
|
@ -4,6 +4,7 @@ import { createRoute, type OpenAPIHono } from '@hono/zod-openapi'
|
|||
|
||||
import { schema } from '@/db'
|
||||
import { aclPublicProject } from '@/lib/acl-public-project'
|
||||
import { setPublicCacheControl } from '@/lib/cache-control'
|
||||
import { tryGetDeploymentByIdentifier } from '@/lib/deployments/try-get-deployment-by-identifier'
|
||||
import {
|
||||
openapiAuthenticatedSecuritySchemas,
|
||||
|
@ -59,6 +60,13 @@ export function registerV1GetPublicDeploymentByIdentifier(
|
|||
)
|
||||
aclPublicProject(deployment.project!)
|
||||
|
||||
if (deployment.published) {
|
||||
// Note that published deployments should be immutable
|
||||
setPublicCacheControl(c.res, '1m')
|
||||
} else {
|
||||
setPublicCacheControl(c.res, '10s')
|
||||
}
|
||||
|
||||
return c.json(parseZodSchema(schema.deploymentSelectSchema, deployment))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import { createRoute, type OpenAPIHono } from '@hono/zod-openapi'
|
|||
|
||||
import { db, eq, schema } from '@/db'
|
||||
import { aclPublicProject } from '@/lib/acl-public-project'
|
||||
import { setPublicCacheControl } from '@/lib/cache-control'
|
||||
import { env } from '@/lib/env'
|
||||
import {
|
||||
openapiAuthenticatedSecuritySchemas,
|
||||
openapiErrorResponse404,
|
||||
|
@ -50,7 +52,8 @@ export function registerV1GetPublicProjectByIdentifier(
|
|||
...Object.fromEntries(populate.map((field) => [field, true]))
|
||||
}
|
||||
})
|
||||
await aclPublicProject(project, projectIdentifier)
|
||||
aclPublicProject(project, projectIdentifier)
|
||||
setPublicCacheControl(c.res, env.isProd ? '1m' : '10s')
|
||||
|
||||
return c.json(parseZodSchema(schema.projectSelectSchema, project))
|
||||
})
|
||||
|
|
|
@ -4,6 +4,8 @@ import { createRoute, type OpenAPIHono } from '@hono/zod-openapi'
|
|||
|
||||
import { db, eq, schema } from '@/db'
|
||||
import { aclPublicProject } from '@/lib/acl-public-project'
|
||||
import { setPublicCacheControl } from '@/lib/cache-control'
|
||||
import { env } from '@/lib/env'
|
||||
import {
|
||||
openapiAuthenticatedSecuritySchemas,
|
||||
openapiErrorResponse404,
|
||||
|
@ -50,6 +52,7 @@ export function registerV1GetPublicProject(app: OpenAPIHono<DefaultHonoEnv>) {
|
|||
}
|
||||
})
|
||||
aclPublicProject(project, projectId)
|
||||
setPublicCacheControl(c.res, env.isProd ? '1m' : '10s')
|
||||
|
||||
return c.json(parseZodSchema(schema.projectSelectSchema, project))
|
||||
})
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import { env } from 'node:process'
|
||||
|
||||
import type { DefaultHonoEnv } from '@agentic/platform-hono'
|
||||
import { parseZodSchema } from '@agentic/platform-core'
|
||||
import { createRoute, type OpenAPIHono, z } from '@hono/zod-openapi'
|
||||
|
||||
import { and, db, eq, isNotNull, schema } from '@/db'
|
||||
import { setPublicCacheControl } from '@/lib/cache-control'
|
||||
import {
|
||||
openapiAuthenticatedSecuritySchemas,
|
||||
openapiErrorResponses
|
||||
|
@ -60,6 +63,7 @@ export function registerV1ListPublicProjects(app: OpenAPIHono<DefaultHonoEnv>) {
|
|||
offset,
|
||||
limit
|
||||
})
|
||||
setPublicCacheControl(c.res, env.isProd ? '1m' : '10s')
|
||||
|
||||
return c.json(parseZodSchema(z.array(schema.projectSelectSchema), projects))
|
||||
})
|
||||
|
|
|
@ -4,6 +4,8 @@ import { createRoute, type OpenAPIHono } from '@hono/zod-openapi'
|
|||
import type { AuthenticatedHonoEnv } from '@/lib/types'
|
||||
import { db, eq, schema } from '@/db'
|
||||
import { acl } from '@/lib/acl'
|
||||
import { setPublicCacheControl } from '@/lib/cache-control'
|
||||
import { env } from '@/lib/env'
|
||||
import {
|
||||
openapiAuthenticatedSecuritySchemas,
|
||||
openapiErrorResponse404,
|
||||
|
@ -45,6 +47,7 @@ export function registerV1GetUser(app: OpenAPIHono<AuthenticatedHonoEnv>) {
|
|||
where: eq(schema.users.id, userId)
|
||||
})
|
||||
assert(user, 404, `User not found "${userId}"`)
|
||||
setPublicCacheControl(c.res, env.isProd ? '30s' : '10s')
|
||||
|
||||
return c.json(parseZodSchema(schema.userSelectSchema, user))
|
||||
})
|
||||
|
|
|
@ -1,12 +1,25 @@
|
|||
import { assert } from '@agentic/platform-core'
|
||||
|
||||
export type PublicCacheControlLevels = '1s' | '10s' | '1m' | '1h' | '1d'
|
||||
export type PublicCacheControlLevels =
|
||||
| '1s'
|
||||
| '10s'
|
||||
| '30s'
|
||||
| '1m'
|
||||
| '5m'
|
||||
| '10m'
|
||||
| '30m'
|
||||
| '1h'
|
||||
| '1d'
|
||||
|
||||
const publicCacheControlLevelsMap: Record<PublicCacheControlLevels, string> = {
|
||||
'1s': 'public, max-age=1, s-maxage=1 stale-while-revalidate=0',
|
||||
'10s': 'public, max-age=10, s-maxage=10 stale-while-revalidate=1',
|
||||
'30s': 'public, max-age=30, s-maxage=30 stale-while-revalidate=5',
|
||||
'1m': 'public, max-age=60, s-maxage=60 stale-while-revalidate=10',
|
||||
'1h': 'public, max-age=3600, s-maxage=3600, stale-while-revalidate=300',
|
||||
'5m': 'public, max-age=300, s-maxage=300 stale-while-revalidate=60',
|
||||
'10m': 'public, max-age=600, s-maxage=600 stale-while-revalidate=120',
|
||||
'30m': 'public, max-age=1800, s-maxage=1800 stale-while-revalidate=300',
|
||||
'1h': 'public, max-age=3600, s-maxage=3600, stale-while-revalidate=500',
|
||||
'1d': 'public, max-age=86400, s-maxage=86400, stale-while-revalidate=3600'
|
||||
}
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ export function recordToolCallUsage({
|
|||
// If there's a consumer and it hasn't been activated yet, make sure it's
|
||||
// activated. This may be called multiple times if the consumer is cached,
|
||||
// but this method is intentionally idempotent, and we don't cache non-
|
||||
// activated consumers for long, so shouldn't be a problem.
|
||||
// activated consumers for long, so it shouldn't be a problem.
|
||||
waitUntil(client.adminActivateConsumer({ consumerId: consumer.id }))
|
||||
}
|
||||
|
||||
|
|
4
todo.md
4
todo.md
|
@ -11,6 +11,9 @@
|
|||
- should we bypass stripe for `free` plans to increase conversions?
|
||||
- handle browser back/forward with `?next=`
|
||||
- add some social proof to signup page
|
||||
- example usage
|
||||
- fix mcp examples
|
||||
- add example usage to project detail pages
|
||||
- docs
|
||||
- main readme
|
||||
- sub readmes (https://www.npmjs.com/package/@agentic/cli)
|
||||
|
@ -23,7 +26,6 @@
|
|||
- finesse header (mobile)
|
||||
- create agentic products for legacy tools
|
||||
- add basic legal terms and privacy policy (and update links in stripe)
|
||||
- add caching to public projects api endpoints
|
||||
- add support for [`@google/genai`](https://github.com/googleapis/js-genai) tools adapter
|
||||
- add feature about optimized context to marketing site
|
||||
- ensure all agentic tool inputSchemas support openai strict mode by default
|
||||
|
|
Ładowanie…
Reference in New Issue