import { Hono } from 'hono' import * as z from 'zod/mini' import type * as App from '../../../App.js' import * as Auth from '../../../internal/Auth.js' import * as Cache from '../../../internal/Cache.js' import * as OpenApi from '../../../internal/OpenApi.js' import * as Response from '../../../internal/Response.js' /** Zod schemas owned by the scope-catalog resource. */ export namespace schema { /** Schemas for the getScopes operation. */ export namespace getScopes { /** A single issuable API-key scope. */ export const Entry = OpenApi.component( z .object({ description: z .string() .check( z.describe('Human-readable explanation of what the scope grants.'), z.meta({ examples: ['Read webhook subscriptions.'] }), ), scope: z .string() .check( z.describe( 'Scope identifier used in API-key grants and route policies. Zone templates carry a concrete chain id and access level in grants.', ), z.meta({ examples: ['data:read'] }), ), selfServe: z .boolean() .check( z.describe('Whether an eligible session may self-mint this scope.'), z.meta({ examples: [true] }), ), }) .check(z.describe('A single issuable API-key scope.')), 'Scope', ) /** Response body for the scope catalog. */ export const Response = OpenApi.component( z .object({ data: z .array(Entry) .check(z.describe('Issuable API-key scopes.'), z.meta({ examples: [[]] })), }) .check(z.describe('Response body for the scope catalog.')), 'ScopeList', ) } } /** * Mounts the `/scopes` resource: the issuable API-key scope vocabulary, served * from the configured catalog. Public catalog data: anonymous callers are served * within the public quota; the session lane lets signed-in consoles skip it. */ export function scopes() { return new Hono().get( '/v1/scopes', Auth.policy({ apiKey: { scopes: [] }, public: true, session: true }), OpenApi.describeRoute({ description: 'See which scopes can be granted to API keys.', operationId: 'getScopes', responses: OpenApi.responses({ errors: { 400: { codes: [], description: 'Malformed API key.' } }, success: { description: 'Issuable scope catalog.', schema: schema.getScopes.Response }, }), summary: 'List scopes', tags: ['API Keys'], }), Cache.response({ cacheControl: Cache.policies.stable, name: 'tempo-api:scopes:v5', key: (c) => { const url = new URL(c.req.url) url.search = '' return url.toString() }, }), (c) => { if (Auth.narrowAccess) return Auth.accessError(c) return c.json( Response.validated(schema.getScopes.Response, { data: c.get('scopeCatalog').map((entry) => ({ ...entry })), }), 200, ) }, ) }