@zireal/result-kit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ali Farooq
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # @zireal/result-kit
2
+
3
+ Type-safe result and structured error utilities for TypeScript, with optional NestJS adapters.
4
+
5
+ ## Packages
6
+
7
+ - `@zireal/result-kit`
8
+ - `@zireal/result-kit/core`
9
+ - `@zireal/result-kit/nest`
10
+
11
+ The package root re-exports the framework-agnostic core only. Nest-specific helpers live in `@zireal/result-kit/nest`.
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ pnpm add @zireal/result-kit
17
+ ```
18
+
19
+ If you use the Nest adapter:
20
+
21
+ ```bash
22
+ pnpm add @nestjs/common
23
+ ```
24
+
25
+ ## Core Concepts
26
+
27
+ ### `Result<T, E>`
28
+
29
+ ```ts
30
+ type Result<T, E> = Success<T> | Failure<E>;
31
+ ```
32
+
33
+ Use `Result` to model success and failure explicitly rather than throwing through your service layer.
34
+
35
+ ### `TypedError`
36
+
37
+ ```ts
38
+ interface TypedError<TType extends string = string> {
39
+ type: TType;
40
+ message: string;
41
+ details?: Record<string, unknown>;
42
+ cause?: unknown;
43
+ }
44
+ ```
45
+
46
+ `TypedError` is the package’s structured error convention. You can still use any `E` with `Result<T, E>`, but `TypedError` works well for application and domain failures.
47
+
48
+ ## Core Usage
49
+
50
+ ```ts
51
+ import {
52
+ ResultKit,
53
+ type Result,
54
+ type TypedErrorUnion,
55
+ } from "@zireal/result-kit";
56
+
57
+ type UserError = TypedErrorUnion<"not_found" | "validation_error">;
58
+
59
+ const findUser = (id: string): Result<{ id: string }, UserError> => {
60
+ if (!id.trim()) {
61
+ return ResultKit.fail({
62
+ type: "validation_error",
63
+ message: "id is required",
64
+ });
65
+ }
66
+
67
+ if (id !== "123") {
68
+ return ResultKit.fail({
69
+ type: "not_found",
70
+ message: "User not found",
71
+ details: { id },
72
+ });
73
+ }
74
+
75
+ return ResultKit.success({ id });
76
+ };
77
+ ```
78
+
79
+ ## Nest Usage
80
+
81
+ ```ts
82
+ import { Controller, Get, Param } from "@nestjs/common";
83
+ import { unwrapOrThrow } from "@zireal/result-kit/nest";
84
+
85
+ @Controller("users")
86
+ export class UserController {
87
+ constructor(private readonly service: UserService) {}
88
+
89
+ @Get(":id")
90
+ async getUser(@Param("id") id: string) {
91
+ return unwrapOrThrow(await this.service.findUser(id));
92
+ }
93
+ }
94
+ ```
95
+
96
+ Use a mapper when your domain error types need custom HTTP status behavior:
97
+
98
+ ```ts
99
+ import { BadRequestException, NotFoundException } from "@nestjs/common";
100
+ import { unwrapOrThrow } from "@zireal/result-kit/nest";
101
+ import { ResultKit } from "@zireal/result-kit";
102
+
103
+ const user = unwrapOrThrow(result, {
104
+ mapError: (error) => {
105
+ if (!ResultKit.isTypedError(error)) return undefined;
106
+ if (error.type === "validation_error") {
107
+ return new BadRequestException(error.message);
108
+ }
109
+ if (error.type === "not_found") {
110
+ return new NotFoundException(error.message);
111
+ }
112
+
113
+ return undefined;
114
+ },
115
+ });
116
+ ```
117
+
118
+ ## API Surface
119
+
120
+ ### Core
121
+
122
+ - `TypedError`, `TypedErrorOf`, `TypedErrorUnion`
123
+ - `Success`, `Failure`, `Result`
124
+ - `ResultKit.success`, `failure`, `fail`
125
+ - `ResultKit.isSuccess`, `isFailure`, `isTypedError`
126
+ - `ResultKit.map`, `mapAsync`, `mapError`, `mapErrorAsync`
127
+ - `ResultKit.andThen`, `andThenAsync`, `orElse`, `orElseAsync`
128
+ - `ResultKit.match`, `matchAsync`
129
+ - `ResultKit.unwrap`, `unwrapSuccess`, `unwrapFailure`, `unwrapOr`, `unwrapOrElse`, `unwrapOrElseAsync`
130
+ - `ResultKit.combine`, `combineAsync`, `combineWithAllErrors`, `combineWithAllErrorsAsync`
131
+ - `ResultKit.fromNullable`, `fromPredicate`, `fromPromise`, `fromThrowable`, `fromThrowableAsync`
132
+ - `ResultKit.partition`, `filterSuccesses`, `filterFailures`, `toNullable`, `flatten`
133
+
134
+ ### Nest
135
+
136
+ - `toHttpException`
137
+ - `unwrapOrThrow`
138
+ - `unwrapPromise`
139
+
140
+ ## Examples
141
+
142
+ - [`examples/core.ts`](./examples/core.ts)
143
+ - [`examples/nest.ts`](./examples/nest.ts)
@@ -0,0 +1,4 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_result_kit = require("../result-kit-Ck1xAp-J.cjs");
3
+ exports.ResultKit = require_result_kit.ResultKit;
4
+ exports.isTypedError = require_result_kit.isTypedError;
@@ -0,0 +1,3 @@
1
+ import { a as isTypedError, i as TypedErrorUnion, n as TypedError, r as TypedErrorOf, t as ResultKit } from "../index-EJ_Ol5Fu.cjs";
2
+ import { n as Result, r as Success, t as Failure } from "../result-DbQ8o1Cs.cjs";
3
+ export { Failure, Result, ResultKit, Success, TypedError, TypedErrorOf, TypedErrorUnion, isTypedError };
@@ -0,0 +1,3 @@
1
+ import { a as isTypedError, i as TypedErrorUnion, n as TypedError, r as TypedErrorOf, t as ResultKit } from "../index-Ch6k0lVU.mjs";
2
+ import { n as Result, r as Success, t as Failure } from "../result-CI_HBDHK.mjs";
3
+ export { Failure, Result, ResultKit, Success, TypedError, TypedErrorOf, TypedErrorUnion, isTypedError };
@@ -0,0 +1,2 @@
1
+ import { n as isTypedError, t as ResultKit } from "../result-kit-C5ZY61pO.mjs";
2
+ export { ResultKit, isTypedError };
@@ -0,0 +1,70 @@
1
+ import { n as Result, r as Success, t as Failure } from "./result-CI_HBDHK.mjs";
2
+
3
+ //#region src/core/error.d.ts
4
+ interface TypedError<TType extends string = string> {
5
+ readonly type: TType;
6
+ readonly message: string;
7
+ readonly details?: Record<string, unknown>;
8
+ readonly cause?: unknown;
9
+ }
10
+ type TypedErrorOf<TType extends string> = TypedError<TType>;
11
+ type TypedErrorUnion<TType extends string> = TType extends string ? TypedError<TType> : never;
12
+ declare const isTypedError: (error: unknown) => error is TypedError<string>;
13
+ //#endregion
14
+ //#region src/core/result-kit.d.ts
15
+ declare abstract class ResultKit {
16
+ static isSuccess<T, E>(result: Result<T, E>): result is Success<T>;
17
+ static isFailure<T, E>(result: Result<T, E>): result is Failure<E>;
18
+ static success<T>(value: T): Success<T>;
19
+ static failure<E>(error: E): Failure<E>;
20
+ static fail<T extends string>(error: TypedError<T>): Failure<TypedError<T>>;
21
+ static isTypedError(error: unknown): error is TypedError<string>;
22
+ static map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;
23
+ static bimap<T, U, E, F>(result: Result<T, E>, onSuccess: (value: T) => U, onFailure: (error: E) => F): Result<U, F>;
24
+ static mapAsync<T, U, E>(result: Result<T, E>, fn: (value: T) => Promise<U>): Promise<Result<U, E>>;
25
+ static mapError<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F>;
26
+ static mapErrorAsync<T, E, F>(result: Result<T, E>, fn: (error: E) => Promise<F>): Promise<Result<T, F>>;
27
+ static andThen<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E>;
28
+ static andThenAsync<T, U, E>(result: Result<T, E>, fn: (value: T) => Promise<Result<U, E>>): Promise<Result<U, E>>;
29
+ static orElse<T, E, F>(result: Result<T, E>, fn: (error: E) => Result<T, F>): Result<T, F>;
30
+ static orElseAsync<T, E, F>(result: Result<T, E>, fn: (error: E) => Promise<Result<T, F>>): Promise<Result<T, F>>;
31
+ static unwrap<T, E>(result: Result<T, E>): T | undefined;
32
+ static unwrapSuccess<T>(result: Success<T>): T;
33
+ static unwrapFailure<E>(result: Failure<E>): E;
34
+ static unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T;
35
+ static unwrapOrElse<T, E>(result: Result<T, E>, fn: (error: E) => T): T;
36
+ static unwrapOrElseAsync<T, E>(result: Result<T, E>, fn: (error: E) => Promise<T>): Promise<T>;
37
+ static match<T, E, U>(result: Result<T, E>, handlers: {
38
+ onSuccess: (value: T) => U;
39
+ onFailure: (error: E) => U;
40
+ }): U;
41
+ static matchAsync<T, E, U>(result: Result<T, E>, handlers: {
42
+ onSuccess: (value: T) => Promise<U>;
43
+ onFailure: (error: E) => Promise<U>;
44
+ }): Promise<U>;
45
+ static tap<T, E>(result: Result<T, E>, handlers: {
46
+ onSuccess?: (value: T) => void;
47
+ onFailure?: (error: E) => void;
48
+ }): Result<T, E>;
49
+ static tapAsync<T, E>(result: Result<T, E>, handlers: {
50
+ onSuccess?: (value: T) => Promise<void>;
51
+ onFailure?: (error: E) => Promise<void>;
52
+ }): Promise<Result<T, E>>;
53
+ static combine<T, E>(results: Result<T, E>[]): Result<T[], E>;
54
+ static combineAsync<T, E>(results: Promise<Result<T, E>>[]): Promise<Result<T[], E>>;
55
+ static combineWithAllErrors<T, E>(results: Result<T, E>[]): Result<T[], E[]>;
56
+ static combineWithAllErrorsAsync<T, E>(results: Promise<Result<T, E>>[]): Promise<Result<T[], E[]>>;
57
+ static flatten<T, E>(result: Result<Result<T, E>, E>): Result<T, E>;
58
+ static fromPromise<T, E>(promise: Promise<T>, errorFn: (error: unknown) => E): Promise<Result<T, E>>;
59
+ static fromThrowable<Args extends unknown[], T, E>(fn: (...args: Args) => T, errorFn: (error: unknown) => E): (...args: Args) => Result<T, E>;
60
+ static fromThrowableAsync<Args extends unknown[], T, E>(fn: (...args: Args) => Promise<T>, errorFn: (error: unknown) => E): (...args: Args) => Promise<Result<T, E>>;
61
+ static fromNullable<T, E>(value: T | null | undefined, error: E): Result<NonNullable<T>, E>;
62
+ static fromPredicate<T, E>(value: T, predicate: (value: T) => boolean, error: E): Result<T, E>;
63
+ static toNullable<T, E>(result: Result<T, E>): T | null;
64
+ static partition<T, E>(results: Result<T, E>[]): [T[], E[]];
65
+ static filterSuccesses<T, E>(results: Result<T, E>[]): T[];
66
+ static filterFailures<T, E>(results: Result<T, E>[]): E[];
67
+ }
68
+ //#endregion
69
+ export { isTypedError as a, TypedErrorUnion as i, TypedError as n, TypedErrorOf as r, ResultKit as t };
70
+ //# sourceMappingURL=index-Ch6k0lVU.d.mts.map
@@ -0,0 +1,70 @@
1
+ import { n as Result, r as Success, t as Failure } from "./result-DbQ8o1Cs.cjs";
2
+
3
+ //#region src/core/error.d.ts
4
+ interface TypedError<TType extends string = string> {
5
+ readonly type: TType;
6
+ readonly message: string;
7
+ readonly details?: Record<string, unknown>;
8
+ readonly cause?: unknown;
9
+ }
10
+ type TypedErrorOf<TType extends string> = TypedError<TType>;
11
+ type TypedErrorUnion<TType extends string> = TType extends string ? TypedError<TType> : never;
12
+ declare const isTypedError: (error: unknown) => error is TypedError<string>;
13
+ //#endregion
14
+ //#region src/core/result-kit.d.ts
15
+ declare abstract class ResultKit {
16
+ static isSuccess<T, E>(result: Result<T, E>): result is Success<T>;
17
+ static isFailure<T, E>(result: Result<T, E>): result is Failure<E>;
18
+ static success<T>(value: T): Success<T>;
19
+ static failure<E>(error: E): Failure<E>;
20
+ static fail<T extends string>(error: TypedError<T>): Failure<TypedError<T>>;
21
+ static isTypedError(error: unknown): error is TypedError<string>;
22
+ static map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;
23
+ static bimap<T, U, E, F>(result: Result<T, E>, onSuccess: (value: T) => U, onFailure: (error: E) => F): Result<U, F>;
24
+ static mapAsync<T, U, E>(result: Result<T, E>, fn: (value: T) => Promise<U>): Promise<Result<U, E>>;
25
+ static mapError<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F>;
26
+ static mapErrorAsync<T, E, F>(result: Result<T, E>, fn: (error: E) => Promise<F>): Promise<Result<T, F>>;
27
+ static andThen<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E>;
28
+ static andThenAsync<T, U, E>(result: Result<T, E>, fn: (value: T) => Promise<Result<U, E>>): Promise<Result<U, E>>;
29
+ static orElse<T, E, F>(result: Result<T, E>, fn: (error: E) => Result<T, F>): Result<T, F>;
30
+ static orElseAsync<T, E, F>(result: Result<T, E>, fn: (error: E) => Promise<Result<T, F>>): Promise<Result<T, F>>;
31
+ static unwrap<T, E>(result: Result<T, E>): T | undefined;
32
+ static unwrapSuccess<T>(result: Success<T>): T;
33
+ static unwrapFailure<E>(result: Failure<E>): E;
34
+ static unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T;
35
+ static unwrapOrElse<T, E>(result: Result<T, E>, fn: (error: E) => T): T;
36
+ static unwrapOrElseAsync<T, E>(result: Result<T, E>, fn: (error: E) => Promise<T>): Promise<T>;
37
+ static match<T, E, U>(result: Result<T, E>, handlers: {
38
+ onSuccess: (value: T) => U;
39
+ onFailure: (error: E) => U;
40
+ }): U;
41
+ static matchAsync<T, E, U>(result: Result<T, E>, handlers: {
42
+ onSuccess: (value: T) => Promise<U>;
43
+ onFailure: (error: E) => Promise<U>;
44
+ }): Promise<U>;
45
+ static tap<T, E>(result: Result<T, E>, handlers: {
46
+ onSuccess?: (value: T) => void;
47
+ onFailure?: (error: E) => void;
48
+ }): Result<T, E>;
49
+ static tapAsync<T, E>(result: Result<T, E>, handlers: {
50
+ onSuccess?: (value: T) => Promise<void>;
51
+ onFailure?: (error: E) => Promise<void>;
52
+ }): Promise<Result<T, E>>;
53
+ static combine<T, E>(results: Result<T, E>[]): Result<T[], E>;
54
+ static combineAsync<T, E>(results: Promise<Result<T, E>>[]): Promise<Result<T[], E>>;
55
+ static combineWithAllErrors<T, E>(results: Result<T, E>[]): Result<T[], E[]>;
56
+ static combineWithAllErrorsAsync<T, E>(results: Promise<Result<T, E>>[]): Promise<Result<T[], E[]>>;
57
+ static flatten<T, E>(result: Result<Result<T, E>, E>): Result<T, E>;
58
+ static fromPromise<T, E>(promise: Promise<T>, errorFn: (error: unknown) => E): Promise<Result<T, E>>;
59
+ static fromThrowable<Args extends unknown[], T, E>(fn: (...args: Args) => T, errorFn: (error: unknown) => E): (...args: Args) => Result<T, E>;
60
+ static fromThrowableAsync<Args extends unknown[], T, E>(fn: (...args: Args) => Promise<T>, errorFn: (error: unknown) => E): (...args: Args) => Promise<Result<T, E>>;
61
+ static fromNullable<T, E>(value: T | null | undefined, error: E): Result<NonNullable<T>, E>;
62
+ static fromPredicate<T, E>(value: T, predicate: (value: T) => boolean, error: E): Result<T, E>;
63
+ static toNullable<T, E>(result: Result<T, E>): T | null;
64
+ static partition<T, E>(results: Result<T, E>[]): [T[], E[]];
65
+ static filterSuccesses<T, E>(results: Result<T, E>[]): T[];
66
+ static filterFailures<T, E>(results: Result<T, E>[]): E[];
67
+ }
68
+ //#endregion
69
+ export { isTypedError as a, TypedErrorUnion as i, TypedError as n, TypedErrorOf as r, ResultKit as t };
70
+ //# sourceMappingURL=index-EJ_Ol5Fu.d.cts.map
package/dist/index.cjs ADDED
@@ -0,0 +1,5 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_result_kit = require("./result-kit-Ck1xAp-J.cjs");
3
+ require("./core/index.cjs");
4
+ exports.ResultKit = require_result_kit.ResultKit;
5
+ exports.isTypedError = require_result_kit.isTypedError;
@@ -0,0 +1,3 @@
1
+ import { a as isTypedError, i as TypedErrorUnion, n as TypedError, r as TypedErrorOf, t as ResultKit } from "./index-EJ_Ol5Fu.cjs";
2
+ import { n as Result, r as Success, t as Failure } from "./result-DbQ8o1Cs.cjs";
3
+ export { Failure, Result, ResultKit, Success, TypedError, TypedErrorOf, TypedErrorUnion, isTypedError };
@@ -0,0 +1,3 @@
1
+ import { a as isTypedError, i as TypedErrorUnion, n as TypedError, r as TypedErrorOf, t as ResultKit } from "./index-Ch6k0lVU.mjs";
2
+ import { n as Result, r as Success, t as Failure } from "./result-CI_HBDHK.mjs";
3
+ export { Failure, Result, ResultKit, Success, TypedError, TypedErrorOf, TypedErrorUnion, isTypedError };
package/dist/index.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import { n as isTypedError, t as ResultKit } from "./result-kit-C5ZY61pO.mjs";
2
+ import "./core/index.mjs";
3
+ export { ResultKit, isTypedError };
@@ -0,0 +1,46 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_result_kit = require("../result-kit-Ck1xAp-J.cjs");
3
+ let _nestjs_common = require("@nestjs/common");
4
+ //#region src/nest/http.ts
5
+ const DEFAULT_UNKNOWN_MESSAGE = "An unknown error occurred";
6
+ const DEFAULT_ERROR_CODE = "INTERNAL_SERVER_ERROR";
7
+ const normalizeErrorCode = (value) => value.trim().replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase() || DEFAULT_ERROR_CODE;
8
+ const toHttpExceptionFromDescriptor = (descriptor) => {
9
+ const status = descriptor.status ?? _nestjs_common.HttpStatus.INTERNAL_SERVER_ERROR;
10
+ return new _nestjs_common.HttpException({
11
+ code: descriptor.code ?? (status === _nestjs_common.HttpStatus.INTERNAL_SERVER_ERROR ? DEFAULT_ERROR_CODE : String(status)),
12
+ message: descriptor.message ?? DEFAULT_UNKNOWN_MESSAGE,
13
+ ...descriptor.details ? { details: descriptor.details } : {},
14
+ ...descriptor.error ? { error: descriptor.error } : {}
15
+ }, status);
16
+ };
17
+ const toHttpException = (error, options) => {
18
+ const mapped = options?.mapError?.(error);
19
+ if (mapped instanceof _nestjs_common.HttpException) return mapped;
20
+ if (mapped) return toHttpExceptionFromDescriptor(mapped);
21
+ if (error instanceof _nestjs_common.HttpException) return error;
22
+ if (require_result_kit.isTypedError(error)) return new _nestjs_common.InternalServerErrorException({
23
+ code: normalizeErrorCode(error.type),
24
+ message: error.message,
25
+ ...error.details ? { details: error.details } : {}
26
+ });
27
+ if (error instanceof Error) return new _nestjs_common.InternalServerErrorException({
28
+ code: DEFAULT_ERROR_CODE,
29
+ message: error.message || options?.fallbackMessage || DEFAULT_UNKNOWN_MESSAGE
30
+ });
31
+ return new _nestjs_common.InternalServerErrorException({
32
+ code: DEFAULT_ERROR_CODE,
33
+ message: options?.fallbackMessage || DEFAULT_UNKNOWN_MESSAGE
34
+ });
35
+ };
36
+ const unwrapOrThrow = (result, options) => {
37
+ if (require_result_kit.ResultKit.isSuccess(result)) return result.value;
38
+ throw toHttpException(result.error, options);
39
+ };
40
+ const unwrapPromise = async (promise, options) => unwrapOrThrow(await promise, options);
41
+ //#endregion
42
+ exports.toHttpException = toHttpException;
43
+ exports.unwrapOrThrow = unwrapOrThrow;
44
+ exports.unwrapPromise = unwrapPromise;
45
+
46
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1,21 @@
1
+ import { n as Result } from "../result-DbQ8o1Cs.cjs";
2
+ import { HttpException } from "@nestjs/common";
3
+
4
+ //#region src/nest/http.d.ts
5
+ interface HttpExceptionDescriptor {
6
+ readonly status?: number;
7
+ readonly code?: string | number;
8
+ readonly message?: string;
9
+ readonly details?: Record<string, unknown>;
10
+ readonly error?: string;
11
+ }
12
+ interface NestErrorOptions<E> {
13
+ readonly mapError?: (error: E) => HttpException | HttpExceptionDescriptor | undefined;
14
+ readonly fallbackMessage?: string;
15
+ }
16
+ declare const toHttpException: <E>(error: E, options?: NestErrorOptions<E>) => HttpException;
17
+ declare const unwrapOrThrow: <T, E>(result: Result<T, E>, options?: NestErrorOptions<E>) => T;
18
+ declare const unwrapPromise: <T, E>(promise: Promise<Result<T, E>>, options?: NestErrorOptions<E>) => Promise<T>;
19
+ //#endregion
20
+ export { type HttpExceptionDescriptor, type NestErrorOptions, toHttpException, unwrapOrThrow, unwrapPromise };
21
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1,21 @@
1
+ import { n as Result } from "../result-CI_HBDHK.mjs";
2
+ import { HttpException } from "@nestjs/common";
3
+
4
+ //#region src/nest/http.d.ts
5
+ interface HttpExceptionDescriptor {
6
+ readonly status?: number;
7
+ readonly code?: string | number;
8
+ readonly message?: string;
9
+ readonly details?: Record<string, unknown>;
10
+ readonly error?: string;
11
+ }
12
+ interface NestErrorOptions<E> {
13
+ readonly mapError?: (error: E) => HttpException | HttpExceptionDescriptor | undefined;
14
+ readonly fallbackMessage?: string;
15
+ }
16
+ declare const toHttpException: <E>(error: E, options?: NestErrorOptions<E>) => HttpException;
17
+ declare const unwrapOrThrow: <T, E>(result: Result<T, E>, options?: NestErrorOptions<E>) => T;
18
+ declare const unwrapPromise: <T, E>(promise: Promise<Result<T, E>>, options?: NestErrorOptions<E>) => Promise<T>;
19
+ //#endregion
20
+ export { type HttpExceptionDescriptor, type NestErrorOptions, toHttpException, unwrapOrThrow, unwrapPromise };
21
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1,43 @@
1
+ import { n as isTypedError, t as ResultKit } from "../result-kit-C5ZY61pO.mjs";
2
+ import { HttpException, HttpStatus, InternalServerErrorException } from "@nestjs/common";
3
+ //#region src/nest/http.ts
4
+ const DEFAULT_UNKNOWN_MESSAGE = "An unknown error occurred";
5
+ const DEFAULT_ERROR_CODE = "INTERNAL_SERVER_ERROR";
6
+ const normalizeErrorCode = (value) => value.trim().replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase() || DEFAULT_ERROR_CODE;
7
+ const toHttpExceptionFromDescriptor = (descriptor) => {
8
+ const status = descriptor.status ?? HttpStatus.INTERNAL_SERVER_ERROR;
9
+ return new HttpException({
10
+ code: descriptor.code ?? (status === HttpStatus.INTERNAL_SERVER_ERROR ? DEFAULT_ERROR_CODE : String(status)),
11
+ message: descriptor.message ?? DEFAULT_UNKNOWN_MESSAGE,
12
+ ...descriptor.details ? { details: descriptor.details } : {},
13
+ ...descriptor.error ? { error: descriptor.error } : {}
14
+ }, status);
15
+ };
16
+ const toHttpException = (error, options) => {
17
+ const mapped = options?.mapError?.(error);
18
+ if (mapped instanceof HttpException) return mapped;
19
+ if (mapped) return toHttpExceptionFromDescriptor(mapped);
20
+ if (error instanceof HttpException) return error;
21
+ if (isTypedError(error)) return new InternalServerErrorException({
22
+ code: normalizeErrorCode(error.type),
23
+ message: error.message,
24
+ ...error.details ? { details: error.details } : {}
25
+ });
26
+ if (error instanceof Error) return new InternalServerErrorException({
27
+ code: DEFAULT_ERROR_CODE,
28
+ message: error.message || options?.fallbackMessage || DEFAULT_UNKNOWN_MESSAGE
29
+ });
30
+ return new InternalServerErrorException({
31
+ code: DEFAULT_ERROR_CODE,
32
+ message: options?.fallbackMessage || DEFAULT_UNKNOWN_MESSAGE
33
+ });
34
+ };
35
+ const unwrapOrThrow = (result, options) => {
36
+ if (ResultKit.isSuccess(result)) return result.value;
37
+ throw toHttpException(result.error, options);
38
+ };
39
+ const unwrapPromise = async (promise, options) => unwrapOrThrow(await promise, options);
40
+ //#endregion
41
+ export { toHttpException, unwrapOrThrow, unwrapPromise };
42
+
43
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,13 @@
1
+ //#region src/core/result.d.ts
2
+ interface Success<T> {
3
+ readonly ok: true;
4
+ readonly value: T;
5
+ }
6
+ interface Failure<E> {
7
+ readonly ok: false;
8
+ readonly error: E;
9
+ }
10
+ type Result<T, E> = Success<T> | Failure<E>;
11
+ //#endregion
12
+ export { Result as n, Success as r, Failure as t };
13
+ //# sourceMappingURL=result-CI_HBDHK.d.mts.map
@@ -0,0 +1,13 @@
1
+ //#region src/core/result.d.ts
2
+ interface Success<T> {
3
+ readonly ok: true;
4
+ readonly value: T;
5
+ }
6
+ interface Failure<E> {
7
+ readonly ok: false;
8
+ readonly error: E;
9
+ }
10
+ type Result<T, E> = Success<T> | Failure<E>;
11
+ //#endregion
12
+ export { Result as n, Success as r, Failure as t };
13
+ //# sourceMappingURL=result-DbQ8o1Cs.d.cts.map
@@ -0,0 +1,172 @@
1
+ //#region src/core/error.ts
2
+ const isTypedError = (error) => {
3
+ if (!error || typeof error !== "object") return false;
4
+ const candidate = error;
5
+ if (typeof candidate.type !== "string" || typeof candidate.message !== "string") return false;
6
+ if ("details" in candidate && candidate.details !== void 0 && (candidate.details === null || typeof candidate.details !== "object" || Array.isArray(candidate.details))) return false;
7
+ return true;
8
+ };
9
+ //#endregion
10
+ //#region src/core/result-kit.ts
11
+ var ResultKit = class {
12
+ static isSuccess(result) {
13
+ return result.ok === true;
14
+ }
15
+ static isFailure(result) {
16
+ return result.ok === false;
17
+ }
18
+ static success(value) {
19
+ return {
20
+ ok: true,
21
+ value
22
+ };
23
+ }
24
+ static failure(error) {
25
+ return {
26
+ ok: false,
27
+ error
28
+ };
29
+ }
30
+ static fail(error) {
31
+ return this.failure(error);
32
+ }
33
+ static isTypedError(error) {
34
+ return isTypedError(error);
35
+ }
36
+ static map(result, fn) {
37
+ return this.isSuccess(result) ? this.success(fn(result.value)) : result;
38
+ }
39
+ static bimap(result, onSuccess, onFailure) {
40
+ return this.isSuccess(result) ? this.success(onSuccess(result.value)) : this.failure(onFailure(result.error));
41
+ }
42
+ static async mapAsync(result, fn) {
43
+ return this.isSuccess(result) ? this.success(await fn(result.value)) : result;
44
+ }
45
+ static mapError(result, fn) {
46
+ return this.isFailure(result) ? this.failure(fn(result.error)) : result;
47
+ }
48
+ static async mapErrorAsync(result, fn) {
49
+ return this.isFailure(result) ? this.failure(await fn(result.error)) : result;
50
+ }
51
+ static andThen(result, fn) {
52
+ return this.isSuccess(result) ? fn(result.value) : result;
53
+ }
54
+ static async andThenAsync(result, fn) {
55
+ return this.isSuccess(result) ? fn(result.value) : result;
56
+ }
57
+ static orElse(result, fn) {
58
+ return this.isFailure(result) ? fn(result.error) : result;
59
+ }
60
+ static async orElseAsync(result, fn) {
61
+ return this.isFailure(result) ? fn(result.error) : result;
62
+ }
63
+ static unwrap(result) {
64
+ return this.isSuccess(result) ? result.value : void 0;
65
+ }
66
+ static unwrapSuccess(result) {
67
+ return result.value;
68
+ }
69
+ static unwrapFailure(result) {
70
+ return result.error;
71
+ }
72
+ static unwrapOr(result, defaultValue) {
73
+ return this.isSuccess(result) ? result.value : defaultValue;
74
+ }
75
+ static unwrapOrElse(result, fn) {
76
+ return this.isSuccess(result) ? result.value : fn(result.error);
77
+ }
78
+ static async unwrapOrElseAsync(result, fn) {
79
+ return this.isSuccess(result) ? result.value : fn(result.error);
80
+ }
81
+ static match(result, handlers) {
82
+ return this.isSuccess(result) ? handlers.onSuccess(result.value) : handlers.onFailure(result.error);
83
+ }
84
+ static async matchAsync(result, handlers) {
85
+ return this.isSuccess(result) ? handlers.onSuccess(result.value) : handlers.onFailure(result.error);
86
+ }
87
+ static tap(result, handlers) {
88
+ if (this.isSuccess(result)) handlers.onSuccess?.(result.value);
89
+ else handlers.onFailure?.(result.error);
90
+ return result;
91
+ }
92
+ static async tapAsync(result, handlers) {
93
+ if (this.isSuccess(result)) await handlers.onSuccess?.(result.value);
94
+ else await handlers.onFailure?.(result.error);
95
+ return result;
96
+ }
97
+ static combine(results) {
98
+ const values = [];
99
+ for (const result of results) {
100
+ if (this.isFailure(result)) return result;
101
+ values.push(result.value);
102
+ }
103
+ return this.success(values);
104
+ }
105
+ static async combineAsync(results) {
106
+ return this.combine(await Promise.all(results));
107
+ }
108
+ static combineWithAllErrors(results) {
109
+ const values = [];
110
+ const errors = [];
111
+ for (const result of results) if (this.isSuccess(result)) values.push(result.value);
112
+ else errors.push(result.error);
113
+ return errors.length > 0 ? this.failure(errors) : this.success(values);
114
+ }
115
+ static async combineWithAllErrorsAsync(results) {
116
+ return this.combineWithAllErrors(await Promise.all(results));
117
+ }
118
+ static flatten(result) {
119
+ return this.isSuccess(result) ? result.value : result;
120
+ }
121
+ static async fromPromise(promise, errorFn) {
122
+ try {
123
+ return this.success(await promise);
124
+ } catch (error) {
125
+ return this.failure(errorFn(error));
126
+ }
127
+ }
128
+ static fromThrowable(fn, errorFn) {
129
+ return (...args) => {
130
+ try {
131
+ return this.success(fn(...args));
132
+ } catch (error) {
133
+ return this.failure(errorFn(error));
134
+ }
135
+ };
136
+ }
137
+ static fromThrowableAsync(fn, errorFn) {
138
+ return async (...args) => {
139
+ try {
140
+ return this.success(await fn(...args));
141
+ } catch (error) {
142
+ return this.failure(errorFn(error));
143
+ }
144
+ };
145
+ }
146
+ static fromNullable(value, error) {
147
+ return value == null ? this.failure(error) : this.success(value);
148
+ }
149
+ static fromPredicate(value, predicate, error) {
150
+ return predicate(value) ? this.success(value) : this.failure(error);
151
+ }
152
+ static toNullable(result) {
153
+ return this.isSuccess(result) ? result.value : null;
154
+ }
155
+ static partition(results) {
156
+ const values = [];
157
+ const errors = [];
158
+ for (const result of results) if (this.isSuccess(result)) values.push(result.value);
159
+ else errors.push(result.error);
160
+ return [values, errors];
161
+ }
162
+ static filterSuccesses(results) {
163
+ return results.filter((result) => this.isSuccess(result)).map((result) => result.value);
164
+ }
165
+ static filterFailures(results) {
166
+ return results.filter((result) => this.isFailure(result)).map((result) => result.error);
167
+ }
168
+ };
169
+ //#endregion
170
+ export { isTypedError as n, ResultKit as t };
171
+
172
+ //# sourceMappingURL=result-kit-C5ZY61pO.mjs.map
@@ -0,0 +1,183 @@
1
+ //#region src/core/error.ts
2
+ const isTypedError = (error) => {
3
+ if (!error || typeof error !== "object") return false;
4
+ const candidate = error;
5
+ if (typeof candidate.type !== "string" || typeof candidate.message !== "string") return false;
6
+ if ("details" in candidate && candidate.details !== void 0 && (candidate.details === null || typeof candidate.details !== "object" || Array.isArray(candidate.details))) return false;
7
+ return true;
8
+ };
9
+ //#endregion
10
+ //#region src/core/result-kit.ts
11
+ var ResultKit = class {
12
+ static isSuccess(result) {
13
+ return result.ok === true;
14
+ }
15
+ static isFailure(result) {
16
+ return result.ok === false;
17
+ }
18
+ static success(value) {
19
+ return {
20
+ ok: true,
21
+ value
22
+ };
23
+ }
24
+ static failure(error) {
25
+ return {
26
+ ok: false,
27
+ error
28
+ };
29
+ }
30
+ static fail(error) {
31
+ return this.failure(error);
32
+ }
33
+ static isTypedError(error) {
34
+ return isTypedError(error);
35
+ }
36
+ static map(result, fn) {
37
+ return this.isSuccess(result) ? this.success(fn(result.value)) : result;
38
+ }
39
+ static bimap(result, onSuccess, onFailure) {
40
+ return this.isSuccess(result) ? this.success(onSuccess(result.value)) : this.failure(onFailure(result.error));
41
+ }
42
+ static async mapAsync(result, fn) {
43
+ return this.isSuccess(result) ? this.success(await fn(result.value)) : result;
44
+ }
45
+ static mapError(result, fn) {
46
+ return this.isFailure(result) ? this.failure(fn(result.error)) : result;
47
+ }
48
+ static async mapErrorAsync(result, fn) {
49
+ return this.isFailure(result) ? this.failure(await fn(result.error)) : result;
50
+ }
51
+ static andThen(result, fn) {
52
+ return this.isSuccess(result) ? fn(result.value) : result;
53
+ }
54
+ static async andThenAsync(result, fn) {
55
+ return this.isSuccess(result) ? fn(result.value) : result;
56
+ }
57
+ static orElse(result, fn) {
58
+ return this.isFailure(result) ? fn(result.error) : result;
59
+ }
60
+ static async orElseAsync(result, fn) {
61
+ return this.isFailure(result) ? fn(result.error) : result;
62
+ }
63
+ static unwrap(result) {
64
+ return this.isSuccess(result) ? result.value : void 0;
65
+ }
66
+ static unwrapSuccess(result) {
67
+ return result.value;
68
+ }
69
+ static unwrapFailure(result) {
70
+ return result.error;
71
+ }
72
+ static unwrapOr(result, defaultValue) {
73
+ return this.isSuccess(result) ? result.value : defaultValue;
74
+ }
75
+ static unwrapOrElse(result, fn) {
76
+ return this.isSuccess(result) ? result.value : fn(result.error);
77
+ }
78
+ static async unwrapOrElseAsync(result, fn) {
79
+ return this.isSuccess(result) ? result.value : fn(result.error);
80
+ }
81
+ static match(result, handlers) {
82
+ return this.isSuccess(result) ? handlers.onSuccess(result.value) : handlers.onFailure(result.error);
83
+ }
84
+ static async matchAsync(result, handlers) {
85
+ return this.isSuccess(result) ? handlers.onSuccess(result.value) : handlers.onFailure(result.error);
86
+ }
87
+ static tap(result, handlers) {
88
+ if (this.isSuccess(result)) handlers.onSuccess?.(result.value);
89
+ else handlers.onFailure?.(result.error);
90
+ return result;
91
+ }
92
+ static async tapAsync(result, handlers) {
93
+ if (this.isSuccess(result)) await handlers.onSuccess?.(result.value);
94
+ else await handlers.onFailure?.(result.error);
95
+ return result;
96
+ }
97
+ static combine(results) {
98
+ const values = [];
99
+ for (const result of results) {
100
+ if (this.isFailure(result)) return result;
101
+ values.push(result.value);
102
+ }
103
+ return this.success(values);
104
+ }
105
+ static async combineAsync(results) {
106
+ return this.combine(await Promise.all(results));
107
+ }
108
+ static combineWithAllErrors(results) {
109
+ const values = [];
110
+ const errors = [];
111
+ for (const result of results) if (this.isSuccess(result)) values.push(result.value);
112
+ else errors.push(result.error);
113
+ return errors.length > 0 ? this.failure(errors) : this.success(values);
114
+ }
115
+ static async combineWithAllErrorsAsync(results) {
116
+ return this.combineWithAllErrors(await Promise.all(results));
117
+ }
118
+ static flatten(result) {
119
+ return this.isSuccess(result) ? result.value : result;
120
+ }
121
+ static async fromPromise(promise, errorFn) {
122
+ try {
123
+ return this.success(await promise);
124
+ } catch (error) {
125
+ return this.failure(errorFn(error));
126
+ }
127
+ }
128
+ static fromThrowable(fn, errorFn) {
129
+ return (...args) => {
130
+ try {
131
+ return this.success(fn(...args));
132
+ } catch (error) {
133
+ return this.failure(errorFn(error));
134
+ }
135
+ };
136
+ }
137
+ static fromThrowableAsync(fn, errorFn) {
138
+ return async (...args) => {
139
+ try {
140
+ return this.success(await fn(...args));
141
+ } catch (error) {
142
+ return this.failure(errorFn(error));
143
+ }
144
+ };
145
+ }
146
+ static fromNullable(value, error) {
147
+ return value == null ? this.failure(error) : this.success(value);
148
+ }
149
+ static fromPredicate(value, predicate, error) {
150
+ return predicate(value) ? this.success(value) : this.failure(error);
151
+ }
152
+ static toNullable(result) {
153
+ return this.isSuccess(result) ? result.value : null;
154
+ }
155
+ static partition(results) {
156
+ const values = [];
157
+ const errors = [];
158
+ for (const result of results) if (this.isSuccess(result)) values.push(result.value);
159
+ else errors.push(result.error);
160
+ return [values, errors];
161
+ }
162
+ static filterSuccesses(results) {
163
+ return results.filter((result) => this.isSuccess(result)).map((result) => result.value);
164
+ }
165
+ static filterFailures(results) {
166
+ return results.filter((result) => this.isFailure(result)).map((result) => result.error);
167
+ }
168
+ };
169
+ //#endregion
170
+ Object.defineProperty(exports, "ResultKit", {
171
+ enumerable: true,
172
+ get: function() {
173
+ return ResultKit;
174
+ }
175
+ });
176
+ Object.defineProperty(exports, "isTypedError", {
177
+ enumerable: true,
178
+ get: function() {
179
+ return isTypedError;
180
+ }
181
+ });
182
+
183
+ //# sourceMappingURL=result-kit-Ck1xAp-J.cjs.map
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@zireal/result-kit",
3
+ "version": "1.0.0",
4
+ "description": "Type-safe result and structured error utilities for TypeScript, with optional NestJS adapters.",
5
+ "license": "MIT",
6
+ "author": "Ali Farooq <alifarooq122@gmail.com>",
7
+ "type": "module",
8
+ "sideEffects": false,
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/alifarooq-zk/result-kit.git"
12
+ },
13
+ "keywords": [
14
+ "result",
15
+ "error-handling",
16
+ "result-type",
17
+ "result monad"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsdown",
21
+ "clean": "rm -rf dist coverage",
22
+ "changeset": "changeset",
23
+ "changeset:version": "changeset version",
24
+ "changeset:publish": "changeset publish",
25
+ "test": "vitest run",
26
+ "test:watch": "vitest watch",
27
+ "test:cov": "vitest run --coverage",
28
+ "check": "tsc --noEmit"
29
+ },
30
+ "peerDependencies": {
31
+ "@nestjs/common": "^11.0.0"
32
+ },
33
+ "peerDependenciesMeta": {
34
+ "@nestjs/common": {
35
+ "optional": true
36
+ }
37
+ },
38
+ "devDependencies": {
39
+ "@arethetypeswrong/core": "^0.18.2",
40
+ "@changesets/cli": "^2.30.0",
41
+ "@nestjs/common": "^11.1.17",
42
+ "@types/node": "^22.19.15",
43
+ "publint": "^0.3.18",
44
+ "tsdown": "^0.21.4",
45
+ "typescript": "^5.9.3",
46
+ "vitest": "^3.2.4"
47
+ },
48
+ "engines": {
49
+ "node": ">=20.0.0"
50
+ },
51
+ "main": "./dist/index.cjs",
52
+ "module": "./dist/index.mjs",
53
+ "types": "./dist/index.d.cts",
54
+ "exports": {
55
+ ".": {
56
+ "import": "./dist/index.mjs",
57
+ "require": "./dist/index.cjs"
58
+ },
59
+ "./core": {
60
+ "import": "./dist/core/index.mjs",
61
+ "require": "./dist/core/index.cjs"
62
+ },
63
+ "./nest": {
64
+ "import": "./dist/nest/index.mjs",
65
+ "require": "./dist/nest/index.cjs"
66
+ },
67
+ "./package.json": "./package.json"
68
+ }
69
+ }