@vertz/errors 0.2.14 → 0.2.16
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/dist/index.d.ts +478 -478
- package/dist/index.js +259 -259
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -156,13 +156,13 @@ declare function isRateLimitedError(error: {
|
|
|
156
156
|
interface AuthValidationError {
|
|
157
157
|
readonly code: "AUTH_VALIDATION_ERROR";
|
|
158
158
|
readonly message: string;
|
|
159
|
-
readonly field: "email" | "password";
|
|
159
|
+
readonly field: "email" | "password" | "general";
|
|
160
160
|
readonly constraint?: string;
|
|
161
161
|
}
|
|
162
162
|
/**
|
|
163
163
|
* Creates an AuthValidationError.
|
|
164
164
|
*/
|
|
165
|
-
declare function createAuthValidationError(message: string, field: "email" | "password", constraint?: string): AuthValidationError;
|
|
165
|
+
declare function createAuthValidationError(message: string, field: "email" | "password" | "general", constraint?: string): AuthValidationError;
|
|
166
166
|
/**
|
|
167
167
|
* Type guard for AuthValidationError.
|
|
168
168
|
*/
|
|
@@ -713,380 +713,219 @@ declare function isValidationError2(error: {
|
|
|
713
713
|
readonly code: string;
|
|
714
714
|
}): error is ValidationError3;
|
|
715
715
|
/**
|
|
716
|
-
*
|
|
716
|
+
* Entity error classes.
|
|
717
717
|
*
|
|
718
|
-
* These
|
|
719
|
-
* in business logic. They're caught by global middleware/error boundaries
|
|
720
|
-
* and result in 500/503 responses.
|
|
721
|
-
*/
|
|
722
|
-
/**
|
|
723
|
-
* Base class for infrastructure errors.
|
|
718
|
+
* These errors mirror server HTTP error codes and are used at the HTTP boundary.
|
|
724
719
|
*/
|
|
725
|
-
declare class InfraError extends Error {
|
|
726
|
-
constructor(message: string);
|
|
727
|
-
}
|
|
728
720
|
/**
|
|
729
|
-
*
|
|
721
|
+
* Base class for entity errors.
|
|
730
722
|
*
|
|
731
|
-
*
|
|
723
|
+
* @example
|
|
724
|
+
* import { EntityError } from '@ *
|
|
725
|
+
* // Checkvertz/errors';
|
|
726
|
+
error type
|
|
727
|
+
* if (error instanceof EntityError) {
|
|
728
|
+
* console.log(error.code); // e.g., 'NOT_FOUND'
|
|
729
|
+
* console.log(error.message);
|
|
730
|
+
* }
|
|
732
731
|
*/
|
|
733
|
-
declare class
|
|
734
|
-
|
|
732
|
+
declare abstract class EntityError extends Error {
|
|
733
|
+
/**
|
|
734
|
+
* The error code - a string literal for type-safe discrimination.
|
|
735
|
+
*/
|
|
736
|
+
readonly code: string;
|
|
737
|
+
constructor(code: string, message: string);
|
|
735
738
|
}
|
|
736
739
|
/**
|
|
737
|
-
*
|
|
738
|
-
*
|
|
739
|
-
* Thrown when no connections are available in the pool.
|
|
740
|
+
* Bad request error - 400.
|
|
740
741
|
*/
|
|
741
|
-
declare class
|
|
742
|
+
declare class BadRequestError extends EntityError {
|
|
743
|
+
readonly code: "BadRequest";
|
|
742
744
|
constructor(message?: string);
|
|
743
745
|
}
|
|
744
746
|
/**
|
|
745
|
-
*
|
|
746
|
-
*
|
|
747
|
-
* Thrown when a query fails (malformed, syntax error, etc.).
|
|
747
|
+
* Type guard for BadRequestError.
|
|
748
748
|
*/
|
|
749
|
-
declare
|
|
750
|
-
constructor(message?: string);
|
|
751
|
-
}
|
|
749
|
+
declare function isBadRequestError(error: unknown): error is BadRequestError;
|
|
752
750
|
/**
|
|
753
|
-
*
|
|
754
|
-
*
|
|
755
|
-
* Thrown when an operation takes too long.
|
|
751
|
+
* Unauthorized error - 401.
|
|
756
752
|
*/
|
|
757
|
-
declare class
|
|
753
|
+
declare class EntityUnauthorizedError extends EntityError {
|
|
754
|
+
readonly code: "Unauthorized";
|
|
758
755
|
constructor(message?: string);
|
|
759
756
|
}
|
|
760
757
|
/**
|
|
761
|
-
*
|
|
762
|
-
*
|
|
763
|
-
* Thrown when HTTP client can't reach the server.
|
|
758
|
+
* Type guard for EntityUnauthorizedError.
|
|
764
759
|
*/
|
|
765
|
-
declare
|
|
766
|
-
constructor(message?: string);
|
|
767
|
-
}
|
|
760
|
+
declare function isEntityUnauthorizedError(error: unknown): error is EntityUnauthorizedError;
|
|
768
761
|
/**
|
|
769
|
-
*
|
|
770
|
-
*
|
|
771
|
-
* Thrown when response couldn't be decoded.
|
|
762
|
+
* Forbidden error - 403.
|
|
772
763
|
*/
|
|
773
|
-
declare class
|
|
764
|
+
declare class EntityForbiddenError extends EntityError {
|
|
765
|
+
readonly code: "Forbidden";
|
|
774
766
|
constructor(message?: string);
|
|
775
767
|
}
|
|
776
768
|
/**
|
|
777
|
-
*
|
|
769
|
+
* Type guard for EntityForbiddenError.
|
|
778
770
|
*/
|
|
779
|
-
|
|
771
|
+
declare function isEntityForbiddenError(error: unknown): error is EntityForbiddenError;
|
|
780
772
|
/**
|
|
781
|
-
*
|
|
773
|
+
* Not found error - 404.
|
|
782
774
|
*
|
|
783
|
-
* @
|
|
784
|
-
*
|
|
775
|
+
* @example
|
|
776
|
+
* // Using in matchError for server-side error handling
|
|
777
|
+
* const result = await db.users.get(userId);
|
|
778
|
+
* if (!result.ok) {
|
|
779
|
+
* return matchError(result.error, {
|
|
780
|
+
* NOT_FOUND: (e) => Response.json(
|
|
781
|
+
* { error: { code: 'NOT_FOUND', message: `User ${userId} not found` } },
|
|
782
|
+
* { status: 404 }
|
|
783
|
+
* ),
|
|
784
|
+
* // ... other handlers
|
|
785
|
+
* });
|
|
786
|
+
* }
|
|
785
787
|
*
|
|
786
788
|
* @example
|
|
787
|
-
*
|
|
788
|
-
*
|
|
789
|
-
* // UNIQUE_VIOLATION → 409
|
|
790
|
-
* // FK_VIOLATION → 422
|
|
791
|
-
* // NOT_NULL_VIOLATION → 422
|
|
792
|
-
* // CHECK_VIOLATION → 422
|
|
793
|
-
*/
|
|
794
|
-
declare function dbErrorToHttpStatus(error: ReadError | WriteError): number;
|
|
795
|
-
/**
|
|
796
|
-
* Maps a NotFoundError to HTTP status.
|
|
797
|
-
*/
|
|
798
|
-
declare function notFoundErrorToHttpStatus(_error: NotFoundError2): number;
|
|
799
|
-
/**
|
|
800
|
-
* Maps a UniqueViolation to HTTP status.
|
|
801
|
-
*/
|
|
802
|
-
declare function uniqueViolationToHttpStatus(_error: UniqueViolation): number;
|
|
803
|
-
/**
|
|
804
|
-
* Maps a FKViolation to HTTP status.
|
|
805
|
-
*/
|
|
806
|
-
declare function fkViolationToHttpStatus(_error: FKViolation): number;
|
|
807
|
-
/**
|
|
808
|
-
* Maps a NotNullViolation to HTTP status.
|
|
809
|
-
*/
|
|
810
|
-
declare function notNullViolationToHttpStatus(_error: NotNullViolation): number;
|
|
811
|
-
/**
|
|
812
|
-
* Maps a CheckViolation to HTTP status.
|
|
813
|
-
*/
|
|
814
|
-
declare function checkViolationToHttpStatus(_error: CheckViolation): number;
|
|
815
|
-
/**
|
|
816
|
-
* Unknown error response from server.
|
|
789
|
+
* // With resource info
|
|
790
|
+
* throw new EntityNotFoundError('User not found', 'User', userId);
|
|
817
791
|
*/
|
|
818
|
-
|
|
819
|
-
readonly code: "
|
|
820
|
-
|
|
821
|
-
|
|
792
|
+
declare class EntityNotFoundError extends EntityError {
|
|
793
|
+
readonly code: "NotFound";
|
|
794
|
+
/**
|
|
795
|
+
* The type of resource that wasn't found.
|
|
796
|
+
*/
|
|
797
|
+
readonly resource?: string;
|
|
798
|
+
/**
|
|
799
|
+
* The ID of the resource that wasn't found.
|
|
800
|
+
*/
|
|
801
|
+
readonly resourceId?: string;
|
|
802
|
+
constructor(message?: string, resource?: string, resourceId?: string);
|
|
822
803
|
}
|
|
823
804
|
/**
|
|
824
|
-
*
|
|
825
|
-
*
|
|
826
|
-
* @param status - HTTP status code
|
|
827
|
-
* @param body - Response body
|
|
828
|
-
* @returns Client domain error
|
|
829
|
-
*
|
|
830
|
-
* @example
|
|
831
|
-
* const error = httpToClientError(404, { message: 'User not found' });
|
|
832
|
-
* // { code: 'NOT_FOUND', message: 'User not found', resource: 'user' }
|
|
805
|
+
* Type guard for EntityNotFoundError.
|
|
833
806
|
*/
|
|
834
|
-
declare function
|
|
807
|
+
declare function isEntityNotFoundError(error: unknown): error is EntityNotFoundError;
|
|
835
808
|
/**
|
|
836
|
-
*
|
|
809
|
+
* Method not allowed error - 405.
|
|
837
810
|
*/
|
|
838
|
-
declare
|
|
811
|
+
declare class MethodNotAllowedError extends EntityError {
|
|
812
|
+
readonly code: "MethodNotAllowed";
|
|
813
|
+
/**
|
|
814
|
+
* Allowed HTTP methods.
|
|
815
|
+
*/
|
|
816
|
+
readonly allowedMethods?: string;
|
|
817
|
+
constructor(allowedMethods?: string, message?: string);
|
|
818
|
+
}
|
|
839
819
|
/**
|
|
840
|
-
*
|
|
841
|
-
*
|
|
842
|
-
* This module provides a type-safe alternative to throwing exceptions.
|
|
843
|
-
* Every operation that can fail returns a Result<T, E> instead of throwing.
|
|
844
|
-
*
|
|
845
|
-
* @example
|
|
846
|
-
* import { ok, err, unwrap, map, flatMap, match, matchErr } from '@vertz/errors';
|
|
847
|
-
*
|
|
848
|
-
* // Creating results
|
|
849
|
-
* const success = ok({ name: 'Alice' });
|
|
850
|
-
* const failure = err({ code: 'NOT_FOUND', message: 'User not found' });
|
|
851
|
-
*
|
|
852
|
-
* // Transforming
|
|
853
|
-
* const doubled = map(ok(5), x => x * 2);
|
|
854
|
-
*
|
|
855
|
-
* // Chaining
|
|
856
|
-
* const result = await flatMap(ok(5), async x => ok(x * 2));
|
|
857
|
-
*
|
|
858
|
-
* // Pattern matching
|
|
859
|
-
* const message = match(result, {
|
|
860
|
-
* ok: (data) => `Success: ${data}`,
|
|
861
|
-
* err: (error) => `Error: ${error.message}`
|
|
862
|
-
* });
|
|
820
|
+
* Type guard for MethodNotAllowedError.
|
|
863
821
|
*/
|
|
822
|
+
declare function isMethodNotAllowedError(error: unknown): error is MethodNotAllowedError;
|
|
864
823
|
/**
|
|
865
|
-
*
|
|
866
|
-
*
|
|
867
|
-
* @example
|
|
868
|
-
* { ok: true, data: { name: 'Alice' } }
|
|
824
|
+
* Conflict error - 409.
|
|
869
825
|
*/
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
826
|
+
declare class EntityConflictError extends EntityError {
|
|
827
|
+
readonly code: "Conflict";
|
|
828
|
+
/**
|
|
829
|
+
* The field that caused the conflict.
|
|
830
|
+
*/
|
|
831
|
+
readonly field?: string;
|
|
832
|
+
constructor(message?: string, field?: string);
|
|
875
833
|
}
|
|
876
834
|
/**
|
|
877
|
-
*
|
|
878
|
-
*
|
|
879
|
-
* @example
|
|
880
|
-
* { ok: false, error: { code: 'NOT_FOUND', message: 'User not found' } }
|
|
835
|
+
* Type guard for EntityConflictError.
|
|
881
836
|
*/
|
|
882
|
-
|
|
883
|
-
/** Always false for error results */
|
|
884
|
-
readonly ok: false;
|
|
885
|
-
/** The error value */
|
|
886
|
-
readonly error: E;
|
|
887
|
-
}
|
|
837
|
+
declare function isEntityConflictError(error: unknown): error is EntityConflictError;
|
|
888
838
|
/**
|
|
889
|
-
*
|
|
839
|
+
* Entity validation error - 422.
|
|
890
840
|
*
|
|
891
841
|
* @example
|
|
892
|
-
*
|
|
893
|
-
*
|
|
842
|
+
* // Server-side: throwing validation errors
|
|
843
|
+
* throw new EntityValidationError([
|
|
844
|
+
* { path: ['email'], message: 'Invalid email format', code: 'INVALID_FORMAT' },
|
|
845
|
+
* { path: ['age'], message: 'Must be positive', code: 'MIN_VALUE' },
|
|
846
|
+
* ]);
|
|
894
847
|
*
|
|
895
848
|
* @example
|
|
896
|
-
*
|
|
897
|
-
* if (result.ok) {
|
|
898
|
-
*
|
|
899
|
-
*
|
|
900
|
-
*
|
|
849
|
+
* // Server-side: handling in HTTP response
|
|
850
|
+
* if (!result.ok) {
|
|
851
|
+
* return matchError(result.error, {
|
|
852
|
+
* ENTITY_VALIDATION_ERROR: (e) => Response.json(
|
|
853
|
+
* { error: { code: 'VALIDATION_ERROR', message: 'Validation failed', errors: e.errors } },
|
|
854
|
+
* { status: 422 }
|
|
855
|
+
* ),
|
|
856
|
+
* // ... other handlers
|
|
857
|
+
* });
|
|
901
858
|
* }
|
|
902
859
|
*/
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
/**
|
|
920
|
-
* Creates an error Result.
|
|
921
|
-
*
|
|
922
|
-
* @example
|
|
923
|
-
* const result = err({ code: 'VALIDATION_FAILED', message: 'Invalid email', issues: [] });
|
|
924
|
-
* // { ok: false, error: { code: 'VALIDATION_FAILED', ... } }
|
|
925
|
-
*
|
|
926
|
-
* @example
|
|
927
|
-
* // With simple string errors
|
|
928
|
-
* const result = err('Something went wrong');
|
|
929
|
-
* // { ok: false, error: 'Something went wrong' }
|
|
930
|
-
*/
|
|
931
|
-
declare const err: <E>(error: E) => Err<E>;
|
|
932
|
-
/**
|
|
933
|
-
* Unwraps a Result, throwing if error.
|
|
934
|
-
*
|
|
935
|
-
* Use only in tests, scripts, or when failure is truly exceptional.
|
|
936
|
-
*
|
|
937
|
-
* @example
|
|
938
|
-
* // Tests
|
|
939
|
-
* const user = unwrap(await repo.findOneRequired(id));
|
|
940
|
-
*
|
|
941
|
-
* @example
|
|
942
|
-
* // Scripts
|
|
943
|
-
* const config = unwrap(parseConfig());
|
|
944
|
-
*
|
|
945
|
-
* @throws The error value if the Result is an error
|
|
946
|
-
*/
|
|
947
|
-
declare function unwrap<
|
|
948
|
-
T,
|
|
949
|
-
E
|
|
950
|
-
>(result: Result<T, E>): T;
|
|
951
|
-
/**
|
|
952
|
-
* Unwraps a Result, returning a default value if error.
|
|
953
|
-
*
|
|
954
|
-
* @example
|
|
955
|
-
* const user = await findById(id) ?? { name: 'Guest' };
|
|
956
|
-
*/
|
|
957
|
-
declare function unwrapOr<
|
|
958
|
-
T,
|
|
959
|
-
E
|
|
960
|
-
>(result: Result<T, E>, defaultValue: T): T;
|
|
961
|
-
/**
|
|
962
|
-
* Maps the success value to a new type.
|
|
963
|
-
*
|
|
964
|
-
* @example
|
|
965
|
-
* const userName = map(userResult, u => u.name);
|
|
966
|
-
* // Result<string, Error> if userResult was Result<User, Error>
|
|
967
|
-
*
|
|
968
|
-
* @example
|
|
969
|
-
* // Transform while preserving error type
|
|
970
|
-
* const id = map(ok({ userId: 5 }), u => u.userId);
|
|
971
|
-
* // Ok<number>
|
|
972
|
-
*/
|
|
973
|
-
declare function map<
|
|
974
|
-
T,
|
|
975
|
-
E,
|
|
976
|
-
U
|
|
977
|
-
>(result: Result<T, E>, fn: (data: T) => U): Result<U, E>;
|
|
860
|
+
declare class EntityValidationError extends EntityError {
|
|
861
|
+
readonly code: "ValidationError";
|
|
862
|
+
/**
|
|
863
|
+
* Validation errors.
|
|
864
|
+
*/
|
|
865
|
+
readonly errors: readonly {
|
|
866
|
+
readonly path: readonly (string | number)[];
|
|
867
|
+
readonly message: string;
|
|
868
|
+
readonly code: string;
|
|
869
|
+
}[];
|
|
870
|
+
constructor(errors: readonly {
|
|
871
|
+
readonly path: readonly (string | number)[];
|
|
872
|
+
readonly message: string;
|
|
873
|
+
readonly code: string;
|
|
874
|
+
}[]);
|
|
875
|
+
}
|
|
978
876
|
/**
|
|
979
|
-
*
|
|
980
|
-
*
|
|
981
|
-
* Allows chaining operations that can fail without nested try/catch.
|
|
982
|
-
*
|
|
983
|
-
* @example
|
|
984
|
-
* // Synchronous
|
|
985
|
-
* const profile = flatMap(
|
|
986
|
-
* await repo.findOne(userId),
|
|
987
|
-
* (user) => profileRepo.findOne(user.profileId)
|
|
988
|
-
* );
|
|
989
|
-
*
|
|
990
|
-
* @example
|
|
991
|
-
* // Asynchronous
|
|
992
|
-
* const finalResult = await flatMap(
|
|
993
|
-
* await repo.findOne(userId),
|
|
994
|
-
* async (user) => await profileRepo.findOne(user.profileId)
|
|
995
|
-
* );
|
|
877
|
+
* Type guard for EntityValidationError.
|
|
996
878
|
*/
|
|
997
|
-
declare function
|
|
998
|
-
T,
|
|
999
|
-
E,
|
|
1000
|
-
U,
|
|
1001
|
-
F
|
|
1002
|
-
>(result: Result<T, E>, fn: (data: T) => Result<U, F>): Result<U, E | F>;
|
|
1003
|
-
declare function flatMap<
|
|
1004
|
-
T,
|
|
1005
|
-
E,
|
|
1006
|
-
U,
|
|
1007
|
-
F
|
|
1008
|
-
>(result: Result<T, E>, fn: (data: T) => Promise<Result<U, F>>): Promise<Result<U, E | F>>;
|
|
879
|
+
declare function isEntityValidationError(error: unknown): error is EntityValidationError;
|
|
1009
880
|
/**
|
|
1010
|
-
*
|
|
1011
|
-
*
|
|
1012
|
-
* @example
|
|
1013
|
-
* const message = match(result, {
|
|
1014
|
-
* ok: (user) => \`Hello, \${user.name}!\`,
|
|
1015
|
-
* err: (e) => \`Error: \${e.message}\`
|
|
1016
|
-
* });
|
|
881
|
+
* Internal server error - 500.
|
|
1017
882
|
*/
|
|
1018
|
-
declare
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
ErrR
|
|
1023
|
-
>(result: Result<T, E>, handlers: {
|
|
1024
|
-
ok: (data: T) => OkR;
|
|
1025
|
-
err: (error: E) => ErrR;
|
|
1026
|
-
}): OkR | ErrR;
|
|
883
|
+
declare class InternalError2 extends EntityError {
|
|
884
|
+
readonly code: "InternalError";
|
|
885
|
+
constructor(message?: string);
|
|
886
|
+
}
|
|
1027
887
|
/**
|
|
1028
|
-
* Type for
|
|
1029
|
-
* Extracts error codes from an error union and creates a handler map.
|
|
888
|
+
* Type guard for InternalError.
|
|
1030
889
|
*/
|
|
1031
|
-
|
|
1032
|
-
E,
|
|
1033
|
-
R
|
|
1034
|
-
> = { [K in E as K extends {
|
|
1035
|
-
readonly code: infer C extends string;
|
|
1036
|
-
} ? C : never] : (error: K) => R };
|
|
890
|
+
declare function isInternalError(error: unknown): error is InternalError2;
|
|
1037
891
|
/**
|
|
1038
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
* Unlike `match()` which gives you a single `err` handler,
|
|
1041
|
-
* `matchErr` requires a handler for every error type in the union.
|
|
1042
|
-
* The compiler enforces exhaustiveness — add a new error type to the union
|
|
1043
|
-
* and every callsite lights up until you handle it.
|
|
1044
|
-
*
|
|
1045
|
-
* Errors are discriminated by their `code` string literal field.
|
|
1046
|
-
*
|
|
1047
|
-
* @example
|
|
1048
|
-
* const response = matchErr(result, {
|
|
1049
|
-
* ok: (user) => json({ data: user }, 201),
|
|
1050
|
-
* NOT_FOUND: (e) => json({ error: 'NOT_FOUND', message: e.message }, 404),
|
|
1051
|
-
* UNIQUE_VIOLATION: (e) => json({ error: 'EMAIL_EXISTS', field: e.column }, 409),
|
|
1052
|
-
* });
|
|
1053
|
-
* // ^ Compile error if error union adds a new member you didn't handle
|
|
1054
|
-
*
|
|
1055
|
-
* @throws Error if an error code is not handled
|
|
892
|
+
* Service unavailable error - 503.
|
|
1056
893
|
*/
|
|
1057
|
-
declare
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
} & ErrorHandlers<E, R>): R;
|
|
894
|
+
declare class ServiceUnavailableError extends EntityError {
|
|
895
|
+
readonly code: "ServiceUnavailable";
|
|
896
|
+
/**
|
|
897
|
+
* Seconds until retry.
|
|
898
|
+
*/
|
|
899
|
+
readonly retryAfter?: number;
|
|
900
|
+
constructor(message?: string, retryAfter?: number);
|
|
901
|
+
}
|
|
1066
902
|
/**
|
|
1067
|
-
* Type guard for
|
|
1068
|
-
*
|
|
1069
|
-
* @example
|
|
1070
|
-
* if (isOk(result)) {
|
|
1071
|
-
* console.log(result.data); // TypeScript knows this is T
|
|
1072
|
-
* }
|
|
903
|
+
* Type guard for ServiceUnavailableError.
|
|
1073
904
|
*/
|
|
1074
|
-
declare function
|
|
1075
|
-
T,
|
|
1076
|
-
E
|
|
1077
|
-
>(result: Result<T, E>): result is Ok<T>;
|
|
905
|
+
declare function isServiceUnavailableError(error: unknown): error is ServiceUnavailableError;
|
|
1078
906
|
/**
|
|
1079
|
-
*
|
|
907
|
+
* Union type for all entity errors.
|
|
1080
908
|
*
|
|
1081
909
|
* @example
|
|
1082
|
-
*
|
|
1083
|
-
*
|
|
910
|
+
* import { matchError, EntityErrorType } from '@vertz/errors';
|
|
911
|
+
*
|
|
912
|
+
* // Server-side: handling database errors
|
|
913
|
+
* const result = await db.users.create(data);
|
|
914
|
+
* if (!result.ok) {
|
|
915
|
+
* return matchError(result.error, {
|
|
916
|
+
* BAD_REQUEST: (e) => Response.json({ error: e.message }, { status: 400 }),
|
|
917
|
+
* UNAUTHORIZED: () => Response.json({ error: 'Unauthorized' }, { status: 401 }),
|
|
918
|
+
* FORBIDDEN: () => Response.json({ error: 'Forbidden' }, { status: 403 }),
|
|
919
|
+
* NOT_FOUND: (e) => Response.json({ error: e.message }, { status: 404 }),
|
|
920
|
+
* METHOD_NOT_ALLOWED: () => Response.json({ error: 'Method not allowed' }, { status: 405 }),
|
|
921
|
+
* CONFLICT: (e) => Response.json({ error: e.message }, { status: 409 }),
|
|
922
|
+
* ENTITY_VALIDATION_ERROR: (e) => Response.json({ error: e.errors }, { status: 422 }),
|
|
923
|
+
* INTERNAL_ERROR: () => Response.json({ error: 'Internal error' }, { status: 500 }),
|
|
924
|
+
* SERVICE_UNAVAILABLE: () => Response.json({ error: 'Service unavailable' }, { status: 503 }),
|
|
925
|
+
* });
|
|
1084
926
|
* }
|
|
1085
927
|
*/
|
|
1086
|
-
|
|
1087
|
-
T,
|
|
1088
|
-
E
|
|
1089
|
-
>(result: Result<T, E>): result is Err<E>;
|
|
928
|
+
type EntityErrorType = BadRequestError | EntityUnauthorizedError | EntityForbiddenError | EntityNotFoundError | MethodNotAllowedError | EntityConflictError | EntityValidationError | InternalError2 | ServiceUnavailableError;
|
|
1090
929
|
/**
|
|
1091
930
|
* Fetch error classes.
|
|
1092
931
|
*
|
|
@@ -1383,219 +1222,129 @@ declare function createHttpError(status: number, message: string, serverCode?: s
|
|
|
1383
1222
|
*/
|
|
1384
1223
|
type FetchErrorType = FetchNetworkError | HttpError2 | FetchBadRequestError | FetchUnauthorizedError | FetchForbiddenError | FetchNotFoundError | FetchConflictError | FetchGoneError | FetchUnprocessableEntityError | FetchRateLimitError | FetchInternalServerError | FetchServiceUnavailableError | FetchTimeoutError | ParseError2 | FetchValidationError;
|
|
1385
1224
|
/**
|
|
1386
|
-
*
|
|
1225
|
+
* Infrastructure errors.
|
|
1387
1226
|
*
|
|
1388
|
-
* These
|
|
1227
|
+
* These are operational failures that the application developer never handles
|
|
1228
|
+
* in business logic. They're caught by global middleware/error boundaries
|
|
1229
|
+
* and result in 500/503 responses.
|
|
1389
1230
|
*/
|
|
1390
1231
|
/**
|
|
1391
|
-
* Base class for
|
|
1392
|
-
*
|
|
1393
|
-
* @example
|
|
1394
|
-
* import { EntityError } from '@ *
|
|
1395
|
-
* // Checkvertz/errors';
|
|
1396
|
-
error type
|
|
1397
|
-
* if (error instanceof EntityError) {
|
|
1398
|
-
* console.log(error.code); // e.g., 'NOT_FOUND'
|
|
1399
|
-
* console.log(error.message);
|
|
1400
|
-
* }
|
|
1232
|
+
* Base class for infrastructure errors.
|
|
1401
1233
|
*/
|
|
1402
|
-
declare
|
|
1403
|
-
|
|
1404
|
-
* The error code - a string literal for type-safe discrimination.
|
|
1405
|
-
*/
|
|
1406
|
-
readonly code: string;
|
|
1407
|
-
constructor(code: string, message: string);
|
|
1234
|
+
declare class InfraError extends Error {
|
|
1235
|
+
constructor(message: string);
|
|
1408
1236
|
}
|
|
1409
1237
|
/**
|
|
1410
|
-
*
|
|
1238
|
+
* Database connection error.
|
|
1239
|
+
*
|
|
1240
|
+
* Thrown when the database is unreachable.
|
|
1411
1241
|
*/
|
|
1412
|
-
declare class
|
|
1413
|
-
readonly code: "BadRequest";
|
|
1242
|
+
declare class ConnectionError extends InfraError {
|
|
1414
1243
|
constructor(message?: string);
|
|
1415
1244
|
}
|
|
1416
1245
|
/**
|
|
1417
|
-
*
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
/**
|
|
1421
|
-
* Unauthorized error - 401.
|
|
1246
|
+
* Connection pool exhausted error.
|
|
1247
|
+
*
|
|
1248
|
+
* Thrown when no connections are available in the pool.
|
|
1422
1249
|
*/
|
|
1423
|
-
declare class
|
|
1424
|
-
readonly code: "Unauthorized";
|
|
1250
|
+
declare class PoolExhaustedError extends InfraError {
|
|
1425
1251
|
constructor(message?: string);
|
|
1426
1252
|
}
|
|
1427
1253
|
/**
|
|
1428
|
-
*
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
/**
|
|
1432
|
-
* Forbidden error - 403.
|
|
1254
|
+
* Query error.
|
|
1255
|
+
*
|
|
1256
|
+
* Thrown when a query fails (malformed, syntax error, etc.).
|
|
1433
1257
|
*/
|
|
1434
|
-
declare class
|
|
1435
|
-
readonly code: "Forbidden";
|
|
1258
|
+
declare class QueryError extends InfraError {
|
|
1436
1259
|
constructor(message?: string);
|
|
1437
1260
|
}
|
|
1438
1261
|
/**
|
|
1439
|
-
*
|
|
1440
|
-
*/
|
|
1441
|
-
declare function isEntityForbiddenError(error: unknown): error is EntityForbiddenError;
|
|
1442
|
-
/**
|
|
1443
|
-
* Not found error - 404.
|
|
1444
|
-
*
|
|
1445
|
-
* @example
|
|
1446
|
-
* // Using in matchError for server-side error handling
|
|
1447
|
-
* const result = await db.users.get(userId);
|
|
1448
|
-
* if (!result.ok) {
|
|
1449
|
-
* return matchError(result.error, {
|
|
1450
|
-
* NOT_FOUND: (e) => Response.json(
|
|
1451
|
-
* { error: { code: 'NOT_FOUND', message: `User ${userId} not found` } },
|
|
1452
|
-
* { status: 404 }
|
|
1453
|
-
* ),
|
|
1454
|
-
* // ... other handlers
|
|
1455
|
-
* });
|
|
1456
|
-
* }
|
|
1262
|
+
* Timeout error.
|
|
1457
1263
|
*
|
|
1458
|
-
*
|
|
1459
|
-
* // With resource info
|
|
1460
|
-
* throw new EntityNotFoundError('User not found', 'User', userId);
|
|
1264
|
+
* Thrown when an operation takes too long.
|
|
1461
1265
|
*/
|
|
1462
|
-
declare class
|
|
1463
|
-
|
|
1464
|
-
/**
|
|
1465
|
-
* The type of resource that wasn't found.
|
|
1466
|
-
*/
|
|
1467
|
-
readonly resource?: string;
|
|
1468
|
-
/**
|
|
1469
|
-
* The ID of the resource that wasn't found.
|
|
1470
|
-
*/
|
|
1471
|
-
readonly resourceId?: string;
|
|
1472
|
-
constructor(message?: string, resource?: string, resourceId?: string);
|
|
1266
|
+
declare class TimeoutError2 extends InfraError {
|
|
1267
|
+
constructor(message?: string);
|
|
1473
1268
|
}
|
|
1474
1269
|
/**
|
|
1475
|
-
*
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
/**
|
|
1479
|
-
* Method not allowed error - 405.
|
|
1270
|
+
* Network error.
|
|
1271
|
+
*
|
|
1272
|
+
* Thrown when HTTP client can't reach the server.
|
|
1480
1273
|
*/
|
|
1481
|
-
declare class
|
|
1482
|
-
|
|
1483
|
-
/**
|
|
1484
|
-
* Allowed HTTP methods.
|
|
1485
|
-
*/
|
|
1486
|
-
readonly allowedMethods?: string;
|
|
1487
|
-
constructor(allowedMethods?: string, message?: string);
|
|
1274
|
+
declare class NetworkError2 extends InfraError {
|
|
1275
|
+
constructor(message?: string);
|
|
1488
1276
|
}
|
|
1489
1277
|
/**
|
|
1490
|
-
*
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
/**
|
|
1494
|
-
* Conflict error - 409.
|
|
1278
|
+
* Serialization error.
|
|
1279
|
+
*
|
|
1280
|
+
* Thrown when response couldn't be decoded.
|
|
1495
1281
|
*/
|
|
1496
|
-
declare class
|
|
1497
|
-
|
|
1498
|
-
/**
|
|
1499
|
-
* The field that caused the conflict.
|
|
1500
|
-
*/
|
|
1501
|
-
readonly field?: string;
|
|
1502
|
-
constructor(message?: string, field?: string);
|
|
1282
|
+
declare class SerializationError extends InfraError {
|
|
1283
|
+
constructor(message?: string);
|
|
1503
1284
|
}
|
|
1504
1285
|
/**
|
|
1505
|
-
*
|
|
1286
|
+
* Union type for all infrastructure errors.
|
|
1506
1287
|
*/
|
|
1507
|
-
|
|
1288
|
+
type InfraErrors = ConnectionError | PoolExhaustedError | QueryError | TimeoutError2 | NetworkError2 | SerializationError;
|
|
1508
1289
|
/**
|
|
1509
|
-
*
|
|
1290
|
+
* Maps a database error to an HTTP status code.
|
|
1510
1291
|
*
|
|
1511
|
-
* @
|
|
1512
|
-
*
|
|
1513
|
-
* throw new EntityValidationError([
|
|
1514
|
-
* { path: ['email'], message: 'Invalid email format', code: 'INVALID_FORMAT' },
|
|
1515
|
-
* { path: ['age'], message: 'Must be positive', code: 'MIN_VALUE' },
|
|
1516
|
-
* ]);
|
|
1292
|
+
* @param error - A database domain error
|
|
1293
|
+
* @returns HTTP status code
|
|
1517
1294
|
*
|
|
1518
1295
|
* @example
|
|
1519
|
-
*
|
|
1520
|
-
*
|
|
1521
|
-
*
|
|
1522
|
-
*
|
|
1523
|
-
*
|
|
1524
|
-
*
|
|
1525
|
-
* ),
|
|
1526
|
-
* // ... other handlers
|
|
1527
|
-
* });
|
|
1528
|
-
* }
|
|
1296
|
+
* const status = dbErrorToHttpStatus(error);
|
|
1297
|
+
* // NOT_FOUND → 404
|
|
1298
|
+
* // UNIQUE_VIOLATION → 409
|
|
1299
|
+
* // FK_VIOLATION → 422
|
|
1300
|
+
* // NOT_NULL_VIOLATION → 422
|
|
1301
|
+
* // CHECK_VIOLATION → 422
|
|
1529
1302
|
*/
|
|
1530
|
-
declare
|
|
1531
|
-
readonly code: "ValidationError";
|
|
1532
|
-
/**
|
|
1533
|
-
* Validation errors.
|
|
1534
|
-
*/
|
|
1535
|
-
readonly errors: readonly {
|
|
1536
|
-
readonly path: readonly (string | number)[];
|
|
1537
|
-
readonly message: string;
|
|
1538
|
-
readonly code: string;
|
|
1539
|
-
}[];
|
|
1540
|
-
constructor(errors: readonly {
|
|
1541
|
-
readonly path: readonly (string | number)[];
|
|
1542
|
-
readonly message: string;
|
|
1543
|
-
readonly code: string;
|
|
1544
|
-
}[]);
|
|
1545
|
-
}
|
|
1303
|
+
declare function dbErrorToHttpStatus(error: ReadError | WriteError): number;
|
|
1546
1304
|
/**
|
|
1547
|
-
*
|
|
1305
|
+
* Maps a NotFoundError to HTTP status.
|
|
1548
1306
|
*/
|
|
1549
|
-
declare function
|
|
1307
|
+
declare function notFoundErrorToHttpStatus(_error: NotFoundError2): number;
|
|
1550
1308
|
/**
|
|
1551
|
-
*
|
|
1309
|
+
* Maps a UniqueViolation to HTTP status.
|
|
1552
1310
|
*/
|
|
1553
|
-
declare
|
|
1554
|
-
readonly code: "InternalError";
|
|
1555
|
-
constructor(message?: string);
|
|
1556
|
-
}
|
|
1311
|
+
declare function uniqueViolationToHttpStatus(_error: UniqueViolation): number;
|
|
1557
1312
|
/**
|
|
1558
|
-
*
|
|
1313
|
+
* Maps a FKViolation to HTTP status.
|
|
1559
1314
|
*/
|
|
1560
|
-
declare function
|
|
1315
|
+
declare function fkViolationToHttpStatus(_error: FKViolation): number;
|
|
1561
1316
|
/**
|
|
1562
|
-
*
|
|
1317
|
+
* Maps a NotNullViolation to HTTP status.
|
|
1563
1318
|
*/
|
|
1564
|
-
declare
|
|
1565
|
-
readonly code: "ServiceUnavailable";
|
|
1566
|
-
/**
|
|
1567
|
-
* Seconds until retry.
|
|
1568
|
-
*/
|
|
1569
|
-
readonly retryAfter?: number;
|
|
1570
|
-
constructor(message?: string, retryAfter?: number);
|
|
1571
|
-
}
|
|
1319
|
+
declare function notNullViolationToHttpStatus(_error: NotNullViolation): number;
|
|
1572
1320
|
/**
|
|
1573
|
-
*
|
|
1321
|
+
* Maps a CheckViolation to HTTP status.
|
|
1574
1322
|
*/
|
|
1575
|
-
declare function
|
|
1323
|
+
declare function checkViolationToHttpStatus(_error: CheckViolation): number;
|
|
1576
1324
|
/**
|
|
1577
|
-
*
|
|
1325
|
+
* Unknown error response from server.
|
|
1326
|
+
*/
|
|
1327
|
+
interface UnknownError {
|
|
1328
|
+
readonly code: "UNKNOWN";
|
|
1329
|
+
readonly message: string;
|
|
1330
|
+
readonly status: number;
|
|
1331
|
+
}
|
|
1332
|
+
/**
|
|
1333
|
+
* Maps an HTTP response to a client domain error.
|
|
1578
1334
|
*
|
|
1579
|
-
* @
|
|
1580
|
-
*
|
|
1335
|
+
* @param status - HTTP status code
|
|
1336
|
+
* @param body - Response body
|
|
1337
|
+
* @returns Client domain error
|
|
1581
1338
|
*
|
|
1582
|
-
*
|
|
1583
|
-
* const
|
|
1584
|
-
*
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
*
|
|
1589
|
-
* NOT_FOUND: (e) => Response.json({ error: e.message }, { status: 404 }),
|
|
1590
|
-
* METHOD_NOT_ALLOWED: () => Response.json({ error: 'Method not allowed' }, { status: 405 }),
|
|
1591
|
-
* CONFLICT: (e) => Response.json({ error: e.message }, { status: 409 }),
|
|
1592
|
-
* ENTITY_VALIDATION_ERROR: (e) => Response.json({ error: e.errors }, { status: 422 }),
|
|
1593
|
-
* INTERNAL_ERROR: () => Response.json({ error: 'Internal error' }, { status: 500 }),
|
|
1594
|
-
* SERVICE_UNAVAILABLE: () => Response.json({ error: 'Service unavailable' }, { status: 503 }),
|
|
1595
|
-
* });
|
|
1596
|
-
* }
|
|
1339
|
+
* @example
|
|
1340
|
+
* const error = httpToClientError(404, { message: 'User not found' });
|
|
1341
|
+
* // { code: 'NOT_FOUND', message: 'User not found', resource: 'user' }
|
|
1342
|
+
*/
|
|
1343
|
+
declare function httpToClientError(status: number, body: unknown): ApiError | UnknownError;
|
|
1344
|
+
/**
|
|
1345
|
+
* Checks if an error is an UnknownError.
|
|
1597
1346
|
*/
|
|
1598
|
-
|
|
1347
|
+
declare function isUnknownError(error: ApiError | UnknownError): error is UnknownError;
|
|
1599
1348
|
/**
|
|
1600
1349
|
* Handler map type for FetchError.
|
|
1601
1350
|
* Each key corresponds to an error code, and the value is a handler function.
|
|
@@ -1666,4 +1415,255 @@ type EntityErrorHandlers<R> = {
|
|
|
1666
1415
|
*/
|
|
1667
1416
|
declare function matchError<R>(error: FetchErrorType, handlers: FetchErrorHandlers<R>): R;
|
|
1668
1417
|
declare function matchError<R>(error: EntityErrorType, handlers: EntityErrorHandlers<R>): R;
|
|
1418
|
+
/**
|
|
1419
|
+
* Result type and utilities for errors-as-values pattern.
|
|
1420
|
+
*
|
|
1421
|
+
* This module provides a type-safe alternative to throwing exceptions.
|
|
1422
|
+
* Every operation that can fail returns a Result<T, E> instead of throwing.
|
|
1423
|
+
*
|
|
1424
|
+
* @example
|
|
1425
|
+
* import { ok, err, unwrap, map, flatMap, match, matchErr } from '@vertz/errors';
|
|
1426
|
+
*
|
|
1427
|
+
* // Creating results
|
|
1428
|
+
* const success = ok({ name: 'Alice' });
|
|
1429
|
+
* const failure = err({ code: 'NOT_FOUND', message: 'User not found' });
|
|
1430
|
+
*
|
|
1431
|
+
* // Transforming
|
|
1432
|
+
* const doubled = map(ok(5), x => x * 2);
|
|
1433
|
+
*
|
|
1434
|
+
* // Chaining
|
|
1435
|
+
* const result = await flatMap(ok(5), async x => ok(x * 2));
|
|
1436
|
+
*
|
|
1437
|
+
* // Pattern matching
|
|
1438
|
+
* const message = match(result, {
|
|
1439
|
+
* ok: (data) => `Success: ${data}`,
|
|
1440
|
+
* err: (error) => `Error: ${error.message}`
|
|
1441
|
+
* });
|
|
1442
|
+
*/
|
|
1443
|
+
/**
|
|
1444
|
+
* Represents a successful result.
|
|
1445
|
+
*
|
|
1446
|
+
* @example
|
|
1447
|
+
* { ok: true, data: { name: 'Alice' } }
|
|
1448
|
+
*/
|
|
1449
|
+
interface Ok<T> {
|
|
1450
|
+
/** Always true for successful results */
|
|
1451
|
+
readonly ok: true;
|
|
1452
|
+
/** The successful value */
|
|
1453
|
+
readonly data: T;
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* Represents an erroneous result.
|
|
1457
|
+
*
|
|
1458
|
+
* @example
|
|
1459
|
+
* { ok: false, error: { code: 'NOT_FOUND', message: 'User not found' } }
|
|
1460
|
+
*/
|
|
1461
|
+
interface Err<E> {
|
|
1462
|
+
/** Always false for error results */
|
|
1463
|
+
readonly ok: false;
|
|
1464
|
+
/** The error value */
|
|
1465
|
+
readonly error: E;
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* A discriminated union representing success or failure.
|
|
1469
|
+
*
|
|
1470
|
+
* @example
|
|
1471
|
+
* type UserResult = Result<User, ValidationError>;
|
|
1472
|
+
* type UsersResult = Result<User[], NotFoundError>;
|
|
1473
|
+
*
|
|
1474
|
+
* @example
|
|
1475
|
+
* const result: Result<string, Error> = ok('hello');
|
|
1476
|
+
* if (result.ok) {
|
|
1477
|
+
* console.log(result.data); // TypeScript knows this is string
|
|
1478
|
+
* } else {
|
|
1479
|
+
* console.log(result.error); // TypeScript knows this is Error
|
|
1480
|
+
* }
|
|
1481
|
+
*/
|
|
1482
|
+
type Result<
|
|
1483
|
+
T,
|
|
1484
|
+
E = unknown
|
|
1485
|
+
> = Ok<T> | Err<E>;
|
|
1486
|
+
/**
|
|
1487
|
+
* Creates a successful Result.
|
|
1488
|
+
*
|
|
1489
|
+
* @example
|
|
1490
|
+
* const result = ok({ name: 'Alice' });
|
|
1491
|
+
* // { ok: true, data: { name: 'Alice' } }
|
|
1492
|
+
*
|
|
1493
|
+
* @example
|
|
1494
|
+
* // With type inference
|
|
1495
|
+
* const result = ok(42); // Ok<number>
|
|
1496
|
+
*/
|
|
1497
|
+
declare const ok: <T>(data: T) => Ok<T>;
|
|
1498
|
+
/**
|
|
1499
|
+
* Creates an error Result.
|
|
1500
|
+
*
|
|
1501
|
+
* @example
|
|
1502
|
+
* const result = err({ code: 'VALIDATION_FAILED', message: 'Invalid email', issues: [] });
|
|
1503
|
+
* // { ok: false, error: { code: 'VALIDATION_FAILED', ... } }
|
|
1504
|
+
*
|
|
1505
|
+
* @example
|
|
1506
|
+
* // With simple string errors
|
|
1507
|
+
* const result = err('Something went wrong');
|
|
1508
|
+
* // { ok: false, error: 'Something went wrong' }
|
|
1509
|
+
*/
|
|
1510
|
+
declare const err: <E>(error: E) => Err<E>;
|
|
1511
|
+
/**
|
|
1512
|
+
* Unwraps a Result, throwing if error.
|
|
1513
|
+
*
|
|
1514
|
+
* Use only in tests, scripts, or when failure is truly exceptional.
|
|
1515
|
+
*
|
|
1516
|
+
* @example
|
|
1517
|
+
* // Tests
|
|
1518
|
+
* const user = unwrap(await repo.findOneRequired(id));
|
|
1519
|
+
*
|
|
1520
|
+
* @example
|
|
1521
|
+
* // Scripts
|
|
1522
|
+
* const config = unwrap(parseConfig());
|
|
1523
|
+
*
|
|
1524
|
+
* @throws The error value if the Result is an error
|
|
1525
|
+
*/
|
|
1526
|
+
declare function unwrap<
|
|
1527
|
+
T,
|
|
1528
|
+
E
|
|
1529
|
+
>(result: Result<T, E>): T;
|
|
1530
|
+
/**
|
|
1531
|
+
* Unwraps a Result, returning a default value if error.
|
|
1532
|
+
*
|
|
1533
|
+
* @example
|
|
1534
|
+
* const user = await findById(id) ?? { name: 'Guest' };
|
|
1535
|
+
*/
|
|
1536
|
+
declare function unwrapOr<
|
|
1537
|
+
T,
|
|
1538
|
+
E
|
|
1539
|
+
>(result: Result<T, E>, defaultValue: T): T;
|
|
1540
|
+
/**
|
|
1541
|
+
* Maps the success value to a new type.
|
|
1542
|
+
*
|
|
1543
|
+
* @example
|
|
1544
|
+
* const userName = map(userResult, u => u.name);
|
|
1545
|
+
* // Result<string, Error> if userResult was Result<User, Error>
|
|
1546
|
+
*
|
|
1547
|
+
* @example
|
|
1548
|
+
* // Transform while preserving error type
|
|
1549
|
+
* const id = map(ok({ userId: 5 }), u => u.userId);
|
|
1550
|
+
* // Ok<number>
|
|
1551
|
+
*/
|
|
1552
|
+
declare function map<
|
|
1553
|
+
T,
|
|
1554
|
+
E,
|
|
1555
|
+
U
|
|
1556
|
+
>(result: Result<T, E>, fn: (data: T) => U): Result<U, E>;
|
|
1557
|
+
/**
|
|
1558
|
+
* Chains Result-returning functions.
|
|
1559
|
+
*
|
|
1560
|
+
* Allows chaining operations that can fail without nested try/catch.
|
|
1561
|
+
*
|
|
1562
|
+
* @example
|
|
1563
|
+
* // Synchronous
|
|
1564
|
+
* const profile = flatMap(
|
|
1565
|
+
* await repo.findOne(userId),
|
|
1566
|
+
* (user) => profileRepo.findOne(user.profileId)
|
|
1567
|
+
* );
|
|
1568
|
+
*
|
|
1569
|
+
* @example
|
|
1570
|
+
* // Asynchronous
|
|
1571
|
+
* const finalResult = await flatMap(
|
|
1572
|
+
* await repo.findOne(userId),
|
|
1573
|
+
* async (user) => await profileRepo.findOne(user.profileId)
|
|
1574
|
+
* );
|
|
1575
|
+
*/
|
|
1576
|
+
declare function flatMap<
|
|
1577
|
+
T,
|
|
1578
|
+
E,
|
|
1579
|
+
U,
|
|
1580
|
+
F
|
|
1581
|
+
>(result: Result<T, E>, fn: (data: T) => Result<U, F>): Result<U, E | F>;
|
|
1582
|
+
declare function flatMap<
|
|
1583
|
+
T,
|
|
1584
|
+
E,
|
|
1585
|
+
U,
|
|
1586
|
+
F
|
|
1587
|
+
>(result: Result<T, E>, fn: (data: T) => Promise<Result<U, F>>): Promise<Result<U, E | F>>;
|
|
1588
|
+
/**
|
|
1589
|
+
* Pattern matching on Result.
|
|
1590
|
+
*
|
|
1591
|
+
* @example
|
|
1592
|
+
* const message = match(result, {
|
|
1593
|
+
* ok: (user) => \`Hello, \${user.name}!\`,
|
|
1594
|
+
* err: (e) => \`Error: \${e.message}\`
|
|
1595
|
+
* });
|
|
1596
|
+
*/
|
|
1597
|
+
declare function match<
|
|
1598
|
+
T,
|
|
1599
|
+
E,
|
|
1600
|
+
OkR,
|
|
1601
|
+
ErrR
|
|
1602
|
+
>(result: Result<T, E>, handlers: {
|
|
1603
|
+
ok: (data: T) => OkR;
|
|
1604
|
+
err: (error: E) => ErrR;
|
|
1605
|
+
}): OkR | ErrR;
|
|
1606
|
+
/**
|
|
1607
|
+
* Type for error handlers in matchErr.
|
|
1608
|
+
* Extracts error codes from an error union and creates a handler map.
|
|
1609
|
+
*/
|
|
1610
|
+
type ErrorHandlers<
|
|
1611
|
+
E,
|
|
1612
|
+
R
|
|
1613
|
+
> = { [K in E as K extends {
|
|
1614
|
+
readonly code: infer C extends string;
|
|
1615
|
+
} ? C : never] : (error: K) => R };
|
|
1616
|
+
/**
|
|
1617
|
+
* Exhaustive pattern matching on Result errors.
|
|
1618
|
+
*
|
|
1619
|
+
* Unlike `match()` which gives you a single `err` handler,
|
|
1620
|
+
* `matchErr` requires a handler for every error type in the union.
|
|
1621
|
+
* The compiler enforces exhaustiveness — add a new error type to the union
|
|
1622
|
+
* and every callsite lights up until you handle it.
|
|
1623
|
+
*
|
|
1624
|
+
* Errors are discriminated by their `code` string literal field.
|
|
1625
|
+
*
|
|
1626
|
+
* @example
|
|
1627
|
+
* const response = matchErr(result, {
|
|
1628
|
+
* ok: (user) => json({ data: user }, 201),
|
|
1629
|
+
* NOT_FOUND: (e) => json({ error: 'NOT_FOUND', message: e.message }, 404),
|
|
1630
|
+
* UNIQUE_VIOLATION: (e) => json({ error: 'EMAIL_EXISTS', field: e.column }, 409),
|
|
1631
|
+
* });
|
|
1632
|
+
* // ^ Compile error if error union adds a new member you didn't handle
|
|
1633
|
+
*
|
|
1634
|
+
* @throws Error if an error code is not handled
|
|
1635
|
+
*/
|
|
1636
|
+
declare function matchErr<
|
|
1637
|
+
T,
|
|
1638
|
+
E extends {
|
|
1639
|
+
readonly code: string;
|
|
1640
|
+
},
|
|
1641
|
+
R
|
|
1642
|
+
>(result: Result<T, E>, handlers: {
|
|
1643
|
+
ok: (data: T) => R;
|
|
1644
|
+
} & ErrorHandlers<E, R>): R;
|
|
1645
|
+
/**
|
|
1646
|
+
* Type guard for Ok results.
|
|
1647
|
+
*
|
|
1648
|
+
* @example
|
|
1649
|
+
* if (isOk(result)) {
|
|
1650
|
+
* console.log(result.data); // TypeScript knows this is T
|
|
1651
|
+
* }
|
|
1652
|
+
*/
|
|
1653
|
+
declare function isOk<
|
|
1654
|
+
T,
|
|
1655
|
+
E
|
|
1656
|
+
>(result: Result<T, E>): result is Ok<T>;
|
|
1657
|
+
/**
|
|
1658
|
+
* Type guard for Err results.
|
|
1659
|
+
*
|
|
1660
|
+
* @example
|
|
1661
|
+
* if (isErr(result)) {
|
|
1662
|
+
* console.log(result.error); // TypeScript knows this is E
|
|
1663
|
+
* }
|
|
1664
|
+
*/
|
|
1665
|
+
declare function isErr<
|
|
1666
|
+
T,
|
|
1667
|
+
E
|
|
1668
|
+
>(result: Result<T, E>): result is Err<E>;
|
|
1669
1669
|
export { unwrapOr, unwrap, uniqueViolationToHttpStatus, ok, notNullViolationToHttpStatus, notFoundErrorToHttpStatus, matchError, matchErr, match, map, isUserExistsError, isUnknownError, isUniqueViolation, isUnauthorizedError, isTokenInvalidError, isTokenExpiredError, isSessionNotFoundError, isSessionExpiredError, isServiceUnavailableError, isValidationError2 as isSchemaValidationError, isPermissionDeniedError, isParseError, isOk, isOAuthError, isNotNullViolation, isMigrationQueryError, isMigrationHistoryNotFound, isMigrationChecksumMismatch, isMfaRequiredError, isMfaNotEnabledError, isMfaInvalidCodeError, isMfaAlreadyEnabledError, isMethodNotAllowedError, isInvalidCredentialsError, isInternalError, isHttpError, isForbiddenError, isFetchValidationError, isFetchUnprocessableEntityError, isFetchUnauthorizedError, isFetchTimeoutError, isFetchServiceUnavailableError, isFetchRateLimitError, isFetchNotFoundError, isFetchNetworkError, isFetchInternalServerError, isFetchGoneError, isFetchForbiddenError, isFetchConflictError, isFetchBadRequestError, isFKViolation, isErr, isEntityValidationError, isEntityUnauthorizedError, isEntityNotFoundError, isEntityForbiddenError, isEntityConflictError, isNotFoundError2 as isDBNotFoundError, isConflictError, isValidationError as isClientValidationError, isRateLimitedError2 as isClientRateLimitedError, isNotFoundError as isClientNotFoundError, isCheckViolation, isBadRequestError, isAuthValidationError, isRateLimitedError as isAuthRateLimitedError, httpToClientError, flatMap, fkViolationToHttpStatus, err, dbErrorToHttpStatus, createUserExistsError, createUniqueViolation, createUnauthorizedError, createTokenInvalidError, createTokenExpiredError, createSessionNotFoundError, createSessionExpiredError, createValidationError2 as createSchemaValidationError, createPermissionDeniedError, createOAuthError, createNotNullViolation, createMigrationQueryError, createMigrationHistoryNotFound, createMigrationChecksumMismatch, createMfaRequiredError, createMfaNotEnabledError, createMfaInvalidCodeError, createMfaAlreadyEnabledError, createInvalidCredentialsError, createHttpError, createForbiddenError, createFKViolation, createNotFoundError2 as createDBNotFoundError, createConflictError, createValidationError as createClientValidationError, createRateLimitedError2 as createClientRateLimitedError, createNotFoundError as createClientNotFoundError, createCheckViolation, createAuthValidationError, createRateLimitedError as createAuthRateLimitedError, checkViolationToHttpStatus, WriteError, ValidationIssue, UserExistsError, UnknownError, UniqueViolation, UnauthorizedError, TokenInvalidError, TokenExpiredError, TimeoutError2 as TimeoutError, SessionNotFoundError, SessionExpiredError, ServiceUnavailableError, SerializationError, ValidationError3 as SchemaValidationError, Result, ReadError, QueryError, PoolExhaustedError, PermissionDeniedError, ParseError2 as ParseError, Ok, OAuthError, NotNullViolation, NetworkError2 as NetworkError, MigrationQueryError, MigrationHistoryNotFound, MigrationError, MigrationChecksumMismatch, MfaRequiredError, MfaNotEnabledError, MfaInvalidCodeError, MfaAlreadyEnabledError, MethodNotAllowedError, InvalidCredentialsError, InternalError2 as InternalError, InfraErrors, InfraError, HttpError2 as HttpError, ForbiddenError, FetchValidationError, FetchUnprocessableEntityError, FetchUnauthorizedError, FetchTimeoutError, FetchServiceUnavailableError, FetchRateLimitError, FetchNotFoundError, FetchNetworkError, FetchInternalServerError, FetchGoneError, FetchForbiddenError, FetchErrorType, FetchError, FetchConflictError, FetchBadRequestError, FKViolation, Err, EntityValidationError, EntityUnauthorizedError, EntityNotFoundError, EntityForbiddenError, EntityErrorType, EntityError, EntityConflictError, NotFoundError2 as DBNotFoundError, ConnectionError, ConflictError, ValidationError2 as ClientValidationError, RateLimitedError2 as ClientRateLimitedError, NotFoundError as ClientNotFoundError, CheckViolation, BadRequestError, AuthValidationError, RateLimitedError as AuthRateLimitedError, AuthError, AppError, ApiError };
|