hyper-scheduler 1.1.1 → 1.1.2
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.
|
@@ -407,9 +407,12 @@ class FloatingTrigger extends HTMLElement {
|
|
|
407
407
|
__publicField(this, "_offsetX", 0);
|
|
408
408
|
__publicField(this, "_offsetY", 0);
|
|
409
409
|
__publicField(this, "_isCollapsed", false);
|
|
410
|
+
// 新增:收起状态
|
|
411
|
+
// 内部状态:保存展开时的位置
|
|
412
|
+
__publicField(this, "_savedX", 0);
|
|
413
|
+
__publicField(this, "_savedY", 0);
|
|
410
414
|
this._shadow = this.attachShadow({ mode: "open" });
|
|
411
415
|
}
|
|
412
|
-
// 新增:收起状态
|
|
413
416
|
static get observedAttributes() {
|
|
414
417
|
return ["position", "bg-color", "text-color"];
|
|
415
418
|
}
|
|
@@ -417,7 +420,9 @@ class FloatingTrigger extends HTMLElement {
|
|
|
417
420
|
this.loadState();
|
|
418
421
|
this.render();
|
|
419
422
|
this.addEventListeners();
|
|
420
|
-
|
|
423
|
+
requestAnimationFrame(() => {
|
|
424
|
+
this.applyPosition();
|
|
425
|
+
});
|
|
421
426
|
window.addEventListener("resize", this.onResize.bind(this));
|
|
422
427
|
}
|
|
423
428
|
disconnectedCallback() {
|
|
@@ -429,7 +434,9 @@ class FloatingTrigger extends HTMLElement {
|
|
|
429
434
|
attributeChangedCallback(name, _oldVal, newVal) {
|
|
430
435
|
if (name === "position") {
|
|
431
436
|
this._position = newVal || "bottom-right";
|
|
432
|
-
this.
|
|
437
|
+
if (!this.style.getPropertyValue("--hs-trigger-position-set")) {
|
|
438
|
+
this.resetPositionToDefault();
|
|
439
|
+
}
|
|
433
440
|
} else if (name === "bg-color") {
|
|
434
441
|
this._bgColor = newVal || "";
|
|
435
442
|
this.updateStyles();
|
|
@@ -443,9 +450,11 @@ class FloatingTrigger extends HTMLElement {
|
|
|
443
450
|
const savedPos = localStorage.getItem(STORAGE_KEY_POS);
|
|
444
451
|
if (savedPos) {
|
|
445
452
|
const { x, y } = JSON.parse(savedPos);
|
|
446
|
-
this.
|
|
447
|
-
this.
|
|
453
|
+
this._savedX = parseFloat(x);
|
|
454
|
+
this._savedY = parseFloat(y);
|
|
448
455
|
this.style.setProperty("--hs-trigger-position-set", "true");
|
|
456
|
+
} else {
|
|
457
|
+
this.resetPositionToDefault();
|
|
449
458
|
}
|
|
450
459
|
const savedCollapsed = localStorage.getItem(STORAGE_KEY_COLLAPSED);
|
|
451
460
|
if (savedCollapsed === "true") {
|
|
@@ -453,60 +462,45 @@ class FloatingTrigger extends HTMLElement {
|
|
|
453
462
|
}
|
|
454
463
|
} catch (e) {
|
|
455
464
|
console.warn("[FloatingTrigger] Failed to load state:", e);
|
|
465
|
+
this.resetPositionToDefault();
|
|
456
466
|
}
|
|
457
467
|
}
|
|
468
|
+
resetPositionToDefault() {
|
|
469
|
+
const width = 48;
|
|
470
|
+
const height = 48;
|
|
471
|
+
const padding = 20;
|
|
472
|
+
if (this._position.includes("left")) this._savedX = padding;
|
|
473
|
+
else this._savedX = window.innerWidth - width - padding;
|
|
474
|
+
if (this._position.includes("top")) this._savedY = padding;
|
|
475
|
+
else this._savedY = window.innerHeight - height - padding;
|
|
476
|
+
}
|
|
458
477
|
saveState() {
|
|
459
|
-
|
|
460
|
-
if (!button) return;
|
|
478
|
+
localStorage.setItem(STORAGE_KEY_POS, JSON.stringify({ x: this._savedX, y: this._savedY }));
|
|
461
479
|
localStorage.setItem(STORAGE_KEY_COLLAPSED, String(this._isCollapsed));
|
|
462
|
-
if (!this._isCollapsed) {
|
|
463
|
-
const rect = button.getBoundingClientRect();
|
|
464
|
-
localStorage.setItem(STORAGE_KEY_POS, JSON.stringify({ x: rect.left, y: rect.top }));
|
|
465
|
-
} else {
|
|
466
|
-
try {
|
|
467
|
-
const savedPos = localStorage.getItem(STORAGE_KEY_POS);
|
|
468
|
-
if (savedPos) {
|
|
469
|
-
const { x } = JSON.parse(savedPos);
|
|
470
|
-
const rect = button.getBoundingClientRect();
|
|
471
|
-
localStorage.setItem(STORAGE_KEY_POS, JSON.stringify({ x, y: rect.top }));
|
|
472
|
-
}
|
|
473
|
-
} catch (e) {
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
480
|
}
|
|
477
481
|
applyPosition() {
|
|
478
482
|
const button = this._shadow.querySelector("button");
|
|
479
483
|
if (!button) return;
|
|
480
|
-
const
|
|
481
|
-
const
|
|
484
|
+
const width = this._isCollapsed ? 24 : 48;
|
|
485
|
+
const height = 48;
|
|
486
|
+
const maxX = window.innerWidth - width;
|
|
487
|
+
const maxY = window.innerHeight - height;
|
|
488
|
+
let targetX, targetY;
|
|
482
489
|
if (this._isCollapsed) {
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
button.style.right = "0px";
|
|
486
|
-
button.style.left = "auto";
|
|
487
|
-
button.style.top = `${currentY}px`;
|
|
488
|
-
button.style.bottom = "auto";
|
|
489
|
-
this.style.setProperty("--hs-trigger-top", `${currentY}px`);
|
|
490
|
+
targetX = maxX;
|
|
491
|
+
targetY = Math.max(0, Math.min(this._savedY, maxY));
|
|
490
492
|
} else {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
button.style.right = pos.includes("right") ? "20px" : "auto";
|
|
497
|
-
} else {
|
|
498
|
-
let currentX = parseFloat(this.style.getPropertyValue("--hs-trigger-left") || "0");
|
|
499
|
-
let currentY = parseFloat(this.style.getPropertyValue("--hs-trigger-top") || "0");
|
|
500
|
-
currentX = Math.max(0, Math.min(currentX, maxX));
|
|
501
|
-
currentY = Math.max(0, Math.min(currentY, maxY));
|
|
502
|
-
this.style.setProperty("--hs-trigger-left", `${currentX}px`);
|
|
503
|
-
this.style.setProperty("--hs-trigger-top", `${currentY}px`);
|
|
504
|
-
button.style.left = `${currentX}px`;
|
|
505
|
-
button.style.top = `${currentY}px`;
|
|
506
|
-
button.style.right = "auto";
|
|
507
|
-
button.style.bottom = "auto";
|
|
493
|
+
targetX = Math.max(0, Math.min(this._savedX, maxX));
|
|
494
|
+
targetY = Math.max(0, Math.min(this._savedY, maxY));
|
|
495
|
+
if (targetX !== this._savedX || targetY !== this._savedY) {
|
|
496
|
+
this._savedX = targetX;
|
|
497
|
+
this._savedY = targetY;
|
|
508
498
|
}
|
|
509
499
|
}
|
|
500
|
+
button.style.left = `${targetX}px`;
|
|
501
|
+
button.style.top = `${targetY}px`;
|
|
502
|
+
this.style.setProperty("--hs-trigger-left", `${targetX}px`);
|
|
503
|
+
this.style.setProperty("--hs-trigger-top", `${targetY}px`);
|
|
510
504
|
this.updateCollapsedState();
|
|
511
505
|
}
|
|
512
506
|
updateStyles() {
|
|
@@ -564,38 +558,38 @@ class FloatingTrigger extends HTMLElement {
|
|
|
564
558
|
if (e.target.closest(".collapse-btn")) return;
|
|
565
559
|
this._isDragging = true;
|
|
566
560
|
this._wasDragging = false;
|
|
567
|
-
|
|
568
|
-
this.
|
|
561
|
+
const rect = btn.getBoundingClientRect();
|
|
562
|
+
this._offsetX = e.clientX - rect.left;
|
|
563
|
+
this._offsetY = e.clientY - rect.top;
|
|
569
564
|
const startX = e.clientX;
|
|
570
565
|
const startY = e.clientY;
|
|
571
566
|
let hasMoved = false;
|
|
567
|
+
btn.style.transition = "none";
|
|
572
568
|
const onMouseMove = (moveEvent) => {
|
|
573
569
|
if (!this._isDragging) return;
|
|
574
570
|
if (!hasMoved && (Math.abs(moveEvent.clientX - startX) > 2 || Math.abs(moveEvent.clientY - startY) > 2)) {
|
|
575
571
|
hasMoved = true;
|
|
576
572
|
this._wasDragging = true;
|
|
577
573
|
btn.style.cursor = "grabbing";
|
|
578
|
-
btn.style.transition = "none";
|
|
579
574
|
}
|
|
580
575
|
if (hasMoved) {
|
|
581
576
|
let newX = moveEvent.clientX - this._offsetX;
|
|
582
577
|
let newY = moveEvent.clientY - this._offsetY;
|
|
583
|
-
const
|
|
584
|
-
const
|
|
578
|
+
const width = this._isCollapsed ? 24 : 48;
|
|
579
|
+
const height = 48;
|
|
580
|
+
const maxX = window.innerWidth - width;
|
|
581
|
+
const maxY = window.innerHeight - height;
|
|
585
582
|
newX = Math.max(0, Math.min(newX, maxX));
|
|
586
583
|
newY = Math.max(0, Math.min(newY, maxY));
|
|
587
584
|
if (this._isCollapsed) {
|
|
588
|
-
|
|
589
|
-
|
|
585
|
+
newX = window.innerWidth - 24;
|
|
586
|
+
this._savedY = newY;
|
|
590
587
|
} else {
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
this.style.setProperty("--hs-trigger-left", `${newX}px`);
|
|
588
|
+
this._savedX = newX;
|
|
589
|
+
this._savedY = newY;
|
|
594
590
|
}
|
|
591
|
+
btn.style.left = `${newX}px`;
|
|
595
592
|
btn.style.top = `${newY}px`;
|
|
596
|
-
btn.style.bottom = "auto";
|
|
597
|
-
this.style.setProperty("--hs-trigger-position-set", "true");
|
|
598
|
-
this.style.setProperty("--hs-trigger-top", `${newY}px`);
|
|
599
593
|
}
|
|
600
594
|
};
|
|
601
595
|
const onMouseUp = () => {
|
|
@@ -620,11 +614,9 @@ class FloatingTrigger extends HTMLElement {
|
|
|
620
614
|
}
|
|
621
615
|
render() {
|
|
622
616
|
const posStyles = `
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
right: var(--hs-trigger-right, ${this._position.includes("right") ? "20px" : "auto"});
|
|
627
|
-
transform: translateX(0);
|
|
617
|
+
left: 0;
|
|
618
|
+
top: 0;
|
|
619
|
+
transform: translateZ(0); /* 开启硬件加速 */
|
|
628
620
|
`;
|
|
629
621
|
const bgStyle = this._bgColor ? `background: ${this._bgColor};` : "";
|
|
630
622
|
const colorStyle = this._textColor ? `color: ${this._textColor};` : "";
|
|
@@ -636,21 +628,27 @@ class FloatingTrigger extends HTMLElement {
|
|
|
636
628
|
${posStyles}
|
|
637
629
|
width: 48px;
|
|
638
630
|
height: 48px;
|
|
639
|
-
border-radius: 12px;
|
|
631
|
+
border-radius: 12px;
|
|
640
632
|
background: var(--hs-primary);
|
|
641
633
|
color: white;
|
|
642
634
|
${bgStyle}
|
|
643
635
|
${colorStyle}
|
|
644
636
|
border: none;
|
|
645
|
-
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
637
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
646
638
|
cursor: pointer;
|
|
647
639
|
display: flex;
|
|
648
640
|
align-items: center;
|
|
649
641
|
justify-content: center;
|
|
650
642
|
font-family: var(--hs-font-family);
|
|
651
643
|
z-index: var(--hs-z-index);
|
|
652
|
-
|
|
653
|
-
|
|
644
|
+
/* 添加平滑过渡动画 */
|
|
645
|
+
transition: width 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),
|
|
646
|
+
left 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),
|
|
647
|
+
top 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),
|
|
648
|
+
border-radius 0.3s,
|
|
649
|
+
background 0.2s,
|
|
650
|
+
box-shadow 0.2s;
|
|
651
|
+
overflow: visible;
|
|
654
652
|
}
|
|
655
653
|
.icon {
|
|
656
654
|
transition: transform 0.2s;
|
|
@@ -679,13 +677,14 @@ class FloatingTrigger extends HTMLElement {
|
|
|
679
677
|
display: flex;
|
|
680
678
|
align-items: center;
|
|
681
679
|
justify-content: center;
|
|
682
|
-
opacity: 1;
|
|
680
|
+
opacity: 1;
|
|
683
681
|
transition: opacity 0.2s, background 0.2s;
|
|
684
682
|
color: white;
|
|
685
683
|
font-weight: bold;
|
|
684
|
+
z-index: 2;
|
|
686
685
|
}
|
|
687
686
|
.collapse-btn::before {
|
|
688
|
-
content: '—';
|
|
687
|
+
content: '—';
|
|
689
688
|
font-size: 12px;
|
|
690
689
|
color: currentColor;
|
|
691
690
|
}
|
|
@@ -701,27 +700,24 @@ class FloatingTrigger extends HTMLElement {
|
|
|
701
700
|
width: 24px;
|
|
702
701
|
height: 48px;
|
|
703
702
|
border-radius: 12px 0 0 12px;
|
|
704
|
-
|
|
705
|
-
opacity: 1;
|
|
706
|
-
right: 0 !important; /* 强制右对齐 */
|
|
707
|
-
left: auto !important;
|
|
703
|
+
/* 不再强制 left/right,由 JS 控制 left 实现动画 */
|
|
708
704
|
}
|
|
709
705
|
button.collapsed:hover {
|
|
710
|
-
width: 28px;
|
|
711
|
-
opacity: 1;
|
|
706
|
+
width: 28px;
|
|
712
707
|
}
|
|
708
|
+
|
|
713
709
|
button.collapsed .icon {
|
|
714
710
|
display: none;
|
|
715
711
|
}
|
|
716
712
|
button.collapsed .collapse-btn {
|
|
717
|
-
position: static;
|
|
713
|
+
position: static;
|
|
718
714
|
width: 100%;
|
|
719
715
|
height: 100%;
|
|
720
716
|
border-radius: 0;
|
|
721
717
|
background: transparent;
|
|
722
718
|
}
|
|
723
719
|
button.collapsed .collapse-btn::before {
|
|
724
|
-
content: '‹';
|
|
720
|
+
content: '‹';
|
|
725
721
|
font-size: 20px;
|
|
726
722
|
line-height: 48px;
|
|
727
723
|
}
|
|
@@ -731,9 +727,6 @@ class FloatingTrigger extends HTMLElement {
|
|
|
731
727
|
<span class="icon">${ICONS.chart}</span>
|
|
732
728
|
</button>
|
|
733
729
|
`;
|
|
734
|
-
this.applyPosition();
|
|
735
|
-
this.updateCollapsedState();
|
|
736
|
-
this.updateStyles();
|
|
737
730
|
}
|
|
738
731
|
}
|
|
739
732
|
customElements.define("hs-floating-trigger", FloatingTrigger);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var t=Object.defineProperty,e=(e,s,n)=>((e,s,n)=>s in e?t(e,s,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[s]=n)(e,"symbol"!=typeof s?s+"":s,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("./index.cjs"),n={header:{title:"DevTools",searchPlaceholder:"Search IDs/Tags... 🔍",toggleDock:"Toggle Dock Position",toggleTheme:"Toggle Theme",close:"Close"},stats:{loading:"Loading...",fps:"FPS",status:"Status",active:"Active",total:"Total",mainThread:"Main Thread",scheduler:"Scheduler",running:"Running",stopped:"Stopped"},tabs:{tasks:"Tasks List",timeline:"Timeline"},list:{idTags:"ID / Tags",status:"Status",driver:"Driver",driverWorker:"Worker (Web Worker)",driverMain:"Main (setTimeout)",schedule:"Schedule",count:"Count",lastRun:"Last Run",actions:"Actions",noTags:"(No Tags)",tip:"✨ Tip: Click a row for details & history."},detail:{back:"Back",details:"Task Details",config:"Config",history:"Execution History",lastRuns:"Last {n} runs",avgDuration:"Avg Duration",startTime:"Start Time",duration:"Duration",drift:"Drift",status:"Status",noHistory:"No execution history",noTask:"No task selected",success:"Success",failed:"Failed",error:"Error"},timeline:{zoom:"Zoom",timeRange:"Time Range: Last {n}s",legend:"Legend",instant:"Instant",duration:"Duration",workerDriver:"Worker Driver",mainDriver:"Main Driver"},status:{running:"Running",paused:"Paused",stopped:"Stopped",idle:"Scheduled",error:"Error"},actions:{trigger:"Trigger now",start:"Start task",stop:"Stop task",remove:"Remove task"}},i={header:{title:"调试工具",searchPlaceholder:"搜索 ID/标签... 🔍",toggleDock:"切换停靠位置",toggleTheme:"切换主题",close:"关闭"},stats:{loading:"加载中...",fps:"帧率",status:"状态",active:"活跃",total:"总数",mainThread:"主线程",scheduler:"调度器",running:"运行中",stopped:"已停止"},tabs:{tasks:"任务列表",timeline:"时间线"},list:{idTags:"ID / 标签",status:"状态",driver:"驱动",driverWorker:"Worker (Web Worker)",driverMain:"主线程 (setTimeout)",schedule:"调度规则",count:"次数",lastRun:"最后运行",actions:"操作",noTags:"(无标签)",tip:"✨ 提示: 点击行查看详情和历史记录。"},detail:{back:"返回",details:"任务详情",config:"配置",history:"执行历史",lastRuns:"最近 {n} 次运行",avgDuration:"平均耗时",startTime:"开始时间",duration:"耗时",drift:"偏差",status:"状态",noHistory:"暂无执行历史",noTask:"未选择任务",success:"成功",failed:"失败",error:"错误"},timeline:{zoom:"缩放",timeRange:"时间范围: 最近 {n}秒",legend:"图例",instant:"瞬间",duration:"耗时",workerDriver:"Worker 驱动",mainDriver:"主线程 驱动"},status:{running:"执行中",paused:"已暂停",stopped:"已停止",idle:"调度中",error:"错误"},actions:{trigger:"立即触发",start:"启动任务",stop:"停止任务",remove:"删除任务"}};let o=n;function a(t){o="zh"===t?i:n}function r(t,e){const s=t.split(".");let n=o;for(const i of s){if(!n||"object"!=typeof n||!(i in n))return t;n=n[i]}return"string"!=typeof n?t:e?n.replace(/\{(\w+)\}/g,(t,s)=>void 0!==e[s]?String(e[s]):`{${s}}`):n}class h{constructor(){e(this,"state"),e(this,"listeners"),e(this,"scheduler"),this.state={isOpen:!1,activeTab:"tasks",theme:"auto",dockPosition:"right",panelSize:{width:500,height:500},language:"en",filterText:"",selectedTaskId:null,tasks:new Map,history:new Map,fps:0,schedulerRunning:!1},this.listeners=new Map}setScheduler(t){this.scheduler=t}getState(){return this.state}subscribe(t,e){return this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e),()=>{var s;null==(s=this.listeners.get(t))||s.delete(e)}}notify(t,e){var s;null==(s=this.listeners.get(t))||s.forEach(t=>t(e))}toggle(){this.state.isOpen=!this.state.isOpen,this.notify("isOpen",this.state.isOpen)}setTheme(t){this.state.theme=t,this.notify("theme",this.state.theme)}setLanguageSync(t){a(t),this.state.language=t}setLanguage(t){a(t),this.state.language=t,this.notify("language",this.state.language)}setPanelSize(t){this.state.panelSize={...this.state.panelSize,...t};try{localStorage.setItem("hs-panel-size",JSON.stringify(this.state.panelSize))}catch(e){}this.notify("panelSize",this.state.panelSize)}setTab(t){this.state.activeTab=t,this.notify("activeTab",this.state.activeTab)}setDockPosition(t){this.state.dockPosition=t,this.notify("dockPosition",this.state.dockPosition)}setFilterText(t){this.state.filterText=t,this.notify("filterText",this.state.filterText)}updateTask(t){const e=new Map(this.state.tasks);if(e.set(t.id,t),this.state.tasks=e,this.notify("tasks",this.state.tasks),"history"in t&&Array.isArray(t.history)){const e=new Map(this.state.history);e.set(t.id,t.history),this.state.history=e,this.notify("history",this.state.history)}}selectTask(t){this.state.selectedTaskId=t,this.notify("selectedTaskId",t)}addHistory(t,e){const s=[...this.state.history.get(t)||[]];s.push(e),s.length>50&&s.splice(0,s.length-50);const n=new Map(this.state.history);n.set(t,s),this.state.history=n,this.notify("history",n)}async triggerTask(t){this.scheduler&&await this.scheduler.trigger(t)}stopTask(t){console.log("[DevToolsStore] stopTask:",t),this.scheduler&&this.scheduler.pause(t)}startTask(t){console.log("[DevToolsStore] startTask:",t),this.scheduler&&this.scheduler.resume(t)}removeTask(t){if(this.scheduler){this.scheduler.remove(t);const e=new Map(this.state.tasks);e.delete(t),this.state.tasks=e,this.notify("tasks",this.state.tasks)}}setSchedulerRunning(t){this.state.schedulerRunning=t,this.notify("schedulerRunning",t)}}const l='\n :host {\n --hs-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;\n --hs-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;\n --hs-font-size: 12px;\n --hs-line-height: 1.5;\n --hs-panel-width: 400px;\n --hs-panel-height: 300px;\n \n /* 等宽数字字体 */\n --hs-font-monospaced-num: var(--hs-font-mono);\n\n /* Light Theme (Default) */\n --hs-bg: #ffffff;\n --hs-bg-secondary: #f3f4f6;\n --hs-text: #1f2937;\n --hs-text-secondary: #6b7280;\n --hs-border: #e5e7eb;\n --hs-primary: #3b82f6;\n --hs-primary-hover: #2563eb;\n --hs-danger: #ef4444;\n --hs-danger-hover: #dc2626;\n --hs-success: #10b981;\n --hs-warning: #f59e0b;\n \n --hs-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);\n --hs-radius: 6px;\n --hs-header-height: 40px;\n --hs-z-index: 9999;\n --hs-z-index-overlay: 9998;\n\n /* Default display styles for the host itself */\n background: var(--hs-bg);\n color: var(--hs-text);\n font-family: var(--hs-font-family);\n font-size: var(--hs-font-size);\n line-height: var(--hs-line-height);\n }\n\n :host([theme="dark"]) {\n --hs-bg: #111827;\n --hs-bg-secondary: #1f2937;\n --hs-text: #f9fafb;\n --hs-text-secondary: #9ca3af;\n --hs-border: #374151;\n --hs-primary: #60a5fa;\n --hs-primary-hover: #3b82f6;\n --hs-danger: #f87171;\n --hs-danger-hover: #ef4444;\n --hs-success: #34d399;\n --hs-warning: #fbbf24;\n \n --hs-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.5), 0 2px 4px -1px rgba(0, 0, 0, 0.3);\n }\n\n :host {\n background: var(--hs-bg);\n color: var(--hs-text);\n }\n',d={back:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="12" x2="5" y2="12"></line><polyline points="12 19 5 12 12 5"></polyline></svg>',trigger:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>',pause:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="4" width="4" height="16"></rect><rect x="14" y="4" width="4" height="16"></rect></svg>',resume:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>',remove:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>',close:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>',sun:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>',moon:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>',dock:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="18" rx="2" ry="2"></rect><line x1="2" y1="15" x2="22" y2="15"></line></svg>',dockRight:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="18" rx="2" ry="2"></rect><line x1="15" y1="3" x2="15" y2="21"></line></svg>',chart:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"></line><line x1="12" y1="20" x2="12" y2="4"></line><line x1="6" y1="20" x2="6" y2="14"></line></svg>'},c="hs-trigger-position",p="hs-trigger-collapsed";class g extends HTMLElement{constructor(){super(),e(this,"_shadow"),e(this,"_position","bottom-right"),e(this,"_bgColor",""),e(this,"_textColor",""),e(this,"_isDragging",!1),e(this,"_wasDragging",!1),e(this,"_offsetX",0),e(this,"_offsetY",0),e(this,"_isCollapsed",!1),e(this,"_savedX",0),e(this,"_savedY",0),this._shadow=this.attachShadow({mode:"open"})}static get observedAttributes(){return["position","bg-color","text-color"]}connectedCallback(){this.loadState(),this.render(),this.addEventListeners(),requestAnimationFrame(()=>{this.applyPosition()}),window.addEventListener("resize",this.onResize.bind(this))}disconnectedCallback(){window.removeEventListener("resize",this.onResize.bind(this))}onResize(){this.applyPosition()}attributeChangedCallback(t,e,s){"position"===t?(this._position=s||"bottom-right",this.style.getPropertyValue("--hs-trigger-position-set")||this.resetPositionToDefault()):"bg-color"===t?(this._bgColor=s||"",this.updateStyles()):"text-color"===t&&(this._textColor=s||"",this.updateStyles())}loadState(){try{const t=localStorage.getItem(c);if(t){const{x:e,y:s}=JSON.parse(t);this._savedX=parseFloat(e),this._savedY=parseFloat(s),this.style.setProperty("--hs-trigger-position-set","true")}else this.resetPositionToDefault();"true"===localStorage.getItem(p)&&(this._isCollapsed=!0)}catch(t){console.warn("[FloatingTrigger] Failed to load state:",t),this.resetPositionToDefault()}}resetPositionToDefault(){this._position.includes("left")?this._savedX=20:this._savedX=window.innerWidth-48-20,this._position.includes("top")?this._savedY=20:this._savedY=window.innerHeight-48-20}saveState(){localStorage.setItem(c,JSON.stringify({x:this._savedX,y:this._savedY})),localStorage.setItem(p,String(this._isCollapsed))}applyPosition(){const t=this._shadow.querySelector("button");if(!t)return;const e=this._isCollapsed?24:48,s=window.innerWidth-e,n=window.innerHeight-48;let i,o;this._isCollapsed?(i=s,o=Math.max(0,Math.min(this._savedY,n))):(i=Math.max(0,Math.min(this._savedX,s)),o=Math.max(0,Math.min(this._savedY,n)),i===this._savedX&&o===this._savedY||(this._savedX=i,this._savedY=o)),t.style.left=`${i}px`,t.style.top=`${o}px`,this.style.setProperty("--hs-trigger-left",`${i}px`),this.style.setProperty("--hs-trigger-top",`${o}px`),this.updateCollapsedState()}updateStyles(){const t=this._shadow.querySelector("button");t&&(t.style.background=this._bgColor||"var(--hs-primary)",t.style.color=this._textColor||"white",this._bgColor?t.style.setProperty("--hs-trigger-bg-hover",`${this._bgColor}; filter: brightness(1.1);`):t.style.removeProperty("--hs-trigger-bg-hover"))}updateCollapsedState(){const t=this._shadow.querySelector("button");t&&(this._isCollapsed?t.classList.add("collapsed"):t.classList.remove("collapsed"))}addEventListeners(){const t=this._shadow.querySelector("button");if(!t)return;t.addEventListener("click",t=>{if(this._wasDragging)return t.preventDefault(),t.stopPropagation(),void(this._wasDragging=!1);this.dispatchEvent(new CustomEvent("toggle",{bubbles:!0,composed:!0}))});const e=this._shadow.querySelector(".collapse-btn");null==e||e.addEventListener("click",t=>{t.stopPropagation(),t.preventDefault(),this._isCollapsed=!this._isCollapsed,this.applyPosition(),this.saveState()}),t.addEventListener("dblclick",t=>{this._isCollapsed&&(t.stopPropagation(),this._isCollapsed=!1,this.applyPosition(),this.saveState())}),t.addEventListener("mousedown",e=>{if(0!==e.button)return;if(e.target.closest(".collapse-btn"))return;this._isDragging=!0,this._wasDragging=!1;const s=t.getBoundingClientRect();this._offsetX=e.clientX-s.left,this._offsetY=e.clientY-s.top;const n=e.clientX,i=e.clientY;let o=!1;t.style.transition="none";const a=e=>{if(this._isDragging&&(!o&&(Math.abs(e.clientX-n)>2||Math.abs(e.clientY-i)>2)&&(o=!0,this._wasDragging=!0,t.style.cursor="grabbing"),o)){let s=e.clientX-this._offsetX,n=e.clientY-this._offsetY;const i=this._isCollapsed?24:48,o=48,a=window.innerWidth-i,r=window.innerHeight-o;s=Math.max(0,Math.min(s,a)),n=Math.max(0,Math.min(n,r)),this._isCollapsed?(s=window.innerWidth-24,this._savedY=n):(this._savedX=s,this._savedY=n),t.style.left=`${s}px`,t.style.top=`${n}px`}},r=()=>{if(this._isDragging){if(this._isDragging=!1,t.style.cursor="pointer",t.style.transition="",o){this.saveState();const t=t=>{t.stopPropagation(),t.preventDefault()};window.addEventListener("click",t,{capture:!0,once:!0})}window.removeEventListener("mousemove",a),window.removeEventListener("mouseup",r)}};window.addEventListener("mousemove",a),window.addEventListener("mouseup",r)})}render(){const t=this._bgColor?`background: ${this._bgColor};`:"",e=this._textColor?`color: ${this._textColor};`:"";this._shadow.innerHTML=`\n <style>\n ${l}\n button {\n position: fixed;\n \n left: 0;\n top: 0;\n transform: translateZ(0); /* 开启硬件加速 */\n \n width: 48px;\n height: 48px;\n border-radius: 12px;\n background: var(--hs-primary);\n color: white;\n ${t}\n ${e}\n border: none;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-family: var(--hs-font-family);\n z-index: var(--hs-z-index);\n /* 添加平滑过渡动画 */\n transition: width 0.3s cubic-bezier(0.25, 0.8, 0.25, 1), \n left 0.3s cubic-bezier(0.25, 0.8, 0.25, 1), \n top 0.3s cubic-bezier(0.25, 0.8, 0.25, 1), \n border-radius 0.3s,\n background 0.2s, \n box-shadow 0.2s;\n overflow: visible;\n }\n .icon {\n transition: transform 0.2s;\n display: flex;\n }\n button:hover {\n ${this._bgColor?`background: ${this._bgColor}; filter: brightness(1.1);`:"background: var(--hs-primary-hover);"}\n box-shadow: 0 6px 16px rgba(0,0,0,0.2);\n }\n button:hover .icon {\n transform: scale(1.1);\n }\n button:active .icon {\n transform: scale(0.95);\n }\n\n /* 显式收起按钮 */\n .collapse-btn {\n position: absolute;\n top: 0;\n right: 0;\n width: 20px;\n height: 20px;\n background: rgba(0,0,0,0.1);\n border-top-right-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 1; \n transition: opacity 0.2s, background 0.2s;\n color: white;\n font-weight: bold;\n z-index: 2;\n }\n .collapse-btn::before {\n content: '—'; \n font-size: 12px;\n color: currentColor;\n }\n button:hover .collapse-btn {\n opacity: 1;\n }\n .collapse-btn:hover {\n background: rgba(0,0,0,0.3);\n }\n\n /* 收起状态样式 */\n button.collapsed {\n width: 24px;\n height: 48px;\n border-radius: 12px 0 0 12px;\n /* 不再强制 left/right,由 JS 控制 left 实现动画 */\n }\n button.collapsed:hover {\n width: 28px; \n }\n \n button.collapsed .icon {\n display: none;\n }\n button.collapsed .collapse-btn {\n position: static;\n width: 100%;\n height: 100%;\n border-radius: 0;\n background: transparent;\n }\n button.collapsed .collapse-btn::before {\n content: '‹'; \n font-size: 20px;\n line-height: 48px;\n }\n </style>\n <button title="Toggle Hyper Scheduler DevTools">\n <div class="collapse-btn" title="Minimize"></div>\n <span class="icon">${d.chart}</span>\n </button>\n `}}customElements.define("hs-floating-trigger",g);class u extends HTMLElement{constructor(){super(),e(this,"_shadow"),e(this,"_fps",0),e(this,"_stats",{active:0,total:0}),e(this,"_theme","auto"),e(this,"_activeTab","tasks"),e(this,"_language","en"),e(this,"_schedulerRunning",!1),e(this,"$fps"),e(this,"$stats"),e(this,"$schedulerStatus"),e(this,"$themeIcon"),e(this,"$dockIcon"),e(this,"$tabs"),e(this,"$searchInput"),e(this,"$title"),e(this,"$langBtn"),this._shadow=this.attachShadow({mode:"open"})}connectedCallback(){this.render(),this.cacheDom(),this.addEventListeners(),this.updateView()}set fps(t){if(this._fps=Math.round(t),this.$fps){const t=this._fps<30?"var(--hs-danger)":this._fps<50?"var(--hs-warning)":"var(--hs-success)";this.$fps.innerHTML=`⚡ ${r("stats.fps")}: <span style="color:${t}; font-family:var(--hs-font-monospaced-num);">${this._fps}</span> (${r("stats.mainThread")})`}}set stats(t){this._stats=t,this.$stats&&(this.$stats.innerHTML=`📊 ${r("stats.status")}: <span style="color:var(--hs-success)">🟢 ${r("stats.active")}: ${t.active}</span> <span style="margin-left:12px;color:var(--hs-text-secondary)">⚪ ${r("stats.total")}: ${t.total}</span>`)}set schedulerRunning(t){if(this._schedulerRunning=t,this.$schedulerStatus){const e=r(t?"stats.running":"stats.stopped"),s=t?"var(--hs-success)":"var(--hs-danger)",n=t?"▶️":"⏹️";this.$schedulerStatus.innerHTML=`${n} ${r("stats.scheduler")}: <span style="color:${s}">${e}</span>`}}set theme(t){this._theme=t,this.setAttribute("theme",t),this.updateThemeIcon()}set language(t){this._language=t,this.updateTexts()}set dockPosition(t){var e;this.$dockIcon&&(this.$dockIcon.innerHTML="right"===t?d.dock:d.dockRight,null==(e=this.$dockIcon.parentElement)||e.setAttribute("title",r("header.toggleDock")))}set activeTab(t){this._activeTab=t,this.updateTabs()}cacheDom(){this.$fps=this._shadow.querySelector(".fps"),this.$stats=this._shadow.querySelector(".stats"),this.$schedulerStatus=this._shadow.querySelector(".scheduler-status"),this.$themeIcon=this._shadow.querySelector(".theme-btn span"),this.$dockIcon=this._shadow.querySelector(".dock-btn"),this.$tabs=this._shadow.querySelectorAll(".tab"),this.$searchInput=this._shadow.querySelector(".search-input"),this.$title=this._shadow.querySelector(".title"),this.$langBtn=this._shadow.querySelector(".lang-btn")}addEventListeners(){var t,e,s,n,i;null==(t=this._shadow.querySelector(".dock-btn"))||t.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("dock-toggle"))}),null==(e=this._shadow.querySelector(".theme-btn"))||e.addEventListener("click",()=>{const t="dark"===this._theme?"light":"dark";this.dispatchEvent(new CustomEvent("theme-toggle",{detail:t}))}),null==(s=this._shadow.querySelector(".lang-btn"))||s.addEventListener("click",()=>{const t="en"===this._language?"zh":"en";this.dispatchEvent(new CustomEvent("lang-toggle",{detail:t}))}),null==(n=this._shadow.querySelector(".close-btn"))||n.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("close"))}),this.$tabs.forEach(t=>{t.addEventListener("click",t=>{const e=t.currentTarget.dataset.tab;this.dispatchEvent(new CustomEvent("tab-change",{detail:e}))})}),null==(i=this.$searchInput)||i.addEventListener("input",t=>{const e=t.target.value;this.dispatchEvent(new CustomEvent("search",{detail:e}))})}updateThemeIcon(){this.$themeIcon&&(this.$themeIcon.innerHTML="dark"===this._theme?d.moon:d.sun)}updateTabs(){this.$tabs.forEach(t=>{t.dataset.tab===this._activeTab?t.classList.add("active"):t.classList.remove("active")})}updateTexts(){this.$title&&(this.$title.innerHTML=`🕒 ${r("header.title")}`),this.$searchInput&&(this.$searchInput.placeholder=r("header.searchPlaceholder")),this.$langBtn&&(this.$langBtn.textContent="en"===this._language?"中":"EN"),this.$tabs.forEach(t=>{const e=t.dataset.tab;"tasks"===e&&(t.innerHTML=`📌 ${r("tabs.tasks")}`),"timeline"===e&&(t.innerHTML=`📈 ${r("tabs.timeline")}`)}),this.stats=this._stats,this.fps=this._fps,this.schedulerRunning=this._schedulerRunning}updateView(){this.updateThemeIcon(),this.updateTabs(),this.updateTexts()}render(){this._shadow.innerHTML=`\n <style>\n ${l}\n :host {\n display: block;\n background: var(--hs-bg);\n border-bottom: 1px solid var(--hs-border);\n padding: 0 16px;\n height: var(--hs-header-height);\n height: auto; \n }\n .top-bar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n height: 40px;\n border-bottom: 1px solid var(--hs-border);\n }\n .title {\n font-weight: 600;\n font-size: 13px;\n color: var(--hs-text);\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .search-box {\n flex: 1;\n max-width: 300px;\n margin: 0px 32px 0 16px;\n }\n .search-input {\n width: 100%;\n background: var(--hs-bg-secondary);\n border: 1px solid var(--hs-border);\n color: var(--hs-text);\n padding: 6px 12px;\n border-radius: 4px;\n font-size: 12px;\n }\n .search-input::placeholder {\n color: var(--hs-text-secondary);\n }\n .controls {\n display: flex;\n align-items: center;\n gap: 4px;\n }\n button {\n background: transparent;\n border: none;\n color: var(--hs-text-secondary);\n cursor: pointer;\n padding: 4px;\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n width: 28px;\n height: 28px;\n }\n .theme-btn span {\n margin-top: 4px;\n }\n button:hover {\n background: var(--hs-bg-secondary);\n color: var(--hs-text);\n }\n button svg {\n width: 16px;\n height: 16px;\n }\n .lang-btn {\n font-weight: 600;\n }\n .stats-bar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n height: 30px;\n font-size: 11px;\n color: var(--hs-text-secondary);\n border-bottom: 1px solid var(--hs-border);\n gap: 16px;\n }\n .stats-left {\n display: flex;\n gap: 16px;\n }\n .tabs-bar {\n display: flex;\n height: 36px;\n gap: 0;\n }\n .tab {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--hs-text-secondary);\n cursor: pointer;\n border-bottom: 3px solid transparent;\n padding: 0 16px;\n transition: all 0.2s;\n }\n .tab:hover {\n color: var(--hs-text);\n background: var(--hs-bg-secondary);\n }\n .tab.active {\n color: var(--hs-text);\n font-weight: 600;\n border-bottom-color: var(--hs-primary);\n background: var(--hs-bg-secondary);\n }\n </style>\n \n <div class="top-bar">\n <div class="title"></div>\n <div class="search-box">\n <input type="text" class="search-input">\n </div>\n <div class="controls">\n <button class="lang-btn" title="Switch Language">EN</button>\n <button class="dock-btn" title="Toggle Dock">${d.dock}</button>\n <button class="theme-btn" title="Toggle Theme"><span>${d.sun}</span></button>\n <button class="close-btn" title="Close">${d.close}</button>\n </div>\n </div>\n \n <div class="stats-bar">\n <div class="stats-left">\n <div class="scheduler-status"></div>\n <div class="stats"></div>\n </div>\n <div class="fps"></div>\n </div>\n \n <div class="tabs-bar">\n <div class="tab active" data-tab="tasks"></div>\n <div class="tab" data-tab="timeline"></div>\n </div>\n `}}customElements.define("hs-task-header",u);class b extends HTMLElement{constructor(){super(),e(this,"_shadow"),e(this,"_tasks",[]),e(this,"_lastExecutionTimes",new Map),e(this,"_expandedNamespaces",new Set(["default"])),this._shadow=this.attachShadow({mode:"open"})}connectedCallback(){this.render()}set tasks(t){const e=Array.from(t.values());e.forEach(t=>{const e=this._tasks.find(e=>e.id===t.id);e&&t.executionCount>e.executionCount&&this._lastExecutionTimes.set(t.id,Date.now())}),this._tasks=e,this.renderRows()}groupTasksByNamespace(t){const e=new Map;return t.forEach(t=>{const s=t.namespace||"default";e.has(s)||e.set(s,[]),e.get(s).push(t)}),e}filter(t,e){const s=Array.from(e.values());if(t){const e=t.toLowerCase();this._tasks=s.filter(t=>t.id.toLowerCase().includes(e)||t.tags.some(t=>t.toLowerCase().includes(e))||t.namespace&&t.namespace.toLowerCase().includes(e))}else this._tasks=s;this.renderRows()}updateHeaders(){const t=this._shadow.querySelector("thead");t&&(t.innerHTML=`\n <tr>\n <th style="width:40px">#</th>\n <th style="min-width:150px">${r("list.idTags")}</th>\n <th style="width:150px">${r("list.status")}</th>\n <th style="width:70px">${r("list.driver")}</th>\n <th style="width:100px">${r("list.schedule")}</th>\n <th style="width:60px">${r("list.count")}</th>\n <th style="width:100px">${r("list.lastRun")}</th>\n <th style="width:100px">${r("list.actions")}</th>\n </tr>\n `);const e=this._shadow.querySelector(".tip");e&&(e.textContent=r("list.tip")),this.renderRows()}getStatusIcon(t,e){const n=this._lastExecutionTimes.get(e),i=n&&Date.now()-n<1e3;switch(t){case s.TaskStatus.RUNNING:return`<span style="color:var(--hs-primary)">🔵</span> <strong>${r("status.running")}</strong>`;case s.TaskStatus.STOPPED:return`<span style="color:var(--hs-text-secondary)">⚪</span> ${r("status.stopped")}`;case s.TaskStatus.IDLE:return i?`<span class="status-flash" style="color:var(--hs-success)">🟢</span> ${r("status.idle")}`:`<span style="color:var(--hs-success)">🟢</span> ${r("status.idle")}`;case s.TaskStatus.ERROR:return`<span style="color:var(--hs-warning)">🟠</span> ${r("status.error")}`;default:return t}}formatSchedule(t){return"number"==typeof t?`${t}ms`:t&&(t.includes("*")||t.includes(" "))?t.length>15?t.substring(0,12)+"...":t:t||"-"}formatTime(t){if(!t)return"-";const e=new Date(t);return e.toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit",second:"2-digit"})+"."+e.getMilliseconds().toString().padStart(3,"0")}getDriverBadge(t){return"worker"===(t||"worker")?`<span class="driver-badge worker" title="${r("list.driverWorker")}">W</span>`:`<span class="driver-badge main" title="${r("list.driverMain")}">M</span>`}renderTaskRow(t,e,n=!1){const i=this._lastExecutionTimes.get(t.id),o=i&&Date.now()-i<1e3?"recently-executed":"",a=n?"nested-task":"";return`\n <tr data-id="${t.id}" class="${o} ${a}">\n <td class="col-num">\n ${n?"":e+1}\n </td>\n <td class="col-id">\n <div class="task-id">\n ${t.id}\n ${t.namespace&&"default"!==t.namespace&&!n?`<span class="namespace-badge" title="Namespace">${t.namespace}</span>`:""}\n </div>\n <div class="tags">\n ${t.tags&&t.tags.length>0?t.tags.map(t=>`<span class="tag">${t}</span>`).join(""):`<span class="no-tags">${r("list.noTags")}</span>`}\n </div>\n </td>\n <td>${this.getStatusIcon(t.status,t.id)}</td>\n <td>${this.getDriverBadge(t.driver)}</td>\n <td>${this.formatSchedule(t.schedule)}</td>\n <td>${t.executionCount||0}</td>\n <td>${this.formatTime(t.lastRun)}</td>\n <td class="col-actions">\n <div class="action-group">\n <button class="btn-icon" data-action="trigger" title="${r("actions.trigger")}" ${t.status===s.TaskStatus.RUNNING?"disabled":""}>${d.trigger}</button>\n ${t.status===s.TaskStatus.STOPPED||t.status===s.TaskStatus.ERROR?`<button class="btn-icon success" data-action="start" title="${r("actions.start")}">${d.resume}</button>`:`<button class="btn-icon warning" data-action="stop" title="${r("actions.stop")}" ${t.status===s.TaskStatus.RUNNING?"disabled":""}>${d.pause}</button>`}\n <button class="btn-icon danger" data-action="remove" title="${r("actions.remove")}">${d.remove}</button>\n </div>\n </td>\n </tr>\n `}renderRows(){const t=this._shadow.querySelector("tbody");if(!t)return;const e=this.groupTasksByNamespace(this._tasks);let s="",n=0;const i=e.get("default");i&&i.length>0&&(s+=i.map(t=>this.renderTaskRow(t,++n,!1)).join("")),e.delete("default");Array.from(e.keys()).sort((t,e)=>t.localeCompare(e)).forEach(t=>{const i=e.get(t),o=this._expandedNamespaces.has(t);s+=`\n <tr class="namespace-row ${o?"ns-expanded":""}" data-ns="${t}">\n <td colspan="8">\n <span class="ns-toggle">${o?"▼":"▶"}</span>\n <span class="ns-icon">📂</span>\n <span class="ns-name">${t}</span>\n <span class="ns-count">(${i.length})</span>\n </td>\n </tr>\n `,o&&(s+=i.map(t=>this.renderTaskRow(t,++n,!0)).join(""))}),t.innerHTML=s}render(){this._shadow.innerHTML=`\n <style>\n ${l}\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--hs-bg);\n }\n .table-container {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overflow-x: auto;\n position: relative;\n }\n table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--hs-font-size);\n color: var(--hs-text);\n }\n thead {\n position: sticky;\n top: 0;\n z-index: 2;\n background: var(--hs-bg);\n }\n th {\n text-align: left;\n padding: 8px 12px;\n border-bottom: 2px solid var(--hs-border);\n color: var(--hs-text-secondary);\n font-weight: 600;\n background: var(--hs-bg);\n font-size: 11px;\n text-transform: uppercase;\n white-space: nowrap;\n }\n th:last-child {\n position: sticky;\n right: 0;\n background: var(--hs-bg);\n box-shadow: -2px 0 4px rgba(0,0,0,0.1);\n }\n td {\n padding: 8px 12px;\n border-bottom: 1px solid var(--hs-border);\n vertical-align: middle;\n }\n tr:hover {\n background: var(--hs-bg-secondary);\n cursor: pointer;\n }\n tr.recently-executed {\n animation: flash-row 1s ease-out;\n }\n @keyframes flash-row {\n 0% { background: rgba(34, 197, 94, 0.2); }\n 100% { background: transparent; }\n }\n .status-flash {\n animation: flash-icon 1s ease-out;\n }\n @keyframes flash-icon {\n 0%, 50% { opacity: 1; }\n 25%, 75% { opacity: 0.3; }\n }\n .tip {\n padding: 12px;\n text-align: center;\n font-size: 11px;\n color: var(--hs-text-secondary);\n border-top: 1px solid var(--hs-border);\n background: var(--hs-bg);\n }\n .task-id {\n font-weight: 600;\n }\n .namespace-badge {\n display: inline-block;\n background: var(--hs-bg-secondary);\n color: var(--hs-text-secondary);\n border: 1px solid var(--hs-border);\n border-radius: 4px;\n padding: 0 4px;\n font-size: 9px;\n margin-left: 6px;\n font-family: monospace;\n vertical-align: middle;\n }\n .tags {\n display: flex;\n gap: 4px;\n margin-top: 4px;\n }\n .tag {\n background: var(--hs-bg-secondary);\n border: 1px solid var(--hs-border);\n border-radius: 10px;\n padding: 2px 8px;\n font-size: 10px;\n color: var(--hs-text-secondary);\n }\n .no-tags {\n font-size: 10px;\n color: var(--hs-text-secondary);\n font-style: italic;\n }\n .driver-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n border-radius: 4px;\n font-size: 11px;\n font-weight: 600;\n font-family: monospace;\n }\n .driver-badge.worker {\n background: rgba(34, 197, 94, 0.15);\n color: var(--hs-success);\n border: 1px solid var(--hs-success);\n }\n .driver-badge.main {\n background: rgba(245, 158, 11, 0.15);\n color: var(--hs-warning);\n border: 1px solid var(--hs-warning);\n }\n .col-num {\n width: 40px;\n color: var(--hs-text-secondary);\n font-size: 11px;\n }\n .col-actions {\n width: 100px;\n position: sticky;\n right: 0;\n background: var(--hs-bg);\n box-shadow: -2px 0 4px rgba(0,0,0,0.1);\n }\n .action-group {\n display: flex;\n gap: 4px;\n }\n .btn-icon {\n background: transparent;\n border: 1px solid var(--hs-border);\n color: var(--hs-text-secondary);\n border-radius: 4px;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n padding: 0;\n flex-shrink: 0;\n }\n .btn-icon svg {\n width: 14px;\n height: 14px;\n display: block;\n }\n .btn-icon:hover {\n background: var(--hs-primary);\n color: white;\n border-color: var(--hs-primary);\n }\n .btn-trigger:hover {\n background: var(--hs-success);\n border-color: var(--hs-success);\n }\n .btn-pause:hover {\n background: var(--hs-warning);\n border-color: var(--hs-warning);\n }\n .btn-resume:hover {\n background: var(--hs-success);\n border-color: var(--hs-success);\n }\n .btn-remove:hover {\n color: white;\n background: var(--hs-danger);\n border-color: var(--hs-danger);\n }\n .btn-icon:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n }\n .btn-icon:disabled:hover {\n background: transparent;\n color: var(--hs-text-secondary);\n border-color: var(--hs-border);\n }\n /* Namespace Styles */\n .namespace-row {\n background: var(--hs-bg-secondary);\n cursor: pointer;\n font-weight: 600;\n user-select: none;\n }\n .namespace-row:hover {\n background: var(--hs-border);\n }\n .namespace-row td {\n padding: 8px 12px;\n border-bottom: 1px solid var(--hs-border);\n }\n .ns-toggle {\n display: inline-block;\n width: 20px;\n text-align: center;\n font-size: 10px;\n color: var(--hs-text-secondary);\n transition: transform 0.2s;\n }\n .ns-icon {\n margin-right: 4px;\n }\n .ns-count {\n font-weight: normal;\n color: var(--hs-text-secondary);\n font-size: 11px;\n margin-left: 4px;\n }\n .nested-task .col-id {\n padding-left: 32px !important;\n }\n </style>\n <div class="table-container">\n <table>\n <thead>\n <tr>\n <th style="width:40px">#</th>\n <th style="min-width:150px">${r("list.idTags")}</th>\n <th style="width:150px">${r("list.status")}</th>\n <th style="width:70px">${r("list.driver")}</th>\n <th style="width:100px">${r("list.schedule")}</th>\n <th style="width:60px">${r("list.count")}</th>\n <th style="width:100px">${r("list.lastRun")}</th>\n <th style="width:100px">${r("list.actions")}</th>\n </tr>\n </thead>\n <tbody>\n \x3c!-- Rows --\x3e\n </tbody>\n </table>\n </div>\n <div class="tip">\n ${r("list.tip")}\n </div>\n `,this._shadow.addEventListener("click",t=>{const e=t.target,s=e.closest(".namespace-row");if(s){const t=s.dataset.ns;return void(t&&(this._expandedNamespaces.has(t)?this._expandedNamespaces.delete(t):this._expandedNamespaces.add(t),this.renderRows()))}const n=e.closest("button");if(n){const t=n.dataset.action,e=n.closest("tr");if(!t||!e)return;const s=e.dataset.id;return void this.dispatchEvent(new CustomEvent("task-action",{detail:{action:t,id:s},bubbles:!0,composed:!0}))}const i=e.closest("tr");if(i&&!e.closest(".col-actions")&&!i.classList.contains("namespace-row")){const t=i.dataset.id;this.dispatchEvent(new CustomEvent("task-select",{detail:t,bubbles:!0,composed:!0}))}})}}customElements.define("hs-task-list",b);class v extends HTMLElement{constructor(){super(),e(this,"_shadow"),e(this,"_task",null),e(this,"_history",[]),this._shadow=this.attachShadow({mode:"open"})}connectedCallback(){this.render(),this._shadow.addEventListener("click",t=>{t.target.closest(".back-btn")&&this.dispatchEvent(new CustomEvent("back"))})}set task(t){this._task=t,this.renderContent()}set history(t){this._history=t||[],this.renderContent()}updateTexts(){this.renderContent()}renderContent(){const t=this._shadow.querySelector(".content");if(!t)return;if(!this._task)return void(t.innerHTML=`<div class="empty">${r("detail.noTask")}</div>`);const e=this._task,s={id:e.id,schedule:e.schedule,tags:e.tags},n=this._history.length>0?Math.round(this._history.reduce((t,e)=>t+e.duration,0)/this._history.length):0;t.innerHTML=`\n <div class="header">\n <button class="back-btn" title="${r("detail.back")}">${d.back}</button>\n <h2>📂 ${e.id}</h2>\n </div>\n \n <div class="section">\n <div class="config-label">${r("detail.config")}:</div>\n <pre>${JSON.stringify(s,null,2)}</pre>\n </div>\n\n <div class="section">\n <h3>📜 ${r("detail.history")} (${r("detail.lastRuns",{n:this._history.length})}) ${n>0?`- ${r("detail.avgDuration")}: ${n}ms`:""}</h3>\n <table class="history-table">\n <thead>\n <tr>\n <th>#</th>\n <th>${r("detail.startTime")}</th>\n <th>${r("detail.duration")}</th>\n <th>${r("detail.drift")}</th>\n <th>${r("detail.status")}</th>\n </tr>\n </thead>\n <tbody>\n ${0===this._history.length?`<tr><td colspan="5" class="no-data">${r("detail.noHistory")}</td></tr>`:""}\n ${this._history.slice().reverse().map((t,e)=>{const s=t.success?`✅ ${r("detail.success")}`:t.error?`❌ ${r("detail.error")}: ${t.error}`:`⚠️ ${r("detail.failed")}`,n=t.duration>100?"slow":"";return`\n <tr class="${t.success?"success":"error"}">\n <td class="col-num">${this._history.length-e}</td>\n <td>${new Date(t.timestamp).toLocaleTimeString("en-US",{hour12:!1})}</td>\n <td class="${n}">${t.duration}ms</td>\n <td>0ms</td>\n <td class="status-cell">${s}</td>\n </tr>\n `}).join("")}\n </tbody>\n </table>\n </div>\n `}render(){this._shadow.innerHTML=`\n <style>\n ${l}\n :host {\n display: block;\n height: 100%;\n background: var(--hs-bg);\n overflow-y: auto;\n }\n .content {\n padding: 16px;\n }\n .header {\n display: flex;\n align-items: center;\n gap: 16px;\n margin-bottom: 24px;\n padding-bottom: 16px;\n border-bottom: 2px solid var(--hs-border);\n }\n .back-btn {\n background: var(--hs-bg-secondary);\n border: 1px solid var(--hs-border);\n color: var(--hs-text);\n padding: 6px 12px;\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n }\n .back-btn:hover {\n background: var(--hs-primary);\n color: white;\n border-color: var(--hs-primary);\n }\n h2 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n }\n h3 {\n font-size: 13px;\n color: var(--hs-text);\n margin-bottom: 12px;\n font-weight: 600;\n }\n .section {\n margin-bottom: 32px;\n }\n .config-label {\n font-size: 12px;\n color: var(--hs-text-secondary);\n margin-bottom: 8px;\n }\n pre {\n background: var(--hs-bg-secondary);\n padding: 12px;\n border-radius: 6px;\n border: 1px solid var(--hs-border);\n font-family: 'Monaco', 'Menlo', monospace;\n font-size: 11px;\n overflow-x: auto;\n line-height: 1.5;\n }\n .history-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 11px;\n }\n .history-table th {\n text-align: left;\n padding: 8px;\n border-bottom: 2px solid var(--hs-border);\n color: var(--hs-text-secondary);\n font-weight: 600;\n background: var(--hs-bg-secondary);\n }\n .history-table td {\n padding: 8px;\n border-bottom: 1px solid var(--hs-border);\n }\n .history-table tr.success {\n background: rgba(34, 197, 94, 0.05);\n }\n .history-table tr.error {\n background: rgba(239, 68, 68, 0.05);\n }\n .history-table tr:hover {\n background: var(--hs-bg-secondary);\n }\n .col-num {\n width: 40px;\n color: var(--hs-text-secondary);\n }\n .slow {\n color: var(--hs-warning);\n font-weight: 600;\n }\n .status-cell {\n font-size: 11px;\n }\n .no-data {\n color: var(--hs-text-secondary);\n font-style: italic;\n text-align: center;\n padding: 24px;\n }\n </style>\n <div class="content"></div>\n `}}customElements.define("hs-task-detail",v);class m extends HTMLElement{constructor(){super(),e(this,"_shadow"),e(this,"_tasks",new Map),e(this,"_history",new Map),e(this,"$canvas"),e(this,"ctx"),e(this,"timeRange",6e4),e(this,"zoom",1),this._shadow=this.attachShadow({mode:"open"})}connectedCallback(){if(this.render(),this.$canvas=this._shadow.querySelector("canvas"),!this.$canvas)return void console.error("[Timeline] Canvas not found");if(this.ctx=this.$canvas.getContext("2d"),!this.ctx)return void console.error("[Timeline] Canvas context not available");this.setupZoom(),this.startLoop();const t=this._shadow.querySelector(".canvas-container");if(t){new ResizeObserver(()=>{requestAnimationFrame(()=>this.draw())}).observe(t)}}set data(t){this._tasks=t.tasks,this._history=t.history}set defaultZoom(t){if(t>=.5&&t<=5){this.zoom=t,this.timeRange=6e4/this.zoom;const e=this._shadow.querySelector(".zoom-slider");e&&(e.value=t.toString()),this.updateZoomLabel()}}updateTexts(){this.updateZoomLabel()}updateZoomLabel(){const t=this._shadow.querySelector(".zoom-label");t&&(t.textContent=`${r("timeline.zoom")}: ${this.zoom}x (${Math.round(this.timeRange/1e3)}s)`)}setupZoom(){const t=this._shadow.querySelector(".zoom-slider"),e=this._shadow.querySelector(".zoom-out"),s=this._shadow.querySelector(".zoom-in"),n=t=>{this.zoom=t,this.timeRange=6e4/this.zoom,this.updateZoomLabel()};null==t||t.addEventListener("input",t=>{const e=parseFloat(t.target.value);n(e)}),null==e||e.addEventListener("click",()=>{const e=Math.max(.5,this.zoom-.5);t&&(t.value=e.toString()),n(e)}),null==s||s.addEventListener("click",()=>{const e=Math.min(5,this.zoom+.5);t&&(t.value=e.toString()),n(e)}),this.updateZoomLabel()}startLoop(){const t=()=>{this.isConnected&&(this.draw(),requestAnimationFrame(t))};requestAnimationFrame(t)}draw(){if(!this.ctx||!this.$canvas)return;const t=this._shadow.querySelector(".canvas-container");if(!t)return;const e=window.devicePixelRatio||1,s=t.clientWidth;if(0===s)return;const n=Array.from(this._tasks.keys()),i=t.clientHeight||300,o=40*n.length+60+40,a=Math.max(i,o);this.$canvas.width=s*e,this.$canvas.height=a*e,this.$canvas.style.width=`${s}px`,this.$canvas.style.height=`${a}px`,this.ctx.setTransform(e,0,0,e,0,0);const r=Date.now(),h=r-this.timeRange,l=getComputedStyle(this),d=l.getPropertyValue("--hs-bg").trim()||"#1e1e1e",c=l.getPropertyValue("--hs-text").trim()||"#fff",p=l.getPropertyValue("--hs-text-secondary").trim()||"#888",g=l.getPropertyValue("--hs-border").trim()||"#333",u=l.getPropertyValue("--hs-success").trim()||"#22c55e",b=l.getPropertyValue("--hs-danger").trim()||"#ef4444";this.ctx.fillStyle=d,this.ctx.fillRect(0,0,s,a),this.drawTimeAxis(s,150,h,p,g),n.forEach((t,e)=>{const n=40*e+60;this.drawTaskRow(t,n,s,150,h,r,c,p,g,u,b)}),this.drawLegend(s,a,p,u)}drawTimeAxis(t,e,s,n,i){const o=this.ctx,a=t-e-20;o.fillStyle=n,o.font="10px monospace",o.textAlign="center";for(let r=0;r<=4;r++){const t=e+a/4*r,n=s+this.timeRange/4*r,h=new Date(n).toLocaleTimeString("en-US",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1});o.fillText(h,t,30),o.strokeStyle=i,o.beginPath(),o.moveTo(t,40),o.lineTo(t,this.$canvas.clientHeight-40),o.stroke()}o.textAlign="left",o.fillText(r("timeline.timeRange",{n:Math.round(this.timeRange/1e3)}),10,15)}drawTaskRow(t,e,s,n,i,o,a,r,h,l,d){const c=this.ctx,p=s-n-20;c.fillStyle=a,c.font="11px sans-serif",c.textAlign="left",c.fillText(t,10,e+15);const g=this._tasks.get(t),u="main"===(null==g?void 0:g.driver)?"M":"W",b="W"===u?"#22c55e":"#f59e0b";c.fillStyle=b,c.font="9px monospace",c.fillText(`[${u}]`,10,e+28),c.strokeStyle=h,c.beginPath(),c.moveTo(0,e+35),c.lineTo(s,e+35),c.stroke();(this._history.get(t)||[]).forEach(t=>{if(t.timestamp<i||t.timestamp>o)return;const s=n+(t.timestamp-i)/this.timeRange*p,a=t.duration;if(a<10)c.fillStyle=t.success?l:d,c.beginPath(),c.arc(s,e+15,3,0,2*Math.PI),c.fill();else{const n=Math.max(2,a/this.timeRange*p);c.fillStyle=t.success?l:d,c.globalAlpha=.7,c.fillRect(s,e+5,n,20),c.globalAlpha=1}})}drawLegend(t,e,s,n){const i=this.ctx,o=e-25;i.font="10px sans-serif",i.textAlign="left",i.fillStyle=s;let a=10;i.fillText(`${r("timeline.legend")}:`,a,o),a+=50,i.fillStyle=n,i.beginPath(),i.arc(a,o-4,3,0,2*Math.PI),i.fill(),i.fillStyle=s,i.fillText(r("timeline.instant"),a+10,o),a+=60,i.fillStyle=n,i.globalAlpha=.7,i.fillRect(a,o-8,15,10),i.globalAlpha=1,i.fillStyle=s,i.fillText(r("timeline.duration"),a+20,o),a+=80,i.fillText(`[W] ${r("timeline.workerDriver")}`,a,o),a+=110,i.fillText(`[M] ${r("timeline.mainDriver")}`,a,o)}render(){this._shadow.innerHTML=`\n <style>\n ${l}\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--hs-bg);\n overflow: hidden;\n }\n .controls {\n display: flex;\n justify-content: flex-end;\n align-items: center;\n padding: 12px 16px;\n gap: 8px;\n border-bottom: 1px solid var(--hs-border);\n flex-shrink: 0;\n }\n .zoom-label {\n font-size: 11px;\n color: var(--hs-text-secondary);\n }\n .zoom-btn {\n background: var(--hs-bg-secondary);\n border: 1px solid var(--hs-border);\n color: var(--hs-text);\n width: 24px;\n height: 24px;\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .zoom-btn:hover {\n background: var(--hs-primary);\n color: white;\n }\n .zoom-slider {\n width: 100px;\n }\n .canvas-container {\n flex: 1;\n overflow: auto;\n position: relative;\n }\n canvas {\n display: block;\n }\n </style>\n <div class="controls">\n <span class="zoom-label">Zoom:</span>\n <button class="zoom-btn zoom-out">-</button>\n <input type="range" class="zoom-slider" min="0.5" max="5" step="0.5" value="1">\n <button class="zoom-btn zoom-in">+</button>\n </div>\n <div class="canvas-container">\n <canvas></canvas>\n </div>\n `}}customElements.define("hs-timeline",m);class y extends HTMLElement{constructor(){super(),e(this,"_shadow"),e(this,"startX",0),e(this,"startY",0),e(this,"startWidth",0),e(this,"startHeight",0),e(this,"panel",null),e(this,"mode","right"),this._shadow=this.attachShadow({mode:"open"})}isMobile(){return window.innerWidth<=480}connectedCallback(){this.render(),this.addEventListeners(),this.panel=this.closest(".panel"),this.panel&&this.panel.classList.contains("dock-bottom")&&(this.mode="bottom")}addEventListeners(){const t=this._shadow.querySelector(".handle"),e=t=>{if(this.panel&&!this.isMobile())if("right"===this.mode){const e=this.startX-t.clientX,s=Math.max(300,Math.min(window.innerWidth-50,this.startWidth+e));this.panel.style.width=`${s}px`,this.dispatchEvent(new CustomEvent("resize",{detail:{width:s},bubbles:!0,composed:!0}))}else{const e=Math.max(200,Math.min(window.innerHeight-50,this.startHeight+(this.startY-t.clientY)));this.panel.style.height=`${e}px`,this.dispatchEvent(new CustomEvent("resize",{detail:{height:e},bubbles:!0,composed:!0}))}},s=()=>{document.removeEventListener("mousemove",e),document.removeEventListener("mouseup",s),document.body.style.userSelect="",document.body.style.cursor=""};t.addEventListener("mousedown",t=>{this.isMobile()||(this.startX=t.clientX,this.startY=t.clientY,this.panel&&(this.panel.classList.contains("dock-bottom")?(this.mode="bottom",this.startHeight=this.panel.offsetHeight):(this.mode="right",this.startWidth=this.panel.offsetWidth)),document.addEventListener("mousemove",e),document.addEventListener("mouseup",s),document.body.style.userSelect="none",document.body.style.cursor="right"===this.mode?"col-resize":"row-resize")})}render(){this._shadow.innerHTML=`\n <style>\n ${l}\n :host {\n display: block;\n z-index: 100;\n }\n .handle {\n background: transparent;\n transition: background 0.2s;\n }\n .handle:hover {\n background: var(--hs-primary);\n }\n \n /* Right Dock Mode (Vertical Handle on Left) */\n :host-context(.dock-right) .handle {\n width: 4px;\n height: 100%;\n cursor: col-resize;\n position: absolute;\n left: 0;\n top: 0;\n }\n\n /* Bottom Dock Mode (Horizontal Handle on Top) */\n :host-context(.dock-bottom) .handle {\n width: 100%;\n height: 4px;\n cursor: row-resize;\n position: absolute;\n top: 0;\n left: 0;\n }\n \n /* 移动端隐藏拖拽手柄 */\n @media (max-width: 480px) {\n .handle {\n display: none;\n }\n }\n </style>\n <div class="handle"></div>\n `}}customElements.define("hs-resizer",y);class x extends HTMLElement{constructor(){super(),e(this,"_shadow"),e(this,"store"),e(this,"scheduler"),e(this,"rAFId"),e(this,"lastTime",0),e(this,"$panel"),e(this,"$header"),e(this,"$taskList"),e(this,"$taskDetail"),e(this,"$timeline"),e(this,"$trigger"),e(this,"$overlay"),this._shadow=this.attachShadow({mode:"open"}),this.store=new h}connectedCallback(){const t=this.getAttribute("language");"en"!==t&&"zh"!==t||this.store.setLanguageSync(t),this.render(),this.cacheDom(),this.bindStore();const e=this.getAttribute("dock");console.log("[DevTools] dock attribute:",e),"bottom"===e&&this.store.setDockPosition("bottom");const s=this.getAttribute("theme");"light"!==s&&"dark"!==s&&"auto"!==s||this.store.setTheme(s),"en"!==t&&"zh"!==t||this.store.setLanguage(t);const n=this.getAttribute("trigger-bg"),i=this.getAttribute("trigger-color"),o=this.getAttribute("trigger-position");console.log("[DevTools] trigger attrs:",{triggerBg:n,triggerColor:i,triggerPosition:o}),n&&this.$trigger.setAttribute("bg-color",n),i&&this.$trigger.setAttribute("text-color",i),o&&this.$trigger.setAttribute("position",o);const a=this.getAttribute("default-zoom");if(a){const t=parseFloat(a);!isNaN(t)&&t>=.5&&t<=5&&(this.$timeline.defaultZoom=t)}this.addEventListeners(),this.startLoop()}disconnectedCallback(){this.rAFId&&cancelAnimationFrame(this.rAFId)}setScheduler(t){this.scheduler=t,this.store.setScheduler(t);this.scheduler.getTasks().forEach(t=>this.store.updateTask(t));const e=this.scheduler.isRunning();this.store.setSchedulerRunning(e);const n=()=>{var t;((null==(t=this.scheduler)?void 0:t.getTasks())||[]).forEach(t=>this.store.updateTask(t))};this.scheduler.on(s.SchedulerEvents.TASK_REGISTERED,n),this.scheduler.on(s.SchedulerEvents.TASK_UPDATED,t=>{console.log("[DevTools] task_updated event:",t),n()}),this.scheduler.on(s.SchedulerEvents.TASK_STARTED,n),this.scheduler.on(s.SchedulerEvents.TASK_REMOVED,n),this.scheduler.on(s.SchedulerEvents.TASK_STOPPED,t=>{console.log("[DevTools] task_stopped event:",t),n()}),this.scheduler.on(s.SchedulerEvents.SCHEDULER_STARTED,()=>{console.log("[DevTools] scheduler_started event"),this.store.setSchedulerRunning(!0),n()}),this.scheduler.on(s.SchedulerEvents.SCHEDULER_STOPPED,()=>{console.log("[DevTools] scheduler_stopped event"),this.store.setSchedulerRunning(!1),n()}),this.scheduler.on(s.SchedulerEvents.TASK_COMPLETED,t=>{var e;n(),t&&t.taskId&&this.store.addHistory(t.taskId,{timestamp:(null==(e=t.task)?void 0:e.lastRun)||Date.now(),duration:t.duration||0,success:!0,error:null})}),this.scheduler.on(s.SchedulerEvents.TASK_FAILED,t=>{var e;n(),t&&t.taskId&&this.store.addHistory(t.taskId,{timestamp:(null==(e=t.task)?void 0:e.lastRun)||Date.now(),duration:t.duration||0,success:!1,error:t.error||"Unknown error"})}),setInterval(()=>{this.store.getState().isOpen&&n()},500)}cacheDom(){this.$panel=this._shadow.querySelector(".panel"),this.$header=this._shadow.querySelector("hs-task-header"),this.$taskList=this._shadow.querySelector("hs-task-list"),this.$taskDetail=this._shadow.querySelector("hs-task-detail"),this.$timeline=this._shadow.querySelector("hs-timeline"),this.$trigger=this._shadow.querySelector("hs-floating-trigger"),this.$overlay=this._shadow.querySelector(".overlay")}bindStore(){try{const t=localStorage.getItem("hs-panel-size");t&&this.store.setPanelSize(JSON.parse(t))}catch(t){}this.store.subscribe("isOpen",t=>{const e=this.store.getState().dockPosition,s=this.store.getState().panelSize;t?(this.$panel.classList.add("open"),this.$trigger.style.display="none",this.$overlay.style.display="block","right"===e?this.$panel.style.right="0":this.$panel.style.bottom="0"):(this.$panel.classList.remove("open"),this.$trigger.style.display="block",this.$overlay.style.display="none","right"===e?this.$panel.style.right=`-${s.width}px`:this.$panel.style.bottom=`-${s.height}px`)}),this.store.subscribe("theme",t=>{const e="auto"===t?"light":t;this.setAttribute("theme",e),this.$header.setAttribute("theme",e),this.$taskList.setAttribute("theme",e),this.$taskDetail.setAttribute("theme",e),this.$timeline.setAttribute("theme",e),this.$header.theme=t}),this.store.subscribe("tasks",t=>{this.$taskList.tasks=t,this.$timeline.data={tasks:t,history:this.store.getState().history};let e=0;t.forEach(t=>{"idle"!==t.status&&"running"!==t.status||e++}),this.$header.stats={active:e,total:t.size};const s=this.store.getState().selectedTaskId;s&&t.has(s)&&(this.$taskDetail.task=t.get(s)||null)}),this.store.subscribe("history",t=>{this.$timeline.data={tasks:this.store.getState().tasks,history:t};const e=this.store.getState().selectedTaskId;e&&(this.$taskDetail.history=t.get(e)||[])}),this.store.subscribe("selectedTaskId",t=>{if("tasks"===this.store.getState().activeTab)if(t){this.$taskList.style.display="none",this.$taskDetail.style.display="block";const e=this.store.getState().tasks.get(t),s=this.store.getState().history.get(t);this.$taskDetail.task=e||null,this.$taskDetail.history=s||[]}else this.$taskList.style.display="block",this.$taskDetail.style.display="none"}),this.store.subscribe("activeTab",t=>{this.$header.activeTab=t,"tasks"===t?(this.$taskList.style.display="block",this.$timeline.style.display="none",this.store.getState().selectedTaskId?(this.$taskList.style.display="none",this.$taskDetail.style.display="block"):(this.$taskList.style.display="block",this.$taskDetail.style.display="none")):(this.$taskList.style.display="none",this.$taskDetail.style.display="none",this.$timeline.style.display="block")}),this.store.subscribe("dockPosition",t=>{this.$header.dockPosition=t;const e=this.store.getState().panelSize,s=this.store.getState().isOpen,n=window.innerWidth<=480;if("right"===t){this.$panel.classList.add("dock-right"),this.$panel.classList.remove("dock-bottom");const t=n?window.innerWidth:e.width;this.$panel.style.width=n?"100vw":`${t}px`,this.$panel.style.height="100vh",this.$panel.style.bottom="",this.$panel.style.right=s?"0":`-${t}px`}else{this.$panel.classList.add("dock-bottom"),this.$panel.classList.remove("dock-right"),this.$panel.style.width="100%";const t=n?"50vh":`${e.height}px`;this.$panel.style.height=t,this.$panel.style.right="",this.$panel.style.bottom=s?"0":n?"-50vh":`-${e.height}px`}}),this.store.subscribe("panelSize",t=>{const e=this.store.getState().dockPosition;"right"===e&&t.width?(this.$panel.style.width=`${t.width}px`,this.$panel.style.right=this.store.getState().isOpen?"0":`-${t.width}px`):"bottom"===e&&t.height&&(this.$panel.style.height=`${t.height}px`,this.$panel.style.bottom=this.store.getState().isOpen?"0":`-${t.height}px`)}),this.store.subscribe("language",t=>{var e,s,n,i;this.$header.language=t,this.$taskList.updateHeaders(),null==(s=(e=this.$taskDetail).updateTexts)||s.call(e),null==(i=(n=this.$timeline).updateTexts)||i.call(n)}),this.store.subscribe("filterText",t=>{const e=this.store.getState().tasks;this.$taskList.filter(t,e)}),this.store.subscribe("schedulerRunning",t=>{this.$header.schedulerRunning=t})}addEventListeners(){this.$trigger.addEventListener("toggle",()=>{this.store.toggle()}),this.$header.addEventListener("close",t=>{t.stopPropagation(),this.store.toggle()}),this.$header.addEventListener("dock-toggle",()=>{const t=this.store.getState().dockPosition;this.store.setDockPosition("right"===t?"bottom":"right")}),this.$header.addEventListener("theme-toggle",t=>{const e=t.detail;this.store.setTheme(e)}),this.$header.addEventListener("lang-toggle",t=>{const e=t.detail;this.store.setLanguage(e)}),this.$header.addEventListener("tab-change",t=>{const e=t.detail;this.store.setTab(e)}),this.$header.addEventListener("search",t=>{const e=t.detail;this.store.setFilterText(e)}),this.$overlay.addEventListener("click",()=>{this.store.toggle()}),this.$taskList.addEventListener("task-select",t=>{const e=t.detail;this.store.selectTask(e)}),this.$taskDetail.addEventListener("back",()=>{this.store.selectTask(null)}),this.$taskList.addEventListener("task-action",t=>{const{action:e,id:s}=t.detail;switch(console.log("[DevTools] task-action:",e,s),e){case"trigger":this.store.triggerTask(s);break;case"stop":this.store.stopTask(s);break;case"start":this.store.startTask(s);break;case"remove":confirm(`Remove task "${s}"?`)&&this.store.removeTask(s)}})}startLoop(){const t=e=>{const s=e-this.lastTime;this.lastTime=e;const n=1e3/s;this.$header&&(this.$header.fps=n),this.rAFId=requestAnimationFrame(t)};this.rAFId=requestAnimationFrame(t)}render(){this._shadow.innerHTML=`\n <style>\n ${l}\n :host {\n font-family: var(--hs-font-family);\n font-size: var(--hs-font-size);\n color: var(--hs-text);\n line-height: var(--hs-line-height);\n }\n .overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n background: rgba(0, 0, 0, 0.5);\n z-index: calc(var(--hs-z-index) - 1); /* 确保在面板之下,但在应用之上 */\n display: none; /* 默认隐藏 */\n }\n .panel {\n position: fixed;\n background: var(--hs-bg);\n box-shadow: var(--hs-shadow);\n z-index: var(--hs-z-index);\n transition: all 0.3s ease;\n display: flex;\n flex-direction: column;\n border-left: 1px solid var(--hs-border);\n }\n /* Default Right Dock */\n .panel.dock-right {\n top: 0;\n right: -500px;\n width: 500px;\n height: 100vh;\n border-left: 1px solid var(--hs-border);\n border-top: none;\n }\n \n /* Bottom Dock */\n .panel.dock-bottom {\n bottom: -50vh;\n left: 0;\n width: 100%;\n height: 50vh;\n max-height: 50vh;\n border-top: 1px solid var(--hs-border);\n border-left: none;\n }\n\n .content {\n flex: 1;\n overflow: hidden;\n position: relative;\n display: flex;\n flex-direction: column;\n }\n .content > * {\n flex: 1;\n min-height: 0;\n }\n \n /* Mobile - 固定尺寸,禁用拖拽 */\n @media (max-width: 480px) {\n .panel.dock-right {\n width: 100vw !important;\n right: -100vw;\n }\n .panel.dock-right.open {\n right: 0;\n }\n .panel.dock-bottom {\n height: 50vh !important;\n max-height: 50vh !important;\n bottom: -50vh;\n }\n .panel.dock-bottom.open {\n bottom: 0;\n }\n }\n </style>\n \n <div class="overlay"></div>\n <hs-floating-trigger></hs-floating-trigger>\n \n <div class="panel dock-right">\n <hs-resizer></hs-resizer>\n <hs-task-header></hs-task-header>\n <div class="content">\n <hs-task-list></hs-task-list>\n <hs-task-detail style="display:none"></hs-task-detail>\n <hs-timeline style="display:none"></hs-timeline>\n </div>\n </div>\n `}}customElements.define("hs-devtools",x),exports.DevTools=x;
|
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"),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-xPwLHcqi.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;
|
|
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-CRTqUH_8.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
|
@@ -936,7 +936,7 @@ class DevTools {
|
|
|
936
936
|
}
|
|
937
937
|
async mount(scheduler) {
|
|
938
938
|
try {
|
|
939
|
-
await import("./devtools-
|
|
939
|
+
await import("./devtools-B029_YOS.js");
|
|
940
940
|
await customElements.whenDefined("hs-devtools");
|
|
941
941
|
this.setupElement(scheduler);
|
|
942
942
|
} catch (e) {
|