aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/client')
-rw-r--r--src/client/api/client.test.ts30
-rw-r--r--src/client/api/client.ts15
-rw-r--r--src/client/api/index.ts4
-rw-r--r--src/client/api/types.ts11
-rw-r--r--src/client/stores/auth.tsx3
5 files changed, 45 insertions, 18 deletions
diff --git a/src/client/api/client.test.ts b/src/client/api/client.test.ts
index 5489547..27c3a0a 100644
--- a/src/client/api/client.test.ts
+++ b/src/client/api/client.test.ts
@@ -13,8 +13,10 @@ import {
import {
ApiClient,
ApiClientError,
+ type LoginResponse,
localStorageTokenStorage,
type TokenStorage,
+ type User,
} from "./client";
function createMockTokenStorage(): TokenStorage & {
@@ -209,3 +211,31 @@ describe("localStorageTokenStorage", () => {
expect(localStorageTokenStorage.getTokens()).toBeNull();
});
});
+
+describe("InferResponseType types", () => {
+ it("LoginResponse has expected properties", () => {
+ // This test verifies the inferred types have the correct structure
+ // The type assertions will fail at compile time if the types are wrong
+ const mockResponse: LoginResponse = {
+ accessToken: "access-token",
+ refreshToken: "refresh-token",
+ user: { id: "123", username: "testuser" },
+ };
+
+ expect(mockResponse.accessToken).toBe("access-token");
+ expect(mockResponse.refreshToken).toBe("refresh-token");
+ expect(mockResponse.user.id).toBe("123");
+ expect(mockResponse.user.username).toBe("testuser");
+ });
+
+ it("User type is correctly derived from LoginResponse", () => {
+ // Verify User type has expected structure
+ const user: User = {
+ id: "user-1",
+ username: "testuser",
+ };
+
+ expect(user.id).toBe("user-1");
+ expect(user.username).toBe("testuser");
+ });
+});
diff --git a/src/client/api/client.ts b/src/client/api/client.ts
index 7741942..7607eb6 100644
--- a/src/client/api/client.ts
+++ b/src/client/api/client.ts
@@ -1,6 +1,13 @@
-import { hc } from "hono/client";
+import { hc, type InferResponseType } from "hono/client";
import type { AppType } from "../../server/index.js";
-import type { ApiError, AuthResponse, Tokens } from "./types";
+import type { ApiError, Tokens } from "./types";
+
+// Create a temporary client just for type inference
+const _rpc = hc<AppType>("");
+
+// Infer response types from server definitions
+export type LoginResponse = InferResponseType<typeof _rpc.api.auth.login.$post>;
+export type User = LoginResponse["user"];
export class ApiClientError extends Error {
constructor(
@@ -120,12 +127,12 @@ export class ApiClient {
}
}
- async login(username: string, password: string): Promise<AuthResponse> {
+ async login(username: string, password: string): Promise<LoginResponse> {
const res = await this.rpc.api.auth.login.$post({
json: { username, password },
});
- const data = await this.handleResponse<AuthResponse>(res);
+ const data = await this.handleResponse<LoginResponse>(res);
this.tokenStorage.setTokens({
accessToken: data.accessToken,
diff --git a/src/client/api/index.ts b/src/client/api/index.ts
index fb26b70..63d0a40 100644
--- a/src/client/api/index.ts
+++ b/src/client/api/index.ts
@@ -3,7 +3,9 @@ export {
ApiClientError,
type ApiClientOptions,
apiClient,
+ type LoginResponse,
localStorageTokenStorage,
type TokenStorage,
+ type User,
} from "./client";
-export type { ApiError, AuthResponse, Tokens, User } from "./types";
+export type { ApiError, Tokens } from "./types";
diff --git a/src/client/api/types.ts b/src/client/api/types.ts
index eaf69eb..70918fe 100644
--- a/src/client/api/types.ts
+++ b/src/client/api/types.ts
@@ -1,14 +1,3 @@
-export interface User {
- id: string;
- username: string;
-}
-
-export interface AuthResponse {
- accessToken: string;
- refreshToken: string;
- user: User;
-}
-
export interface ApiError {
error: {
message: string;
diff --git a/src/client/stores/auth.tsx b/src/client/stores/auth.tsx
index 58e9d40..b34717b 100644
--- a/src/client/stores/auth.tsx
+++ b/src/client/stores/auth.tsx
@@ -7,8 +7,7 @@ import {
useMemo,
useState,
} from "react";
-import { ApiClientError, apiClient } from "../api/client";
-import type { User } from "../api/types";
+import { ApiClientError, apiClient, type User } from "../api/client";
export interface AuthState {
user: User | null;