stelo 1.0.1
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/LICENSE +184 -0
- package/README.md +853 -0
- package/dist/accessibility.d.ts +227 -0
- package/dist/accessibility.d.ts.map +1 -0
- package/dist/accessibility.js +602 -0
- package/dist/accessibility.js.map +1 -0
- package/dist/agent.d.ts +870 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +1107 -0
- package/dist/agent.js.map +1 -0
- package/dist/audio-stream.d.ts +114 -0
- package/dist/audio-stream.d.ts.map +1 -0
- package/dist/audio-stream.js +167 -0
- package/dist/audio-stream.js.map +1 -0
- package/dist/clipboard.d.ts +99 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +352 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/config.d.ts +183 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +477 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +213 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +387 -0
- package/dist/context.js.map +1 -0
- package/dist/cortex.d.ts +548 -0
- package/dist/cortex.d.ts.map +1 -0
- package/dist/cortex.js +1479 -0
- package/dist/cortex.js.map +1 -0
- package/dist/errors.d.ts +133 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +278 -0
- package/dist/errors.js.map +1 -0
- package/dist/events.d.ts +227 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +429 -0
- package/dist/events.js.map +1 -0
- package/dist/executor.d.ts +212 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +545 -0
- package/dist/executor.js.map +1 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +167 -0
- package/dist/index.js.map +1 -0
- package/dist/integration.d.ts +159 -0
- package/dist/integration.d.ts.map +1 -0
- package/dist/integration.js +533 -0
- package/dist/integration.js.map +1 -0
- package/dist/keyboard.d.ts +276 -0
- package/dist/keyboard.d.ts.map +1 -0
- package/dist/keyboard.js +404 -0
- package/dist/keyboard.js.map +1 -0
- package/dist/logger.d.ts +198 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +516 -0
- package/dist/logger.js.map +1 -0
- package/dist/middleware.d.ts +183 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +493 -0
- package/dist/middleware.js.map +1 -0
- package/dist/monitor.d.ts +136 -0
- package/dist/monitor.d.ts.map +1 -0
- package/dist/monitor.js +341 -0
- package/dist/monitor.js.map +1 -0
- package/dist/mouse.d.ts +290 -0
- package/dist/mouse.d.ts.map +1 -0
- package/dist/mouse.js +466 -0
- package/dist/mouse.js.map +1 -0
- package/dist/plugin.d.ts +157 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +409 -0
- package/dist/plugin.js.map +1 -0
- package/dist/process.d.ts +106 -0
- package/dist/process.d.ts.map +1 -0
- package/dist/process.js +326 -0
- package/dist/process.js.map +1 -0
- package/dist/recorder.d.ts +100 -0
- package/dist/recorder.d.ts.map +1 -0
- package/dist/recorder.js +258 -0
- package/dist/recorder.js.map +1 -0
- package/dist/safety.d.ts +59 -0
- package/dist/safety.d.ts.map +1 -0
- package/dist/safety.js +98 -0
- package/dist/safety.js.map +1 -0
- package/dist/scheduler.d.ts +152 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +615 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/screen.d.ts +96 -0
- package/dist/screen.d.ts.map +1 -0
- package/dist/screen.js +154 -0
- package/dist/screen.js.map +1 -0
- package/dist/session.d.ts +209 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +479 -0
- package/dist/session.js.map +1 -0
- package/dist/stream.d.ts +168 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +298 -0
- package/dist/stream.js.map +1 -0
- package/dist/telemetry.d.ts +223 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +433 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/types.d.ts +165 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/bezier.d.ts +51 -0
- package/dist/utils/bezier.d.ts.map +1 -0
- package/dist/utils/bezier.js +117 -0
- package/dist/utils/bezier.js.map +1 -0
- package/dist/utils/helpers.d.ts +90 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +143 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/validation.d.ts +254 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +478 -0
- package/dist/validation.js.map +1 -0
- package/dist/vision.d.ts +719 -0
- package/dist/vision.d.ts.map +1 -0
- package/dist/vision.js +1197 -0
- package/dist/vision.js.map +1 -0
- package/dist/window.d.ts +80 -0
- package/dist/window.d.ts.map +1 -0
- package/dist/window.js +170 -0
- package/dist/window.js.map +1 -0
- package/dist/workflow.d.ts +224 -0
- package/dist/workflow.d.ts.map +1 -0
- package/dist/workflow.js +578 -0
- package/dist/workflow.js.map +1 -0
- package/index.d.ts +840 -0
- package/index.js +495 -0
- package/package.json +91 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
export type ActionType = 'mouse.move' | 'mouse.moveSmoothly' | 'mouse.moveHumanized' | 'mouse.click' | 'mouse.doubleClick' | 'mouse.tripleClick' | 'mouse.down' | 'mouse.up' | 'mouse.scroll' | 'mouse.drag' | 'mouse.clickAt' | 'keyboard.type' | 'keyboard.typeHumanized' | 'keyboard.typeBatch' | 'keyboard.press' | 'keyboard.down' | 'keyboard.up' | 'keyboard.hotkey' | 'keyboard.sequence' | 'screen.capture' | 'screen.pixelColor' | 'window.focus' | 'window.resize' | 'window.move' | 'window.close' | 'agent.batch' | 'agent.clickAndVerify' | 'custom' | string;
|
|
2
|
+
/** Context passed to middleware at each stage */
|
|
3
|
+
export interface MiddlewareContext {
|
|
4
|
+
/** The action type being performed */
|
|
5
|
+
action: ActionType;
|
|
6
|
+
/** Arguments passed to the action */
|
|
7
|
+
args: unknown[];
|
|
8
|
+
/** Timestamp when the action was initiated */
|
|
9
|
+
timestamp: string;
|
|
10
|
+
/** Arbitrary metadata (middleware can read/write) */
|
|
11
|
+
metadata: Record<string, unknown>;
|
|
12
|
+
/** Set to true to skip the action entirely */
|
|
13
|
+
skip: boolean;
|
|
14
|
+
/** Error info (set by 'after' if action failed) */
|
|
15
|
+
error?: Error;
|
|
16
|
+
/** Result (set by 'after' if action succeeded) */
|
|
17
|
+
result?: unknown;
|
|
18
|
+
/** Duration (set by 'after') */
|
|
19
|
+
durationMs?: number;
|
|
20
|
+
/** Was the action modified by middleware? */
|
|
21
|
+
modified: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** Middleware function signature */
|
|
24
|
+
export type MiddlewareFn = (ctx: MiddlewareContext, next: () => void | Promise<void>) => void | Promise<void>;
|
|
25
|
+
export interface Middleware {
|
|
26
|
+
/** Unique name */
|
|
27
|
+
name: string;
|
|
28
|
+
/** Description */
|
|
29
|
+
description?: string;
|
|
30
|
+
/** Priority (higher = runs first). Default: 0 */
|
|
31
|
+
priority: number;
|
|
32
|
+
/** Which actions this middleware applies to (empty = all) */
|
|
33
|
+
actions: ActionType[];
|
|
34
|
+
/** The before-action hook */
|
|
35
|
+
before?: MiddlewareFn;
|
|
36
|
+
/** The after-action hook */
|
|
37
|
+
after?: MiddlewareFn;
|
|
38
|
+
/** Enabled? */
|
|
39
|
+
enabled: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface MiddlewarePipelineOptions {
|
|
42
|
+
/** Enable pipeline? Default: true */
|
|
43
|
+
enabled?: boolean;
|
|
44
|
+
/** Log middleware execution? Default: false */
|
|
45
|
+
debug?: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface BoundaryRegion {
|
|
48
|
+
x: number;
|
|
49
|
+
y: number;
|
|
50
|
+
width: number;
|
|
51
|
+
height: number;
|
|
52
|
+
}
|
|
53
|
+
export interface BoundaryPolicyOptions {
|
|
54
|
+
/** The region the mouse must stay within */
|
|
55
|
+
region: BoundaryRegion;
|
|
56
|
+
/** What to do when boundary is violated: 'clamp' | 'block' | 'warn' */
|
|
57
|
+
mode?: 'clamp' | 'block' | 'warn';
|
|
58
|
+
/** Priority. Default: 100 (very high, runs before most middleware) */
|
|
59
|
+
priority?: number;
|
|
60
|
+
}
|
|
61
|
+
/** Create a boundary enforcement middleware */
|
|
62
|
+
export declare function boundaryPolicy(options: BoundaryPolicyOptions): Middleware;
|
|
63
|
+
export interface RatePolicyOptions {
|
|
64
|
+
/** Maximum actions per period */
|
|
65
|
+
maxActions: number;
|
|
66
|
+
/** Period in ms (default: 1000) */
|
|
67
|
+
periodMs?: number;
|
|
68
|
+
/** Actions to rate limit (empty = all) */
|
|
69
|
+
actions?: ActionType[];
|
|
70
|
+
/** What to do when rate exceeded: 'block' | 'delay' */
|
|
71
|
+
mode?: 'block' | 'delay';
|
|
72
|
+
/** Priority. Default: 90 */
|
|
73
|
+
priority?: number;
|
|
74
|
+
}
|
|
75
|
+
/** Create a rate-limiting middleware */
|
|
76
|
+
export declare function ratePolicy(options: RatePolicyOptions): Middleware;
|
|
77
|
+
export interface CooldownPolicyOptions {
|
|
78
|
+
/** Cooldown period in ms between same action types */
|
|
79
|
+
cooldownMs: number;
|
|
80
|
+
/** Actions to apply cooldown to (empty = all) */
|
|
81
|
+
actions?: ActionType[];
|
|
82
|
+
/** Priority. Default: 80 */
|
|
83
|
+
priority?: number;
|
|
84
|
+
}
|
|
85
|
+
/** Create a cooldown middleware — prevents rapid repeat of same action type */
|
|
86
|
+
export declare function cooldownPolicy(options: CooldownPolicyOptions): Middleware;
|
|
87
|
+
export interface LoggingMiddlewareOptions {
|
|
88
|
+
/** Log level for actions. Default: 'debug' */
|
|
89
|
+
level?: 'trace' | 'debug' | 'info';
|
|
90
|
+
/** Include action args in logs? Default: false */
|
|
91
|
+
includeArgs?: boolean;
|
|
92
|
+
/** Include results in logs? Default: false */
|
|
93
|
+
includeResults?: boolean;
|
|
94
|
+
/** Priority. Default: -100 (very low, runs last before) */
|
|
95
|
+
priority?: number;
|
|
96
|
+
}
|
|
97
|
+
/** Create a logging middleware for action auditing */
|
|
98
|
+
export declare function loggingMiddleware(options?: LoggingMiddlewareOptions): Middleware;
|
|
99
|
+
export interface RetryMiddlewareOptions {
|
|
100
|
+
/** Max retries. Default: 2 */
|
|
101
|
+
maxRetries?: number;
|
|
102
|
+
/** Delay between retries in ms. Default: 500 */
|
|
103
|
+
delayMs?: number;
|
|
104
|
+
/** Backoff multiplier. Default: 2.0 */
|
|
105
|
+
backoff?: number;
|
|
106
|
+
/** Only retry these actions (empty = all) */
|
|
107
|
+
actions?: ActionType[];
|
|
108
|
+
/** Only retry if error matches predicate */
|
|
109
|
+
retryIf?: (error: Error) => boolean;
|
|
110
|
+
/** Priority. Default: -50 */
|
|
111
|
+
priority?: number;
|
|
112
|
+
}
|
|
113
|
+
/** Create a retry middleware for automatic action retry on failure */
|
|
114
|
+
export declare function retryMiddleware(options?: RetryMiddlewareOptions): Middleware;
|
|
115
|
+
/**
|
|
116
|
+
* Create a middleware that transforms action arguments.
|
|
117
|
+
* Useful for coordinate scaling, offset adjustment, etc.
|
|
118
|
+
*/
|
|
119
|
+
export declare function transformMiddleware(name: string, actions: ActionType[], transform: (action: ActionType, args: unknown[]) => unknown[], priority?: number): Middleware;
|
|
120
|
+
export declare const middleware: {
|
|
121
|
+
/**
|
|
122
|
+
* Register a middleware.
|
|
123
|
+
*/
|
|
124
|
+
use(mw: Middleware): void;
|
|
125
|
+
/**
|
|
126
|
+
* Remove a middleware by name.
|
|
127
|
+
*/
|
|
128
|
+
remove(name: string): boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Enable a middleware by name.
|
|
131
|
+
*/
|
|
132
|
+
enable(name: string): boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Disable a middleware by name.
|
|
135
|
+
*/
|
|
136
|
+
disable(name: string): boolean;
|
|
137
|
+
/**
|
|
138
|
+
* List all registered middleware.
|
|
139
|
+
*/
|
|
140
|
+
list(): {
|
|
141
|
+
name: string;
|
|
142
|
+
enabled: boolean;
|
|
143
|
+
priority: number;
|
|
144
|
+
description?: string;
|
|
145
|
+
}[];
|
|
146
|
+
/**
|
|
147
|
+
* Enable or disable the entire pipeline.
|
|
148
|
+
*/
|
|
149
|
+
setEnabled(enabled: boolean): void;
|
|
150
|
+
/** Is the pipeline enabled? */
|
|
151
|
+
isEnabled(): boolean;
|
|
152
|
+
/** Enable debug logging for the pipeline */
|
|
153
|
+
setDebug(enabled: boolean): void;
|
|
154
|
+
/**
|
|
155
|
+
* Execute an action through the middleware pipeline.
|
|
156
|
+
*
|
|
157
|
+
* This is the core function that modules call to run actions through middleware.
|
|
158
|
+
* It runs all matching 'before' hooks, then the action, then all 'after' hooks.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* // Inside mouse.ts:
|
|
163
|
+
* const result = await middleware.execute('mouse.move', [x, y], () => {
|
|
164
|
+
* native.mouseMove(x, y);
|
|
165
|
+
* });
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
execute<T>(action: ActionType, args: unknown[], fn: (...args: unknown[]) => T | Promise<T>): Promise<T>;
|
|
169
|
+
/**
|
|
170
|
+
* Execute an action synchronously through the pipeline.
|
|
171
|
+
* Only runs synchronous middleware (skips async middleware).
|
|
172
|
+
*/
|
|
173
|
+
executeSync<T>(action: ActionType, args: unknown[], fn: (...args: unknown[]) => T): T;
|
|
174
|
+
/**
|
|
175
|
+
* Clear all middleware.
|
|
176
|
+
*/
|
|
177
|
+
clear(): void;
|
|
178
|
+
/**
|
|
179
|
+
* Reset pipeline to defaults.
|
|
180
|
+
*/
|
|
181
|
+
reset(): void;
|
|
182
|
+
};
|
|
183
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../ts/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// Stelo — Middleware & Policy Pipeline
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Pluggable before/after hooks for EVERY automation action. Built-in policies
|
|
6
|
+
// for boundary enforcement, rate limiting, cooldowns, logging, retry, and
|
|
7
|
+
// action transformation.
|
|
8
|
+
// ============================================================================
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.middleware = void 0;
|
|
11
|
+
exports.boundaryPolicy = boundaryPolicy;
|
|
12
|
+
exports.ratePolicy = ratePolicy;
|
|
13
|
+
exports.cooldownPolicy = cooldownPolicy;
|
|
14
|
+
exports.loggingMiddleware = loggingMiddleware;
|
|
15
|
+
exports.retryMiddleware = retryMiddleware;
|
|
16
|
+
exports.transformMiddleware = transformMiddleware;
|
|
17
|
+
const events_1 = require("./events");
|
|
18
|
+
const logger_1 = require("./logger");
|
|
19
|
+
/** Create a boundary enforcement middleware */
|
|
20
|
+
function boundaryPolicy(options) {
|
|
21
|
+
const { region, mode = 'clamp', priority = 100 } = options;
|
|
22
|
+
const log = logger_1.logger.child('boundary');
|
|
23
|
+
return {
|
|
24
|
+
name: 'boundary-enforcement',
|
|
25
|
+
description: `Keep mouse within [${region.x},${region.y}]-[${region.x + region.width},${region.y + region.height}]`,
|
|
26
|
+
priority,
|
|
27
|
+
actions: [
|
|
28
|
+
'mouse.move', 'mouse.moveSmoothly', 'mouse.moveHumanized',
|
|
29
|
+
'mouse.click', 'mouse.clickAt', 'mouse.drag',
|
|
30
|
+
'agent.clickAndVerify',
|
|
31
|
+
],
|
|
32
|
+
enabled: true,
|
|
33
|
+
before: (ctx) => {
|
|
34
|
+
// Find x, y in args
|
|
35
|
+
const args = ctx.args;
|
|
36
|
+
let x;
|
|
37
|
+
let y;
|
|
38
|
+
if (ctx.action === 'mouse.move' || ctx.action === 'mouse.moveSmoothly' || ctx.action === 'mouse.moveHumanized') {
|
|
39
|
+
x = args[0];
|
|
40
|
+
y = args[1];
|
|
41
|
+
}
|
|
42
|
+
else if (ctx.action === 'mouse.clickAt' || ctx.action === 'agent.clickAndVerify') {
|
|
43
|
+
x = args[0];
|
|
44
|
+
y = args[1];
|
|
45
|
+
}
|
|
46
|
+
else if (ctx.action === 'mouse.drag') {
|
|
47
|
+
// Check both from and to coordinates
|
|
48
|
+
const fromX = args[0], fromY = args[1], toX = args[2], toY = args[3];
|
|
49
|
+
if (typeof toX === 'number' && typeof toY === 'number') {
|
|
50
|
+
x = toX;
|
|
51
|
+
y = toY;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (x === undefined || y === undefined)
|
|
55
|
+
return;
|
|
56
|
+
const minX = region.x;
|
|
57
|
+
const minY = region.y;
|
|
58
|
+
const maxX = region.x + region.width;
|
|
59
|
+
const maxY = region.y + region.height;
|
|
60
|
+
const outOfBounds = x < minX || x > maxX || y < minY || y > maxY;
|
|
61
|
+
if (outOfBounds) {
|
|
62
|
+
if (mode === 'block') {
|
|
63
|
+
log.warn('Action blocked: mouse target out of bounds', { x, y, region });
|
|
64
|
+
ctx.skip = true;
|
|
65
|
+
events_1.events.emit('middleware.boundary.blocked', 'safety', { x, y, region, action: ctx.action }, { source: 'middleware' });
|
|
66
|
+
}
|
|
67
|
+
else if (mode === 'clamp') {
|
|
68
|
+
const clampedX = Math.max(minX, Math.min(maxX, x));
|
|
69
|
+
const clampedY = Math.max(minY, Math.min(maxY, y));
|
|
70
|
+
log.debug('Clamping mouse to boundary', { original: { x, y }, clamped: { x: clampedX, y: clampedY } });
|
|
71
|
+
// Modify args in-place
|
|
72
|
+
if (ctx.action === 'mouse.move' || ctx.action === 'mouse.moveSmoothly' || ctx.action === 'mouse.moveHumanized') {
|
|
73
|
+
ctx.args[0] = clampedX;
|
|
74
|
+
ctx.args[1] = clampedY;
|
|
75
|
+
}
|
|
76
|
+
else if (ctx.action === 'mouse.clickAt' || ctx.action === 'agent.clickAndVerify') {
|
|
77
|
+
ctx.args[0] = clampedX;
|
|
78
|
+
ctx.args[1] = clampedY;
|
|
79
|
+
}
|
|
80
|
+
else if (ctx.action === 'mouse.drag') {
|
|
81
|
+
ctx.args[2] = clampedX;
|
|
82
|
+
ctx.args[3] = clampedY;
|
|
83
|
+
}
|
|
84
|
+
ctx.modified = true;
|
|
85
|
+
events_1.events.emit('middleware.boundary.clamped', 'safety', { original: { x, y }, clamped: { x: clampedX, y: clampedY } }, { source: 'middleware' });
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
log.warn('Mouse target out of bounds (warning only)', { x, y, region });
|
|
89
|
+
events_1.events.emit('middleware.boundary.warning', 'safety', { x, y, region, action: ctx.action }, { source: 'middleware' });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/** Create a rate-limiting middleware */
|
|
96
|
+
function ratePolicy(options) {
|
|
97
|
+
const { maxActions, periodMs = 1000, mode = 'block', priority = 90 } = options;
|
|
98
|
+
const log = logger_1.logger.child('rate-policy');
|
|
99
|
+
const timestamps = [];
|
|
100
|
+
return {
|
|
101
|
+
name: 'rate-policy',
|
|
102
|
+
description: `Max ${maxActions} actions per ${periodMs}ms`,
|
|
103
|
+
priority,
|
|
104
|
+
actions: options.actions ?? [],
|
|
105
|
+
enabled: true,
|
|
106
|
+
before: async (ctx) => {
|
|
107
|
+
const now = Date.now();
|
|
108
|
+
// Remove timestamps outside the window
|
|
109
|
+
while (timestamps.length > 0 && timestamps[0] < now - periodMs) {
|
|
110
|
+
timestamps.shift();
|
|
111
|
+
}
|
|
112
|
+
if (timestamps.length >= maxActions) {
|
|
113
|
+
if (mode === 'block') {
|
|
114
|
+
log.warn('Action rate-limited', { action: ctx.action, count: timestamps.length, max: maxActions });
|
|
115
|
+
ctx.skip = true;
|
|
116
|
+
events_1.events.emit('middleware.rate.blocked', 'safety', { action: ctx.action, count: timestamps.length }, { source: 'middleware' });
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
// Delay until there's room
|
|
120
|
+
const waitUntil = timestamps[0] + periodMs;
|
|
121
|
+
const delay = waitUntil - now;
|
|
122
|
+
if (delay > 0) {
|
|
123
|
+
log.debug('Action delayed by rate policy', { action: ctx.action, delayMs: delay });
|
|
124
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (!ctx.skip) {
|
|
129
|
+
timestamps.push(Date.now());
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/** Create a cooldown middleware — prevents rapid repeat of same action type */
|
|
135
|
+
function cooldownPolicy(options) {
|
|
136
|
+
const { cooldownMs, priority = 80 } = options;
|
|
137
|
+
const lastExecution = new Map();
|
|
138
|
+
return {
|
|
139
|
+
name: 'cooldown-policy',
|
|
140
|
+
description: `${cooldownMs}ms cooldown between same action types`,
|
|
141
|
+
priority,
|
|
142
|
+
actions: options.actions ?? [],
|
|
143
|
+
enabled: true,
|
|
144
|
+
before: async (ctx) => {
|
|
145
|
+
const last = lastExecution.get(ctx.action);
|
|
146
|
+
if (last) {
|
|
147
|
+
const elapsed = Date.now() - last;
|
|
148
|
+
if (elapsed < cooldownMs) {
|
|
149
|
+
const remaining = cooldownMs - elapsed;
|
|
150
|
+
await new Promise((resolve) => setTimeout(resolve, remaining));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
after: (ctx) => {
|
|
155
|
+
if (!ctx.skip && !ctx.error) {
|
|
156
|
+
lastExecution.set(ctx.action, Date.now());
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/** Create a logging middleware for action auditing */
|
|
162
|
+
function loggingMiddleware(options) {
|
|
163
|
+
const { level = 'debug', includeArgs = false, includeResults = false, priority = -100 } = options ?? {};
|
|
164
|
+
const log = logger_1.logger.child('action-audit');
|
|
165
|
+
const logFn = level === 'trace' ? log.trace.bind(log)
|
|
166
|
+
: level === 'info' ? log.info.bind(log)
|
|
167
|
+
: log.debug.bind(log);
|
|
168
|
+
return {
|
|
169
|
+
name: 'logging',
|
|
170
|
+
description: 'Log all actions for auditing',
|
|
171
|
+
priority,
|
|
172
|
+
actions: [],
|
|
173
|
+
enabled: true,
|
|
174
|
+
before: (ctx) => {
|
|
175
|
+
const data = { action: ctx.action };
|
|
176
|
+
if (includeArgs)
|
|
177
|
+
data.args = ctx.args;
|
|
178
|
+
logFn(`Action starting: ${ctx.action}`, data);
|
|
179
|
+
},
|
|
180
|
+
after: (ctx) => {
|
|
181
|
+
const data = {
|
|
182
|
+
action: ctx.action,
|
|
183
|
+
durationMs: ctx.durationMs,
|
|
184
|
+
skipped: ctx.skip,
|
|
185
|
+
modified: ctx.modified,
|
|
186
|
+
};
|
|
187
|
+
if (ctx.error) {
|
|
188
|
+
data.error = ctx.error.message;
|
|
189
|
+
log.warn(`Action failed: ${ctx.action}`, data);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
if (includeResults)
|
|
193
|
+
data.result = ctx.result;
|
|
194
|
+
logFn(`Action completed: ${ctx.action}`, data);
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
/** Create a retry middleware for automatic action retry on failure */
|
|
200
|
+
function retryMiddleware(options) {
|
|
201
|
+
const { maxRetries = 2, delayMs = 500, backoff = 2.0, priority = -50, retryIf } = options ?? {};
|
|
202
|
+
const log = logger_1.logger.child('retry');
|
|
203
|
+
return {
|
|
204
|
+
name: 'retry',
|
|
205
|
+
description: `Retry failed actions up to ${maxRetries} times`,
|
|
206
|
+
priority,
|
|
207
|
+
actions: options?.actions ?? [],
|
|
208
|
+
enabled: true,
|
|
209
|
+
after: async (ctx) => {
|
|
210
|
+
if (!ctx.error)
|
|
211
|
+
return;
|
|
212
|
+
if (retryIf && !retryIf(ctx.error))
|
|
213
|
+
return;
|
|
214
|
+
const attempts = ctx.metadata._retryAttempt || 0;
|
|
215
|
+
if (attempts >= maxRetries)
|
|
216
|
+
return;
|
|
217
|
+
ctx.metadata._retryAttempt = attempts + 1;
|
|
218
|
+
const delay = delayMs * Math.pow(backoff, attempts);
|
|
219
|
+
log.debug(`Retrying action: ${ctx.action}`, {
|
|
220
|
+
attempt: attempts + 1,
|
|
221
|
+
maxRetries,
|
|
222
|
+
delayMs: delay,
|
|
223
|
+
error: ctx.error.message,
|
|
224
|
+
});
|
|
225
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
226
|
+
// Signal that the action should be retried
|
|
227
|
+
ctx.metadata._shouldRetry = true;
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
// ── Transform Middleware ─────────────────────────────────────────────────────
|
|
232
|
+
/**
|
|
233
|
+
* Create a middleware that transforms action arguments.
|
|
234
|
+
* Useful for coordinate scaling, offset adjustment, etc.
|
|
235
|
+
*/
|
|
236
|
+
function transformMiddleware(name, actions, transform, priority = 50) {
|
|
237
|
+
return {
|
|
238
|
+
name,
|
|
239
|
+
description: `Transform args for [${actions.join(', ')}]`,
|
|
240
|
+
priority,
|
|
241
|
+
actions,
|
|
242
|
+
enabled: true,
|
|
243
|
+
before: (ctx) => {
|
|
244
|
+
ctx.args = transform(ctx.action, ctx.args);
|
|
245
|
+
ctx.modified = true;
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
// ── Pipeline ─────────────────────────────────────────────────────────────────
|
|
250
|
+
const _middlewares = [];
|
|
251
|
+
let _pipelineEnabled = true;
|
|
252
|
+
let _debug = false;
|
|
253
|
+
const _log = logger_1.logger.child('middleware');
|
|
254
|
+
function getMatchingMiddleware(action) {
|
|
255
|
+
return _middlewares
|
|
256
|
+
.filter((m) => m.enabled && (m.actions.length === 0 || m.actions.includes(action)))
|
|
257
|
+
.sort((a, b) => b.priority - a.priority);
|
|
258
|
+
}
|
|
259
|
+
exports.middleware = {
|
|
260
|
+
/**
|
|
261
|
+
* Register a middleware.
|
|
262
|
+
*/
|
|
263
|
+
use(mw) {
|
|
264
|
+
_middlewares.push(mw);
|
|
265
|
+
if (_debug)
|
|
266
|
+
_log.debug(`Middleware registered: ${mw.name}`, { priority: mw.priority });
|
|
267
|
+
events_1.events.emit('middleware.registered', 'middleware', { name: mw.name }, { source: 'middleware' });
|
|
268
|
+
},
|
|
269
|
+
/**
|
|
270
|
+
* Remove a middleware by name.
|
|
271
|
+
*/
|
|
272
|
+
remove(name) {
|
|
273
|
+
const idx = _middlewares.findIndex((m) => m.name === name);
|
|
274
|
+
if (idx !== -1) {
|
|
275
|
+
_middlewares.splice(idx, 1);
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
return false;
|
|
279
|
+
},
|
|
280
|
+
/**
|
|
281
|
+
* Enable a middleware by name.
|
|
282
|
+
*/
|
|
283
|
+
enable(name) {
|
|
284
|
+
const mw = _middlewares.find((m) => m.name === name);
|
|
285
|
+
if (mw) {
|
|
286
|
+
mw.enabled = true;
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
return false;
|
|
290
|
+
},
|
|
291
|
+
/**
|
|
292
|
+
* Disable a middleware by name.
|
|
293
|
+
*/
|
|
294
|
+
disable(name) {
|
|
295
|
+
const mw = _middlewares.find((m) => m.name === name);
|
|
296
|
+
if (mw) {
|
|
297
|
+
mw.enabled = false;
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
return false;
|
|
301
|
+
},
|
|
302
|
+
/**
|
|
303
|
+
* List all registered middleware.
|
|
304
|
+
*/
|
|
305
|
+
list() {
|
|
306
|
+
return _middlewares.map((m) => ({
|
|
307
|
+
name: m.name,
|
|
308
|
+
enabled: m.enabled,
|
|
309
|
+
priority: m.priority,
|
|
310
|
+
description: m.description,
|
|
311
|
+
}));
|
|
312
|
+
},
|
|
313
|
+
/**
|
|
314
|
+
* Enable or disable the entire pipeline.
|
|
315
|
+
*/
|
|
316
|
+
setEnabled(enabled) {
|
|
317
|
+
_pipelineEnabled = enabled;
|
|
318
|
+
},
|
|
319
|
+
/** Is the pipeline enabled? */
|
|
320
|
+
isEnabled() {
|
|
321
|
+
return _pipelineEnabled;
|
|
322
|
+
},
|
|
323
|
+
/** Enable debug logging for the pipeline */
|
|
324
|
+
setDebug(enabled) {
|
|
325
|
+
_debug = enabled;
|
|
326
|
+
},
|
|
327
|
+
/**
|
|
328
|
+
* Execute an action through the middleware pipeline.
|
|
329
|
+
*
|
|
330
|
+
* This is the core function that modules call to run actions through middleware.
|
|
331
|
+
* It runs all matching 'before' hooks, then the action, then all 'after' hooks.
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* ```ts
|
|
335
|
+
* // Inside mouse.ts:
|
|
336
|
+
* const result = await middleware.execute('mouse.move', [x, y], () => {
|
|
337
|
+
* native.mouseMove(x, y);
|
|
338
|
+
* });
|
|
339
|
+
* ```
|
|
340
|
+
*/
|
|
341
|
+
async execute(action, args, fn) {
|
|
342
|
+
if (!_pipelineEnabled) {
|
|
343
|
+
return fn(...args);
|
|
344
|
+
}
|
|
345
|
+
const matching = getMatchingMiddleware(action);
|
|
346
|
+
if (matching.length === 0) {
|
|
347
|
+
return fn(...args);
|
|
348
|
+
}
|
|
349
|
+
const ctx = {
|
|
350
|
+
action,
|
|
351
|
+
args: [...args],
|
|
352
|
+
timestamp: new Date().toISOString(),
|
|
353
|
+
metadata: {},
|
|
354
|
+
skip: false,
|
|
355
|
+
modified: false,
|
|
356
|
+
};
|
|
357
|
+
// Run before hooks
|
|
358
|
+
for (const mw of matching) {
|
|
359
|
+
if (mw.before) {
|
|
360
|
+
try {
|
|
361
|
+
await mw.before(ctx, () => { });
|
|
362
|
+
}
|
|
363
|
+
catch (err) {
|
|
364
|
+
if (_debug)
|
|
365
|
+
_log.error(`Before middleware error: ${mw.name}`, err);
|
|
366
|
+
}
|
|
367
|
+
if (ctx.skip)
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
// Execute action (unless skipped)
|
|
372
|
+
const startTime = performance.now();
|
|
373
|
+
if (!ctx.skip) {
|
|
374
|
+
try {
|
|
375
|
+
ctx.result = await Promise.resolve(fn(...ctx.args));
|
|
376
|
+
}
|
|
377
|
+
catch (err) {
|
|
378
|
+
ctx.error = err instanceof Error ? err : new Error(String(err));
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
ctx.durationMs = performance.now() - startTime;
|
|
382
|
+
// Run after hooks (in reverse priority order)
|
|
383
|
+
const reversedMatching = [...matching].reverse();
|
|
384
|
+
for (const mw of reversedMatching) {
|
|
385
|
+
if (mw.after) {
|
|
386
|
+
try {
|
|
387
|
+
await mw.after(ctx, () => { });
|
|
388
|
+
}
|
|
389
|
+
catch (err) {
|
|
390
|
+
if (_debug)
|
|
391
|
+
_log.error(`After middleware error: ${mw.name}`, err);
|
|
392
|
+
}
|
|
393
|
+
// Check if retry was requested
|
|
394
|
+
if (ctx.metadata._shouldRetry) {
|
|
395
|
+
ctx.metadata._shouldRetry = false;
|
|
396
|
+
ctx.error = undefined;
|
|
397
|
+
ctx.result = undefined;
|
|
398
|
+
try {
|
|
399
|
+
ctx.result = await Promise.resolve(fn(...ctx.args));
|
|
400
|
+
}
|
|
401
|
+
catch (err) {
|
|
402
|
+
ctx.error = err instanceof Error ? err : new Error(String(err));
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
if (ctx.error)
|
|
408
|
+
throw ctx.error;
|
|
409
|
+
return ctx.result;
|
|
410
|
+
},
|
|
411
|
+
/**
|
|
412
|
+
* Execute an action synchronously through the pipeline.
|
|
413
|
+
* Only runs synchronous middleware (skips async middleware).
|
|
414
|
+
*/
|
|
415
|
+
executeSync(action, args, fn) {
|
|
416
|
+
if (!_pipelineEnabled) {
|
|
417
|
+
return fn(...args);
|
|
418
|
+
}
|
|
419
|
+
const matching = getMatchingMiddleware(action);
|
|
420
|
+
if (matching.length === 0) {
|
|
421
|
+
return fn(...args);
|
|
422
|
+
}
|
|
423
|
+
const ctx = {
|
|
424
|
+
action,
|
|
425
|
+
args: [...args],
|
|
426
|
+
timestamp: new Date().toISOString(),
|
|
427
|
+
metadata: {},
|
|
428
|
+
skip: false,
|
|
429
|
+
modified: false,
|
|
430
|
+
};
|
|
431
|
+
// Run synchronous before hooks
|
|
432
|
+
for (const mw of matching) {
|
|
433
|
+
if (mw.before) {
|
|
434
|
+
try {
|
|
435
|
+
const result = mw.before(ctx, () => { });
|
|
436
|
+
// Skip async middleware in sync mode
|
|
437
|
+
if (result instanceof Promise)
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
catch (err) {
|
|
441
|
+
if (_debug)
|
|
442
|
+
_log.error(`Before middleware error (sync): ${mw.name}`, err);
|
|
443
|
+
}
|
|
444
|
+
if (ctx.skip)
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
// Execute
|
|
449
|
+
const startTime = performance.now();
|
|
450
|
+
if (!ctx.skip) {
|
|
451
|
+
try {
|
|
452
|
+
ctx.result = fn(...ctx.args);
|
|
453
|
+
}
|
|
454
|
+
catch (err) {
|
|
455
|
+
ctx.error = err instanceof Error ? err : new Error(String(err));
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
ctx.durationMs = performance.now() - startTime;
|
|
459
|
+
// Run synchronous after hooks
|
|
460
|
+
const reversedMatching = [...matching].reverse();
|
|
461
|
+
for (const mw of reversedMatching) {
|
|
462
|
+
if (mw.after) {
|
|
463
|
+
try {
|
|
464
|
+
const result = mw.after(ctx, () => { });
|
|
465
|
+
if (result instanceof Promise)
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
catch (err) {
|
|
469
|
+
if (_debug)
|
|
470
|
+
_log.error(`After middleware error (sync): ${mw.name}`, err);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (ctx.error)
|
|
475
|
+
throw ctx.error;
|
|
476
|
+
return ctx.result;
|
|
477
|
+
},
|
|
478
|
+
/**
|
|
479
|
+
* Clear all middleware.
|
|
480
|
+
*/
|
|
481
|
+
clear() {
|
|
482
|
+
_middlewares.length = 0;
|
|
483
|
+
},
|
|
484
|
+
/**
|
|
485
|
+
* Reset pipeline to defaults.
|
|
486
|
+
*/
|
|
487
|
+
reset() {
|
|
488
|
+
_middlewares.length = 0;
|
|
489
|
+
_pipelineEnabled = true;
|
|
490
|
+
_debug = false;
|
|
491
|
+
},
|
|
492
|
+
};
|
|
493
|
+
//# sourceMappingURL=middleware.js.map
|