/** * defineContract() — Type-safe contract definition helper * * Provides TypeScript type inference for service contracts, enabling * IDE autocomplete and type checking on auto-generated proxy clients. * * @example * ```ts * import { Service, defineContract } from 'threadforge'; * * // Define the contract with full type information * const contract = defineContract({ * expose: ['getUser', 'createUser', 'findByEmail'], * routes: [ * { method: 'GET', path: '/users/:id', handler: 'getUser' }, * { method: 'POST', path: '/users', handler: 'createUser' }, * ], * emits: { createUser: 'user.created' }, * }); * * export default class UserService extends Service { * static contract = contract; * * async getUser(id: string): Promise { * return this.db.findUser(id); * } * * async createUser(data: CreateUserInput): Promise { * return this.db.insert(data); * } * * async findByEmail(email: string): Promise { * return this.db.findOne({ email }); * } * } * ``` * * In consuming services, use `ServiceProxy` for typed proxy access: * * ```ts * import type { ServiceProxy } from 'threadforge'; * import type UserService from './users.js'; * * class ApiService extends Service { * // Declare typed proxies * declare users: ServiceProxy; * * async onStart(ctx: ForgeContext) { * // Full autocomplete and type checking: * const user = await this.users.getUser('123'); * // ^? Promise * } * } * ``` */ interface ContractRouteEntry { method: string; path: string; handler: string; auth?: string; rateLimit?: string; cacheSecs?: number; cache?: number; validate?: Record | ((input: unknown) => string | null | undefined | false); } interface ContractSubscription { service: string; event: string; handler: string; } /** * Static contract definition shape. The generic parameter `T` constrains * `expose`, `routes.handler`, and `emits` keys to actual method names * on the service class. */ export interface ContractDefinition { /** Method names exposed for IPC proxy calls */ expose?: Array>; /** HTTP route definitions */ routes?: Array; }>; /** Map of method name to event name emitted after execution */ emits?: Partial, string>>; /** Event subscriptions from other services */ on?: ContractSubscription[]; } /** * Extract method names from a class type (excludes constructor and * non-function properties). */ type MethodNames = { [K in keyof T]: T[K] extends (...args: unknown[]) => unknown ? K : never; }[keyof T] & string; /** * ServiceProxy extracts a typed proxy interface from a service class. * Each exposed method becomes an async function returning the original * return type. Use this with `declare` to type proxy properties. * * @example * ```ts * declare users: ServiceProxy; * const user = await this.users.getUser('123'); // typed! * ``` */ export type ServiceProxy = { [K in MethodNames]: T[K] extends (...args: infer A) => infer R ? (...args: A) => R extends Promise ? R : Promise : never; }; /** * Define a type-safe static contract for a service. * * The generic parameter constrains handler names to actual methods on * the service class, catching typos at compile time. * * At runtime this is a simple passthrough — it returns the contract * object unchanged. The value is entirely in the TypeScript types. */ export declare function defineContract(contract: ContractDefinition): ContractDefinition; export {}; //# sourceMappingURL=contract.d.ts.map