File size: 2,400 Bytes
fb12607
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import { createTRPCReact, httpBatchLink } from "@trpc/react-query";
import { createTRPCProxyClient } from "@trpc/client";
import { inferRouterInputs, inferRouterOutputs } from "@trpc/server";
import { extractSubdomain, isReservedSubdomain } from "@micprotocol/shared-types";

import type { AppRouter } from "@micprotocol/api";

export const trpc = createTRPCReact<AppRouter>();

const API_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:4000";

type AuthTokenGetter = () => Promise<string | null>;
type WorkspaceIdGetter = () => string | null;

/**
 * Create a tRPC React client that sends both the auth token and the
 * active workspace ID on every request.
 *
 * @param getAuthToken  – async function returning the session token (or null)
 * @param getWorkspaceId – sync function returning the currently active
 *                         workspace ID from React context (or null)
 */
export function getTrpcClient(
  getAuthToken?: AuthTokenGetter,
  getWorkspaceId?: WorkspaceIdGetter,
) {
  return trpc.createClient({
    links: [
      httpBatchLink({
        url: `${API_URL}/trpc`,
        async headers() {
          const token = getAuthToken ? await getAuthToken() : null;
          const workspaceId = getWorkspaceId ? getWorkspaceId() : null;

          const headers: Record<string, string> = {};

          if (token) {
            headers.Authorization = `Bearer ${token}`;
          }

          if (workspaceId) {
            headers["x-workspace-id"] = workspaceId;
          }

          if (typeof window !== "undefined") {
            const subdomain = extractSubdomain(window.location.hostname);
            if (subdomain && !isReservedSubdomain(subdomain)) {
              headers["x-subdomain"] = subdomain;
            }
          }

          return headers;
        },
        // Send cookies with requests
        fetch(url, options) {
          return fetch(url, {
            ...options,
            credentials: "include",
          });
        },
      }),
    ],
  });
}

// Utility to create a server-side client (for RSC)
export function getServerTrpcClient() {
  return createTRPCProxyClient<AppRouter>({
    links: [
      httpBatchLink({
        url: `${API_URL}/trpc`,
      }),
    ],
  });
}

// Types for router inputs/outputs
export type RouterInputs = inferRouterInputs<AppRouter>;
export type RouterOutputs = inferRouterOutputs<AppRouter>;