@stacksjs/cron
Version:
3 lines (2 loc) • 17.9 kB
JavaScript
// @bun
function l(t,e,i,r,s,n,o,a){return l.fromTZ(l.tp(t,e,i,r,s,n,o),a)}l.fromTZISO=(t,e,i)=>l.fromTZ(_(t,e),i);l.fromTZ=function(t,e){let i=new Date(Date.UTC(t.y,t.m-1,t.d,t.h,t.i,t.s)),r=T(t.tz,i),s=new Date(i.getTime()-r),n=T(t.tz,s);if(n-r===0)return s;{let o=new Date(i.getTime()-n),a=T(t.tz,o);if(a-n===0)return o;if(!e&&a-n>0)return o;if(e)throw new Error("Invalid date passed to fromTZ()");return s}};l.toTZ=function(t,e){let i=t.toLocaleString("en-US",{timeZone:e}).replace(/[\u202f]/," "),r=new Date(i);return{y:r.getFullYear(),m:r.getMonth()+1,d:r.getDate(),h:r.getHours(),i:r.getMinutes(),s:r.getSeconds(),tz:e}};l.tp=(t,e,i,r,s,n,o)=>({y:t,m:e,d:i,h:r,i:s,s:n,tz:o});function T(t,e=new Date){let i=e.toLocaleString("en-US",{timeZone:t,timeZoneName:"shortOffset"}).split(" ").slice(-1)[0],r=e.toLocaleString("en-US").replace(/[\u202f]/," ");return Date.parse(`${r} GMT`)-Date.parse(`${r} ${i}`)}function _(t,e){let i=new Date(Date.parse(t));if(isNaN(i))throw new Error("minitz: Invalid ISO8601 passed to parser.");let r=t.substring(9);return t.includes("Z")||r.includes("-")||r.includes("+")?l.tp(i.getUTCFullYear(),i.getUTCMonth()+1,i.getUTCDate(),i.getUTCHours(),i.getUTCMinutes(),i.getUTCSeconds(),"Etc/UTC"):l.tp(i.getFullYear(),i.getMonth()+1,i.getDate(),i.getHours(),i.getMinutes(),i.getSeconds(),e)}l.minitz=l;var v=32,m=31|v,x=[1,2,4,8,16],C=class{pattern;timezone;second;minute;hour;day;month;dayOfWeek;lastDayOfMonth;starDOM;starDOW;constructor(t,e){this.pattern=t,this.timezone=e,this.second=Array(60).fill(0),this.minute=Array(60).fill(0),this.hour=Array(24).fill(0),this.day=Array(31).fill(0),this.month=Array(12).fill(0),this.dayOfWeek=Array(7).fill(0),this.lastDayOfMonth=!1,this.starDOM=!1,this.starDOW=!1,this.parse()}parse(){if(!(typeof this.pattern=="string"||this.pattern instanceof String))throw new TypeError("CronPattern: Pattern has to be of type string.");this.pattern.indexOf("@")>=0&&(this.pattern=this.handleNicknames(this.pattern).trim());let t=this.pattern.replace(/\s+/g," ").split(" ");if(t.length<5||t.length>6)throw new TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exactly five or six space separated parts are required.");if(t.length===5&&t.unshift("0"),t[3].indexOf("L")>=0&&(t[3]=t[3].replace("L",""),this.lastDayOfMonth=!0),t[3]=="*"&&(this.starDOM=!0),t[4].length>=3&&(t[4]=this.replaceAlphaMonths(t[4])),t[5].length>=3&&(t[5]=this.replaceAlphaDays(t[5])),t[5]=="*"&&(this.starDOW=!0),this.pattern.indexOf("?")>=0){let e=new u(new Date,this.timezone).getDate(!0);t[0]=t[0].replace("?",e.getSeconds().toString()),t[1]=t[1].replace("?",e.getMinutes().toString()),t[2]=t[2].replace("?",e.getHours().toString()),this.starDOM||(t[3]=t[3].replace("?",e.getDate().toString())),t[4]=t[4].replace("?",(e.getMonth()+1).toString()),this.starDOW||(t[5]=t[5].replace("?",e.getDay().toString()))}this.throwAtIllegalCharacters(t),this.partToArray("second",t[0],0,1),this.partToArray("minute",t[1],0,1),this.partToArray("hour",t[2],0,1),this.partToArray("day",t[3],-1,1),this.partToArray("month",t[4],-1,1),this.partToArray("dayOfWeek",t[5],0,m),this.dayOfWeek[7]&&(this.dayOfWeek[0]=this.dayOfWeek[7])}partToArray(t,e,i,r){let s=this[t],n=t==="day"&&this.lastDayOfMonth;if(e===""&&!n)throw new TypeError("CronPattern: configuration entry "+t+" ("+e+") is empty, check for trailing spaces.");if(e==="*")return s.fill(r);let o=e.split(",");if(o.length>1)for(let a=0;a<o.length;a++)this.partToArray(t,o[a],i,r);else e.indexOf("-")!==-1&&e.indexOf("/")!==-1?this.handleRangeWithStepping(e,t,i,r):e.indexOf("-")!==-1?this.handleRange(e,t,i,r):e.indexOf("/")!==-1?this.handleStepping(e,t,i,r):e!==""&&this.handleNumber(e,t,i,r)}throwAtIllegalCharacters(t){for(let e=0;e<t.length;e++)if((e===5?/[^/*0-9,\-#L]+/:/[^/*0-9,-]+/).test(t[e]))throw new TypeError("CronPattern: configuration entry "+e+" ("+t[e]+") contains illegal characters.")}handleNumber(t,e,i,r){let s=this.extractNth(t,e),n=parseInt(s[0],10)+i;if(isNaN(n))throw new TypeError("CronPattern: "+e+" is not a number: '"+t+"'");this.setPart(e,n,s[1]||r)}setPart(t,e,i){if(!Object.prototype.hasOwnProperty.call(this,t))throw new TypeError("CronPattern: Invalid part specified: "+t);if(t==="dayOfWeek"){if(e===7&&(e=0),e<0||e>6)throw new RangeError("CronPattern: Invalid value for dayOfWeek: "+e);this.setNthWeekdayOfMonth(e,i);return}if(t==="second"||t==="minute"){if(e<0||e>=60)throw new RangeError("CronPattern: Invalid value for "+t+": "+e)}else if(t==="hour"){if(e<0||e>=24)throw new RangeError("CronPattern: Invalid value for "+t+": "+e)}else if(t==="day"){if(e<0||e>=31)throw new RangeError("CronPattern: Invalid value for "+t+": "+e)}else if(t==="month"&&(e<0||e>=12))throw new RangeError("CronPattern: Invalid value for "+t+": "+e);this[t][e]=i}handleRangeWithStepping(t,e,i,r){let s=this.extractNth(t,e),n=s[0].match(/^(\d+)-(\d+)\/(\d+)$/);if(n===null)throw new TypeError("CronPattern: Syntax error, illegal range with stepping: '"+t+"'");let[,o,a,h]=n,p=parseInt(o,10)+i,f=parseInt(a,10)+i,y=parseInt(h,10);if(isNaN(p))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(f))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(isNaN(y))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(y===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(y>this[e].length)throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+this[e].length+")");if(p>f)throw new TypeError("CronPattern: From value is larger than to value: '"+t+"'");for(let w=p;w<=f;w+=y)this.setPart(e,w,s[1]||r)}extractNth(t,e){let i=t,r;if(i.includes("#")){if(e!=="dayOfWeek")throw new Error("CronPattern: nth (#) only allowed in day-of-week field");r=i.split("#")[1],i=i.split("#")[0]}return[i,r]}handleRange(t,e,i,r){let s=this.extractNth(t,e),n=s[0].split("-");if(n.length!==2)throw new TypeError("CronPattern: Syntax error, illegal range: '"+t+"'");let o=parseInt(n[0],10)+i,a=parseInt(n[1],10)+i;if(isNaN(o))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(a))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(o>a)throw new TypeError("CronPattern: From value is larger than to value: '"+t+"'");for(let h=o;h<=a;h++)this.setPart(e,h,s[1]||r)}handleStepping(t,e,i,r){let s=this.extractNth(t,e),n=s[0].split("/");if(n.length!==2)throw new TypeError("CronPattern: Syntax error, illegal stepping: '"+t+"'");n[0]===""&&(n[0]="*");let o=0;n[0]!=="*"&&(o=parseInt(n[0],10)+i);let a=parseInt(n[1],10);if(isNaN(a))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(a===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(a>this[e].length)throw new TypeError("CronPattern: Syntax error, max steps for part is ("+this[e].length+")");for(let h=o;h<this[e].length;h+=a)this.setPart(e,h,s[1]||r)}replaceAlphaDays(t){return t.replace(/-sun/gi,"-7").replace(/sun/gi,"0").replace(/mon/gi,"1").replace(/tue/gi,"2").replace(/wed/gi,"3").replace(/thu/gi,"4").replace(/fri/gi,"5").replace(/sat/gi,"6")}replaceAlphaMonths(t){return t.replace(/jan/gi,"1").replace(/feb/gi,"2").replace(/mar/gi,"3").replace(/apr/gi,"4").replace(/may/gi,"5").replace(/jun/gi,"6").replace(/jul/gi,"7").replace(/aug/gi,"8").replace(/sep/gi,"9").replace(/oct/gi,"10").replace(/nov/gi,"11").replace(/dec/gi,"12")}handleNicknames(t){let e=t.trim().toLowerCase();return e==="@yearly"||e==="@annually"?"0 0 1 1 *":e==="@monthly"?"0 0 1 * *":e==="@weekly"?"0 0 * * 0":e==="@daily"?"0 0 * * *":e==="@hourly"?"0 * * * *":t}setNthWeekdayOfMonth(t,e){if(typeof e!="number"&&e==="L")this.dayOfWeek[t]=this.dayOfWeek[t]|v;else if(e===m)this.dayOfWeek[t]=m;else if(e<6&&e>0)this.dayOfWeek[t]=this.dayOfWeek[t]|x[e-1];else throw new TypeError(`CronPattern: nth weekday out of range, should be 1-5 or L. Value: ${e}, Type: ${typeof e}`)}},D=[31,28,31,30,31,30,31,31,30,31,30,31],c=[["month","year",0],["day","month",-1],["hour","day",0],["minute","hour",0],["second","minute",0]],u=class t{tz;ms;second;minute;hour;day;month;year;constructor(e,i){if(this.tz=i,e&&e instanceof Date)if(!isNaN(e))this.fromDate(e);else throw new TypeError("CronDate: Invalid date passed to CronDate constructor");else if(e===void 0)this.fromDate(new Date);else if(e&&typeof e=="string")this.fromString(e);else if(e instanceof t)this.fromCronDate(e);else throw new TypeError("CronDate: Invalid type ("+typeof e+") passed to CronDate constructor")}isNthWeekdayOfMonth(e,i,r,s){let n=new Date(Date.UTC(e,i,r)).getUTCDay(),o=0;for(let a=1;a<=r;a++)new Date(Date.UTC(e,i,a)).getUTCDay()===n&&o++;if(s&m&&x[o-1]&s)return!0;if(s&v){let a=new Date(Date.UTC(e,i+1,0)).getUTCDate();for(let h=r+1;h<=a;h++)if(new Date(Date.UTC(e,i,h)).getUTCDay()===n)return!1;return!0}return!1}fromDate(e){if(this.tz!==void 0)if(typeof this.tz=="number")this.ms=e.getUTCMilliseconds(),this.second=e.getUTCSeconds(),this.minute=e.getUTCMinutes()+this.tz,this.hour=e.getUTCHours(),this.day=e.getUTCDate(),this.month=e.getUTCMonth(),this.year=e.getUTCFullYear(),this.apply();else{let i=l.toTZ(e,this.tz);this.ms=e.getMilliseconds(),this.second=i.s,this.minute=i.i,this.hour=i.h,this.day=i.d,this.month=i.m-1,this.year=i.y}else this.ms=e.getMilliseconds(),this.second=e.getSeconds(),this.minute=e.getMinutes(),this.hour=e.getHours(),this.day=e.getDate(),this.month=e.getMonth(),this.year=e.getFullYear()}fromCronDate(e){this.tz=e.tz,this.year=e.year,this.month=e.month,this.day=e.day,this.hour=e.hour,this.minute=e.minute,this.second=e.second,this.ms=e.ms}apply(){if(this.month>11||this.day>D[this.month]||this.hour>59||this.minute>59||this.second>59||this.hour<0||this.minute<0||this.second<0){let e=new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms));return this.ms=e.getUTCMilliseconds(),this.second=e.getUTCSeconds(),this.minute=e.getUTCMinutes(),this.hour=e.getUTCHours(),this.day=e.getUTCDate(),this.month=e.getUTCMonth(),this.year=e.getUTCFullYear(),!0}else return!1}fromString(e){if(typeof this.tz=="number"){let i=l.fromTZISO(e);this.ms=i.getUTCMilliseconds(),this.second=i.getUTCSeconds(),this.minute=i.getUTCMinutes(),this.hour=i.getUTCHours(),this.day=i.getUTCDate(),this.month=i.getUTCMonth(),this.year=i.getUTCFullYear(),this.apply()}else return this.fromDate(l.fromTZISO(e,this.tz))}findNext(e,i,r,s){let n=this[i],o;r.lastDayOfMonth&&(this.month!==1?o=D[this.month]:o=new Date(Date.UTC(this.year,this.month+1,0,0,0,0,0)).getUTCDate());let a=!r.starDOW&&i=="day"?new Date(Date.UTC(this.year,this.month,1,0,0,0,0)).getUTCDay():void 0;for(let h=this[i]+s;h<r[i].length;h++){let p=r[i][h];if(i==="day"&&r.lastDayOfMonth&&h-s==o&&(p=1),i==="day"&&!r.starDOW){let f=r.dayOfWeek[(a+(h-s-1))%7];if(f&&f&m)f=this.isNthWeekdayOfMonth(this.year,this.month,h-s,f)?1:0;else if(f)throw new Error(`CronDate: Invalid value for dayOfWeek encountered. ${f}`);e.legacyMode&&!r.starDOM?p=p||f:p=p&&f}if(p)return this[i]=h-s,n!==this[i]?2:1}return 3}recurse(e,i,r){let s=this.findNext(i,c[r][0],e,c[r][2]);if(s>1){let n=r+1;for(;n<c.length;)this[c[n][0]]=-c[n][2],n++;if(s===3)return this[c[r][1]]++,this[c[r][0]]=-c[r][2],this.apply(),this.recurse(e,i,0);if(this.apply())return this.recurse(e,i,r-1)}return r+=1,r>=c.length?this:this.year>=3000?null:this.recurse(e,i,r)}increment(e,i,r){return this.second+=i.interval!==void 0&&i.interval>1&&r?i.interval:1,this.ms=0,this.apply(),this.recurse(e,i,0)}getDate(e){return e||this.tz===void 0?new Date(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms):typeof this.tz=="number"?new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute-this.tz,this.second,this.ms)):l.fromTZ(l.tp(this.year,this.month+1,this.day,this.hour,this.minute,this.second,this.tz),!1)}getTime(){return this.getDate(!1).getTime()}};function N(t){if(t===void 0&&(t={}),delete t.name,t.legacyMode=t.legacyMode===void 0?!0:t.legacyMode,t.paused=t.paused===void 0?!1:t.paused,t.maxRuns=t.maxRuns===void 0?1/0:t.maxRuns,t.catch=t.catch===void 0?!1:t.catch,t.interval=t.interval===void 0?0:parseInt(t.interval.toString(),10),t.utcOffset=t.utcOffset===void 0?void 0:parseInt(t.utcOffset.toString(),10),t.unref=t.unref===void 0?!1:t.unref,t.startAt&&(t.startAt=new u(t.startAt,t.timezone)),t.stopAt&&(t.stopAt=new u(t.stopAt,t.timezone)),t.interval!==null){if(isNaN(t.interval))throw new Error("CronOptions: Supplied value for interval is not a number");if(t.interval<0)throw new Error("CronOptions: Supplied value for interval can not be negative")}if(t.utcOffset!==void 0){if(isNaN(t.utcOffset))throw new Error("CronOptions: Invalid value passed for utcOffset, should be number representing minutes offset from UTC.");if(t.utcOffset<-870||t.utcOffset>870)throw new Error("CronOptions: utcOffset out of bounds.");if(t.utcOffset!==void 0&&t.timezone)throw new Error("CronOptions: Combining 'utcOffset' with 'timezone' is not allowed.")}if(t.unref!==!0&&t.unref!==!1)throw new Error("CronOptions: Unref should be either true, false or undefined(false).");return t}function g(t){return Object.prototype.toString.call(t)==="[object Function]"||typeof t=="function"||t instanceof Function}function S(t){typeof Deno<"u"&&typeof Deno.unrefTimer<"u"?Deno.unrefTimer(t):t&&typeof t.unref<"u"&&t.unref()}var O=30000,d=[],M=class{name;options;_states;fn;constructor(t,e,i){let r,s;if(g(e))s=e;else if(typeof e=="object")r=e;else if(e!==void 0)throw new Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).");if(g(i))s=i;else if(typeof i=="object")r=i;else if(i!==void 0)throw new Error("Cron: Invalid argument passed for funcIn. Should be one of function, or object (options).");if(this.name=r?.name,this.options=N(r),this._states={kill:!1,blocking:!1,previousRun:void 0,currentRun:void 0,once:void 0,currentTimeout:void 0,maxRuns:r?r.maxRuns:void 0,paused:r?r.paused:!1,pattern:new C("* * * * *")},t&&(t instanceof Date||typeof t=="string"&&t.indexOf(":")>0)?this._states.once=new u(t,this.options.timezone||this.options.utcOffset):this._states.pattern=new C(t,this.options.timezone),this.name){if(d.find((n)=>n.name===this.name))throw new Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.");d.push(this)}return s!==void 0&&g(s)&&(this.fn=s,this.schedule()),this}nextRun(t){let e=this._next(t);return e?e.getDate(!1):null}nextRuns(t,e){this._states.maxRuns!==void 0&&t>this._states.maxRuns&&(t=this._states.maxRuns);let i=[],r=e||this._states.currentRun||void 0;for(;t--&&(r=this.nextRun(r));)i.push(r);return i}getPattern(){return this._states.pattern?this._states.pattern.pattern:void 0}isRunning(){let t=this.nextRun(this._states.currentRun),e=!this._states.paused,i=this.fn!==void 0,r=!this._states.kill;return e&&i&&r&&t!==null}isStopped(){return this._states.kill}isBusy(){return this._states.blocking}currentRun(){return this._states.currentRun?this._states.currentRun.getDate():null}previousRun(){return this._states.previousRun?this._states.previousRun.getDate():null}msToNext(t){t=t||new Date;let e=this._next(t);return e?t instanceof u||t instanceof Date?e.getTime()-t.getTime():e.getTime()-new u(t).getTime():null}stop(){this._states.kill=!0,this._states.currentTimeout&&clearTimeout(this._states.currentTimeout);let t=d.indexOf(this);t>=0&&d.splice(t,1)}pause(){return this._states.paused=!0,!this._states.kill}resume(){return this._states.paused=!1,!this._states.kill}schedule(t){if(t&&this.fn)throw new Error("Cron: It is not allowed to schedule two functions using the same Croner instance.");t&&(this.fn=t);let e=this.msToNext(),i=this.nextRun(this._states.currentRun);return e==null||isNaN(e)||i===null?this:(e>O&&(e=O),this._states.currentTimeout=setTimeout(()=>this._checkTrigger(i),e),this._states.currentTimeout&&this.options.unref&&S(this._states.currentTimeout),this)}async _trigger(t){if(this._states.blocking=!0,this._states.currentRun=new u(void 0,this.options.timezone||this.options.utcOffset),this.options.catch)try{this.fn!==void 0&&await this.fn(this,this.options.context)}catch(e){g(this.options.catch)&&this.options.catch(e,this)}else this.fn!==void 0&&await this.fn(this,this.options.context);this._states.previousRun=new u(t,this.options.timezone||this.options.utcOffset),this._states.blocking=!1}async trigger(){await this._trigger()}runsLeft(){return this._states.maxRuns}_checkTrigger(t){let e=new Date,i=!this._states.paused&&e.getTime()>=t.getTime(),r=this._states.blocking&&this.options.protect;i&&!r?(this._states.maxRuns!==void 0&&this._states.maxRuns--,this._trigger()):i&&r&&g(this.options.protect)&&setTimeout(()=>this.options.protect(this),0),this.schedule()}_next(t){let e=!!(t||this._states.currentRun),i=!1;!t&&this.options.startAt&&this.options.interval&&([t,e]=this._calculatePreviousRun(t,e),i=!t),t=new u(t,this.options.timezone||this.options.utcOffset),this.options.startAt&&t&&t.getTime()<this.options.startAt.getTime()&&(t=this.options.startAt);let r=this._states.once||new u(t,this.options.timezone||this.options.utcOffset);return!i&&r!==this._states.once&&(r=r.increment(this._states.pattern,this.options,e)),this._states.once&&this._states.once.getTime()<=t.getTime()||r===null||this._states.maxRuns!==void 0&&this._states.maxRuns<=0||this._states.kill||this.options.stopAt&&r.getTime()>=this.options.stopAt.getTime()?null:r}_calculatePreviousRun(t,e){let i=new u(void 0,this.options.timezone||this.options.utcOffset),r=t;if(this.options.startAt.getTime()<=i.getTime()){r=this.options.startAt;let s=r.getTime()+this.options.interval*1000;for(;s<=i.getTime();)r=new u(r,this.options.timezone||this.options.utcOffset).increment(this._states.pattern,this.options,!0),s=r.getTime()+this.options.interval*1000;e=!0}return r===null&&(r=void 0),[r,e]}};export{d as scheduledJobs,C as CronPattern,u as CronDate,M as Cron};