hyper-scheduler 1.0.1 → 1.1.0

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.
Files changed (34) hide show
  1. package/README.md +17 -0
  2. package/dist/devtools-Bxtz0rO_.cjs +1 -0
  3. package/dist/{devtools-4xVHTaUz.js → devtools-ByJU-Gv1.js} +378 -34
  4. package/dist/index.cjs +1 -1
  5. package/dist/index.js +91 -38
  6. package/dist/index.umd.cjs +1 -1
  7. package/docs/.vitepress/cache/deps/_metadata.json +31 -0
  8. package/docs/.vitepress/cache/deps/chunk-EKBJ2FPM.js +12798 -0
  9. package/docs/.vitepress/cache/deps/chunk-EKBJ2FPM.js.map +7 -0
  10. package/docs/.vitepress/cache/deps/package.json +3 -0
  11. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4505 -0
  12. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  13. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +9731 -0
  14. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  15. package/docs/.vitepress/cache/deps/vue.js +347 -0
  16. package/docs/.vitepress/cache/deps/vue.js.map +7 -0
  17. package/docs/.vitepress/config.ts +56 -0
  18. package/docs/.vitepress/theme/components/DemoFrame.vue +111 -0
  19. package/docs/.vitepress/theme/custom.css +6 -0
  20. package/docs/.vitepress/theme/index.ts +10 -0
  21. package/docs/README.md +120 -0
  22. package/docs/api/devtools.md +245 -0
  23. package/docs/api/index.md +178 -0
  24. package/docs/api/scheduler.md +342 -0
  25. package/docs/api/task.md +439 -0
  26. package/docs/api/types.md +365 -0
  27. package/docs/examples/index.md +342 -0
  28. package/docs/guide/best-practices.md +436 -0
  29. package/docs/guide/core-concepts.md +363 -0
  30. package/docs/guide/getting-started.md +176 -0
  31. package/docs/index.md +33 -0
  32. package/docs/public/logo.svg +54 -0
  33. package/package.json +9 -6
  34. package/dist/devtools-DdQ1I25H.cjs +0 -1
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var t=Object.defineProperty,e=(e,s,i)=>((e,s,i)=>s in e?t(e,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[s]=i)(e,"symbol"!=typeof s?s+"":s,i);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s={IDLE:"idle",RUNNING:"running",STOPPED:"stopped",ERROR:"error"},i={TASK_REGISTERED:"task_registered",TASK_STARTED:"task_started",TASK_COMPLETED:"task_completed",TASK_FAILED:"task_failed",TASK_STOPPED:"task_stopped",TASK_REMOVED:"task_removed",TASK_UPDATED:"task_updated",SCHEDULER_STARTED:"scheduler_started",SCHEDULER_STOPPED:"scheduler_stopped"};class r{constructor(){e(this,"tasks"),this.tasks=new Map}addTask(t){if(this.tasks.has(t.id))throw new Error(`Task with ID "${t.id}" already exists.`);this.tasks.set(t.id,t)}getTask(t){return this.tasks.get(t)}deleteTask(t){return this.tasks.delete(t)}getAllTasks(){return Array.from(this.tasks.values())}clear(){this.tasks.clear()}}function n(t,e,s){const i=new Set;if("*"===t){for(let t=e;t<=s;t++)i.add(t);return Array.from(i).sort((t,e)=>t-e)}const r=t.split(",");for(const n of r)if(n.includes("/")){const[t,r]=n.split("/"),o=parseInt(r,10);if("*"===t)for(let n=e;n<=s;n+=o)i.add(n);else if(t.includes("-")){const[r,n]=t.split("-").map(Number);if(r<e||n>s)throw new Error(`Value out of range: ${r}-${n} (expected ${e}-${s})`);for(let t=r;t<=n;t+=o)i.add(t)}else{const r=parseInt(t,10);if(r<e||r>s)throw new Error(`Value out of range: ${r} (expected ${e}-${s})`);for(let t=r;t<=s;t+=o)i.add(t)}}else if(n.includes("-")){const[t,r]=n.split("-").map(Number);if(t<e||r>s)throw new Error(`Value out of range: ${t}-${r} (expected ${e}-${s})`);for(let e=t;e<=r;e++)i.add(e)}else{const t=parseInt(n,10);if(t<e||t>s)throw new Error(`Value out of range: ${t} (expected ${e}-${s})`);i.add(t)}return Array.from(i).sort((t,e)=>t-e)}function o(t){const e=t.trim().split(/\s+/);let s,i,r,o,a,l;if(5===e.length)s=[0],[i,r,o,a,l]=[n(e[0],0,59),n(e[1],0,23),n(e[2],1,31),n(e[3],1,12),n(e[4],0,6)];else{if(6!==e.length)throw new Error(`Invalid cron expression: expected 5 or 6 fields, got ${e.length}`);[s,i,r,o,a,l]=[n(e[0],0,59),n(e[1],0,59),n(e[2],0,23),n(e[3],1,31),n(e[4],1,12),n(e[5],0,6)]}return{second:s,minute:i,hour:r,dayOfMonth:o,month:a,dayOfWeek:l}}function a(t,e){const s=t.getSeconds(),i=t.getMinutes(),r=t.getHours(),n=t.getDate(),o=t.getMonth()+1,a=t.getDay();return e.second.includes(s)&&e.minute.includes(i)&&e.hour.includes(r)&&e.month.includes(o)&&(e.dayOfMonth.includes(n)||e.dayOfWeek.includes(a))}function l(t){const e=t.match(/^(\d+)(s|m|h|d)$/);if(e){const t=parseInt(e[1],10);let s=1e3;switch(e[2]){case"s":s=1e3;break;case"m":s=6e4;break;case"h":s=36e5;break;case"d":s=864e5}return{type:"interval",value:t*s}}try{return function(t){try{o(t)}catch(e){throw new Error(`Invalid cron expression: ${t}`)}}(t),{type:"cron",value:t}}catch(s){throw new Error(`无效的调度格式: "${t}". 必须是有效的 Cron 表达式或间隔字符串 (例如 "10s")。`)}}function c(t,e){let s;if(s="string"==typeof t?l(t):t,"interval"===s.type){const t=s.value,i=(null==e?void 0:e.lastRun)||Date.now();return new Date(i+t)}{const t=s.value;try{return function(t){const e=o(t);let s=new Date((new Date).getTime()+1e3);s.setMilliseconds(0);let i=0;for(;i<126144e3;){if(a(s,e))return s;const t=s.getSeconds(),r=s.getMinutes(),n=s.getHours();if(!e.second.includes(t)){const n=e.second.find(e=>e>t)??e.second[0];n>t?s.setSeconds(n):s.setMinutes(r+1,n),s.setMilliseconds(0),i++;continue}if(!e.minute.includes(r)){const t=e.minute.find(t=>t>r)??e.minute[0];t>r?s.setMinutes(t,e.second[0]):s.setHours(n+1,t,e.second[0]),s.setMilliseconds(0),i++;continue}if(!e.hour.includes(n)){const t=e.hour.find(t=>t>n)??e.hour[0];t>n||s.setDate(s.getDate()+1),s.setHours(t,e.minute[0],e.second[0]),s.setMilliseconds(0),i++;continue}s=new Date(s.getTime()+1e3),i++}throw new Error(`Could not find next run time for cron expression: ${t}`)}(t,null==e||e.timezone)}catch(i){throw new Error(`无法计算下一次 Cron 运行时间: ${t}`)}}}class u{static getDelay(t,e){if(!e)return-1;const{maxAttempts:s,initialDelay:i,factor:r=2}=e;return t>=s?-1:i*Math.pow(r,t)}}let d=class{constructor(t,s={},i){e(this,"registry"),e(this,"config"),e(this,"defaultTimerStrategy"),e(this,"timerStrategyFactory"),e(this,"taskTimerStrategies"),e(this,"running"),e(this,"timers"),e(this,"listeners"),e(this,"eventListeners"),this.registry=new r,this.defaultTimerStrategy=t,this.timerStrategyFactory=i,this.taskTimerStrategies=new Map,this.config={debug:!1,maxHistory:50,...s},this.running=!1,this.timers=new Map,this.listeners=[],this.eventListeners=new Map,this.config.plugins&&Array.isArray(this.config.plugins)&&this.config.plugins.forEach(t=>{try{this.log(`Initializing plugin: ${t.name}`),t.init(this)}catch(e){console.warn(`[HyperScheduler] Failed to initialize plugin ${t.name}:`,e)}})}subscribe(t){return this.listeners.push(t),()=>{this.listeners=this.listeners.filter(e=>e!==t)}}on(t,e){return this.eventListeners.has(t)||this.eventListeners.set(t,new Set),this.eventListeners.get(t).add(e),()=>{var s;null==(s=this.eventListeners.get(t))||s.delete(e)}}emit(t,e){const s=this.eventListeners.get(t);s&&s.forEach(t=>t(e))}getTimerStrategy(t){var e;const s=null==(e=t.options)?void 0:e.driver,i=this.config.driver,r=s||i;if(!r||!this.timerStrategyFactory)return this.defaultTimerStrategy;const n=`${t.id}_${r}`;if(this.taskTimerStrategies.has(n))return this.taskTimerStrategies.get(n);const o=this.timerStrategyFactory(r);return this.taskTimerStrategies.set(n,o),o}notify(){if(this.listeners.length>0){const t=this.registry.getAllTasks();this.listeners.forEach(e=>e(t))}}createTask(t){!function(t){if(!t||"string"!=typeof t||""===t.trim())throw new Error("Task ID must be a non-empty string.")}(t.id),l(t.schedule);const e={...t,tags:t.tags||[],status:s.STOPPED,history:[],executionCount:0};this.registry.addTask(e),this.log(`Task created: ${e.id}`),this.emit(i.TASK_REGISTERED,{taskId:e.id,task:e}),this.notify(),this.running&&(e.status=s.IDLE,this.scheduleTask(e))}deleteTask(t){this.stopTask(t);const e=this.registry.deleteTask(t);return e&&(this.log(`Task deleted: ${t}`),this.emit(i.TASK_REMOVED,{taskId:t}),this.notify()),e}startTask(t){const e=this.registry.getTask(t);if(!e)throw new Error(`Task not found: ${t}`);if(e.status===s.RUNNING)return;const r=this.timers.get(t);r&&(this.getTimerStrategy(e).cancel(r),this.timers.delete(t)),e.status=s.IDLE,this.log(`Starting task: ${t}`),this.emit(i.TASK_STARTED,{taskId:t,task:e}),this.notify(),this.scheduleTaskForce(e)}scheduleTaskForce(t){var e;try{const s=c(t.schedule,{timezone:(null==(e=t.options)?void 0:e.timezone)||this.config.timezone,lastRun:t.lastRun});t.nextRun=s.getTime();const i=Date.now(),r=Math.max(0,s.getTime()-i);this.log(`Scheduling task ${t.id} for ${s.toISOString()} (in ${r}ms)`);const n=this.getTimerStrategy(t).schedule(()=>{this.executeTaskIndividual(t)},r);this.timers.set(t.id,n)}catch(i){this.log(`Error scheduling task ${t.id}: ${i}`),t.status=s.ERROR,this.notify()}}async executeTaskIndividual(t,e=0){var r,n;if(this.timers.delete(t.id),t.status===s.STOPPED)return;t.status=s.RUNNING,t.lastRun=Date.now(),t.executionCount=(t.executionCount||0)+1;const o=Date.now();this.log(`Executing task: ${t.id} (Attempt ${e})`),this.emit(i.TASK_STARTED,{taskId:t.id,task:t}),this.notify();try{await t.handler();const e=Date.now()-o;this.recordHistory(t,{timestamp:o,duration:e,success:!0}),t.status=s.IDLE,this.log(`Task execution success: ${t.id}`),this.emit(i.TASK_COMPLETED,{taskId:t.id,task:t,duration:e}),this.notify(),this.scheduleTaskForce(t)}catch(a){const c=Date.now()-o;if(this.recordHistory(t,{timestamp:o,duration:c,success:!1,error:a.message}),this.log(`Task execution failed: ${t.id} - ${a.message}`),this.emit(i.TASK_FAILED,{taskId:t.id,task:t,error:a.message,duration:c}),null==(r=t.options)?void 0:r.onError)try{t.options.onError(a,t.id)}catch(l){this.log(`onError callback failed: ${l}`)}const d=u.getDelay(e,null==(n=t.options)?void 0:n.retry);if(d>=0){this.log(`Retrying task ${t.id} in ${d}ms (Attempt ${e+1})`);const i=this.getTimerStrategy(t).schedule(()=>{this.executeTaskIndividual(t,e+1)},d);this.timers.set(t.id,i),t.status=s.ERROR,this.notify()}else t.status=s.ERROR,this.notify(),this.scheduleTaskForce(t)}}stopTask(t){const e=this.registry.getTask(t),r=this.timers.get(t);r&&e?(this.getTimerStrategy(e).cancel(r),this.timers.delete(t)):r&&(this.defaultTimerStrategy.cancel(r),this.timers.delete(t)),e&&(e.status=s.STOPPED,this.log(`Task stopped: ${t}`),this.emit(i.TASK_STOPPED,{taskId:t,task:e}),this.notify())}getTask(t){return this.registry.getTask(t)}getAllTasks(){return this.registry.getAllTasks()}isRunning(){return this.running}getTaskDriver(t){var e;const s=this.registry.getTask(t);return s?(null==(e=s.options)?void 0:e.driver)||this.config.driver||"worker":this.config.driver||"worker"}getGlobalDriver(){return this.config.driver||"worker"}async triggerTask(t){const e=this.getTask(t);if(!e)return;if(e.status===s.RUNNING)return;const r=e.status;e.status=s.RUNNING,e.lastRun=Date.now(),e.executionCount=(e.executionCount||0)+1;const n=Date.now();this.log(`Triggering task: ${e.id}`),this.emit(i.TASK_STARTED,{taskId:e.id,task:e}),this.notify();try{await e.handler();const t=Date.now()-n;this.recordHistory(e,{timestamp:n,duration:t,success:!0}),e.status=r,this.log(`Task trigger success: ${e.id}`),this.emit(i.TASK_COMPLETED,{taskId:e.id,task:e,duration:t}),this.notify()}catch(o){const t=Date.now()-n;this.recordHistory(e,{timestamp:n,duration:t,success:!1,error:o.message}),this.log(`Task trigger failed: ${e.id} - ${o.message}`),this.emit(i.TASK_FAILED,{taskId:e.id,task:e,error:o.message,duration:t}),e.status=r,this.notify()}}start(){this.running||(this.running=!0,this.log("Scheduler started"),this.emit(i.SCHEDULER_STARTED,{running:!0}),this.registry.getAllTasks().forEach(t=>{t.status===s.STOPPED&&(t.status=s.IDLE,this.emit(i.TASK_UPDATED,{taskId:t.id,task:t})),t.status!==s.RUNNING&&this.scheduleTask(t)}),this.notify())}stop(){this.running=!1,this.log("Scheduler stopped"),this.emit(i.SCHEDULER_STOPPED,{running:!1}),this.timers.forEach((t,e)=>{const s=this.registry.getTask(e);s?this.getTimerStrategy(s).cancel(t):this.defaultTimerStrategy.cancel(t)}),this.timers.clear(),this.registry.getAllTasks().forEach(t=>{t.status!==s.STOPPED&&(t.status=s.STOPPED,this.emit(i.TASK_UPDATED,{taskId:t.id,task:t}))}),this.notify()}scheduleTask(t){var e;if(this.running||t.status===s.RUNNING)try{const s=c(t.schedule,{timezone:(null==(e=t.options)?void 0:e.timezone)||this.config.timezone,lastRun:t.lastRun});t.nextRun=s.getTime();const i=Date.now(),r=Math.max(0,s.getTime()-i);this.log(`Scheduling task ${t.id} for ${s.toISOString()} (in ${r}ms)`);const n=this.getTimerStrategy(t).schedule(()=>{this.executeTask(t)},r);this.timers.set(t.id,n)}catch(i){this.log(`Error scheduling task ${t.id}: ${i}`),t.status=s.ERROR}}async executeTask(t,e=0,r=!1){var n,o;if(this.timers.delete(t.id),!(r||this.running&&t.status!==s.STOPPED))return;t.status=s.RUNNING,t.lastRun=Date.now(),t.executionCount=(t.executionCount||0)+1;const a=Date.now();this.log(`Executing task: ${t.id} (Attempt ${e})`),this.emit(i.TASK_STARTED,{taskId:t.id,task:t}),this.notify();try{await t.handler();const e=Date.now()-a;this.recordHistory(t,{timestamp:a,duration:e,success:!0}),t.status=s.IDLE,this.log(`Task execution success: ${t.id}`),this.emit(i.TASK_COMPLETED,{taskId:t.id,task:t,duration:e}),this.notify(),this.scheduleTask(t)}catch(l){const r=Date.now()-a;if(this.recordHistory(t,{timestamp:a,duration:r,success:!1,error:l.message}),this.log(`Task execution failed: ${t.id} - ${l.message}`),this.emit(i.TASK_FAILED,{taskId:t.id,task:t,error:l.message,duration:r}),null==(n=t.options)?void 0:n.onError)try{t.options.onError(l,t.id)}catch(c){this.log(`onError callback failed: ${c}`)}const d=u.getDelay(e,null==(o=t.options)?void 0:o.retry);if(d>=0){this.log(`Retrying task ${t.id} in ${d}ms (Attempt ${e+1})`);const i=this.getTimerStrategy(t).schedule(()=>{this.executeTask(t,e+1)},d);this.timers.set(t.id,i),t.status=s.ERROR,this.notify()}else t.status=s.ERROR,this.notify(),this.scheduleTask(t)}}recordHistory(t,e){t.history.unshift(e),this.config.maxHistory&&t.history.length>this.config.maxHistory&&t.history.pop()}log(t){this.config.debug&&console.log(`[HyperScheduler] ${t}`)}};class h{schedule(t,e){return setTimeout(t,e)}cancel(t){clearTimeout(t)}}const g="IWZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO2NvbnN0IGU9bmV3IE1hcDtzZWxmLm9ubWVzc2FnZT1zPT57Y29uc3R7aWQ6dCxkZWxheTpjLHR5cGU6bH09cy5kYXRhO2lmKCJzY2hlZHVsZSI9PT1sKXtjb25zdCBzPXNlbGYuc2V0VGltZW91dCgoKT0+e3NlbGYucG9zdE1lc3NhZ2Uoe2lkOnQsdHlwZToidGljayJ9KSxlLmRlbGV0ZSh0KX0sYyk7ZS5zZXQodCxzKX1lbHNlIGlmKCJjYW5jZWwiPT09bCl7Y29uc3Qgcz1lLmdldCh0KTt2b2lkIDAhPT1zJiYoc2VsZi5jbGVhclRpbWVvdXQocyksZS5kZWxldGUodCkpfX19KCk7Cg==",m="undefined"!=typeof self&&self.Blob&&new Blob([(k=g,Uint8Array.from(atob(k),t=>t.charCodeAt(0)))],{type:"text/javascript;charset=utf-8"});var k;function T(t){let e;try{if(e=m&&(self.URL||self.webkitURL).createObjectURL(m),!e)throw"";const s=new Worker(e,{name:null==t?void 0:t.name});return s.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(e)}),s}catch(s){return new Worker("data:text/javascript;base64,"+g,{name:null==t?void 0:t.name})}finally{e&&(self.URL||self.webkitURL).revokeObjectURL(e)}}class f{constructor(){e(this,"worker"),e(this,"callbacks"),e(this,"nextId"),this.worker=void 0!==T?new T:{postMessage:()=>{},onmessage:null,terminate:()=>{},addEventListener:()=>{},removeEventListener:()=>{},dispatchEvent:()=>!1},this.callbacks=new Map,this.nextId=1,this.worker.onmessage=t=>{const{id:e,type:s}=t.data;if("tick"===s){const t=this.callbacks.get(e);t&&(t(),this.callbacks.delete(e))}}}schedule(t,e){const s=this.nextId++;return this.callbacks.set(s,t),this.worker.postMessage({id:s,delay:e,type:"schedule"}),s}cancel(t){this.worker.postMessage({id:t,type:"cancel"}),this.callbacks.delete(t)}}class y{schedule(t,e){return window.setTimeout(t,e)}cancel(t){window.clearTimeout(t)}}const p="undefined"!=typeof window&&void 0!==window.document;let E=null,S=null;exports.CoreScheduler=d,exports.DevTools=class{constructor(t={}){e(this,"name","DevTools"),e(this,"options"),this.options=t}init(t){"undefined"!=typeof window&&void 0!==window.document&&this.mount(t)}async mount(t){try{await Promise.resolve().then(()=>require("./devtools-DdQ1I25H.cjs")),await customElements.whenDefined("hs-devtools"),this.setupElement(t)}catch(e){console.error("[DevTools] Failed to mount:",e)}}setupElement(t){try{let e=document.querySelector("hs-devtools");e&&e.remove(),e=document.createElement("hs-devtools");const i=this.options;console.log("[DevTools Plugin] options:",JSON.stringify(i)),i.theme&&e.setAttribute("theme",i.theme),i.dockPosition&&e.setAttribute("dock",i.dockPosition),i.language&&e.setAttribute("language",i.language),i.defaultZoom&&e.setAttribute("default-zoom",i.defaultZoom.toString()),i.trigger&&(i.trigger.backgroundColor&&e.setAttribute("trigger-bg",i.trigger.backgroundColor),i.trigger.textColor&&e.setAttribute("trigger-color",i.trigger.textColor),i.trigger.position&&e.setAttribute("trigger-position",i.trigger.position)),console.log("[DevTools Plugin] attributes set:",e.getAttribute("dock"),e.getAttribute("trigger-position")),document.body.appendChild(e),"function"==typeof e.setScheduler?e.setScheduler({getTasks:()=>t.getAllTasks().map(e=>({id:e.id,status:e.status,lastRun:e.lastRun||null,nextRun:e.nextRun||null,executionCount:e.executionCount||0,schedule:e.schedule,tags:e.tags||[],error:e.status===s.ERROR?"Execution failed":null,driver:t.getTaskDriver(e.id)})),on:(e,s)=>t.on(e,s),isRunning:()=>t.isRunning(),trigger:e=>t.triggerTask(e),pause:e=>t.stopTask(e),resume:e=>t.startTask(e),remove:e=>t.deleteTask(e)}):console.warn("[DevTools] hs-devtools element does not have setScheduler method.")}catch(e){console.error("[DevTools] Failed to setup element:",e)}}},exports.Scheduler=class extends d{constructor(t){super(function(t){if(p)return"main"===((null==t?void 0:t.driver)||"worker")?(S||(S=new y),S):(E||(E=new f),E);return new h}(t),t,function(){if(p)return t=>"main"===t?(S||(S=new y),S):(E||(E=new f),E)}())}},exports.SchedulerEvents=i,exports.TaskStatus=s;
1
+ "use strict";var t=Object.defineProperty,e=(e,s,i)=>((e,s,i)=>s in e?t(e,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[s]=i)(e,"symbol"!=typeof s?s+"":s,i);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s={IDLE:"idle",RUNNING:"running",STOPPED:"stopped",ERROR:"error"},i={TASK_REGISTERED:"task_registered",TASK_STARTED:"task_started",TASK_COMPLETED:"task_completed",TASK_FAILED:"task_failed",TASK_STOPPED:"task_stopped",TASK_REMOVED:"task_removed",TASK_UPDATED:"task_updated",SCHEDULER_STARTED:"scheduler_started",SCHEDULER_STOPPED:"scheduler_stopped"};class r{constructor(){e(this,"tasks"),e(this,"namespaceIndex"),this.tasks=new Map,this.namespaceIndex=new Map}addTask(t){var e,s;if(this.tasks.has(t.id))throw new Error(`Task with ID "${t.id}" already exists.`);this.tasks.set(t.id,t);const i=(null==(e=t.options)?void 0:e.namespace)||"default";this.namespaceIndex.has(i)||this.namespaceIndex.set(i,new Set),null==(s=this.namespaceIndex.get(i))||s.add(t.id)}getTask(t){return this.tasks.get(t)}deleteTask(t){var e,s,i;const r=this.tasks.get(t);if(!r)return!1;const n=(null==(e=r.options)?void 0:e.namespace)||"default";return null==(s=this.namespaceIndex.get(n))||s.delete(t),0===(null==(i=this.namespaceIndex.get(n))?void 0:i.size)&&this.namespaceIndex.delete(n),this.tasks.delete(t)}getAllTasks(){return Array.from(this.tasks.values())}getTasksByNamespace(t){const e=this.namespaceIndex.get(t);return e?Array.from(e).map(t=>this.tasks.get(t)).filter(Boolean):[]}clear(){this.tasks.clear(),this.namespaceIndex.clear()}}function n(t,e,s){const i=new Set;if("*"===t){for(let t=e;t<=s;t++)i.add(t);return Array.from(i).sort((t,e)=>t-e)}const r=t.split(",");for(const n of r)if(n.includes("/")){const[t,r]=n.split("/"),o=parseInt(r,10);if("*"===t)for(let n=e;n<=s;n+=o)i.add(n);else if(t.includes("-")){const[r,n]=t.split("-").map(Number);if(r<e||n>s)throw new Error(`Value out of range: ${r}-${n} (expected ${e}-${s})`);for(let t=r;t<=n;t+=o)i.add(t)}else{const r=parseInt(t,10);if(r<e||r>s)throw new Error(`Value out of range: ${r} (expected ${e}-${s})`);for(let t=r;t<=s;t+=o)i.add(t)}}else if(n.includes("-")){const[t,r]=n.split("-").map(Number);if(t<e||r>s)throw new Error(`Value out of range: ${t}-${r} (expected ${e}-${s})`);for(let e=t;e<=r;e++)i.add(e)}else{const t=parseInt(n,10);if(t<e||t>s)throw new Error(`Value out of range: ${t} (expected ${e}-${s})`);i.add(t)}return Array.from(i).sort((t,e)=>t-e)}function o(t){const e=t.trim().split(/\s+/);let s,i,r,o,a,l;if(5===e.length)s=[0],[i,r,o,a,l]=[n(e[0],0,59),n(e[1],0,23),n(e[2],1,31),n(e[3],1,12),n(e[4],0,6)];else{if(6!==e.length)throw new Error(`Invalid cron expression: expected 5 or 6 fields, got ${e.length}`);[s,i,r,o,a,l]=[n(e[0],0,59),n(e[1],0,59),n(e[2],0,23),n(e[3],1,31),n(e[4],1,12),n(e[5],0,6)]}return{second:s,minute:i,hour:r,dayOfMonth:o,month:a,dayOfWeek:l}}function a(t,e){const s=t.getSeconds(),i=t.getMinutes(),r=t.getHours(),n=t.getDate(),o=t.getMonth()+1,a=t.getDay();return e.second.includes(s)&&e.minute.includes(i)&&e.hour.includes(r)&&e.month.includes(o)&&(e.dayOfMonth.includes(n)||e.dayOfWeek.includes(a))}function l(t){const e=t.match(/^(\d+)(s|m|h|d)$/);if(e){const t=parseInt(e[1],10);let s=1e3;switch(e[2]){case"s":s=1e3;break;case"m":s=6e4;break;case"h":s=36e5;break;case"d":s=864e5}return{type:"interval",value:t*s}}try{return function(t){try{o(t)}catch(e){throw new Error(`Invalid cron expression: ${t}`)}}(t),{type:"cron",value:t}}catch(s){throw new Error(`无效的调度格式: "${t}". 必须是有效的 Cron 表达式或间隔字符串 (例如 "10s")。`)}}function c(t,e){let s;if(s="string"==typeof t?l(t):t,"interval"===s.type){const t=s.value,i=(null==e?void 0:e.lastRun)||Date.now();return new Date(i+t)}{const t=s.value;try{return function(t){var e,s,i;const r=o(t);let n=new Date((new Date).getTime()+1e3);n.setMilliseconds(0);let l=0;for(;l<126144e3;){if(a(n,r))return n;const t=n.getSeconds(),o=n.getMinutes(),c=n.getHours();if(!r.second.includes(t)){const s=null!=(e=r.second.find(e=>e>t))?e:r.second[0];s>t?n.setSeconds(s):n.setMinutes(o+1,s),n.setMilliseconds(0),l++;continue}if(!r.minute.includes(o)){const t=null!=(s=r.minute.find(t=>t>o))?s:r.minute[0];t>o?n.setMinutes(t,r.second[0]):n.setHours(c+1,t,r.second[0]),n.setMilliseconds(0),l++;continue}if(!r.hour.includes(c)){const t=null!=(i=r.hour.find(t=>t>c))?i:r.hour[0];t>c||n.setDate(n.getDate()+1),n.setHours(t,r.minute[0],r.second[0]),n.setMilliseconds(0),l++;continue}n=new Date(n.getTime()+1e3),l++}throw new Error(`Could not find next run time for cron expression: ${t}`)}(t,null==e||e.timezone)}catch(i){throw new Error(`无法计算下一次 Cron 运行时间: ${t}`)}}}class u{static getDelay(t,e){if(!e)return-1;const{maxAttempts:s,initialDelay:i,factor:r=2}=e;return t>=s?-1:i*Math.pow(r,t)}}let d=class{constructor(t,s={},i){e(this,"registry"),e(this,"config"),e(this,"defaultTimerStrategy"),e(this,"timerStrategyFactory"),e(this,"taskTimerStrategies"),e(this,"running"),e(this,"timers"),e(this,"listeners"),e(this,"eventListeners"),this.registry=new r,this.defaultTimerStrategy=t,this.timerStrategyFactory=i,this.taskTimerStrategies=new Map,this.config={debug:!1,maxHistory:50,...s},this.running=!1,this.timers=new Map,this.listeners=[],this.eventListeners=new Map,this.config.plugins&&Array.isArray(this.config.plugins)&&this.config.plugins.forEach(t=>{try{this.log(`Initializing plugin: ${t.name}`),t.init(this)}catch(e){console.warn(`[HyperScheduler] Failed to initialize plugin ${t.name}:`,e)}})}subscribe(t){return this.listeners.push(t),()=>{this.listeners=this.listeners.filter(e=>e!==t)}}on(t,e){return this.eventListeners.has(t)||this.eventListeners.set(t,new Set),this.eventListeners.get(t).add(e),()=>{var s;null==(s=this.eventListeners.get(t))||s.delete(e)}}emit(t,e){const s=this.eventListeners.get(t);s&&s.forEach(t=>t(e))}getTimerStrategy(t){var e;const s=null==(e=t.options)?void 0:e.driver,i=this.config.driver,r=s||i;if(!r||!this.timerStrategyFactory)return this.defaultTimerStrategy;const n=`${t.id}_${r}`;if(this.taskTimerStrategies.has(n))return this.taskTimerStrategies.get(n);const o=this.timerStrategyFactory(r);return this.taskTimerStrategies.set(n,o),o}notify(){if(this.listeners.length>0){const t=this.registry.getAllTasks();this.listeners.forEach(e=>e(t))}}createTask(t){var e;!function(t){if(!t||"string"!=typeof t||""===t.trim())throw new Error("Task ID must be a non-empty string.")}(t.id),l(t.schedule);const r={...t,tags:t.tags||[],status:s.STOPPED,history:[],executionCount:0};this.registry.addTask(r),this.log(`Task created: ${r.id}`),this.emit(i.TASK_REGISTERED,{taskId:r.id,task:r}),this.notify(),this.running&&(r.status=s.IDLE,(null==(e=r.options)?void 0:e.runImmediately)&&this.triggerTask(r.id),this.scheduleTask(r))}deleteTask(t){this.stopTask(t);const e=this.registry.deleteTask(t);return e&&(this.log(`Task deleted: ${t}`),this.emit(i.TASK_REMOVED,{taskId:t}),this.notify()),e}startTask(t){const e=this.registry.getTask(t);if(!e)throw new Error(`Task not found: ${t}`);if(e.status===s.RUNNING)return;const r=this.timers.get(t);r&&(this.getTimerStrategy(e).cancel(r),this.timers.delete(t)),e.status=s.IDLE,this.log(`Starting task: ${t}`),this.emit(i.TASK_STARTED,{taskId:t,task:e}),this.notify(),this.scheduleTaskForce(e)}scheduleTaskForce(t){var e;try{const s=c(t.schedule,{timezone:(null==(e=t.options)?void 0:e.timezone)||this.config.timezone,lastRun:t.lastRun});t.nextRun=s.getTime();const i=Date.now(),r=Math.max(0,s.getTime()-i);this.log(`Scheduling task ${t.id} for ${s.toISOString()} (in ${r}ms)`);const n=this.getTimerStrategy(t).schedule(()=>{this.executeTaskIndividual(t)},r);this.timers.set(t.id,n)}catch(i){this.log(`Error scheduling task ${t.id}: ${i}`),t.status=s.ERROR,this.notify()}}async executeTaskIndividual(t,e=0){var r,n;if(this.timers.delete(t.id),t.status===s.STOPPED)return;t.status=s.RUNNING,t.lastRun=Date.now(),t.executionCount=(t.executionCount||0)+1;const o=Date.now();this.log(`Executing task: ${t.id} (Attempt ${e})`),this.emit(i.TASK_STARTED,{taskId:t.id,task:t}),this.notify();try{await t.handler();const e=Date.now()-o;this.recordHistory(t,{timestamp:o,duration:e,success:!0}),t.status=s.IDLE,this.log(`Task execution success: ${t.id}`),this.emit(i.TASK_COMPLETED,{taskId:t.id,task:t,duration:e}),this.notify(),this.scheduleTaskForce(t)}catch(a){const c=Date.now()-o;if(this.recordHistory(t,{timestamp:o,duration:c,success:!1,error:a.message}),this.log(`Task execution failed: ${t.id} - ${a.message}`),this.emit(i.TASK_FAILED,{taskId:t.id,task:t,error:a.message,duration:c}),null==(r=t.options)?void 0:r.onError)try{t.options.onError(a,t.id)}catch(l){this.log(`onError callback failed: ${l}`)}const d=u.getDelay(e,null==(n=t.options)?void 0:n.retry);if(d>=0){this.log(`Retrying task ${t.id} in ${d}ms (Attempt ${e+1})`);const i=this.getTimerStrategy(t).schedule(()=>{this.executeTaskIndividual(t,e+1)},d);this.timers.set(t.id,i),t.status=s.ERROR,this.notify()}else t.status=s.ERROR,this.notify(),this.scheduleTaskForce(t)}}stopTask(t){const e=this.registry.getTask(t),r=this.timers.get(t);r&&e?(this.getTimerStrategy(e).cancel(r),this.timers.delete(t)):r&&(this.defaultTimerStrategy.cancel(r),this.timers.delete(t)),e&&(e.status=s.STOPPED,this.log(`Task stopped: ${t}`),this.emit(i.TASK_STOPPED,{taskId:t,task:e}),this.notify())}getTask(t){return this.registry.getTask(t)}getAllTasks(t){return t?this.registry.getTasksByNamespace(t):this.registry.getAllTasks()}isRunning(){return this.running}getTaskDriver(t){var e;const s=this.registry.getTask(t);return s?(null==(e=s.options)?void 0:e.driver)||this.config.driver||"worker":this.config.driver||"worker"}getGlobalDriver(){return this.config.driver||"worker"}async triggerTask(t){const e=this.getTask(t);if(!e)return;if(e.status===s.RUNNING)return;const r=e.status;e.status=s.RUNNING,e.lastRun=Date.now(),e.executionCount=(e.executionCount||0)+1;const n=Date.now();this.log(`Triggering task: ${e.id}`),this.emit(i.TASK_STARTED,{taskId:e.id,task:e}),this.notify();try{await e.handler();const t=Date.now()-n;this.recordHistory(e,{timestamp:n,duration:t,success:!0}),e.status=r,this.log(`Task trigger success: ${e.id}`),this.emit(i.TASK_COMPLETED,{taskId:e.id,task:e,duration:t}),this.notify()}catch(o){const t=Date.now()-n;this.recordHistory(e,{timestamp:n,duration:t,success:!1,error:o.message}),this.log(`Task trigger failed: ${e.id} - ${o.message}`),this.emit(i.TASK_FAILED,{taskId:e.id,task:e,error:o.message,duration:t}),e.status=r,this.notify()}}start(t){if(!t&&this.running)return;this.log(t?`Scheduler starting for scope: ${t}`:"Scheduler started"),this.emit(i.SCHEDULER_STARTED,{running:!0,scope:t});(t?this.registry.getTasksByNamespace(t):this.registry.getAllTasks()).forEach(t=>{var e;t.status===s.STOPPED&&(t.status=s.IDLE,this.emit(i.TASK_UPDATED,{taskId:t.id,task:t})),t.status!==s.RUNNING&&((null==(e=t.options)?void 0:e.runImmediately)&&this.triggerTask(t.id),this.scheduleTask(t))}),t||(this.running=!0),this.notify()}stop(t){if(!t&&!this.running)return;this.log(t?`Scheduler stopping for scope: ${t}`:"Scheduler stopped"),this.emit(i.SCHEDULER_STOPPED,{running:!1,scope:t});(t?this.registry.getTasksByNamespace(t):this.registry.getAllTasks()).forEach(t=>{const e=this.timers.get(t.id);e&&(this.getTimerStrategy(t).cancel(e),this.timers.delete(t.id)),t.status!==s.STOPPED&&(t.status=s.STOPPED,this.emit(i.TASK_UPDATED,{taskId:t.id,task:t}))}),t||(this.running=!1),this.notify()}scheduleTask(t){var e;try{const s=c(t.schedule,{timezone:(null==(e=t.options)?void 0:e.timezone)||this.config.timezone,lastRun:t.lastRun});t.nextRun=s.getTime();const i=Date.now(),r=Math.max(0,s.getTime()-i);this.log(`Scheduling task ${t.id} for ${s.toISOString()} (in ${r}ms)`);const n=this.getTimerStrategy(t).schedule(()=>{this.executeTask(t)},r);this.timers.set(t.id,n)}catch(i){this.log(`Error scheduling task ${t.id}: ${i}`),t.status=s.ERROR}}async executeTask(t,e=0,r=!1){var n,o;if(this.timers.delete(t.id),!r&&t.status===s.STOPPED)return;t.status=s.RUNNING,t.lastRun=Date.now(),t.executionCount=(t.executionCount||0)+1;const a=Date.now();this.log(`Executing task: ${t.id} (Attempt ${e})`),this.emit(i.TASK_STARTED,{taskId:t.id,task:t}),this.notify();try{await t.handler();const e=Date.now()-a;this.recordHistory(t,{timestamp:a,duration:e,success:!0}),t.status=s.IDLE,this.log(`Task execution success: ${t.id}`),this.emit(i.TASK_COMPLETED,{taskId:t.id,task:t,duration:e}),this.notify(),this.scheduleTask(t)}catch(l){const r=Date.now()-a;if(this.recordHistory(t,{timestamp:a,duration:r,success:!1,error:l.message}),this.log(`Task execution failed: ${t.id} - ${l.message}`),this.emit(i.TASK_FAILED,{taskId:t.id,task:t,error:l.message,duration:r}),null==(n=t.options)?void 0:n.onError)try{t.options.onError(l,t.id)}catch(c){this.log(`onError callback failed: ${c}`)}const d=u.getDelay(e,null==(o=t.options)?void 0:o.retry);if(d>=0){this.log(`Retrying task ${t.id} in ${d}ms (Attempt ${e+1})`);const i=this.getTimerStrategy(t).schedule(()=>{this.executeTask(t,e+1)},d);this.timers.set(t.id,i),t.status=s.ERROR,this.notify()}else t.status=s.ERROR,this.notify(),this.scheduleTask(t)}}recordHistory(t,e){t.history.unshift(e),this.config.maxHistory&&t.history.length>this.config.maxHistory&&t.history.pop()}log(t){this.config.debug&&console.log(`[HyperScheduler] ${t}`)}};class h{schedule(t,e){return setTimeout(t,e)}cancel(t){clearTimeout(t)}}const g="IWZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO2NvbnN0IGU9bmV3IE1hcDtzZWxmLm9ubWVzc2FnZT1zPT57Y29uc3R7aWQ6dCxkZWxheTpjLHR5cGU6bH09cy5kYXRhO2lmKCJzY2hlZHVsZSI9PT1sKXtjb25zdCBzPXNlbGYuc2V0VGltZW91dCgoKT0+e3NlbGYucG9zdE1lc3NhZ2Uoe2lkOnQsdHlwZToidGljayJ9KSxlLmRlbGV0ZSh0KX0sYyk7ZS5zZXQodCxzKX1lbHNlIGlmKCJjYW5jZWwiPT09bCl7Y29uc3Qgcz1lLmdldCh0KTt2b2lkIDAhPT1zJiYoc2VsZi5jbGVhclRpbWVvdXQocyksZS5kZWxldGUodCkpfX19KCk7Cg==",m="undefined"!=typeof self&&self.Blob&&new Blob([(k=g,Uint8Array.from(atob(k),t=>t.charCodeAt(0)))],{type:"text/javascript;charset=utf-8"});var k;function f(t){let e;try{if(e=m&&(self.URL||self.webkitURL).createObjectURL(m),!e)throw"";const s=new Worker(e,{name:null==t?void 0:t.name});return s.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(e)}),s}catch(s){return new Worker("data:text/javascript;base64,"+g,{name:null==t?void 0:t.name})}finally{e&&(self.URL||self.webkitURL).revokeObjectURL(e)}}class T{constructor(){e(this,"worker"),e(this,"callbacks"),e(this,"nextId"),this.worker=void 0!==f?new f:{postMessage:()=>{},onmessage:null,terminate:()=>{},addEventListener:()=>{},removeEventListener:()=>{},dispatchEvent:()=>!1},this.callbacks=new Map,this.nextId=1,this.worker.onmessage=t=>{const{id:e,type:s}=t.data;if("tick"===s){const t=this.callbacks.get(e);t&&(t(),this.callbacks.delete(e))}}}schedule(t,e){const s=this.nextId++;return this.callbacks.set(s,t),this.worker.postMessage({id:s,delay:e,type:"schedule"}),s}cancel(t){this.worker.postMessage({id:t,type:"cancel"}),this.callbacks.delete(t)}}class p{schedule(t,e){return window.setTimeout(t,e)}cancel(t){window.clearTimeout(t)}}const y="undefined"!=typeof window&&void 0!==window.document;let E=null,S=null;exports.CoreScheduler=d,exports.DevTools=class{constructor(t={}){e(this,"name","DevTools"),e(this,"options"),this.options=t}init(t){"undefined"!=typeof window&&void 0!==window.document&&this.mount(t)}async mount(t){try{await Promise.resolve().then(()=>require("./devtools-Bxtz0rO_.cjs")),await customElements.whenDefined("hs-devtools"),this.setupElement(t)}catch(e){console.error("[DevTools] Failed to mount:",e)}}setupElement(t){try{let e=document.querySelector("hs-devtools");e&&e.remove(),e=document.createElement("hs-devtools");const i=this.options;console.log("[DevTools Plugin] options:",JSON.stringify(i)),i.theme&&e.setAttribute("theme",i.theme),i.dockPosition&&e.setAttribute("dock",i.dockPosition),i.language&&e.setAttribute("language",i.language),i.defaultZoom&&e.setAttribute("default-zoom",i.defaultZoom.toString()),i.trigger&&(i.trigger.backgroundColor&&e.setAttribute("trigger-bg",i.trigger.backgroundColor),i.trigger.textColor&&e.setAttribute("trigger-color",i.trigger.textColor),i.trigger.position&&e.setAttribute("trigger-position",i.trigger.position)),console.log("[DevTools Plugin] attributes set:",e.getAttribute("dock"),e.getAttribute("trigger-position")),document.body.appendChild(e),"function"==typeof e.setScheduler?e.setScheduler({getTasks:()=>t.getAllTasks().map(e=>{var i;return{id:e.id,status:e.status,lastRun:e.lastRun||null,nextRun:e.nextRun||null,executionCount:e.executionCount||0,schedule:e.schedule,tags:e.tags||[],error:e.status===s.ERROR?"Execution failed":null,driver:t.getTaskDriver(e.id),namespace:(null==(i=e.options)?void 0:i.namespace)||"default"}}),on:(e,s)=>t.on(e,s),isRunning:()=>t.isRunning(),trigger:e=>t.triggerTask(e),pause:e=>t.stopTask(e),resume:e=>t.startTask(e),remove:e=>t.deleteTask(e)}):console.warn("[DevTools] hs-devtools element does not have setScheduler method.")}catch(e){console.error("[DevTools] Failed to setup element:",e)}}},exports.Scheduler=class extends d{constructor(t){super(function(t){if(y)return"main"===((null==t?void 0:t.driver)||"worker")?(S||(S=new p),S):(E||(E=new T),E);return new h}(t),t,function(){if(y)return t=>"main"===t?(S||(S=new p),S):(E||(E=new T),E)}())}},exports.SchedulerEvents=i,exports.TaskStatus=s;
package/dist/index.js CHANGED
@@ -19,9 +19,12 @@ const SchedulerEvents = {
19
19
  SCHEDULER_STOPPED: "scheduler_stopped"
20
20
  };
21
21
  class TaskRegistry {
22
+ // 命名空间 -> Set<任务ID>
22
23
  constructor() {
23
24
  __publicField(this, "tasks");
25
+ __publicField(this, "namespaceIndex");
24
26
  this.tasks = /* @__PURE__ */ new Map();
27
+ this.namespaceIndex = /* @__PURE__ */ new Map();
25
28
  }
26
29
  /**
27
30
  * 注册一个新任务。
@@ -29,10 +32,16 @@ class TaskRegistry {
29
32
  * @throws Error 如果 ID 已存在
30
33
  */
31
34
  addTask(task) {
35
+ var _a, _b;
32
36
  if (this.tasks.has(task.id)) {
33
37
  throw new Error(`Task with ID "${task.id}" already exists.`);
34
38
  }
35
39
  this.tasks.set(task.id, task);
40
+ const namespace = ((_a = task.options) == null ? void 0 : _a.namespace) || "default";
41
+ if (!this.namespaceIndex.has(namespace)) {
42
+ this.namespaceIndex.set(namespace, /* @__PURE__ */ new Set());
43
+ }
44
+ (_b = this.namespaceIndex.get(namespace)) == null ? void 0 : _b.add(task.id);
36
45
  }
37
46
  /**
38
47
  * 根据 ID 获取任务。
@@ -48,6 +57,16 @@ class TaskRegistry {
48
57
  * @returns 是否删除成功
49
58
  */
50
59
  deleteTask(id) {
60
+ var _a, _b, _c;
61
+ const task = this.tasks.get(id);
62
+ if (!task) {
63
+ return false;
64
+ }
65
+ const namespace = ((_a = task.options) == null ? void 0 : _a.namespace) || "default";
66
+ (_b = this.namespaceIndex.get(namespace)) == null ? void 0 : _b.delete(id);
67
+ if (((_c = this.namespaceIndex.get(namespace)) == null ? void 0 : _c.size) === 0) {
68
+ this.namespaceIndex.delete(namespace);
69
+ }
51
70
  return this.tasks.delete(id);
52
71
  }
53
72
  /**
@@ -58,10 +77,23 @@ class TaskRegistry {
58
77
  return Array.from(this.tasks.values());
59
78
  }
60
79
  /**
61
- * 清空所有任务。
80
+ * 根据命名空间获取所有任务。
81
+ * @param namespace 命名空间名称
82
+ * @returns 该命名空间下的任务数组
83
+ */
84
+ getTasksByNamespace(namespace) {
85
+ const taskIds = this.namespaceIndex.get(namespace);
86
+ if (!taskIds) {
87
+ return [];
88
+ }
89
+ return Array.from(taskIds).map((id) => this.tasks.get(id)).filter(Boolean);
90
+ }
91
+ /**
92
+ * 清空所有任务和索引。
62
93
  */
63
94
  clear() {
64
95
  this.tasks.clear();
96
+ this.namespaceIndex.clear();
65
97
  }
66
98
  }
67
99
  function validateId(id) {
@@ -164,6 +196,7 @@ function matchesCron(date, fields) {
164
196
  return fields.second.includes(second) && fields.minute.includes(minute) && fields.hour.includes(hour) && fields.month.includes(month) && (fields.dayOfMonth.includes(dayOfMonth) || fields.dayOfWeek.includes(dayOfWeek));
165
197
  }
166
198
  function getNextRun$1(expression, _timezone) {
199
+ var _a, _b, _c;
167
200
  const fields = parseCronExpression(expression);
168
201
  const now = /* @__PURE__ */ new Date();
169
202
  let candidate = new Date(now.getTime() + 1e3);
@@ -178,7 +211,7 @@ function getNextRun$1(expression, _timezone) {
178
211
  const minute = candidate.getMinutes();
179
212
  const hour = candidate.getHours();
180
213
  if (!fields.second.includes(second)) {
181
- const nextSecond = fields.second.find((s) => s > second) ?? fields.second[0];
214
+ const nextSecond = (_a = fields.second.find((s) => s > second)) != null ? _a : fields.second[0];
182
215
  if (nextSecond > second) {
183
216
  candidate.setSeconds(nextSecond);
184
217
  } else {
@@ -189,7 +222,7 @@ function getNextRun$1(expression, _timezone) {
189
222
  continue;
190
223
  }
191
224
  if (!fields.minute.includes(minute)) {
192
- const nextMinute = fields.minute.find((m) => m > minute) ?? fields.minute[0];
225
+ const nextMinute = (_b = fields.minute.find((m) => m > minute)) != null ? _b : fields.minute[0];
193
226
  if (nextMinute > minute) {
194
227
  candidate.setMinutes(nextMinute, fields.second[0]);
195
228
  } else {
@@ -200,7 +233,7 @@ function getNextRun$1(expression, _timezone) {
200
233
  continue;
201
234
  }
202
235
  if (!fields.hour.includes(hour)) {
203
- const nextHour = fields.hour.find((h) => h > hour) ?? fields.hour[0];
236
+ const nextHour = (_c = fields.hour.find((h) => h > hour)) != null ? _c : fields.hour[0];
204
237
  if (nextHour > hour) {
205
238
  candidate.setHours(nextHour, fields.minute[0], fields.second[0]);
206
239
  } else {
@@ -399,6 +432,7 @@ let Scheduler$1 = class Scheduler {
399
432
  * @param definition 任务定义
400
433
  */
401
434
  createTask(definition) {
435
+ var _a;
402
436
  validateId(definition.id);
403
437
  parseSchedule(definition.schedule);
404
438
  const task = {
@@ -415,6 +449,9 @@ let Scheduler$1 = class Scheduler {
415
449
  this.notify();
416
450
  if (this.running) {
417
451
  task.status = TaskStatus.IDLE;
452
+ if ((_a = task.options) == null ? void 0 : _a.runImmediately) {
453
+ this.triggerTask(task.id);
454
+ }
418
455
  this.scheduleTask(task);
419
456
  }
420
457
  }
@@ -572,9 +609,14 @@ let Scheduler$1 = class Scheduler {
572
609
  return this.registry.getTask(id);
573
610
  }
574
611
  /**
575
- * 获取所有任务。
612
+ * 获取所有任务,可按命名空间筛选。
613
+ * @param namespace 可选的命名空间名称
614
+ * @returns 任务数组
576
615
  */
577
- getAllTasks() {
616
+ getAllTasks(namespace) {
617
+ if (namespace) {
618
+ return this.registry.getTasksByNamespace(namespace);
619
+ }
578
620
  return this.registry.getAllTasks();
579
621
  }
580
622
  /**
@@ -646,50 +688,56 @@ let Scheduler$1 = class Scheduler {
646
688
  * 启动调度器。
647
689
  * 开始处理所有任务(除了手动停止的任务)。
648
690
  */
649
- start() {
650
- if (this.running) return;
651
- this.running = true;
652
- this.log("Scheduler started");
653
- this.emit(SchedulerEvents.SCHEDULER_STARTED, { running: true });
654
- this.registry.getAllTasks().forEach((task) => {
691
+ start(scope) {
692
+ if (!scope && this.running) return;
693
+ this.log(scope ? `Scheduler starting for scope: ${scope}` : "Scheduler started");
694
+ this.emit(SchedulerEvents.SCHEDULER_STARTED, { running: true, scope });
695
+ const tasksToStart = scope ? this.registry.getTasksByNamespace(scope) : this.registry.getAllTasks();
696
+ tasksToStart.forEach((task) => {
697
+ var _a;
655
698
  if (task.status === TaskStatus.STOPPED) {
656
699
  task.status = TaskStatus.IDLE;
657
700
  this.emit(SchedulerEvents.TASK_UPDATED, { taskId: task.id, task });
658
701
  }
659
702
  if (task.status !== TaskStatus.RUNNING) {
703
+ if ((_a = task.options) == null ? void 0 : _a.runImmediately) {
704
+ this.triggerTask(task.id);
705
+ }
660
706
  this.scheduleTask(task);
661
707
  }
662
708
  });
709
+ if (!scope) {
710
+ this.running = true;
711
+ }
663
712
  this.notify();
664
713
  }
665
714
  /**
666
715
  * 停止调度器。
667
716
  * 取消所有正在等待的定时器。
668
717
  */
669
- stop() {
670
- this.running = false;
671
- this.log("Scheduler stopped");
672
- this.emit(SchedulerEvents.SCHEDULER_STOPPED, { running: false });
673
- this.timers.forEach((handle, taskId) => {
674
- const task = this.registry.getTask(taskId);
675
- if (task) {
718
+ stop(scope) {
719
+ if (!scope && !this.running) return;
720
+ this.log(scope ? `Scheduler stopping for scope: ${scope}` : "Scheduler stopped");
721
+ this.emit(SchedulerEvents.SCHEDULER_STOPPED, { running: false, scope });
722
+ const tasksToStop = scope ? this.registry.getTasksByNamespace(scope) : this.registry.getAllTasks();
723
+ tasksToStop.forEach((task) => {
724
+ const handle = this.timers.get(task.id);
725
+ if (handle) {
676
726
  this.getTimerStrategy(task).cancel(handle);
677
- } else {
678
- this.defaultTimerStrategy.cancel(handle);
727
+ this.timers.delete(task.id);
679
728
  }
680
- });
681
- this.timers.clear();
682
- this.registry.getAllTasks().forEach((task) => {
683
729
  if (task.status !== TaskStatus.STOPPED) {
684
730
  task.status = TaskStatus.STOPPED;
685
731
  this.emit(SchedulerEvents.TASK_UPDATED, { taskId: task.id, task });
686
732
  }
687
733
  });
734
+ if (!scope) {
735
+ this.running = false;
736
+ }
688
737
  this.notify();
689
738
  }
690
739
  scheduleTask(task) {
691
740
  var _a;
692
- if (!this.running && task.status !== TaskStatus.RUNNING) return;
693
741
  try {
694
742
  const nextRun = getNextRun(task.schedule, {
695
743
  timezone: ((_a = task.options) == null ? void 0 : _a.timezone) || this.config.timezone,
@@ -713,7 +761,7 @@ let Scheduler$1 = class Scheduler {
713
761
  async executeTask(task, attempt = 0, force = false) {
714
762
  var _a, _b;
715
763
  this.timers.delete(task.id);
716
- if (!force && (!this.running || task.status === TaskStatus.STOPPED)) return;
764
+ if (!force && task.status === TaskStatus.STOPPED) return;
717
765
  task.status = TaskStatus.RUNNING;
718
766
  task.lastRun = Date.now();
719
767
  task.executionCount = (task.executionCount || 0) + 1;
@@ -888,7 +936,7 @@ class DevTools {
888
936
  }
889
937
  async mount(scheduler) {
890
938
  try {
891
- await import("./devtools-4xVHTaUz.js");
939
+ await import("./devtools-ByJU-Gv1.js");
892
940
  await customElements.whenDefined("hs-devtools");
893
941
  this.setupElement(scheduler);
894
942
  } catch (e) {
@@ -918,17 +966,22 @@ class DevTools {
918
966
  if (typeof el.setScheduler === "function") {
919
967
  el.setScheduler({
920
968
  getTasks: () => {
921
- return scheduler.getAllTasks().map((task) => ({
922
- id: task.id,
923
- status: task.status,
924
- lastRun: task.lastRun || null,
925
- nextRun: task.nextRun || null,
926
- executionCount: task.executionCount || 0,
927
- schedule: task.schedule,
928
- tags: task.tags || [],
929
- error: task.status === TaskStatus.ERROR ? "Execution failed" : null,
930
- driver: scheduler.getTaskDriver(task.id)
931
- }));
969
+ return scheduler.getAllTasks().map((task) => {
970
+ var _a;
971
+ return {
972
+ id: task.id,
973
+ status: task.status,
974
+ lastRun: task.lastRun || null,
975
+ nextRun: task.nextRun || null,
976
+ executionCount: task.executionCount || 0,
977
+ schedule: task.schedule,
978
+ tags: task.tags || [],
979
+ error: task.status === TaskStatus.ERROR ? "Execution failed" : null,
980
+ driver: scheduler.getTaskDriver(task.id),
981
+ namespace: ((_a = task.options) == null ? void 0 : _a.namespace) || "default"
982
+ // 添加 namespace
983
+ };
984
+ });
932
985
  },
933
986
  on: (evt, handler) => {
934
987
  return scheduler.on(evt, handler);