jitterbug 1.0.0-alpha.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/LICENSE +21 -0
- package/README.md +176 -0
- package/dist/index.cjs +56 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +35 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Cory Lewis
|
|
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,176 @@
|
|
|
1
|
+
# jitterbug
|
|
2
|
+
|
|
3
|
+
Jitterbug is a lightweight library for building reliable retry behavior in distributed systems and API clients.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install jitterbug
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
### JavaScript/TypeScript
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { retry, type RetryOptions } from 'jitterbug';
|
|
22
|
+
|
|
23
|
+
// Basic usage
|
|
24
|
+
const fetchWithRetry = retry(async (url) => {
|
|
25
|
+
const response = await fetch(url);
|
|
26
|
+
if (!response.ok) throw new Error('Request failed');
|
|
27
|
+
return response.json();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// With options
|
|
31
|
+
const fetchWithRetry = retry(async (url) => {
|
|
32
|
+
const response = await fetch(url);
|
|
33
|
+
if (!response.ok) throw new Error('Request failed');
|
|
34
|
+
return response.json();
|
|
35
|
+
}, {
|
|
36
|
+
maxAttempts: 5,
|
|
37
|
+
delay: 1000,
|
|
38
|
+
backoff: 'exponential', // 'exponential', 'linear', or 'fixed'
|
|
39
|
+
onRetry: (error, attempt, waitTime) => {
|
|
40
|
+
console.log(`Retry attempt ${attempt} after ${waitTime}ms`);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Use it
|
|
45
|
+
try {
|
|
46
|
+
const data = await fetchWithRetry('https://api.example.com/data');
|
|
47
|
+
console.log(data);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error('All retry attempts failed:', error);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## API
|
|
54
|
+
|
|
55
|
+
### `retry<T>(fn: T, options?: RetryOptions): T`
|
|
56
|
+
|
|
57
|
+
Creates a retry wrapper function.
|
|
58
|
+
|
|
59
|
+
**Parameters:**
|
|
60
|
+
- `fn`: The async function to retry
|
|
61
|
+
- `options`: Configuration object (optional)
|
|
62
|
+
- `maxAttempts` (number, default: 3): Maximum number of retry attempts
|
|
63
|
+
- `delay` (number, default: 1000): Base delay in milliseconds
|
|
64
|
+
- `backoff` ('exponential' | 'linear' | 'fixed', default: 'exponential'): Backoff strategy
|
|
65
|
+
- `onRetry` ((error: Error, attempt: number, waitTime: number) => void, optional): Callback called before each retry
|
|
66
|
+
|
|
67
|
+
**Returns:** A function that wraps the original function with retry logic
|
|
68
|
+
|
|
69
|
+
**TypeScript Types:**
|
|
70
|
+
```typescript
|
|
71
|
+
import type { RetryOptions, BackoffStrategy } from 'jitterbug';
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Development
|
|
75
|
+
|
|
76
|
+
### Building
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Build the project
|
|
80
|
+
npm run build
|
|
81
|
+
|
|
82
|
+
# Build in watch mode
|
|
83
|
+
npm run dev
|
|
84
|
+
|
|
85
|
+
# Type check without building
|
|
86
|
+
npm run typecheck
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Running Tests
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# Run tests in watch mode
|
|
93
|
+
npm test
|
|
94
|
+
|
|
95
|
+
# Run tests once
|
|
96
|
+
npm run test:run
|
|
97
|
+
|
|
98
|
+
# Run tests with coverage
|
|
99
|
+
npm run test:coverage
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Publishing
|
|
103
|
+
|
|
104
|
+
Publishing to npm is automated via GitHub Actions. To publish a new version:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Choose one based on the type of change:
|
|
108
|
+
npm version patch # Bug fixes: 0.1.0 -> 0.1.1
|
|
109
|
+
npm version minor # New features: 0.1.0 -> 0.2.0
|
|
110
|
+
npm version major # Breaking changes: 0.1.0 -> 1.0.0
|
|
111
|
+
|
|
112
|
+
# This automatically:
|
|
113
|
+
# - Updates package.json version
|
|
114
|
+
# - Builds the project (via version script)
|
|
115
|
+
# - Creates a git commit
|
|
116
|
+
# - Creates a git tag (v0.1.1, v0.2.0, etc.)
|
|
117
|
+
|
|
118
|
+
# Then push both the commit and tags:
|
|
119
|
+
git push && git push --tags
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Publishing alpha/beta versions:**
|
|
123
|
+
|
|
124
|
+
For pre-release versions (alpha, beta, rc):
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Create an alpha version
|
|
128
|
+
npm version prepatch --preid=alpha # 0.1.0 -> 0.1.1-alpha.0
|
|
129
|
+
npm version preminor --preid=alpha # 0.1.0 -> 0.2.0-alpha.0
|
|
130
|
+
npm version premajor --preid=alpha # 0.1.0 -> 1.0.0-alpha.0
|
|
131
|
+
|
|
132
|
+
# Increment alpha version
|
|
133
|
+
npm version prerelease --preid=alpha # 0.1.1-alpha.0 -> 0.1.1-alpha.1
|
|
134
|
+
|
|
135
|
+
# Push the commit and tag
|
|
136
|
+
git push && git push --tags
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The CI/CD pipeline will automatically:
|
|
140
|
+
- Run all tests
|
|
141
|
+
- Build the project
|
|
142
|
+
- Verify version matches the tag
|
|
143
|
+
- Publish to npm (if tests pass)
|
|
144
|
+
|
|
145
|
+
**Note:** `NPM_TOKEN` secret needs to be setupas a GitHub secret with your npm access token.
|
|
146
|
+
|
|
147
|
+
### Project Structure
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
jitterbug/
|
|
151
|
+
├── src/ # TypeScript source code
|
|
152
|
+
│ ├── retry.ts # Core retry implementation
|
|
153
|
+
│ └── index.ts # Main entry point
|
|
154
|
+
├── dist/ # Built output (ESM + CJS + types)
|
|
155
|
+
├── test/ # Test files
|
|
156
|
+
│ └── retry.test.js
|
|
157
|
+
├── tsconfig.json # TypeScript configuration
|
|
158
|
+
├── tsup.config.ts # Build configuration
|
|
159
|
+
└── package.json
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Test Coverage
|
|
163
|
+
|
|
164
|
+

|
|
165
|
+
|
|
166
|
+
| Metric | Coverage |
|
|
167
|
+
|--------|----------|
|
|
168
|
+
| Statements | 37.31% |
|
|
169
|
+
| Branches | 82.35% |
|
|
170
|
+
| Functions | 66.67% |
|
|
171
|
+
| Lines | 37.31% |
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
## License
|
|
175
|
+
|
|
176
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
// src/retry.ts
|
|
6
|
+
function calculateDelay(baseDelay, attempt, backoff) {
|
|
7
|
+
switch (backoff) {
|
|
8
|
+
case "exponential":
|
|
9
|
+
return baseDelay * Math.pow(2, attempt - 1);
|
|
10
|
+
case "linear":
|
|
11
|
+
return baseDelay * attempt;
|
|
12
|
+
case "fixed":
|
|
13
|
+
default:
|
|
14
|
+
return baseDelay;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function sleep(ms) {
|
|
18
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
19
|
+
}
|
|
20
|
+
function retry(fn, options = {}) {
|
|
21
|
+
const {
|
|
22
|
+
maxAttempts = 3,
|
|
23
|
+
delay = 1e3,
|
|
24
|
+
backoff = "exponential",
|
|
25
|
+
onRetry = () => {
|
|
26
|
+
}
|
|
27
|
+
} = options;
|
|
28
|
+
return (async function(...args) {
|
|
29
|
+
let lastError;
|
|
30
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
31
|
+
try {
|
|
32
|
+
return await fn(...args);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
35
|
+
if (attempt < maxAttempts) {
|
|
36
|
+
const waitTime = calculateDelay(delay, attempt, backoff);
|
|
37
|
+
onRetry(lastError, attempt, waitTime);
|
|
38
|
+
await sleep(waitTime);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
throw lastError;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// src/index.ts
|
|
47
|
+
var index_default = {
|
|
48
|
+
retry
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
exports.calculateDelay = calculateDelay;
|
|
52
|
+
exports.default = index_default;
|
|
53
|
+
exports.retry = retry;
|
|
54
|
+
exports.sleep = sleep;
|
|
55
|
+
//# sourceMappingURL=index.cjs.map
|
|
56
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/retry.ts","../src/index.ts"],"names":[],"mappings":";;;;;AAiBA,SAAS,cAAA,CAAe,SAAA,EAAmB,OAAA,EAAiB,OAAA,EAAkC;AAC5F,EAAA,QAAQ,OAAA;AAAS,IACf,KAAK,aAAA;AACH,MAAA,OAAO,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,UAAU,CAAC,CAAA;AAAA,IAC5C,KAAK,QAAA;AACH,MAAA,OAAO,SAAA,GAAY,OAAA;AAAA,IACrB,KAAK,OAAA;AAAA,IACL;AACE,MAAA,OAAO,SAAA;AAAA;AAEb;AAEA,SAAS,MAAM,EAAA,EAA2B;AACxC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACvD;AAQO,SAAS,KAAA,CACd,EAAA,EACA,OAAA,GAAwB,EAAC,EACtB;AACH,EAAA,MAAM;AAAA,IACJ,WAAA,GAAc,CAAA;AAAA,IACd,KAAA,GAAQ,GAAA;AAAA,IACR,OAAA,GAAU,aAAA;AAAA,IACV,UAAU,MAAM;AAAA,IAAC;AAAA,GACnB,GAAI,OAAA;AAEJ,EAAA,QAAQ,kBAAkB,IAAA,EAA6C;AACrE,IAAA,IAAI,SAAA;AAEJ,IAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,WAAA,EAAa,OAAA,EAAA,EAAW;AACvD,MAAA,IAAI;AACF,QAAA,OAAO,MAAM,EAAA,CAAG,GAAG,IAAI,CAAA;AAAA,MACzB,SAAS,KAAA,EAAO;AACd,QAAA,SAAA,GAAY,iBAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AAEpE,QAAA,IAAI,UAAU,WAAA,EAAa;AACzB,UAAA,MAAM,QAAA,GAAW,cAAA,CAAe,KAAA,EAAO,OAAA,EAAS,OAAO,CAAA;AACvD,UAAA,OAAA,CAAQ,SAAA,EAAW,SAAS,QAAQ,CAAA;AACpC,UAAA,MAAM,MAAM,QAAQ,CAAA;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AAEA,IAAA,MAAM,SAAA;AAAA,EACR,CAAA;AACF;;;AC7DA,IAAO,aAAA,GAAQ;AAAA,EACb;AACF","file":"index.cjs","sourcesContent":["/**\n * Core retry logic implementation\n */\n\nexport type BackoffStrategy = 'exponential' | 'linear' | 'fixed';\n\nexport interface RetryOptions {\n /** Maximum number of retry attempts (default: 3) */\n maxAttempts?: number;\n /** Base delay in milliseconds (default: 1000) */\n delay?: number;\n /** Backoff strategy: 'exponential', 'linear', or 'fixed' (default: 'exponential') */\n backoff?: BackoffStrategy;\n /** Callback called before each retry (error, attempt, waitTime) */\n onRetry?: (error: Error, attempt: number, waitTime: number) => void;\n}\n\nfunction calculateDelay(baseDelay: number, attempt: number, backoff: BackoffStrategy): number {\n switch (backoff) {\n case 'exponential':\n return baseDelay * Math.pow(2, attempt - 1);\n case 'linear':\n return baseDelay * attempt;\n case 'fixed':\n default:\n return baseDelay;\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Creates a retry wrapper function\n * @param fn - The async function to retry\n * @param options - Retry configuration\n * @returns A function that wraps the original function with retry logic\n */\nexport function retry<T extends (...args: any[]) => Promise<any>>(\n fn: T,\n options: RetryOptions = {}\n): T {\n const {\n maxAttempts = 3,\n delay = 1000,\n backoff = 'exponential',\n onRetry = () => {}\n } = options;\n\n return (async function(...args: Parameters<T>): Promise<ReturnType<T>> {\n let lastError: Error;\n \n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await fn(...args);\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n \n if (attempt < maxAttempts) {\n const waitTime = calculateDelay(delay, attempt, backoff);\n onRetry(lastError, attempt, waitTime);\n await sleep(waitTime);\n }\n }\n }\n \n throw lastError!;\n }) as T;\n}\n\nexport { calculateDelay, sleep };\n\n","/**\n * Jitterbug - A lightweight library for building reliable retry behavior\n */\n\nexport { retry, calculateDelay, sleep, type RetryOptions, type BackoffStrategy } from './retry';\n\nimport { retry } from './retry';\n\nexport default {\n retry\n};\n\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core retry logic implementation
|
|
3
|
+
*/
|
|
4
|
+
type BackoffStrategy = 'exponential' | 'linear' | 'fixed';
|
|
5
|
+
interface RetryOptions {
|
|
6
|
+
/** Maximum number of retry attempts (default: 3) */
|
|
7
|
+
maxAttempts?: number;
|
|
8
|
+
/** Base delay in milliseconds (default: 1000) */
|
|
9
|
+
delay?: number;
|
|
10
|
+
/** Backoff strategy: 'exponential', 'linear', or 'fixed' (default: 'exponential') */
|
|
11
|
+
backoff?: BackoffStrategy;
|
|
12
|
+
/** Callback called before each retry (error, attempt, waitTime) */
|
|
13
|
+
onRetry?: (error: Error, attempt: number, waitTime: number) => void;
|
|
14
|
+
}
|
|
15
|
+
declare function calculateDelay(baseDelay: number, attempt: number, backoff: BackoffStrategy): number;
|
|
16
|
+
declare function sleep(ms: number): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a retry wrapper function
|
|
19
|
+
* @param fn - The async function to retry
|
|
20
|
+
* @param options - Retry configuration
|
|
21
|
+
* @returns A function that wraps the original function with retry logic
|
|
22
|
+
*/
|
|
23
|
+
declare function retry<T extends (...args: any[]) => Promise<any>>(fn: T, options?: RetryOptions): T;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Jitterbug - A lightweight library for building reliable retry behavior
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
declare const _default: {
|
|
30
|
+
retry: typeof retry;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
export = _default;
|
|
35
|
+
export { type BackoffStrategy, type RetryOptions, calculateDelay, retry, sleep };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core retry logic implementation
|
|
3
|
+
*/
|
|
4
|
+
type BackoffStrategy = 'exponential' | 'linear' | 'fixed';
|
|
5
|
+
interface RetryOptions {
|
|
6
|
+
/** Maximum number of retry attempts (default: 3) */
|
|
7
|
+
maxAttempts?: number;
|
|
8
|
+
/** Base delay in milliseconds (default: 1000) */
|
|
9
|
+
delay?: number;
|
|
10
|
+
/** Backoff strategy: 'exponential', 'linear', or 'fixed' (default: 'exponential') */
|
|
11
|
+
backoff?: BackoffStrategy;
|
|
12
|
+
/** Callback called before each retry (error, attempt, waitTime) */
|
|
13
|
+
onRetry?: (error: Error, attempt: number, waitTime: number) => void;
|
|
14
|
+
}
|
|
15
|
+
declare function calculateDelay(baseDelay: number, attempt: number, backoff: BackoffStrategy): number;
|
|
16
|
+
declare function sleep(ms: number): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a retry wrapper function
|
|
19
|
+
* @param fn - The async function to retry
|
|
20
|
+
* @param options - Retry configuration
|
|
21
|
+
* @returns A function that wraps the original function with retry logic
|
|
22
|
+
*/
|
|
23
|
+
declare function retry<T extends (...args: any[]) => Promise<any>>(fn: T, options?: RetryOptions): T;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Jitterbug - A lightweight library for building reliable retry behavior
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
declare const _default: {
|
|
30
|
+
retry: typeof retry;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export { type BackoffStrategy, type RetryOptions, calculateDelay, _default as default, retry, sleep };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// src/retry.ts
|
|
2
|
+
function calculateDelay(baseDelay, attempt, backoff) {
|
|
3
|
+
switch (backoff) {
|
|
4
|
+
case "exponential":
|
|
5
|
+
return baseDelay * Math.pow(2, attempt - 1);
|
|
6
|
+
case "linear":
|
|
7
|
+
return baseDelay * attempt;
|
|
8
|
+
case "fixed":
|
|
9
|
+
default:
|
|
10
|
+
return baseDelay;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function sleep(ms) {
|
|
14
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
15
|
+
}
|
|
16
|
+
function retry(fn, options = {}) {
|
|
17
|
+
const {
|
|
18
|
+
maxAttempts = 3,
|
|
19
|
+
delay = 1e3,
|
|
20
|
+
backoff = "exponential",
|
|
21
|
+
onRetry = () => {
|
|
22
|
+
}
|
|
23
|
+
} = options;
|
|
24
|
+
return (async function(...args) {
|
|
25
|
+
let lastError;
|
|
26
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
27
|
+
try {
|
|
28
|
+
return await fn(...args);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
31
|
+
if (attempt < maxAttempts) {
|
|
32
|
+
const waitTime = calculateDelay(delay, attempt, backoff);
|
|
33
|
+
onRetry(lastError, attempt, waitTime);
|
|
34
|
+
await sleep(waitTime);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
throw lastError;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/index.ts
|
|
43
|
+
var index_default = {
|
|
44
|
+
retry
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export { calculateDelay, index_default as default, retry, sleep };
|
|
48
|
+
//# sourceMappingURL=index.js.map
|
|
49
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/retry.ts","../src/index.ts"],"names":[],"mappings":";AAiBA,SAAS,cAAA,CAAe,SAAA,EAAmB,OAAA,EAAiB,OAAA,EAAkC;AAC5F,EAAA,QAAQ,OAAA;AAAS,IACf,KAAK,aAAA;AACH,MAAA,OAAO,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,UAAU,CAAC,CAAA;AAAA,IAC5C,KAAK,QAAA;AACH,MAAA,OAAO,SAAA,GAAY,OAAA;AAAA,IACrB,KAAK,OAAA;AAAA,IACL;AACE,MAAA,OAAO,SAAA;AAAA;AAEb;AAEA,SAAS,MAAM,EAAA,EAA2B;AACxC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACvD;AAQO,SAAS,KAAA,CACd,EAAA,EACA,OAAA,GAAwB,EAAC,EACtB;AACH,EAAA,MAAM;AAAA,IACJ,WAAA,GAAc,CAAA;AAAA,IACd,KAAA,GAAQ,GAAA;AAAA,IACR,OAAA,GAAU,aAAA;AAAA,IACV,UAAU,MAAM;AAAA,IAAC;AAAA,GACnB,GAAI,OAAA;AAEJ,EAAA,QAAQ,kBAAkB,IAAA,EAA6C;AACrE,IAAA,IAAI,SAAA;AAEJ,IAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,WAAA,EAAa,OAAA,EAAA,EAAW;AACvD,MAAA,IAAI;AACF,QAAA,OAAO,MAAM,EAAA,CAAG,GAAG,IAAI,CAAA;AAAA,MACzB,SAAS,KAAA,EAAO;AACd,QAAA,SAAA,GAAY,iBAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AAEpE,QAAA,IAAI,UAAU,WAAA,EAAa;AACzB,UAAA,MAAM,QAAA,GAAW,cAAA,CAAe,KAAA,EAAO,OAAA,EAAS,OAAO,CAAA;AACvD,UAAA,OAAA,CAAQ,SAAA,EAAW,SAAS,QAAQ,CAAA;AACpC,UAAA,MAAM,MAAM,QAAQ,CAAA;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AAEA,IAAA,MAAM,SAAA;AAAA,EACR,CAAA;AACF;;;AC7DA,IAAO,aAAA,GAAQ;AAAA,EACb;AACF","file":"index.js","sourcesContent":["/**\n * Core retry logic implementation\n */\n\nexport type BackoffStrategy = 'exponential' | 'linear' | 'fixed';\n\nexport interface RetryOptions {\n /** Maximum number of retry attempts (default: 3) */\n maxAttempts?: number;\n /** Base delay in milliseconds (default: 1000) */\n delay?: number;\n /** Backoff strategy: 'exponential', 'linear', or 'fixed' (default: 'exponential') */\n backoff?: BackoffStrategy;\n /** Callback called before each retry (error, attempt, waitTime) */\n onRetry?: (error: Error, attempt: number, waitTime: number) => void;\n}\n\nfunction calculateDelay(baseDelay: number, attempt: number, backoff: BackoffStrategy): number {\n switch (backoff) {\n case 'exponential':\n return baseDelay * Math.pow(2, attempt - 1);\n case 'linear':\n return baseDelay * attempt;\n case 'fixed':\n default:\n return baseDelay;\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Creates a retry wrapper function\n * @param fn - The async function to retry\n * @param options - Retry configuration\n * @returns A function that wraps the original function with retry logic\n */\nexport function retry<T extends (...args: any[]) => Promise<any>>(\n fn: T,\n options: RetryOptions = {}\n): T {\n const {\n maxAttempts = 3,\n delay = 1000,\n backoff = 'exponential',\n onRetry = () => {}\n } = options;\n\n return (async function(...args: Parameters<T>): Promise<ReturnType<T>> {\n let lastError: Error;\n \n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await fn(...args);\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n \n if (attempt < maxAttempts) {\n const waitTime = calculateDelay(delay, attempt, backoff);\n onRetry(lastError, attempt, waitTime);\n await sleep(waitTime);\n }\n }\n }\n \n throw lastError!;\n }) as T;\n}\n\nexport { calculateDelay, sleep };\n\n","/**\n * Jitterbug - A lightweight library for building reliable retry behavior\n */\n\nexport { retry, calculateDelay, sleep, type RetryOptions, type BackoffStrategy } from './retry';\n\nimport { retry } from './retry';\n\nexport default {\n retry\n};\n\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jitterbug",
|
|
3
|
+
"version": "1.0.0-alpha.2",
|
|
4
|
+
"description": "A lightweight library for building reliable retry behavior in distributed systems and API clients",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"dev": "tsup --watch",
|
|
22
|
+
"test": "vitest",
|
|
23
|
+
"test:run": "vitest run",
|
|
24
|
+
"test:coverage": "vitest run --coverage",
|
|
25
|
+
"test:watch": "vitest --watch",
|
|
26
|
+
"typecheck": "tsc --noEmit",
|
|
27
|
+
"prepublishOnly": "npm run build && npm run test:run",
|
|
28
|
+
"version": "npm run build"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^25.2.0",
|
|
32
|
+
"@vitest/coverage-v8": "^1.2.0",
|
|
33
|
+
"tsup": "^8.5.1",
|
|
34
|
+
"typescript": "^5.9.3",
|
|
35
|
+
"vitest": "^1.2.0"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"retry",
|
|
39
|
+
"retry-logic",
|
|
40
|
+
"api-client",
|
|
41
|
+
"distributed-systems"
|
|
42
|
+
],
|
|
43
|
+
"author": "Cory Lewis",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "https://github.com/mecharmor/jitterbug.git"
|
|
48
|
+
}
|
|
49
|
+
}
|