@veloxts/client 0.7.9 → 0.8.1
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/README.md +1 -1
- package/dist/errors.d.ts +29 -1
- package/dist/errors.js +41 -0
- package/dist/index.d.ts +1 -1
- package/dist/react/provider.d.ts +1 -1
- package/dist/react/types.d.ts +1 -1
- package/dist/types.d.ts +79 -4
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @veloxts/client
|
|
2
2
|
|
|
3
|
-
> **Early Access (v0.
|
|
3
|
+
> **Early Access (v0.8.x)**
|
|
4
4
|
|
|
5
5
|
Type-safe frontend API client for VeloxTS Framework - provides zero code generation with full type inference from backend procedures. Learn more at [@veloxts/velox](https://www.npmjs.com/package/@veloxts/velox).
|
|
6
6
|
|
package/dist/errors.d.ts
CHANGED
|
@@ -35,6 +35,18 @@ interface NotFoundErrorResponse extends BaseErrorResponse {
|
|
|
35
35
|
resource: string;
|
|
36
36
|
resourceId?: string;
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Domain error response from server
|
|
40
|
+
*
|
|
41
|
+
* When server-side DomainError.toJSON() is called, it returns:
|
|
42
|
+
* { error, message, statusCode, code, data }
|
|
43
|
+
*/
|
|
44
|
+
interface DomainErrorResponse extends BaseErrorResponse {
|
|
45
|
+
error: string;
|
|
46
|
+
statusCode: number;
|
|
47
|
+
code: string;
|
|
48
|
+
data?: unknown;
|
|
49
|
+
}
|
|
38
50
|
/**
|
|
39
51
|
* Generic error response from server
|
|
40
52
|
*/
|
|
@@ -46,7 +58,7 @@ interface GenericErrorResponse extends BaseErrorResponse {
|
|
|
46
58
|
/**
|
|
47
59
|
* Union of all error response types from server
|
|
48
60
|
*/
|
|
49
|
-
export type ErrorResponse = ValidationErrorResponse | NotFoundErrorResponse | GenericErrorResponse;
|
|
61
|
+
export type ErrorResponse = ValidationErrorResponse | NotFoundErrorResponse | DomainErrorResponse | GenericErrorResponse;
|
|
50
62
|
/**
|
|
51
63
|
* Base error class for all client errors
|
|
52
64
|
*
|
|
@@ -57,12 +69,19 @@ export declare class VeloxClientError extends Error implements ClientError {
|
|
|
57
69
|
readonly statusCode?: number;
|
|
58
70
|
readonly code?: string;
|
|
59
71
|
readonly body?: unknown;
|
|
72
|
+
/**
|
|
73
|
+
* Typed domain error payload, extracted from `body.data` when the response
|
|
74
|
+
* contains a `code` field (i.e. it is a DomainError response).
|
|
75
|
+
* This is DISTINCT from `body` which holds the full raw response body.
|
|
76
|
+
*/
|
|
77
|
+
readonly data?: unknown;
|
|
60
78
|
readonly url: string;
|
|
61
79
|
readonly method: string;
|
|
62
80
|
constructor(message: string, options: {
|
|
63
81
|
statusCode?: number;
|
|
64
82
|
code?: string;
|
|
65
83
|
body?: unknown;
|
|
84
|
+
data?: unknown;
|
|
66
85
|
url: string;
|
|
67
86
|
method: string;
|
|
68
87
|
});
|
|
@@ -124,6 +143,7 @@ export declare class ServerError extends VeloxClientError {
|
|
|
124
143
|
url: string;
|
|
125
144
|
method: string;
|
|
126
145
|
body?: unknown;
|
|
146
|
+
data?: unknown;
|
|
127
147
|
});
|
|
128
148
|
}
|
|
129
149
|
/**
|
|
@@ -154,6 +174,14 @@ export declare function isValidationErrorResponse(response: ErrorResponse): resp
|
|
|
154
174
|
* Type guard for not found error response
|
|
155
175
|
*/
|
|
156
176
|
export declare function isNotFoundErrorResponse(response: ErrorResponse): response is NotFoundErrorResponse;
|
|
177
|
+
/**
|
|
178
|
+
* Type guard for domain error response
|
|
179
|
+
*
|
|
180
|
+
* A domain error response has a `code` field that is not one of the built-in
|
|
181
|
+
* error codes (VALIDATION_ERROR, NOT_FOUND). The server-side DomainError
|
|
182
|
+
* serializes as: { error, message, statusCode, code, data }.
|
|
183
|
+
*/
|
|
184
|
+
export declare function isDomainErrorResponse(response: ErrorResponse): response is DomainErrorResponse;
|
|
157
185
|
/**
|
|
158
186
|
* Parses an error response from the server and creates appropriate error instance
|
|
159
187
|
*
|
package/dist/errors.js
CHANGED
|
@@ -19,6 +19,12 @@ export class VeloxClientError extends Error {
|
|
|
19
19
|
statusCode;
|
|
20
20
|
code;
|
|
21
21
|
body;
|
|
22
|
+
/**
|
|
23
|
+
* Typed domain error payload, extracted from `body.data` when the response
|
|
24
|
+
* contains a `code` field (i.e. it is a DomainError response).
|
|
25
|
+
* This is DISTINCT from `body` which holds the full raw response body.
|
|
26
|
+
*/
|
|
27
|
+
data;
|
|
22
28
|
url;
|
|
23
29
|
method;
|
|
24
30
|
constructor(message, options) {
|
|
@@ -27,6 +33,7 @@ export class VeloxClientError extends Error {
|
|
|
27
33
|
this.statusCode = options.statusCode;
|
|
28
34
|
this.code = options.code;
|
|
29
35
|
this.body = options.body;
|
|
36
|
+
this.data = options.data;
|
|
30
37
|
this.url = options.url;
|
|
31
38
|
this.method = options.method;
|
|
32
39
|
// Maintains proper stack trace for where error was thrown (V8 only)
|
|
@@ -161,6 +168,18 @@ export function isValidationErrorResponse(response) {
|
|
|
161
168
|
export function isNotFoundErrorResponse(response) {
|
|
162
169
|
return response.error === 'NotFoundError';
|
|
163
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Type guard for domain error response
|
|
173
|
+
*
|
|
174
|
+
* A domain error response has a `code` field that is not one of the built-in
|
|
175
|
+
* error codes (VALIDATION_ERROR, NOT_FOUND). The server-side DomainError
|
|
176
|
+
* serializes as: { error, message, statusCode, code, data }.
|
|
177
|
+
*/
|
|
178
|
+
export function isDomainErrorResponse(response) {
|
|
179
|
+
return (typeof response.code === 'string' &&
|
|
180
|
+
response.code !== 'VALIDATION_ERROR' &&
|
|
181
|
+
response.code !== 'NOT_FOUND');
|
|
182
|
+
}
|
|
164
183
|
// ============================================================================
|
|
165
184
|
// Error Parsing
|
|
166
185
|
// ============================================================================
|
|
@@ -192,6 +211,28 @@ export function parseErrorResponse(response, body, url, method) {
|
|
|
192
211
|
body,
|
|
193
212
|
});
|
|
194
213
|
}
|
|
214
|
+
// Domain error — has a custom `code` and optional `data` payload
|
|
215
|
+
if (isDomainErrorResponse(errorResponse)) {
|
|
216
|
+
const domainData = errorResponse.data;
|
|
217
|
+
if (response.status >= 500) {
|
|
218
|
+
return new ServerError(errorResponse.message, {
|
|
219
|
+
statusCode: errorResponse.statusCode,
|
|
220
|
+
code: errorResponse.code,
|
|
221
|
+
url,
|
|
222
|
+
method,
|
|
223
|
+
body,
|
|
224
|
+
data: domainData,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return new VeloxClientError(errorResponse.message, {
|
|
228
|
+
statusCode: errorResponse.statusCode,
|
|
229
|
+
code: errorResponse.code,
|
|
230
|
+
url,
|
|
231
|
+
method,
|
|
232
|
+
body,
|
|
233
|
+
data: domainData,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
195
236
|
// Server error (5xx)
|
|
196
237
|
if (response.status >= 500) {
|
|
197
238
|
return new ServerError(errorResponse.message, {
|
package/dist/index.d.ts
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* @module @veloxts/client
|
|
22
22
|
*/
|
|
23
23
|
export { createClient } from './client.js';
|
|
24
|
-
export type { ClientConfig, ClientError, ClientFromCollection, ClientFromRouter, ClientMode, ClientProcedure, HttpMethod, InferProcedureInput, InferProcedureOutput, ProcedureCall, ProcedureCollection, ProcedureRecord, } from './types.js';
|
|
24
|
+
export type { ClientConfig, ClientError, ClientFromCollection, ClientFromRouter, ClientMode, ClientProcedure, HttpMethod, InferProcedureErrors, InferProcedureInput, InferProcedureOutput, ProcedureCall, ProcedureCollection, ProcedureRecord, } from './types.js';
|
|
25
25
|
export { ClientNotFoundError, ClientValidationError, NetworkError, ServerError, VeloxClientError, } from './errors.js';
|
|
26
26
|
export { isClientNotFoundError, isClientValidationError, isNetworkError, isNotFoundErrorResponse, isServerError, isValidationErrorResponse, isVeloxClientError, } from './errors.js';
|
|
27
27
|
export type { ErrorResponse } from './errors.js';
|
package/dist/react/provider.d.ts
CHANGED
|
@@ -104,4 +104,4 @@ export declare function VeloxProvider<TRouter>({ children, config, queryClient:
|
|
|
104
104
|
* ```
|
|
105
105
|
*/
|
|
106
106
|
export declare function useVeloxContext<TRouter>(): VeloxContextValue<TRouter>;
|
|
107
|
-
export type {
|
|
107
|
+
export type { VeloxContextValue, VeloxProviderProps };
|
package/dist/react/types.d.ts
CHANGED
|
@@ -79,4 +79,4 @@ export interface VeloxProviderProps<_TRouter> {
|
|
|
79
79
|
/** Optional pre-configured QueryClient instance */
|
|
80
80
|
readonly queryClient?: import('@tanstack/react-query').QueryClient;
|
|
81
81
|
}
|
|
82
|
-
export type {
|
|
82
|
+
export type { ClientConfig, ClientFromRouter, InferProcedureInput, InferProcedureOutput, ProcedureCollection, };
|
package/dist/types.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export type ProcedureType = 'query' | 'mutation';
|
|
|
23
23
|
*
|
|
24
24
|
* @see {@link https://github.com/veloxts/velox-ts-framework/velox | @veloxts/router CompiledProcedure}
|
|
25
25
|
*/
|
|
26
|
-
export interface ClientProcedure<TInput = unknown, TOutput = unknown, TType extends ProcedureType = ProcedureType> {
|
|
26
|
+
export interface ClientProcedure<TInput = unknown, TOutput = unknown, TType extends ProcedureType = ProcedureType, TErrors = never> {
|
|
27
27
|
/** Whether this is a query or mutation */
|
|
28
28
|
readonly type: TType;
|
|
29
29
|
/** The procedure handler function - uses `any` for ctx to enable contravariant matching with CompiledProcedure */
|
|
@@ -53,13 +53,15 @@ export interface ClientProcedure<TInput = unknown, TOutput = unknown, TType exte
|
|
|
53
53
|
resource: string;
|
|
54
54
|
param: string;
|
|
55
55
|
};
|
|
56
|
+
/** Phantom type holder for error types — not used at runtime */
|
|
57
|
+
readonly _errors?: TErrors;
|
|
56
58
|
}
|
|
57
59
|
/**
|
|
58
60
|
* Record of named procedures
|
|
59
61
|
*
|
|
60
62
|
* NOTE: Uses `any` for variance compatibility with @veloxts/router's ProcedureRecord
|
|
61
63
|
*/
|
|
62
|
-
export type ProcedureRecord = Record<string, ClientProcedure<any, any, any>>;
|
|
64
|
+
export type ProcedureRecord = Record<string, ClientProcedure<any, any, any, any>>;
|
|
63
65
|
/**
|
|
64
66
|
* Procedure collection with namespace
|
|
65
67
|
*
|
|
@@ -169,15 +171,39 @@ export type IsTRPCNamespace<T> = T extends Record<string, {
|
|
|
169
171
|
$types: unknown;
|
|
170
172
|
};
|
|
171
173
|
}> ? true : false;
|
|
174
|
+
/**
|
|
175
|
+
* Extracts the error types from a procedure's `_errors` phantom field
|
|
176
|
+
*
|
|
177
|
+
* Returns the TErrors union directly from the phantom. Works with both
|
|
178
|
+
* `CompiledProcedure` and `ClientProcedure`.
|
|
179
|
+
*/
|
|
180
|
+
type ExtractProcedureErrors<T> = T extends {
|
|
181
|
+
readonly _errors?: infer E;
|
|
182
|
+
} ? E : never;
|
|
183
|
+
/**
|
|
184
|
+
* A callable client procedure method with error type information
|
|
185
|
+
*
|
|
186
|
+
* Extends a plain function type with a phantom `_errors` property so that
|
|
187
|
+
* `InferProcedureErrors<typeof client.namespace.method>` can extract the
|
|
188
|
+
* declared domain error types from client callables.
|
|
189
|
+
*
|
|
190
|
+
* @template TInput - The validated input type
|
|
191
|
+
* @template TOutput - The handler output type
|
|
192
|
+
* @template TErrors - Union of domain error types (defaults to never)
|
|
193
|
+
*/
|
|
194
|
+
export type ClientCallable<TInput, TOutput, TErrors = never> = ((input: TInput) => Promise<TOutput>) & {
|
|
195
|
+
readonly _errors?: TErrors;
|
|
196
|
+
};
|
|
172
197
|
/**
|
|
173
198
|
* Builds a callable client interface from a single procedure collection
|
|
174
199
|
*
|
|
175
|
-
* For each procedure, creates a method that:
|
|
200
|
+
* For each procedure, creates a `ClientCallable` method that:
|
|
176
201
|
* - Takes the procedure's input type as parameter
|
|
177
202
|
* - Returns a Promise of the procedure's output type
|
|
203
|
+
* - Carries the procedure's declared error types via a `_errors` phantom
|
|
178
204
|
*/
|
|
179
205
|
export type ClientFromCollection<TCollection extends ProcedureCollection> = {
|
|
180
|
-
[K in keyof TCollection['procedures']]:
|
|
206
|
+
[K in keyof TCollection['procedures']]: ClientCallable<InferProcedureInput<TCollection['procedures'][K]>, InferProcedureOutput<TCollection['procedures'][K]>, ExtractProcedureErrors<TCollection['procedures'][K]>>;
|
|
181
207
|
};
|
|
182
208
|
/**
|
|
183
209
|
* Builds a complete client interface from a router (collection of collections)
|
|
@@ -385,11 +411,60 @@ export interface ClientError extends Error {
|
|
|
385
411
|
code?: string;
|
|
386
412
|
/** Original response body (if available) */
|
|
387
413
|
body?: unknown;
|
|
414
|
+
/**
|
|
415
|
+
* Typed domain error payload, extracted from `body.data` when the response
|
|
416
|
+
* is a DomainError (has a `code` field). Distinct from `body`.
|
|
417
|
+
*/
|
|
418
|
+
data?: unknown;
|
|
388
419
|
/** URL that was requested */
|
|
389
420
|
url: string;
|
|
390
421
|
/** HTTP method used */
|
|
391
422
|
method: string;
|
|
392
423
|
}
|
|
424
|
+
/**
|
|
425
|
+
* Extracts the union of domain error shapes from a procedure or client callable.
|
|
426
|
+
*
|
|
427
|
+
* Supports two extraction paths:
|
|
428
|
+
* 1. **`_errors` phantom** (primary) — extracts `{ code, data }` from the TErrors
|
|
429
|
+
* union carried by `CompiledProcedure`, `ClientProcedure`, or `ClientCallable`.
|
|
430
|
+
* 2. **`errorClasses` constructors** (fallback) — extracts from constructor signatures
|
|
431
|
+
* when the `_errors` phantom is absent or empty.
|
|
432
|
+
*
|
|
433
|
+
* @example From a procedure
|
|
434
|
+
* ```typescript
|
|
435
|
+
* const proc = procedure().throws(InsufficientFundsError, UserBannedError).query(...);
|
|
436
|
+
* type Errors = InferProcedureErrors<typeof proc>;
|
|
437
|
+
* // → { code: 'INSUFFICIENT_FUNDS'; data: { amount: number } }
|
|
438
|
+
* // | { code: 'USER_BANNED'; data: { reason: string } }
|
|
439
|
+
* ```
|
|
440
|
+
*
|
|
441
|
+
* @example From a client callable
|
|
442
|
+
* ```typescript
|
|
443
|
+
* const client = createClient<AppRouter>({ baseUrl: '/api' });
|
|
444
|
+
* type Errors = InferProcedureErrors<typeof client.orders.createOrder>;
|
|
445
|
+
* // Same result — errors are threaded through ClientFromCollection
|
|
446
|
+
* ```
|
|
447
|
+
*/
|
|
448
|
+
export type InferProcedureErrors<T> = _ExtractErrorsFromPhantom<T> extends never ? _ExtractErrorsFromClasses<T> : _ExtractErrorsFromPhantom<T>;
|
|
449
|
+
/** @internal Extracts `{ code, data }` shapes from the `_errors` phantom type */
|
|
450
|
+
type _ExtractErrorsFromPhantom<T> = T extends {
|
|
451
|
+
readonly _errors?: infer E;
|
|
452
|
+
} ? E extends {
|
|
453
|
+
readonly code: infer C;
|
|
454
|
+
readonly data: infer D;
|
|
455
|
+
} ? {
|
|
456
|
+
code: C;
|
|
457
|
+
data: D;
|
|
458
|
+
} : never : never;
|
|
459
|
+
/** @internal Fallback: extracts `{ code, data }` from `errorClasses` constructor signatures */
|
|
460
|
+
type _ExtractErrorsFromClasses<T> = T extends {
|
|
461
|
+
readonly errorClasses?: ReadonlyArray<infer E>;
|
|
462
|
+
} ? E extends new (data: infer D) => {
|
|
463
|
+
code: infer C;
|
|
464
|
+
} ? {
|
|
465
|
+
code: C;
|
|
466
|
+
data: D;
|
|
467
|
+
} : never : never;
|
|
393
468
|
/**
|
|
394
469
|
* Internal representation of a procedure call
|
|
395
470
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veloxts/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Type-safe frontend API client for VeloxTS framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -40,12 +40,12 @@
|
|
|
40
40
|
"@testing-library/react": "16.3.2",
|
|
41
41
|
"@types/react": "19.2.14",
|
|
42
42
|
"@types/react-dom": "19.2.3",
|
|
43
|
-
"@vitest/coverage-v8": "4.0
|
|
44
|
-
"jsdom": "28.
|
|
43
|
+
"@vitest/coverage-v8": "4.1.0",
|
|
44
|
+
"jsdom": "28.1.0",
|
|
45
45
|
"react": "19.2.4",
|
|
46
46
|
"react-dom": "19.2.4",
|
|
47
47
|
"typescript": "5.9.3",
|
|
48
|
-
"vitest": "4.0
|
|
48
|
+
"vitest": "4.1.0"
|
|
49
49
|
},
|
|
50
50
|
"keywords": [
|
|
51
51
|
"velox",
|