@veloxts/client 0.1.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/LICENSE +21 -0
- package/README.md +263 -0
- package/dist/client.d.ts +56 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +376 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +164 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +250 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +173 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 VeloxTS Framework Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# @veloxts/client
|
|
2
|
+
|
|
3
|
+
Type-safe frontend API client for the VeloxTS framework.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Zero code generation** - Types inferred directly from backend procedure definitions
|
|
8
|
+
- **Full type safety** - Autocomplete and compile-time type checking
|
|
9
|
+
- **Fetch-based** - Works in both browser and Node.js environments
|
|
10
|
+
- **Error handling** - Typed error classes with full response context
|
|
11
|
+
- **Interceptors** - Request, response, and error hooks
|
|
12
|
+
- **REST integration** - Maps to auto-generated REST endpoints
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @veloxts/client
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Basic Setup
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// Import your backend procedure types
|
|
26
|
+
import type { userProcedures, postProcedures } from '../server/procedures';
|
|
27
|
+
import { createClient } from '@veloxts/client';
|
|
28
|
+
|
|
29
|
+
// Create a typed client
|
|
30
|
+
const api = createClient<{
|
|
31
|
+
users: typeof userProcedures;
|
|
32
|
+
posts: typeof postProcedures;
|
|
33
|
+
}>({
|
|
34
|
+
baseUrl: '/api',
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Make fully typed API calls
|
|
38
|
+
const user = await api.users.getUser({ id: '123' });
|
|
39
|
+
// user is typed as User (inferred from backend output schema)
|
|
40
|
+
|
|
41
|
+
const users = await api.users.listUsers({ page: 1, limit: 10 });
|
|
42
|
+
// users is typed as User[] (or whatever your output schema defines)
|
|
43
|
+
|
|
44
|
+
const newUser = await api.users.createUser({
|
|
45
|
+
name: 'Alice',
|
|
46
|
+
email: 'alice@example.com'
|
|
47
|
+
});
|
|
48
|
+
// newUser is typed as User
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Custom Configuration
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
const api = createClient<Router>({
|
|
55
|
+
baseUrl: 'https://api.example.com/api',
|
|
56
|
+
|
|
57
|
+
// Add custom headers to all requests
|
|
58
|
+
headers: {
|
|
59
|
+
'Authorization': 'Bearer token123',
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
// Request interceptor
|
|
63
|
+
onRequest: async (url, options) => {
|
|
64
|
+
console.log(`${options.method} ${url}`);
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
// Response interceptor
|
|
68
|
+
onResponse: async (response) => {
|
|
69
|
+
console.log(`Response: ${response.status}`);
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
// Error interceptor
|
|
73
|
+
onError: async (error) => {
|
|
74
|
+
console.error('API Error:', error.message);
|
|
75
|
+
// You can track errors, show notifications, etc.
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Error Handling
|
|
81
|
+
|
|
82
|
+
The client provides typed error classes for different error scenarios:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import {
|
|
86
|
+
isVeloxClientError,
|
|
87
|
+
isClientValidationError,
|
|
88
|
+
isClientNotFoundError,
|
|
89
|
+
isServerError,
|
|
90
|
+
isNetworkError,
|
|
91
|
+
} from '@veloxts/client';
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const user = await api.users.getUser({ id: 'invalid' });
|
|
95
|
+
} catch (error) {
|
|
96
|
+
if (isClientValidationError(error)) {
|
|
97
|
+
// Handle validation errors (400)
|
|
98
|
+
console.log('Validation failed:', error.fields);
|
|
99
|
+
} else if (isClientNotFoundError(error)) {
|
|
100
|
+
// Handle not found errors (404)
|
|
101
|
+
console.log('Resource not found:', error.resource);
|
|
102
|
+
} else if (isServerError(error)) {
|
|
103
|
+
// Handle server errors (5xx)
|
|
104
|
+
console.log('Server error:', error.statusCode);
|
|
105
|
+
} else if (isNetworkError(error)) {
|
|
106
|
+
// Handle network errors (can't reach server)
|
|
107
|
+
console.log('Network error:', error.message);
|
|
108
|
+
} else if (isVeloxClientError(error)) {
|
|
109
|
+
// Generic client error
|
|
110
|
+
console.log('Error:', error.statusCode, error.message);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Using with React
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// hooks/useApi.ts
|
|
119
|
+
import { createClient } from '@veloxts/client';
|
|
120
|
+
import type { AppRouter } from '../server/procedures';
|
|
121
|
+
|
|
122
|
+
export const api = createClient<AppRouter>({
|
|
123
|
+
baseUrl: import.meta.env.VITE_API_URL || '/api',
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// In your component
|
|
127
|
+
import { api } from './hooks/useApi';
|
|
128
|
+
import { useState, useEffect } from 'react';
|
|
129
|
+
|
|
130
|
+
function UserProfile({ userId }: { userId: string }) {
|
|
131
|
+
const [user, setUser] = useState(null);
|
|
132
|
+
const [loading, setLoading] = useState(true);
|
|
133
|
+
const [error, setError] = useState(null);
|
|
134
|
+
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
api.users.getUser({ id: userId })
|
|
137
|
+
.then(setUser)
|
|
138
|
+
.catch(setError)
|
|
139
|
+
.finally(() => setLoading(false));
|
|
140
|
+
}, [userId]);
|
|
141
|
+
|
|
142
|
+
if (loading) return <div>Loading...</div>;
|
|
143
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
144
|
+
|
|
145
|
+
return <div>User: {user.name}</div>;
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Using with React Query (Recommended)
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
153
|
+
import { api } from './hooks/useApi';
|
|
154
|
+
|
|
155
|
+
// Query hook
|
|
156
|
+
function useUser(userId: string) {
|
|
157
|
+
return useQuery({
|
|
158
|
+
queryKey: ['users', userId],
|
|
159
|
+
queryFn: () => api.users.getUser({ id: userId }),
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Mutation hook
|
|
164
|
+
function useCreateUser() {
|
|
165
|
+
const queryClient = useQueryClient();
|
|
166
|
+
|
|
167
|
+
return useMutation({
|
|
168
|
+
mutationFn: (data) => api.users.createUser(data),
|
|
169
|
+
onSuccess: () => {
|
|
170
|
+
// Invalidate and refetch
|
|
171
|
+
queryClient.invalidateQueries({ queryKey: ['users'] });
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// In your component
|
|
177
|
+
function UserList() {
|
|
178
|
+
const { data: users, isLoading, error } = useQuery({
|
|
179
|
+
queryKey: ['users'],
|
|
180
|
+
queryFn: () => api.users.listUsers({}),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const createUser = useCreateUser();
|
|
184
|
+
|
|
185
|
+
const handleCreate = () => {
|
|
186
|
+
createUser.mutate({
|
|
187
|
+
name: 'New User',
|
|
188
|
+
email: 'user@example.com'
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// ... rest of component
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Type Inference
|
|
197
|
+
|
|
198
|
+
The client uses TypeScript's type system to infer the complete API shape from your backend procedure definitions:
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
// Backend (procedures.ts)
|
|
202
|
+
export const userProcedures = defineProcedures('users', {
|
|
203
|
+
getUser: procedure()
|
|
204
|
+
.input(z.object({ id: z.string().uuid() }))
|
|
205
|
+
.output(UserSchema)
|
|
206
|
+
.query(async ({ input, ctx }) => {
|
|
207
|
+
return ctx.db.user.findUnique({ where: { id: input.id } });
|
|
208
|
+
}),
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Frontend - Types are automatically inferred!
|
|
212
|
+
const client = createClient<{ users: typeof userProcedures }>({ baseUrl: '/api' });
|
|
213
|
+
|
|
214
|
+
// TypeScript knows:
|
|
215
|
+
// - api.users.getUser expects { id: string }
|
|
216
|
+
// - api.users.getUser returns Promise<User>
|
|
217
|
+
// - Invalid inputs will show compile-time errors
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## REST Endpoint Mapping
|
|
221
|
+
|
|
222
|
+
The client automatically maps procedure calls to REST endpoints using the same conventions as the server:
|
|
223
|
+
|
|
224
|
+
| Procedure Name | HTTP Method | Path |
|
|
225
|
+
|---------------|-------------|------|
|
|
226
|
+
| `getUser` | GET | `/users/:id` |
|
|
227
|
+
| `listUsers` | GET | `/users` |
|
|
228
|
+
| `createUser` | POST | `/users` |
|
|
229
|
+
| `updateUser` | PUT | `/users/:id` |
|
|
230
|
+
| `deleteUser` | DELETE | `/users/:id` |
|
|
231
|
+
|
|
232
|
+
## Browser and Node.js Support
|
|
233
|
+
|
|
234
|
+
The client uses the native `fetch` API, which is available in:
|
|
235
|
+
- All modern browsers
|
|
236
|
+
- Node.js v20+ (native fetch)
|
|
237
|
+
- Earlier Node.js versions with a polyfill
|
|
238
|
+
|
|
239
|
+
For older Node.js versions, provide a custom fetch implementation:
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
import fetch from 'node-fetch';
|
|
243
|
+
|
|
244
|
+
const api = createClient<Router>({
|
|
245
|
+
baseUrl: 'https://api.example.com',
|
|
246
|
+
fetch: fetch as typeof globalThis.fetch,
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Related Packages
|
|
251
|
+
|
|
252
|
+
- [@veloxts/core](/packages/core) - Core framework with error classes
|
|
253
|
+
- [@veloxts/router](/packages/router) - Procedure definitions for backend
|
|
254
|
+
- [@veloxts/validation](/packages/validation) - Schema validation with Zod
|
|
255
|
+
- [create-velox-app](/packages/create) - Project scaffolder
|
|
256
|
+
|
|
257
|
+
## TypeScript Support
|
|
258
|
+
|
|
259
|
+
All exports are fully typed with comprehensive JSDoc documentation. The package includes type definitions and declaration maps for excellent IDE support.
|
|
260
|
+
|
|
261
|
+
## License
|
|
262
|
+
|
|
263
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-safe API client implementation
|
|
3
|
+
*
|
|
4
|
+
* Provides a fetch-based client that calls REST endpoints with full type safety
|
|
5
|
+
* inferred from backend procedure definitions.
|
|
6
|
+
*
|
|
7
|
+
* @module client
|
|
8
|
+
*/
|
|
9
|
+
import type { ClientConfig, ClientFromRouter } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Creates a type-safe API client for a VeloxTS backend
|
|
12
|
+
*
|
|
13
|
+
* The client uses TypeScript's type system to infer the full API shape from
|
|
14
|
+
* backend procedure definitions, providing autocomplete and compile-time type checking.
|
|
15
|
+
*
|
|
16
|
+
* @template TRouter - The router type (typeof imported procedures)
|
|
17
|
+
* @param config - Client configuration
|
|
18
|
+
* @returns Fully typed API client with namespaced procedures
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* // Import procedure types from backend
|
|
23
|
+
* import type { userProcedures, postProcedures } from '../server/procedures';
|
|
24
|
+
*
|
|
25
|
+
* // Create client with inferred types
|
|
26
|
+
* const api = createClient<{
|
|
27
|
+
* users: typeof userProcedures;
|
|
28
|
+
* posts: typeof postProcedures;
|
|
29
|
+
* }>({
|
|
30
|
+
* baseUrl: 'https://api.example.com/api',
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* // Fully typed calls
|
|
34
|
+
* const user = await api.users.getUser({ id: '123' });
|
|
35
|
+
* const newPost = await api.posts.createPost({ title: 'Hello', content: '...' });
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* // With custom configuration
|
|
41
|
+
* const api = createClient<Router>({
|
|
42
|
+
* baseUrl: '/api',
|
|
43
|
+
* headers: {
|
|
44
|
+
* 'Authorization': 'Bearer token123',
|
|
45
|
+
* },
|
|
46
|
+
* onRequest: async (url, options) => {
|
|
47
|
+
* console.log(`${options.method} ${url}`);
|
|
48
|
+
* },
|
|
49
|
+
* onError: async (error) => {
|
|
50
|
+
* console.error('API Error:', error.message);
|
|
51
|
+
* },
|
|
52
|
+
* });
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function createClient<TRouter>(config: ClientConfig): ClientFromRouter<TRouter>;
|
|
56
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAA6B,MAAM,YAAY,CAAC;AA4X5F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAYrF"}
|