orpc-nuxt 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -173,15 +173,10 @@ const post = await orpc.blog.posts.get.call({ id: 1 })
173
173
 
174
174
  ### Declared errors
175
175
 
176
- Treat an expected rejection as an application outcome only when the procedure declares it with `.errors()`.
177
- Let every other error propagate to the application's error handler, including an `ORPCError` whose code was not declared by that procedure.
178
-
179
- Use `catchORPCError()` from the client entrypoint to handle selected declared errors while preserving their code and data types:
176
+ Use `.callCatching()` to call a procedure and handle errors it declares with `.errors()`, with their code and data types:
180
177
 
181
178
  ```ts
182
- import { catchORPCError } from "orpc-nuxt/client"
183
-
184
- const post = await catchORPCError(orpc.blog.posts.update.call(input), {
179
+ const post = await orpc.blog.posts.update.callCatching(input, {
185
180
  CONFLICT: (error) => {
186
181
  message.value = error.message
187
182
  conflictingField.value = error.data.field
@@ -195,16 +190,26 @@ Undeclared errors and declared codes without a handler are rethrown unchanged.
195
190
 
196
191
  When one declared error simply means there is no result, map it to `undefined` or `null` directly:
197
192
 
193
+ ```ts
194
+ const post = await orpc.blog.posts.get.callCatching({ id }, { NOT_FOUND: null })
195
+ // post is the procedure output or null.
196
+ ```
197
+
198
+ Pass call options such as `context` or `signal` as the third argument.
199
+ Pass `undefined` as input for procedures without input.
200
+
201
+ `.callCatching()` is built on `catchORPCError()`, which handles errors of a promise returned directly by any typed oRPC client call.
202
+ Import it from the client entrypoint when you do not call the procedure through this package's client:
203
+
198
204
  ```ts
199
205
  import { catchORPCError } from "orpc-nuxt/client"
200
206
 
201
- const post = await catchORPCError(orpc.blog.posts.get.call({ id }), {
202
- NOT_FOUND: null,
203
- })
204
- // post is the procedure output or null.
207
+ const post = await catchORPCError(client.blog.posts.get({ id }), { NOT_FOUND: null })
205
208
  ```
206
209
 
207
- The client also exposes oRPC's utilities:
210
+ ### oRPC utilities
211
+
212
+ The client also exposes oRPC's TanStack Query utilities:
208
213
 
209
214
  - `.key()` builds a cache key prefix for a procedure or router branch.
210
215
  - `.queryKey()` builds a query key for a specific input.
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^3.14.1592 || ^4.0.1"
6
6
  },
7
- "version": "0.6.0",
7
+ "version": "0.7.0",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.3",
10
10
  "unbuild": "unknown"
@@ -4,6 +4,7 @@ import { useORPCMutation } from "../vue-query/mutation.js";
4
4
  import { useORPCQuery } from "../vue-query/query.js";
5
5
  import { resolveQueryClient } from "../vue-query/query-client.js";
6
6
  import { decorateClient } from "./decorate.js";
7
+ import { catchDefinedErrors } from "./error.js";
7
8
  export function createORPCNuxtClient(client, options = {}) {
8
9
  const utils = createTanstackQueryUtils(client, { prefix: options.prefix });
9
10
  let queryClient = options.queryClient ?? resolveQueryClient();
@@ -18,6 +19,10 @@ export function createORPCNuxtClient(client, options = {}) {
18
19
  useMutation(mutationOptions) {
19
20
  return useORPCMutation(target, mutationOptions, getQueryClient());
20
21
  },
22
+ callCatching(input, handlers, callOptions) {
23
+ const utils2 = target;
24
+ return catchDefinedErrors(utils2.call(input, callOptions), handlers);
25
+ },
21
26
  invalidate() {
22
27
  const utils2 = target;
23
28
  return getQueryClient().invalidateQueries({ queryKey: utils2.key() });
@@ -4,17 +4,20 @@ type ErrorOf<TPromise extends Promise<unknown>> = TPromise extends {
4
4
  type: infer Error;
5
5
  };
6
6
  } ? Error : never;
7
- type DefinedError<TPromise extends Promise<unknown>> = Extract<ErrorOf<TPromise>, AnyORPCError>;
8
- type DefinedErrorCode<TPromise extends Promise<unknown>> = DefinedError<TPromise>["code"] & string;
7
+ type DefinedError<TError> = Extract<TError, AnyORPCError>;
8
+ /** Error codes declared by a procedure whose client error union is `TError`. */
9
+ export type DefinedErrorCode<TError> = DefinedError<TError>["code"] & string;
9
10
  type ErrorResultValue = string | number | boolean | bigint | symbol | null | undefined | readonly unknown[] | {
10
11
  readonly [key: string]: unknown;
11
12
  };
12
- type DefinedErrorHandlers<TPromise extends Promise<unknown>> = Partial<{
13
- [Code in DefinedErrorCode<TPromise>]: ((error: Extract<DefinedError<TPromise>, {
13
+ /** Handlers or result values keyed by the codes declared in the client error union `TError`. */
14
+ export type DefinedErrorHandlers<TError> = Partial<{
15
+ [Code in DefinedErrorCode<TError>]: ((error: Extract<DefinedError<TError>, {
14
16
  code: Code;
15
17
  }>) => unknown) | ErrorResultValue;
16
18
  }>;
17
- type HandledResult<Handlers> = {
19
+ /** The awaited result of any handler or value in `Handlers`. */
20
+ export type HandledResult<Handlers> = {
18
21
  [Code in keyof Handlers]: Handlers[Code] extends (...args: never[]) => infer Result ? Awaited<Result> : Awaited<Handlers[Code]>;
19
22
  }[keyof Handlers];
20
23
  /**
@@ -28,5 +31,13 @@ type HandledResult<Handlers> = {
28
31
  * @param handlers - Handlers keyed by declared error code.
29
32
  * @returns The procedure output or the result of the matching handler.
30
33
  */
31
- export declare function catchORPCError<TPromise extends Promise<unknown>, Handlers extends object & DefinedErrorHandlers<NoInfer<TPromise>>>(promise: TPromise, handlers: "__error" extends keyof TPromise ? Handlers & Record<Exclude<keyof Handlers, DefinedErrorCode<NoInfer<TPromise>>>, never> : never): Promise<Awaited<TPromise> | HandledResult<Handlers>>;
34
+ export declare function catchORPCError<TPromise extends Promise<unknown>, Handlers extends object & DefinedErrorHandlers<ErrorOf<NoInfer<TPromise>>>>(promise: TPromise, handlers: "__error" extends keyof TPromise ? Handlers & Record<Exclude<keyof Handlers, DefinedErrorCode<ErrorOf<NoInfer<TPromise>>>>, never> : never): Promise<Awaited<TPromise> | HandledResult<Handlers>>;
35
+ /**
36
+ * Untyped runtime of `catchORPCError()` for callers that enforce handler types themselves.
37
+ *
38
+ * @param promise - A procedure call result.
39
+ * @param handlers - Handlers or result values keyed by declared error code.
40
+ * @returns The procedure output or the result of the matching handler.
41
+ */
42
+ export declare function catchDefinedErrors(promise: Promise<unknown>, handlers: Record<string, unknown>): Promise<unknown>;
32
43
  export {};
@@ -1,5 +1,8 @@
1
1
  import { isDefinedError } from "@orpc/client";
2
2
  export function catchORPCError(promise, handlers) {
3
+ return catchDefinedErrors(promise, handlers);
4
+ }
5
+ export function catchDefinedErrors(promise, handlers) {
3
6
  return promise.catch((error) => {
4
7
  const orpcError = error;
5
8
  if (!isDefinedError(orpcError)) throw error;
@@ -1,7 +1,8 @@
1
- import type { AnyNestedClient, Client, ClientContext } from "@orpc/client";
1
+ import type { AnyNestedClient, Client, ClientContext, FriendlyClientOptions } from "@orpc/client";
2
2
  import type { RouterUtils } from "@orpc/tanstack-query";
3
3
  import type { QueryClient, SkipToken, UseMutationOptions, UseMutationReturnType, UseQueryOptions, UseQueryReturnType } from "@tanstack/vue-query";
4
4
  import type { ComputedRef, DeepReadonly, MaybeRefOrGetter, Ref, WritableComputedRef } from "vue";
5
+ import type { DefinedErrorCode, DefinedErrorHandlers, HandledResult } from "./client/error.js";
5
6
  /** Configure cache ownership and key namespacing when wrapping an application-owned client. */
6
7
  export interface ORPCNuxtClientOptions {
7
8
  /** Separate the cache keys of clients whose procedure paths overlap. */
@@ -11,7 +12,8 @@ export interface ORPCNuxtClientOptions {
11
12
  }
12
13
  /**
13
14
  * An oRPC client decorated with Vue composables and the official TanStack Query utilities.
14
- * Router branches retain their names; finite procedures gain query and mutation composables.
15
+ * Router branches retain their names; finite procedures gain query and mutation composables
16
+ * and `callCatching()`.
15
17
  * Procedures whose output includes an async iterable retain only the upstream utilities.
16
18
  */
17
19
  export type ORPCNuxtClient<T extends AnyNestedClient> = RouterUtils<T> & {
@@ -85,5 +87,10 @@ interface ProcedureHooks<C extends ClientContext, I, O, E> {
85
87
  }>>): AwaitableQuery<ORPCQueryResult<O, E>>;
86
88
  /** Create a mutation observer; call mutate or mutateAsync to execute the procedure. */
87
89
  useMutation<M = unknown>(...args: object extends C ? [options?: MaybeRefOrGetter<ORPCMutationOptions<C, I, O, E, M>>] : [options: MaybeRefOrGetter<ORPCMutationOptions<C, I, O, E, M>>]): UseMutationReturnType<O, E, I, M>;
90
+ /**
91
+ * Call the procedure and handle selected declared errors like `catchORPCError()`.
92
+ * Pass `undefined` as input for procedures without input.
93
+ */
94
+ callCatching<Handlers extends object & DefinedErrorHandlers<E>>(input: I, handlers: Handlers & Record<Exclude<keyof Handlers, DefinedErrorCode<E>>, never>, ...rest: object extends C ? [options?: FriendlyClientOptions<C>] : [options: FriendlyClientOptions<C>]): Promise<O | HandledResult<Handlers>>;
88
95
  }
89
96
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orpc-nuxt",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "oRPC integration for Nuxt with TanStack Vue Query composables.",
5
5
  "homepage": "https://github.com/IlyaSemenov/orpc-nuxt#readme",
6
6
  "bugs": "https://github.com/IlyaSemenov/orpc-nuxt/issues",