@meistrari/data-token 0.0.11 → 0.0.12

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/dist/index.js CHANGED
@@ -1,12 +1,14 @@
1
- import { ExponentialBackoff, handleType, retry } from 'cockatiel';
2
1
  import { createRemoteJWKSet, errors, jwtVerify } from 'jose';
2
+ import { createExponentialBackoff } from './retry';
3
3
  import { DataToken } from './types';
4
- const retryJWKS = retry(handleType(errors.JWKSTimeout)
5
- .orWhen(err => err.message.includes('ECONNRESET')), { maxAttempts: 3, backoff: new ExponentialBackoff() });
4
+ const retry = createExponentialBackoff({
5
+ maxRetries: 3,
6
+ jitter: true,
7
+ });
6
8
  export function getValidator(jwksUrl, { algorithms } = { algorithms: ['RS256'] }) {
7
9
  const JWKS = createRemoteJWKSet(new URL(jwksUrl), { cacheMaxAge: 0, headers: { 'cache-control': 'no-cache', 'pragma': 'no-cache' } });
8
10
  return async (token) => {
9
- const { payload } = await retryJWKS.execute(async () => jwtVerify(token, JWKS, { algorithms }));
11
+ const { payload } = await retry(async () => jwtVerify(token, JWKS, { algorithms }), err => err instanceof errors.JWKSTimeout || (err instanceof Error && err.message.includes('ECONNRESET')));
10
12
  return DataToken.parse(payload);
11
13
  };
12
14
  }
@@ -0,0 +1,34 @@
1
+ type BackoffOptions = {
2
+ /**
3
+ * Maximum number of retry attempts
4
+ * @default 5
5
+ */
6
+ maxRetries?: number;
7
+ /**
8
+ * Initial delay in milliseconds
9
+ * @default 1000 (1 second)
10
+ */
11
+ baseDelay?: number;
12
+ /**
13
+ * Multiplier for exponential backoff
14
+ * @default 2
15
+ */
16
+ factor?: number;
17
+ /**
18
+ * Maximum delay cap in milliseconds
19
+ * @default 30000 (30 seconds)
20
+ */
21
+ maxDelay?: number;
22
+ /**
23
+ * Jitter to prevent synchronized retries in distributed systems
24
+ * @default true
25
+ */
26
+ jitter?: boolean;
27
+ };
28
+ /**
29
+ * Create an exponential backoff retry function
30
+ * @param userOptions Configuration options for backoff strategy
31
+ * @returns Retry function with exponential backoff
32
+ */
33
+ declare function createExponentialBackoff(userOptions?: BackoffOptions): <T>(fn: () => Promise<T>, errorFilter?: (error: unknown) => boolean) => Promise<T>;
34
+ export { createExponentialBackoff };
package/dist/retry.js ADDED
@@ -0,0 +1,65 @@
1
+ const sleep = async (ms) => new Promise(resolve => setTimeout(resolve, ms));
2
+ /**
3
+ * Calculate delay for a specific retry attempt
4
+ * @param options Backoff configuration options
5
+ * @param attempt Current retry attempt (0-indexed)
6
+ * @returns Calculated delay in milliseconds
7
+ */
8
+ function calculateDelay(options, attempt) {
9
+ // Basic exponential backoff calculation
10
+ let delay = options.baseDelay * options.factor ** attempt;
11
+ // Cap the delay at maxDelay
12
+ delay = Math.min(delay, options.maxDelay);
13
+ // Apply jitter if enabled
14
+ if (options.jitter) {
15
+ // Add random variation between 0.5x and 1.5x of the calculated delay
16
+ const jitterMultiplier = 0.5 + Math.random();
17
+ delay *= jitterMultiplier;
18
+ }
19
+ return Math.round(delay);
20
+ }
21
+ /**
22
+ * Create an exponential backoff retry function
23
+ * @param userOptions Configuration options for backoff strategy
24
+ * @returns Retry function with exponential backoff
25
+ */
26
+ function createExponentialBackoff(userOptions = {}) {
27
+ // Merge default options with user-provided options
28
+ const options = {
29
+ maxRetries: 5,
30
+ baseDelay: 1000,
31
+ factor: 2,
32
+ maxDelay: 30000,
33
+ jitter: true,
34
+ ...userOptions,
35
+ };
36
+ /**
37
+ * Execute a function with exponential backoff retry strategy
38
+ * @param fn Function to execute
39
+ * @param errorFilter Optional function to determine if retry is needed
40
+ * @returns Promise resolving to the result of the function
41
+ */
42
+ return async function executeWithBackoff(fn, errorFilter) {
43
+ let lastError;
44
+ for (let attempt = 0; attempt <= options.maxRetries; attempt++) {
45
+ try {
46
+ return await fn();
47
+ }
48
+ catch (error) {
49
+ // If no error filter is provided, or the error passes the filter
50
+ const shouldRetry = errorFilter
51
+ ? errorFilter(error)
52
+ : attempt < options.maxRetries;
53
+ if (!shouldRetry) {
54
+ throw error;
55
+ }
56
+ lastError = error;
57
+ // Calculate and apply delay
58
+ const delay = calculateDelay(options, attempt);
59
+ await sleep(delay);
60
+ }
61
+ }
62
+ throw lastError;
63
+ };
64
+ }
65
+ export { createExponentialBackoff };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meistrari/data-token",
3
3
  "type": "module",
4
- "version": "0.0.11",
4
+ "version": "0.0.12",
5
5
  "description": "Internal library to verify and decode the API Gateway data token",
6
6
  "author": "Roz <roz@meistrari.com>",
7
7
  "license": "UNLICENSED",