@ts-rest/core
Advanced tools
Comparing version 3.19.5 to 3.20.0
138
index.js
@@ -0,8 +1,86 @@ | ||
const isZodType = (obj) => { | ||
return typeof (obj === null || obj === void 0 ? void 0 : obj.safeParse) === 'function'; | ||
}; | ||
const isZodObject = (obj) => { | ||
const isZodEffects = typeof (obj === null || obj === void 0 ? void 0 : obj.innerType) === 'function'; | ||
const maybeZodObject = isZodEffects | ||
? obj === null || obj === void 0 ? void 0 : obj.innerType() | ||
: obj; | ||
return typeof (maybeZodObject === null || maybeZodObject === void 0 ? void 0 : maybeZodObject.passthrough) === 'function'; | ||
}; | ||
const isZodObjectStrict = (obj) => { | ||
return typeof (obj === null || obj === void 0 ? void 0 : obj.passthrough) === 'function'; | ||
}; | ||
const extractZodObjectShape = (obj) => { | ||
if (!isZodObject(obj)) { | ||
throw new Error('Unknown zod object type'); | ||
} | ||
if ('innerType' in obj) { | ||
return obj.innerType().shape; | ||
} | ||
return obj.shape; | ||
}; | ||
const zodMerge = (objectA, objectB) => { | ||
if (isZodObjectStrict(objectA)) { | ||
if (isZodObjectStrict(objectB)) { | ||
return objectA.merge(objectB); | ||
} | ||
return objectA; | ||
} | ||
if (isZodObjectStrict(objectB)) { | ||
return objectB; | ||
} | ||
return Object.assign({}, objectA, objectB); | ||
}; | ||
const checkZodSchema = (data, schema, { passThroughExtraKeys = false } = {}) => { | ||
if (isZodObject(schema)) { | ||
const result = schema.safeParse(data); | ||
if (result.success) { | ||
return { | ||
success: true, | ||
data: passThroughExtraKeys && typeof data === 'object' | ||
? { ...data, ...result.data } | ||
: result.data, | ||
}; | ||
} | ||
return { | ||
success: false, | ||
error: result.error, | ||
}; | ||
} | ||
return { | ||
success: true, | ||
data: data, | ||
}; | ||
}; | ||
const zodErrorResponse = (error) => { | ||
return { | ||
name: error.name, | ||
issues: error.issues, | ||
}; | ||
}; | ||
const isAppRoute = (obj) => { | ||
return (obj === null || obj === void 0 ? void 0 : obj.method) !== undefined; | ||
return 'method' in obj && 'path' in obj; | ||
}; | ||
const initTsRest = () => initContract(); | ||
const recursivelyApplyOptions = (router, options) => { | ||
return Object.fromEntries(Object.entries(router).map(([key, value]) => { | ||
if (isAppRoute(value)) { | ||
return [ | ||
key, | ||
{ | ||
...value, | ||
headers: zodMerge(options === null || options === void 0 ? void 0 : options.baseHeaders, value.headers), | ||
}, | ||
]; | ||
} | ||
else { | ||
return [key, recursivelyApplyOptions(value, options)]; | ||
} | ||
})); | ||
}; | ||
const initContract = () => { | ||
return { | ||
router: (args) => args, | ||
router: (endpoints, options) => recursivelyApplyOptions(endpoints, options), | ||
query: (args) => args, | ||
@@ -171,3 +249,3 @@ mutation: (args) => args, | ||
return async (inputArgs) => { | ||
const { query, params, body, headers, ...extraInputArgs } = inputArgs || {}; | ||
const { query, params, body, headers, extraHeaders, ...extraInputArgs } = inputArgs || {}; | ||
const completeUrl = getCompleteUrl(query, clientArgs.baseUrl, params, route, !!clientArgs.jsonQuery); | ||
@@ -180,3 +258,6 @@ return await fetchApi({ | ||
extraInputArgs, | ||
headers: headers || {}, | ||
headers: { | ||
...extraHeaders, | ||
...headers, | ||
}, | ||
}); | ||
@@ -196,49 +277,2 @@ }; | ||
const isZodType = (obj) => { | ||
return typeof (obj === null || obj === void 0 ? void 0 : obj.safeParse) === 'function'; | ||
}; | ||
const isZodObject = (obj) => { | ||
const isZodEffects = typeof (obj === null || obj === void 0 ? void 0 : obj.innerType) === 'function'; | ||
const maybeZodObject = isZodEffects | ||
? obj === null || obj === void 0 ? void 0 : obj.innerType() | ||
: obj; | ||
return typeof (maybeZodObject === null || maybeZodObject === void 0 ? void 0 : maybeZodObject.passthrough) === 'function'; | ||
}; | ||
const extractZodObjectShape = (obj) => { | ||
if (!isZodObject(obj)) { | ||
throw new Error('Unknown zod object type'); | ||
} | ||
if ('innerType' in obj) { | ||
return obj.innerType().shape; | ||
} | ||
return obj.shape; | ||
}; | ||
const checkZodSchema = (data, schema, { passThroughExtraKeys = false } = {}) => { | ||
if (isZodObject(schema)) { | ||
const result = schema.safeParse(data); | ||
if (result.success) { | ||
return { | ||
success: true, | ||
data: passThroughExtraKeys && typeof data === 'object' | ||
? { ...data, ...result.data } | ||
: result.data, | ||
}; | ||
} | ||
return { | ||
success: false, | ||
error: result.error, | ||
}; | ||
} | ||
return { | ||
success: true, | ||
data: data, | ||
}; | ||
}; | ||
const zodErrorResponse = (error) => { | ||
return { | ||
name: error.name, | ||
issues: error.issues, | ||
}; | ||
}; | ||
class ResponseValidationError extends Error { | ||
@@ -273,2 +307,2 @@ constructor(cause) { | ||
export { ResponseValidationError, checkZodSchema, convertQueryParamsToUrlString, encodeQueryParams, encodeQueryParamsJson, extractZodObjectShape, fetchApi, getCompleteUrl, getRouteQuery, getRouteResponses, initClient, initContract, initTsRest, insertParamsIntoPath, isAppRoute, isAppRouteResponse, isZodObject, isZodType, parseJsonQueryObject, tsRestFetchApi, validateResponse, zodErrorResponse }; | ||
export { ResponseValidationError, checkZodSchema, convertQueryParamsToUrlString, encodeQueryParams, encodeQueryParamsJson, extractZodObjectShape, fetchApi, getCompleteUrl, getRouteQuery, getRouteResponses, initClient, initContract, initTsRest, insertParamsIntoPath, isAppRoute, isAppRouteResponse, isZodObject, isZodObjectStrict, isZodType, parseJsonQueryObject, tsRestFetchApi, validateResponse, zodErrorResponse, zodMerge }; |
{ | ||
"name": "@ts-rest/core", | ||
"version": "3.19.5", | ||
"version": "3.20.0", | ||
"description": "RPC-like experience over a regular REST API, with type safe server implementations 🪄", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
import { AppRoute, AppRouteMutation, AppRouter } from './dsl'; | ||
import { ParamsFromUrl } from './paths'; | ||
import { HTTPStatusCode } from './status-codes'; | ||
import { AreAllPropertiesOptional, Merge, OptionalIfAllOptional, Prettify, Without, ZodInferOrType, ZodInputOrType } from './type-utils'; | ||
import { AreAllPropertiesOptional, LowercaseKeys, Merge, OptionalIfAllOptional, PartialByLooseKeys, Prettify, Without, ZodInferOrType, ZodInputOrType } from './type-utils'; | ||
type RecursiveProxyObj<T extends AppRouter, TClientArgs extends ClientArgs> = { | ||
@@ -22,14 +22,12 @@ [TKey in keyof T]: T[TKey] extends AppRoute ? AppRouteFunction<T[TKey], TClientArgs> : T[TKey] extends AppRouter ? RecursiveProxyObj<T[TKey], TClientArgs> : never; | ||
export type ExtractExtraParametersFromClientArgs<TClientArgs extends ClientArgs> = TClientArgs['api'] extends ApiFetcher ? Omit<Parameters<TClientArgs['api']>[0], keyof Parameters<ApiFetcher>[0]> : {}; | ||
type DataReturnArgsBase<TRoute extends AppRoute, TClientArgs extends ClientArgs> = { | ||
type DataReturnArgsBase<TRoute extends AppRoute, TClientArgs extends ClientArgs, THeaders = Prettify<'headers' extends keyof TRoute ? PartialByLooseKeys<LowercaseKeys<ZodInputOrType<TRoute['headers']>>, keyof LowercaseKeys<TClientArgs['baseHeaders']>> : never>> = { | ||
body: TRoute extends AppRouteMutation ? AppRouteBodyOrFormData<TRoute> : never; | ||
params: PathParamsFromUrl<TRoute>; | ||
query: 'query' extends keyof TRoute ? AppRouteMutationType<TRoute['query']> : never; | ||
/** | ||
* Additional headers to send with the request, merged over baseHeaders, | ||
* | ||
* Unset a header by setting it to undefined | ||
*/ | ||
headers?: Record<string, string>; | ||
headers: THeaders; | ||
extraHeaders?: { | ||
[K in NonNullable<keyof THeaders>]: never; | ||
} & Record<string, string | undefined>; | ||
} & ExtractExtraParametersFromClientArgs<TClientArgs>; | ||
type DataReturnArgs<TRoute extends AppRoute, TClientArgs extends ClientArgs> = OptionalIfAllOptional<DataReturnArgsBase<TRoute, TClientArgs>>; | ||
type DataReturnArgs<TRoute extends AppRoute, TClientArgs extends ClientArgs> = OptionalIfAllOptional<Without<DataReturnArgsBase<TRoute, TClientArgs>, never>>; | ||
export type ApiRouteResponse<T> = { | ||
@@ -55,3 +53,3 @@ [K in keyof T]: { | ||
*/ | ||
export type AppRouteFunction<TRoute extends AppRoute, TClientArgs extends ClientArgs> = AreAllPropertiesOptional<Without<DataReturnArgs<TRoute, TClientArgs>, never>> extends true ? (args?: Prettify<Without<DataReturnArgs<TRoute, TClientArgs>, never>>) => Promise<Prettify<ApiRouteResponse<TRoute['responses']>>> : (args: Prettify<Without<DataReturnArgs<TRoute, TClientArgs>, never>>) => Promise<Prettify<ApiRouteResponse<TRoute['responses']>>>; | ||
export type AppRouteFunction<TRoute extends AppRoute, TClientArgs extends ClientArgs> = AreAllPropertiesOptional<DataReturnArgs<TRoute, TClientArgs>> extends true ? (args?: Prettify<DataReturnArgs<TRoute, TClientArgs>>) => Promise<Prettify<ApiRouteResponse<TRoute['responses']>>> : (args: Prettify<DataReturnArgs<TRoute, TClientArgs>>) => Promise<Prettify<ApiRouteResponse<TRoute['responses']>>>; | ||
export interface ClientArgs { | ||
@@ -100,3 +98,3 @@ baseUrl: string; | ||
export declare const getCompleteUrl: (query: unknown, baseUrl: string, params: unknown, route: AppRoute, jsonQuery: boolean) => string; | ||
export declare const getRouteQuery: <TAppRoute extends AppRoute>(route: TAppRoute, clientArgs: ClientArgs) => (inputArgs?: DataReturnArgs<any, ClientArgs>) => Promise<{ | ||
export declare const getRouteQuery: <TAppRoute extends AppRoute>(route: TAppRoute, clientArgs: ClientArgs) => (inputArgs?: DataReturnArgsBase<any, ClientArgs>) => Promise<{ | ||
status: number; | ||
@@ -103,0 +101,0 @@ body: unknown; |
@@ -0,1 +1,7 @@ | ||
import { Merge, Opaque, Prettify, WithoutUnknown } from './type-utils'; | ||
import { z } from 'zod'; | ||
type MixedZodError<A, B> = Opaque<{ | ||
a: A; | ||
b: B; | ||
}, 'MixedZodError'>; | ||
/** | ||
@@ -14,2 +20,3 @@ * The path with colon-prefixed parameters | ||
query?: unknown; | ||
headers?: unknown; | ||
summary?: string; | ||
@@ -31,2 +38,3 @@ description?: string; | ||
query?: unknown; | ||
headers?: unknown; | ||
summary?: string; | ||
@@ -37,2 +45,7 @@ description?: string; | ||
}; | ||
type ValidatedHeaders<T extends AppRoute, TOptions extends RouterOptions, TOptionsApplied = ApplyOptions<T, TOptions>> = 'headers' extends keyof TOptionsApplied ? TOptionsApplied['headers'] extends MixedZodError<infer A, infer B> ? { | ||
_error: 'Cannot mix plain object types with Zod objects for headers'; | ||
a: A; | ||
b: B; | ||
} : T : T; | ||
/** | ||
@@ -43,5 +56,12 @@ * Recursively process a router, allowing for you to define nested routers. | ||
*/ | ||
type RecursivelyProcessAppRouter<T extends AppRouter> = { | ||
[K in keyof T]: T[K] extends AppRoute ? T[K] : T[K] extends AppRouter ? RecursivelyProcessAppRouter<T[K]> : T[K]; | ||
type RecursivelyProcessAppRouter<T extends AppRouter, TOptions extends RouterOptions> = { | ||
[K in keyof T]: T[K] extends AppRoute ? ValidatedHeaders<T[K], TOptions> : T[K] extends AppRouter ? RecursivelyProcessAppRouter<T[K], TOptions> : T[K]; | ||
}; | ||
type RecursivelyApplyOptions<TRouter extends AppRouter, TOptions extends RouterOptions> = { | ||
[TRouterKey in keyof TRouter]: TRouter[TRouterKey] extends AppRoute ? Prettify<ApplyOptions<TRouter[TRouterKey], TOptions>> : TRouter[TRouterKey] extends AppRouter ? RecursivelyApplyOptions<TRouter[TRouterKey], TOptions> : TRouter[TRouterKey]; | ||
}; | ||
type UniversalMerge<A, B> = A extends z.AnyZodObject ? B extends z.AnyZodObject ? z.ZodObject<z.objectUtil.MergeShapes<A['shape'], B['shape']>, B['_def']['unknownKeys'], B['_def']['catchall']> : unknown extends B ? A : MixedZodError<A, B> : unknown extends A ? B : B extends z.AnyZodObject ? MixedZodError<A, B> : unknown extends B ? A : Prettify<Merge<A, B>>; | ||
type ApplyOptions<TRoute extends AppRoute, TOptions extends RouterOptions> = Omit<TRoute, 'headers'> & WithoutUnknown<{ | ||
headers: UniversalMerge<TOptions['baseHeaders'], TRoute['headers']>; | ||
}>; | ||
/** | ||
@@ -58,2 +78,5 @@ * A union of all possible endpoint types. | ||
}; | ||
export type RouterOptions = { | ||
baseHeaders?: unknown; | ||
}; | ||
/** | ||
@@ -73,3 +96,3 @@ * Differentiate between a route and a router | ||
*/ | ||
router: <T extends AppRouter>(endpoints: RecursivelyProcessAppRouter<T>) => T; | ||
router: <TRouter extends AppRouter, TOptions extends RouterOptions>(endpoints: RecursivelyProcessAppRouter<TRouter, TOptions>, options?: TOptions) => RecursivelyApplyOptions<TRouter, TOptions>; | ||
/** | ||
@@ -76,0 +99,0 @@ * A single query route, should exist within |
import { AppRoute, AppRouteMutation, AppRouter } from './dsl'; | ||
import { HTTPStatusCode } from './status-codes'; | ||
import { Prettify, Without, ZodInferOrType, ZodInputOrType } from './type-utils'; | ||
import { LowercaseKeys, Prettify, Without, ZodInferOrType, ZodInputOrType } from './type-utils'; | ||
import { PathParamsWithCustomValidators } from './client'; | ||
@@ -27,2 +27,3 @@ type AppRouteResponses<T extends AppRoute, TStatus extends HTTPStatusCode, TClientOrServer extends 'client' | 'server'> = { | ||
query: 'query' extends keyof T ? ZodInferOrType<T['query']> : never; | ||
headers: 'headers' extends keyof T ? Prettify<LowercaseKeys<ZodInferOrType<T['headers']>>> : never; | ||
}, never>> : T extends AppRouter ? { | ||
@@ -35,2 +36,3 @@ [TKey in keyof T]: ServerInferRequest<T[TKey]>; | ||
query: 'query' extends keyof T ? ZodInputOrType<T['query']> : never; | ||
headers: 'headers' extends keyof T ? Prettify<LowercaseKeys<ZodInputOrType<T['headers']>>> : never; | ||
}, never>> : T extends AppRouter ? { | ||
@@ -37,0 +39,0 @@ [TKey in keyof T]: ClientInferRequest<T[TKey]>; |
@@ -24,2 +24,3 @@ import { z } from 'zod'; | ||
export type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>; | ||
export type PartialByLooseKeys<T, K> = Omit<T, K extends keyof T ? K : never> & Partial<Pick<T, K extends keyof T ? K : never>>; | ||
type OptionalKeys<T> = T extends unknown ? { | ||
@@ -37,2 +38,14 @@ [K in keyof T]-?: undefined extends { | ||
} & {}; | ||
export type DefinedOrEmpty<T, K extends keyof NonNullable<T>> = undefined extends T ? {} : NonNullable<T>[K]; | ||
declare const tag: unique symbol; | ||
declare type Tagged<Token> = { | ||
readonly [tag]: Token; | ||
}; | ||
export type Opaque<Type, Token = unknown> = Type & Tagged<Token>; | ||
export type WithoutUnknown<T> = Pick<T, { | ||
[K in keyof T]: unknown extends Exclude<T[K], undefined> ? never : K; | ||
}[keyof T]>; | ||
export type LowercaseKeys<T> = Prettify<{ | ||
[K in keyof T as K extends string ? Lowercase<K> : K]: T[K]; | ||
}>; | ||
export {}; |
@@ -8,2 +8,3 @@ import { z } from 'zod'; | ||
}>; | ||
export declare const isZodObjectStrict: (obj: unknown) => obj is z.AnyZodObject; | ||
export declare const extractZodObjectShape: <T extends z.AnyZodObject | z.ZodEffects<z.AnyZodObject, { | ||
@@ -14,2 +15,3 @@ [x: string]: any; | ||
}>>(obj: T) => any; | ||
export declare const zodMerge: (objectA: unknown, objectB: unknown) => {}; | ||
export declare const checkZodSchema: (data: unknown, schema: unknown, { passThroughExtraKeys }?: { | ||
@@ -16,0 +18,0 @@ passThroughExtraKeys?: boolean | undefined; |
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
50960
1057