summaryrefslogtreecommitdiff
path: root/node_modules/@jet-app/app-store/tmp/src/foundation/util/promise-util.js
blob: d661559f8dde20d87c6d4691a1d81cbcda8fcf88 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/**
 * This module provides enhanced promise handling capabilities beyond native JavaScript Promises.
 * It focuses on distinguishing between required and optional promises, standardizing results,
 * and simplifying error handling for complex async operations.
 */
/**
 * Symbol used to uniquely identify PromiseResult objects.
 * This allows for reliable type checking.
 */
export const PROMISE_RESULT_SYMBOL = Symbol("PromiseResult");
/**
 * Type guard to check if a value is a PromiseResult.
 *
 * @param value - The value to check
 * @returns True if the value is a PromiseResult, false otherwise
 */
function isPromiseResult(value) {
    return value !== null && typeof value === "object" && PROMISE_RESULT_SYMBOL in value;
}
/**
 * Custom error class that aggregates multiple promise failures.
 * Provides access to all underlying errors while presenting a combined error message.
 */
export class MultiPromiseError extends Error {
    constructor(reasons) {
        super(errorMessageForReasons(reasons));
        this.reasons = reasons;
        this.reasons = reasons;
    }
}
/**
 * Helper function to create a standardized fulfilled result object.
 * Ensures the result has the PROMISE_RESULT_SYMBOL for type checking.
 *
 * @param value - The value to wrap in a fulfilled result
 * @returns A standardized fulfilled result object
 */
export function makeFulfilledResult(value) {
    return {
        success: true,
        value,
        error: null,
        [PROMISE_RESULT_SYMBOL]: true,
    };
}
/**
 * Helper function to create a standardized rejected result object.
 * Ensures the result has the PROMISE_RESULT_SYMBOL for type checking.
 *
 * @param error - The error to wrap in a rejected result
 * @returns A standardized rejected result object
 */
export function makeRejectedResult(error) {
    const normalizedError = error instanceof Error ? error : new Error(String(error));
    return {
        success: false,
        value: null,
        error: normalizedError,
        [PROMISE_RESULT_SYMBOL]: true,
    };
}
/**
 * Custom error class that indicates that a required promise failed.
 */
export class RequiredPromiseError extends Error {
    constructor(reason) {
        super(reason.message);
        this.reason = reason;
        this.reason = reason;
    }
}
/**
 * Transforms a promise into one that never throws, instead returning a standardized result.
 * Use this for optional operations that shouldn't cause the overall process to fail.
 * This is a convenience alias for tryAwait with a more semantic name.
 *
 * @param promise - The promise to make optional
 * @returns A promise that resolves to a PromiseResult instead of throwing
 */
export async function optional(promise) {
    return await tryAwait(promise);
}
/**
 * Marks a promise as required (will throw on rejection).
 * This is mainly for code clarity as regular promises are already required by default.
 *
 * @param promise - The promise to mark as required
 * @returns The original promise (identity function)
 */
export async function required(promise) {
    return await promise;
}
/**
 * Executes a mix of required and optional promises, returning standardized results.
 * Regular promises are treated as required and will cause this function to throw if they fail.
 * Promises wrapped with optional() will never cause this function to throw.
 *
 * This implementation handles both regular promises and promises that resolve to PromiseResult.
 *
 * @param promises - Array of promises (both required and optional)
 * @returns Promise resolving to an array of standardized results
 * @throws Original error if a single required promise fails
 * @throws MultiPromiseError if multiple required promises fail
 * @note For homogeneous promise arrays, prefer using more specific functions:
 * - Use allRequired() when all promises should be treated as required
 * - Use allOptional() when all promises should be treated as optional
 * - Only use allMixed() when you need to combine both required and optional promises
 */
export async function allMixed(promises) {
    // Process each promise
    const results = await Promise.all(promises.map(async (promise) => {
        try {
            const value = await promise;
            // If it's a PromiseResult (from optional()/tryAwait), use it directly
            if (isPromiseResult(value)) {
                // Handle the case where T is already a PromiseResult
                // This fixes the double-wrapping issue when all promises are optional
                return value;
            }
            else {
                // It's a regular promise that succeeded
                return makeFulfilledResult(value);
            }
        }
        catch (error) {
            // This was a required promise that failed
            return makeRejectedResult(error instanceof Error ? error : new Error(String(error)));
        }
    }));
    const requiredFailures = [];
    results.forEach((result) => {
        if (!result.success) {
            requiredFailures.push(result.error);
        }
    });
    // If any required promises failed, throw an error
    if (requiredFailures.length > 0) {
        if (requiredFailures.length === 1) {
            throw requiredFailures[0];
        }
        else {
            throw new MultiPromiseError(requiredFailures);
        }
    }
    return results;
}
/**
 * Executes all promises and returns their values.
 * All promises are treated as required and will cause this function to throw if any fail.
 *
 * @param promises - Array of promises
 * @returns Promise resolving to an array of values
 * @throws Original error if a single promise fails
 * @throws MultiPromiseError if multiple promises fail
 */
export async function allRequired(promises) {
    return await Promise.all(promises);
}
/**
 * Makes all promises optional and then executes them, returning standardized results.
 * This function is specifically designed for cases where you want all promises to be treated as optional.
 * It avoids the double-wrapping issue that can occur when using allMixed with arrays of optional promises.
 *
 * @param promises - Array of promises to make optional
 * @returns Promise resolving to an array of standardized results
 * @example
 * ```
 * const promises = urls.map(fetchData);
 * const results = await allOptional(promises);
 * // Each result is a PromiseResult<T> that won't cause the overall operation to fail
 * ```
 */
export async function allOptional(promises) {
    // Use Promise.all with optional() for each promise
    return await Promise.all(promises.map(optional));
}
/**
 * Creates an error message from multiple rejection reasons.
 * Formats multiple error reasons into a single error message string,
 * handling both Error objects and other rejection values.
 *
 * @param reasons - Array of error reasons that caused promise rejections
 * @returns Concatenated error message string
 */
function errorMessageForReasons(reasons) {
    return reasons
        .map((reason) => {
        if (reason instanceof Error) {
            return reason.message;
        }
        else {
            return JSON.stringify(reason);
        }
    })
        .join("");
}
/**
 * Safely awaits a promise and returns a standardized result object.
 * Eliminates the need for repetitive try/catch blocks throughout the codebase.
 *
 * @param promiseOrFn - Either a promise or a function that returns a promise
 * @returns A standardized PromiseResult object indicating success or failure
 */
export async function tryAwait(promiseOrFn) {
    try {
        // Handle both promise and function that returns a promise
        const promise = typeof promiseOrFn === "function" ? promiseOrFn() : promiseOrFn;
        const value = await promise;
        return makeFulfilledResult(value);
    }
    catch (error) {
        return makeRejectedResult(error);
    }
}
//# sourceMappingURL=promise-util.js.map