@ts-rest/core
Advanced tools
Comparing version 3.26.0-rc3.0 to 3.26.0
# @ts-rest/core | ||
## 3.26.0-rc3.0 | ||
## 3.26.0 | ||
### Minor Changes | ||
- e8ea535: Add new `SingleHandler` and `MultiHandler` API to `@ts-rest/nest` | ||
- fcf877d: Allow defining non-json response types in the contract | ||
- 48b138d: Add new `SingleHandler` and `MultiHandler` API to `@ts-rest/nest` | ||
- 2763208: Added `pathPrefix` to contract options to allow recursive path prefixing. | ||
@@ -9,0 +10,0 @@ |
24
index.js
@@ -94,2 +94,3 @@ 'use strict'; | ||
}; | ||
const ContractPlainTypeRuntimeSymbol = Symbol('ContractPlainType'); | ||
const initContract = () => { | ||
@@ -100,4 +101,9 @@ return { | ||
mutation: (args) => args, | ||
response: () => undefined, | ||
body: () => undefined, | ||
response: () => ContractPlainTypeRuntimeSymbol, | ||
body: () => ContractPlainTypeRuntimeSymbol, | ||
type: () => ContractPlainTypeRuntimeSymbol, | ||
otherResponse: ({ contentType, body, }) => ({ | ||
contentType, | ||
body, | ||
}), | ||
}; | ||
@@ -109,3 +115,3 @@ }; | ||
.replace(/:([^/]+)/g, (_, p) => { | ||
return (params === null || params === void 0 ? void 0 : params[p]) || ''; | ||
return params[p] || ''; | ||
}) | ||
@@ -340,6 +346,14 @@ .replace(/\/\//g, '/'); | ||
}; | ||
const isAppRouteOtherResponse = (response) => { | ||
return (response != null && | ||
typeof response === 'object' && | ||
'contentType' in response); | ||
}; | ||
const validateResponse = ({ responseType, response, }) => { | ||
if (isAppRouteResponse(response)) { | ||
const { body } = response; | ||
const responseValidation = checkZodSchema(body, responseType); | ||
const responseSchema = isAppRouteOtherResponse(responseType) | ||
? responseType.body | ||
: responseType; | ||
const responseValidation = checkZodSchema(body, responseSchema); | ||
if (!responseValidation.success) { | ||
@@ -357,2 +371,3 @@ const { error } = responseValidation; | ||
exports.ContractPlainTypeRuntimeSymbol = ContractPlainTypeRuntimeSymbol; | ||
exports.ResponseValidationError = ResponseValidationError; | ||
@@ -374,2 +389,3 @@ exports.UnknownStatusError = UnknownStatusError; | ||
exports.isAppRoute = isAppRoute; | ||
exports.isAppRouteOtherResponse = isAppRouteOtherResponse; | ||
exports.isAppRouteResponse = isAppRouteResponse; | ||
@@ -376,0 +392,0 @@ exports.isZodObject = isZodObject; |
{ | ||
"name": "@ts-rest/core", | ||
"version": "3.26.0-rc3.0", | ||
"version": "3.26.0", | ||
"description": "RPC-like experience over a regular REST API, with type safe server implementations 🪄", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
@@ -69,6 +69,3 @@ import { AppRoute, AppRouteMutation, AppRouter } from './dsl'; | ||
export declare const getCompleteUrl: (query: unknown, baseUrl: string, params: unknown, route: AppRoute, jsonQuery: boolean) => string; | ||
type FullClientInferRequest = ClientInferRequest<AppRouteMutation & { | ||
path: '/:placeholder'; | ||
}, ClientArgs>; | ||
export declare const getRouteQuery: <TAppRoute extends AppRoute>(route: TAppRoute, clientArgs: InitClientArgs) => (inputArgs?: FullClientInferRequest) => Promise<{ | ||
export declare const getRouteQuery: <TAppRoute extends AppRoute>(route: TAppRoute, clientArgs: InitClientArgs) => (inputArgs?: ClientInferRequest<AppRouteMutation, ClientArgs>) => Promise<{ | ||
status: number; | ||
@@ -75,0 +72,0 @@ body: unknown; |
@@ -12,11 +12,19 @@ import { Merge, Opaque, Prettify, WithoutUnknown } from './type-utils'; | ||
type Path = string; | ||
declare const NullSymbol: unique symbol; | ||
export type ContractPlainType<T> = Opaque<T, 'ContractPlainType'>; | ||
export type ContractNullType = Opaque<typeof NullSymbol, 'ContractNullType'>; | ||
export type ContractAnyType = z.ZodTypeAny | ContractPlainType<unknown> | ContractNullType | null; | ||
export type ContractOtherResponse<T extends ContractAnyType> = Opaque<{ | ||
contentType: string; | ||
body: T; | ||
}, 'ContractOtherResponse'>; | ||
type AppRouteCommon = { | ||
path: Path; | ||
pathParams?: unknown; | ||
query?: unknown; | ||
headers?: unknown; | ||
pathParams?: ContractAnyType; | ||
query?: ContractAnyType; | ||
headers?: ContractAnyType; | ||
summary?: string; | ||
description?: string; | ||
deprecated?: boolean; | ||
responses: Record<number, unknown>; | ||
responses: Record<number, ContractAnyType | ContractOtherResponse<ContractAnyType>>; | ||
strictStatusCodes?: boolean; | ||
@@ -38,3 +46,3 @@ metadata?: unknown; | ||
contentType?: 'application/json' | 'multipart/form-data'; | ||
body: unknown; | ||
body: ContractAnyType; | ||
}; | ||
@@ -96,3 +104,3 @@ type ValidatedHeaders<T extends AppRoute, TOptions extends RouterOptions, TOptionsApplied = ApplyOptions<T, TOptions>> = 'headers' extends keyof TOptionsApplied ? TOptionsApplied['headers'] extends MixedZodError<infer A, infer B> ? { | ||
*/ | ||
router: <TRouter extends AppRouter, TPrefix extends string, TOptions extends RouterOptions<TPrefix>>(endpoints: RecursivelyProcessAppRouter<TRouter, TOptions>, options?: TOptions) => RecursivelyApplyOptions<TRouter, TOptions>; | ||
router: <TRouter extends AppRouter, TPrefix extends string, TOptions extends RouterOptions<TPrefix> = {}>(endpoints: RecursivelyProcessAppRouter<TRouter, TOptions>, options?: TOptions) => RecursivelyApplyOptions<TRouter, TOptions>; | ||
/** | ||
@@ -109,9 +117,20 @@ * A single query route, should exist within | ||
/** | ||
* Exists to allow storing a Type in the contract (at compile time only) | ||
* @deprecated Please use type() instead. | ||
*/ | ||
response: <T>() => T; | ||
response: <T>() => T extends null ? ContractNullType : ContractPlainType<T>; | ||
/** | ||
* @deprecated Please use type() instead. | ||
*/ | ||
body: <T>() => T extends null ? ContractNullType : ContractPlainType<T>; | ||
/** | ||
* Exists to allow storing a Type in the contract (at compile time only) | ||
*/ | ||
body: <T>() => T; | ||
type: <T>() => T extends null ? ContractNullType : ContractPlainType<T>; | ||
/** | ||
* Define a custom response type | ||
*/ | ||
otherResponse: <T extends ContractAnyType>({ contentType, body, }: { | ||
contentType: string; | ||
body: T; | ||
}) => ContractOtherResponse<T>; | ||
}; | ||
@@ -123,2 +142,3 @@ /** | ||
export declare const initTsRest: () => ContractInstance; | ||
export declare const ContractPlainTypeRuntimeSymbol: any; | ||
/** | ||
@@ -125,0 +145,0 @@ * Instantiate a ts-rest client, primarily to access `router`, `response`, and `body` |
@@ -1,2 +0,2 @@ | ||
import { AppRoute, AppRouteMutation, AppRouter, AppRouteStrictStatusCodes } from './dsl'; | ||
import { AppRoute, AppRouteMutation, AppRouter, AppRouteStrictStatusCodes, ContractAnyType, ContractOtherResponse } from './dsl'; | ||
import { HTTPStatusCode } from './status-codes'; | ||
@@ -15,6 +15,7 @@ import { And, Extends, LowercaseKeys, Merge, Not, OptionalIfAllOptional, Or, PartialByLooseKeys, Prettify, Without, ZodInferOrType, ZodInputOrType } from './type-utils'; | ||
type PathParamsWithCustomValidators<T extends AppRoute, TClientOrServer extends 'client' | 'server' = 'server'> = T['pathParams'] extends undefined ? PathParamsFromUrl<T> : Merge<PathParamsFromUrl<T>, TClientOrServer extends 'server' ? ZodInferOrType<T['pathParams']> : ZodInputOrType<T['pathParams']>>; | ||
export type ResolveResponseType<T extends ContractAnyType | ContractOtherResponse<ContractAnyType>> = T extends ContractOtherResponse<infer U> ? U : T; | ||
type AppRouteResponses<T extends AppRoute, TStatus extends HTTPStatusCode, TClientOrServer extends 'client' | 'server', TStrictStatusCodes extends 'default' | 'ignore' | 'force' = 'default'> = { | ||
[K in keyof T['responses'] & TStatus]: { | ||
status: K; | ||
body: TClientOrServer extends 'server' ? ZodInputOrType<T['responses'][K]> : ZodInferOrType<T['responses'][K]>; | ||
body: TClientOrServer extends 'server' ? ZodInputOrType<ResolveResponseType<T['responses'][K]>> : ZodInferOrType<ResolveResponseType<T['responses'][K]>>; | ||
} & (TClientOrServer extends 'client' ? { | ||
@@ -37,5 +38,5 @@ headers: Headers; | ||
export type ClientInferResponseBody<T extends AppRoute, TStatus extends keyof T['responses'] = keyof T['responses']> = Prettify<AppRouteResponses<T, TStatus & HTTPStatusCode, 'client'>['body']>; | ||
type BodyWithoutFileIfMultiPart<T extends AppRouteMutation> = Prettify<T['contentType'] extends 'multipart/form-data' ? Without<ZodInferOrType<T['body']>, File> : ZodInferOrType<T['body']>>; | ||
type BodyWithoutFileIfMultiPart<T extends AppRouteMutation> = T['contentType'] extends 'multipart/form-data' ? Without<ZodInferOrType<T['body']>, File> : ZodInferOrType<T['body']>; | ||
export type ServerInferRequest<T extends AppRoute | AppRouter, TServerHeaders = never> = T extends AppRoute ? Prettify<Without<{ | ||
params: [undefined] extends PathParamsWithCustomValidators<T> ? never : Prettify<PathParamsWithCustomValidators<T>>; | ||
params: [keyof PathParamsWithCustomValidators<T>] extends [never] ? never : Prettify<PathParamsWithCustomValidators<T>>; | ||
body: T extends AppRouteMutation ? BodyWithoutFileIfMultiPart<T> : never; | ||
@@ -50,3 +51,5 @@ query: 'query' extends keyof T ? ZodInferOrType<T['query']> : never; | ||
}, THeaders = 'headers' extends keyof T ? Prettify<PartialByLooseKeys<LowercaseKeys<ZodInputOrType<T['headers']>>, keyof LowercaseKeys<TClientArgs['baseHeaders']>>> : never> = Prettify<Without<{ | ||
params: [undefined] extends PathParamsWithCustomValidators<T, 'client'> ? never : Prettify<PathParamsWithCustomValidators<T, 'client'>>; | ||
params: [keyof PathParamsWithCustomValidators<T, 'client'>] extends [ | ||
never | ||
] ? never : Prettify<PathParamsWithCustomValidators<T, 'client'>>; | ||
body: T extends AppRouteMutation ? T['body'] extends null ? never : T['contentType'] extends 'multipart/form-data' ? FormData | ZodInputOrType<T['body']> : ZodInputOrType<T['body']> : never; | ||
@@ -53,0 +56,0 @@ query: 'query' extends keyof T ? T['query'] extends null ? never : ZodInputOrType<T['query']> : never; |
@@ -21,3 +21,3 @@ /** | ||
*/ | ||
export type ParamsFromUrl<T extends string> = RecursivelyExtractPathParams<T, {}> extends infer U ? keyof U extends never ? undefined : { | ||
export type ParamsFromUrl<T extends string> = RecursivelyExtractPathParams<T, {}> extends infer U ? { | ||
[key in keyof U]: U[key]; | ||
@@ -24,0 +24,0 @@ } : never; |
import { HTTPStatusCode } from './status-codes'; | ||
import { ContractAnyType, ContractOtherResponse } from './dsl'; | ||
export declare const isAppRouteResponse: (value: unknown) => value is { | ||
@@ -6,4 +7,5 @@ status: HTTPStatusCode; | ||
}; | ||
export declare const isAppRouteOtherResponse: (response: ContractAnyType | ContractOtherResponse<ContractAnyType>) => response is ContractOtherResponse<ContractAnyType>; | ||
export declare const validateResponse: ({ responseType, response, }: { | ||
responseType: unknown; | ||
responseType: ContractAnyType | ContractOtherResponse<ContractAnyType>; | ||
response: { | ||
@@ -10,0 +12,0 @@ status: number; |
import { z } from 'zod'; | ||
import { ContractNullType, ContractPlainType } from './dsl'; | ||
type GetIndexedField<T, K> = K extends keyof T ? T[K] : K extends `${number}` ? '0' extends keyof T ? undefined : number extends keyof T ? T[number] : undefined : undefined; | ||
@@ -14,4 +15,4 @@ type FieldWithPossiblyUndefined<T, Key> = GetFieldType<Exclude<T, undefined>, Key> | Extract<T, undefined>; | ||
export type With<T, V> = Pick<T, ExcludeKeysWithoutTypeOf<T, V>>; | ||
export type ZodInferOrType<T> = T extends z.ZodTypeAny ? z.infer<T> : T; | ||
export type ZodInputOrType<T> = T extends z.ZodTypeAny ? z.input<T> : T; | ||
export type ZodInferOrType<T> = T extends ContractNullType ? null : T extends ContractPlainType<infer U> ? U : T extends z.ZodTypeAny ? z.infer<T> : T; | ||
export type ZodInputOrType<T> = T extends ContractNullType ? null : T extends ContractPlainType<infer U> ? U : T extends z.ZodTypeAny ? z.input<T> : T; | ||
export type Merge<T, U> = Omit<T, keyof U> & U; | ||
@@ -44,2 +45,3 @@ type Try<A, B, C> = A extends B ? A : C; | ||
export type Opaque<Type, Token = unknown> = Type & Tagged<Token>; | ||
export type UnwrapOpaque<OpaqueType extends Tagged<unknown>> = OpaqueType extends Opaque<infer Type, OpaqueType[typeof tag]> ? Type : OpaqueType; | ||
export type WithoutUnknown<T> = Pick<T, { | ||
@@ -46,0 +48,0 @@ [K in keyof T]: unknown extends Exclude<T[K], undefined> ? never : K; |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
67594
1237
1