safe-await-lib 0.1.2

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/README.md ADDED
@@ -0,0 +1,184 @@
1
+ # SAFE-AWAIT
2
+
3
+ [![Build Status](https://github.com/chelohubinc/safe-await/actions/workflows/ci.yml/badge.svg)](https://github.com/chelohubinc/safe-await/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/safe-await.svg)](https://www.npmjs.com/package/safe-await)
5
+ [![License](https://img.shields.io/npm/l/safe-await.svg)](https://github.com/chelohubinc/safe-await/blob/main/LICENSE)
6
+
7
+ Safe async/await utility for handling promises without try/catch.
8
+ Designed for **Node.js**, **TypeScript**, **React**, **React Native**, and **Expo**.
9
+
10
+ ---
11
+
12
+ ## ๐Ÿ“Œ Why SAFE-AWAIT?
13
+
14
+ Traditional async/await patterns require `try/catch` blocks, which can clutter code and make error handling inconsistent.
15
+
16
+ **SAFE-AWAIT solves this problem by:**
17
+
18
+ - Returning a consistent `[SafeError | null, T | null]` tuple for every async operation
19
+ - Normalizing errors into a predictable format
20
+ - Eliminating boilerplate `try/catch` blocks
21
+ - Making code cleaner, safer, and easier to maintain
22
+
23
+ ---
24
+
25
+ ## ๐Ÿš€ Features
26
+
27
+ - Safe execution of async functions and promises
28
+ - Standardized error handling with `SafeError` objects
29
+ - Fully TypeScript-typed for modern development
30
+ - Compatible with Node.js, React, React Native, and Expo
31
+ - Supports dual module output (ESM + CJS)
32
+ - Tree-shakable for modern bundlers
33
+ - Future-ready with planned modules: `withTimeout`, `retry`, `all`, `allSettled`, `once`, `strict`, `map`, `unwrap`, `mockSuccess`, `mockError`, `debug`
34
+
35
+ ---
36
+
37
+ ## ๐Ÿ“ฆ Installation
38
+
39
+ ```bash
40
+ # npm
41
+ npm install safe-await
42
+
43
+ # yarn
44
+ yarn add safe-await
45
+
46
+ # pnpm
47
+ pnpm add safe-await
48
+ ````
49
+
50
+ ---
51
+
52
+ ## โšก Basic Usage
53
+
54
+ ```ts
55
+ import safe from 'safe-await';
56
+
57
+ // Async function
58
+ async function fetchData() {
59
+ return Promise.resolve('Hello World!');
60
+ }
61
+
62
+ // Using safe
63
+ const [err, data] = await safe(fetchData);
64
+
65
+ if (err) {
66
+ console.error(err.message);
67
+ } else {
68
+ console.log(data); // 'Hello World!'
69
+ }
70
+
71
+ // Direct promise usage
72
+ const [err2, result] = await safe(Promise.resolve(42));
73
+ ```
74
+
75
+ ---
76
+
77
+ ## ๐Ÿ› ๏ธ API Overview
78
+
79
+ ### `safe(input: SafeInput<T>): SafeResult<T>`
80
+
81
+ - **input**: `Promise<T>` or `() => T | Promise<T>`
82
+ - **returns**: `[SafeError | null, T | null]`
83
+
84
+ ### `SafeError` Structure
85
+
86
+ ```ts
87
+ interface SafeError {
88
+ message: string; // Human-readable message
89
+ code: string; // Standardized error code
90
+ cause?: unknown; // Original error or additional context
91
+ }
92
+ ```
93
+
94
+ ---
95
+
96
+ ## ๐ŸŒฑ Advanced Usage Examples
97
+
98
+ ### Handling multiple async operations
99
+
100
+ ```ts
101
+ // Future module: safe.all
102
+ const [err, results] = await safe.all([fetchData(), Promise.resolve(10)]);
103
+ ```
104
+
105
+ ### Using retry (planned in v0.2.0)
106
+
107
+ ```ts
108
+ const [err, data] = await safe.retry(() => fetchData(), { attempts: 3, delay: 500 });
109
+ ```
110
+
111
+ ---
112
+
113
+ ## ๐Ÿ“Š Roadmap
114
+
115
+ | Version | Features Planned |
116
+ | ------- | ---------------------- |
117
+ | v0.2.0 | withTimeout, retry |
118
+ | v0.3.0 | all, allSettled |
119
+ | v0.4.0 | withContext |
120
+ | v0.5.0 | once |
121
+ | v0.6.0 | strict |
122
+ | v0.7.0 | map, unwrap |
123
+ | v0.8.0 | mockSuccess, mockError |
124
+ | v0.9.0 | debug |
125
+
126
+ ---
127
+
128
+ ## ๐Ÿงช Development
129
+
130
+ ```bash
131
+ # Install dev dependencies
132
+ npm install
133
+
134
+ # Run development build with watch
135
+ npm run dev
136
+
137
+ # Type check
138
+ npm run typecheck
139
+
140
+ # Run tests
141
+ npm test
142
+
143
+ # Build for distribution
144
+ npm run build
145
+ ```
146
+
147
+ ---
148
+
149
+ ## ๐Ÿ“ Contributing
150
+
151
+ SAFE-AWAIT welcomes contributions!
152
+
153
+ 1. Fork the repository
154
+ 2. Create a feature branch (`git checkout -b feature/your-feature`)
155
+ 3. Run tests locally (`npm test`)
156
+ 4. Submit a pull request
157
+
158
+ Please adhere to the existing **TypeScript typings** and **code style**.
159
+
160
+ ---
161
+
162
+ ## โ“ FAQ / Tips
163
+
164
+ - **Why use `[SafeError | null, T | null]` instead of try/catch?**
165
+ It ensures consistent error handling and makes async code more readable.
166
+
167
+ - **Can I use this in React Native / Expo?**
168
+ Yes. SAFE-AWAIT is fully compatible.
169
+
170
+ - **How do I handle retries or timeouts?**
171
+ Future modules like `retry` and `withTimeout` will handle these cases cleanly.
172
+
173
+ ---
174
+
175
+ ## ๐Ÿ“– License
176
+
177
+ ISC License ยฉ Chelohub Inc.
178
+
179
+ ---
180
+
181
+ ## ๐ŸŒ Links
182
+
183
+ - **GitHub:** [https://github.com/chelohubinc/safe-await](https://github.com/chelohubinc/safe-await)
184
+ - **NPM:** [https://www.npmjs.com/package/safe-await](https://www.npmjs.com/package/safe-await)
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Standardized error object used throughout the SAFE-AWAIT package.
3
+ *
4
+ * Every error returned by `safe()` or its extensions follows this shape,
5
+ * ensuring consistent and predictable error handling.
6
+ */
7
+ interface SafeError {
8
+ /** Human-readable error message */
9
+ message: string;
10
+ /** Machine-readable error code */
11
+ code: string;
12
+ /** Original error or additional context, if available */
13
+ cause?: unknown;
14
+ }
15
+ /**
16
+ * Standard return type for all SAFE-AWAIT operations.
17
+ *
18
+ * The result is always a tuple:
19
+ * - `[null, T]` when the operation succeeds
20
+ * - `[SafeError, null]` when the operation fails
21
+ *
22
+ * This pattern eliminates the need for try/catch blocks.
23
+ */
24
+ type SafeResult<T> = Promise<[SafeError | null, T | null]>;
25
+ /**
26
+ * Accepted input type for the `safe()` function.
27
+ *
28
+ * Allows passing either:
29
+ * - a Promise
30
+ * - a function returning a value or a Promise
31
+ *
32
+ * This enables lazy execution and consistent error handling.
33
+ */
34
+ type SafeInput<T> = Promise<T> | (() => T | Promise<T>);
35
+
36
+ /**
37
+ * Internal execution engine for SAFE-AWAIT.
38
+ *
39
+ * This function executes a promise or a function safely and converts
40
+ * any thrown or rejected value into a standardized `SafeResult` tuple.
41
+ *
42
+ * It is intentionally minimal and side-effect free, serving as the
43
+ * foundation for all higher-level modules (retry, timeout, etc.).
44
+ *
45
+ * @param input - A promise or a function returning a value or a promise
46
+ *
47
+ * @returns A Promise resolving to a `[SafeError | null, T | null]` tuple
48
+ */
49
+ declare function coreSafe<T>(input: SafeInput<T>): SafeResult<T>;
50
+
51
+ /**
52
+ * `safe` is the core function of the SAFE-AWAIT package.
53
+ *
54
+ * It safely executes any synchronous or asynchronous operation and
55
+ * always returns a predictable tuple instead of throwing errors.
56
+ *
57
+ * ## Basic usage
58
+ * ```ts
59
+ * import safe from "safe-await";
60
+ *
61
+ * const [err, data] = await safe(async () => fetchData());
62
+ *
63
+ * if (err) {
64
+ * console.error(err.message, err.code);
65
+ * } else {
66
+ * console.log(data);
67
+ * }
68
+ * ```
69
+ *
70
+ * ## Philosophy
71
+ * - No try/catch pollution
72
+ * - No unhandled promise rejections
73
+ * - Explicit error handling
74
+ *
75
+ * ## Planned extensions
76
+ * - v0.2.0: withTimeout, retry
77
+ * - v0.3.0: all, allSettled
78
+ * - v0.4.0: withContext
79
+ * - v0.5.0: once
80
+ * - v0.6.0: strict
81
+ * - v0.7.0: map, unwrap
82
+ * - v0.8.0: mockSuccess, mockError
83
+ * - v0.9.0: debug
84
+ *
85
+ * ## Return value
86
+ * Always returns a tuple:
87
+ * - `[null, result]` on success
88
+ * - `[SafeError, null]` on failure
89
+ */
90
+ declare const safe: typeof coreSafe;
91
+
92
+ export { safe as default, safe };
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Standardized error object used throughout the SAFE-AWAIT package.
3
+ *
4
+ * Every error returned by `safe()` or its extensions follows this shape,
5
+ * ensuring consistent and predictable error handling.
6
+ */
7
+ interface SafeError {
8
+ /** Human-readable error message */
9
+ message: string;
10
+ /** Machine-readable error code */
11
+ code: string;
12
+ /** Original error or additional context, if available */
13
+ cause?: unknown;
14
+ }
15
+ /**
16
+ * Standard return type for all SAFE-AWAIT operations.
17
+ *
18
+ * The result is always a tuple:
19
+ * - `[null, T]` when the operation succeeds
20
+ * - `[SafeError, null]` when the operation fails
21
+ *
22
+ * This pattern eliminates the need for try/catch blocks.
23
+ */
24
+ type SafeResult<T> = Promise<[SafeError | null, T | null]>;
25
+ /**
26
+ * Accepted input type for the `safe()` function.
27
+ *
28
+ * Allows passing either:
29
+ * - a Promise
30
+ * - a function returning a value or a Promise
31
+ *
32
+ * This enables lazy execution and consistent error handling.
33
+ */
34
+ type SafeInput<T> = Promise<T> | (() => T | Promise<T>);
35
+
36
+ /**
37
+ * Internal execution engine for SAFE-AWAIT.
38
+ *
39
+ * This function executes a promise or a function safely and converts
40
+ * any thrown or rejected value into a standardized `SafeResult` tuple.
41
+ *
42
+ * It is intentionally minimal and side-effect free, serving as the
43
+ * foundation for all higher-level modules (retry, timeout, etc.).
44
+ *
45
+ * @param input - A promise or a function returning a value or a promise
46
+ *
47
+ * @returns A Promise resolving to a `[SafeError | null, T | null]` tuple
48
+ */
49
+ declare function coreSafe<T>(input: SafeInput<T>): SafeResult<T>;
50
+
51
+ /**
52
+ * `safe` is the core function of the SAFE-AWAIT package.
53
+ *
54
+ * It safely executes any synchronous or asynchronous operation and
55
+ * always returns a predictable tuple instead of throwing errors.
56
+ *
57
+ * ## Basic usage
58
+ * ```ts
59
+ * import safe from "safe-await";
60
+ *
61
+ * const [err, data] = await safe(async () => fetchData());
62
+ *
63
+ * if (err) {
64
+ * console.error(err.message, err.code);
65
+ * } else {
66
+ * console.log(data);
67
+ * }
68
+ * ```
69
+ *
70
+ * ## Philosophy
71
+ * - No try/catch pollution
72
+ * - No unhandled promise rejections
73
+ * - Explicit error handling
74
+ *
75
+ * ## Planned extensions
76
+ * - v0.2.0: withTimeout, retry
77
+ * - v0.3.0: all, allSettled
78
+ * - v0.4.0: withContext
79
+ * - v0.5.0: once
80
+ * - v0.6.0: strict
81
+ * - v0.7.0: map, unwrap
82
+ * - v0.8.0: mockSuccess, mockError
83
+ * - v0.9.0: debug
84
+ *
85
+ * ## Return value
86
+ * Always returns a tuple:
87
+ * - `[null, result]` on success
88
+ * - `[SafeError, null]` on failure
89
+ */
90
+ declare const safe: typeof coreSafe;
91
+
92
+ export { safe as default, safe };
package/dist/index.js ADDED
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ default: () => index_default,
24
+ safe: () => safe
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/errors/codes.ts
29
+ var ERROR_CODES = {
30
+ /** Fallback error for unknown or unhandled failures */
31
+ UNKNOWN: "UNKNOWN_ERROR",
32
+ /** Thrown when an operation exceeds a configured timeout */
33
+ TIMEOUT: "TIMEOUT_ERROR",
34
+ /** Used when all retry attempts have failed */
35
+ RETRY_FAILED: "RETRY_FAILED",
36
+ /** Used when an operation is explicitly aborted or cancelled */
37
+ ABORTED: "ABORT_ERROR",
38
+ /** Used when input validation fails */
39
+ VALIDATION: "VALIDATION_ERROR",
40
+ /** Used when a function guarded by `once()` is called more than once */
41
+ EXECUTION_ONCE: "ALREADY_EXECUTED"
42
+ };
43
+
44
+ // src/errors/formatter.ts
45
+ function formatError(err, defaultCode = ERROR_CODES.UNKNOWN) {
46
+ var _a;
47
+ if (err instanceof Error) {
48
+ const errorWithCause = err;
49
+ return {
50
+ message: err.message,
51
+ code: err.code || defaultCode,
52
+ cause: (_a = errorWithCause.cause) != null ? _a : err
53
+ };
54
+ }
55
+ if (typeof err === "string") {
56
+ return {
57
+ message: err,
58
+ code: defaultCode
59
+ };
60
+ }
61
+ return {
62
+ message: "An unexpected error occurred",
63
+ code: defaultCode,
64
+ cause: err
65
+ };
66
+ }
67
+
68
+ // src/core/safe.ts
69
+ async function coreSafe(input) {
70
+ try {
71
+ const promise = typeof input === "function" ? input() : input;
72
+ const data = await promise;
73
+ return [null, data];
74
+ } catch (error) {
75
+ return [formatError(error), null];
76
+ }
77
+ }
78
+
79
+ // src/index.ts
80
+ var safe = Object.assign(coreSafe, {
81
+ // v0.2.0
82
+ // withTimeout,
83
+ // retry,
84
+ // v0.3.0
85
+ // all,
86
+ // allSettled,
87
+ // v0.4.0
88
+ // withContext,
89
+ // v0.5.0
90
+ // once,
91
+ // v0.6.0
92
+ // strict,
93
+ // v0.7.0
94
+ // map,
95
+ // unwrap,
96
+ // v0.8.0
97
+ // mockSuccess,
98
+ // mockError,
99
+ // v0.9.0
100
+ // debug,
101
+ });
102
+ var index_default = safe;
103
+ // Annotate the CommonJS export names for ESM import in node:
104
+ 0 && (module.exports = {
105
+ safe
106
+ });
107
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/errors/codes.ts","../src/errors/formatter.ts","../src/core/safe.ts"],"sourcesContent":["import { coreSafe } from \"./core/safe\";\n\n/**\n * `safe` is the core function of the SAFE-AWAIT package.\n *\n * It safely executes any synchronous or asynchronous operation and\n * always returns a predictable tuple instead of throwing errors.\n *\n * ## Basic usage\n * ```ts\n * import safe from \"safe-await\";\n *\n * const [err, data] = await safe(async () => fetchData());\n *\n * if (err) {\n * console.error(err.message, err.code);\n * } else {\n * console.log(data);\n * }\n * ```\n *\n * ## Philosophy\n * - No try/catch pollution\n * - No unhandled promise rejections\n * - Explicit error handling\n *\n * ## Planned extensions\n * - v0.2.0: withTimeout, retry\n * - v0.3.0: all, allSettled\n * - v0.4.0: withContext\n * - v0.5.0: once\n * - v0.6.0: strict\n * - v0.7.0: map, unwrap\n * - v0.8.0: mockSuccess, mockError\n * - v0.9.0: debug\n *\n * ## Return value\n * Always returns a tuple:\n * - `[null, result]` on success\n * - `[SafeError, null]` on failure\n */\nexport const safe = Object.assign(coreSafe, {\n // v0.2.0\n // withTimeout,\n // retry,\n\n // v0.3.0\n // all,\n // allSettled,\n\n // v0.4.0\n // withContext,\n\n // v0.5.0\n // once,\n\n // v0.6.0\n // strict,\n\n // v0.7.0\n // map,\n // unwrap,\n\n // v0.8.0\n // mockSuccess,\n // mockError,\n\n // v0.9.0\n // debug,\n});\n\nexport default safe;","/**\n * Standardized error codes used across the SAFE-AWAIT package.\n *\n * These codes allow consumers to reliably identify the nature\n * of an error without relying on string comparison of messages.\n *\n * Each module of the package should use one of these codes\n * when returning or normalizing an error.\n */\nexport const ERROR_CODES = {\n /** Fallback error for unknown or unhandled failures */\n UNKNOWN: 'UNKNOWN_ERROR',\n\n /** Thrown when an operation exceeds a configured timeout */\n TIMEOUT: 'TIMEOUT_ERROR',\n\n /** Used when all retry attempts have failed */\n RETRY_FAILED: 'RETRY_FAILED',\n\n /** Used when an operation is explicitly aborted or cancelled */\n ABORTED: 'ABORT_ERROR',\n\n /** Used when input validation fails */\n VALIDATION: 'VALIDATION_ERROR',\n\n /** Used when a function guarded by `once()` is called more than once */\n EXECUTION_ONCE: 'ALREADY_EXECUTED'\n} as const;\n\n/**\n * Union type of all supported error codes.\n *\n * This type ensures strong typing and prevents the use\n * of unsupported or custom error codes across the package.\n */\nexport type ErrorCode = typeof ERROR_CODES[keyof typeof ERROR_CODES];\n\n/**\n * Internal helper interface to support the `cause` property\n * on Error objects in environments where it is not\n * yet fully supported or typed.\n *\n * This allows SAFE-AWAIT to preserve the original error\n * while still returning a normalized SafeError object.\n */\nexport interface ErrorWithCause extends Error {\n cause?: unknown;\n}\n","import { SafeError } from '../core/type';\nimport { ERROR_CODES, ErrorCode, ErrorWithCause } from './codes';\n\n/**\n * Normalizes any thrown value into a `SafeError`.\n *\n * This function is the foundation of SAFE-AWAIT's error-handling strategy.\n * It guarantees that all errors returned by the library follow the same\n * predictable structure, regardless of what was originally thrown.\n *\n * Supported inputs:\n * - `Error` instances (native or custom)\n * - string errors\n * - unknown or non-error values\n *\n * ## Normalization rules\n * - Preserves the original error message when possible\n * - Uses a standardized error code\n * - Keeps the original error in the `cause` field when available\n *\n * @param err - Any value thrown or rejected by an operation\n * @param defaultCode - Fallback error code when none is provided\n *\n * @returns A normalized `SafeError` object\n */\nexport function formatError(\n err: unknown,\n defaultCode: ErrorCode = ERROR_CODES.UNKNOWN\n): SafeError {\n if (err instanceof Error) {\n const errorWithCause = err as ErrorWithCause;\n\n return {\n message: err.message,\n code: (err as any).code || defaultCode,\n cause: errorWithCause.cause ?? err\n };\n }\n\n if (typeof err === 'string') {\n return {\n message: err,\n code: defaultCode,\n };\n }\n\n return {\n message: 'An unexpected error occurred',\n code: defaultCode,\n cause: err\n };\n}\n","import { formatError } from \"../errors/formatter\";\nimport { SafeInput, SafeResult } from \"./type\";\n\n/**\n * Internal execution engine for SAFE-AWAIT.\n *\n * This function executes a promise or a function safely and converts\n * any thrown or rejected value into a standardized `SafeResult` tuple.\n *\n * It is intentionally minimal and side-effect free, serving as the\n * foundation for all higher-level modules (retry, timeout, etc.).\n *\n * @param input - A promise or a function returning a value or a promise\n *\n * @returns A Promise resolving to a `[SafeError | null, T | null]` tuple\n */\nexport async function coreSafe<T>(input: SafeInput<T>): SafeResult<T> {\n try {\n const promise = typeof input === 'function' ? input() : input;\n const data = await promise;\n\n return [null, data];\n } catch (error) {\n return [formatError(error), null];\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACSO,IAAM,cAAc;AAAA;AAAA,EAEvB,SAAS;AAAA;AAAA,EAGT,SAAS;AAAA;AAAA,EAGT,cAAc;AAAA;AAAA,EAGd,SAAS;AAAA;AAAA,EAGT,YAAY;AAAA;AAAA,EAGZ,gBAAgB;AACpB;;;ACFO,SAAS,YACZ,KACA,cAAyB,YAAY,SAC5B;AA5Bb;AA6BI,MAAI,eAAe,OAAO;AACtB,UAAM,iBAAiB;AAEvB,WAAO;AAAA,MACH,SAAS,IAAI;AAAA,MACb,MAAO,IAAY,QAAQ;AAAA,MAC3B,QAAO,oBAAe,UAAf,YAAwB;AAAA,IACnC;AAAA,EACJ;AAEA,MAAI,OAAO,QAAQ,UAAU;AACzB,WAAO;AAAA,MACH,SAAS;AAAA,MACT,MAAM;AAAA,IACV;AAAA,EACJ;AAEA,SAAO;AAAA,IACH,SAAS;AAAA,IACT,MAAM;AAAA,IACN,OAAO;AAAA,EACX;AACJ;;;ACnCA,eAAsB,SAAY,OAAoC;AAClE,MAAI;AACA,UAAM,UAAU,OAAO,UAAU,aAAa,MAAM,IAAI;AACxD,UAAM,OAAO,MAAM;AAEnB,WAAO,CAAC,MAAM,IAAI;AAAA,EACtB,SAAS,OAAO;AACZ,WAAO,CAAC,YAAY,KAAK,GAAG,IAAI;AAAA,EACpC;AACJ;;;AHgBO,IAAM,OAAO,OAAO,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4B5C,CAAC;AAED,IAAO,gBAAQ;","names":[]}
package/dist/index.mjs ADDED
@@ -0,0 +1,80 @@
1
+ // src/errors/codes.ts
2
+ var ERROR_CODES = {
3
+ /** Fallback error for unknown or unhandled failures */
4
+ UNKNOWN: "UNKNOWN_ERROR",
5
+ /** Thrown when an operation exceeds a configured timeout */
6
+ TIMEOUT: "TIMEOUT_ERROR",
7
+ /** Used when all retry attempts have failed */
8
+ RETRY_FAILED: "RETRY_FAILED",
9
+ /** Used when an operation is explicitly aborted or cancelled */
10
+ ABORTED: "ABORT_ERROR",
11
+ /** Used when input validation fails */
12
+ VALIDATION: "VALIDATION_ERROR",
13
+ /** Used when a function guarded by `once()` is called more than once */
14
+ EXECUTION_ONCE: "ALREADY_EXECUTED"
15
+ };
16
+
17
+ // src/errors/formatter.ts
18
+ function formatError(err, defaultCode = ERROR_CODES.UNKNOWN) {
19
+ var _a;
20
+ if (err instanceof Error) {
21
+ const errorWithCause = err;
22
+ return {
23
+ message: err.message,
24
+ code: err.code || defaultCode,
25
+ cause: (_a = errorWithCause.cause) != null ? _a : err
26
+ };
27
+ }
28
+ if (typeof err === "string") {
29
+ return {
30
+ message: err,
31
+ code: defaultCode
32
+ };
33
+ }
34
+ return {
35
+ message: "An unexpected error occurred",
36
+ code: defaultCode,
37
+ cause: err
38
+ };
39
+ }
40
+
41
+ // src/core/safe.ts
42
+ async function coreSafe(input) {
43
+ try {
44
+ const promise = typeof input === "function" ? input() : input;
45
+ const data = await promise;
46
+ return [null, data];
47
+ } catch (error) {
48
+ return [formatError(error), null];
49
+ }
50
+ }
51
+
52
+ // src/index.ts
53
+ var safe = Object.assign(coreSafe, {
54
+ // v0.2.0
55
+ // withTimeout,
56
+ // retry,
57
+ // v0.3.0
58
+ // all,
59
+ // allSettled,
60
+ // v0.4.0
61
+ // withContext,
62
+ // v0.5.0
63
+ // once,
64
+ // v0.6.0
65
+ // strict,
66
+ // v0.7.0
67
+ // map,
68
+ // unwrap,
69
+ // v0.8.0
70
+ // mockSuccess,
71
+ // mockError,
72
+ // v0.9.0
73
+ // debug,
74
+ });
75
+ var index_default = safe;
76
+ export {
77
+ index_default as default,
78
+ safe
79
+ };
80
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors/codes.ts","../src/errors/formatter.ts","../src/core/safe.ts","../src/index.ts"],"sourcesContent":["/**\n * Standardized error codes used across the SAFE-AWAIT package.\n *\n * These codes allow consumers to reliably identify the nature\n * of an error without relying on string comparison of messages.\n *\n * Each module of the package should use one of these codes\n * when returning or normalizing an error.\n */\nexport const ERROR_CODES = {\n /** Fallback error for unknown or unhandled failures */\n UNKNOWN: 'UNKNOWN_ERROR',\n\n /** Thrown when an operation exceeds a configured timeout */\n TIMEOUT: 'TIMEOUT_ERROR',\n\n /** Used when all retry attempts have failed */\n RETRY_FAILED: 'RETRY_FAILED',\n\n /** Used when an operation is explicitly aborted or cancelled */\n ABORTED: 'ABORT_ERROR',\n\n /** Used when input validation fails */\n VALIDATION: 'VALIDATION_ERROR',\n\n /** Used when a function guarded by `once()` is called more than once */\n EXECUTION_ONCE: 'ALREADY_EXECUTED'\n} as const;\n\n/**\n * Union type of all supported error codes.\n *\n * This type ensures strong typing and prevents the use\n * of unsupported or custom error codes across the package.\n */\nexport type ErrorCode = typeof ERROR_CODES[keyof typeof ERROR_CODES];\n\n/**\n * Internal helper interface to support the `cause` property\n * on Error objects in environments where it is not\n * yet fully supported or typed.\n *\n * This allows SAFE-AWAIT to preserve the original error\n * while still returning a normalized SafeError object.\n */\nexport interface ErrorWithCause extends Error {\n cause?: unknown;\n}\n","import { SafeError } from '../core/type';\nimport { ERROR_CODES, ErrorCode, ErrorWithCause } from './codes';\n\n/**\n * Normalizes any thrown value into a `SafeError`.\n *\n * This function is the foundation of SAFE-AWAIT's error-handling strategy.\n * It guarantees that all errors returned by the library follow the same\n * predictable structure, regardless of what was originally thrown.\n *\n * Supported inputs:\n * - `Error` instances (native or custom)\n * - string errors\n * - unknown or non-error values\n *\n * ## Normalization rules\n * - Preserves the original error message when possible\n * - Uses a standardized error code\n * - Keeps the original error in the `cause` field when available\n *\n * @param err - Any value thrown or rejected by an operation\n * @param defaultCode - Fallback error code when none is provided\n *\n * @returns A normalized `SafeError` object\n */\nexport function formatError(\n err: unknown,\n defaultCode: ErrorCode = ERROR_CODES.UNKNOWN\n): SafeError {\n if (err instanceof Error) {\n const errorWithCause = err as ErrorWithCause;\n\n return {\n message: err.message,\n code: (err as any).code || defaultCode,\n cause: errorWithCause.cause ?? err\n };\n }\n\n if (typeof err === 'string') {\n return {\n message: err,\n code: defaultCode,\n };\n }\n\n return {\n message: 'An unexpected error occurred',\n code: defaultCode,\n cause: err\n };\n}\n","import { formatError } from \"../errors/formatter\";\nimport { SafeInput, SafeResult } from \"./type\";\n\n/**\n * Internal execution engine for SAFE-AWAIT.\n *\n * This function executes a promise or a function safely and converts\n * any thrown or rejected value into a standardized `SafeResult` tuple.\n *\n * It is intentionally minimal and side-effect free, serving as the\n * foundation for all higher-level modules (retry, timeout, etc.).\n *\n * @param input - A promise or a function returning a value or a promise\n *\n * @returns A Promise resolving to a `[SafeError | null, T | null]` tuple\n */\nexport async function coreSafe<T>(input: SafeInput<T>): SafeResult<T> {\n try {\n const promise = typeof input === 'function' ? input() : input;\n const data = await promise;\n\n return [null, data];\n } catch (error) {\n return [formatError(error), null];\n }\n}\n","import { coreSafe } from \"./core/safe\";\n\n/**\n * `safe` is the core function of the SAFE-AWAIT package.\n *\n * It safely executes any synchronous or asynchronous operation and\n * always returns a predictable tuple instead of throwing errors.\n *\n * ## Basic usage\n * ```ts\n * import safe from \"safe-await\";\n *\n * const [err, data] = await safe(async () => fetchData());\n *\n * if (err) {\n * console.error(err.message, err.code);\n * } else {\n * console.log(data);\n * }\n * ```\n *\n * ## Philosophy\n * - No try/catch pollution\n * - No unhandled promise rejections\n * - Explicit error handling\n *\n * ## Planned extensions\n * - v0.2.0: withTimeout, retry\n * - v0.3.0: all, allSettled\n * - v0.4.0: withContext\n * - v0.5.0: once\n * - v0.6.0: strict\n * - v0.7.0: map, unwrap\n * - v0.8.0: mockSuccess, mockError\n * - v0.9.0: debug\n *\n * ## Return value\n * Always returns a tuple:\n * - `[null, result]` on success\n * - `[SafeError, null]` on failure\n */\nexport const safe = Object.assign(coreSafe, {\n // v0.2.0\n // withTimeout,\n // retry,\n\n // v0.3.0\n // all,\n // allSettled,\n\n // v0.4.0\n // withContext,\n\n // v0.5.0\n // once,\n\n // v0.6.0\n // strict,\n\n // v0.7.0\n // map,\n // unwrap,\n\n // v0.8.0\n // mockSuccess,\n // mockError,\n\n // v0.9.0\n // debug,\n});\n\nexport default safe;"],"mappings":";AASO,IAAM,cAAc;AAAA;AAAA,EAEvB,SAAS;AAAA;AAAA,EAGT,SAAS;AAAA;AAAA,EAGT,cAAc;AAAA;AAAA,EAGd,SAAS;AAAA;AAAA,EAGT,YAAY;AAAA;AAAA,EAGZ,gBAAgB;AACpB;;;ACFO,SAAS,YACZ,KACA,cAAyB,YAAY,SAC5B;AA5Bb;AA6BI,MAAI,eAAe,OAAO;AACtB,UAAM,iBAAiB;AAEvB,WAAO;AAAA,MACH,SAAS,IAAI;AAAA,MACb,MAAO,IAAY,QAAQ;AAAA,MAC3B,QAAO,oBAAe,UAAf,YAAwB;AAAA,IACnC;AAAA,EACJ;AAEA,MAAI,OAAO,QAAQ,UAAU;AACzB,WAAO;AAAA,MACH,SAAS;AAAA,MACT,MAAM;AAAA,IACV;AAAA,EACJ;AAEA,SAAO;AAAA,IACH,SAAS;AAAA,IACT,MAAM;AAAA,IACN,OAAO;AAAA,EACX;AACJ;;;ACnCA,eAAsB,SAAY,OAAoC;AAClE,MAAI;AACA,UAAM,UAAU,OAAO,UAAU,aAAa,MAAM,IAAI;AACxD,UAAM,OAAO,MAAM;AAEnB,WAAO,CAAC,MAAM,IAAI;AAAA,EACtB,SAAS,OAAO;AACZ,WAAO,CAAC,YAAY,KAAK,GAAG,IAAI;AAAA,EACpC;AACJ;;;ACgBO,IAAM,OAAO,OAAO,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4B5C,CAAC;AAED,IAAO,gBAAQ;","names":[]}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "safe-await-lib",
3
+ "version": "0.1.2",
4
+ "description": "Safe async/await utility for handling promises without try/catch.",
5
+ "author": "Chelohub Inc. <npm@borislukrece.com>",
6
+ "scripts": {
7
+ "build": "tsup",
8
+ "dev": "tsup --watch",
9
+ "typecheck": "tsc --noEmit",
10
+ "release:patch": "npm version patch && git push origin HEAD --follow-tags",
11
+ "release:minor": "npm version minor && git push origin HEAD --follow-tags",
12
+ "release:major": "npm version major && git push origin HEAD --follow-tags",
13
+ "test": "vitest"
14
+ },
15
+ "directories": {
16
+ "test": "tests"
17
+ },
18
+ "main": "./dist/index.cjs",
19
+ "module": "./dist/index.js",
20
+ "types": "./dist/index.d.ts",
21
+ "exports": {
22
+ ".": {
23
+ "import": "./dist/index.js",
24
+ "require": "./dist/index.cjs"
25
+ }
26
+ },
27
+ "devDependencies": {
28
+ "tsup": "^8.5.1",
29
+ "typescript": "^5.9.3",
30
+ "vitest": "^4.0.16"
31
+ },
32
+ "files": [
33
+ "dist"
34
+ ],
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/chelohubinc/safe-await"
38
+ },
39
+ "keywords": [
40
+ "async",
41
+ "await",
42
+ "promise",
43
+ "error-handling",
44
+ "try-catch",
45
+ "result",
46
+ "typescript",
47
+ "react-native",
48
+ "expo"
49
+ ],
50
+ "license": "ISC",
51
+ "sideEffects": false,
52
+ "engines": {
53
+ "node": ">=18"
54
+ }
55
+ }