Releases: unnoq/orpc
Releases Β· unnoq/orpc
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' },
}));
π Features
π Bug Fixes
View changes on GitHub
v0.22.0
π Official Vue Pinia Colada integration now available π
import { useMutation, useQuery, useQueryCache } from '@pinia/colada'
import { orpc } from 'examples/vue-colada'
// Fetch data
const { data: gettingData } = useQuery(orpc.getting.queryOptions({ input: { name: 'unnoq' } }))
// Perform mutations
const { mutate: postMutate } = useMutation(orpc.post.create.mutationOptions())
// Invalidate queries
const queryCache = useQueryCache()
queryCache.invalidateQueries({ key: orpc.key() }) // Invalidate all queries
queryCache.invalidateQueries({ key: orpc.post.find.key({ input: { id: 'example' } }) }) // Specific queries
π Features
π Bug Fixes
View changes on GitHub
v0.21.0
π¨ Breaking Changes π¨
.func
is now.handler
to better convey its purpose and functionality.
π New Features π
1. successStatus
for Routes
You can now use the successStatus
option in .route
to override the default success status in OpenAPI specifications.
2. Enhanced ORPCLink with Custom Methods
ORPCLink now supports defining custom methods, making the Client context
more powerful and flexible.
type ClientContext = { cache?: RequestCache } | undefined;
// If `ClientContext` is not `undefinable`, it will enforce providing `context` in every call.
const orpcLink = new ORPCLink<ClientContext>({
url: 'http://localhost:3000/api',
// Optional headers for additional configurations
headers: () => ({
Authorization: 'Bearer token',
}),
fetch: (input, init, context) =>
globalThis.fetch(input, {
...init,
cache: context?.cache,
}),
method: (path, input, context) => {
// Automatically switch between GET and POST based on input and context
if (context?.cache) {
return 'GET';
}
// Example: Use GET for paths ending with 'get', 'find', 'list', or 'search'
if (['get', 'find', 'list', 'search'].includes(path.at(-1)!)) {
return 'GET';
}
return 'POST';
},
});
const client = createORPCClient<typeof router, ClientContext>(orpcLink);
// Example call with `context` specifying cache
client.getting({ name: 'unnoq' }, { context: { cache: 'force-cache' } });
These updates make it easier to build flexible and type-safe clients with more control over request handling.
π¨ Breaking Changes
- client: DynamicLink pass only context instead of full option - by @unnoq (2ba06)
- server: Rename .func() to .handler() - by @unteifu in #60 (5d3da)
π Features
- client:
- openapi: