import { type CrudBuses, type CrudOperation, type CrudResource } from './crud.js'; import { type Route } from './route.js'; /** * What `api.resource(Articles)` asks of a resource: its name. * * Structural on purpose. This package may not depend on `@assemora/resources` * (SPEC.md §8) and does not need to — a resource has already described itself into the * Schema Registry, and its name is the whole address of that description. */ export type NamedResource = { readonly name: string; }; /** * Which of the five generated endpoints a version publishes (SPEC.md §43, §47). * * The point of a version is usually that *one* endpoint changed. Without this, saying * so meant abandoning `api.resource()` and hand-writing all five, because the generated * listing had already claimed the path the new one wanted. */ export type VersionedResourceOptions = { /** Publish only these. */ readonly only?: readonly CrudOperation[]; /** Publish everything the resource allows except these — the usual half. */ readonly except?: readonly CrudOperation[]; }; /** * What can be done inside a version, which is what the server does outside one. * * Deliberately narrow. Commands, queries and assets are absent because none of them is * a versioned thing: a command belongs to the application rather than to a shape of its * REST surface (SPEC.md §14), and a stylesheet is not an endpoint. So is a nested * `version` — `/v2/v1/articles` is not a path anybody means. */ export type ApiVersion = { /** Mounts routes under this version: `/articles` becomes `/v1/articles`. */ mount(...routes: Route[]): ApiVersion; /** * Mounts generated CRUD for a resource the registry already describes (SPEC.md §43). * * ```ts * api.resource(Articles, { except: ['list'] }).mount(listArticlesV2) * ``` */ resource(resource: NamedResource, options?: VersionedResourceOptions): ApiVersion; /** * Also publishes, under this version, every route the modules registered. * * Beside their bare addresses, not instead of them: `module('blog').routes(search)` * describes `/search` when the application is created, and a description cannot be * withdrawn. This is "v1 answers everything too", and a route that should live only * under a version is declared inside the version with `api.mount()`. */ mountRegistered(): ApiVersion; }; /** * What a version's declaration may answer with: nothing, or the chain it built. * * Not `void`. TypeScript's void-return rule accepts a function returning anything where * `=> void` is expected, so an `async` callback compiled cleanly and then published * nothing: everything after its first `await` ran once the routes had already been * collected. A type parameter constrained to this union is what makes that a compile * error instead of an empty API with a green start-up. */ export type VersionDeclaration = void | ApiVersion; export type ApiVersionOptions = { readonly name: string; /** Every resource the registry describes — what `resource()` looks a name up in. */ readonly resources: readonly CrudResource[]; readonly buses: CrudBuses; /** Every route the modules registered — what `mountRegistered()` publishes. */ readonly registered?: readonly Route[]; }; /** * The same route, published under a version. * * A copy rather than a mutation, so one route object can be published in several * versions — which is the ordinary case for a handler two versions still share. */ export declare const versionedRoute: (definition: Route, version: string) => Route; /** * Runs a version's declaration and answers with its routes, paths already rewritten. * * Collecting instead of mounting keeps this pure, and keeps the server's `mount` the * one place a route is described and served. A versioned endpoint therefore takes no * second code path anywhere — the only difference between it and any other route is * the string it calls its path. */ export declare const versionRoutes: (options: ApiVersionOptions, define: (api: ApiVersion) => R) => readonly Route[]; //# sourceMappingURL=version.d.ts.map