orpc-nuxt 0.4.0 → 0.5.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 +50 -2
- package/dist/module.d.mts +2 -2
- package/dist/module.json +2 -2
- package/dist/runtime/client/error.d.ts +32 -0
- package/dist/runtime/client/error.js +10 -0
- package/dist/runtime/client.d.ts +1 -0
- package/dist/runtime/client.js +1 -0
- package/dist/runtime/testing.d.ts +20 -1
- package/dist/runtime/testing.js +4 -1
- package/dist/runtime/vue-query/mutation.d.ts +1 -1
- package/package.json +10 -13
package/README.md
CHANGED
|
@@ -171,6 +171,39 @@ Use `.call()` when you just need a procedure's response, without query state or
|
|
|
171
171
|
const post = await orpc.blog.posts.get.call({ id: 1 })
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
+
### Declared errors
|
|
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:
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import { catchORPCError } from "orpc-nuxt/client"
|
|
183
|
+
|
|
184
|
+
const post = await catchORPCError(orpc.blog.posts.update.call(input), {
|
|
185
|
+
CONFLICT: (error) => {
|
|
186
|
+
message.value = error.message
|
|
187
|
+
conflictingField.value = error.data.field
|
|
188
|
+
},
|
|
189
|
+
NOT_FOUND: () => navigateTo("/posts"),
|
|
190
|
+
})
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
The successful output, matching handler's awaited result, or matching non-function value becomes the call result.
|
|
194
|
+
Undeclared errors and declared codes without a handler are rethrown unchanged.
|
|
195
|
+
|
|
196
|
+
When one declared error simply means there is no result, map it to `undefined` or `null` directly:
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
import { catchORPCError } from "orpc-nuxt/client"
|
|
200
|
+
|
|
201
|
+
const post = await catchORPCError(orpc.blog.posts.get.call({ id }), {
|
|
202
|
+
NOT_FOUND: null,
|
|
203
|
+
})
|
|
204
|
+
// post is the procedure output or null.
|
|
205
|
+
```
|
|
206
|
+
|
|
174
207
|
The client also exposes oRPC's utilities:
|
|
175
208
|
|
|
176
209
|
- `.key()` builds a cache key prefix for a procedure or router branch.
|
|
@@ -524,6 +557,19 @@ test("renders the posts", async () => {
|
|
|
524
557
|
})
|
|
525
558
|
```
|
|
526
559
|
|
|
560
|
+
Use `createORPCError()` when a fake procedure must reproduce a declared rejection:
|
|
561
|
+
|
|
562
|
+
```ts
|
|
563
|
+
import { createORPCError } from "orpc-nuxt/testing"
|
|
564
|
+
|
|
565
|
+
procedures.blog.posts.update.handle(() => {
|
|
566
|
+
throw createORPCError("CONFLICT", "Already exists", { field: "title" })
|
|
567
|
+
})
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
Because this helper is standalone, it cannot infer which fake procedure will throw the error.
|
|
571
|
+
Its code and data are therefore not checked against that procedure's `.errors()` map.
|
|
572
|
+
|
|
527
573
|
### Outside Vue components
|
|
528
574
|
|
|
529
575
|
You can call `.useQuery()` and `.useMutation()` outside a component, for example in a script or in a test that never mounts one.
|
|
@@ -553,14 +599,16 @@ try {
|
|
|
553
599
|
|
|
554
600
|
## Development
|
|
555
601
|
|
|
556
|
-
Install dependencies
|
|
602
|
+
Install dependencies from the repository root with `bun install`.
|
|
603
|
+
Run `bun run build`, `bun run types`, and `bun run test` from this package's directory.
|
|
557
604
|
|
|
558
605
|
Run `bun run test:component` to check the documented component-test recipe in the fixture application; it uses the built package, so build first.
|
|
559
606
|
|
|
560
607
|
To try the package in a Nuxt app, build it and run `bunx nuxt dev tests/fixtures/nuxt`.
|
|
561
608
|
The example app uses the built package, so rebuild after changing its source.
|
|
562
609
|
|
|
563
|
-
|
|
610
|
+
From the repository root, install the shared test browser with `bunx playwright install chromium-headless-shell`.
|
|
611
|
+
Then run `bun run test:nuxt` from this package's directory to check the packed npm archive with the Nuxt version installed in the workspace.
|
|
564
612
|
It is checked with both module-managed and app-managed QueryClients, including types, SSR, and hydration in development and production.
|
|
565
613
|
|
|
566
614
|
To check other Nuxt versions by hand, pass them explicitly: `bun run test:nuxt 3.14.1592 4.0.1`.
|
package/dist/module.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as nuxt_schema from 'nuxt/schema';
|
|
2
2
|
import { StaticQueryClientConfig } from '../dist/runtime/nuxt/query-config.js';
|
|
3
3
|
export { StaticQueryClientConfig } from '../dist/runtime/nuxt/query-config.js';
|
|
4
4
|
export { ORPCRuntimeHooks as ModuleRuntimeHooks } from '../dist/runtime/nuxt/hooks.js';
|
|
@@ -8,7 +8,7 @@ interface ModuleOptions {
|
|
|
8
8
|
/** Set static query defaults, or use false when another plugin owns Vue Query and hydration. */
|
|
9
9
|
queryClient?: boolean | StaticQueryClientConfig;
|
|
10
10
|
}
|
|
11
|
-
declare const _default:
|
|
11
|
+
declare const _default: nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
12
12
|
|
|
13
13
|
export { _default as default };
|
|
14
14
|
export type { ModuleOptions };
|
package/dist/module.json
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type AnyORPCError } from "@orpc/client";
|
|
2
|
+
type ErrorOf<TPromise extends Promise<unknown>> = TPromise extends {
|
|
3
|
+
__error?: {
|
|
4
|
+
type: infer Error;
|
|
5
|
+
};
|
|
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;
|
|
9
|
+
type ErrorResultValue = string | number | boolean | bigint | symbol | null | undefined | readonly unknown[] | {
|
|
10
|
+
readonly [key: string]: unknown;
|
|
11
|
+
};
|
|
12
|
+
type DefinedErrorHandlers<TPromise extends Promise<unknown>> = Partial<{
|
|
13
|
+
[Code in DefinedErrorCode<TPromise>]: ((error: Extract<DefinedError<TPromise>, {
|
|
14
|
+
code: Code;
|
|
15
|
+
}>) => unknown) | ErrorResultValue;
|
|
16
|
+
}>;
|
|
17
|
+
type HandledResult<Handlers> = {
|
|
18
|
+
[Code in keyof Handlers]: Handlers[Code] extends (...args: never[]) => infer Result ? Awaited<Result> : Awaited<Handlers[Code]>;
|
|
19
|
+
}[keyof Handlers];
|
|
20
|
+
/**
|
|
21
|
+
* Handle selected errors declared by an oRPC procedure and rethrow every other rejection.
|
|
22
|
+
* The promise must come directly from a typed client call so its declared error union is preserved.
|
|
23
|
+
* Each handler receives the declared error branch narrowed to its own code.
|
|
24
|
+
* A non-function value is returned directly when its error code matches.
|
|
25
|
+
* Synchronous and asynchronous handler results are included in the returned promise type.
|
|
26
|
+
*
|
|
27
|
+
* @param promise - The `PromiseWithError` returned by an oRPC client procedure.
|
|
28
|
+
* @param handlers - Handlers keyed by declared error code.
|
|
29
|
+
* @returns The procedure output or the result of the matching handler.
|
|
30
|
+
*/
|
|
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>>;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { isDefinedError } from "@orpc/client";
|
|
2
|
+
export function catchORPCError(promise, handlers) {
|
|
3
|
+
return promise.catch((error) => {
|
|
4
|
+
const orpcError = error;
|
|
5
|
+
if (!isDefinedError(orpcError)) throw error;
|
|
6
|
+
if (!Object.hasOwn(handlers, orpcError.code)) throw error;
|
|
7
|
+
const handler = handlers[orpcError.code];
|
|
8
|
+
return typeof handler === "function" ? handler(orpcError) : handler;
|
|
9
|
+
});
|
|
10
|
+
}
|
package/dist/runtime/client.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { createORPCNuxtClient } from "./client/create.js";
|
|
2
|
+
export { catchORPCError } from "./client/error.js";
|
|
2
3
|
export type { AwaitableQuery, ORPCMutationOptions, ORPCNuxtClient, ORPCNuxtClientOptions, ORPCQueryOptions, ORPCQueryResult, ORPCSelectedQueryResult, } from "./types.js";
|
package/dist/runtime/client.js
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
|
-
import type { AnyNestedClient, Client } from "@orpc/client";
|
|
1
|
+
import type { AnyNestedClient, Client, ORPCError, ORPCErrorCode } from "@orpc/client";
|
|
2
2
|
import { QueryClient } from "@tanstack/vue-query";
|
|
3
3
|
import type { Mock } from "vitest";
|
|
4
4
|
import type { ORPCNuxtClient, ORPCNuxtClientOptions } from "./types.js";
|
|
5
5
|
type MaybePromise<T> = T | Promise<T>;
|
|
6
|
+
/**
|
|
7
|
+
* Create an oRPC error marked as declared for a fake client procedure.
|
|
8
|
+
* The standalone helper cannot infer a specific procedure, so its code is not limited to that procedure's `.errors()` map.
|
|
9
|
+
*
|
|
10
|
+
* @param code - The error code exposed to the client.
|
|
11
|
+
* @param message - The human-readable error message.
|
|
12
|
+
* @returns An error that `isDefinedError()` and `catchORPCError()` recognize as declared.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createORPCError<Code extends ORPCErrorCode>(code: Code, message: string): ORPCError<Code, undefined>;
|
|
15
|
+
/**
|
|
16
|
+
* Create an oRPC error with typed data marked as declared for a fake client procedure.
|
|
17
|
+
* The standalone helper cannot infer a specific procedure, so its code and data are not checked against that procedure's `.errors()` map.
|
|
18
|
+
*
|
|
19
|
+
* @param code - The error code exposed to the client.
|
|
20
|
+
* @param message - The human-readable error message.
|
|
21
|
+
* @param data - Error data exposed to the client.
|
|
22
|
+
* @returns An error that `isDefinedError()` and `catchORPCError()` recognize as declared.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createORPCError<Code extends ORPCErrorCode, Data>(code: Code, message: string, data: Data): ORPCError<Code, Data>;
|
|
6
25
|
/** A procedure implementation registered for a test client. */
|
|
7
26
|
export type TestORPCHandler<TProcedure> = TProcedure extends Client<infer _Context, infer Input, infer Output, infer _Error> ? (input: Input) => MaybePromise<Awaited<Output>> : never;
|
|
8
27
|
/** Registration methods for one procedure in a test client. */
|
package/dist/runtime/testing.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { createORPCClient } from "@orpc/client";
|
|
1
|
+
import { createORPCClient, createORPCErrorFromJson } from "@orpc/client";
|
|
2
2
|
import { QueryClient } from "@tanstack/vue-query";
|
|
3
3
|
import { vi } from "vitest";
|
|
4
4
|
import { createORPCNuxtClient } from "./client/create.js";
|
|
5
|
+
export function createORPCError(code, message, data) {
|
|
6
|
+
return createORPCErrorFromJson({ defined: true, code, message, data });
|
|
7
|
+
}
|
|
5
8
|
export function createTestORPCClient(options = {}) {
|
|
6
9
|
const registrations = /* @__PURE__ */ new Map();
|
|
7
10
|
const queryClient = options.queryClient ?? new QueryClient({
|
|
@@ -8,4 +8,4 @@ import { type QueryClient } from "@tanstack/vue-query";
|
|
|
8
8
|
* @param options - Mutation options, optionally wrapped in a ref or getter.
|
|
9
9
|
* @param queryClient - An explicit cache owner; otherwise Vue Query uses the injected client.
|
|
10
10
|
*/
|
|
11
|
-
export declare function useORPCMutation(target: object, options: unknown, queryClient?: QueryClient): import("@tanstack/vue-query").UseMutationReturnType<unknown, Error, unknown, unknown, Omit<import("@tanstack/query
|
|
11
|
+
export declare function useORPCMutation(target: object, options: unknown, queryClient?: QueryClient): import("@tanstack/vue-query").UseMutationReturnType<unknown, Error, unknown, unknown, Omit<import("@tanstack/vue-query").MutationObserverIdleResult<unknown, Error, unknown, unknown>, "mutate" | "reset"> | Omit<import("@tanstack/vue-query").MutationObserverLoadingResult<unknown, Error, unknown, unknown>, "mutate" | "reset"> | Omit<import("@tanstack/vue-query").MutationObserverErrorResult<unknown, Error, unknown, unknown>, "mutate" | "reset"> | Omit<import("@tanstack/vue-query").MutationObserverSuccessResult<unknown, Error, unknown, unknown>, "mutate" | "reset">>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "orpc-nuxt",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.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",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"author": "Ilya Semenov",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/IlyaSemenov/orpc-nuxt.git"
|
|
11
|
+
"url": "git+https://github.com/IlyaSemenov/orpc-nuxt.git",
|
|
12
|
+
"directory": "packages/orpc-nuxt"
|
|
12
13
|
},
|
|
13
14
|
"files": [
|
|
14
15
|
"README.md",
|
|
@@ -45,14 +46,11 @@
|
|
|
45
46
|
},
|
|
46
47
|
"scripts": {
|
|
47
48
|
"build": "nuxt-module-build build && publint",
|
|
48
|
-
"lint": "oxlint --fix && oxfmt",
|
|
49
|
-
"lint:check": "oxlint && oxfmt --check",
|
|
50
|
-
"prepare": "lefthook install",
|
|
51
|
-
"prepublishOnly": "bun run build",
|
|
52
49
|
"test": "bun test src tests/runtime",
|
|
53
50
|
"test:component": "vitest run --root tests/fixtures/nuxt",
|
|
54
51
|
"test:nuxt": "bun tests/nuxt/run.ts",
|
|
55
|
-
"types": "tsc --noEmit && tsc --noEmit -p tests/tsconfig.json && nuxt typecheck tests/fixtures/nuxt"
|
|
52
|
+
"types": "tsc --noEmit && tsc --noEmit -p tests/tsconfig.json && nuxt typecheck tests/fixtures/nuxt",
|
|
53
|
+
"prepublishOnly": "bun run build"
|
|
56
54
|
},
|
|
57
55
|
"dependencies": {
|
|
58
56
|
"@nuxt/kit": "^3.14.1592 || ^4.0.1",
|
|
@@ -60,23 +58,23 @@
|
|
|
60
58
|
"es-toolkit": "^1.52.0"
|
|
61
59
|
},
|
|
62
60
|
"devDependencies": {
|
|
63
|
-
"@changesets/cli": "^2.31.1",
|
|
64
61
|
"@nuxt/cli": "^3.37.0",
|
|
65
62
|
"@nuxt/module-builder": "^1.0.3",
|
|
66
63
|
"@nuxt/test-utils": "^4.3.2",
|
|
64
|
+
"@orpc/client": "^2.0.0-beta.35",
|
|
67
65
|
"@orpc/server": "2.0.0-beta.35",
|
|
68
|
-
"@
|
|
66
|
+
"@orpc/tanstack-query": "^2.0.0-beta.35",
|
|
67
|
+
"@tanstack/vue-query": "^5.102.8",
|
|
69
68
|
"@tsconfig/bun": "^1.0.10",
|
|
70
69
|
"@types/bun": "^1.3.14",
|
|
71
70
|
"@vue/server-renderer": "^3.5.0",
|
|
72
71
|
"@vue/test-utils": "^2.5.0",
|
|
73
72
|
"happy-dom": "^20.14.3",
|
|
74
73
|
"nuxt": "^4.5.2",
|
|
75
|
-
"oxfmt": "^0.67.0",
|
|
76
|
-
"oxlint": "^1.82.0",
|
|
77
74
|
"publint": "^0.3.22",
|
|
78
75
|
"typescript": "^5.9.3",
|
|
79
76
|
"vitest": "^5.0.0",
|
|
77
|
+
"vue": "^3.5.0",
|
|
80
78
|
"vue-tsc": "^3.3.11",
|
|
81
79
|
"zod": "^4.3.6"
|
|
82
80
|
},
|
|
@@ -92,6 +90,5 @@
|
|
|
92
90
|
"vitest": {
|
|
93
91
|
"optional": true
|
|
94
92
|
}
|
|
95
|
-
}
|
|
96
|
-
"packageManager": "bun@1.3.14"
|
|
93
|
+
}
|
|
97
94
|
}
|