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

@ts-rest/nest

Package Overview
Dependencies
Maintainers
1
Versions
126
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ts-rest/nest - npm Package Compare versions

Comparing version 3.28.0 to 3.30.0

15

CHANGELOG.md
# @ts-rest/nest
## 3.30.0
## 3.29.0
### Minor Changes
- 19aeb0a: - feat: Add option to disable request validation
- This is useful when a user wants to perform validation or handle validation errors themselves
### Patch Changes
- 5f7b236: - bump `@ts-rest/react-query` peer dependency `@tanstack/react-query` to `^4.0.0` (latest 4.33.0)
- bump `@ts-rest/react-query` peer dependency `zod` to `^3.21.0`
- upgrades NX to 16.7 for project root
## 3.28.0

@@ -4,0 +19,0 @@

89

index.js

@@ -13,2 +13,5 @@ 'use strict';

const ValidateResponsesSymbol = Symbol('ts-rest-validate-responses');
const ValidateRequestHeadersSymbol = Symbol('ts-rest-validate-request-headers');
const ValidateRequestQuerySymbol = Symbol('ts-rest-validate-request-query');
const ValidateRequestBodySymbol = Symbol('ts-rest-validate-request-body');

@@ -99,2 +102,3 @@ const JsonQuery = (jsonQuery = true) => {

const TsRest = (appRouteOrOptions, options = {}) => {
var _a, _b, _c;
const decorators = [];

@@ -110,2 +114,5 @@ const isMethodDecorator = 'path' in appRouteOrOptions;

}
else {
decorators.push(common.SetMetadata(ValidateRequestHeadersSymbol, (_a = optionsToUse.validateRequestHeaders) !== null && _a !== void 0 ? _a : true), common.SetMetadata(ValidateRequestQuerySymbol, (_b = optionsToUse.validateRequestQuery) !== null && _b !== void 0 ? _b : true), common.SetMetadata(ValidateRequestBodySymbol, (_c = optionsToUse.validateRequestBody) !== null && _c !== void 0 ? _c : true));
}
if (optionsToUse.jsonQuery !== undefined) {

@@ -117,2 +124,11 @@ decorators.push(JsonQuery(optionsToUse.jsonQuery));

}
if (optionsToUse.validateRequestBody !== undefined) {
decorators.push(common.SetMetadata(ValidateRequestBodySymbol, optionsToUse.validateRequestBody));
}
if (optionsToUse.validateRequestQuery !== undefined) {
decorators.push(common.SetMetadata(ValidateRequestQuerySymbol, optionsToUse.validateRequestQuery));
}
if (optionsToUse.validateRequestHeaders !== undefined) {
decorators.push(common.SetMetadata(ValidateRequestHeadersSymbol, optionsToUse.validateRequestHeaders));
}
return common.applyDecorators(...decorators);

@@ -151,6 +167,18 @@ };

}
const getRequestValidationValue = (key) => {
const handlerValue = Reflect.getMetadata(key, ctx.getHandler());
const classValue = Reflect.getMetadata(key, ctx.getClass());
if (handlerValue === undefined && classValue === undefined) {
return true;
}
if (handlerValue !== undefined) {
return handlerValue;
}
return classValue;
};
const headersResult = core.checkZodSchema(req.headers, appRoute.headers, {
passThroughExtraKeys: true,
});
if (!headersResult.success) {
const headerValidation = getRequestValidationValue(ValidateRequestHeadersSymbol);
if (!headersResult.success && headerValidation) {
throw new common.BadRequestException(core.zodErrorResponse(headersResult.error));

@@ -163,14 +191,18 @@ }

const queryResult = core.checkZodSchema(query, appRoute.query);
if (!queryResult.success) {
const queryValidation = getRequestValidationValue(ValidateRequestQuerySymbol);
if (!queryResult.success && queryValidation) {
throw new common.BadRequestException(core.zodErrorResponse(queryResult.error));
}
const bodyResult = core.checkZodSchema(req.body, appRoute.method === 'GET' ? null : appRoute.body);
if (!bodyResult.success) {
const bodyValidation = getRequestValidationValue(ValidateRequestBodySymbol);
if (!bodyResult.success && bodyValidation) {
throw new common.BadRequestException(core.zodErrorResponse(bodyResult.error));
}
return {
query: queryResult.data,
query: queryResult.success ? queryResult.data : req.query,
params: pathParamsResult.data,
body: bodyResult.data,
headers: headersResult.data,
body: bodyResult.success ? bodyResult.data : req.body,
headers: headersResult.success
? headersResult.data
: req.headers,
};

@@ -202,2 +234,3 @@ });

const TsRestHandler = (appRouterOrRoute, options = {}) => {
var _a, _b, _c;
const decorators = [];

@@ -210,2 +243,3 @@ if (options.jsonQuery !== undefined) {

}
decorators.push(common.SetMetadata(ValidateRequestHeadersSymbol, (_a = options.validateRequestHeaders) !== null && _a !== void 0 ? _a : true), common.SetMetadata(ValidateRequestQuerySymbol, (_b = options.validateRequestQuery) !== null && _b !== void 0 ? _b : true), common.SetMetadata(ValidateRequestBodySymbol, (_c = options.validateRequestBody) !== null && _c !== void 0 ? _c : true));
const isMultiHandler = !core.isAppRoute(appRouterOrRoute);

@@ -310,3 +344,6 @@ if (isMultiHandler) {

const isJsonQuery = !!((_a = Reflect.getMetadata(JsonQuerySymbol, ctx.getHandler())) !== null && _a !== void 0 ? _a : Reflect.getMetadata(JsonQuerySymbol, ctx.getClass()));
const isValidationEnabled = Boolean(this.reflector.getAllAndOverride(ValidateResponsesSymbol, [ctx.getHandler(), ctx.getClass()]));
const getMetadataValue = (key) => Boolean(this.reflector.getAllAndOverride(key, [
ctx.getHandler(),
ctx.getClass(),
]));
const paramsResult = core.checkZodSchema(req.params, appRoute.pathParams, {

@@ -323,7 +360,11 @@ passThroughExtraKeys: true,

const bodyResult = core.checkZodSchema(req.body, 'body' in appRoute ? appRoute.body : null);
const isValidationEnabled = getMetadataValue(ValidateResponsesSymbol);
const isHeadersInvalid = !headersResult.success && getMetadataValue(ValidateRequestHeadersSymbol);
const isQueryInvalid = !queryResult.success && getMetadataValue(ValidateRequestQuerySymbol);
const isBodyInvalid = !bodyResult.success && getMetadataValue(ValidateRequestBodySymbol);
if (!paramsResult.success ||
!headersResult.success ||
!queryResult.success ||
!bodyResult.success) {
throw new RequestValidationError(!paramsResult.success ? paramsResult.error : null, !headersResult.success ? headersResult.error : null, !queryResult.success ? queryResult.error : null, !bodyResult.success ? bodyResult.error : null);
isHeadersInvalid ||
isQueryInvalid ||
isBodyInvalid) {
throw new RequestValidationError(!paramsResult.success ? paramsResult.error : null, isHeadersInvalid ? headersResult.error : null, isQueryInvalid ? queryResult.error : null, isBodyInvalid ? bodyResult.error : null);
}

@@ -333,18 +374,9 @@ return next.handle().pipe(rxjs.map(async (impl) => {

try {
if (routeKey) {
result = await impl[routeKey]({
query: queryResult.data,
params: paramsResult.data,
body: bodyResult.data,
headers: headersResult.data,
});
}
else {
result = await impl({
query: queryResult.data,
params: paramsResult.data,
body: bodyResult.data,
headers: headersResult.data,
});
}
const res = {
params: paramsResult.data,
query: queryResult.success ? queryResult.data : req.query,
body: bodyResult.success ? bodyResult.data : req.body,
headers: headersResult.success ? headersResult.data : req.headers,
};
result = routeKey ? await impl[routeKey](res) : await impl(res);
}

@@ -415,2 +447,5 @@ catch (e) {

exports.TsRestRequest = TsRestRequest;
exports.ValidateRequestBodySymbol = ValidateRequestBodySymbol;
exports.ValidateRequestHeadersSymbol = ValidateRequestHeadersSymbol;
exports.ValidateRequestQuerySymbol = ValidateRequestQuerySymbol;
exports.ValidateResponsesSymbol = ValidateResponsesSymbol;

@@ -417,0 +452,0 @@ exports.doesUrlMatchContractPath = doesUrlMatchContractPath;

{
"name": "@ts-rest/nest",
"version": "3.28.0",
"version": "3.30.0",
"description": "Nest server integration for @ts-rest",

@@ -27,3 +27,3 @@ "license": "MIT",

"zod": "^3.21.0",
"@ts-rest/core": "3.28.0"
"@ts-rest/core": "3.30.0"
},

@@ -40,6 +40,2 @@ "peerDependenciesMeta": {

},
"typedoc": {
"entryPoint": "./src/index.ts",
"tsconfig": "./tsconfig.lib.json"
},
"module": "./index.mjs",

@@ -46,0 +42,0 @@ "main": "./index.js",

@@ -7,13 +7,26 @@ # ts-rest

<p align="center">RPC-like client and server helpers for a magical end to end typed experience</p>
<p align="center">Incrementally adoptable RPC-like client and server helpers for a magical end to end typed experience ๐Ÿช„</p>
<p align="center">
<a href="https://www.npmjs.com/package/@ts-rest/core"><img src="https://img.shields.io/npm/v/@ts-rest/core.svg" alt="langue typescript"/></a>
<img alt="Github Workflow Status" src="https://img.shields.io/github/actions/workflow/status/ts-rest/ts-rest/release.yml?branch=main"/>
<a href="https://www.npmjs.com/package/@ts-rest/core"><img alt="npm" src="https://img.shields.io/npm/dw/@ts-rest/core"/></a>
<a href="https://github.com/ts-rest/ts-rest/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/github/license/ts-rest/ts-rest"/></a>
<img alt="Bundle Size" src="https://img.shields.io/bundlephobia/minzip/@ts-rest/core?label=%40ts-rest%2Fcore"/>
<a href="https://discord.com/invite/2Megk85k5a"><img alt="Discord" src="https://img.shields.io/discord/1055855205960392724"/></a>
<a href="https://github.com/ts-rest/ts-rest">
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/ts-rest/ts-rest"/>
</a>
<a href="https://www.npmjs.com/package/@ts-rest/core">
<img src="https://img.shields.io/npm/dm/%40ts-rest/core"/>
</a>
<a href="https://github.com/ts-rest/ts-rest/blob/main/LICENSE">
<img alt="License" src="https://img.shields.io/github/license/ts-rest/ts-rest"/>
</a>
<a href="https://bundlephobia.com/package/@ts-rest/core">
<img alt="Bundle Size" src="https://img.shields.io/bundlephobia/minzip/@ts-rest/core?label=%40ts-rest%2Fcore"/>
</a>
</p>
<div align="center">
<div>Join us on Discord for help, feedback, and discussions!</div><br></br>
<a href="https://discord.gg/2Megk85k5a">
<img src="https://discordapp.com/api/guilds/1055855205960392724/widget.png?style=banner2" alt="Discord Shield"/>
</a>
</div>
# Introduction

@@ -25,10 +38,13 @@

- End to end type safety ๐Ÿ›Ÿ
- RPC-like client side interface ๐Ÿ“ก
- [Tiny bundle size ๐ŸŒŸ](https://bundlephobia.com/package/@ts-rest/core) (1kb!)
- Well-tested and production ready โœ…
- End-to-end type safety ๐Ÿ›Ÿ
- RPC-like client side API โšก๏ธ
- Small Bundle Size ๐Ÿ“‰
- No Code Generation ๐Ÿƒโ€โ™€๏ธ
- Zod support for runtime type checks ๐Ÿ‘ฎโ€โ™€๏ธ
- Zod support for runtime validation ๐Ÿ”’
- Full optional OpenAPI integration ๐Ÿ“
<div align="center">
<h3>๐Ÿ‘‰ Start reading the official <a href="https://ts-rest.com/docs/quickstart?utm_source=github&utm_medium=documentation&utm_campaign=readme">Quickstart Guide</a> ๐Ÿ‘ˆ</h3>
</div>
### Super Simple Example

@@ -57,7 +73,7 @@

Fulfil the contract on your server, with a type-safe router:
Fulfill the contract on your server, with a type-safe router:
```typescript
const router = s.router(contract, {
getPost: async ({ params: { id } }) => {
getPosts: async ({ params: { id } }) => {
return {

@@ -83,27 +99,11 @@ status: 200,

Install the core package
```bash
yarn add @ts-rest/core
# Optional react-query integration
yarn add @ts-rest/react-query
# Pick your backend
yarn add @ts-rest/nest @ts-rest/express
# For automatic server OpenAPI gen
yarn add @ts-rest/open-api
```
Create a contract, implement it on your server then consume it in your client. Incrementally adopt, trial it with your team, then get shipping faster.
<div align="center">
<h3>๐Ÿ‘‰ Read more on the official <a href="https://ts-rest.com/docs/quickstart?utm_source=github&utm_medium=documentation&utm_campaign=readme">Quickstart Guide</a> ๐Ÿ‘ˆ</h3>
<h3>๐Ÿ‘‰ Start reading the official <a href="https://ts-rest.com/docs/quickstart?utm_source=github&utm_medium=documentation&utm_campaign=readme">Quickstart Guide</a> ๐Ÿ‘ˆ</h3>
</div>
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=ts-rest/ts-rest&type=Timeline)](https://star-history.com/#ts-rest/ts-rest&Timeline)
## Contributors โœจ
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
MASSIVE Thanks to all of these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)), who have helped make ts-rest possible:

@@ -129,2 +129,5 @@ <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->

<td align="center" valign="top" width="14.28%"><a href="https://nad.dev"><img src="https://avatars.githubusercontent.com/u/6670753?v=4?s=100" width="100px;" alt="Neil A. Dobson"/><br /><sub><b>Neil A. Dobson</b></sub></a><br /><a href="https://github.com/ts-rest/ts-rest/commits?author=neildobson-au" title="Code">๐Ÿ’ป</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dohaicuong"><img src="https://avatars.githubusercontent.com/u/20808725?v=4?s=100" width="100px;" alt="Eric Do"/><br /><sub><b>Eric Do</b></sub></a><br /><a href="https://github.com/ts-rest/ts-rest/commits?author=dohaicuong" title="Documentation">๐Ÿ“–</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fruchtzwerg"><img src="https://avatars.githubusercontent.com/u/15377955?v=4?s=100" width="100px;" alt="Ben"/><br /><sub><b>Ben</b></sub></a><br /><a href="https://github.com/ts-rest/ts-rest/commits?author=fruchtzwerg" title="Code">๐Ÿ’ป</a> <a href="https://github.com/ts-rest/ts-rest/commits?author=fruchtzwerg" title="Documentation">๐Ÿ“–</a> <a href="https://github.com/ts-rest/ts-rest/commits?author=fruchtzwerg" title="Tests">โš ๏ธ</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://llllvvuu.dev"><img src="https://avatars.githubusercontent.com/u/5601392?v=4?s=100" width="100px;" alt="LW"/><br /><sub><b>LW</b></sub></a><br /><a href="https://github.com/ts-rest/ts-rest/commits?author=llllvvuu" title="Code">๐Ÿ’ป</a> <a href="https://github.com/ts-rest/ts-rest/issues?q=author%3Allllvvuu" title="Bug reports">๐Ÿ›</a></td>
</tr>

@@ -139,5 +142,24 @@ </tbody>

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
## Star History
<div style={{paddingTop: "25px"}}>
Since our first commit in 2022 we've been growing steadily. We're proud of our progress and we're excited about the future.
<div align="center">
<a href="https://star-history.com/#ts-rest/ts-rest&Timeline">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=ts-rest/ts-rest&type=Timeline&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=ts-rest/ts-rest&type=Timeline" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=ts-rest/ts-rest&type=Timeline" />
</picture>
</a>
</div>
<div align="center" >
<div>Join us on Discord for help, feedback, and discussions!</div><br></br>
<a href="https://discord.gg/2Megk85k5a">
<img src="https://discordapp.com/api/guilds/1055855205960392724/widget.png?style=banner2" alt="Discord Shield"/>
</a>
</div>
<div align="center">
<a

@@ -144,0 +166,0 @@ href="https://vercel.com/?utm_source=ts-rest&utm_campaign=oss"

@@ -0,0 +0,0 @@ export * from './lib/constants';

export declare const TsRestAppRouteMetadataKey: unique symbol;
export declare const JsonQuerySymbol: unique symbol;
export declare const ValidateResponsesSymbol: unique symbol;
export declare const ValidateRequestHeadersSymbol: unique symbol;
export declare const ValidateRequestQuerySymbol: unique symbol;
export declare const ValidateRequestBodySymbol: unique symbol;

@@ -0,0 +0,0 @@ import { JsonQuerySymbol } from './constants';

import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';
import { NestInterceptor, ExecutionContext, CallHandler, BadRequestException, InternalServerErrorException, HttpException } from '@nestjs/common';
import { AppRouter, AppRoute, ServerInferResponses } from '@ts-rest/core';
import { BadRequestException, CallHandler, ExecutionContext, HttpException, InternalServerErrorException, NestInterceptor } from '@nestjs/common';
import { AppRoute, AppRouter, ServerInferResponses } from '@ts-rest/core';
import { TsRestRequestShape } from './ts-rest-request.decorator';

@@ -6,0 +6,0 @@ import { z } from 'zod';

@@ -0,0 +0,0 @@ import { AppRoute, AppRouter, Without, ServerInferResponses } from '@ts-rest/core';

@@ -0,0 +0,0 @@ import { AppRoute, ServerInferRequest } from '@ts-rest/core';

@@ -5,2 +5,5 @@ import { AppRoute } from '@ts-rest/core';

validateResponses?: boolean;
validateRequestHeaders?: boolean;
validateRequestQuery?: boolean;
validateRequestBody?: boolean;
};

@@ -7,0 +10,0 @@ type TsRestType = {

@@ -0,0 +0,0 @@ import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';

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