@veloxts/client 0.2.0 → 0.3.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.
@@ -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"}
package/dist/client.js ADDED
@@ -0,0 +1,376 @@
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 { NetworkError, parseErrorResponse } from './errors.js';
10
+ // ============================================================================
11
+ // Naming Convention Mapping
12
+ // ============================================================================
13
+ /**
14
+ * Maps procedure naming convention to HTTP method
15
+ *
16
+ * Matches the same logic used in @veloxts/router REST adapter
17
+ */
18
+ const PROCEDURE_METHOD_MAP = {
19
+ get: 'GET',
20
+ list: 'GET',
21
+ find: 'GET',
22
+ create: 'POST',
23
+ add: 'POST',
24
+ update: 'PUT',
25
+ edit: 'PUT',
26
+ patch: 'PATCH',
27
+ delete: 'DELETE',
28
+ remove: 'DELETE',
29
+ };
30
+ /**
31
+ * Pre-compiled regex pattern for path parameters
32
+ *
33
+ * PERFORMANCE: Compiled once at module load instead of per-request.
34
+ * The pattern matches :paramName format (e.g., :id, :userId, :post_id)
35
+ *
36
+ * @internal
37
+ */
38
+ const PATH_PARAM_PATTERN = /:([a-zA-Z_][a-zA-Z0-9_]*)/g;
39
+ /**
40
+ * Infers HTTP method from procedure name
41
+ *
42
+ * @internal
43
+ */
44
+ function inferMethodFromName(procedureName) {
45
+ // Check each prefix
46
+ for (const [prefix, method] of Object.entries(PROCEDURE_METHOD_MAP)) {
47
+ if (procedureName.startsWith(prefix)) {
48
+ return method;
49
+ }
50
+ }
51
+ // Default to POST for mutations (conservative default)
52
+ return 'POST';
53
+ }
54
+ // Note: extractResourceFromName is reserved for future use in path building enhancements
55
+ // Keeping it commented for now to avoid unused code warnings
56
+ // function extractResourceFromName(procedureName: string): string | undefined {
57
+ // for (const prefix of Object.keys(PROCEDURE_METHOD_MAP)) {
58
+ // if (procedureName.startsWith(prefix)) {
59
+ // const remainder = procedureName.slice(prefix.length);
60
+ // if (remainder.length > 0) {
61
+ // return remainder.charAt(0).toLowerCase() + remainder.slice(1);
62
+ // }
63
+ // }
64
+ // }
65
+ // return undefined;
66
+ // }
67
+ /**
68
+ * Builds REST path from namespace and procedure name
69
+ *
70
+ * @example
71
+ * - namespace='users', name='getUser' -> '/users/:id'
72
+ * - namespace='users', name='listUsers' -> '/users'
73
+ * - namespace='posts', name='createPost' -> '/posts'
74
+ *
75
+ * @internal
76
+ */
77
+ function buildRestPath(namespace, procedureName) {
78
+ const method = inferMethodFromName(procedureName);
79
+ // List operations: /namespace
80
+ if (procedureName.startsWith('list')) {
81
+ return `/${namespace}`;
82
+ }
83
+ // Single resource operations (get, update, delete): /namespace/:id
84
+ if (procedureName.startsWith('get') ||
85
+ procedureName.startsWith('update') ||
86
+ procedureName.startsWith('delete')) {
87
+ return `/${namespace}/:id`;
88
+ }
89
+ // Create operations: /namespace
90
+ if (method === 'POST') {
91
+ return `/${namespace}`;
92
+ }
93
+ // Default: /namespace
94
+ return `/${namespace}`;
95
+ }
96
+ /**
97
+ * Replaces path parameters with actual values from input
98
+ *
99
+ * PERFORMANCE: Uses pre-compiled PATH_PARAM_PATTERN instead of creating
100
+ * a new RegExp on each call. Resets lastIndex for safe reuse.
101
+ *
102
+ * @example
103
+ * - path='/users/:id', input={ id: '123' } -> '/users/123'
104
+ * - path='/posts/:postId/comments/:id', input={ postId: 'abc', id: '456' } -> '/posts/abc/comments/456'
105
+ *
106
+ * @internal
107
+ */
108
+ function resolvePathParams(path, input) {
109
+ // Reset lastIndex for safe reuse of global regex
110
+ PATH_PARAM_PATTERN.lastIndex = 0;
111
+ return path.replace(PATH_PARAM_PATTERN, (_match, paramName) => {
112
+ const value = input[paramName];
113
+ if (value === undefined || value === null) {
114
+ throw new Error(`Missing path parameter: ${paramName}`);
115
+ }
116
+ return String(value);
117
+ });
118
+ }
119
+ /**
120
+ * Builds query string from input object, excluding path params
121
+ *
122
+ * @internal
123
+ */
124
+ function buildQueryString(input, pathParams) {
125
+ const params = new URLSearchParams();
126
+ for (const [key, value] of Object.entries(input)) {
127
+ // Skip path parameters
128
+ if (pathParams.has(key)) {
129
+ continue;
130
+ }
131
+ // Skip undefined values
132
+ if (value === undefined) {
133
+ continue;
134
+ }
135
+ // Handle arrays
136
+ if (Array.isArray(value)) {
137
+ for (const item of value) {
138
+ params.append(key, String(item));
139
+ }
140
+ }
141
+ else {
142
+ params.append(key, String(value));
143
+ }
144
+ }
145
+ const queryString = params.toString();
146
+ return queryString ? `?${queryString}` : '';
147
+ }
148
+ /**
149
+ * Extracts path parameter names from a path pattern
150
+ *
151
+ * PERFORMANCE: Uses pre-compiled PATH_PARAM_PATTERN instead of creating
152
+ * a new RegExp on each call. Uses matchAll which handles lastIndex internally.
153
+ *
154
+ * @example
155
+ * - '/users/:id' -> Set(['id'])
156
+ * - '/posts/:postId/comments/:commentId' -> Set(['postId', 'commentId'])
157
+ *
158
+ * @internal
159
+ */
160
+ function extractPathParams(path) {
161
+ const params = new Set();
162
+ // matchAll creates an iterator that handles lastIndex internally
163
+ for (const match of path.matchAll(PATH_PARAM_PATTERN)) {
164
+ params.add(match[1]);
165
+ }
166
+ return params;
167
+ }
168
+ // ============================================================================
169
+ // Request Building
170
+ // ============================================================================
171
+ /**
172
+ * Builds the full URL and request options for a procedure call
173
+ *
174
+ * @internal
175
+ */
176
+ function buildRequest(call, baseUrl, config) {
177
+ const method = inferMethodFromName(call.procedureName);
178
+ const path = buildRestPath(call.namespace, call.procedureName);
179
+ // Prepare headers
180
+ const headers = {
181
+ 'Content-Type': 'application/json',
182
+ ...config.headers,
183
+ };
184
+ let finalPath = path;
185
+ let body;
186
+ // Handle input based on method
187
+ if (method === 'GET') {
188
+ // GET: params in URL
189
+ const pathParams = extractPathParams(path);
190
+ const input = (call.input || {});
191
+ // Resolve path parameters
192
+ finalPath = resolvePathParams(path, input);
193
+ // Add query string for remaining parameters
194
+ const queryString = buildQueryString(input, pathParams);
195
+ finalPath = `${finalPath}${queryString}`;
196
+ }
197
+ else {
198
+ // POST/PUT/PATCH/DELETE: body as JSON
199
+ // But first resolve path params if any
200
+ const pathParams = extractPathParams(path);
201
+ if (pathParams.size > 0 && call.input && typeof call.input === 'object') {
202
+ const input = call.input;
203
+ finalPath = resolvePathParams(path, input);
204
+ // For POST with path params, body is the input minus path params
205
+ const bodyInput = {};
206
+ for (const [key, value] of Object.entries(input)) {
207
+ if (!pathParams.has(key)) {
208
+ bodyInput[key] = value;
209
+ }
210
+ }
211
+ body = JSON.stringify(bodyInput);
212
+ }
213
+ else {
214
+ body = JSON.stringify(call.input);
215
+ }
216
+ }
217
+ // Build full URL
218
+ const url = `${baseUrl}${finalPath}`;
219
+ return {
220
+ url,
221
+ options: {
222
+ method,
223
+ headers,
224
+ body,
225
+ },
226
+ };
227
+ }
228
+ /**
229
+ * Executes a procedure call against the API
230
+ *
231
+ * @internal
232
+ */
233
+ async function executeProcedure(call, state) {
234
+ const { url, options } = buildRequest(call, state.config.baseUrl, state.config);
235
+ // Call onRequest interceptor
236
+ if (state.config.onRequest) {
237
+ await state.config.onRequest(url, options);
238
+ }
239
+ let response;
240
+ try {
241
+ response = await state.fetch(url, options);
242
+ }
243
+ catch (error) {
244
+ // Network error - couldn't reach server
245
+ const networkError = new NetworkError('Network request failed', {
246
+ url,
247
+ method: options.method || 'GET',
248
+ cause: error instanceof Error ? error : undefined,
249
+ });
250
+ // Call onError interceptor
251
+ if (state.config.onError) {
252
+ await state.config.onError(networkError);
253
+ }
254
+ throw networkError;
255
+ }
256
+ // Parse response body
257
+ let body;
258
+ const contentType = response.headers.get('content-type');
259
+ if (contentType?.includes('application/json')) {
260
+ try {
261
+ body = await response.json();
262
+ }
263
+ catch {
264
+ // Couldn't parse JSON - use text
265
+ body = await response.text();
266
+ }
267
+ }
268
+ else {
269
+ body = await response.text();
270
+ }
271
+ // Handle error responses
272
+ if (!response.ok) {
273
+ const error = parseErrorResponse(response, body, url, options.method || 'GET');
274
+ // Call onError interceptor
275
+ if (state.config.onError) {
276
+ await state.config.onError(error);
277
+ }
278
+ throw error;
279
+ }
280
+ // Call onResponse interceptor
281
+ if (state.config.onResponse) {
282
+ await state.config.onResponse(response);
283
+ }
284
+ return body;
285
+ }
286
+ /**
287
+ * Creates a proxy for a namespace that intercepts procedure calls
288
+ *
289
+ * @internal
290
+ */
291
+ function createNamespaceProxy(namespace, state) {
292
+ return new Proxy({}, {
293
+ get(_target, procedureName) {
294
+ // Return a function that executes the procedure
295
+ return (input) => {
296
+ return executeProcedure({
297
+ namespace,
298
+ procedureName,
299
+ input,
300
+ }, state);
301
+ };
302
+ },
303
+ });
304
+ }
305
+ /**
306
+ * Creates the root client proxy
307
+ *
308
+ * @internal
309
+ */
310
+ function createClientProxy(state) {
311
+ return new Proxy({}, {
312
+ get(_target, namespace) {
313
+ return createNamespaceProxy(namespace, state);
314
+ },
315
+ });
316
+ }
317
+ // ============================================================================
318
+ // Public API
319
+ // ============================================================================
320
+ /**
321
+ * Creates a type-safe API client for a VeloxTS backend
322
+ *
323
+ * The client uses TypeScript's type system to infer the full API shape from
324
+ * backend procedure definitions, providing autocomplete and compile-time type checking.
325
+ *
326
+ * @template TRouter - The router type (typeof imported procedures)
327
+ * @param config - Client configuration
328
+ * @returns Fully typed API client with namespaced procedures
329
+ *
330
+ * @example
331
+ * ```typescript
332
+ * // Import procedure types from backend
333
+ * import type { userProcedures, postProcedures } from '../server/procedures';
334
+ *
335
+ * // Create client with inferred types
336
+ * const api = createClient<{
337
+ * users: typeof userProcedures;
338
+ * posts: typeof postProcedures;
339
+ * }>({
340
+ * baseUrl: 'https://api.example.com/api',
341
+ * });
342
+ *
343
+ * // Fully typed calls
344
+ * const user = await api.users.getUser({ id: '123' });
345
+ * const newPost = await api.posts.createPost({ title: 'Hello', content: '...' });
346
+ * ```
347
+ *
348
+ * @example
349
+ * ```typescript
350
+ * // With custom configuration
351
+ * const api = createClient<Router>({
352
+ * baseUrl: '/api',
353
+ * headers: {
354
+ * 'Authorization': 'Bearer token123',
355
+ * },
356
+ * onRequest: async (url, options) => {
357
+ * console.log(`${options.method} ${url}`);
358
+ * },
359
+ * onError: async (error) => {
360
+ * console.error('API Error:', error.message);
361
+ * },
362
+ * });
363
+ * ```
364
+ */
365
+ export function createClient(config) {
366
+ // Use provided fetch or global fetch
367
+ const fetchImpl = config.fetch || fetch;
368
+ // Create client state
369
+ const state = {
370
+ config,
371
+ fetch: fetchImpl,
372
+ };
373
+ // Return the proxy-based client
374
+ return createClientProxy(state);
375
+ }
376
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Client-side error handling
3
+ *
4
+ * Provides error classes that mirror the server-side VeloxError structure,
5
+ * with additional context about the failed request.
6
+ *
7
+ * @module errors
8
+ */
9
+ import type { ClientError } from './types.js';
10
+ /**
11
+ * Base error response fields from server
12
+ */
13
+ interface BaseErrorResponse {
14
+ error: string;
15
+ message: string;
16
+ statusCode: number;
17
+ code?: string;
18
+ }
19
+ /**
20
+ * Validation error response from server
21
+ */
22
+ interface ValidationErrorResponse extends BaseErrorResponse {
23
+ error: 'ValidationError';
24
+ statusCode: 400;
25
+ code: 'VALIDATION_ERROR';
26
+ fields?: Record<string, string>;
27
+ }
28
+ /**
29
+ * Not found error response from server
30
+ */
31
+ interface NotFoundErrorResponse extends BaseErrorResponse {
32
+ error: 'NotFoundError';
33
+ statusCode: 404;
34
+ code: 'NOT_FOUND';
35
+ resource: string;
36
+ resourceId?: string;
37
+ }
38
+ /**
39
+ * Generic error response from server
40
+ */
41
+ interface GenericErrorResponse extends BaseErrorResponse {
42
+ error: string;
43
+ statusCode: number;
44
+ code?: string;
45
+ }
46
+ /**
47
+ * Union of all error response types from server
48
+ */
49
+ export type ErrorResponse = ValidationErrorResponse | NotFoundErrorResponse | GenericErrorResponse;
50
+ /**
51
+ * Base error class for all client errors
52
+ *
53
+ * Represents an error that occurred during an API request, including
54
+ * both network errors and server-returned error responses.
55
+ */
56
+ export declare class VeloxClientError extends Error implements ClientError {
57
+ readonly statusCode?: number;
58
+ readonly code?: string;
59
+ readonly body?: unknown;
60
+ readonly url: string;
61
+ readonly method: string;
62
+ constructor(message: string, options: {
63
+ statusCode?: number;
64
+ code?: string;
65
+ body?: unknown;
66
+ url: string;
67
+ method: string;
68
+ });
69
+ }
70
+ /**
71
+ * Network error when request fails to reach server
72
+ *
73
+ * Thrown when the request cannot be completed due to network issues,
74
+ * CORS problems, or other transport-level failures.
75
+ */
76
+ export declare class NetworkError extends VeloxClientError {
77
+ readonly cause?: Error;
78
+ constructor(message: string, options: {
79
+ url: string;
80
+ method: string;
81
+ cause?: Error;
82
+ });
83
+ }
84
+ /**
85
+ * Validation error from server (400 status)
86
+ *
87
+ * Thrown when request data fails server-side validation.
88
+ * Includes field-level error details if provided by server.
89
+ */
90
+ export declare class ClientValidationError extends VeloxClientError {
91
+ readonly fields?: Record<string, string>;
92
+ constructor(message: string, options: {
93
+ url: string;
94
+ method: string;
95
+ fields?: Record<string, string>;
96
+ body?: unknown;
97
+ });
98
+ }
99
+ /**
100
+ * Not found error from server (404 status)
101
+ *
102
+ * Thrown when a requested resource doesn't exist.
103
+ */
104
+ export declare class ClientNotFoundError extends VeloxClientError {
105
+ readonly resource?: string;
106
+ readonly resourceId?: string;
107
+ constructor(message: string, options: {
108
+ url: string;
109
+ method: string;
110
+ resource?: string;
111
+ resourceId?: string;
112
+ body?: unknown;
113
+ });
114
+ }
115
+ /**
116
+ * Server error (5xx status)
117
+ *
118
+ * Thrown when server returns an internal error.
119
+ */
120
+ export declare class ServerError extends VeloxClientError {
121
+ constructor(message: string, options: {
122
+ statusCode: number;
123
+ code?: string;
124
+ url: string;
125
+ method: string;
126
+ body?: unknown;
127
+ });
128
+ }
129
+ /**
130
+ * Type guard for VeloxClientError
131
+ */
132
+ export declare function isVeloxClientError(error: unknown): error is VeloxClientError;
133
+ /**
134
+ * Type guard for NetworkError
135
+ */
136
+ export declare function isNetworkError(error: unknown): error is NetworkError;
137
+ /**
138
+ * Type guard for ClientValidationError
139
+ */
140
+ export declare function isClientValidationError(error: unknown): error is ClientValidationError;
141
+ /**
142
+ * Type guard for ClientNotFoundError
143
+ */
144
+ export declare function isClientNotFoundError(error: unknown): error is ClientNotFoundError;
145
+ /**
146
+ * Type guard for ServerError
147
+ */
148
+ export declare function isServerError(error: unknown): error is ServerError;
149
+ /**
150
+ * Type guard for validation error response
151
+ */
152
+ export declare function isValidationErrorResponse(response: ErrorResponse): response is ValidationErrorResponse;
153
+ /**
154
+ * Type guard for not found error response
155
+ */
156
+ export declare function isNotFoundErrorResponse(response: ErrorResponse): response is NotFoundErrorResponse;
157
+ /**
158
+ * Parses an error response from the server and creates appropriate error instance
159
+ *
160
+ * @internal
161
+ */
162
+ export declare function parseErrorResponse(response: Response, body: unknown, url: string, method: string): VeloxClientError;
163
+ export {};
164
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
package/dist/errors.js ADDED
@@ -0,0 +1,250 @@
1
+ /**
2
+ * Client-side error handling
3
+ *
4
+ * Provides error classes that mirror the server-side VeloxError structure,
5
+ * with additional context about the failed request.
6
+ *
7
+ * @module errors
8
+ */
9
+ // ============================================================================
10
+ // Client Error Classes
11
+ // ============================================================================
12
+ /**
13
+ * Base error class for all client errors
14
+ *
15
+ * Represents an error that occurred during an API request, including
16
+ * both network errors and server-returned error responses.
17
+ */
18
+ export class VeloxClientError extends Error {
19
+ statusCode;
20
+ code;
21
+ body;
22
+ url;
23
+ method;
24
+ constructor(message, options) {
25
+ super(message);
26
+ this.name = 'VeloxClientError';
27
+ this.statusCode = options.statusCode;
28
+ this.code = options.code;
29
+ this.body = options.body;
30
+ this.url = options.url;
31
+ this.method = options.method;
32
+ // Maintains proper stack trace for where error was thrown (V8 only)
33
+ if (Error.captureStackTrace) {
34
+ Error.captureStackTrace(this, VeloxClientError);
35
+ }
36
+ }
37
+ }
38
+ /**
39
+ * Network error when request fails to reach server
40
+ *
41
+ * Thrown when the request cannot be completed due to network issues,
42
+ * CORS problems, or other transport-level failures.
43
+ */
44
+ export class NetworkError extends VeloxClientError {
45
+ cause;
46
+ constructor(message, options) {
47
+ super(message, {
48
+ url: options.url,
49
+ method: options.method,
50
+ });
51
+ this.name = 'NetworkError';
52
+ this.cause = options.cause;
53
+ if (Error.captureStackTrace) {
54
+ Error.captureStackTrace(this, NetworkError);
55
+ }
56
+ }
57
+ }
58
+ /**
59
+ * Validation error from server (400 status)
60
+ *
61
+ * Thrown when request data fails server-side validation.
62
+ * Includes field-level error details if provided by server.
63
+ */
64
+ export class ClientValidationError extends VeloxClientError {
65
+ fields;
66
+ constructor(message, options) {
67
+ super(message, {
68
+ statusCode: 400,
69
+ code: 'VALIDATION_ERROR',
70
+ url: options.url,
71
+ method: options.method,
72
+ body: options.body,
73
+ });
74
+ this.name = 'ClientValidationError';
75
+ this.fields = options.fields;
76
+ if (Error.captureStackTrace) {
77
+ Error.captureStackTrace(this, ClientValidationError);
78
+ }
79
+ }
80
+ }
81
+ /**
82
+ * Not found error from server (404 status)
83
+ *
84
+ * Thrown when a requested resource doesn't exist.
85
+ */
86
+ export class ClientNotFoundError extends VeloxClientError {
87
+ resource;
88
+ resourceId;
89
+ constructor(message, options) {
90
+ super(message, {
91
+ statusCode: 404,
92
+ code: 'NOT_FOUND',
93
+ url: options.url,
94
+ method: options.method,
95
+ body: options.body,
96
+ });
97
+ this.name = 'ClientNotFoundError';
98
+ this.resource = options.resource;
99
+ this.resourceId = options.resourceId;
100
+ if (Error.captureStackTrace) {
101
+ Error.captureStackTrace(this, ClientNotFoundError);
102
+ }
103
+ }
104
+ }
105
+ /**
106
+ * Server error (5xx status)
107
+ *
108
+ * Thrown when server returns an internal error.
109
+ */
110
+ export class ServerError extends VeloxClientError {
111
+ constructor(message, options) {
112
+ super(message, options);
113
+ this.name = 'ServerError';
114
+ if (Error.captureStackTrace) {
115
+ Error.captureStackTrace(this, ServerError);
116
+ }
117
+ }
118
+ }
119
+ // ============================================================================
120
+ // Type Guards
121
+ // ============================================================================
122
+ /**
123
+ * Type guard for VeloxClientError
124
+ */
125
+ export function isVeloxClientError(error) {
126
+ return error instanceof VeloxClientError;
127
+ }
128
+ /**
129
+ * Type guard for NetworkError
130
+ */
131
+ export function isNetworkError(error) {
132
+ return error instanceof NetworkError;
133
+ }
134
+ /**
135
+ * Type guard for ClientValidationError
136
+ */
137
+ export function isClientValidationError(error) {
138
+ return error instanceof ClientValidationError;
139
+ }
140
+ /**
141
+ * Type guard for ClientNotFoundError
142
+ */
143
+ export function isClientNotFoundError(error) {
144
+ return error instanceof ClientNotFoundError;
145
+ }
146
+ /**
147
+ * Type guard for ServerError
148
+ */
149
+ export function isServerError(error) {
150
+ return error instanceof ServerError;
151
+ }
152
+ /**
153
+ * Type guard for validation error response
154
+ */
155
+ export function isValidationErrorResponse(response) {
156
+ return response.error === 'ValidationError';
157
+ }
158
+ /**
159
+ * Type guard for not found error response
160
+ */
161
+ export function isNotFoundErrorResponse(response) {
162
+ return response.error === 'NotFoundError';
163
+ }
164
+ // ============================================================================
165
+ // Error Parsing
166
+ // ============================================================================
167
+ /**
168
+ * Parses an error response from the server and creates appropriate error instance
169
+ *
170
+ * @internal
171
+ */
172
+ export function parseErrorResponse(response, body, url, method) {
173
+ // Try to parse as ErrorResponse
174
+ if (isErrorResponseLike(body)) {
175
+ const errorResponse = body;
176
+ // Validation error
177
+ if (isValidationErrorResponse(errorResponse)) {
178
+ return new ClientValidationError(errorResponse.message, {
179
+ url,
180
+ method,
181
+ fields: errorResponse.fields,
182
+ body,
183
+ });
184
+ }
185
+ // Not found error
186
+ if (isNotFoundErrorResponse(errorResponse)) {
187
+ return new ClientNotFoundError(errorResponse.message, {
188
+ url,
189
+ method,
190
+ resource: errorResponse.resource,
191
+ resourceId: errorResponse.resourceId,
192
+ body,
193
+ });
194
+ }
195
+ // Server error (5xx)
196
+ if (response.status >= 500) {
197
+ return new ServerError(errorResponse.message, {
198
+ statusCode: errorResponse.statusCode,
199
+ code: errorResponse.code,
200
+ url,
201
+ method,
202
+ body,
203
+ });
204
+ }
205
+ // Generic error
206
+ return new VeloxClientError(errorResponse.message, {
207
+ statusCode: errorResponse.statusCode,
208
+ code: errorResponse.code,
209
+ url,
210
+ method,
211
+ body,
212
+ });
213
+ }
214
+ // Fallback for non-standard error responses
215
+ const message = typeof body === 'object' &&
216
+ body !== null &&
217
+ 'message' in body &&
218
+ typeof body.message === 'string'
219
+ ? body.message
220
+ : `Request failed with status ${response.status}`;
221
+ if (response.status >= 500) {
222
+ return new ServerError(message, {
223
+ statusCode: response.status,
224
+ url,
225
+ method,
226
+ body,
227
+ });
228
+ }
229
+ return new VeloxClientError(message, {
230
+ statusCode: response.status,
231
+ url,
232
+ method,
233
+ body,
234
+ });
235
+ }
236
+ /**
237
+ * Type guard to check if body looks like an error response
238
+ *
239
+ * @internal
240
+ */
241
+ function isErrorResponseLike(body) {
242
+ if (typeof body !== 'object' || body === null) {
243
+ return false;
244
+ }
245
+ const obj = body;
246
+ return (typeof obj.error === 'string' &&
247
+ typeof obj.message === 'string' &&
248
+ typeof obj.statusCode === 'number');
249
+ }
250
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @veloxts/client - Type-safe API client for frontend applications
3
+ *
4
+ * Provides a fully typed client for consuming VeloxTS APIs from frontend code.
5
+ * Types are inferred directly from backend procedure definitions without code generation.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // Import procedure types from backend
10
+ * import type { userProcedures } from '../server/procedures';
11
+ *
12
+ * // Create client with full type safety
13
+ * const api = createClient<{ users: typeof userProcedures }>({
14
+ * baseUrl: '/api'
15
+ * });
16
+ *
17
+ * // Fully typed API calls
18
+ * const user = await api.users.getUser({ id: '123' });
19
+ * ```
20
+ *
21
+ * @module @veloxts/client
22
+ */
23
+ export { createClient } from './client.js';
24
+ export type { ClientConfig, ClientError, ClientFromCollection, ClientFromRouter, ClientProcedure, HttpMethod, InferProcedureInput, InferProcedureOutput, ProcedureCall, ProcedureCollection, ProcedureRecord, } from './types.js';
25
+ export { ClientNotFoundError, ClientValidationError, NetworkError, ServerError, VeloxClientError, } from './errors.js';
26
+ export { isClientNotFoundError, isClientValidationError, isNetworkError, isNotFoundErrorResponse, isServerError, isValidationErrorResponse, isVeloxClientError, } from './errors.js';
27
+ export type { ErrorResponse } from './errors.js';
28
+ export declare const CLIENT_VERSION = "0.1.0";
29
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAMH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAO3C,YAAY,EACV,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,mBAAmB,EACnB,oBAAoB,EACpB,aAAa,EACb,mBAAmB,EACnB,eAAe,GAChB,MAAM,YAAY,CAAC;AAMpB,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,YAAY,EACZ,WAAW,EACX,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAMrB,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,cAAc,EACd,uBAAuB,EACvB,aAAa,EACb,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAMrB,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAMjD,eAAO,MAAM,cAAc,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @veloxts/client - Type-safe API client for frontend applications
3
+ *
4
+ * Provides a fully typed client for consuming VeloxTS APIs from frontend code.
5
+ * Types are inferred directly from backend procedure definitions without code generation.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // Import procedure types from backend
10
+ * import type { userProcedures } from '../server/procedures';
11
+ *
12
+ * // Create client with full type safety
13
+ * const api = createClient<{ users: typeof userProcedures }>({
14
+ * baseUrl: '/api'
15
+ * });
16
+ *
17
+ * // Fully typed API calls
18
+ * const user = await api.users.getUser({ id: '123' });
19
+ * ```
20
+ *
21
+ * @module @veloxts/client
22
+ */
23
+ // ============================================================================
24
+ // Core Client
25
+ // ============================================================================
26
+ export { createClient } from './client.js';
27
+ // ============================================================================
28
+ // Error Classes
29
+ // ============================================================================
30
+ export { ClientNotFoundError, ClientValidationError, NetworkError, ServerError, VeloxClientError, } from './errors.js';
31
+ // ============================================================================
32
+ // Type Guards
33
+ // ============================================================================
34
+ export { isClientNotFoundError, isClientValidationError, isNetworkError, isNotFoundErrorResponse, isServerError, isValidationErrorResponse, isVeloxClientError, } from './errors.js';
35
+ // ============================================================================
36
+ // Version
37
+ // ============================================================================
38
+ export const CLIENT_VERSION = '0.1.0';
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,+EAA+E;AAC/E,cAAc;AACd,+EAA+E;AAE/E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAqB3C,+EAA+E;AAC/E,gBAAgB;AAChB,+EAA+E;AAE/E,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,YAAY,EACZ,WAAW,EACX,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,+EAA+E;AAC/E,cAAc;AACd,+EAA+E;AAE/E,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,cAAc,EACd,uBAAuB,EACvB,aAAa,EACb,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAQrB,+EAA+E;AAC/E,UAAU;AACV,+EAA+E;AAE/E,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC"}
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Type inference utilities for the VeloxTS client
3
+ *
4
+ * Provides type extraction from backend procedure collections to enable
5
+ * full-stack type safety without code generation.
6
+ *
7
+ * @module types
8
+ */
9
+ /**
10
+ * Procedure operation type (matches @veloxts/router)
11
+ */
12
+ export type ProcedureType = 'query' | 'mutation';
13
+ /**
14
+ * Minimal interface representing a compiled procedure
15
+ *
16
+ * This interface is designed to be structurally compatible with @veloxts/router's
17
+ * CompiledProcedure type, enabling type inference without requiring a direct
18
+ * package dependency. The client only needs the schema types for inference.
19
+ *
20
+ * @template TInput - The validated input type
21
+ * @template TOutput - The handler output type
22
+ *
23
+ * @see {@link https://github.com/veloxts/velox-ts-framework/velox | @veloxts/router CompiledProcedure}
24
+ */
25
+ export interface ClientProcedure<TInput = unknown, TOutput = unknown> {
26
+ /** Whether this is a query or mutation */
27
+ readonly type: ProcedureType;
28
+ /** The procedure handler function */
29
+ readonly handler: (args: {
30
+ input: TInput;
31
+ ctx: unknown;
32
+ }) => TOutput | Promise<TOutput>;
33
+ /** Input validation schema (if specified) */
34
+ readonly inputSchema?: {
35
+ parse: (input: unknown) => TInput;
36
+ };
37
+ /** Output validation schema (if specified) */
38
+ readonly outputSchema?: {
39
+ parse: (output: unknown) => TOutput;
40
+ };
41
+ /** Middleware chain (not used by client, but part of CompiledProcedure) */
42
+ readonly middlewares?: ReadonlyArray<unknown>;
43
+ /** REST route override (not used by client, but part of CompiledProcedure) */
44
+ readonly restOverride?: {
45
+ method?: string;
46
+ path?: string;
47
+ };
48
+ }
49
+ /**
50
+ * Record of named procedures
51
+ *
52
+ * NOTE: Uses `any` for variance compatibility with @veloxts/router's ProcedureRecord
53
+ */
54
+ export type ProcedureRecord = Record<string, ClientProcedure<any, any>>;
55
+ /**
56
+ * Procedure collection with namespace
57
+ *
58
+ * Matches the structure of @veloxts/router's ProcedureCollection
59
+ */
60
+ export interface ProcedureCollection<TProcedures extends ProcedureRecord = ProcedureRecord> {
61
+ /** Resource namespace (e.g., 'users', 'posts') */
62
+ readonly namespace: string;
63
+ /** Named procedures in this collection */
64
+ readonly procedures: TProcedures;
65
+ }
66
+ /**
67
+ * Extracts the input type from a procedure
68
+ *
69
+ * Works with both ClientProcedure and @veloxts/router's CompiledProcedure
70
+ */
71
+ export type InferProcedureInput<T> = T extends ClientProcedure<infer I, unknown> ? I : never;
72
+ /**
73
+ * Extracts the output type from a procedure
74
+ *
75
+ * Works with both ClientProcedure and @veloxts/router's CompiledProcedure
76
+ */
77
+ export type InferProcedureOutput<T> = T extends ClientProcedure<unknown, infer O> ? O : never;
78
+ /**
79
+ * Builds a callable client interface from a single procedure collection
80
+ *
81
+ * For each procedure, creates a method that:
82
+ * - Takes the procedure's input type as parameter
83
+ * - Returns a Promise of the procedure's output type
84
+ */
85
+ export type ClientFromCollection<TCollection extends ProcedureCollection> = {
86
+ [K in keyof TCollection['procedures']]: (input: InferProcedureInput<TCollection['procedures'][K]>) => Promise<InferProcedureOutput<TCollection['procedures'][K]>>;
87
+ };
88
+ /**
89
+ * Builds a complete client interface from a router (collection of collections)
90
+ *
91
+ * For each collection namespace, creates a property with all callable procedures.
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * // Backend defines:
96
+ * const userProcedures = defineProcedures('users', {
97
+ * getUser: procedure().input(...).output(...).query(...),
98
+ * createUser: procedure().input(...).output(...).mutation(...),
99
+ * });
100
+ *
101
+ * // Frontend gets:
102
+ * type Client = ClientFromRouter<{ users: typeof userProcedures }>;
103
+ * // Client = {
104
+ * // users: {
105
+ * // getUser: (input: { id: string }) => Promise<User>;
106
+ * // createUser: (input: CreateUserInput) => Promise<User>;
107
+ * // }
108
+ * // }
109
+ * ```
110
+ */
111
+ export type ClientFromRouter<TRouter> = {
112
+ [K in keyof TRouter]: TRouter[K] extends ProcedureCollection ? ClientFromCollection<TRouter[K]> : never;
113
+ };
114
+ /**
115
+ * Configuration for creating a client instance
116
+ */
117
+ export interface ClientConfig {
118
+ /** Base URL for API requests (e.g., 'https://api.example.com' or '/api') */
119
+ baseUrl: string;
120
+ /** Optional custom headers to include in all requests */
121
+ headers?: Record<string, string>;
122
+ /**
123
+ * Optional request interceptor
124
+ * Called before each request is sent
125
+ */
126
+ onRequest?: (url: string, options: RequestInit) => void | Promise<void>;
127
+ /**
128
+ * Optional response interceptor
129
+ * Called after each successful response
130
+ */
131
+ onResponse?: (response: Response) => void | Promise<void>;
132
+ /**
133
+ * Optional error interceptor
134
+ * Called when a request fails or returns an error response
135
+ */
136
+ onError?: (error: ClientError) => void | Promise<void>;
137
+ /**
138
+ * Optional custom fetch implementation
139
+ * Defaults to global fetch
140
+ */
141
+ fetch?: typeof fetch;
142
+ }
143
+ /**
144
+ * Client error with full context about the failed request
145
+ */
146
+ export interface ClientError extends Error {
147
+ /** HTTP status code (if available) */
148
+ statusCode?: number;
149
+ /** Error code from server (if available) */
150
+ code?: string;
151
+ /** Original response body (if available) */
152
+ body?: unknown;
153
+ /** URL that was requested */
154
+ url: string;
155
+ /** HTTP method used */
156
+ method: string;
157
+ }
158
+ /**
159
+ * Internal representation of a procedure call
160
+ */
161
+ export interface ProcedureCall {
162
+ /** Namespace (e.g., 'users') */
163
+ namespace: string;
164
+ /** Procedure name (e.g., 'getUser') */
165
+ procedureName: string;
166
+ /** Input data */
167
+ input: unknown;
168
+ }
169
+ /**
170
+ * HTTP method inferred from procedure name
171
+ */
172
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
173
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Type inference utilities for the VeloxTS client
3
+ *
4
+ * Provides type extraction from backend procedure collections to enable
5
+ * full-stack type safety without code generation.
6
+ *
7
+ * @module types
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veloxts/client",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Type-safe frontend API client for VeloxTS framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",