opinionated-machine
Version:
Very opinionated DI framework for fastify, built on top of awilix
67 lines (66 loc) • 3.35 kB
TypeScript
import type { ApiContract, CommonRouteDefinition } from '@lokalise/api-contracts';
import { type GatewayMetadataValue } from './gatewayMetadata.ts';
import type { GatewayMetadata } from './gatewayTypes.ts';
type AnyContract = CommonRouteDefinition<any, any, any, any, any, any, any, any> | ApiContract;
/**
* Validate gateway metadata and stamp it onto a route via the
* `GATEWAY_METADATA_SYMBOL` non-enumerable property.
*
* Shared between `withGatewayMetadata` (the post-hoc helper) and
* `buildApiRoute` (which accepts `gatewayMetadata` inline via its options).
* Centralising the validate-and-stamp logic here keeps both authoring styles
* behaviourally identical: same Zod errors at the call site, same hidden
* symbol storage, same value visible to `readGatewayMetadata` and
* `buildGatewayManifest`.
*
* Parameter is `unknown` because the contract-narrowed `GatewayMetadata<C>`
* shapes from the two call sites aren't structurally assignable to each
* other (variant `ContractRateLimitKey<C>`), and the runtime Zod schema is
* the actual source of truth either way.
*/
export declare function attachGatewayMetadata<Route extends object>(route: Route, metadata: unknown): Route;
/**
* Attach gateway metadata to a route built by `buildFastifyRoute` / `buildApiRoute`.
*
* The metadata is stamped on the route via a non-enumerable `Symbol` property,
* so Fastify never sees it (it walks own enumerable keys when registering
* routes). The same route reference is returned — no copy, no spread.
*
* Apply at the `buildRoutes()` return site (or in the `routes` object for
* `AbstractApiController`) so all gateway annotations for a controller live in
* a single, scannable block:
*
* @example
* ```ts
* public buildRoutes(): BuildRoutesReturnType<typeof MyController.contracts> {
* return {
* getItem: withGatewayMetadata(MyController.contracts.getItem, this.getItem, {
* cache: { ttl: '60s' },
* match: { customHeaders: { 'x-tenant-id': { regex: '^t_' } } },
* }),
* // un-annotated routes pass through directly — they still inherit
* // controller- and service-wide gateway defaults.
* deleteItem: this.deleteItem,
* }
* }
* ```
*
* For `buildApiRoute`-built routes, `options.gatewayMetadata` is the simpler
* inline path; this helper remains the right tool for routes built with
* `buildFastifyRoute` and for cases where the route is constructed elsewhere.
*
* @param _contract - The contract is taken purely to drive type inference for
* `match.headers`, `match.query`, and `rateLimit.key`. It is not stored.
* @param route - The route returned by `buildFastifyRoute` or `buildApiRoute`.
* @param metadata - Per-route gateway metadata.
* @returns The same `route` reference, with metadata attached via Symbol.
*/
export declare function withGatewayMetadata<Contract extends AnyContract, Route extends object>(_contract: Contract, route: Route, metadata: GatewayMetadata<Contract>): Route;
/**
* Read gateway metadata previously stamped on a route — either by
* `withGatewayMetadata`, by `buildApiRoute(..., { gatewayMetadata })`, or by
* the shared `attachGatewayMetadata` helper. Returns `undefined` if no
* metadata was attached.
*/
export declare function readGatewayMetadata(route: object): GatewayMetadataValue | undefined;
export {};