@veloxts/client 0.6.93 → 0.6.95
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/CHANGELOG.md +12 -0
- package/GUIDE.md +39 -0
- package/dist/client.js +8 -0
- package/dist/react/proxy-types.d.ts +59 -9
- package/dist/types.d.ts +77 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @veloxts/client
|
|
2
2
|
|
|
3
|
+
## 0.6.95
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- fix(create): use /trpc baseUrl for tRPC template and unwrap tRPC response format
|
|
8
|
+
|
|
9
|
+
## 0.6.94
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- feat(client): add tRPC router type support for ClientFromRouter and VeloxHooks
|
|
14
|
+
|
|
3
15
|
## 0.6.93
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/GUIDE.md
CHANGED
|
@@ -4,6 +4,24 @@ Type-safe frontend API client with zero code generation.
|
|
|
4
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
7
|
+
### tRPC Mode (Recommended for tRPC template)
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { createClient } from '@veloxts/client';
|
|
11
|
+
import type { AppRouter } from '../../api/src/router.js';
|
|
12
|
+
|
|
13
|
+
// AppRouter is typeof router from rpc()
|
|
14
|
+
const api = createClient<AppRouter>({
|
|
15
|
+
baseUrl: 'http://localhost:3030/trpc',
|
|
16
|
+
// mode: 'trpc' - auto-detected when baseUrl ends with /trpc
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const health = await api.health.getHealth();
|
|
20
|
+
const users = await api.users.listUsers();
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### REST Mode (ProcedureCollection)
|
|
24
|
+
|
|
7
25
|
```typescript
|
|
8
26
|
import { createClient } from '@veloxts/client';
|
|
9
27
|
import type { userProcedures } from '../server/procedures';
|
|
@@ -42,6 +60,27 @@ try {
|
|
|
42
60
|
|
|
43
61
|
## React Query Integration
|
|
44
62
|
|
|
63
|
+
### Recommended: createVeloxHooks (tRPC-style API)
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { createVeloxHooks, VeloxProvider } from '@veloxts/client/react';
|
|
67
|
+
import type { AppRouter } from '../../api/src/router.js';
|
|
68
|
+
|
|
69
|
+
// Create typed hooks - works with both ProcedureCollection and tRPC router types
|
|
70
|
+
export const api = createVeloxHooks<AppRouter>();
|
|
71
|
+
|
|
72
|
+
// In component
|
|
73
|
+
function UserList() {
|
|
74
|
+
const { data, isLoading } = api.users.listUsers.useQuery();
|
|
75
|
+
const { mutate } = api.users.createUser.useMutation();
|
|
76
|
+
|
|
77
|
+
// Suspense variant
|
|
78
|
+
const { data: users } = api.users.listUsers.useSuspenseQuery();
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Basic: Manual React Query
|
|
83
|
+
|
|
45
84
|
```typescript
|
|
46
85
|
import { useQuery, useMutation } from '@tanstack/react-query';
|
|
47
86
|
|
package/dist/client.js
CHANGED
|
@@ -412,6 +412,14 @@ async function executeProcedure(call, state, isRetry = false) {
|
|
|
412
412
|
if (state.config.onResponse) {
|
|
413
413
|
await state.config.onResponse(response);
|
|
414
414
|
}
|
|
415
|
+
// Unwrap tRPC response format: { result: { data: ... } }
|
|
416
|
+
const mode = detectMode(state.config);
|
|
417
|
+
if (mode === 'trpc' && body && typeof body === 'object') {
|
|
418
|
+
const trpcResponse = body;
|
|
419
|
+
if (trpcResponse.result?.data !== undefined) {
|
|
420
|
+
return trpcResponse.result.data;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
415
423
|
return body;
|
|
416
424
|
}
|
|
417
425
|
/**
|
|
@@ -342,27 +342,77 @@ type VeloxProcedureHooks<TProcedure> = TProcedure extends ClientProcedure<infer
|
|
|
342
342
|
export type VeloxNamespace<TProcedures extends ProcedureRecord> = {
|
|
343
343
|
[K in keyof TProcedures]: VeloxProcedureHooks<TProcedures[K]>;
|
|
344
344
|
};
|
|
345
|
+
/**
|
|
346
|
+
* Extract input type from a tRPC procedure
|
|
347
|
+
*/
|
|
348
|
+
type InferTRPCInput<T> = T extends {
|
|
349
|
+
_def: {
|
|
350
|
+
$types: {
|
|
351
|
+
input: infer I;
|
|
352
|
+
};
|
|
353
|
+
};
|
|
354
|
+
} ? I : unknown;
|
|
355
|
+
/**
|
|
356
|
+
* Extract output type from a tRPC procedure
|
|
357
|
+
*/
|
|
358
|
+
type InferTRPCOutput<T> = T extends {
|
|
359
|
+
_def: {
|
|
360
|
+
$types: {
|
|
361
|
+
output: infer O;
|
|
362
|
+
};
|
|
363
|
+
};
|
|
364
|
+
} ? O : unknown;
|
|
365
|
+
/**
|
|
366
|
+
* Determine if a tRPC procedure is a query or mutation
|
|
367
|
+
*/
|
|
368
|
+
type InferTRPCType<T> = T extends {
|
|
369
|
+
_def: {
|
|
370
|
+
type: infer TType;
|
|
371
|
+
};
|
|
372
|
+
} ? TType extends 'query' ? 'query' : TType extends 'mutation' ? 'mutation' : 'query' : 'query';
|
|
373
|
+
/**
|
|
374
|
+
* Resolve a tRPC procedure to its appropriate hook interface
|
|
375
|
+
*/
|
|
376
|
+
type VeloxTRPCProcedureHooks<TProcedure> = InferTRPCType<TProcedure> extends 'mutation' ? VeloxMutationProcedure<InferTRPCInput<TProcedure>, InferTRPCOutput<TProcedure>> : VeloxQueryProcedure<InferTRPCInput<TProcedure>, InferTRPCOutput<TProcedure>>;
|
|
377
|
+
/**
|
|
378
|
+
* Maps a tRPC namespace to hook interfaces
|
|
379
|
+
*/
|
|
380
|
+
export type VeloxTRPCNamespace<TNamespace> = {
|
|
381
|
+
[K in keyof TNamespace]: TNamespace[K] extends {
|
|
382
|
+
_def: unknown;
|
|
383
|
+
} ? VeloxTRPCProcedureHooks<TNamespace[K]> : never;
|
|
384
|
+
};
|
|
345
385
|
/**
|
|
346
386
|
* Maps router namespaces to their namespace hook interfaces
|
|
347
387
|
*
|
|
348
388
|
* This is the top-level type returned by `createVeloxHooks`.
|
|
349
389
|
*
|
|
350
|
-
*
|
|
390
|
+
* Supports two router shapes:
|
|
391
|
+
* 1. ProcedureCollection-based (REST mode): { namespace: ProcedureCollection }
|
|
392
|
+
* 2. tRPC router (tRPC mode): { namespace: { procedure: TRPCProcedure } }
|
|
393
|
+
*
|
|
394
|
+
* @template TRouter - The router type (collection of procedure collections or tRPC router)
|
|
351
395
|
*
|
|
352
396
|
* @example
|
|
353
397
|
* ```typescript
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
*
|
|
357
|
-
*
|
|
398
|
+
* // REST mode (ProcedureCollection)
|
|
399
|
+
* type AppRouter = { users: typeof userProcedures };
|
|
400
|
+
* const api = createVeloxHooks<AppRouter>();
|
|
401
|
+
*
|
|
402
|
+
* // tRPC mode
|
|
403
|
+
* const { router } = rpc([userProcedures] as const);
|
|
404
|
+
* export type AppRouter = typeof router;
|
|
405
|
+
* const api = createVeloxHooks<AppRouter>();
|
|
358
406
|
*
|
|
359
|
-
*
|
|
360
|
-
* // api.users.getUser
|
|
361
|
-
* // api.users.createUser
|
|
407
|
+
* // Both support:
|
|
408
|
+
* // api.users.getUser.useQuery({ id })
|
|
409
|
+
* // api.users.createUser.useMutation()
|
|
362
410
|
* ```
|
|
363
411
|
*/
|
|
364
412
|
export type VeloxHooks<TRouter> = {
|
|
365
|
-
[K in keyof TRouter]: TRouter[K] extends ProcedureCollection<infer _TNamespace, infer TProcedures> ? VeloxNamespace<TProcedures> :
|
|
413
|
+
[K in keyof TRouter]: TRouter[K] extends ProcedureCollection<infer _TNamespace, infer TProcedures> ? VeloxNamespace<TProcedures> : TRouter[K] extends Record<string, {
|
|
414
|
+
_def: unknown;
|
|
415
|
+
}> ? VeloxTRPCNamespace<TRouter[K]> : never;
|
|
366
416
|
};
|
|
367
417
|
/**
|
|
368
418
|
* Configuration for createVeloxHooks
|
package/dist/types.d.ts
CHANGED
|
@@ -94,6 +94,67 @@ export type InferProcedureOutput<T> = T extends ClientProcedure<unknown, infer O
|
|
|
94
94
|
* Works with both ClientProcedure and @veloxts/router's CompiledProcedure
|
|
95
95
|
*/
|
|
96
96
|
export type InferProcedureType<T> = T extends ClientProcedure<unknown, unknown, infer TType> ? TType : never;
|
|
97
|
+
/**
|
|
98
|
+
* Extracts the input type from a tRPC procedure
|
|
99
|
+
*
|
|
100
|
+
* tRPC procedures have shape: { _def: { $types: { input: I, output: O } } }
|
|
101
|
+
*/
|
|
102
|
+
export type InferTRPCProcedureInput<T> = T extends {
|
|
103
|
+
_def: {
|
|
104
|
+
$types: {
|
|
105
|
+
input: infer I;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
} ? I : unknown;
|
|
109
|
+
/**
|
|
110
|
+
* Extracts the output type from a tRPC procedure
|
|
111
|
+
*
|
|
112
|
+
* tRPC procedures have shape: { _def: { $types: { input: I, output: O } } }
|
|
113
|
+
*/
|
|
114
|
+
export type InferTRPCProcedureOutput<T> = T extends {
|
|
115
|
+
_def: {
|
|
116
|
+
$types: {
|
|
117
|
+
output: infer O;
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
} ? O : unknown;
|
|
121
|
+
/**
|
|
122
|
+
* Helper type to determine if input is "empty" (void, undefined, never, or unknown)
|
|
123
|
+
*
|
|
124
|
+
* tRPC uses `void` for procedures with no input, but the type can also appear as
|
|
125
|
+
* `undefined` or `unknown` in some cases.
|
|
126
|
+
*/
|
|
127
|
+
type IsEmptyInput<T> = [T] extends [void] ? true : [T] extends [undefined] ? true : [T] extends [never] ? true : unknown extends T ? true : false;
|
|
128
|
+
/**
|
|
129
|
+
* Builds a callable client interface from a tRPC namespace
|
|
130
|
+
*
|
|
131
|
+
* tRPC namespaces are objects where each key is a procedure with
|
|
132
|
+
* the shape: { _def: { $types: { input: I, output: O } } }
|
|
133
|
+
*
|
|
134
|
+
* Handles procedures with no input (void/undefined) by making the parameter optional.
|
|
135
|
+
*/
|
|
136
|
+
export type ClientFromTRPCNamespace<TNamespace> = {
|
|
137
|
+
[K in keyof TNamespace]: IsEmptyInput<InferTRPCProcedureInput<TNamespace[K]>> extends true ? () => Promise<InferTRPCProcedureOutput<TNamespace[K]>> : (input: InferTRPCProcedureInput<TNamespace[K]>) => Promise<InferTRPCProcedureOutput<TNamespace[K]>>;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Checks if a type looks like a tRPC procedure
|
|
141
|
+
*/
|
|
142
|
+
export type IsTRPCProcedure<T> = T extends {
|
|
143
|
+
_def: {
|
|
144
|
+
$types: {
|
|
145
|
+
input: unknown;
|
|
146
|
+
output: unknown;
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
} ? true : false;
|
|
150
|
+
/**
|
|
151
|
+
* Checks if a type looks like a tRPC namespace (object containing tRPC procedures)
|
|
152
|
+
*/
|
|
153
|
+
export type IsTRPCNamespace<T> = T extends Record<string, {
|
|
154
|
+
_def: {
|
|
155
|
+
$types: unknown;
|
|
156
|
+
};
|
|
157
|
+
}> ? true : false;
|
|
97
158
|
/**
|
|
98
159
|
* Builds a callable client interface from a single procedure collection
|
|
99
160
|
*
|
|
@@ -107,28 +168,31 @@ export type ClientFromCollection<TCollection extends ProcedureCollection> = {
|
|
|
107
168
|
/**
|
|
108
169
|
* Builds a complete client interface from a router (collection of collections)
|
|
109
170
|
*
|
|
110
|
-
*
|
|
171
|
+
* Supports two router shapes:
|
|
172
|
+
* 1. ProcedureCollection-based (REST mode): { namespace: ProcedureCollection }
|
|
173
|
+
* 2. tRPC router (tRPC mode): { namespace: { procedure: TRPCProcedure } }
|
|
111
174
|
*
|
|
112
175
|
* @example
|
|
113
176
|
* ```typescript
|
|
114
|
-
* //
|
|
177
|
+
* // REST mode (ProcedureCollection):
|
|
115
178
|
* const userProcedures = defineProcedures('users', {
|
|
116
179
|
* getUser: procedure().input(...).output(...).query(...),
|
|
117
|
-
* createUser: procedure().input(...).output(...).mutation(...),
|
|
118
180
|
* });
|
|
119
|
-
*
|
|
120
|
-
* // Frontend gets:
|
|
121
181
|
* type Client = ClientFromRouter<{ users: typeof userProcedures }>;
|
|
122
|
-
*
|
|
123
|
-
* //
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
182
|
+
*
|
|
183
|
+
* // tRPC mode (AppRouter):
|
|
184
|
+
* const { router } = rpc([userProcedures] as const);
|
|
185
|
+
* export type AppRouter = typeof router;
|
|
186
|
+
* type Client = ClientFromRouter<AppRouter>;
|
|
187
|
+
*
|
|
188
|
+
* // Both result in:
|
|
189
|
+
* // Client = { users: { getUser: (input: { id: string }) => Promise<User> } }
|
|
128
190
|
* ```
|
|
129
191
|
*/
|
|
130
192
|
export type ClientFromRouter<TRouter> = {
|
|
131
|
-
[K in keyof TRouter]: TRouter[K] extends ProcedureCollection ? ClientFromCollection<TRouter[K]> :
|
|
193
|
+
[K in keyof TRouter]: TRouter[K] extends ProcedureCollection ? ClientFromCollection<TRouter[K]> : TRouter[K] extends Record<string, {
|
|
194
|
+
_def: unknown;
|
|
195
|
+
}> ? ClientFromTRPCNamespace<TRouter[K]> : never;
|
|
132
196
|
};
|
|
133
197
|
/**
|
|
134
198
|
* A single route entry with method, path, and procedure kind
|
|
@@ -327,3 +391,4 @@ export interface ProcedureCall {
|
|
|
327
391
|
* HTTP method inferred from procedure name
|
|
328
392
|
*/
|
|
329
393
|
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
394
|
+
export {};
|