@reasonabletech/utils 0.1.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.
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Object utility functions for handling exactOptionalPropertyTypes and clean object construction
3
+ *
4
+ * These utilities are designed to work with TypeScript's strict mode and exactOptionalPropertyTypes
5
+ * configuration, which prevents assigning undefined to optional properties. They provide clean,
6
+ * type-safe ways to construct objects with conditional properties.
7
+ *
8
+ * ## Key Use Cases
9
+ *
10
+ * 1. **exactOptionalPropertyTypes compliance** - When you cannot assign undefined to optional properties
11
+ * 2. **Clean object construction** - Building objects with conditional properties based on runtime values
12
+ * 3. **API response formatting** - Creating response objects that omit undefined fields
13
+ * 4. **Configuration objects** - Building config objects where some properties may not be defined
14
+ *
15
+ * ## Examples
16
+ *
17
+ * ### Basic Conditional Properties
18
+ * ```typescript
19
+ * // Instead of this (fails with exactOptionalPropertyTypes):
20
+ * const badObj = {
21
+ * name: "test",
22
+ * description: undefined, // ❌ Error: undefined not assignable to optional property
23
+ * };
24
+ *
25
+ * // Use this:
26
+ * const goodObj = {
27
+ * name: "test",
28
+ * ...includeIf("description", maybeDescription),
29
+ * };
30
+ * ```
31
+ *
32
+ * ### Multiple Conditional Properties
33
+ * ```typescript
34
+ * const config = {
35
+ * host: "localhost",
36
+ * port: 3000,
37
+ * ...includeIfDefined({
38
+ * ssl: enableSsl ? { cert: certPath, key: keyPath } : undefined,
39
+ * auth: authConfig, // may be undefined
40
+ * timeout: customTimeout, // may be undefined
41
+ * }),
42
+ * };
43
+ * ```
44
+ *
45
+ * ### API Response Building
46
+ * ```typescript
47
+ * function buildApiResponse(user: User) {
48
+ * return {
49
+ * id: user.id,
50
+ * name: user.name,
51
+ * ...includeIf("email", user.email), // only include if user has email
52
+ * ...includeIf("avatar", user.avatarUrl), // only include if user has avatar
53
+ * ...includeIf("lastSeen", user.lastSeenAt ? lastSeenAt.toISOString()), // convert and include if exists
54
+ * };
55
+ * }
56
+ * ```
57
+ * @module object
58
+ * @since 1.0.0
59
+ */
60
+ /**
61
+ * Conditionally includes a property in an object if the value is not undefined.
62
+ * This is useful for exactOptionalPropertyTypes compliance where you cannot assign undefined to optional properties.
63
+ * @param key - The property key to conditionally include
64
+ * @param value - The value to include, or undefined to omit the property
65
+ * @returns An empty object if value is undefined, otherwise an object with the key-value pair
66
+ * @example Basic usage
67
+ * ```typescript
68
+ * const obj = {
69
+ * required : "value",
70
+ * ...includeIf("optional", maybeUndefinedValue),
71
+ * };
72
+ * // If maybeUndefinedValue is "hello": { required: "value", optional: "hello" }
73
+ * // If maybeUndefinedValue is undefined: { required: "value" }
74
+ * ```
75
+ * @example API response building
76
+ * ```typescript
77
+ * function createUserResponse(user: User) {
78
+ * return {
79
+ * id: user.id,
80
+ * name: user.name,
81
+ * ...includeIf("email", user.email),
82
+ * ...includeIf("avatar", user.avatar ? avatar.url),
83
+ * ...includeIf("lastLogin", user.lastLoginAt?.toISOString()),
84
+ * };
85
+ * }
86
+ * ```
87
+ * @example Billing service usage (real project example)
88
+ * ```typescript
89
+ * return {
90
+ * amount : pricing.amount,
91
+ * ...includeIf("setupFee", pricing.setupFee),
92
+ * ...includeIf("savings", calculatedSavings),
93
+ * };
94
+ * ```
95
+ */
96
+ export declare function includeIf<K extends string, V>(key: K, value: V | undefined): Record<string, unknown>;
97
+ /**
98
+ * Conditionally includes multiple properties from an object, omitting any with undefined values.
99
+ * This creates a new object with only the defined properties.
100
+ * @param obj - Object containing key-value pairs where values may be undefined
101
+ * @returns New object containing only the properties where values are not undefined
102
+ * @example Basic usage
103
+ * ```typescript
104
+ * const obj = {
105
+ * required: "value",
106
+ * ...includeIfDefined({
107
+ * optional1: maybeUndefined1, // included only if not undefined
108
+ * optional2: maybeUndefined2, // included only if not undefined
109
+ * }),
110
+ * };
111
+ * ```
112
+ * @example Configuration object building
113
+ * ```typescript
114
+ * const config = {
115
+ * host: "localhost",
116
+ * port: 3000,
117
+ * ...includeIfDefined({
118
+ * ssl: sslEnabled ? sslEnabled.sslConfig : undefined,
119
+ * auth: authConfig, // may be undefined
120
+ * timeout: userTimeout, // may be undefined
121
+ * retries: retryCount, // may be undefined
122
+ * }),
123
+ * };
124
+ * ```
125
+ * @example Form data processing
126
+ * ```typescript
127
+ * const formData = {
128
+ * name: data.name,
129
+ * email: data.email,
130
+ * ...includeIfDefined({
131
+ * phone: data.phone ? phone.trim() || undefined,
132
+ * company : data.company?.trim() || undefined,
133
+ * website: data.website ? website.startsWith('http') ? data.website : undefined,
134
+ * }),
135
+ * };
136
+ * ```
137
+ */
138
+ export declare function includeIfDefined<T extends Record<string, unknown>>(obj: T): Record<string, unknown>;
139
+ /**
140
+ * Omits properties with undefined values from an object.
141
+ * This is useful for cleaning up objects before assignment when using exactOptionalPropertyTypes.
142
+ * Note: This only removes undefined values, not other falsy values like null, 0, "", or false.
143
+ * @param obj - The object to clean of undefined properties
144
+ * @returns New object with undefined properties removed
145
+ * @example Basic cleanup
146
+ * ```typescript
147
+ * const cleanObj = omitUndefined({
148
+ * a: "defined",
149
+ * b: undefined, // ❌ removed
150
+ * c: null, // ✅ preserved (null ≠ undefined)
151
+ * d: 0, // ✅ preserved (falsy but defined)
152
+ * e: "", // ✅ preserved (falsy but defined)
153
+ * f: false, // ✅ preserved (falsy but defined)
154
+ * });
155
+ * // Result: { a: "defined", c: null, d: 0, e: "", f: false }
156
+ * ```
157
+ * @example API data cleaning
158
+ * ```typescript
159
+ * function sanitizeApiResponse(rawData: any) {
160
+ * return omitUndefined({
161
+ * id: rawData.id,
162
+ * name: rawData.name,
163
+ * description: rawData.description, // may be undefined
164
+ * metadata: rawData.metadata, // may be undefined
165
+ * createdAt: rawData.created_at,
166
+ * });
167
+ * }
168
+ * ```
169
+ * @example Before database save
170
+ * ```typescript
171
+ * const userUpdate = omitUndefined({
172
+ * name: formData.name,
173
+ * email: formData.email,
174
+ * avatar: formData.avatar, // only update if provided
175
+ * settings: formData.settings, // only update if provided
176
+ * });
177
+ * ```
178
+ */
179
+ export declare function omitUndefined<T extends Record<string, unknown>>(obj: T): Record<string, unknown>;
180
+ /**
181
+ * Creates an object with conditional properties based on boolean conditions.
182
+ * Each condition is checked and only truthy conditions include their corresponding properties.
183
+ * @param conditions - Object where keys are boolean conditions (as strings) and values are objects to include
184
+ * @returns Object containing properties from all truthy conditions
185
+ * @example Basic conditional properties
186
+ * ```typescript
187
+ * const obj = {
188
+ * always: "included",
189
+ * ...conditionalProps({
190
+ * [String(isEnabled)]: { feature: "enabled" },
191
+ * [String(hasPermission)]: { admin: true },
192
+ * }),
193
+ * };
194
+ * ```
195
+ * @example Feature flags
196
+ * ```typescript
197
+ * const config = {
198
+ * baseUrl: "https://api.example.com",
199
+ * ...conditionalProps({
200
+ * [String(enableLogging)]: { logging: { level: "debug" } },
201
+ * [String(enableMetrics)]: { metrics: { endpoint: "/metrics" } },
202
+ * [String(enableAuth)]: { auth: { provider: "oauth" } },
203
+ * }),
204
+ * };
205
+ * ```
206
+ * @example User permission-based UI
207
+ * ```typescript
208
+ * const uiConfig = {
209
+ * showProfile: true,
210
+ * ...conditionalProps({
211
+ * [String(user.isAdmin)]: { showAdminPanel: true },
212
+ * [String(user.isPremium)]: { showPremiumFeatures: true },
213
+ * [String(user.canEdit)]: { showEditTools: true },
214
+ * }),
215
+ * };
216
+ * ```
217
+ */
218
+ export declare function conditionalProps(conditions: Record<string, Record<string, unknown>>): Record<string, unknown>;
219
+ /**
220
+ * Type-safe way to pick properties from an object, with undefined handling.
221
+ * Unlike Lodash pick, this preserves exact types and handles undefined values correctly.
222
+ * Only includes properties that exist in the source object.
223
+ * @param obj - The source object to pick properties from
224
+ * @param keys - Array of keys to pick from the object
225
+ * @returns New object containing only the specified properties
226
+ * @example Basic property picking
227
+ * ```typescript
228
+ * const user = { id: 1, name: "John", email: "john@example.com", password: "secret" };
229
+ * const publicUser = pick(user, ['id', 'name', 'email']);
230
+ * // Result: { id: 1, name: "John", email: "john@example.com" }
231
+ * ```
232
+ * @example API response filtering
233
+ * ```typescript
234
+ * function createPublicProfile(fullUser: FullUser) {
235
+ * return pick(fullUser, [
236
+ * 'id',
237
+ * 'username',
238
+ * 'displayName',
239
+ * 'avatar',
240
+ * 'joinedAt'
241
+ * ]);
242
+ * }
243
+ * ```
244
+ * @example Configuration subset
245
+ * ```typescript
246
+ * const fullConfig = { host: "localhost", port: 3000, ssl: true, debug: true, secret: "xxx" };
247
+ * const clientConfig = pick(fullConfig, ['host', 'port', 'ssl']);
248
+ * // Result: { host: "localhost", port: 3000, ssl: true }
249
+ * ```
250
+ */
251
+ export declare function pick<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: readonly K[]): Pick<T, K>;
252
+ /**
253
+ * Type-safe way to omit properties from an object, with undefined handling.
254
+ * Unlike Lodash omit, this preserves exact types and handles undefined values correctly.
255
+ * Creates a new object excluding the specified properties.
256
+ * @param obj - The source object to omit properties from
257
+ * @param keys - Array of keys to omit from the object
258
+ * @returns New object with the specified properties removed
259
+ * @example Remove sensitive data
260
+ * ```typescript
261
+ * const user = { id: 1, name: "John", email: "john@example.com", password: "secret", ssn: "xxx" };
262
+ * const safeUser = omit(user, ['password', 'ssn']);
263
+ * // Result: { id: 1, name: "John", email: "john@example.com" }
264
+ * ```
265
+ * @example Remove internal properties
266
+ * ```typescript
267
+ * function toApiResponse(internalObj: InternalUser) {
268
+ * return omit(internalObj, [
269
+ * '_id',
270
+ * '_version',
271
+ * '_internal',
272
+ * 'hashedPassword',
273
+ * 'secretKey'
274
+ * ]);
275
+ * }
276
+ * ```
277
+ * @example Configuration sanitization
278
+ * ```typescript
279
+ * const fullConfig = {
280
+ * host: "localhost",
281
+ * port: 3000,
282
+ * ssl: true,
283
+ * debug: true,
284
+ * apiSecret: "xxx",
285
+ * dbPassword: "yyy"
286
+ * };
287
+ * const publicConfig = omit(fullConfig, ['apiSecret', 'dbPassword']);
288
+ * // Result: { host: "localhost", port: 3000, ssl: true, debug: true }
289
+ * ```
290
+ */
291
+ export declare function omit<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: readonly K[]): Omit<T, K>;
292
+ //# sourceMappingURL=object.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../../src/object.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAC3C,GAAG,EAAE,CAAC,EACN,KAAK,EAAE,CAAC,GAAG,SAAS,GACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChE,GAAG,EAAE,CAAC,GACL,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7D,GAAG,EAAE,CAAC,GACL,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAClD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,EACvE,GAAG,EAAE,CAAC,EACN,IAAI,EAAE,SAAS,CAAC,EAAE,GACjB,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAQZ;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,EACvE,GAAG,EAAE,CAAC,EACN,IAAI,EAAE,SAAS,CAAC,EAAE,GACjB,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CASZ"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Represents a successful Result with a value.
3
+ * Can be used for type narrowing in tests and assertions.
4
+ */
5
+ export interface Success<T> {
6
+ success: true;
7
+ value: T;
8
+ error?: undefined;
9
+ }
10
+ /**
11
+ * Represents a failed Result with an error.
12
+ * Can be used for type narrowing in tests and assertions.
13
+ */
14
+ export interface Failure<E> {
15
+ success: false;
16
+ error: E;
17
+ value?: undefined;
18
+ }
19
+ /**
20
+ * A simplified Result type inspired by Rust's Result.
21
+ *
22
+ * This type represents either a successful value (ok) or an error (err).
23
+ * It is used for consistent error handling across the `@reasonabletech` platform.
24
+ */
25
+ export type Result<T, E = Error> = Success<T> | Failure<E>;
26
+ /**
27
+ * Creates a successful Result.
28
+ * @param value - Optional value to wrap in a successful Result
29
+ * @returns A successful Result containing the value
30
+ */
31
+ export declare function ok<T, E = Error>(value: T): Result<T, E>;
32
+ export declare function ok<E = Error>(): Result<void, E>;
33
+ /**
34
+ * Creates an error Result.
35
+ * @param error The error to wrap in an error Result
36
+ * @returns An error Result containing the error
37
+ */
38
+ export declare function err<T = never, E = Error>(error: E): Result<T, E>;
39
+ /**
40
+ * Type guard to check if a Result is successful.
41
+ * @param result The Result to check
42
+ * @returns True if the Result is successful
43
+ */
44
+ export declare function isSuccess<T, E = Error>(result: Readonly<Result<T, E>>): result is Success<T>;
45
+ /**
46
+ * Type guard to check if a Result is an error.
47
+ * @param result The Result to check
48
+ * @returns True if the Result is an error
49
+ */
50
+ export declare function isFailure<T, E = Error>(result: Readonly<Result<T, E>>): result is Failure<E>;
51
+ /**
52
+ * Wraps a Promise to return a Result.
53
+ * @param promise The Promise to wrap
54
+ * @returns A Promise that resolves to a Result
55
+ */
56
+ export declare function fromPromise<T>(promise: Promise<T>): Promise<Result<T, Error>>;
57
+ /**
58
+ * Maps a successful Result to a new Result with a transformed value.
59
+ * @param result The Result to map
60
+ * @param fn The function to apply to the value
61
+ * @returns A new Result with the transformed value or the original error
62
+ */
63
+ export declare function map<T, U, E = Error>(result: Readonly<Result<T, E>>, fn: (value: T) => U): Result<U, E>;
64
+ /**
65
+ * Maps an error Result to a new Result with a transformed error.
66
+ * @param result The Result to map
67
+ * @param fn The function to apply to the error
68
+ * @returns A new Result with the transformed error or the original value
69
+ */
70
+ export declare function mapErr<T, E = Error, F = Error>(result: Readonly<Result<T, E>>, fn: (error: E) => F): Result<T, F>;
71
+ /**
72
+ * Chains a function that returns a Result after a successful Result.
73
+ * @param result The Result to chain
74
+ * @param fn The function to apply to the value that returns a Result
75
+ * @returns The Result returned by the function or the original error
76
+ */
77
+ export declare function andThen<T, U, E = Error>(result: Readonly<Result<T, E>>, fn: (value: T) => Result<U, E>): Result<U, E>;
78
+ /**
79
+ * Applies a fallback function to an error Result.
80
+ * @param result The Result to check
81
+ * @param fn The function to apply to the error that returns a Result
82
+ * @returns The original Result if successful, or the Result returned by the function
83
+ */
84
+ export declare function orElse<T, E = Error, F = Error>(result: Readonly<Result<T, E>>, fn: (error: E) => Result<T, F>): Result<T, F>;
85
+ /**
86
+ * Unwraps a Result, returning the value or throwing the error.
87
+ * @param result The Result to unwrap
88
+ * @returns The value if the Result is successful
89
+ * @throws {Error} The error if the Result is an error
90
+ */
91
+ export declare function unwrap<T, E = Error>(result: Readonly<Result<T, E>>): T;
92
+ /**
93
+ * Unwraps a Result, returning the value or a default value.
94
+ * @param result The Result to unwrap
95
+ * @param defaultValue The default value to return if the Result is an error
96
+ * @returns The value if the Result is successful, or the default value
97
+ */
98
+ export declare function unwrapOr<T, E = Error>(result: Readonly<Result<T, E>>, defaultValue: T): T;
99
+ /**
100
+ * Unwraps a Result, returning the value or computing a default value from the error.
101
+ * @param result The Result to unwrap
102
+ * @param fn The function to compute the default value from the error
103
+ * @returns The value if the Result is successful, or the computed default value
104
+ */
105
+ export declare function unwrapOrElse<T, E = Error>(result: Readonly<Result<T, E>>, fn: (error: E) => T): T;
106
+ /**
107
+ * Combines an array of Results into a single Result containing an array of values.
108
+ * If any Result is an error, returns the first error.
109
+ * @param results Array of Results to combine
110
+ * @returns A Result containing an array of values or the first error
111
+ */
112
+ export declare function combine<T, E = Error>(results: ReadonlyArray<Result<T, E>>): Result<T[], E>;
113
+ //# sourceMappingURL=result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../../src/result.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Retry utility functions for the `@reasonabletech` platform
3
+ */
4
+ /**
5
+ * Core retry configuration fields that have default values
6
+ */
7
+ interface RetryConfigDefaults {
8
+ /**
9
+ * Maximum number of attempts (including the initial attempt)
10
+ * @default 3
11
+ */
12
+ maxAttempts: number;
13
+ /**
14
+ * Initial delay in milliseconds before the first retry
15
+ * @default 1000
16
+ */
17
+ initialDelay: number;
18
+ /**
19
+ * Maximum delay in milliseconds between retries
20
+ * @default 30000
21
+ */
22
+ maxDelay: number;
23
+ /**
24
+ * Multiplier for exponential backoff
25
+ * @default 2
26
+ */
27
+ backoffMultiplier: number;
28
+ /**
29
+ * Jitter factor (0-1) to add randomness to delays
30
+ * @default 0.1
31
+ */
32
+ jitterFactor: number;
33
+ /**
34
+ * Function to determine if an error should trigger a retry
35
+ * @default () => true (always retry)
36
+ */
37
+ shouldRetry: (error: unknown, attempt: number) => boolean;
38
+ }
39
+ /**
40
+ * Optional callback hooks for retry operations
41
+ */
42
+ interface RetryCallbacks {
43
+ /**
44
+ * Callback invoked when an attempt fails (before retry decision).
45
+ * Use this for logging, running interceptors, or other side effects.
46
+ */
47
+ onError?: (error: unknown, attempt: number) => void | Promise<void>;
48
+ /**
49
+ * Custom delay calculator that overrides the default exponential backoff.
50
+ * Useful when the error contains retry timing hints (e.g., Retry-After header).
51
+ */
52
+ getDelay?: (attempt: number, error: unknown) => number;
53
+ }
54
+ /**
55
+ * Configuration options for retry operations (all fields optional for user input)
56
+ * @example
57
+ * ```typescript
58
+ * const result = await retry(() => fetchData(), {
59
+ * maxAttempts: 5,
60
+ * initialDelay: 500,
61
+ * onError: (error, attempt) => console.log(`Attempt ${attempt} failed`),
62
+ * });
63
+ * ```
64
+ */
65
+ export interface RetryOptions extends Partial<RetryConfigDefaults>, RetryCallbacks {
66
+ }
67
+ /**
68
+ * Result of a retry operation
69
+ */
70
+ export interface RetryResult<T> {
71
+ /** Whether the operation succeeded */
72
+ success: boolean;
73
+ /** The result value if successful */
74
+ value?: T;
75
+ /** The final error if all attempts failed */
76
+ error?: unknown;
77
+ /** Number of attempts made */
78
+ attempts: number;
79
+ }
80
+ /**
81
+ * Sleep for the specified number of milliseconds
82
+ * @param ms - Milliseconds to sleep
83
+ * @returns Promise that resolves after the delay
84
+ */
85
+ export declare function sleep(ms: number): Promise<void>;
86
+ /**
87
+ * Retry an async operation with exponential backoff and jitter
88
+ * @param operation - The async operation to retry
89
+ * @param options - Retry configuration options
90
+ * @returns Promise resolving to retry result
91
+ * @example
92
+ * ```typescript
93
+ * // Basic retry with defaults (3 attempts, 1s initial delay)
94
+ * const result = await retry(() => fetchData());
95
+ *
96
+ * // Custom configuration with error callback
97
+ * const result = await retry(() => apiClient.post('/users', userData), {
98
+ * maxAttempts: 5,
99
+ * initialDelay: 500,
100
+ * onError: (error, attempt) => {
101
+ * logger.warn('API', `Attempt ${attempt} failed`, { error });
102
+ * },
103
+ * });
104
+ *
105
+ * // Use server-provided Retry-After hint
106
+ * const result = await retry(() => rateLimitedApi.call(), {
107
+ * getDelay: (attempt, error) => {
108
+ * if (error instanceof ApiError && error.retryAfter) {
109
+ * return error.retryAfter; // Use server-provided delay
110
+ * }
111
+ * return 1000 * Math.pow(2, attempt - 1); // Fallback to exponential
112
+ * },
113
+ * });
114
+ * ```
115
+ */
116
+ export declare function retry<T>(operation: () => Promise<T>, options?: RetryOptions): Promise<RetryResult<T>>;
117
+ /**
118
+ * Retry an operation with polling (fixed interval, no exponential backoff)
119
+ * @param operation - The async operation to retry
120
+ * @param maxAttempts - Maximum number of attempts
121
+ * @param interval - Fixed interval between attempts in milliseconds
122
+ * @param shouldRetry - Function to determine if retry should continue
123
+ * @returns Promise resolving to retry result
124
+ */
125
+ export declare function retryWithPolling<T>(operation: () => Promise<T>, maxAttempts: number, interval: number, shouldRetry?: (error: unknown, attempt: number) => boolean): Promise<RetryResult<T>>;
126
+ /**
127
+ * Retry an operation with exponential backoff (simplified interface)
128
+ * This function throws on failure instead of returning a result object.
129
+ * @param operation - The async operation to retry
130
+ * @param maxRetries - Maximum number of retries (attempts after the first try, default: 3)
131
+ * @param baseDelay - Base delay in milliseconds (default: 1000)
132
+ * @returns Promise resolving to the operation's result
133
+ * @throws {unknown} The last error if all attempts fail
134
+ * @example
135
+ * ```typescript
136
+ * // Retry up to 3 times with exponential backoff
137
+ * const result = await retryWithBackoff(() => fetchData(), 3, 500);
138
+ *
139
+ * // Use default retries (3) and delay (1000ms)
140
+ * const user = await retryWithBackoff(() => createUser(userData));
141
+ * ```
142
+ */
143
+ export declare function retryWithBackoff<T>(operation: () => Promise<T>, maxRetries?: number, baseDelay?: number): Promise<T>;
144
+ export {};
145
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/retry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,UAAU,mBAAmB;IAC3B;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;CAC3D;AAED;;GAEG;AACH,UAAU,cAAc;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpE;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;CACxD;AAOD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,YACf,SAAQ,OAAO,CAAC,mBAAmB,CAAC,EAClC,cAAc;CAAG;AAErB;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,qCAAqC;IACrC,KAAK,CAAC,EAAE,CAAC,CAAC;IACV,6CAA6C;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAC;CAClB;AA8BD;;;;GAIG;AACH,wBAAsB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAErD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,KAAK,CAAC,CAAC,EAC3B,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CA6CzB;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,WAAW,GAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,OAAoB,GACrE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CASzB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,UAAU,GAAE,MAAU,EACtB,SAAS,GAAE,MAAa,GACvB,OAAO,CAAC,CAAC,CAAC,CAYZ"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * String utility functions
3
+ */
4
+ /**
5
+ * Check if a string is empty or only contains whitespace
6
+ * @param value - The string to check
7
+ * @returns true if the string is empty, null, undefined, or only whitespace
8
+ */
9
+ export declare function isEmptyString(value: string | null | undefined): boolean;
10
+ /**
11
+ * Check if a string is not empty and contains non-whitespace characters
12
+ * @param value - The string to check
13
+ * @returns true if the string has content
14
+ */
15
+ export declare function isNonEmptyString(value: string | null | undefined): value is string;
16
+ /**
17
+ * Truncate a string to a maximum length with ellipsis
18
+ * @param str - The string to truncate
19
+ * @param maxLength - Maximum length (including ellipsis)
20
+ * @returns Truncated string with ellipsis if needed
21
+ */
22
+ export declare function truncateString(str: string, maxLength: number): string;
23
+ /**
24
+ * Capitalize the first letter of a string
25
+ * @param str - The string to capitalize
26
+ * @returns String with first letter capitalized
27
+ */
28
+ export declare function capitalize(str: string): string;
29
+ /**
30
+ * Create a base64url encoded string
31
+ * @param data - Data to encode (string or Buffer)
32
+ * @returns Base64url encoded string (URL-safe, no padding)
33
+ */
34
+ export declare function encodeBase64Url(data: string | Buffer): string;
35
+ /**
36
+ * Decode a base64url encoded string
37
+ * @param encoded - Base64url encoded string
38
+ * @returns Decoded data as Buffer
39
+ */
40
+ export declare function decodeBase64Url(encoded: string): Buffer;
41
+ /**
42
+ * Check if a string is a valid base64url format
43
+ * @param str - String to validate
44
+ * @returns True if the string is valid base64url format
45
+ */
46
+ export declare function isValidBase64Url(str: string): boolean;
47
+ /**
48
+ * Extract a message string from an unknown error value
49
+ * @deprecated This utility is unnecessary. The logger accepts `ErrorLike` (unknown)
50
+ * directly via `logger.error(tag, message, error)`. Pass errors directly to the
51
+ * logger instead of manually converting to strings.
52
+ *
53
+ * See: docs/standards/error-boundary-patterns.md
54
+ * @example
55
+ * ```typescript
56
+ * // ❌ DEPRECATED: Manual error string extraction
57
+ * try {
58
+ * await operation();
59
+ * } catch (error) {
60
+ * logger.error("Component", getErrorMessage(error));
61
+ * }
62
+ *
63
+ * // ✅ CORRECT: Pass error directly to logger
64
+ * try {
65
+ * await operation();
66
+ * } catch (error) {
67
+ * logger.error("Component", "Operation failed", error);
68
+ * }
69
+ * ```
70
+ * @param error - Error value (Error object, string, or other)
71
+ * @returns Error message string
72
+ * @internal
73
+ */
74
+ export declare function getErrorMessage(error: unknown): string;
75
+ //# sourceMappingURL=string.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"string.d.ts","sourceRoot":"","sources":["../../src/string.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEvE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,KAAK,IAAI,MAAM,CAEjB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAKrE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK9C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAG7D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAgBtD"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Type guard utilities for common type checking patterns
3
+ * @module type-guards
4
+ */
5
+ /**
6
+ * Type guard to check if value is neither null nor undefined
7
+ * @template T - The value type
8
+ * @param value - The value to check
9
+ * @returns True if value is present (not null or undefined), with type narrowing
10
+ * @example
11
+ * ```typescript
12
+ * // Optional configuration value
13
+ * const redirectUrl: string | null | undefined = config.redirectUrl;
14
+ * if (isPresent(redirectUrl)) {
15
+ * window.location.href = redirectUrl; // redirectUrl is string
16
+ * }
17
+ *
18
+ * // Database lookup result
19
+ * const user: User | null = await db.users.findById(id);
20
+ * if (isPresent(user)) {
21
+ * console.log(user.email); // user is User
22
+ * }
23
+ * ```
24
+ */
25
+ export declare function isPresent<T>(value: T | null | undefined): value is T;
26
+ //# sourceMappingURL=type-guards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-guards.d.ts","sourceRoot":"","sources":["../../src/type-guards.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,IAAI,CAAC,CAEpE"}