Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More โ†’
Socket
Sign inDemoInstall
Socket

@ts-rest/core

Package Overview
Dependencies
Maintainers
1
Versions
136
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ts-rest/core - npm Package Compare versions

Comparing version 3.17.0 to 3.18.0

src/lib/test-helpers.d.ts

42

index.js

@@ -94,3 +94,3 @@ const isAppRoute = (obj) => {

const defaultApi = async ({ path, method, headers, body, credentials, }) => {
const tsRestFetchApi = async ({ path, method, headers, body, credentials, }) => {
const result = await fetch(path, { method, headers, body, credentials });

@@ -118,4 +118,16 @@ const contentType = result.headers.get('content-type');

};
const fetchApi = (path, clientArgs, route, body) => {
const apiFetcher = clientArgs.api || defaultApi;
const normalizeHeaders = (headers) => {
return Object.fromEntries(Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v]));
};
const fetchApi = ({ path, clientArgs, route, body, extraInputArgs, headers, }) => {
const apiFetcher = clientArgs.api || tsRestFetchApi;
const combinedHeaders = {
...normalizeHeaders(clientArgs.baseHeaders),
...normalizeHeaders(headers),
};
Object.keys(combinedHeaders).forEach((key) => {
if (combinedHeaders[key] === undefined) {
delete combinedHeaders[key];
}
});
if (route.method !== 'GET' && route.contentType === 'multipart/form-data') {

@@ -126,6 +138,5 @@ return apiFetcher({

credentials: clientArgs.credentials,
headers: {
...clientArgs.baseHeaders,
},
headers: combinedHeaders,
body: body instanceof FormData ? body : createFormData(body),
...extraInputArgs,
});

@@ -138,6 +149,7 @@ }

headers: {
...clientArgs.baseHeaders,
'Content-Type': 'application/json',
'content-type': 'application/json',
...combinedHeaders,
},
body: body !== null && body !== undefined ? JSON.stringify(body) : undefined,
...extraInputArgs,
});

@@ -155,4 +167,12 @@ };

return async (inputArgs) => {
const completeUrl = getCompleteUrl(inputArgs === null || inputArgs === void 0 ? void 0 : inputArgs.query, clientArgs.baseUrl, inputArgs === null || inputArgs === void 0 ? void 0 : inputArgs.params, route, !!clientArgs.jsonQuery);
return await fetchApi(completeUrl, clientArgs, route, inputArgs === null || inputArgs === void 0 ? void 0 : inputArgs.body);
const { query, params, body, headers, ...extraInputArgs } = inputArgs || {};
const completeUrl = getCompleteUrl(query, clientArgs.baseUrl, params, route, !!clientArgs.jsonQuery);
return await fetchApi({
path: completeUrl,
clientArgs,
route,
body,
extraInputArgs,
headers: headers || {},
});
};

@@ -231,2 +251,2 @@ };

export { ResponseValidationError, checkZodSchema, convertQueryParamsToUrlString, defaultApi, encodeQueryParams, encodeQueryParamsJson, fetchApi, getCompleteUrl, getRouteQuery, initClient, initContract, initTsRest, insertParamsIntoPath, isAppRoute, isAppRouteResponse, isZodObject, parseJsonQueryObject, validateResponse, zodErrorResponse };
export { ResponseValidationError, checkZodSchema, convertQueryParamsToUrlString, encodeQueryParams, encodeQueryParamsJson, fetchApi, getCompleteUrl, getRouteQuery, initClient, initContract, initTsRest, insertParamsIntoPath, isAppRoute, isAppRouteResponse, isZodObject, parseJsonQueryObject, tsRestFetchApi, validateResponse, zodErrorResponse };
{
"name": "@ts-rest/core",
"version": "3.17.0",
"version": "3.18.0",
"description": "RPC-like experience over a regular REST API, with type safe server implementations ๐Ÿช„",

@@ -5,0 +5,0 @@ "license": "MIT",

@@ -28,16 +28,56 @@ # ts-rest

ts-rest provides an RPC-like client side interface over your existing REST APIs, as well as allowing you define a _separate_ contract implementation rather than going for a 'implementation is the contract' approach, which is best suited for smaller or simpler APIs.
ts-rest offers a simple way to define a contract for your API, which can be both consumed and implemented by your application, giving you end to end type safety without the hassle or code generation.
If you have non typescript consumers, a public API, or maybe want to add type safety to your existing REST API? ts-rest is what you're looking for!
### Features
## Features
- End to end type safety ๐Ÿ›Ÿ
- Magic RPC-like API ๐Ÿช„
- Tiny bundle size ๐ŸŒŸ (1kb!)
- RPC-like client side interface ๐Ÿ“ก
- [Tiny bundle size ๐ŸŒŸ](https://bundlephobia.com/package/@ts-rest/core) (1kb!)
- Well-tested and production ready โœ…
- No Code Generation ๐Ÿƒโ€โ™€๏ธ
- Zod support for body parsing ๐Ÿ‘ฎโ€โ™€๏ธ
- Zod support for runtime type checks ๐Ÿ‘ฎโ€โ™€๏ธ
- Full optional OpenAPI integration ๐Ÿ“
### Super Simple Example
Easily define your API contract somewhere shared
```typescript
const contract = c.contract({
getPosts: {
method: 'GET',
path: '/posts',
query: z.object({
skip: z.number(),
take: z.number(),
}), // <-- Zod schema
responses: {
200: c.response<Post[]>(), // <-- OR normal TS types
},
},
});
```
Fulfil the contract on your sever, with a type-safe router:
```typescript
const router = s.router(contract, {
getPost: async ({ params: { id } }) => {
return {
status: 200,
body: prisma.post.findUnique({ where: { id } }),
};
},
});
```
Consume the api on the client with a RPC-like interface:
```typescript
const result = await client.getPosts({
query: { skip: 0, take: 10 },
// ^-- Fully typed!
});
```
## Quickstart

@@ -44,0 +84,0 @@

import { AppRoute, AppRouteMutation, AppRouter } from './dsl';
import { ParamsFromUrl } from './paths';
import { HTTPStatusCode } from './status-codes';
import { AreAllPropertiesOptional, Merge, OptionalIfAllOptional, Without, ZodInferOrType, ZodInputOrType } from './type-utils';
type RecursiveProxyObj<T extends AppRouter> = {
[TKey in keyof T]: T[TKey] extends AppRoute ? AppRouteFunction<T[TKey]> : T[TKey] extends AppRouter ? RecursiveProxyObj<T[TKey]> : never;
import { AreAllPropertiesOptional, Merge, OptionalIfAllOptional, Prettify, Without, ZodInferOrType, ZodInputOrType } from './type-utils';
type RecursiveProxyObj<T extends AppRouter, TClientArgs extends ClientArgs> = {
[TKey in keyof T]: T[TKey] extends AppRoute ? AppRouteFunction<T[TKey], TClientArgs> : T[TKey] extends AppRouter ? RecursiveProxyObj<T[TKey], TClientArgs> : never;
};

@@ -18,8 +18,18 @@ type AppRouteMutationType<T> = ZodInputOrType<T>;

type AppRouteBodyOrFormData<T extends AppRouteMutation> = T['contentType'] extends 'multipart/form-data' ? FormData | AppRouteMutationType<T['body']> : AppRouteMutationType<T['body']>;
interface DataReturnArgsBase<TRoute extends AppRoute> {
/**
* Extract any extra parameters from the client args
*/
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> = {
body: TRoute extends AppRouteMutation ? AppRouteBodyOrFormData<TRoute> : never;
params: PathParamsFromUrl<TRoute>;
query: 'query' extends keyof TRoute ? AppRouteMutationType<TRoute['query']> : never;
}
type DataReturnArgs<TRoute extends AppRoute> = OptionalIfAllOptional<DataReturnArgsBase<TRoute>>;
/**
* Additional headers to send with the request, merged over baseHeaders,
*
* Unset a header by setting it to undefined
*/
headers?: Record<string, string>;
} & ExtractExtraParametersFromClientArgs<TClientArgs>;
type DataReturnArgs<TRoute extends AppRoute, TClientArgs extends ClientArgs> = OptionalIfAllOptional<DataReturnArgsBase<TRoute, TClientArgs>>;
export type ApiRouteResponse<T> = {

@@ -37,3 +47,3 @@ [K in keyof T]: {

*/
export type AppRouteFunction<TRoute extends AppRoute> = AreAllPropertiesOptional<Without<DataReturnArgs<TRoute>, never>> extends true ? (args?: Without<DataReturnArgs<TRoute>, never>) => Promise<ApiRouteResponse<TRoute['responses']>> : (args: Without<DataReturnArgs<TRoute>, never>) => Promise<ApiRouteResponse<TRoute['responses']>>;
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 interface ClientArgs {

@@ -46,3 +56,3 @@ baseUrl: string;

}
type ApiFetcher = (args: {
export type ApiFetcherArgs = {
path: string;

@@ -53,18 +63,36 @@ method: string;

credentials?: RequestCredentials;
}) => Promise<{
};
export type ApiFetcher = (args: ApiFetcherArgs) => Promise<{
status: number;
body: unknown;
}>;
export declare const defaultApi: ApiFetcher;
export declare const fetchApi: (path: string, clientArgs: ClientArgs, route: AppRoute, body: unknown) => Promise<{
/**
* Default fetch api implementation:
*
* Can be used as a reference for implementing your own fetcher,
* or used in the "api" field of ClientArgs to allow you to hook
* into the request to run custom logic
*/
export declare const tsRestFetchApi: ApiFetcher;
export declare const fetchApi: ({ path, clientArgs, route, body, extraInputArgs, headers, }: {
path: string;
clientArgs: ClientArgs;
route: AppRoute;
body: unknown;
extraInputArgs: Record<string, unknown>;
headers: Record<string, string | undefined>;
}) => Promise<{
status: number;
body: unknown;
}>;
/**
* @hidden
*/
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>) => Promise<{
export declare const getRouteQuery: <TAppRoute extends AppRoute>(route: TAppRoute, clientArgs: ClientArgs) => (inputArgs?: DataReturnArgs<any, ClientArgs>) => Promise<{
status: number;
body: unknown;
}>;
export type InitClientReturn<T extends AppRouter> = RecursiveProxyObj<T>;
export declare const initClient: <T extends AppRouter>(router: T, args: ClientArgs) => RecursiveProxyObj<T>;
export type InitClientReturn<T extends AppRouter, TClientArgs extends ClientArgs> = RecursiveProxyObj<T, TClientArgs>;
export declare const initClient: <T extends AppRouter, TClientArgs extends ClientArgs>(router: T, args: TClientArgs) => RecursiveProxyObj<T, TClientArgs>;
export {};

@@ -33,2 +33,5 @@ import { z } from 'zod';

}[keyof T]>;
export type Prettify<T> = {
[K in keyof T]: T[K];
} & {};
export {};

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with โšก๏ธ by Socket Inc