hyper-scheduler 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +21 -0
- package/.eslintrc.cjs +26 -0
- package/GEMINI.md +1 -0
- package/README.md +38 -0
- package/docs/.vitepress/config.ts +52 -0
- package/docs/README.md +120 -0
- package/docs/api/devtools.md +232 -0
- package/docs/api/index.md +178 -0
- package/docs/api/scheduler.md +322 -0
- package/docs/api/task.md +439 -0
- package/docs/api/types.md +365 -0
- package/docs/examples/index.md +295 -0
- package/docs/guide/best-practices.md +436 -0
- package/docs/guide/core-concepts.md +363 -0
- package/docs/guide/getting-started.md +138 -0
- package/docs/index.md +33 -0
- package/docs/public/logo.svg +54 -0
- package/examples/browser/index.html +354 -0
- package/examples/node/simple.js +36 -0
- package/examples/react-demo/index.html +12 -0
- package/examples/react-demo/package.json +23 -0
- package/examples/react-demo/src/App.css +212 -0
- package/examples/react-demo/src/App.jsx +160 -0
- package/examples/react-demo/src/main.jsx +9 -0
- package/examples/react-demo/vite.config.ts +12 -0
- package/examples/react-demo/yarn.lock +752 -0
- package/examples/vue-demo/index.html +12 -0
- package/examples/vue-demo/package.json +21 -0
- package/examples/vue-demo/src/App.vue +373 -0
- package/examples/vue-demo/src/main.ts +4 -0
- package/examples/vue-demo/vite.config.ts +13 -0
- package/examples/vue-demo/yarn.lock +375 -0
- package/package.json +51 -0
- package/src/constants.ts +18 -0
- package/src/core/retry-strategy.ts +28 -0
- package/src/core/scheduler.ts +601 -0
- package/src/core/task-registry.ts +58 -0
- package/src/index.ts +74 -0
- package/src/platform/browser/browser-timer.ts +66 -0
- package/src/platform/browser/main-thread-timer.ts +16 -0
- package/src/platform/browser/worker.ts +31 -0
- package/src/platform/node/debug-cli.ts +19 -0
- package/src/platform/node/node-timer.ts +15 -0
- package/src/platform/timer-strategy.ts +19 -0
- package/src/plugins/dev-tools.ts +101 -0
- package/src/types.ts +115 -0
- package/src/ui/components/devtools.ts +525 -0
- package/src/ui/components/floating-trigger.ts +102 -0
- package/src/ui/components/icons.ts +16 -0
- package/src/ui/components/resizer.ts +129 -0
- package/src/ui/components/task-detail.ts +228 -0
- package/src/ui/components/task-header.ts +319 -0
- package/src/ui/components/task-list.ts +416 -0
- package/src/ui/components/timeline.ts +364 -0
- package/src/ui/debug-panel.ts +56 -0
- package/src/ui/i18n/en.ts +76 -0
- package/src/ui/i18n/index.ts +42 -0
- package/src/ui/i18n/zh.ts +76 -0
- package/src/ui/store/dev-tools-store.ts +191 -0
- package/src/ui/styles/theme.css.ts +56 -0
- package/src/ui/styles.ts +43 -0
- package/src/utils/cron-lite.ts +221 -0
- package/src/utils/cron.ts +20 -0
- package/src/utils/id.ts +10 -0
- package/src/utils/schedule.ts +93 -0
- package/src/vite-env.d.ts +1 -0
- package/stats.html +4949 -0
- package/tests/integration/Debug.test.ts +58 -0
- package/tests/unit/Plugin.test.ts +16 -0
- package/tests/unit/RetryStrategy.test.ts +21 -0
- package/tests/unit/Scheduler.test.ts +38 -0
- package/tests/unit/schedule.test.ts +70 -0
- package/tests/unit/ui/DevToolsStore.test.ts +67 -0
- package/tsconfig.json +28 -0
- package/vite.config.ts +51 -0
- package/vitest.config.ts +24 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Scheduler as CoreScheduler, TimerStrategyFactory } from './core/scheduler';
|
|
2
|
+
import { SchedulerConfig } from './types';
|
|
3
|
+
import { NodeTimer } from './platform/node/node-timer';
|
|
4
|
+
import { BrowserTimer } from './platform/browser/browser-timer';
|
|
5
|
+
import { MainThreadTimer } from './platform/browser/main-thread-timer';
|
|
6
|
+
import { TimerStrategy } from './platform/timer-strategy';
|
|
7
|
+
import { DevTools } from './plugins/dev-tools';
|
|
8
|
+
import { TaskStatus, SchedulerEvents } from './constants';
|
|
9
|
+
|
|
10
|
+
// Determine environment
|
|
11
|
+
const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
|
|
12
|
+
|
|
13
|
+
// 缓存定时器策略实例
|
|
14
|
+
let workerTimerInstance: BrowserTimer | null = null;
|
|
15
|
+
let mainTimerInstance: MainThreadTimer | null = null;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 获取默认的定时器策略
|
|
19
|
+
*/
|
|
20
|
+
function getDefaultTimerStrategy(config?: SchedulerConfig): TimerStrategy {
|
|
21
|
+
if (isBrowser) {
|
|
22
|
+
const driver = config?.driver || 'worker';
|
|
23
|
+
if (driver === 'main') {
|
|
24
|
+
if (!mainTimerInstance) mainTimerInstance = new MainThreadTimer();
|
|
25
|
+
return mainTimerInstance;
|
|
26
|
+
}
|
|
27
|
+
if (!workerTimerInstance) workerTimerInstance = new BrowserTimer();
|
|
28
|
+
return workerTimerInstance;
|
|
29
|
+
}
|
|
30
|
+
return new NodeTimer();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 创建定时器策略工厂(仅浏览器环境有效)
|
|
35
|
+
*/
|
|
36
|
+
function createTimerStrategyFactory(): TimerStrategyFactory | undefined {
|
|
37
|
+
if (!isBrowser) return undefined;
|
|
38
|
+
|
|
39
|
+
return (driver: 'worker' | 'main'): TimerStrategy => {
|
|
40
|
+
if (driver === 'main') {
|
|
41
|
+
if (!mainTimerInstance) mainTimerInstance = new MainThreadTimer();
|
|
42
|
+
return mainTimerInstance;
|
|
43
|
+
}
|
|
44
|
+
if (!workerTimerInstance) workerTimerInstance = new BrowserTimer();
|
|
45
|
+
return workerTimerInstance;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Hyper Scheduler 主入口类。
|
|
51
|
+
* 自动根据运行环境(浏览器或 Node.js)选择合适的计时策略。
|
|
52
|
+
*
|
|
53
|
+
* 支持两级 driver 配置:
|
|
54
|
+
* 1. 全局配置:new Scheduler({ driver: 'worker' | 'main' })
|
|
55
|
+
* 2. 任务级配置:createTask({ options: { driver: 'worker' | 'main' } })
|
|
56
|
+
*
|
|
57
|
+
* 任务级配置优先于全局配置。
|
|
58
|
+
*/
|
|
59
|
+
export class Scheduler extends CoreScheduler {
|
|
60
|
+
/**
|
|
61
|
+
* 创建调度器实例。
|
|
62
|
+
* @param config 配置项
|
|
63
|
+
*/
|
|
64
|
+
constructor(config?: SchedulerConfig) {
|
|
65
|
+
super(
|
|
66
|
+
getDefaultTimerStrategy(config),
|
|
67
|
+
config,
|
|
68
|
+
createTimerStrategyFactory()
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export * from './types';
|
|
74
|
+
export { CoreScheduler, DevTools, TaskStatus, SchedulerEvents };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { TimerStrategy } from '../timer-strategy';
|
|
2
|
+
// Import the worker as a URL or constructor depending on Vite config.
|
|
3
|
+
// For library mode, it is often safer to inline or assume a specific loading strategy.
|
|
4
|
+
// Here we use Vite's worker import query.
|
|
5
|
+
import Worker from './worker?worker&inline';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 浏览器环境下的计时策略实现。
|
|
9
|
+
* 使用 Web Worker 来运行计时循环,以避免后台标签页的节流限制。
|
|
10
|
+
*/
|
|
11
|
+
export class BrowserTimer implements TimerStrategy {
|
|
12
|
+
private worker: Worker;
|
|
13
|
+
private callbacks: Map<number, () => void>;
|
|
14
|
+
private nextId: number;
|
|
15
|
+
|
|
16
|
+
constructor() {
|
|
17
|
+
// Fallback for environments without Worker (like JSDOM during tests if not mocked)
|
|
18
|
+
// In a real browser, Worker should exist.
|
|
19
|
+
if (typeof Worker !== 'undefined') {
|
|
20
|
+
this.worker = new Worker();
|
|
21
|
+
} else {
|
|
22
|
+
// Minimal mock for SSR/Test env if not provided
|
|
23
|
+
this.worker = {
|
|
24
|
+
postMessage: () => {},
|
|
25
|
+
onmessage: null,
|
|
26
|
+
terminate: () => {},
|
|
27
|
+
addEventListener: () => {},
|
|
28
|
+
removeEventListener: () => {},
|
|
29
|
+
dispatchEvent: () => false
|
|
30
|
+
} as unknown as Worker;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this.callbacks = new Map();
|
|
34
|
+
this.nextId = 1;
|
|
35
|
+
|
|
36
|
+
this.worker.onmessage = (e: MessageEvent) => {
|
|
37
|
+
const { id, type } = e.data;
|
|
38
|
+
if (type === 'tick') {
|
|
39
|
+
const callback = this.callbacks.get(id);
|
|
40
|
+
if (callback) {
|
|
41
|
+
callback();
|
|
42
|
+
this.callbacks.delete(id);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 安排一个定时任务。
|
|
50
|
+
* 向 Web Worker 发送消息以注册计时器。
|
|
51
|
+
*/
|
|
52
|
+
schedule(callback: () => void, delay: number): number {
|
|
53
|
+
const id = this.nextId++;
|
|
54
|
+
this.callbacks.set(id, callback);
|
|
55
|
+
this.worker.postMessage({ id, delay, type: 'schedule' });
|
|
56
|
+
return id;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 取消一个定时任务。
|
|
61
|
+
*/
|
|
62
|
+
cancel(handle: number): void {
|
|
63
|
+
this.worker.postMessage({ id: handle, type: 'cancel' });
|
|
64
|
+
this.callbacks.delete(handle);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TimerStrategy } from '../timer-strategy';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 浏览器环境下的主线程计时策略实现。
|
|
5
|
+
* 使用原生的 setTimeout/clearTimeout,运行在主线程上。
|
|
6
|
+
* 注意:在后台标签页中可能受到浏览器节流限制。
|
|
7
|
+
*/
|
|
8
|
+
export class MainThreadTimer implements TimerStrategy {
|
|
9
|
+
schedule(callback: () => void, delay: number): number {
|
|
10
|
+
return window.setTimeout(callback, delay) as unknown as number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
cancel(handle: number): void {
|
|
14
|
+
window.clearTimeout(handle);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/* eslint-disable no-restricted-globals */
|
|
2
|
+
/**
|
|
3
|
+
* Web Worker 脚本。
|
|
4
|
+
* 用于在后台线程中运行计时器,避免主线程阻塞或页面后台节流影响计时精度。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
interface TimerMessage {
|
|
8
|
+
id: number;
|
|
9
|
+
delay: number;
|
|
10
|
+
type: 'schedule' | 'cancel';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const timers = new Map<number, number>();
|
|
14
|
+
|
|
15
|
+
self.onmessage = (e: MessageEvent<TimerMessage>) => {
|
|
16
|
+
const { id, delay, type } = e.data;
|
|
17
|
+
|
|
18
|
+
if (type === 'schedule') {
|
|
19
|
+
const timerId = self.setTimeout(() => {
|
|
20
|
+
self.postMessage({ id, type: 'tick' });
|
|
21
|
+
timers.delete(id);
|
|
22
|
+
}, delay);
|
|
23
|
+
timers.set(id, timerId);
|
|
24
|
+
} else if (type === 'cancel') {
|
|
25
|
+
const timerId = timers.get(id);
|
|
26
|
+
if (timerId !== undefined) {
|
|
27
|
+
self.clearTimeout(timerId);
|
|
28
|
+
timers.delete(id);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Task } from '../../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Node.js 环境下的调试 CLI 工具。
|
|
5
|
+
* 用于在控制台输出任务状态表格。
|
|
6
|
+
*/
|
|
7
|
+
export class DebugCLI {
|
|
8
|
+
static logTaskUpdate(tasks: Task[]): void {
|
|
9
|
+
console.clear();
|
|
10
|
+
console.log('--- Hyper Scheduler Status ---');
|
|
11
|
+
console.table(tasks.map(t => ({
|
|
12
|
+
ID: t.id,
|
|
13
|
+
Status: t.status,
|
|
14
|
+
Schedule: t.schedule,
|
|
15
|
+
NextRun: t.nextRun ? new Date(t.nextRun).toISOString() : 'N/A',
|
|
16
|
+
LastRun: t.lastRun ? new Date(t.lastRun).toISOString() : 'N/A'
|
|
17
|
+
})));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { TimerStrategy } from '../timer-strategy';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Node.js 环境下的计时策略实现。
|
|
5
|
+
* 简单包装了原生的 setTimeout 和 clearTimeout。
|
|
6
|
+
*/
|
|
7
|
+
export class NodeTimer implements TimerStrategy {
|
|
8
|
+
schedule(callback: () => void, delay: number): NodeJS.Timeout {
|
|
9
|
+
return setTimeout(callback, delay);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
cancel(handle: NodeJS.Timeout): void {
|
|
13
|
+
clearTimeout(handle);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 计时策略接口。
|
|
3
|
+
* 定义了跨平台计时器(Node.js 和 浏览器)的统一接口。
|
|
4
|
+
*/
|
|
5
|
+
export interface TimerStrategy {
|
|
6
|
+
/**
|
|
7
|
+
* 安排一个回调函数在指定延迟后执行。
|
|
8
|
+
* @param callback 回调函数
|
|
9
|
+
* @param delay 延迟毫秒数
|
|
10
|
+
* @returns 用于取消定时器的句柄 (Handle)
|
|
11
|
+
*/
|
|
12
|
+
schedule(callback: () => void, delay: number): any;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 取消一个已安排的定时器。
|
|
16
|
+
* @param handle schedule 方法返回的句柄
|
|
17
|
+
*/
|
|
18
|
+
cancel(handle: any): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Scheduler } from '../core/scheduler';
|
|
2
|
+
import { DevToolsOptions, HyperSchedulerPlugin } from '../types';
|
|
3
|
+
import { TaskStatus } from '../constants';
|
|
4
|
+
|
|
5
|
+
export class DevTools implements HyperSchedulerPlugin {
|
|
6
|
+
name = 'DevTools';
|
|
7
|
+
private options: DevToolsOptions;
|
|
8
|
+
|
|
9
|
+
constructor(options: DevToolsOptions = {}) {
|
|
10
|
+
this.options = options;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
init(scheduler: Scheduler): void {
|
|
14
|
+
if (typeof window === 'undefined' || typeof window.document === 'undefined') {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
this.mount(scheduler);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private async mount(scheduler: Scheduler): Promise<void> {
|
|
22
|
+
try {
|
|
23
|
+
// Import the UI component definition (side effect: defines <hs-devtools>)
|
|
24
|
+
await import('../ui/components/devtools');
|
|
25
|
+
|
|
26
|
+
// Wait for custom element to be defined
|
|
27
|
+
await customElements.whenDefined('hs-devtools');
|
|
28
|
+
|
|
29
|
+
this.setupElement(scheduler);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
console.error('[DevTools] Failed to mount:', e);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private setupElement(scheduler: Scheduler): void {
|
|
36
|
+
try {
|
|
37
|
+
// Check DOM - always create new element to ensure clean state
|
|
38
|
+
let el = document.querySelector('hs-devtools') as any;
|
|
39
|
+
if (el) {
|
|
40
|
+
// Remove existing element to ensure fresh initialization
|
|
41
|
+
el.remove();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Create new element
|
|
45
|
+
el = document.createElement('hs-devtools');
|
|
46
|
+
|
|
47
|
+
// IMPORTANT: Apply options BEFORE adding to DOM
|
|
48
|
+
// so that connectedCallback can read the attributes
|
|
49
|
+
const options = this.options;
|
|
50
|
+
console.log('[DevTools Plugin] options:', JSON.stringify(options));
|
|
51
|
+
if (options.theme) el.setAttribute('theme', options.theme);
|
|
52
|
+
if (options.dockPosition) el.setAttribute('dock', options.dockPosition);
|
|
53
|
+
if (options.language) el.setAttribute('language', options.language);
|
|
54
|
+
if (options.defaultZoom) el.setAttribute('default-zoom', options.defaultZoom.toString());
|
|
55
|
+
if (options.trigger) {
|
|
56
|
+
if (options.trigger.backgroundColor) el.setAttribute('trigger-bg', options.trigger.backgroundColor);
|
|
57
|
+
if (options.trigger.textColor) el.setAttribute('trigger-color', options.trigger.textColor);
|
|
58
|
+
if (options.trigger.position) el.setAttribute('trigger-position', options.trigger.position);
|
|
59
|
+
}
|
|
60
|
+
console.log('[DevTools Plugin] attributes set:', el.getAttribute('dock'), el.getAttribute('trigger-position'));
|
|
61
|
+
|
|
62
|
+
// Add to DOM - connectedCallback will be called with attributes already set
|
|
63
|
+
document.body.appendChild(el);
|
|
64
|
+
|
|
65
|
+
// Set scheduler API adapter
|
|
66
|
+
// We need to wait for the element to upgrade if it hasn't already?
|
|
67
|
+
// import() promise resolution should mean the script is executed and custom element defined.
|
|
68
|
+
|
|
69
|
+
if (typeof el.setScheduler === 'function') {
|
|
70
|
+
el.setScheduler({
|
|
71
|
+
getTasks: () => {
|
|
72
|
+
return scheduler.getAllTasks().map(task => ({
|
|
73
|
+
id: task.id,
|
|
74
|
+
status: task.status,
|
|
75
|
+
lastRun: task.lastRun || null,
|
|
76
|
+
nextRun: task.nextRun || null,
|
|
77
|
+
executionCount: task.executionCount || 0,
|
|
78
|
+
schedule: task.schedule,
|
|
79
|
+
tags: task.tags || [],
|
|
80
|
+
error: task.status === TaskStatus.ERROR ? 'Execution failed' : null,
|
|
81
|
+
driver: scheduler.getTaskDriver(task.id)
|
|
82
|
+
}));
|
|
83
|
+
},
|
|
84
|
+
on: (evt: string, handler: (payload: any) => void) => {
|
|
85
|
+
return scheduler.on(evt, handler);
|
|
86
|
+
},
|
|
87
|
+
isRunning: () => scheduler.isRunning(),
|
|
88
|
+
trigger: (id: string) => scheduler.triggerTask(id),
|
|
89
|
+
pause: (id: string) => scheduler.stopTask(id),
|
|
90
|
+
resume: (id: string) => scheduler.startTask(id),
|
|
91
|
+
remove: (id: string) => scheduler.deleteTask(id)
|
|
92
|
+
});
|
|
93
|
+
} else {
|
|
94
|
+
console.warn('[DevTools] hs-devtools element does not have setScheduler method.');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
} catch (e) {
|
|
98
|
+
console.error('[DevTools] Failed to setup element:', e);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { TaskStatus as TaskStatusEnum } from './constants';
|
|
2
|
+
|
|
3
|
+
export type TaskStatus = typeof TaskStatusEnum[keyof typeof TaskStatusEnum];
|
|
4
|
+
|
|
5
|
+
export interface ExecutionRecord {
|
|
6
|
+
timestamp: number;
|
|
7
|
+
duration: number;
|
|
8
|
+
success: boolean;
|
|
9
|
+
error?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface TaskOptions {
|
|
13
|
+
retry?: {
|
|
14
|
+
maxAttempts: number;
|
|
15
|
+
initialDelay: number;
|
|
16
|
+
factor?: number;
|
|
17
|
+
};
|
|
18
|
+
timezone?: string;
|
|
19
|
+
/** 任务执行失败时的错误处理回调 */
|
|
20
|
+
onError?: (error: Error, taskId: string) => void;
|
|
21
|
+
/**
|
|
22
|
+
* 定时器驱动方式(仅浏览器环境有效)
|
|
23
|
+
* - 'worker': 使用 Web Worker(默认,更精确,不受后台节流影响)
|
|
24
|
+
* - 'main': 使用主线程 setTimeout(更简单,但可能受后台节流影响)
|
|
25
|
+
* 如果不指定,则使用调度器全局配置
|
|
26
|
+
*/
|
|
27
|
+
driver?: 'worker' | 'main';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface TaskDefinition {
|
|
31
|
+
id: string;
|
|
32
|
+
/**
|
|
33
|
+
* 任务调度规则。
|
|
34
|
+
* 支持:
|
|
35
|
+
* 1. Cron 表达式 (例如: "*\/5 * * * * *")
|
|
36
|
+
* 2. 间隔字符串 (例如: "10s", "5m", "1h")
|
|
37
|
+
*/
|
|
38
|
+
schedule: string;
|
|
39
|
+
handler: () => void | Promise<void>;
|
|
40
|
+
options?: TaskOptions;
|
|
41
|
+
tags?: string[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface Task extends TaskDefinition {
|
|
45
|
+
status: TaskStatus;
|
|
46
|
+
lastRun?: number;
|
|
47
|
+
nextRun?: number;
|
|
48
|
+
history: ExecutionRecord[];
|
|
49
|
+
tags?: string[];
|
|
50
|
+
executionCount?: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface SchedulerConfig {
|
|
54
|
+
debug?: boolean;
|
|
55
|
+
maxHistory?: number;
|
|
56
|
+
timezone?: string; // e.g., 'Asia/Shanghai'
|
|
57
|
+
plugins?: HyperSchedulerPlugin[];
|
|
58
|
+
/**
|
|
59
|
+
* 定时器驱动方式(仅浏览器环境有效)
|
|
60
|
+
* - 'worker': 使用 Web Worker(默认,更精确,不受后台节流影响)
|
|
61
|
+
* - 'main': 使用主线程 setTimeout(更简单,但可能受后台节流影响)
|
|
62
|
+
*/
|
|
63
|
+
driver?: 'worker' | 'main';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface HyperSchedulerPlugin {
|
|
67
|
+
name: string;
|
|
68
|
+
init(scheduler: any, options?: any): void;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
export interface TaskSnapshot {
|
|
73
|
+
id: string;
|
|
74
|
+
status: string;
|
|
75
|
+
lastRun: number | null;
|
|
76
|
+
nextRun: number | null;
|
|
77
|
+
executionCount: number;
|
|
78
|
+
schedule: string;
|
|
79
|
+
tags: string[];
|
|
80
|
+
error: string | null;
|
|
81
|
+
driver: 'worker' | 'main';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface DevToolsOptions {
|
|
85
|
+
/** 主题模式 */
|
|
86
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
87
|
+
/** 面板停靠位置 */
|
|
88
|
+
dockPosition?: 'right' | 'bottom';
|
|
89
|
+
/** 界面语言 */
|
|
90
|
+
language?: 'en' | 'zh';
|
|
91
|
+
/** 时间线默认缩放级别 (0.5-5) */
|
|
92
|
+
defaultZoom?: number;
|
|
93
|
+
/** 悬浮按钮配置 */
|
|
94
|
+
trigger?: {
|
|
95
|
+
/** 背景色 */
|
|
96
|
+
backgroundColor?: string;
|
|
97
|
+
/** 文字/图标颜色 */
|
|
98
|
+
textColor?: string;
|
|
99
|
+
/** 位置 */
|
|
100
|
+
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface TaskControlAPI {
|
|
105
|
+
trigger(taskId: string): Promise<void>;
|
|
106
|
+
pause(taskId: string): void;
|
|
107
|
+
resume(taskId: string): void;
|
|
108
|
+
remove(taskId: string): void;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface SchedulerIntrospectionAPI {
|
|
112
|
+
getTasks(): TaskSnapshot[];
|
|
113
|
+
on(event: string, handler: (data: any) => void): () => void;
|
|
114
|
+
isRunning(): boolean;
|
|
115
|
+
}
|