UNPKG

@checkfirst/nestjs-outlook

Version:

An opinionated NestJS module for Microsoft Outlook integration that provides easy access to Microsoft Graph API for emails, calendars, and more.

184 lines 7.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.delay = delay; exports.isNonRetryableError = isNonRetryableError; exports.is410Error = is410Error; exports.is429Error = is429Error; exports.is404Error = is404Error; exports.isNetworkError = isNetworkError; exports.isServerError = isServerError; exports.extractRetryAfterSeconds = extractRetryAfterSeconds; exports.retryWithBackoff = retryWithBackoff; async function delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } function isGraphErrorWithStatus(error, statusCode) { if (!error || typeof error !== 'object') { return false; } if ('statusCode' in error && typeof error.statusCode === 'number') { return error.statusCode === statusCode; } if ('stack' in error && Array.isArray(error.stack) && error.stack.length > 0) { const firstError = error.stack[0]; if (firstError && typeof firstError === 'object' && 'statusCode' in firstError) { return firstError.statusCode === statusCode; } } return false; } function isNonRetryableError(error) { return (isGraphErrorWithStatus(error, 401) || isGraphErrorWithStatus(error, 403) || isGraphErrorWithStatus(error, 404) || isGraphErrorWithStatus(error, 410)); } function is410Error(error) { return isGraphErrorWithStatus(error, 410); } function is429Error(error) { return isGraphErrorWithStatus(error, 429); } function is404Error(error) { return isGraphErrorWithStatus(error, 404); } function isNetworkError(error) { if (!error || typeof error !== 'object') { return false; } if ('code' in error) { const code = String(error.code); return code === 'ECONNABORTED' || code === 'ETIMEDOUT' || code === 'ENOTFOUND' || code === 'ECONNRESET'; } return false; } function isServerError(error) { if (!error || typeof error !== 'object') { return false; } if ('statusCode' in error && typeof error.statusCode === 'number') { return error.statusCode >= 500 && error.statusCode < 600; } if ('stack' in error && Array.isArray(error.stack) && error.stack.length > 0) { const firstError = error.stack[0]; if (firstError && typeof firstError === 'object' && 'statusCode' in firstError) { const statusCode = firstError.statusCode; return statusCode >= 500 && statusCode < 600; } } return false; } function extractRetryAfterSeconds(error) { if (!error || typeof error !== 'object') { return null; } if ('response' in error && error.response && typeof error.response === 'object') { const response = error.response; if (response.headers && 'retry-after' in response.headers) { const retryAfter = response.headers['retry-after']; if (typeof retryAfter === 'string') { const parsed = parseInt(retryAfter, 10); if (!isNaN(parsed)) { return Math.max(parsed, 5); } } else if (typeof retryAfter === 'number') { return Math.max(retryAfter, 5); } } } return null; } async function retryWithBackoff(operation, options) { var _a, _b, _c, _d; const maxRetries = (_a = options === null || options === void 0 ? void 0 : options.maxRetries) !== null && _a !== void 0 ? _a : 3; const retryDelayMs = (_b = options === null || options === void 0 ? void 0 : options.retryDelayMs) !== null && _b !== void 0 ? _b : 1000; const retryCount = (_c = options === null || options === void 0 ? void 0 : options.retryCount) !== null && _c !== void 0 ? _c : 0; const logger = options === null || options === void 0 ? void 0 : options.logger; const operationName = (_d = options === null || options === void 0 ? void 0 : options.operationName) !== null && _d !== void 0 ? _d : 'operation'; try { return await operation(); } catch (error) { const errorDetails = extractErrorInfo(error); if (isNonRetryableError(error)) { if (logger) { logger.warn(`[retryWithBackoff] Non-retryable error for ${operationName}, not retrying`, { statusCode: errorDetails.statusCode, errorCode: errorDetails.code, }); } throw error; } if (retryCount >= maxRetries) { if (logger) { logger.warn(`[retryWithBackoff] Max retries (${maxRetries}) exceeded for ${operationName}`, { statusCode: errorDetails.statusCode, errorCode: errorDetails.code, errorMessage: errorDetails.message, }); } throw error; } const delayMs = retryDelayMs * Math.pow(2, retryCount); if (logger) { logger.warn(`[retryWithBackoff] Retry ${retryCount + 1}/${maxRetries} for ${operationName} after ${delayMs}ms`, { statusCode: errorDetails.statusCode, errorCode: errorDetails.code, errorType: errorDetails.type, delayMs, }); } await delay(delayMs); return retryWithBackoff(operation, { maxRetries, retryDelayMs, retryCount: retryCount + 1, logger, operationName, }); } } function extractErrorInfo(error) { if (!error || typeof error !== 'object') { return { statusCode: 'N/A', code: 'N/A', message: String(error), type: 'unknown', }; } if ('statusCode' in error) { const statusCode = error.statusCode; const code = 'code' in error ? String(error.code) : 'N/A'; const body = 'body' in error ? String(error.body) : 'N/A'; return { statusCode, code, message: body, type: statusCode === -1 ? 'network_error' : 'graph_api_error', }; } if ('stack' in error && Array.isArray(error.stack) && error.stack.length > 0) { const firstError = error.stack[0]; if (firstError && typeof firstError === 'object') { const statusCode = 'statusCode' in firstError ? firstError.statusCode : 'N/A'; const code = 'code' in firstError ? String(firstError.code) : 'N/A'; const body = 'body' in firstError ? String(firstError.body) : 'N/A'; return { statusCode, code, message: body, type: typeof statusCode === 'number' && statusCode === -1 ? 'network_error' : 'graph_api_error', }; } } const errorMessage = error instanceof Error ? error.message : JSON.stringify(error); return { statusCode: 'N/A', code: 'N/A', message: errorMessage, type: 'generic_error', }; } //# sourceMappingURL=retry.util.js.map