UNPKG

@spfn/core

Version:

SPFN Framework Core - File-based routing, transactions, repository pattern

163 lines (159 loc) 5.74 kB
import { Context } from 'hono'; import { ContentfulStatusCode } from 'hono/utils/http-status'; import * as _sinclair_typebox from '@sinclair/typebox'; import { TSchema, Static } from '@sinclair/typebox'; import { b as ErrorResponse } from './error-handler-wjLL3v-a.js'; /** * Success response wrapper */ interface ApiSuccessResponse<T = any> { success: true; data: T; meta?: { timestamp?: string; requestId?: string; pagination?: { page: number; limit: number; total: number; totalPages: number; }; [key: string]: any; }; } /** * Error response type (re-exported from ErrorHandler for consistency) */ type ApiErrorResponse = ErrorResponse; /** * Unified API response type */ type ApiResponse<T = any> = ApiSuccessResponse<T> | ApiErrorResponse; /** * Creates a TypeBox schema for ApiSuccessResponse<T> * * @example * ```ts * const UserSchema = Type.Object({ * id: Type.String(), * name: Type.String(), * }); * * const contract = { * response: ApiSuccessSchema(UserSchema), * }; * ``` */ declare function ApiSuccessSchema<T extends TSchema>(dataSchema: T): _sinclair_typebox.TObject<{ success: _sinclair_typebox.TLiteral<true>; data: T; meta: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{ timestamp: _sinclair_typebox.TOptional<_sinclair_typebox.TString>; requestId: _sinclair_typebox.TOptional<_sinclair_typebox.TString>; pagination: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{ page: _sinclair_typebox.TNumber; limit: _sinclair_typebox.TNumber; total: _sinclair_typebox.TNumber; totalPages: _sinclair_typebox.TNumber; }>>; }>>; }>; /** * Creates a TypeBox schema for ApiErrorResponse */ declare function ApiErrorSchema(): _sinclair_typebox.TObject<{ success: _sinclair_typebox.TLiteral<false>; error: _sinclair_typebox.TObject<{ message: _sinclair_typebox.TString; type: _sinclair_typebox.TString; statusCode: _sinclair_typebox.TNumber; stack: _sinclair_typebox.TOptional<_sinclair_typebox.TString>; details: _sinclair_typebox.TOptional<_sinclair_typebox.TAny>; }>; }>; /** * Creates a TypeBox schema for ApiSuccessResponse<T> * * Use this in your route contract's response field for standardized responses. * Note: ContractClient throws ApiClientError on failure, so only success type is needed. * * @example * ```ts * const contract = { * method: 'GET', * path: '/users/:id', * response: ApiResponseSchema(Type.Object({ * id: Type.String(), * name: Type.String(), * })), * }; * ``` */ declare function ApiResponseSchema<T extends TSchema>(dataSchema: T): _sinclair_typebox.TObject<{ success: _sinclair_typebox.TLiteral<true>; data: T; meta: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{ timestamp: _sinclair_typebox.TOptional<_sinclair_typebox.TString>; requestId: _sinclair_typebox.TOptional<_sinclair_typebox.TString>; pagination: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{ page: _sinclair_typebox.TNumber; limit: _sinclair_typebox.TNumber; total: _sinclair_typebox.TNumber; totalPages: _sinclair_typebox.TNumber; }>>; }>>; }>; /** * File-based Routing System Type Definitions */ type HeaderRecord = Record<string, string | string[]>; type RouteMeta = { public?: boolean; skipMiddlewares?: string[]; tags?: string[]; description?: string; deprecated?: boolean; }; /** * Route Contract: TypeBox-based type-safe route definition * * Defines the shape of request/response for a route endpoint */ type RouteContract = { method: HttpMethod; path: string; params?: TSchema; query?: TSchema; body?: TSchema; response: TSchema; meta?: RouteMeta; }; /** * Infer types from RouteContract * * Extracts TypeScript types from TypeBox schemas */ type InferContract<TContract extends RouteContract> = { params: TContract['params'] extends TSchema ? Static<TContract['params']> : Record<string, never>; query: TContract['query'] extends TSchema ? Static<TContract['query']> : Record<string, never>; body: TContract['body'] extends TSchema ? Static<TContract['body']> : Record<string, never>; response: TContract['response'] extends TSchema ? Static<TContract['response']> : unknown; }; /** * RouteContext: Route Handler Dedicated Context * * Generic version with contract-based type inference */ type RouteContext<TContract extends RouteContract = any> = { params: InferContract<TContract>['params']; query: InferContract<TContract>['query']; data(): Promise<InferContract<TContract>['body']>; json(data: InferContract<TContract>['response'], status?: ContentfulStatusCode, headers?: HeaderRecord): Response; success<T>(data: T, meta?: ApiSuccessResponse<T>['meta'], status?: number): Response; paginated<T>(data: T[], page: number, limit: number, total: number): Response; raw: Context; }; type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; type RouteHandler<TContract extends RouteContract = any> = (c: RouteContext<TContract>) => Response | Promise<Response>; declare function isHttpMethod(value: unknown): value is HttpMethod; export { ApiSuccessSchema as A, type HttpMethod as H, type InferContract as I, type RouteContext as R, type RouteContract as a, type RouteHandler as b, ApiErrorSchema as c, ApiResponseSchema as d, type ApiSuccessResponse as e, type ApiErrorResponse as f, type ApiResponse as g, type HeaderRecord as h, isHttpMethod as i, type RouteMeta as j };