Releases: unnoq/orpc
Releases · unnoq/orpc
v0.32.0
🚨 configGlobal
function replaced with .config
method in builders
The configGlobal
function has been deprecated and replaced with the .config
method for configuring default settings in builders. You can now customize the configuration more easily.
const pub = os
.context<{user?: {id: string}}>()
.config({ // Optional configuration to override defaults
initialRoute: {
method: 'DELETE', // Set the default HTTP method to DELETE
inputStructure: 'detailed', // Set the default input structure to 'detailed'
outputStructure: 'detailed' // Set the default output structure to 'detailed'
}
})
🚀 Features
View changes on GitHub
v0.31.0
🌟 1. Improved Chaining Flow
The chaining flow has been enhanced to reduce confusion and enable more flexible middleware usage.
- You can now insert middleware between
.input
and.output
for more granular control. - TypeScript will now catch invalid chaining patterns, such as calling
.middleware
after.use
, or chaining.input
after another.input
. This ensures developers are guided toward the correct sequence at compile time.
🚀 2. Custom Schemas with type
The type
utility allows you to create custom schemas:
export const getting = oc.input(type<{ id: string }>());
This simplifies validation and reduces bundle size, especially in scenarios where heavy validation logic is unnecessary.
🚀 Features
- contract:
- server:
View changes on GitHub
v0.30.0
🌟 Improvement 🌟
- Implement
.errors
in every builder, allowing you to define error handling at a global or granular level for enhanced reusability and flexibility. - Middleware use before .input/.output will be execute before/after validation step
const pub = os.errors({
UNAUTHORIZED: {},
}).use(({ errors }) => {
throw errors.UNAUTHORIZED()
})
const getting = pub
.input(z.object({ id: z.string() }))
.errors({
NOT_FOUND: {
message: 'User not found',
},
})
.handler(({ errors }) => {
throw errors.NOT_FOUND()
throw errors.UNAUTHORIZED()
// ...
})
🚨 Breaking Changes
🚀 Features
View changes on GitHub
v0.29.0
🚨 Breaking Changes Alert 🚨
procedure
is now completely non-callable by default (use the new.callable
or.actionable
methods for that).createProcedureClient
andcreateRouterClient
now accept two arguments instead of one as before.ORPCHandler
andORPCLink
now becomeRPCHandler
andRPCLink
🚀 New Features 🚀
- New
.callable
method to make a procedure callable like a regular function. - New
.actionable
method, similar to.callable()
, but type-compatible with server actions (yes, server actions work again). - New
call()
helper function to directly call any procedure without creating a client.
'use server'
import { os } from '@orpc/server'
import { z } from 'zod'
export const getting = os
.input(z.object({
name: z.string(),
}))
.output(z.string())
.handler(async ({ input }) => {
return `Hello ${input.name}`
})
.actionable()
// from client just call it as a function
const onClick = async () => {
const result = await getting({ name: 'Unnoq' })
alert(result)
}
🚨 Breaking Changes
- server: Redesign callable ability - by @unnoq in #78 (23aa4)
- server, client: Rename ORPCHandler/Link -> RPCHandler/Link - by @unnoq in #79 (c6c65)
View changes on GitHub
v0.28.0
🤯 End-to-End Typesafe Error Handling 🤯
const createPost = os
.errors({
CONFLICT: {
data: z.object({
why: z.string(),
}),
},
})
.handler(({ errors }) => {
throw errors.CONFLICT({ data: { why: 'some reason' } })
})
const [data, error] = await safe(createPost({ title: 'title' }))
if (error && isDefinedError(error)) {
const data = error.data // { why: 'some reason' } full typed data
}
const mutation = useMutation(orpc.createPost.mutationOptions({
onError(error) {
if (isDefinedError(error)) {
const data = error.data // { why: 'some reason' } full typed data
}
},
}))
- Removed
@orpc/react
since it was too complicated to maintain, while@orpc/react-query
is simpler and easier to maintain while achieve the same functionality. - Temporarily removed
@orpc/next
due to unexpected behavior from Next.js. You can follow progress here. I will bring this package back in a future oRPC version.
🚨 Breaking Changes
View changes on GitHub
v0.27.0
🚨 Breaking Changes Alert 🚨
- The
CompositeHandler
has been removed. Instead, we recommend using separate base paths for each handler. - Handlers will no longer automatically handle cases where no procedure matches. You are now responsible for returning a
404
response or falling back to other routes. - Official Adapters for
Next.js
andHono.js
if (url.pathname.startsWith('/api')) {
const { matched, response } = await openapiHandler.handle(request, {
prefix: '/api'
})
if (matched) {
return response
}
}
if (url.pathname.startsWith('/rpc')) {
const { matched, response } = await orpcHandler.handle(request, {
prefix: '/rpc'
})
if (matched) {
return response
}
}
return new Response('Not Found', { status: 404 })
🚨 Breaking Changes
🚀 Features
View changes on GitHub
v0.26.0
🚨 Breaking Changes
Middleware, and handler parameters has been redesigned.
os.handler((input, context, meta) => { }) // 🛑 old
os.handler(({ context, input }) => { }) // ✅ new
os.middleware((input, context, meta) => meta.next({})) // 🛑 old
os.middleware(({ context, next }, input) => next({})) // ✅ new
os.use((input, context, meta) => meta.next({})) // 🛑 old
os.use(({ context, next }, input) => next({})) // ✅ new
🚨 Breaking Changes
View changes on GitHub
v0.25.0
🚀 New Features 🚀
configGlobal
used to change some default oRPC behavior
import { configGlobal } from '@orpc/contract'; // or '@orpc/server'
configGlobal({
defaultMethod: 'GET', // Default HTTP method for requests
defaultSuccessStatus: 200, // Default HTTP status for successful responses
defaultInputStructure: 'compact', // Input payload structure: 'compact' or 'expanded'
defaultOutputStructure: 'compact', // Output payload structure: 'compact' or 'expanded'
});
successDescripton
option, allow use customize the success description when generate OpenAPI specs
const ping = oc.route({ successDescripton: 'Indicate the system is OK' })
🚨 Breaking Changes
🚀 Features
🐞 Bug Fixes
- zod: Nested descriptions not work when generate JSON Schema - by @gthomas08 in #68 (e7b4f)
View changes on GitHub
v0.24.0
🚀Official Node.js Adapter 🎉
import { createServer } from 'node:http'
import { OpenAPIServerlessHandler } from '@orpc/openapi/node'
import { CompositeHandler, ORPCHandler } from '@orpc/server/node'
const openapiHandler = new OpenAPIServerlessHandler(router, {
schemaCoercers: [
new ZodCoercer(),
],
})
const server = createServer((req, res) => {
if (req.url?.startsWith('/api')) {
return openapiHandler.handle(req, res, {
prefix: '/api',
context: {},
})
}
res.statusCode = 404
res.end('Not found')
})
🚀 Features
🐞 Bug Fixes
View changes on GitHub
v0.23.0
🚀 New Feature: Input/Output Structure 🎉
Simplify or customize how your API handles data with Input/Output Structure!
🌟 Highlights
-
inputStructure
:compact
: Merges params + query/body.detailed
: Keeps params, query, headers, and body separate.
-
outputStructure
:compact
: Returns only the body.detailed
: Separates headers and body.
Example
os.route({
inputStructure: 'detailed',
outputStructure: 'detailed',
})
.input(z.object({
params: z.object({ id: z.string() }),
query: z.object({ search: z.string() }),
body: z.object({ name: z.string() }).optional(),
}))
.handler((input) => ({
body: { message: 'Hello' },
headers: { 'x-header': 'value' },
}));