import { createError, useRuntimeConfig } from 'nuxt/server' import type { RequestEvent } from 'nuxt/server' import { createAirspace } from 'airspace' import type { Identity } from 'airspace' import { timestamps } from 'airspace/plugins/timestamps' import { collections } from '#shared/collections' /** * Reads against our own PDS need no auth, so the public client is shared by * every request and caches its listings. Writes go through * `requireAdminAirspace`, which carries the editor's OAuth session. */ let publicAirspace: ReturnType | null = null /** How long a public listing stays fresh. The site reads far more often than it writes. */ const READ_TTL = 60_000 function identity () { const config = useRuntimeConfig() const did = config.atproto.did const service = config.public.atproto.service if (!did || !service) { throw createError({ status: 500, statusText: 'runtimeConfig.atproto.did / public.atproto.service are not set; the build-time atproto module did not resolve them.', }) } return { did, service } as { did: Identity['did'], service: string } } function createPublicAirspace () { return createAirspace({ identity: identity(), collections, plugins: [timestamps()], cache: { ttl: READ_TTL }, }) } /** The read-only client behind every public page and API route. */ export function useAirspace () { return publicAirspace ??= createPublicAirspace() } /** * A client authenticated as the editor. Built per request, because the OAuth * session store closes over the event. */ export async function requireAdminAirspace (event: RequestEvent) { const session = await requireAdminSession(event) return createAirspace({ identity: identity(), collections, plugins: [timestamps()], session, }) } /** Drop cached public reads after a write, so the site reflects an edit immediately. */ export function invalidatePublicReads (nsid?: string): void { publicAirspace?.invalidate(nsid) }