@markwharton/api-core 1.0.0 → 1.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.
- package/README.md +71 -0
- package/dist/errors.d.ts +24 -1
- package/dist/errors.js +33 -2
- package/dist/index.d.ts +4 -1
- package/dist/index.js +3 -1
- package/dist/result.d.ts +40 -0
- package/dist/result.js +27 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# @markwharton/api-core
|
|
2
|
+
|
|
3
|
+
Shared utilities for API client packages.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @markwharton/api-core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## API Reference
|
|
12
|
+
|
|
13
|
+
### TTLCache
|
|
14
|
+
|
|
15
|
+
In-memory TTL cache with request coalescing. When multiple concurrent callers request the same expired key, only one factory call is made.
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { TTLCache } from '@markwharton/api-core';
|
|
19
|
+
|
|
20
|
+
const cache = new TTLCache();
|
|
21
|
+
|
|
22
|
+
// Get or populate a cached value (5 minute TTL)
|
|
23
|
+
const data = await cache.get('employees', 5 * 60_000, () => fetchEmployees());
|
|
24
|
+
|
|
25
|
+
// Invalidate by key prefix
|
|
26
|
+
cache.invalidate('timesheet:');
|
|
27
|
+
|
|
28
|
+
// Clear all cached data
|
|
29
|
+
cache.clear();
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### fetchWithRetry
|
|
33
|
+
|
|
34
|
+
Automatic retry on HTTP 429 and 503 with exponential backoff. Respects the `Retry-After` header.
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { fetchWithRetry } from '@markwharton/api-core';
|
|
38
|
+
|
|
39
|
+
const response = await fetchWithRetry(url, init, {
|
|
40
|
+
retry: { maxRetries: 3, initialDelayMs: 1000, maxDelayMs: 10000 },
|
|
41
|
+
onRetry: ({ attempt, delayMs, status }) => {
|
|
42
|
+
console.log(`Retry ${attempt} after ${delayMs}ms (HTTP ${status})`);
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### batchMap
|
|
48
|
+
|
|
49
|
+
Map over items with bounded concurrency.
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { batchMap } from '@markwharton/api-core';
|
|
53
|
+
|
|
54
|
+
const results = await batchMap(items, 5, async (item) => fetchItem(item.id));
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### getErrorMessage
|
|
58
|
+
|
|
59
|
+
Extract a safe error message from any error type.
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { getErrorMessage } from '@markwharton/api-core';
|
|
63
|
+
|
|
64
|
+
try { ... } catch (err) {
|
|
65
|
+
console.error(getErrorMessage(err));
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## License
|
|
70
|
+
|
|
71
|
+
MIT
|
package/dist/errors.d.ts
CHANGED
|
@@ -3,5 +3,28 @@
|
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
5
|
* Get a safe error message from any error type
|
|
6
|
+
*
|
|
7
|
+
* @param error - The caught error value
|
|
8
|
+
* @param fallback - Custom fallback message (default: 'Unknown error')
|
|
6
9
|
*/
|
|
7
|
-
export declare function getErrorMessage(error: unknown): string;
|
|
10
|
+
export declare function getErrorMessage(error: unknown, fallback?: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Parsed error from a JSON API response
|
|
13
|
+
*/
|
|
14
|
+
export interface ParsedError {
|
|
15
|
+
/** Human-readable error message */
|
|
16
|
+
message: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Parse a JSON error response body into a human-readable message.
|
|
20
|
+
*
|
|
21
|
+
* Handles common API error formats:
|
|
22
|
+
* - `{ "message": "..." }`
|
|
23
|
+
* - `{ "error": "..." }`
|
|
24
|
+
* - Plain text
|
|
25
|
+
*
|
|
26
|
+
* @param errorText - Raw error response text
|
|
27
|
+
* @param statusCode - HTTP status code (used as fallback message)
|
|
28
|
+
* @returns Parsed error with message
|
|
29
|
+
*/
|
|
30
|
+
export declare function parseJsonErrorResponse(errorText: string, statusCode: number): ParsedError;
|
package/dist/errors.js
CHANGED
|
@@ -5,10 +5,41 @@
|
|
|
5
5
|
const DEFAULT_ERROR_MESSAGE = 'Unknown error';
|
|
6
6
|
/**
|
|
7
7
|
* Get a safe error message from any error type
|
|
8
|
+
*
|
|
9
|
+
* @param error - The caught error value
|
|
10
|
+
* @param fallback - Custom fallback message (default: 'Unknown error')
|
|
8
11
|
*/
|
|
9
|
-
export function getErrorMessage(error) {
|
|
12
|
+
export function getErrorMessage(error, fallback) {
|
|
10
13
|
if (error instanceof Error) {
|
|
11
14
|
return error.message;
|
|
12
15
|
}
|
|
13
|
-
return DEFAULT_ERROR_MESSAGE;
|
|
16
|
+
return fallback ?? DEFAULT_ERROR_MESSAGE;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Parse a JSON error response body into a human-readable message.
|
|
20
|
+
*
|
|
21
|
+
* Handles common API error formats:
|
|
22
|
+
* - `{ "message": "..." }`
|
|
23
|
+
* - `{ "error": "..." }`
|
|
24
|
+
* - Plain text
|
|
25
|
+
*
|
|
26
|
+
* @param errorText - Raw error response text
|
|
27
|
+
* @param statusCode - HTTP status code (used as fallback message)
|
|
28
|
+
* @returns Parsed error with message
|
|
29
|
+
*/
|
|
30
|
+
export function parseJsonErrorResponse(errorText, statusCode) {
|
|
31
|
+
try {
|
|
32
|
+
const errorJson = JSON.parse(errorText);
|
|
33
|
+
if (errorJson.message) {
|
|
34
|
+
return { message: errorJson.message };
|
|
35
|
+
}
|
|
36
|
+
if (errorJson.error) {
|
|
37
|
+
return { message: errorJson.error };
|
|
38
|
+
}
|
|
39
|
+
return { message: `HTTP ${statusCode}` };
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Not JSON, return as-is or fallback
|
|
43
|
+
return { message: errorText || `HTTP ${statusCode}` };
|
|
44
|
+
}
|
|
14
45
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Shared utilities for API client packages.
|
|
5
5
|
*/
|
|
6
|
+
export { ok, okVoid, err } from './result.js';
|
|
7
|
+
export type { Result } from './result.js';
|
|
6
8
|
export { TTLCache } from './cache.js';
|
|
7
9
|
export { batchMap } from './utils.js';
|
|
8
|
-
export { getErrorMessage } from './errors.js';
|
|
10
|
+
export { getErrorMessage, parseJsonErrorResponse } from './errors.js';
|
|
11
|
+
export type { ParsedError } from './errors.js';
|
|
9
12
|
export { fetchWithRetry } from './retry.js';
|
|
10
13
|
export type { RetryConfig, FetchWithRetryOptions } from './retry.js';
|
package/dist/index.js
CHANGED
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Shared utilities for API client packages.
|
|
5
5
|
*/
|
|
6
|
+
// Result
|
|
7
|
+
export { ok, okVoid, err } from './result.js';
|
|
6
8
|
// Cache
|
|
7
9
|
export { TTLCache } from './cache.js';
|
|
8
10
|
// Utilities
|
|
9
11
|
export { batchMap } from './utils.js';
|
|
10
12
|
// Errors
|
|
11
|
-
export { getErrorMessage } from './errors.js';
|
|
13
|
+
export { getErrorMessage, parseJsonErrorResponse } from './errors.js';
|
|
12
14
|
// Retry
|
|
13
15
|
export { fetchWithRetry } from './retry.js';
|
package/dist/result.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal Result Type
|
|
3
|
+
*
|
|
4
|
+
* Standard return type for all fallible API operations.
|
|
5
|
+
* Aligned with @markwharton/pwa-core Result<T>.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Result of a fallible operation
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // Success
|
|
13
|
+
* const result: Result<User> = { ok: true, data: user };
|
|
14
|
+
*
|
|
15
|
+
* // Error
|
|
16
|
+
* const result: Result<User> = { ok: false, error: 'Not found', status: 404 };
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export interface Result<T> {
|
|
20
|
+
/** Whether the operation succeeded */
|
|
21
|
+
ok: boolean;
|
|
22
|
+
/** The data if successful */
|
|
23
|
+
data?: T;
|
|
24
|
+
/** Error message if failed */
|
|
25
|
+
error?: string;
|
|
26
|
+
/** HTTP status code (present on error, sometimes on success) */
|
|
27
|
+
status?: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Create a successful Result with data
|
|
31
|
+
*/
|
|
32
|
+
export declare function ok<T>(data: T): Result<T>;
|
|
33
|
+
/**
|
|
34
|
+
* Create a successful Result with no data
|
|
35
|
+
*/
|
|
36
|
+
export declare function okVoid(): Result<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Create a failed Result with an error message and optional status code
|
|
39
|
+
*/
|
|
40
|
+
export declare function err<T = never>(error: string, status?: number): Result<T>;
|
package/dist/result.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal Result Type
|
|
3
|
+
*
|
|
4
|
+
* Standard return type for all fallible API operations.
|
|
5
|
+
* Aligned with @markwharton/pwa-core Result<T>.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Create a successful Result with data
|
|
9
|
+
*/
|
|
10
|
+
export function ok(data) {
|
|
11
|
+
return { ok: true, data };
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Create a successful Result with no data
|
|
15
|
+
*/
|
|
16
|
+
export function okVoid() {
|
|
17
|
+
return { ok: true };
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Create a failed Result with an error message and optional status code
|
|
21
|
+
*/
|
|
22
|
+
export function err(error, status) {
|
|
23
|
+
const result = { ok: false, error };
|
|
24
|
+
if (status !== undefined)
|
|
25
|
+
result.status = status;
|
|
26
|
+
return result;
|
|
27
|
+
}
|