Skip to content

Releases: unnoq/orpc

v0.32.0

17 Jan 14:05
Compare
Choose a tag to compare

🚨 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

  • contract, server: Replace configGlobal fn with .config in builders  -  by @unnoq in #95 (4e274)
    View changes on GitHub

v0.31.0

16 Jan 13:29
Compare
Choose a tag to compare

🌟 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:
    • Strict .callable/.actionable cannot chainable after call  -  by @unnoq in #88 (f22c7)
    • Strict builders & allow use middleware between .input/output  -  by @unnoq in #93 (43c0c)
    View changes on GitHub

v0.30.0

14 Jan 13:35
Compare
Choose a tag to compare

🌟 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

  • server: Middleware can run both before/after validation step  -  by @unnoq in #83 (cba52)

   🚀 Features

    View changes on GitHub

v0.29.0

11 Jan 13:14
Compare
Choose a tag to compare

🚨 Breaking Changes Alert 🚨

  • procedure is now completely non-callable by default (use the new .callable or .actionable methods for that).
  • createProcedureClient and createRouterClient now accept two arguments instead of one as before.
  • ORPCHandler and ORPCLink now become RPCHandler and RPCLink

🚀 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

    View changes on GitHub

v0.28.0

10 Jan 13:01
Compare
Choose a tag to compare

🤯 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

  • End-to-end typesafe error handling, remove @orpc/react and @orpc/next  -  by @unnoq in #77 (9b3a0)
    View changes on GitHub

v0.27.0

06 Jan 12:43
Compare
Choose a tag to compare

🚨 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 404response or falling back to other routes.
  • Official Adapters for Next.js and Hono.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

  • server, openapi: Rewrite ORPCHandler, OpenAPIHandler  -  by @unnoq in #74 (911bd)

   🚀 Features

    View changes on GitHub

v0.26.0

04 Jan 13:12
Compare
Choose a tag to compare

🚨 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

  • server: Redesign middleware and handler parameters  -  by @unnoq in #72 (7e55b)
    View changes on GitHub

v0.25.0

03 Jan 13:06
Compare
Choose a tag to compare

🚀 New Features 🚀

  1. 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'
});
  1. successDescripton option, allow use customize the success description when generate OpenAPI specs
const ping = oc.route({ successDescripton: 'Indicate the system is OK' })

   🚨 Breaking Changes

  • contract: Spread merge route when redefine  -  by @unnoq (67ca7)

   🚀 Features

   🐞 Bug Fixes

    View changes on GitHub

v0.24.0

02 Jan 13:33
Compare
Choose a tag to compare

🚀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

  • openapi: Silence ignore dangerous error when generate openapi spec  -  by @unnoq (73eb9)
    View changes on GitHub

v0.23.0

01 Jan 14:41
Compare
Choose a tag to compare

🚀 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

  • zod: Zod to json schema not covert zod description  -  by @unnoq (1cee9)
    View changes on GitHub