orpc-nuxt 0.3.1 → 0.4.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
@@ -289,9 +289,42 @@ Relative URLs resolve against the current request URL during SSR.
289
289
  Only headers listed in `forwardHeaders` are forwarded from the incoming SSR request.
290
290
  `credentials: "include"` allows browser cookies on cross-origin requests.
291
291
 
292
+ ### Custom link
293
+
294
+ Return a custom `link` when the server needs a request-scoped transport while the browser should keep a regular HTTP transport:
295
+
296
+ ```ts
297
+ // app/plugins/orpc.ts
298
+ import { RPCLink } from "@orpc/client/fetch"
299
+ import type { RouterClient } from "@orpc/server"
300
+ import { getRequestURL } from "h3"
301
+ import { defineNuxtPlugin } from "orpc-nuxt/plugin"
302
+ import type { router } from "~~/server/rpc/router"
303
+
304
+ export default defineNuxtPlugin<RouterClient<typeof router>>(() => ({
305
+ link: ({ event }) => {
306
+ if (!event) return new RPCLink({ url: "/api/rpc" })
307
+
308
+ const requestFetch = event.context.nuxtMultiApp.createFetch("web")
309
+ const endpoint = new URL("/api/rpc", getRequestURL(event))
310
+
311
+ return new RPCLink({
312
+ origin: endpoint.origin,
313
+ url: endpoint.pathname as `/${string}`,
314
+ fetch: requestFetch,
315
+ })
316
+ },
317
+ }))
318
+ ```
319
+
320
+ The link factory receives `{ nuxtApp, event }`, where `event` is the current H3 event during SSR and `undefined` in the browser.
321
+ It runs once per Nuxt application, so every SSR request gets its own link.
322
+ The plugin setup callback has the same lifecycle: once per SSR request and once when the browser app starts.
323
+ `orpc-nuxt` still creates the typed client, decorates it with Vue Query composables, and provides `$orpc`.
324
+
292
325
  ### Manual client setup
293
326
 
294
- Use `createORPCNuxtClient` when you need a custom transport or want SSR to call the router directly.
327
+ Use `createORPCNuxtClient` when you want SSR to call the router directly or need to own the complete client setup.
295
328
  Instead of the shared HTTP plugin above, add a browser plugin and a server plugin.
296
329
 
297
330
  Keep `orpc-nuxt` in `modules`: manual setup replaces that plugin, not the module that installs the QueryClient and the composables.
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.3.1",
7
+ "version": "0.4.0",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.3",
10
10
  "unbuild": "3.6.1"
@@ -1,8 +1,23 @@
1
- import { type AnyNestedClient } from "@orpc/client";
1
+ import { type AnyNestedClient, type ClientLink, type InferClientContext } from "@orpc/client";
2
2
  import { type NuxtApp, type Plugin } from "nuxt/app";
3
3
  import type { ORPCNuxtClient, ORPCNuxtClientOptions } from "../types.js";
4
- /** Configure the HTTP transport and cache used by a Nuxt app's injected oRPC client. */
5
- export interface OrpcPluginOptions extends ORPCNuxtClientOptions {
4
+ /** Nuxt state available while creating one app's custom oRPC link. */
5
+ export interface OrpcLinkContext {
6
+ /** The Nuxt application that will own the client. */
7
+ nuxtApp: NuxtApp;
8
+ /** The current H3 request event during SSR, or undefined in the browser. */
9
+ event: NonNullable<NuxtApp["ssrContext"]>["event"] | undefined;
10
+ }
11
+ /** Configure the transport and cache used by a Nuxt app's injected oRPC client. */
12
+ export type OrpcPluginOptions<T extends AnyNestedClient = AnyNestedClient> = ORPCNuxtClientOptions & ({
13
+ /** Use an application-owned link or create one for each Nuxt application. */
14
+ link: ClientLink<InferClientContext<T>> | ((context: OrpcLinkContext) => ClientLink<InferClientContext<T>>);
15
+ url?: never;
16
+ serverUrl?: never;
17
+ credentials?: never;
18
+ forwardHeaders?: never;
19
+ } | {
20
+ link?: never;
6
21
  /** RPC handler URL, including its path; relative URLs resolve against the current page URL. */
7
22
  url: string;
8
23
  /** Optional SSR handler URL; an absent or empty value falls back to url. */
@@ -11,13 +26,14 @@ export interface OrpcPluginOptions extends ORPCNuxtClientOptions {
11
26
  credentials?: RequestCredentials;
12
27
  /** Incoming headers to forward during SSR; only explicitly listed headers are forwarded. */
13
28
  forwardHeaders?: readonly string[];
14
- }
29
+ });
15
30
  /**
16
- * Create an HTTP client per Nuxt app and provide it as $orpc with inferred router types.
31
+ * Create an oRPC client per Nuxt app and provide it as $orpc with inferred router types.
17
32
  * The setup callback runs once per SSR request and once when the browser app starts.
33
+ * A custom link factory also runs once per app and receives its Nuxt app and H3 event.
18
34
  * Install Vue Query before this plugin, or return an explicit queryClient from setup.
19
35
  * Its QueryClient is captured immediately, so invalidate works before any composable runs.
20
36
  */
21
- export declare function defineNuxtPlugin<T extends AnyNestedClient>(setup: (nuxtApp: NuxtApp) => OrpcPluginOptions): Plugin<{
37
+ export declare function defineNuxtPlugin<T extends AnyNestedClient>(setup: (nuxtApp: NuxtApp) => OrpcPluginOptions<T>): Plugin<{
22
38
  orpc: ORPCNuxtClient<T>;
23
39
  }>;
@@ -1,4 +1,6 @@
1
- import { createORPCClient } from "@orpc/client";
1
+ import {
2
+ createORPCClient
3
+ } from "@orpc/client";
2
4
  import { RPCLink } from "@orpc/client/fetch";
3
5
  import {
4
6
  defineNuxtPlugin as createNuxtPlugin,
@@ -16,25 +18,7 @@ export function defineNuxtPlugin(setup) {
16
18
  "orpc-nuxt: install Vue Query before the oRPC plugin. Enable the module's QueryClient, use enforce: 'pre' in your Vue Query plugin, or pass queryClient explicitly."
17
19
  );
18
20
  }
19
- const url = import.meta.server ? options.serverUrl || options.url : options.url;
20
- const endpoint = new URL(url, useRequestURL());
21
- if (endpoint.protocol !== "http:" && endpoint.protocol !== "https:") {
22
- throw new Error("orpc-nuxt: the RPC handler URL must use HTTP or HTTPS.");
23
- }
24
- const link = new RPCLink({
25
- // oRPC v2 accepts the origin separately from the handler path and query string.
26
- origin: endpoint.origin,
27
- // HTTP URL.pathname always starts with the slash required by StandardUrl.
28
- url: `${endpoint.pathname}${endpoint.search}`,
29
- // An explicit empty list is essential: undefined would forward every incoming header.
30
- headers: useRequestHeaders([...options.forwardHeaders ?? []]),
31
- fetch(url2, init) {
32
- return globalThis.fetch(url2, {
33
- ...init,
34
- credentials: options.credentials
35
- });
36
- }
37
- });
21
+ const link = typeof options.link === "function" ? options.link({ nuxtApp, event: nuxtApp.ssrContext?.event }) : options.link ?? createHTTPLink(options);
38
22
  const client = createORPCClient(link);
39
23
  const orpc = createORPCNuxtClient(client, {
40
24
  prefix: options.prefix,
@@ -45,3 +29,24 @@ export function defineNuxtPlugin(setup) {
45
29
  };
46
30
  });
47
31
  }
32
+ function createHTTPLink(options) {
33
+ const url = import.meta.server ? options.serverUrl || options.url : options.url;
34
+ const endpoint = new URL(url, useRequestURL());
35
+ if (endpoint.protocol !== "http:" && endpoint.protocol !== "https:") {
36
+ throw new Error("orpc-nuxt: the RPC handler URL must use HTTP or HTTPS.");
37
+ }
38
+ return new RPCLink({
39
+ // oRPC v2 accepts the origin separately from the handler path and query string.
40
+ origin: endpoint.origin,
41
+ // HTTP URL.pathname always starts with the slash required by StandardUrl.
42
+ url: `${endpoint.pathname}${endpoint.search}`,
43
+ // An explicit empty list is essential: undefined would forward every incoming header.
44
+ headers: useRequestHeaders([...options.forwardHeaders ?? []]),
45
+ fetch(url2, init) {
46
+ return globalThis.fetch(url2, {
47
+ ...init,
48
+ credentials: options.credentials
49
+ });
50
+ }
51
+ });
52
+ }
@@ -1,2 +1,2 @@
1
1
  export { defineNuxtPlugin } from "./nuxt/define-plugin.js";
2
- export type { OrpcPluginOptions } from "./nuxt/define-plugin.js";
2
+ export type { OrpcLinkContext, OrpcPluginOptions } from "./nuxt/define-plugin.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orpc-nuxt",
3
- "version": "0.3.1",
3
+ "version": "0.4.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",