Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/content/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ export default withMermaid(defineConfig({
collapsed: true,
items: [
{ text: 'OpenAPI Reference (Swagger)', link: '/docs/openapi/plugins/openapi-reference' },
{ text: 'Zod Smart Coercion', link: '/docs/openapi/plugins/zod-smart-coercion' },
{ text: 'Smart Coercion', link: '/docs/openapi/plugins/smart-coercion' },
{ text: 'Zod Smart Coercion (old)', link: '/docs/openapi/plugins/zod-smart-coercion' },
],
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ oRPC is an ESM-only library. Therefore, your NestJS application must be configur
```

2. **Node.js Environment**:

- **Node.js 22+**: Recommended, as it allows `require()` of ESM modules natively.
- **Older Node.js versions**: Alternatively, use a bundler to compile ESM modules (including `@orpc/nest`) to CommonJS.

Expand Down
155 changes: 155 additions & 0 deletions apps/content/docs/openapi/plugins/smart-coercion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
---
title: Smart Coercion Plugin
description: Automatically converts input values to match schema types without manually defining coercion logic.
---

# Smart Coercion Plugin

Automatically converts input values to match schema types without manually defining coercion logic.

::: warning
This plugin improves developer experience but impacts performance. For high-performance applications or complex schemas, manually defining coercion in your schema validation is more efficient.
:::

## Installation

::: code-group

```sh [npm]
npm install @orpc/json-schema@latest
```

```sh [yarn]
yarn add @orpc/json-schema@latest
```

```sh [pnpm]
pnpm add @orpc/json-schema@latest
```

```sh [bun]
bun add @orpc/json-schema@latest
```

```sh [deno]
deno install npm:@orpc/json-schema@latest
```

:::

## Setup

Configure the plugin with [JSON Schema Converters](/docs/openapi/openapi-specification#generating-specifications) for your validation libraries.

```ts
import { OpenAPIHandler } from '@orpc/openapi/fetch'
import {
experimental_SmartCoercionPlugin as SmartCoercionPlugin
} from '@orpc/json-schema'

const handler = new OpenAPIHandler(router, {
plugins: [
new SmartCoercionPlugin({
schemaConverters: [
new ZodToJsonSchemaConverter(),
// Add other schema converters as needed
],
})
]
})
```

## How It Works

The plugin converts values **safely** using these rules:

1. **Schema-guided:** Only converts when the schema says what type to use
2. **Safe only:** Only converts values that make sense (like `'123'` to `123`)
3. **Keep original:** If conversion is unsafe, keeps the original value
4. **Smart unions:** Picks the best conversion for union types
5. **Deep conversion:** Works inside nested objects and arrays

::: info
JavaScript native types such as BigInt, Date, RegExp, URL, Set, and Map are not natively supported by JSON Schema. To enable correct coercion, oRPC relies on the `x-native-type` metadata in your schema:

- `x-native-type: 'bigint'` for BigInt
- `x-native-type: 'date'` for Date
- `x-native-type: 'regexp'` for RegExp
- `x-native-type: 'url'` for URL
- `x-native-type: 'set'` for Set
- `x-native-type: 'map'` for Map

The built-in [JSON Schema Converters](/docs/openapi/openapi-specification#generating-specifications) handle these cases (except for some experimental converters). Since this approach is not part of the official JSON Schema specification, if you use a custom converter, you may need to add the appropriate `x-native-type` metadata to your schemas to ensure proper coercion.
:::

## Conversion Rules

### String → Boolean

Support specific string values (case-insensitive):

- `'true'`, `'on'` → `true`
- `'false'`, `'off'` → `false`

::: info
HTML `<input type="checkbox">` elements submit `'on'` or `'off'` as values, so this conversion is especially useful for handling checkbox input in forms.
:::

### String → Number

Support valid numeric strings:

- `'123'` → `123`
- `'3.14'` → `3.14`

### String/Number → BigInt

Support valid numeric strings or numbers:

- `'12345678901234567890'` → `12345678901234567890n`
- `12345678901234567890` → `12345678901234567890n`

### String → Date

Support ISO date/datetime strings:

- `'2023-10-01'` → `new Date('2023-10-01')`
- `'2020-01-01T06:15'` → `new Date('2020-01-01T06:15')`
- `'2020-01-01T06:15Z'` → `new Date('2020-01-01T06:15Z')`
- `'2020-01-01T06:15:00Z'` → `new Date('2020-01-01T06:15:00Z')`
- `'2020-01-01T06:15:00.123Z'` → `new Date('2020-01-01T06:15:00.123Z')`

### String → RegExp

Support valid regular expression strings:

- `'/^\\d+$/i'` → `new RegExp('^\\d+$', 'i')`
- `'/abc/'` → `new RegExp('abc')`

### String → URL

Support valid URL strings:

- `'https://example.com'` → `new URL('https://example.com')`

### Array → Set

Support arrays of **unique values**:

- `['apple', 'banana']` → `new Set(['apple', 'banana'])`

### Array → Object

Converts arrays to objects with numeric keys:

- `['apple', 'banana']` → `{ 0: 'apple', 1: 'banana' }`

::: info
This is particularly useful for [Bracket Notation](/docs/openapi/bracket-notation) when you need objects with numeric keys.
:::

### Array → Map

Support arrays of key-value pairs:

- `[['key1', 'value1'], ['key2', 'value2']]` → `new Map([['key1', 'value1'], ['key2', 'value2']])`
26 changes: 26 additions & 0 deletions packages/json-schema/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Hidden folders and files
.*
!.gitignore
!.*.example

# Common generated folders
logs/
node_modules/
out/
dist/
dist-ssr/
build/
coverage/
temp/

# Common generated files
*.log
*.log.*
*.tsbuildinfo
*.vitest-temp.json
vite.config.ts.timestamp-*
vitest.config.ts.timestamp-*

# Common manual ignore files
*.local
*.pem
76 changes: 76 additions & 0 deletions packages/json-schema/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<div align="center">
<image align="center" src="https://orpc.unnoq.com/logo.webp" width=280 alt="oRPC logo" />
Comment thread
dinwwwh marked this conversation as resolved.
</div>

<h1></h1>

<div align="center">
<a href="https://codecov.io/gh/unnoq/orpc">
<img alt="codecov" src="https://codecov.io/gh/unnoq/orpc/branch/main/graph/badge.svg">
</a>
<a href="https://www.npmjs.com/package/@orpc/json-schema">
<img alt="weekly downloads" src="https://img.shields.io/npm/dw/%40orpc%2Fjson-schema?logo=npm" />
</a>
<a href="https://github.com/unnoq/orpc/blob/main/LICENSE">
<img alt="MIT License" src="https://img.shields.io/github/license/unnoq/orpc?logo=open-source-initiative" />
</a>
<a href="https://discord.gg/TXEbwRBvQn">
<img alt="Discord" src="https://img.shields.io/discord/1308966753044398161?color=7389D8&label&logo=discord&logoColor=ffffff" />
</a>
</div>

<h3 align="center">Typesafe APIs Made Simple 🪄</h3>

**oRPC is a powerful combination of RPC and OpenAPI**, makes it easy to build APIs that are end-to-end type-safe and adhere to OpenAPI standards

---

## Highlights

- **🔗 End-to-End Type Safety**: Ensure type-safe inputs, outputs, and errors from client to server.
- **📘 First-Class OpenAPI**: Built-in support that fully adheres to the OpenAPI standard.
- **📝 Contract-First Development**: Optionally define your API contract before implementation.
- **⚙️ Framework Integrations**: Seamlessly integrate with TanStack Query (React, Vue, Solid, Svelte, Angular), Pinia Colada, and more.
- **🚀 Server Actions**: Fully compatible with React Server Actions on Next.js, TanStack Start, and other platforms.
- **🔠 Standard Schema Support**: Works out of the box with Zod, Valibot, ArkType, and other schema validators.
- **🗃️ Native Types**: Supports native types like Date, File, Blob, BigInt, URL, and more.
- **⏱️ Lazy Router**: Enhance cold start times with our lazy routing feature.
- **📡 SSE & Streaming**: Enjoy full type-safe support for SSE and streaming.
- **🌍 Multi-Runtime Support**: Fast and lightweight on Cloudflare, Deno, Bun, Node.js, and beyond.
- **🔌 Extendability**: Easily extend functionality with plugins, middleware, and interceptors.
- **🛡️ Reliability**: Well-tested, TypeScript-based, production-ready, and MIT licensed.

## Documentation

You can find the full documentation [here](https://orpc.unnoq.com).

## Packages

- [@orpc/contract](https://www.npmjs.com/package/@orpc/contract): Build your API contract.
- [@orpc/server](https://www.npmjs.com/package/@orpc/server): Build your API or implement API contract.
- [@orpc/client](https://www.npmjs.com/package/@orpc/client): Consume your API on the client with type-safety.
- [@orpc/openapi](https://www.npmjs.com/package/@orpc/openapi): Generate OpenAPI specs and handle OpenAPI requests.
- [@orpc/nest](https://www.npmjs.com/package/@orpc/nest): Deeply integrate oRPC with [NestJS](https://nestjs.com/).
- [@orpc/react](https://www.npmjs.com/package/@orpc/react): Utilities for integrating oRPC with React and React Server Actions.
- [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query): [TanStack Query](https://tanstack.com/query/latest) integration.
- [@orpc/vue-colada](https://www.npmjs.com/package/@orpc/vue-colada): Integration with [Pinia Colada](https://pinia-colada.esm.dev/).
- [@orpc/hey-api](https://www.npmjs.com/package/@orpc/hey-api): [Hey API](https://heyapi.dev/) integration.
- [@orpc/zod](https://www.npmjs.com/package/@orpc/zod): More schemas that [Zod](https://zod.dev/) doesn't support yet.
- [@orpc/valibot](https://www.npmjs.com/package/@orpc/valibot): OpenAPI spec generation from [Valibot](https://valibot.dev/).
- [@orpc/arktype](https://www.npmjs.com/package/@orpc/arktype): OpenAPI spec generation from [ArkType](https://arktype.io/).

## `@orpc/json-schema`

Json Schema related utilities for oRPC.

## Sponsors

<p align="center">
<a href="https://cdn.jsdelivr.net/gh/unnoq/unnoq/sponsors.svg">
<img src='https://cdn.jsdelivr.net/gh/unnoq/unnoq/sponsors.svg'/>
</a>
</p>

## License

Distributed under the MIT License. See [LICENSE](https://github.com/unnoq/orpc/blob/main/LICENSE) for more information.
46 changes: 46 additions & 0 deletions packages/json-schema/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "@orpc/json-schema",
"type": "module",
"version": "0.0.0",
"license": "MIT",
"homepage": "https://orpc.unnoq.com",
"repository": {
"type": "git",
"url": "git+https://github.com/unnoq/orpc.git",
"directory": "packages/json-schema"
},
"keywords": [
"unnoq",
"orpc"
],
"publishConfig": {
"exports": {
".": {
"types": "./dist/index.d.mts",
"import": "./dist/index.mjs",
"default": "./dist/index.mjs"
}
}
},
"exports": {
".": "./src/index.ts"
},
"files": [
"dist"
],
"scripts": {
"build": "unbuild",
"build:watch": "pnpm run build --watch",
"type:check": "tsc -b"
},
"dependencies": {
"@orpc/contract": "workspace:*",
"@orpc/openapi": "workspace:*",
"@orpc/server": "workspace:*",
"@orpc/shared": "workspace:*",
"json-schema-typed": "^8.0.1"
},
"devDependencies": {
"zod": "^3.25.74"
}
}
Loading