@wentools/result 0.1.2-beta.94ae1942

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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -0
  3. package/esm/err/err.d.ts +38 -0
  4. package/esm/err/err.d.ts.map +1 -0
  5. package/esm/err/err.js +38 -0
  6. package/esm/err/mod.d.ts +2 -0
  7. package/esm/err/mod.d.ts.map +1 -0
  8. package/esm/err/mod.js +1 -0
  9. package/esm/is_result/is_result.d.ts +11 -0
  10. package/esm/is_result/is_result.d.ts.map +1 -0
  11. package/esm/is_result/is_result.js +14 -0
  12. package/esm/is_result/mod.d.ts +2 -0
  13. package/esm/is_result/mod.d.ts.map +1 -0
  14. package/esm/is_result/mod.js +1 -0
  15. package/esm/mod.d.ts +156 -0
  16. package/esm/mod.d.ts.map +1 -0
  17. package/esm/mod.js +65 -0
  18. package/esm/package.json +3 -0
  19. package/esm/propagate_err/mod.d.ts +2 -0
  20. package/esm/propagate_err/mod.d.ts.map +1 -0
  21. package/esm/propagate_err/mod.js +1 -0
  22. package/esm/propagate_err/propagate_err.d.ts +28 -0
  23. package/esm/propagate_err/propagate_err.d.ts.map +1 -0
  24. package/esm/propagate_err/propagate_err.js +30 -0
  25. package/package.json +33 -0
  26. package/script/err/err.d.ts +38 -0
  27. package/script/err/err.d.ts.map +1 -0
  28. package/script/err/err.js +41 -0
  29. package/script/err/mod.d.ts +2 -0
  30. package/script/err/mod.d.ts.map +1 -0
  31. package/script/err/mod.js +5 -0
  32. package/script/is_result/is_result.d.ts +11 -0
  33. package/script/is_result/is_result.d.ts.map +1 -0
  34. package/script/is_result/is_result.js +17 -0
  35. package/script/is_result/mod.d.ts +2 -0
  36. package/script/is_result/mod.d.ts.map +1 -0
  37. package/script/is_result/mod.js +5 -0
  38. package/script/mod.d.ts +156 -0
  39. package/script/mod.d.ts.map +1 -0
  40. package/script/mod.js +77 -0
  41. package/script/package.json +3 -0
  42. package/script/propagate_err/mod.d.ts +2 -0
  43. package/script/propagate_err/mod.d.ts.map +1 -0
  44. package/script/propagate_err/mod.js +5 -0
  45. package/script/propagate_err/propagate_err.d.ts +28 -0
  46. package/script/propagate_err/propagate_err.d.ts.map +1 -0
  47. package/script/propagate_err/propagate_err.js +33 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wentools
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,146 @@
1
+ # @wentools/result
2
+
3
+ A TypeScript-first wrapper around [neverthrow](https://github.com/supermacro/neverthrow) that adds literal type inference and error composition patterns.
4
+
5
+ ## Why This Exists
6
+
7
+ neverthrow is excellent for Result-based error handling, but creating typed errors requires boilerplate:
8
+
9
+ ```typescript
10
+ // With plain neverthrow
11
+ import { err } from 'neverthrow'
12
+
13
+ // You need `as const` or explicit types to preserve the literal
14
+ const result = err({ type: 'not_found' as const, message: 'User not found' })
15
+ ```
16
+
17
+ This library fixes that with TypeScript 5.0+ const type parameters:
18
+
19
+ ```typescript
20
+ // With @wentools/result
21
+ import { err } from '@wentools/result'
22
+
23
+ // Literal type is inferred automatically
24
+ const result = err('not_found', 'User not found')
25
+ // Type: Err<never, { type: 'not_found'; message: string }>
26
+ ```
27
+
28
+ It also provides utilities for:
29
+ - Defining error types concisely
30
+ - Extracting and composing error types from functions
31
+ - Runtime Result detection without importing neverthrow types
32
+
33
+ ## Install
34
+
35
+ ```bash
36
+ # JSR (recommended)
37
+ npx jsr add @wentools/result
38
+
39
+ # Deno
40
+ deno add jsr:@wentools/result
41
+ ```
42
+
43
+ ## Usage
44
+
45
+ ### Basic Error Creation
46
+
47
+ ```typescript
48
+ import { err, ok, type Result, type ErrorType } from '@wentools/result'
49
+
50
+ // Define error types concisely
51
+ type UserNotFoundError = ErrorType<'user_not_found'>
52
+ type InvalidEmailError = ErrorType<'invalid_email', { email: string }>
53
+
54
+ // Create Results with inferred literal types
55
+ const getUser = (id: string): Result<User, UserNotFoundError> => {
56
+ const user = users.get(id)
57
+ if (!user) {
58
+ return err('user_not_found', `User ${id} not found`)
59
+ }
60
+ return ok(user)
61
+ }
62
+
63
+ // Add context to errors
64
+ const validateEmail = (email: string): Result<string, InvalidEmailError> => {
65
+ if (!email.includes('@')) {
66
+ return err('invalid_email', 'Email must contain @', { email })
67
+ }
68
+ return ok(email)
69
+ }
70
+ ```
71
+
72
+ ### Async Chains
73
+
74
+ ```typescript
75
+ import { errAsync, okAsync, type ResultAsync } from '@wentools/result'
76
+
77
+ const createUser = (data: UserData): ResultAsync<User, CreateError> => {
78
+ return validateEmail(data.email)
79
+ .asyncAndThen((email) =>
80
+ checkEmailUnique(email)
81
+ .andThen(() => insertUser({ ...data, email }))
82
+ )
83
+ }
84
+ ```
85
+
86
+ ### Error Type Composition
87
+
88
+ ```typescript
89
+ import { type ExtractFnError } from '@wentools/result'
90
+
91
+ // Extract and combine error types from multiple functions
92
+ type ServiceError =
93
+ | ExtractFnError<typeof getUser>
94
+ | ExtractFnError<typeof validateEmail>
95
+ | ExtractFnError<typeof createUser>
96
+ ```
97
+
98
+ ### Runtime Type Check
99
+
100
+ ```typescript
101
+ import { isResult } from '@wentools/result'
102
+
103
+ const handle = (value: unknown) => {
104
+ if (isResult(value)) {
105
+ if (value.isErr()) {
106
+ console.error(value.error)
107
+ }
108
+ }
109
+ }
110
+ ```
111
+
112
+ ## API
113
+
114
+ ### Functions
115
+
116
+ | Function | Description |
117
+ |----------|-------------|
118
+ | `err(type, message, additional?)` | Create an Err with literal type inference |
119
+ | `errAsync(type, message, additional?)` | Async version of `err` |
120
+ | `ok(value)` | Create an Ok (re-export from neverthrow) |
121
+ | `okAsync(value)` | Create an async Ok (re-export from neverthrow) |
122
+ | `makeErr(type, message, additional?)` | Create error object without wrapping in Err |
123
+ | `rawErr(error)` | Direct neverthrow `err()` for lifting unstructured errors |
124
+ | `isResult(value)` | Runtime check if value is a Result |
125
+ | `propagateErr(result)` | Propagate error to different Result type |
126
+
127
+ ### Types
128
+
129
+ | Type | Description |
130
+ |------|-------------|
131
+ | `Result<T, E>` | Sync Result (from neverthrow) |
132
+ | `ResultAsync<T, E>` | Async Result (from neverthrow) |
133
+ | `ErrorType<Type, Additional?>` | Utility for defining `{ type, message, ...additional }` |
134
+ | `ExtractError<T>` | Extract error type from Result or Promise<Result> |
135
+ | `ExtractFnError<F>` | Extract error type from function return type |
136
+ | `ExtractErrors<T[]>` | Union of errors from multiple Results |
137
+ | `ExtractFnsError<F[]>` | Union of errors from multiple functions |
138
+
139
+ ## Requirements
140
+
141
+ - TypeScript 5.0+ (for const type parameters)
142
+ - neverthrow 8.x (peer dependency)
143
+
144
+ ## License
145
+
146
+ MIT
@@ -0,0 +1,38 @@
1
+ import { type Err } from 'neverthrow';
2
+ /**
3
+ * Create an Err Result with automatic literal type preservation
4
+ *
5
+ * Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
6
+ * No need for 'as const' - the type parameter is inferred as a literal!
7
+ *
8
+ * Returns Err<never, E> (not Result<never, E>) so .error is directly accessible.
9
+ *
10
+ * @example
11
+ * // ✅ Simple error
12
+ * return err('not_found', 'User not found')
13
+ * // Type: Err<never, { type: 'not_found', message: string }>
14
+ *
15
+ * @example
16
+ * // ✅ Error with additional properties
17
+ * return err('not_found', 'User not found', { userId: '123' })
18
+ * // Type: Err<never, { type: 'not_found', message: string, userId: string }>
19
+ *
20
+ * @example
21
+ * // ✅ Direct .error access (no narrowing needed)
22
+ * const error = err('not_found', 'User not found').error
23
+ * // error.type is 'not_found'
24
+ *
25
+ * @example
26
+ * // ✅ Error with complex additional data
27
+ * return err('validation_failed', 'Invalid input', {
28
+ * field: 'email',
29
+ * errors: ['Invalid format']
30
+ * })
31
+ * // Type: Err<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
32
+ */
33
+ declare const err: <const TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>>(type: TType, message: string, additional?: TAdditional) => Err<never, {
34
+ type: TType;
35
+ message: string;
36
+ } & TAdditional>;
37
+ export { err };
38
+ //# sourceMappingURL=err.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"err.d.ts","sourceRoot":"","sources":["../../src/err/err.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,GAAG,EAAE,MAAM,YAAY,CAAA;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,QAAA,MAAM,GAAG,GACR,KAAK,CAAC,KAAK,SAAS,MAAM,EAC1B,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAEnE,MAAM,KAAK,EACX,SAAS,MAAM,EACf,aAAa,WAAW,KACtB,GAAG,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,WAAW,CAKP,CAAA;AAErD,OAAO,EAAE,GAAG,EAAE,CAAA"}
package/esm/err/err.js ADDED
@@ -0,0 +1,38 @@
1
+ import { err as _Err } from 'neverthrow';
2
+ /**
3
+ * Create an Err Result with automatic literal type preservation
4
+ *
5
+ * Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
6
+ * No need for 'as const' - the type parameter is inferred as a literal!
7
+ *
8
+ * Returns Err<never, E> (not Result<never, E>) so .error is directly accessible.
9
+ *
10
+ * @example
11
+ * // ✅ Simple error
12
+ * return err('not_found', 'User not found')
13
+ * // Type: Err<never, { type: 'not_found', message: string }>
14
+ *
15
+ * @example
16
+ * // ✅ Error with additional properties
17
+ * return err('not_found', 'User not found', { userId: '123' })
18
+ * // Type: Err<never, { type: 'not_found', message: string, userId: string }>
19
+ *
20
+ * @example
21
+ * // ✅ Direct .error access (no narrowing needed)
22
+ * const error = err('not_found', 'User not found').error
23
+ * // error.type is 'not_found'
24
+ *
25
+ * @example
26
+ * // ✅ Error with complex additional data
27
+ * return err('validation_failed', 'Invalid input', {
28
+ * field: 'email',
29
+ * errors: ['Invalid format']
30
+ * })
31
+ * // Type: Err<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
32
+ */
33
+ const err = (type, message, additional) => _Err({
34
+ ...additional,
35
+ type,
36
+ message,
37
+ });
38
+ export { err };
@@ -0,0 +1,2 @@
1
+ export { err } from './err.js';
2
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/err/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA"}
package/esm/err/mod.js ADDED
@@ -0,0 +1 @@
1
+ export { err } from './err.js';
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Check if a value is a neverthrow Result type
3
+ *
4
+ * Uses duck typing to detect Result objects without importing neverthrow types.
5
+ */
6
+ declare const isResult: (value: unknown) => value is {
7
+ isOk: () => boolean;
8
+ isErr: () => boolean;
9
+ };
10
+ export { isResult };
11
+ //# sourceMappingURL=is_result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is_result.d.ts","sourceRoot":"","sources":["../../src/is_result/is_result.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,QAAA,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI;IAAE,IAAI,EAAE,MAAM,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,OAAO,CAAA;CAStF,CAAA;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Check if a value is a neverthrow Result type
3
+ *
4
+ * Uses duck typing to detect Result objects without importing neverthrow types.
5
+ */
6
+ const isResult = (value) => {
7
+ return (value !== null &&
8
+ typeof value === 'object' &&
9
+ 'isOk' in value &&
10
+ 'isErr' in value &&
11
+ typeof value.isOk === 'function' &&
12
+ typeof value.isErr === 'function');
13
+ };
14
+ export { isResult };
@@ -0,0 +1,2 @@
1
+ export { isResult } from './is_result.js';
2
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/is_result/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA"}
@@ -0,0 +1 @@
1
+ export { isResult } from './is_result.js';
package/esm/mod.d.ts ADDED
@@ -0,0 +1,156 @@
1
+ import { err as _Err, ok, type Result, type Err, ResultAsync, okAsync as neverthrowOkAsync } from 'neverthrow';
2
+ /**
3
+ * Create an error object with literal type preservation
4
+ *
5
+ * @example
6
+ * const error = makeErr('not_found', 'User not found')
7
+ * // ✅ Type: { type: 'not_found', message: string }
8
+ *
9
+ * @example
10
+ * const error = makeErr('not_found', 'User not found', { userId: '123' })
11
+ * // ✅ Type: { type: 'not_found', message: string, userId: string }
12
+ */
13
+ declare const makeErr: <const TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>>(type: TType, message: string, additional?: TAdditional) => {
14
+ type: TType;
15
+ message: string;
16
+ } & TAdditional;
17
+ /**
18
+ * Create an async Err ResultAsync with automatic literal type preservation
19
+ *
20
+ * Async version of err() - same signature, returns ResultAsync instead of Result.
21
+ * Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
22
+ *
23
+ * @example
24
+ * // ✅ Simple error
25
+ * return errAsync('not_found', 'User not found')
26
+ * // Type: ResultAsync<never, { type: 'not_found', message: string }>
27
+ *
28
+ * @example
29
+ * // ✅ Error with additional properties
30
+ * return errAsync('not_found', 'User not found', { userId: '123' })
31
+ * // Type: ResultAsync<never, { type: 'not_found', message: string, userId: string }>
32
+ *
33
+ * @example
34
+ * // ✅ Error with complex additional data
35
+ * return errAsync('validation_failed', 'Invalid input', {
36
+ * field: 'email',
37
+ * errors: ['Invalid format']
38
+ * })
39
+ * // Type: ResultAsync<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
40
+ */
41
+ declare const errAsync: <const TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>>(type: TType, message: string, additional?: TAdditional) => ResultAsync<never, {
42
+ type: TType;
43
+ message: string;
44
+ } & TAdditional>;
45
+ /**
46
+ * Re-export okAsync from neverthrow for consistency
47
+ * Creates a successful ResultAsync
48
+ */
49
+ declare const okAsync: typeof neverthrowOkAsync;
50
+ /**
51
+ * Utility type for defining error types concisely
52
+ *
53
+ * @example
54
+ * // Instead of:
55
+ * type UserNotFoundError = {
56
+ * type: 'user_not_found'
57
+ * message: string
58
+ * userId: UserId
59
+ * }
60
+ *
61
+ * // Write:
62
+ * type UserNotFoundError = ErrorType<'user_not_found', { userId: UserId }>
63
+ *
64
+ * @example
65
+ * // Error without additional properties:
66
+ * type InvalidOperationError = ErrorType<'invalid_operation'>
67
+ */
68
+ type ErrorType<TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>> = {
69
+ type: TType;
70
+ message: string;
71
+ } & TAdditional;
72
+ /**
73
+ * Extract the error type from a Result or Promise<Result>
74
+ *
75
+ * @example
76
+ * // From async function
77
+ * const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
78
+ * type GetUserError = ExtractError<ReturnType<typeof getUser>>
79
+ * // Type: UserNotFoundError
80
+ *
81
+ * @example
82
+ * // From Result type directly
83
+ * type MyResult = Result<User, InvalidError>
84
+ * type MyError = ExtractError<MyResult>
85
+ * // Type: InvalidError
86
+ *
87
+ * @example
88
+ * // Works with composed errors
89
+ * const replaceVersion = async (): Promise<Result<Version, VersionNotFoundError | VersionExistsError>> => { ... }
90
+ * type ReplaceError = ExtractError<ReturnType<typeof replaceVersion>>
91
+ * // Type: VersionNotFoundError | VersionExistsError
92
+ */
93
+ type ExtractError<TResultOrPromise> = TResultOrPromise extends Promise<Result<unknown, infer TError>> ? TError : TResultOrPromise extends Result<unknown, infer TError> ? TError : never;
94
+ /**
95
+ * Extract the error type from a function that returns Result or Promise<Result>
96
+ *
97
+ * @example
98
+ * // Simple extraction
99
+ * const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
100
+ * type GetUserError = ExtractFnError<typeof getUser>
101
+ * // Type: UserNotFoundError
102
+ *
103
+ * @example
104
+ * // Compose errors from multiple functions
105
+ * const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
106
+ * const getImage = async (id: string): Promise<Result<Image, ImageNotFoundError>> => { ... }
107
+ * type CombinedError = ExtractFnError<typeof getUser> | ExtractFnError<typeof getImage>
108
+ * // Type: UserNotFoundError | ImageNotFoundError
109
+ */
110
+ type ExtractFnError<TFunction extends (...args: unknown[]) => unknown> = ExtractError<ReturnType<TFunction>>;
111
+ /**
112
+ * Extract and combine error types from multiple Result or Promise<Result> types
113
+ *
114
+ * @example
115
+ * type UserResult = Result<User, UserNotFoundError>
116
+ * type ImageResult = Promise<Result<Image, ImageNotFoundError>>
117
+ * type ProductResult = Result<Product, ProductNotFoundError>
118
+ *
119
+ * type CombinedError = ExtractErrors<[UserResult, ImageResult, ProductResult]>
120
+ * // Type: UserNotFoundError | ImageNotFoundError | ProductNotFoundError
121
+ */
122
+ type ExtractErrors<TResults extends readonly unknown[]> = TResults extends readonly [
123
+ infer TFirst,
124
+ ...infer TRest
125
+ ] ? ExtractError<TFirst> | ExtractErrors<TRest> : never;
126
+ /**
127
+ * Extract and combine error types from multiple functions that return Result or Promise<Result>
128
+ *
129
+ * @example
130
+ * const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
131
+ * const getImage = async (id: string): Promise<Result<Image, ImageNotFoundError>> => { ... }
132
+ * const deleteProduct = async (id: string): Promise<Result<void, ProductNotFoundError>> => { ... }
133
+ *
134
+ * type CombinedError = ExtractFnsError<[typeof getUser, typeof getImage, typeof deleteProduct]>
135
+ * // Type: UserNotFoundError | ImageNotFoundError | ProductNotFoundError
136
+ */
137
+ type ExtractFnsError<TFunctions extends readonly ((...args: unknown[]) => unknown)[]> = TFunctions extends readonly [
138
+ infer TFirst,
139
+ ...infer TRest extends readonly ((...args: unknown[]) => unknown)[]
140
+ ] ? ExtractFnError<TFirst & ((...args: unknown[]) => unknown)> | ExtractFnsError<TRest> : never;
141
+ /**
142
+ * Raw error function from neverthrow - use for lifting database errors directly
143
+ *
144
+ * @example
145
+ * const seedResult = await songSeeds.get.one.byId(songSeedId)
146
+ * if (seedResult.isErr()) {
147
+ * return rawErr(seedResult.error)
148
+ * }
149
+ */
150
+ declare const rawErr: typeof _Err;
151
+ export { makeErr, errAsync, ok, okAsync, rawErr, _Err, ResultAsync };
152
+ export type { Result, Err, ErrorType, ExtractError, ExtractFnError, ExtractErrors, ExtractFnsError };
153
+ export { err } from './err/mod.js';
154
+ export { isResult } from './is_result/mod.js';
155
+ export { propagateErr } from './propagate_err/mod.js';
156
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"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"}
package/esm/mod.js ADDED
@@ -0,0 +1,65 @@
1
+ import { err as _Err, ok, ResultAsync, errAsync as neverthrowErrAsync, okAsync as neverthrowOkAsync, } from 'neverthrow';
2
+ /**
3
+ * Create an error object with literal type preservation
4
+ *
5
+ * @example
6
+ * const error = makeErr('not_found', 'User not found')
7
+ * // ✅ Type: { type: 'not_found', message: string }
8
+ *
9
+ * @example
10
+ * const error = makeErr('not_found', 'User not found', { userId: '123' })
11
+ * // ✅ Type: { type: 'not_found', message: string, userId: string }
12
+ */
13
+ const makeErr = (type, message, additional) => ({
14
+ ...additional,
15
+ type,
16
+ message,
17
+ });
18
+ /**
19
+ * Create an async Err ResultAsync with automatic literal type preservation
20
+ *
21
+ * Async version of err() - same signature, returns ResultAsync instead of Result.
22
+ * Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
23
+ *
24
+ * @example
25
+ * // ✅ Simple error
26
+ * return errAsync('not_found', 'User not found')
27
+ * // Type: ResultAsync<never, { type: 'not_found', message: string }>
28
+ *
29
+ * @example
30
+ * // ✅ Error with additional properties
31
+ * return errAsync('not_found', 'User not found', { userId: '123' })
32
+ * // Type: ResultAsync<never, { type: 'not_found', message: string, userId: string }>
33
+ *
34
+ * @example
35
+ * // ✅ Error with complex additional data
36
+ * return errAsync('validation_failed', 'Invalid input', {
37
+ * field: 'email',
38
+ * errors: ['Invalid format']
39
+ * })
40
+ * // Type: ResultAsync<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
41
+ */
42
+ const errAsync = (type, message, additional) => neverthrowErrAsync({
43
+ ...additional,
44
+ type,
45
+ message,
46
+ });
47
+ /**
48
+ * Re-export okAsync from neverthrow for consistency
49
+ * Creates a successful ResultAsync
50
+ */
51
+ const okAsync = neverthrowOkAsync;
52
+ /**
53
+ * Raw error function from neverthrow - use for lifting database errors directly
54
+ *
55
+ * @example
56
+ * const seedResult = await songSeeds.get.one.byId(songSeedId)
57
+ * if (seedResult.isErr()) {
58
+ * return rawErr(seedResult.error)
59
+ * }
60
+ */
61
+ const rawErr = _Err;
62
+ export { makeErr, errAsync, ok, okAsync, rawErr, _Err, ResultAsync };
63
+ export { err } from './err/mod.js';
64
+ export { isResult } from './is_result/mod.js';
65
+ export { propagateErr } from './propagate_err/mod.js';
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,2 @@
1
+ export { propagateErr } from './propagate_err.js';
2
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/propagate_err/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1 @@
1
+ export { propagateErr } from './propagate_err.js';
@@ -0,0 +1,28 @@
1
+ import type { Result } from 'neverthrow';
2
+ /**
3
+ * Propagates an error Result to a different success type context.
4
+ *
5
+ * This is safe because error Results never contain the success value - only the error.
6
+ * TypeScript's structural typing prevents direct assignment of Result<T, E> to Result<U, E>
7
+ * even though the error type is identical and we're in the error branch.
8
+ *
9
+ * Common use case: Early return from a function that creates multiple items. If creating
10
+ * item 2 fails with Result<Item, DatabaseError>, we need to return Result<Item[], DatabaseError>.
11
+ *
12
+ * @example
13
+ * const result = await createUser(db, data) // Result<User, DatabaseError>
14
+ * if (result.isErr()) {
15
+ * // Need to return Result<Profile, DatabaseError> but have Result<User, DatabaseError>
16
+ * return propagateErr(result)
17
+ * }
18
+ *
19
+ * @example
20
+ * // In bulk creation, propagate single-item error to array context
21
+ * const itemResult = await createItem(data) // Result<Item, Error>
22
+ * if (itemResult.isErr()) {
23
+ * return propagateErr<Item[], Error>(itemResult) // Result<Item[], Error>
24
+ * }
25
+ */
26
+ declare const propagateErr: <TNew, E>(errorResult: Result<unknown, E>) => Result<TNew, E>;
27
+ export { propagateErr };
28
+ //# sourceMappingURL=propagate_err.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"propagate_err.d.ts","sourceRoot":"","sources":["../../src/propagate_err/propagate_err.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,QAAA,MAAM,YAAY,GAAI,IAAI,EAAE,CAAC,EAAE,aAAa,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,KAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAI9E,CAAA;AAED,OAAO,EAAE,YAAY,EAAE,CAAA"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Propagates an error Result to a different success type context.
3
+ *
4
+ * This is safe because error Results never contain the success value - only the error.
5
+ * TypeScript's structural typing prevents direct assignment of Result<T, E> to Result<U, E>
6
+ * even though the error type is identical and we're in the error branch.
7
+ *
8
+ * Common use case: Early return from a function that creates multiple items. If creating
9
+ * item 2 fails with Result<Item, DatabaseError>, we need to return Result<Item[], DatabaseError>.
10
+ *
11
+ * @example
12
+ * const result = await createUser(db, data) // Result<User, DatabaseError>
13
+ * if (result.isErr()) {
14
+ * // Need to return Result<Profile, DatabaseError> but have Result<User, DatabaseError>
15
+ * return propagateErr(result)
16
+ * }
17
+ *
18
+ * @example
19
+ * // In bulk creation, propagate single-item error to array context
20
+ * const itemResult = await createItem(data) // Result<Item, Error>
21
+ * if (itemResult.isErr()) {
22
+ * return propagateErr<Item[], Error>(itemResult) // Result<Item[], Error>
23
+ * }
24
+ */
25
+ const propagateErr = (errorResult) => {
26
+ // Type assertion is safe: we're only propagating errors, and error Results
27
+ // don't contain the success value. The error type E is preserved exactly.
28
+ return errorResult;
29
+ };
30
+ export { propagateErr };
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@wentools/result",
3
+ "version": "0.1.2-beta.94ae1942",
4
+ "description": "TypeScript-first Result type with literal error inference",
5
+ "keywords": [
6
+ "result",
7
+ "neverthrow",
8
+ "typescript",
9
+ "error-handling",
10
+ "type-safe"
11
+ ],
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://gitlab.com/wentools/result"
15
+ },
16
+ "license": "MIT",
17
+ "main": "./script/mod.js",
18
+ "module": "./esm/mod.js",
19
+ "exports": {
20
+ ".": {
21
+ "import": "./esm/mod.js",
22
+ "require": "./script/mod.js"
23
+ }
24
+ },
25
+ "scripts": {},
26
+ "dependencies": {
27
+ "neverthrow": "^8.2.0"
28
+ },
29
+ "peerDependencies": {
30
+ "neverthrow": "^8.2.0"
31
+ },
32
+ "_generatedBy": "dnt@dev"
33
+ }
@@ -0,0 +1,38 @@
1
+ import { type Err } from 'neverthrow';
2
+ /**
3
+ * Create an Err Result with automatic literal type preservation
4
+ *
5
+ * Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
6
+ * No need for 'as const' - the type parameter is inferred as a literal!
7
+ *
8
+ * Returns Err<never, E> (not Result<never, E>) so .error is directly accessible.
9
+ *
10
+ * @example
11
+ * // ✅ Simple error
12
+ * return err('not_found', 'User not found')
13
+ * // Type: Err<never, { type: 'not_found', message: string }>
14
+ *
15
+ * @example
16
+ * // ✅ Error with additional properties
17
+ * return err('not_found', 'User not found', { userId: '123' })
18
+ * // Type: Err<never, { type: 'not_found', message: string, userId: string }>
19
+ *
20
+ * @example
21
+ * // ✅ Direct .error access (no narrowing needed)
22
+ * const error = err('not_found', 'User not found').error
23
+ * // error.type is 'not_found'
24
+ *
25
+ * @example
26
+ * // ✅ Error with complex additional data
27
+ * return err('validation_failed', 'Invalid input', {
28
+ * field: 'email',
29
+ * errors: ['Invalid format']
30
+ * })
31
+ * // Type: Err<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
32
+ */
33
+ declare const err: <const TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>>(type: TType, message: string, additional?: TAdditional) => Err<never, {
34
+ type: TType;
35
+ message: string;
36
+ } & TAdditional>;
37
+ export { err };
38
+ //# sourceMappingURL=err.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"err.d.ts","sourceRoot":"","sources":["../../src/err/err.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,GAAG,EAAE,MAAM,YAAY,CAAA;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,QAAA,MAAM,GAAG,GACR,KAAK,CAAC,KAAK,SAAS,MAAM,EAC1B,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAEnE,MAAM,KAAK,EACX,SAAS,MAAM,EACf,aAAa,WAAW,KACtB,GAAG,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,WAAW,CAKP,CAAA;AAErD,OAAO,EAAE,GAAG,EAAE,CAAA"}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.err = void 0;
4
+ const neverthrow_1 = require("neverthrow");
5
+ /**
6
+ * Create an Err Result with automatic literal type preservation
7
+ *
8
+ * Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
9
+ * No need for 'as const' - the type parameter is inferred as a literal!
10
+ *
11
+ * Returns Err<never, E> (not Result<never, E>) so .error is directly accessible.
12
+ *
13
+ * @example
14
+ * // ✅ Simple error
15
+ * return err('not_found', 'User not found')
16
+ * // Type: Err<never, { type: 'not_found', message: string }>
17
+ *
18
+ * @example
19
+ * // ✅ Error with additional properties
20
+ * return err('not_found', 'User not found', { userId: '123' })
21
+ * // Type: Err<never, { type: 'not_found', message: string, userId: string }>
22
+ *
23
+ * @example
24
+ * // ✅ Direct .error access (no narrowing needed)
25
+ * const error = err('not_found', 'User not found').error
26
+ * // error.type is 'not_found'
27
+ *
28
+ * @example
29
+ * // ✅ Error with complex additional data
30
+ * return err('validation_failed', 'Invalid input', {
31
+ * field: 'email',
32
+ * errors: ['Invalid format']
33
+ * })
34
+ * // Type: Err<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
35
+ */
36
+ const err = (type, message, additional) => (0, neverthrow_1.err)({
37
+ ...additional,
38
+ type,
39
+ message,
40
+ });
41
+ exports.err = err;
@@ -0,0 +1,2 @@
1
+ export { err } from './err.js';
2
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/err/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.err = void 0;
4
+ var err_js_1 = require("./err.js");
5
+ Object.defineProperty(exports, "err", { enumerable: true, get: function () { return err_js_1.err; } });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Check if a value is a neverthrow Result type
3
+ *
4
+ * Uses duck typing to detect Result objects without importing neverthrow types.
5
+ */
6
+ declare const isResult: (value: unknown) => value is {
7
+ isOk: () => boolean;
8
+ isErr: () => boolean;
9
+ };
10
+ export { isResult };
11
+ //# sourceMappingURL=is_result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is_result.d.ts","sourceRoot":"","sources":["../../src/is_result/is_result.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,QAAA,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI;IAAE,IAAI,EAAE,MAAM,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,OAAO,CAAA;CAStF,CAAA;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ /**
3
+ * Check if a value is a neverthrow Result type
4
+ *
5
+ * Uses duck typing to detect Result objects without importing neverthrow types.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.isResult = void 0;
9
+ const isResult = (value) => {
10
+ return (value !== null &&
11
+ typeof value === 'object' &&
12
+ 'isOk' in value &&
13
+ 'isErr' in value &&
14
+ typeof value.isOk === 'function' &&
15
+ typeof value.isErr === 'function');
16
+ };
17
+ exports.isResult = isResult;
@@ -0,0 +1,2 @@
1
+ export { isResult } from './is_result.js';
2
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/is_result/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isResult = void 0;
4
+ var is_result_js_1 = require("./is_result.js");
5
+ Object.defineProperty(exports, "isResult", { enumerable: true, get: function () { return is_result_js_1.isResult; } });
@@ -0,0 +1,156 @@
1
+ import { err as _Err, ok, type Result, type Err, ResultAsync, okAsync as neverthrowOkAsync } from 'neverthrow';
2
+ /**
3
+ * Create an error object with literal type preservation
4
+ *
5
+ * @example
6
+ * const error = makeErr('not_found', 'User not found')
7
+ * // ✅ Type: { type: 'not_found', message: string }
8
+ *
9
+ * @example
10
+ * const error = makeErr('not_found', 'User not found', { userId: '123' })
11
+ * // ✅ Type: { type: 'not_found', message: string, userId: string }
12
+ */
13
+ declare const makeErr: <const TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>>(type: TType, message: string, additional?: TAdditional) => {
14
+ type: TType;
15
+ message: string;
16
+ } & TAdditional;
17
+ /**
18
+ * Create an async Err ResultAsync with automatic literal type preservation
19
+ *
20
+ * Async version of err() - same signature, returns ResultAsync instead of Result.
21
+ * Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
22
+ *
23
+ * @example
24
+ * // ✅ Simple error
25
+ * return errAsync('not_found', 'User not found')
26
+ * // Type: ResultAsync<never, { type: 'not_found', message: string }>
27
+ *
28
+ * @example
29
+ * // ✅ Error with additional properties
30
+ * return errAsync('not_found', 'User not found', { userId: '123' })
31
+ * // Type: ResultAsync<never, { type: 'not_found', message: string, userId: string }>
32
+ *
33
+ * @example
34
+ * // ✅ Error with complex additional data
35
+ * return errAsync('validation_failed', 'Invalid input', {
36
+ * field: 'email',
37
+ * errors: ['Invalid format']
38
+ * })
39
+ * // Type: ResultAsync<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
40
+ */
41
+ declare const errAsync: <const TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>>(type: TType, message: string, additional?: TAdditional) => ResultAsync<never, {
42
+ type: TType;
43
+ message: string;
44
+ } & TAdditional>;
45
+ /**
46
+ * Re-export okAsync from neverthrow for consistency
47
+ * Creates a successful ResultAsync
48
+ */
49
+ declare const okAsync: typeof neverthrowOkAsync;
50
+ /**
51
+ * Utility type for defining error types concisely
52
+ *
53
+ * @example
54
+ * // Instead of:
55
+ * type UserNotFoundError = {
56
+ * type: 'user_not_found'
57
+ * message: string
58
+ * userId: UserId
59
+ * }
60
+ *
61
+ * // Write:
62
+ * type UserNotFoundError = ErrorType<'user_not_found', { userId: UserId }>
63
+ *
64
+ * @example
65
+ * // Error without additional properties:
66
+ * type InvalidOperationError = ErrorType<'invalid_operation'>
67
+ */
68
+ type ErrorType<TType extends string, TAdditional extends Record<string, unknown> = Record<string, never>> = {
69
+ type: TType;
70
+ message: string;
71
+ } & TAdditional;
72
+ /**
73
+ * Extract the error type from a Result or Promise<Result>
74
+ *
75
+ * @example
76
+ * // From async function
77
+ * const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
78
+ * type GetUserError = ExtractError<ReturnType<typeof getUser>>
79
+ * // Type: UserNotFoundError
80
+ *
81
+ * @example
82
+ * // From Result type directly
83
+ * type MyResult = Result<User, InvalidError>
84
+ * type MyError = ExtractError<MyResult>
85
+ * // Type: InvalidError
86
+ *
87
+ * @example
88
+ * // Works with composed errors
89
+ * const replaceVersion = async (): Promise<Result<Version, VersionNotFoundError | VersionExistsError>> => { ... }
90
+ * type ReplaceError = ExtractError<ReturnType<typeof replaceVersion>>
91
+ * // Type: VersionNotFoundError | VersionExistsError
92
+ */
93
+ type ExtractError<TResultOrPromise> = TResultOrPromise extends Promise<Result<unknown, infer TError>> ? TError : TResultOrPromise extends Result<unknown, infer TError> ? TError : never;
94
+ /**
95
+ * Extract the error type from a function that returns Result or Promise<Result>
96
+ *
97
+ * @example
98
+ * // Simple extraction
99
+ * const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
100
+ * type GetUserError = ExtractFnError<typeof getUser>
101
+ * // Type: UserNotFoundError
102
+ *
103
+ * @example
104
+ * // Compose errors from multiple functions
105
+ * const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
106
+ * const getImage = async (id: string): Promise<Result<Image, ImageNotFoundError>> => { ... }
107
+ * type CombinedError = ExtractFnError<typeof getUser> | ExtractFnError<typeof getImage>
108
+ * // Type: UserNotFoundError | ImageNotFoundError
109
+ */
110
+ type ExtractFnError<TFunction extends (...args: unknown[]) => unknown> = ExtractError<ReturnType<TFunction>>;
111
+ /**
112
+ * Extract and combine error types from multiple Result or Promise<Result> types
113
+ *
114
+ * @example
115
+ * type UserResult = Result<User, UserNotFoundError>
116
+ * type ImageResult = Promise<Result<Image, ImageNotFoundError>>
117
+ * type ProductResult = Result<Product, ProductNotFoundError>
118
+ *
119
+ * type CombinedError = ExtractErrors<[UserResult, ImageResult, ProductResult]>
120
+ * // Type: UserNotFoundError | ImageNotFoundError | ProductNotFoundError
121
+ */
122
+ type ExtractErrors<TResults extends readonly unknown[]> = TResults extends readonly [
123
+ infer TFirst,
124
+ ...infer TRest
125
+ ] ? ExtractError<TFirst> | ExtractErrors<TRest> : never;
126
+ /**
127
+ * Extract and combine error types from multiple functions that return Result or Promise<Result>
128
+ *
129
+ * @example
130
+ * const getUser = async (id: string): Promise<Result<User, UserNotFoundError>> => { ... }
131
+ * const getImage = async (id: string): Promise<Result<Image, ImageNotFoundError>> => { ... }
132
+ * const deleteProduct = async (id: string): Promise<Result<void, ProductNotFoundError>> => { ... }
133
+ *
134
+ * type CombinedError = ExtractFnsError<[typeof getUser, typeof getImage, typeof deleteProduct]>
135
+ * // Type: UserNotFoundError | ImageNotFoundError | ProductNotFoundError
136
+ */
137
+ type ExtractFnsError<TFunctions extends readonly ((...args: unknown[]) => unknown)[]> = TFunctions extends readonly [
138
+ infer TFirst,
139
+ ...infer TRest extends readonly ((...args: unknown[]) => unknown)[]
140
+ ] ? ExtractFnError<TFirst & ((...args: unknown[]) => unknown)> | ExtractFnsError<TRest> : never;
141
+ /**
142
+ * Raw error function from neverthrow - use for lifting database errors directly
143
+ *
144
+ * @example
145
+ * const seedResult = await songSeeds.get.one.byId(songSeedId)
146
+ * if (seedResult.isErr()) {
147
+ * return rawErr(seedResult.error)
148
+ * }
149
+ */
150
+ declare const rawErr: typeof _Err;
151
+ export { makeErr, errAsync, ok, okAsync, rawErr, _Err, ResultAsync };
152
+ export type { Result, Err, ErrorType, ExtractError, ExtractFnError, ExtractErrors, ExtractFnsError };
153
+ export { err } from './err/mod.js';
154
+ export { isResult } from './is_result/mod.js';
155
+ export { propagateErr } from './propagate_err/mod.js';
156
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"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"}
package/script/mod.js ADDED
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.propagateErr = exports.isResult = exports.err = exports.ResultAsync = exports._Err = exports.rawErr = exports.okAsync = exports.ok = exports.errAsync = exports.makeErr = void 0;
4
+ const neverthrow_1 = require("neverthrow");
5
+ Object.defineProperty(exports, "_Err", { enumerable: true, get: function () { return neverthrow_1.err; } });
6
+ Object.defineProperty(exports, "ok", { enumerable: true, get: function () { return neverthrow_1.ok; } });
7
+ Object.defineProperty(exports, "ResultAsync", { enumerable: true, get: function () { return neverthrow_1.ResultAsync; } });
8
+ /**
9
+ * Create an error object with literal type preservation
10
+ *
11
+ * @example
12
+ * const error = makeErr('not_found', 'User not found')
13
+ * // ✅ Type: { type: 'not_found', message: string }
14
+ *
15
+ * @example
16
+ * const error = makeErr('not_found', 'User not found', { userId: '123' })
17
+ * // ✅ Type: { type: 'not_found', message: string, userId: string }
18
+ */
19
+ const makeErr = (type, message, additional) => ({
20
+ ...additional,
21
+ type,
22
+ message,
23
+ });
24
+ exports.makeErr = makeErr;
25
+ /**
26
+ * Create an async Err ResultAsync with automatic literal type preservation
27
+ *
28
+ * Async version of err() - same signature, returns ResultAsync instead of Result.
29
+ * Uses TypeScript 5.0+ const type parameters to preserve literal types automatically.
30
+ *
31
+ * @example
32
+ * // ✅ Simple error
33
+ * return errAsync('not_found', 'User not found')
34
+ * // Type: ResultAsync<never, { type: 'not_found', message: string }>
35
+ *
36
+ * @example
37
+ * // ✅ Error with additional properties
38
+ * return errAsync('not_found', 'User not found', { userId: '123' })
39
+ * // Type: ResultAsync<never, { type: 'not_found', message: string, userId: string }>
40
+ *
41
+ * @example
42
+ * // ✅ Error with complex additional data
43
+ * return errAsync('validation_failed', 'Invalid input', {
44
+ * field: 'email',
45
+ * errors: ['Invalid format']
46
+ * })
47
+ * // Type: ResultAsync<never, { type: 'validation_failed', message: string, field: string, errors: string[] }>
48
+ */
49
+ const errAsync = (type, message, additional) => (0, neverthrow_1.errAsync)({
50
+ ...additional,
51
+ type,
52
+ message,
53
+ });
54
+ exports.errAsync = errAsync;
55
+ /**
56
+ * Re-export okAsync from neverthrow for consistency
57
+ * Creates a successful ResultAsync
58
+ */
59
+ const okAsync = neverthrow_1.okAsync;
60
+ exports.okAsync = okAsync;
61
+ /**
62
+ * Raw error function from neverthrow - use for lifting database errors directly
63
+ *
64
+ * @example
65
+ * const seedResult = await songSeeds.get.one.byId(songSeedId)
66
+ * if (seedResult.isErr()) {
67
+ * return rawErr(seedResult.error)
68
+ * }
69
+ */
70
+ const rawErr = neverthrow_1.err;
71
+ exports.rawErr = rawErr;
72
+ var mod_js_1 = require("./err/mod.js");
73
+ Object.defineProperty(exports, "err", { enumerable: true, get: function () { return mod_js_1.err; } });
74
+ var mod_js_2 = require("./is_result/mod.js");
75
+ Object.defineProperty(exports, "isResult", { enumerable: true, get: function () { return mod_js_2.isResult; } });
76
+ var mod_js_3 = require("./propagate_err/mod.js");
77
+ Object.defineProperty(exports, "propagateErr", { enumerable: true, get: function () { return mod_js_3.propagateErr; } });
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,2 @@
1
+ export { propagateErr } from './propagate_err.js';
2
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/propagate_err/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.propagateErr = void 0;
4
+ var propagate_err_js_1 = require("./propagate_err.js");
5
+ Object.defineProperty(exports, "propagateErr", { enumerable: true, get: function () { return propagate_err_js_1.propagateErr; } });
@@ -0,0 +1,28 @@
1
+ import type { Result } from 'neverthrow';
2
+ /**
3
+ * Propagates an error Result to a different success type context.
4
+ *
5
+ * This is safe because error Results never contain the success value - only the error.
6
+ * TypeScript's structural typing prevents direct assignment of Result<T, E> to Result<U, E>
7
+ * even though the error type is identical and we're in the error branch.
8
+ *
9
+ * Common use case: Early return from a function that creates multiple items. If creating
10
+ * item 2 fails with Result<Item, DatabaseError>, we need to return Result<Item[], DatabaseError>.
11
+ *
12
+ * @example
13
+ * const result = await createUser(db, data) // Result<User, DatabaseError>
14
+ * if (result.isErr()) {
15
+ * // Need to return Result<Profile, DatabaseError> but have Result<User, DatabaseError>
16
+ * return propagateErr(result)
17
+ * }
18
+ *
19
+ * @example
20
+ * // In bulk creation, propagate single-item error to array context
21
+ * const itemResult = await createItem(data) // Result<Item, Error>
22
+ * if (itemResult.isErr()) {
23
+ * return propagateErr<Item[], Error>(itemResult) // Result<Item[], Error>
24
+ * }
25
+ */
26
+ declare const propagateErr: <TNew, E>(errorResult: Result<unknown, E>) => Result<TNew, E>;
27
+ export { propagateErr };
28
+ //# sourceMappingURL=propagate_err.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"propagate_err.d.ts","sourceRoot":"","sources":["../../src/propagate_err/propagate_err.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,QAAA,MAAM,YAAY,GAAI,IAAI,EAAE,CAAC,EAAE,aAAa,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,KAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAI9E,CAAA;AAED,OAAO,EAAE,YAAY,EAAE,CAAA"}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.propagateErr = void 0;
4
+ /**
5
+ * Propagates an error Result to a different success type context.
6
+ *
7
+ * This is safe because error Results never contain the success value - only the error.
8
+ * TypeScript's structural typing prevents direct assignment of Result<T, E> to Result<U, E>
9
+ * even though the error type is identical and we're in the error branch.
10
+ *
11
+ * Common use case: Early return from a function that creates multiple items. If creating
12
+ * item 2 fails with Result<Item, DatabaseError>, we need to return Result<Item[], DatabaseError>.
13
+ *
14
+ * @example
15
+ * const result = await createUser(db, data) // Result<User, DatabaseError>
16
+ * if (result.isErr()) {
17
+ * // Need to return Result<Profile, DatabaseError> but have Result<User, DatabaseError>
18
+ * return propagateErr(result)
19
+ * }
20
+ *
21
+ * @example
22
+ * // In bulk creation, propagate single-item error to array context
23
+ * const itemResult = await createItem(data) // Result<Item, Error>
24
+ * if (itemResult.isErr()) {
25
+ * return propagateErr<Item[], Error>(itemResult) // Result<Item[], Error>
26
+ * }
27
+ */
28
+ const propagateErr = (errorResult) => {
29
+ // Type assertion is safe: we're only propagating errors, and error Results
30
+ // don't contain the success value. The error type E is preserved exactly.
31
+ return errorResult;
32
+ };
33
+ exports.propagateErr = propagateErr;