UNPKG

curl-runner-core

Version:

Core library for running cURL scripts with comprehensive logging, error handling, and parallel execution capabilities. Zero external dependencies for maximum security.

3 lines (2 loc) โ€ข 22.9 kB
import e from"fs";import t from"path";import{exec as r}from"child_process";const o="18.0.0",s="22.0.0",n="24.9.9",i="22.0.0",l="24.9.9",c="@curl-runner/core",a={UNSUPPORTED_VERSION:"Unsupported Node.js version",RECOMMENDED_VERSION:"Recommended Node.js version"};function g(e){const t=e.replace(/^v/,"").split(".").map(Number);return{major:t[0]||0,minor:t[1]||0,patch:t[2]||0,original:e}}function u(e,t){return e.major!==t.major?e.major-t.major:e.minor!==t.minor?e.minor-t.minor:e.patch-t.patch}function p(e,t,r){const o=g(t),s=g(r),n=u(e,o)>=0,i=u(e,s)<=0;return{isCompatible:n&&i,isMinCompatible:n,isMaxCompatible:i,minVersion:t,maxVersion:r}}function R(){const e=g(process.version),t=s,r=n,c=i,a=l,u=p(e,o,"999.999.999"),R=p(e,t,r),E=p(e,c,a);return{currentVersion:e.original,minCompatibility:u,recommendedCompatibility:R,testedCompatibility:E,isSupported:u.isCompatible,isRecommended:R.isCompatible,isTested:E.isCompatible}}function E(e){const{currentVersion:t,minCompatibility:r,recommendedCompatibility:o,testedCompatibility:s}=e,n=c;let i=`\nโŒ ${a.UNSUPPORTED_VERSION}\n\n`;return i+=`๐Ÿ“ฆ Library: ${n}\n`,i+=`๐Ÿ”ง Current Node.js: ${t}\n`,i+=`๐Ÿ“‹ Required: >=${r.minVersion}\n\n`,r.isCompatible||(i+=`โŒ Your Node.js version (${t}) is below the minimum required version (${r.minVersion}).\n`,i+=` Please upgrade Node.js to continue using ${n}.\n\n`),r.isCompatible&&!o.isCompatible&&(i+=`โš ๏ธ Your Node.js version (${t}) is supported but not recommended.\n`,i+=` Recommended range: ${o.minVersion} - ${o.maxVersion}\n`,i+=" For best performance and security, consider upgrading.\n\n"),r.isCompatible&&o.isCompatible&&!s.isCompatible&&(i+=`โš ๏ธ Your Node.js version (${t}) is supported but not fully tested.\n`,i+=` Tested range: ${s.minVersion} - ${s.maxVersion}\n`,i+=" The library should work, but some features may not be optimized.\n\n"),i+="๐Ÿ”— For more information, visit: https://github.com/Grant-Steinfeld/cURL_runner\n",i+="๐Ÿ“š Compatibility guide: https://github.com/Grant-Steinfeld/cURL_runner/blob/main/lib/VERSION_COMPATIBILITY.md\n",i}function h(e={}){const{strict:t=!1,warn:r=!0}=e,o=R();if(!o.isSupported){const e=E(o);throw new Error(e)}if(r&&!o.isRecommended){const e=function(e){const{currentVersion:t,recommendedCompatibility:r,testedCompatibility:o}=e,s=c;let n=`\nโš ๏ธ ${a.RECOMMENDED_VERSION}\n\n`;return n+=`๐Ÿ“ฆ Library: ${s}\n`,n+=`๐Ÿ”ง Current Node.js: ${t}\n\n`,r.isCompatible||(n+=`๐Ÿ“‹ Recommended range: ${r.minVersion} - ${r.maxVersion}\n`,n+=" For optimal performance and security, consider upgrading.\n\n"),o.isCompatible||(n+=`๐Ÿงช Tested range: ${o.minVersion} - ${o.maxVersion}\n`,n+=" The library should work, but some features may not be optimized.\n\n"),n+="๐Ÿ”— Compatibility guide: https://github.com/Grant-Steinfeld/cURL_runner/blob/main/lib/VERSION_COMPATIBILITY.md\n",n}(o);console.warn(e)}if(t&&!o.isTested){const e=E(o);throw new Error(e)}return o}function S(){return R()}function m(){return R().isTested}function d(){return R().isRecommended}function L(){const e=R();return{current:e.currentVersion,minimum:o,recommended:{min:s,max:n},tested:{min:i,max:l},status:{isSupported:e.isSupported,isRecommended:e.isRecommended,isTested:e.isTested}}}class ${constructor(e){this.logsDir=e,this.reportLogFile="curl-runner-report.log",this.errorLogFile="curl-api-errors.log"}ensureLogsDirectory(){e.existsSync(this.logsDir)||e.mkdirSync(this.logsDir,{recursive:!0})}generateLogFilename(e=null){const t=(new Date).toISOString().replace(/[:.]/g,"-").slice(0,-5);if(e){return`${e.replace(".sh","").replace(/[^a-zA-Z0-9-_]/g,"_")}_${t}.log`}return`run_${t}.log`}writeLog(r,o){const s=t.join(this.logsDir,r),n=`[${(new Date).toISOString()}] ${o}\n`;try{e.appendFileSync(s,n)}catch(e){console.error(`[ERROR] Error writing to log file: ${e.message}`)}}writeReportLog(r){const o=t.join(this.logsDir,this.reportLogFile),s=`[${(new Date).toISOString()}] ${r}\n`;try{e.appendFileSync(o,s)}catch(e){console.error(`[ERROR] Error writing to report log: ${e.message}`)}}writeErrorLog(r,o,s=null,n=null){const i=t.join(this.logsDir,this.errorLogFile),l=(new Date).toISOString();let c=`[${l}] โŒ API ERROR: ${r}`;s&&(c+=` (HTTP ${s})`),n&&(c+=` (${n}ms)`),c+="\n",c+=`[${l}] Error: ${o}\n`,c+=`[${l}] โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n`;try{e.appendFileSync(i,c)}catch(e){console.error(`[ERROR] Error writing to error log: ${e.message}`)}}}class T{static parseCurlOutput(e,t){const r=e.match(/HTTP Status: (\d+)/),o=r?parseInt(r[1]):null,s=o&&o>=400;return{httpStatus:o,isApiError:s,errorMessage:t||(s?`HTTP ${o} error`:null)}}static extractHttpStatus(e){const t=[/HTTP Status: (\d+)/,/HTTP\/\d\.\d (\d+)/,/HTTPSTATUS:(\d+)/,/Status: (\d+)/];for(const r of t){const t=e.match(r);if(t)return parseInt(t[1])}return null}static isHttpError(e){return e&&e>=400}static getErrorCategory(e){return e?e>=500?"server_error":e>=400?"client_error":e>=300?"redirection":e>=200?"success":"unknown":"unknown"}}class O{static scanScripts(t){try{if(!e.existsSync(t)){console.log(`[WARNING] Directory ${t} does not exist. Creating it...`);try{e.mkdirSync(t,{recursive:!0}),console.log(`[SUCCESS] Created directory: ${t}`)}catch(e){return console.error(`[ERROR] Failed to create directory ${t}: ${e.message}`),console.log("[INFO] Please create the directory manually or check permissions."),[]}return[]}const r=e.readdirSync(t).filter(e=>e.endsWith(".sh"));return 0===r.length?(console.log(`[WARNING] No .sh files found in ${t}`),console.log("[INFO] Add some .sh files to get started!")):(console.log(`[INFO] Found ${r.length} .sh files in ${t}:`),r.forEach((e,t)=>{console.log(` ${t+1}. ${e}`)})),r}catch(e){return console.error(`[ERROR] Error scanning directory ${t}: ${e.message}`),"EACCES"===e.code?console.log("[INFO] Permission denied. Please check directory permissions."):"ENOENT"===e.code&&console.log(`[INFO] Directory not found. Please create ${t} manually.`),[]}}static fileExists(t){return e.existsSync(t)}static ensureDirectory(t){return!e.existsSync(t)&&(e.mkdirSync(t,{recursive:!0}),!0)}static getFileExtension(e){return t.extname(e)}static joinPath(...e){return t.join(...e)}static getDirName(e){return t.dirname(e)}static getBaseName(e){return t.basename(e)}}const _={SCRIPTS_DIR:"./cURL_scripts",LOGS_DIR:"./var/logs",REPORT_LOG_FILE:"curl-runner-report.log",ERROR_LOG_FILE:"curl-api-errors.log",APP_NAME:"curl-runner",APP_VERSION:"1.3.3",APP_DESCRIPTION:"Run cURL scripts from .sh files for data gap analysis and reporting",SCRIPT_DELAY_MS:100,TIMEOUT_MS:3e4,PARALLEL_ENABLED:!1,PARALLEL_BATCH_SIZE:5,PARALLEL_MAX_CONCURRENT:10,PARALLEL_DELAY_BETWEEN_BATCHES:200,WEEKLY_REPORTING:{ENABLED:!0,DEFAULT_WEEKS:52,MIN_WEEKS:1,MAX_WEEKS:104,REPORT_DIR:"./var/reports",WEEKLY_REPORT_FILE:"weekly-data-gap-report.json",SUMMARY_REPORT_FILE:"data-gap-summary.json"},DATA_GAP_ANALYSIS:{ENABLED:!0,MISSING_DATA_THRESHOLD:.1,ERROR_RATE_THRESHOLD:.05,SUCCESS_RATE_THRESHOLD:.95,TREND_ANALYSIS_WEEKS:4,ALERT_ON_GAPS:!0,ALERT_ON_ERRORS:!0},HTTP_SUCCESS_MIN:200,HTTP_SUCCESS_MAX:299,HTTP_CLIENT_ERROR_MIN:400,HTTP_CLIENT_ERROR_MAX:499,HTTP_SERVER_ERROR_MIN:500,HTTP_SERVER_ERROR_MAX:599,SCRIPT_EXTENSION:".sh",LOG_TIMESTAMP_FORMAT:"ISO",LOG_ENTRY_PREFIX:"[{timestamp}]",CLI_OPTIONS:{dir:{short:"-d",long:"--dir",description:"Scripts directory",default:"./cURL_scripts"},logs:{short:"-l",long:"--logs",description:"Logs directory",default:"./var/logs"},weeks:{short:"-w",long:"--weeks",description:"Number of weeks for reporting (default: 52)",default:52,type:"number"},reports:{short:"-r",long:"--reports",description:"Reports directory",default:"./var/reports"},"data-gap-analysis":{short:"-g",long:"--data-gap-analysis",description:"Enable data gap analysis",default:!0,type:"boolean"}}};class A{constructor(e=_.SCRIPTS_DIR,t=_.LOGS_DIR){this.scriptsDir=e,this.logsDir=t,this.logger=new $(t),this.ensureLogsDirectory()}ensureLogsDirectory(){this.logger.ensureLogsDirectory()}generateLogFilename(e=null){return this.logger.generateLogFilename(e)}writeLog(e,t){this.logger.writeLog(e,t)}writeReportLog(e){this.logger.writeReportLog(e)}writeErrorLog(e,t,r=null,o=null){this.logger.writeErrorLog(e,t,r,o)}parseCurlOutput(e,t){return T.parseCurlOutput(e,t)}scanScripts(){return O.scanScripts(this.scriptsDir)}async runScript(e,t=null){const o=O.joinPath(this.scriptsDir,e);if(!O.fileExists(o)){const r=`Script ${e} not found in ${this.scriptsDir}`;return console.error(`[ERROR] ${r}`),t&&this.writeLog(t,`ERROR: ${r}`),{success:!1,output:"",httpStatus:null,error:r,duration:0,parsed:{httpStatus:null,isApiError:!1,errorMessage:r}}}return console.log(`\n[RUNNING] ${e}`),console.log("โ”€".repeat(50)),t&&this.writeLog(t,`Starting execution of script: ${e}`),new Promise(s=>{const n=Date.now();r(`bash "${o}"`,(r,o,i)=>{const l=Date.now()-n;if(r){const n=`Error executing ${e}: ${r.message}`;return console.error(`[FAILED] ${n}`),console.error(`[ERROR] ${r.message}`),i&&console.error("[STDERR]",i),t&&(this.writeLog(t,`ERROR: ${n}`),i&&this.writeLog(t,`STDERR: ${i}`)),this.writeReportLog(`โŒ FAILED: ${e} (${l}ms) - ${r.message}`),this.writeErrorLog(e,r.message,null,l),void s({success:!1,output:o||"",httpStatus:null,error:r.message,duration:l,parsed:{httpStatus:null,isApiError:!1,errorMessage:r.message}})}const{httpStatus:c,isApiError:a,errorMessage:g}=this.parseCurlOutput(o,i);if(a){const r=`API Error: HTTP ${c}`;return console.error(`[API_ERROR] ${e}: ${r}`),t&&this.writeLog(t,`API ERROR: ${r}`),this.writeReportLog(`โŒ API ERROR: ${e} (${l}ms) - HTTP ${c}`),this.writeErrorLog(e,g||r,c,l),void s({success:!1,output:o||"",httpStatus:c,error:g||r,duration:l,parsed:{httpStatus:c,isApiError:a,errorMessage:g||r}})}const u=`${e} completed successfully in ${l}ms`;console.log(`[SUCCESS] ${u}`),console.log(`[DURATION] ${l}ms`),t&&this.writeLog(t,`SUCCESS: ${u}`),this.writeReportLog(`โœ… SUCCESS: ${e} (${l}ms)`),o&&(console.log("\n[OUTPUT]"),console.log(o),t&&this.writeLog(t,`OUTPUT: ${o.trim()}`)),s({success:!0,output:o,httpStatus:c,error:null,duration:l,parsed:{httpStatus:c,isApiError:a,errorMessage:g}})})})}async runAllScripts(){const e=this.scanScripts();if(0===e.length)return console.log("[WARNING] No .sh files found to run."),[];const t=this.generateLogFilename();console.log(`\n[BATCH] Running ${e.length} script(s)...`),console.log(`[LOG] Logging to: ${t}`),console.log(`[LOG] Report log: ${_.REPORT_LOG_FILE}`),console.log(`[LOG] Error log: ${_.ERROR_LOG_FILE}`),this.writeLog(t,`Starting batch execution of ${e.length} scripts`),this.writeLog(t,`Scripts to run: ${e.join(", ")}`),this.writeReportLog(`๐Ÿš€ BATCH START: Running ${e.length} scripts`);let r=0,o=0;const s=[];for(const n of e){const e=await this.runScript(n,t);s.push(e),e.success?r++:o++,await new Promise(e=>setTimeout(e,_.SCRIPT_DELAY_MS))}const n=`Batch execution completed: ${r} successful, ${o} failed, ${e.length} total`;return console.log("\n"+"โ”€".repeat(50)),console.log("[SUMMARY]"),console.log(` [SUCCESS] ${r}`),console.log(` [FAILED] ${o}`),console.log(` [TOTAL] ${e.length}`),console.log(`[LOG] Log saved to: ${t}`),console.log(`[LOG] Report log: ${_.REPORT_LOG_FILE}`),console.log(`[LOG] Error log: ${_.ERROR_LOG_FILE}`),this.writeLog(t,n),this.writeReportLog(`๐Ÿ BATCH COMPLETE: ${r}/${e.length} successful (${o} failed)`),s}async runSpecificScript(e){e.endsWith(_.SCRIPT_EXTENSION)||(e+=_.SCRIPT_EXTENSION);const t=this.generateLogFilename(e);console.log(`๐Ÿ“ Logging to: ${t}`),console.log(`๐Ÿ“Š Report log: ${_.REPORT_LOG_FILE}`),console.log(`๐Ÿšจ Error log: ${_.ERROR_LOG_FILE}`),this.writeReportLog(`๐ŸŽฏ SINGLE SCRIPT: Starting ${e}`);const r=await this.runScript(e,t);return r&&(console.log(`๐Ÿ“ Log saved to: ${t}`),console.log(`๐Ÿ“Š Report log: ${_.REPORT_LOG_FILE}`),console.log(`๐Ÿšจ Error log: ${_.ERROR_LOG_FILE}`)),r}async runAllScriptsParallel(){const e=this.scanScripts();if(0===e.length)return console.log("[WARNING] No .sh files found to run."),[];const t=this.generateLogFilename();console.log(`\n[PARALLEL] Running ${e.length} script(s) in parallel...`),console.log(`[LOG] Logging to: ${t}`),console.log(`[LOG] Report log: ${_.REPORT_LOG_FILE}`),console.log(`[LOG] Error log: ${_.ERROR_LOG_FILE}`),this.writeLog(t,`Starting parallel execution of ${e.length} scripts`),this.writeLog(t,`Scripts to run: ${e.join(", ")}`),this.writeReportLog(`๐Ÿš€ PARALLEL START: Running ${e.length} scripts`);const r=Date.now(),o=await Promise.all(e.map(e=>this.runScript(e,t))),s=Date.now()-r,n=o.filter(e=>e.success).length,i=o.filter(e=>!e.success).length,l=`Parallel execution completed: ${n} successful, ${i} failed, ${e.length} total in ${s}ms`;return console.log("\n"+"โ”€".repeat(50)),console.log("[PARALLEL SUMMARY]"),console.log(` [SUCCESS] ${n}`),console.log(` [FAILED] ${i}`),console.log(` [TOTAL] ${e.length}`),console.log(` [DURATION] ${s}ms`),console.log(`[LOG] Log saved to: ${t}`),console.log(`[LOG] Report log: ${_.REPORT_LOG_FILE}`),console.log(`[LOG] Error log: ${_.ERROR_LOG_FILE}`),this.writeLog(t,l),this.writeReportLog(`๐Ÿ PARALLEL COMPLETE: ${n}/${e.length} successful (${i} failed) in ${s}ms`),o}async runAllScriptsConcurrent(e={}){const t=this.scanScripts();if(0===t.length)return console.log("[WARNING] No .sh files found to run."),[];const r=e.batchSize||_.PARALLEL_BATCH_SIZE,o=e.delayBetweenBatches||_.PARALLEL_DELAY_BETWEEN_BATCHES,s=this.generateLogFilename();console.log(`\n[CONCURRENT] Running ${t.length} script(s) in batches of ${r}...`),console.log(`[LOG] Logging to: ${s}`),console.log(`[LOG] Report log: ${_.REPORT_LOG_FILE}`),console.log(`[LOG] Error log: ${_.ERROR_LOG_FILE}`),this.writeLog(s,`Starting concurrent execution of ${t.length} scripts in batches of ${r}`),this.writeLog(s,`Scripts to run: ${t.join(", ")}`),this.writeReportLog(`๐Ÿš€ CONCURRENT START: Running ${t.length} scripts in batches of ${r}`);const n=Date.now(),i=[];let l=0,c=0;for(let e=0;e<t.length;e+=r){const n=t.slice(e,e+r),a=Math.floor(e/r)+1,g=Math.ceil(t.length/r);console.log(`\n[BATCH ${a}/${g}] Running ${n.length} scripts...`),this.writeLog(s,`Starting batch ${a}/${g} with scripts: ${n.join(", ")}`);const u=Date.now(),p=await Promise.all(n.map(e=>this.runScript(e,s))),R=Date.now()-u;i.push(...p);const E=p.filter(e=>e.success).length,h=p.filter(e=>!e.success).length;l+=E,c+=h,console.log(`[BATCH ${a} COMPLETE] ${E} successful, ${h} failed in ${R}ms`),this.writeLog(s,`Batch ${a} completed: ${E} successful, ${h} failed in ${R}ms`),e+r<t.length&&o>0&&(console.log(`[DELAY] Waiting ${o}ms before next batch...`),await new Promise(e=>setTimeout(e,o)))}const a=Date.now()-n,g=`Concurrent execution completed: ${l} successful, ${c} failed, ${t.length} total in ${a}ms`;return console.log("\n"+"โ”€".repeat(50)),console.log("[CONCURRENT SUMMARY]"),console.log(` [SUCCESS] ${l}`),console.log(` [FAILED] ${c}`),console.log(` [TOTAL] ${t.length}`),console.log(` [DURATION] ${a}ms`),console.log(` [BATCHES] ${Math.ceil(t.length/r)}`),console.log(`[LOG] Log saved to: ${s}`),console.log(`[LOG] Report log: ${_.REPORT_LOG_FILE}`),console.log(`[LOG] Error log: ${_.ERROR_LOG_FILE}`),this.writeLog(s,g),this.writeReportLog(`๐Ÿ CONCURRENT COMPLETE: ${l}/${t.length} successful (${c} failed) in ${a}ms across ${Math.ceil(t.length/r)} batches`),i}async runScriptsWithConcurrency(e,t=_.PARALLEL_MAX_CONCURRENT){if(!Array.isArray(e))throw new Error("Scripts must be an array");if(0===e.length)return console.log("[WARNING] No scripts provided to run."),[];const r=this.generateLogFilename();console.log(`\n[CONCURRENCY] Running ${e.length} script(s) with max ${t} concurrent...`),console.log(`[LOG] Logging to: ${r}`),this.writeLog(r,`Starting concurrency-controlled execution of ${e.length} scripts (max ${t} concurrent)`),this.writeLog(r,`Scripts to run: ${e.join(", ")}`),this.writeReportLog(`๐Ÿš€ CONCURRENCY START: Running ${e.length} scripts (max ${t} concurrent)`);const o=Date.now(),s=[];for(let o=0;o<e.length;o+=t){const n=e.slice(o,o+t),i=Math.floor(o/t)+1,l=Math.ceil(e.length/t);console.log(`\n[CONCURRENT BATCH ${i}/${l}] Running ${n.length} scripts...`),this.writeLog(r,`Starting concurrent batch ${i}/${l} with scripts: ${n.join(", ")}`);const c=await Promise.all(n.map(e=>this.runScript(e,r)));s.push(...c);const a=c.filter(e=>e.success).length,g=c.filter(e=>!e.success).length;console.log(`[BATCH ${i} COMPLETE] ${a} successful, ${g} failed`),this.writeLog(r,`Concurrent batch ${i} completed: ${a} successful, ${g} failed`)}const n=Date.now()-o,i=s.filter(e=>e.success).length,l=s.filter(e=>!e.success).length,c=`Concurrency-controlled execution completed: ${i} successful, ${l} failed, ${e.length} total in ${n}ms`;return console.log("\n"+"โ”€".repeat(50)),console.log("[CONCURRENCY SUMMARY]"),console.log(` [SUCCESS] ${i}`),console.log(` [FAILED] ${l}`),console.log(` [TOTAL] ${e.length}`),console.log(` [DURATION] ${n}ms`),console.log(` [MAX CONCURRENT] ${t}`),this.writeLog(r,c),this.writeReportLog(`๐Ÿ CONCURRENCY COMPLETE: ${i}/${e.length} successful (${l} failed) in ${n}ms`),s}listScripts(){return this.scanScripts()}}class f{constructor(e=_.WEEKLY_REPORTING.REPORT_DIR,t=_.WEEKLY_REPORTING.DEFAULT_WEEKS){this.reportsDir=e,this.weeks=Math.max(_.WEEKLY_REPORTING.MIN_WEEKS,Math.min(t,_.WEEKLY_REPORTING.MAX_WEEKS)),this.ensureReportsDirectory()}ensureReportsDirectory(){e.existsSync(this.reportsDir)||(e.mkdirSync(this.reportsDir,{recursive:!0}),console.log(`[INFO] Created reports directory: ${this.reportsDir}`))}generateWeeklyReportFilename(e){const t=new Date;return`weekly-report-${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}-week-${e}.json`}analyzeDataGaps(e){const t={week:e.week,totalScripts:e.scripts.length,successfulScripts:0,failedScripts:0,dataGaps:[],errorRates:{},successRates:{},trends:{},alerts:[]};return e.scripts.forEach(e=>{const r=e.results.filter(e=>e.success).length,o=e.results.length,s=o>0?r/o:0,n=1-s;t.successRates[e.name]=s,t.errorRates[e.name]=n,s>=_.DATA_GAP_ANALYSIS.SUCCESS_RATE_THRESHOLD?t.successfulScripts++:t.failedScripts++,s<_.DATA_GAP_ANALYSIS.SUCCESS_RATE_THRESHOLD&&t.dataGaps.push({script:e.name,successRate:s,missingData:1-s,severity:s<.5?"critical":s<.8?"high":"medium"}),n>_.DATA_GAP_ANALYSIS.ERROR_RATE_THRESHOLD&&t.alerts.push({type:"error_rate",script:e.name,errorRate:n,threshold:_.DATA_GAP_ANALYSIS.ERROR_RATE_THRESHOLD,severity:n>.2?"critical":"high"})}),t.overallSuccessRate=t.totalScripts>0?t.successfulScripts/t.totalScripts:0,t.overallErrorRate=1-t.overallSuccessRate,t.overallSuccessRate<_.DATA_GAP_ANALYSIS.SUCCESS_RATE_THRESHOLD&&t.alerts.push({type:"overall_performance",overallSuccessRate:t.overallSuccessRate,threshold:_.DATA_GAP_ANALYSIS.SUCCESS_RATE_THRESHOLD,severity:t.overallSuccessRate<.5?"critical":"high"}),t}generateWeeklyReport(e){const t=this.analyzeDataGaps(e);return{metadata:{generatedAt:(new Date).toISOString(),week:t.week,totalWeeks:this.weeks,reportVersion:"1.0.0"},summary:{totalScripts:t.totalScripts,successfulScripts:t.successfulScripts,failedScripts:t.failedScripts,overallSuccessRate:t.overallSuccessRate,overallErrorRate:t.overallErrorRate,dataGapsCount:t.dataGaps.length,alertsCount:t.alerts.length},analysis:t,recommendations:this.generateRecommendations(t)}}generateRecommendations(e){const t=[];if(e.dataGaps.length>0){const r=e.dataGaps.filter(e=>"critical"===e.severity),o=e.dataGaps.filter(e=>"high"===e.severity);r.length>0&&t.push({priority:"critical",category:"data_gaps",message:`Critical data gaps detected in ${r.length} script(s)`,scripts:r.map(e=>e.script),action:"Immediate investigation and remediation required"}),o.length>0&&t.push({priority:"high",category:"data_gaps",message:`High priority data gaps detected in ${o.length} script(s)`,scripts:o.map(e=>e.script),action:"Schedule investigation within 24 hours"})}const r=e.alerts.filter(e=>"error_rate"===e.type&&"critical"===e.severity);return r.length>0&&t.push({priority:"critical",category:"error_rates",message:`Critical error rates detected in ${r.length} script(s)`,scripts:r.map(e=>e.script),action:"Check API endpoints and script configurations immediately"}),e.overallSuccessRate<.8&&t.push({priority:"high",category:"overall_performance",message:`Overall success rate is ${(100*e.overallSuccessRate).toFixed(1)}%`,action:"Review all scripts and consider system-wide improvements"}),t}async saveWeeklyReport(r){const o=this.generateWeeklyReportFilename(r.analysis.week),s=t.join(this.reportsDir,o);try{return await e.promises.writeFile(s,JSON.stringify(r,null,2)),console.log(`[REPORT] Weekly report saved: ${s}`),s}catch(e){throw console.error(`[ERROR] Failed to save weekly report: ${e.message}`),e}}generateSummaryReport(e){const t={metadata:{generatedAt:(new Date).toISOString(),totalWeeks:e.length,reportVersion:"1.0.0"},overallMetrics:{totalScripts:0,totalSuccessfulScripts:0,totalFailedScripts:0,averageSuccessRate:0,totalDataGaps:0,totalAlerts:0},weeklyBreakdown:[],trends:{successRateTrend:"stable",dataGapsTrend:"stable",errorRateTrend:"stable"},recommendations:[]};if(e.forEach(e=>{t.overallMetrics.totalScripts+=e.summary.totalScripts,t.overallMetrics.totalSuccessfulScripts+=e.summary.successfulScripts,t.overallMetrics.totalFailedScripts+=e.summary.failedScripts,t.overallMetrics.totalDataGaps+=e.summary.dataGapsCount,t.overallMetrics.totalAlerts+=e.summary.alertsCount,t.weeklyBreakdown.push({week:e.analysis.week,successRate:e.summary.overallSuccessRate,dataGapsCount:e.summary.dataGapsCount,alertsCount:e.summary.alertsCount})}),e.length>0&&(t.overallMetrics.averageSuccessRate=t.overallMetrics.totalSuccessfulScripts/t.overallMetrics.totalScripts),e.length>=2){const r=e.slice(-2),o=e.slice(-4,-2);if(r.length>=2&&o.length>=2){const e=r.reduce((e,t)=>e+t.summary.overallSuccessRate,0)/r.length,s=o.reduce((e,t)=>e+t.summary.overallSuccessRate,0)/o.length;e>1.05*s?t.trends.successRateTrend="improving":e<.95*s&&(t.trends.successRateTrend="declining")}}return t}async saveSummaryReport(r){const o=t.join(this.reportsDir,_.WEEKLY_REPORTING.SUMMARY_REPORT_FILE);try{return await e.promises.writeFile(o,JSON.stringify(r,null,2)),console.log(`[REPORT] Summary report saved: ${o}`),o}catch(e){throw console.error(`[ERROR] Failed to save summary report: ${e.message}`),e}}}const C={CurlResult:"CurlResult",LoggerConfig:"LoggerConfig",CurlRunnerConfig:"CurlRunnerConfig",ScriptInfo:"ScriptInfo",HttpErrorInfo:"HttpErrorInfo"};try{h({strict:!1,warn:!0})}catch(e){throw e}const y="1.3.3",I="@curl-runner/core";export{T as CurlParser,A as CurlRunner,_ as DEFAULT_CONFIG,O as FileSystem,I as LIBRARY_NAME,$ as Logger,C as Types,y as VERSION,f as WeeklyReporter,h as enforceCompatibility,S as getCompatibilityInfo,L as getCompatibilityMatrix,d as isRecommendedVersion,m as isTestedVersion}; //# sourceMappingURL=index.esm.js.map