@bluelibs/runner 3.1.1 → 3.2.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/README.md +37 -0
- package/dist/define.d.ts +1 -1
- package/dist/define.js +3 -2
- package/dist/define.js.map +1 -1
- package/dist/defs.d.ts +12 -0
- package/dist/models/EventManager.js +9 -0
- package/dist/models/EventManager.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/globalEvents.test.ts +419 -1
- package/src/define.ts +4 -3
- package/src/defs.ts +12 -0
- package/src/models/EventManager.ts +11 -0
package/README.md
CHANGED
|
@@ -296,6 +296,43 @@ const taskLogger = task({
|
|
|
296
296
|
});
|
|
297
297
|
```
|
|
298
298
|
|
|
299
|
+
#### Event Propagation Control with stopPropagation()
|
|
300
|
+
|
|
301
|
+
Sometimes you need to prevent other event listeners from processing an event. The `stopPropagation()` method gives you fine-grained control over event flow:
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
const criticalAlert = event<{
|
|
305
|
+
severity: "low" | "medium" | "high" | "critical";
|
|
306
|
+
}>({
|
|
307
|
+
id: "app.events.alert",
|
|
308
|
+
meta: {
|
|
309
|
+
title: "System Alert Event",
|
|
310
|
+
description: "Emitted when system issues are detected",
|
|
311
|
+
tags: ["monitoring", "alerts"],
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// High-priority handler that can stop propagation
|
|
316
|
+
const emergencyHandler = task({
|
|
317
|
+
id: "app.tasks.emergencyHandler",
|
|
318
|
+
on: criticalAlert, // Works with global events too
|
|
319
|
+
listenerOrder: -100, // Higher priority (lower numbers run first)
|
|
320
|
+
run: async (event) => {
|
|
321
|
+
console.log(`Alert received: ${event.data.severity}`);
|
|
322
|
+
|
|
323
|
+
if (event.data.severity === "critical") {
|
|
324
|
+
console.log("🚨 CRITICAL ALERT - Activating emergency protocols");
|
|
325
|
+
|
|
326
|
+
// Stop other handlers from running
|
|
327
|
+
event.stopPropagation();
|
|
328
|
+
// Notify the on-call team, escalate, etc.
|
|
329
|
+
|
|
330
|
+
console.log("🛑 Event propagation stopped - emergency protocols active");
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
```
|
|
335
|
+
|
|
299
336
|
### 4. Middleware: The Interceptor Pattern Done Right
|
|
300
337
|
|
|
301
338
|
Middleware wraps around your tasks and resources, adding cross-cutting concerns without polluting your business logic.
|
package/dist/define.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export declare function defineResource<TConfig = void, TValue = any, TDeps exten
|
|
|
10
10
|
export declare function defineIndex<T extends Record<string, RegisterableItems>, D extends {
|
|
11
11
|
[K in keyof T]: T[K] extends IResourceWithConfig<any, any, any> ? T[K]["resource"] : T[K];
|
|
12
12
|
} & DependencyMapType>(items: T): IResource<void, DependencyValuesType<D>, D>;
|
|
13
|
-
export declare function defineEvent<TPayload = void>(config
|
|
13
|
+
export declare function defineEvent<TPayload = void>(config?: IEventDefinition<TPayload>): IEvent<TPayload>;
|
|
14
14
|
export type MiddlewareEverywhereOptions = {
|
|
15
15
|
/**
|
|
16
16
|
* Enable this for tasks. Default is true.
|
package/dist/define.js
CHANGED
|
@@ -144,9 +144,10 @@ function defineIndex(items) {
|
|
|
144
144
|
}
|
|
145
145
|
function defineEvent(config) {
|
|
146
146
|
const callerFilePath = (0, getCallerFile_1.getCallerFile)();
|
|
147
|
+
const eventConfig = config || {};
|
|
147
148
|
return {
|
|
148
|
-
...
|
|
149
|
-
id:
|
|
149
|
+
...eventConfig,
|
|
150
|
+
id: eventConfig.id || (0, getCallerFile_1.generateCallerIdFromFile)(callerFilePath, "event"),
|
|
150
151
|
[defs_1.symbols.filePath]: callerFilePath,
|
|
151
152
|
[defs_1.symbolEvent]: true, // This is a workaround
|
|
152
153
|
};
|
package/dist/define.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":";;AAwBA,gCAiDC;AAED,wCA+DC;AAQD,kCAgCC;AAED,
|
|
1
|
+
{"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"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"}
|
package/dist/defs.d.ts
CHANGED
|
@@ -201,6 +201,18 @@ export interface IEventEmission<TPayload = any> {
|
|
|
201
201
|
* The source of the event. This can be useful for debugging.
|
|
202
202
|
*/
|
|
203
203
|
source: string | symbol;
|
|
204
|
+
/**
|
|
205
|
+
* Metadata associated with the event definition.
|
|
206
|
+
*/
|
|
207
|
+
meta: IEventMeta;
|
|
208
|
+
/**
|
|
209
|
+
* Stops propagation to remaining event listeners.
|
|
210
|
+
*/
|
|
211
|
+
stopPropagation(): void;
|
|
212
|
+
/**
|
|
213
|
+
* Returns true if propagation has been stopped.
|
|
214
|
+
*/
|
|
215
|
+
isPropagationStopped(): boolean;
|
|
204
216
|
}
|
|
205
217
|
export interface IMiddlewareDefinition<TConfig = any, TDependencies extends DependencyMapType = any> {
|
|
206
218
|
id?: string | symbol;
|
|
@@ -74,13 +74,22 @@ class EventManager {
|
|
|
74
74
|
if (allListeners.length === 0) {
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
|
+
let propagationStopped = false;
|
|
77
78
|
const event = {
|
|
78
79
|
id: eventDefinition.id,
|
|
79
80
|
data,
|
|
80
81
|
timestamp: new Date(),
|
|
81
82
|
source,
|
|
83
|
+
meta: eventDefinition.meta || {},
|
|
84
|
+
stopPropagation: () => {
|
|
85
|
+
propagationStopped = true;
|
|
86
|
+
},
|
|
87
|
+
isPropagationStopped: () => propagationStopped,
|
|
82
88
|
};
|
|
83
89
|
for (const listener of allListeners) {
|
|
90
|
+
if (propagationStopped) {
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
84
93
|
if (!listener.filter || listener.filter(event)) {
|
|
85
94
|
await listener.handler(event);
|
|
86
95
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EventManager.js","sourceRoot":"","sources":["../../src/models/EventManager.ts"],"names":[],"mappings":";;;AAMA,sCAAmC;AAGnC,MAAM,sBAAsB,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AAiB5C,MAAa,YAAY;IACf,SAAS,GAA6C,IAAI,GAAG,EAAE,CAAC;IAChE,eAAe,GAAuB,EAAE,CAAC;IACzC,qBAAqB,GAC3B,IAAI,GAAG,EAAE,CAAC;IACJ,yBAAyB,GAAG,IAAI,CAAC;IACzC,SAAS,GAAG,KAAK,CAAC;IAElB,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACxB,CAAC;IAED,SAAS;QACP,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,eAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAEO,oBAAoB,CAC1B,CAAqB,EACrB,CAAqB;QAErB,MAAM,MAAM,GAAuB,EAAE,CAAC;QACtC,IAAI,CAAC,GAAG,CAAC,EACP,CAAC,GAAG,CAAC,CAAC;QACR,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;YACpC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACtB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACzC,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,wBAAwB,CAC9B,OAAwB;QAExB,IAAI,CAAC,IAAI,CAAC,yBAAyB,EAAE,CAAC;YACpC,IAAI,CAAC,qBAAqB,CAAC,KAAK,EAAE,CAAC;YACnC,IAAI,CAAC,yBAAyB,GAAG,IAAI,CAAC;QACxC,CAAC;QAED,IAAI,MAAM,GAAG,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YACzD,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACrE,MAAM,GAAG,EAAE,CAAC;YACd,CAAC;iBAAM,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvC,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC;YAChC,CAAC;iBAAM,IAAI,IAAI,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7C,MAAM,GAAG,cAAc,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,IAAI,CAAC,oBAAoB,CAChC,cAAc,EACd,IAAI,CAAC,eAAe,CACrB,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAClD,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,eAAe,CAAC,OAAyB;QAC/C,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC7C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,yBAAyB,GAAG,KAAK,CAAC;QACzC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CACR,eAA+B,EAC/B,IAAY,EACZ,MAAuB;QAEvB,MAAM,YAAY,GAAG,IAAI,CAAC,wBAAwB,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QAEvE,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAmB;YAC5B,EAAE,EAAE,eAAe,CAAC,EAAE;YACtB,IAAI;YACJ,SAAS,EAAE,IAAI,IAAI,EAAE;YACrB,MAAM;
|
|
1
|
+
{"version":3,"file":"EventManager.js","sourceRoot":"","sources":["../../src/models/EventManager.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { globalEvents } from "../globals/globalEvents";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
defineTask,
|
|
4
|
+
defineResource,
|
|
5
|
+
defineMiddleware,
|
|
6
|
+
defineEvent,
|
|
7
|
+
} from "../define";
|
|
3
8
|
import { run } from "../run";
|
|
4
9
|
|
|
5
10
|
describe("Global Events", () => {
|
|
@@ -121,4 +126,417 @@ describe("Global Events", () => {
|
|
|
121
126
|
|
|
122
127
|
expect(globalTaskOnErrorHandler).toHaveBeenCalled();
|
|
123
128
|
});
|
|
129
|
+
|
|
130
|
+
it("should ensure global event listeners get their middleware called", async () => {
|
|
131
|
+
const middlewareExecutions: string[] = [];
|
|
132
|
+
const eventHandlerExecutions: string[] = [];
|
|
133
|
+
|
|
134
|
+
// Custom event to emit
|
|
135
|
+
const customEvent = defineEvent<{ message: string }>({
|
|
136
|
+
id: "test.customEvent",
|
|
137
|
+
meta: {
|
|
138
|
+
title: "Test Event",
|
|
139
|
+
description: "Test event for middleware verification",
|
|
140
|
+
tags: ["test"],
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Middleware that logs execution
|
|
145
|
+
const testMiddleware = defineMiddleware({
|
|
146
|
+
id: "test.middleware",
|
|
147
|
+
run: async ({ next, task }) => {
|
|
148
|
+
const taskId = task?.definition?.id || "unknown";
|
|
149
|
+
middlewareExecutions.push(`middleware-before:${String(taskId)}`);
|
|
150
|
+
const result = await next(task?.input);
|
|
151
|
+
middlewareExecutions.push(`middleware-after:${String(taskId)}`);
|
|
152
|
+
return result;
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Global event listener task with middleware
|
|
157
|
+
const globalEventHandler = defineTask({
|
|
158
|
+
id: "global.event.handler",
|
|
159
|
+
on: "*", // Global listener
|
|
160
|
+
middleware: [testMiddleware],
|
|
161
|
+
run: async (event) => {
|
|
162
|
+
if (event && event.id) {
|
|
163
|
+
eventHandlerExecutions.push(`global-handler:${event.id.toString()}`);
|
|
164
|
+
// Verify the event has meta included
|
|
165
|
+
expect(event.meta).toBeDefined();
|
|
166
|
+
if (event.id === customEvent.id) {
|
|
167
|
+
expect(event.meta.title).toBe("Test Event");
|
|
168
|
+
expect(event.meta.tags).toContain("test");
|
|
169
|
+
expect(event.data.message).toBe("Hello from custom event");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Specific event listener task with middleware
|
|
176
|
+
const specificEventHandler = defineTask({
|
|
177
|
+
id: "specific.event.handler",
|
|
178
|
+
on: customEvent,
|
|
179
|
+
middleware: [testMiddleware],
|
|
180
|
+
run: async (event) => {
|
|
181
|
+
if (event && event.id) {
|
|
182
|
+
eventHandlerExecutions.push(
|
|
183
|
+
`specific-handler:${event.id.toString()}`
|
|
184
|
+
);
|
|
185
|
+
expect(event.meta.title).toBe("Test Event");
|
|
186
|
+
expect(event.data.message).toBe("Hello from custom event");
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Task that emits the custom event
|
|
192
|
+
const eventEmitter = defineTask({
|
|
193
|
+
id: "event.emitter",
|
|
194
|
+
dependencies: { customEvent },
|
|
195
|
+
run: async (_, { customEvent }) => {
|
|
196
|
+
await customEvent({ message: "Hello from custom event" });
|
|
197
|
+
return "Event emitted";
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const app = defineResource({
|
|
202
|
+
id: "app",
|
|
203
|
+
register: [
|
|
204
|
+
customEvent,
|
|
205
|
+
testMiddleware,
|
|
206
|
+
globalEventHandler,
|
|
207
|
+
specificEventHandler,
|
|
208
|
+
eventEmitter,
|
|
209
|
+
],
|
|
210
|
+
dependencies: { eventEmitter },
|
|
211
|
+
async init(_, { eventEmitter }) {
|
|
212
|
+
await eventEmitter();
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
await run(app);
|
|
217
|
+
|
|
218
|
+
// Verify middleware was called for global event listener
|
|
219
|
+
expect(middlewareExecutions).toContain(
|
|
220
|
+
"middleware-before:global.event.handler"
|
|
221
|
+
);
|
|
222
|
+
expect(middlewareExecutions).toContain(
|
|
223
|
+
"middleware-after:global.event.handler"
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
// Verify middleware was called for specific event listener
|
|
227
|
+
expect(middlewareExecutions).toContain(
|
|
228
|
+
"middleware-before:specific.event.handler"
|
|
229
|
+
);
|
|
230
|
+
expect(middlewareExecutions).toContain(
|
|
231
|
+
"middleware-after:specific.event.handler"
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
// Verify event handlers were executed
|
|
235
|
+
expect(eventHandlerExecutions).toContain("global-handler:test.customEvent");
|
|
236
|
+
expect(eventHandlerExecutions).toContain(
|
|
237
|
+
"specific-handler:test.customEvent"
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
// Verify global listeners also handle other events (like global events themselves)
|
|
241
|
+
expect(
|
|
242
|
+
eventHandlerExecutions.some(
|
|
243
|
+
(exec) =>
|
|
244
|
+
exec.includes("global-handler:") && exec.includes("beforeInit")
|
|
245
|
+
)
|
|
246
|
+
).toBe(true);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it("should support stopPropagation in event listeners", async () => {
|
|
250
|
+
const eventHandlerExecutions: string[] = [];
|
|
251
|
+
|
|
252
|
+
const testEvent = defineEvent<{ value: number }>({
|
|
253
|
+
id: "test.propagationEvent",
|
|
254
|
+
meta: {
|
|
255
|
+
title: "Propagation Test Event",
|
|
256
|
+
tags: ["propagation", "test"],
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// High priority listener that stops propagation
|
|
261
|
+
const highPriorityHandler = defineTask({
|
|
262
|
+
id: "high.priority.handler",
|
|
263
|
+
on: testEvent,
|
|
264
|
+
listenerOrder: -100, // Higher priority (runs first)
|
|
265
|
+
run: async (event) => {
|
|
266
|
+
eventHandlerExecutions.push("high-priority-executed");
|
|
267
|
+
|
|
268
|
+
if (event && event.data && event.data.value > 10) {
|
|
269
|
+
expect(event.isPropagationStopped()).toBe(false);
|
|
270
|
+
event.stopPropagation();
|
|
271
|
+
expect(event.isPropagationStopped()).toBe(true);
|
|
272
|
+
eventHandlerExecutions.push("propagation-stopped");
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// Low priority listener that should be skipped when propagation is stopped
|
|
278
|
+
const lowPriorityHandler = defineTask({
|
|
279
|
+
id: "low.priority.handler",
|
|
280
|
+
on: testEvent,
|
|
281
|
+
listenerOrder: 100, // Lower priority (runs later)
|
|
282
|
+
run: async () => {
|
|
283
|
+
// This handler will only execute when propagation is NOT stopped
|
|
284
|
+
eventHandlerExecutions.push("low-priority-executed");
|
|
285
|
+
},
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
const eventEmitter = defineTask({
|
|
289
|
+
id: "propagation.emitter",
|
|
290
|
+
dependencies: { testEvent },
|
|
291
|
+
run: async (value: number, { testEvent }) => {
|
|
292
|
+
await testEvent({ value });
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
const app = defineResource({
|
|
297
|
+
id: "app",
|
|
298
|
+
register: [
|
|
299
|
+
testEvent,
|
|
300
|
+
highPriorityHandler,
|
|
301
|
+
lowPriorityHandler,
|
|
302
|
+
eventEmitter,
|
|
303
|
+
],
|
|
304
|
+
dependencies: { eventEmitter },
|
|
305
|
+
async init(_, { eventEmitter }) {
|
|
306
|
+
// Test with value <= 10 (no propagation stop)
|
|
307
|
+
await eventEmitter(5);
|
|
308
|
+
|
|
309
|
+
// Test with value > 10 (propagation stop)
|
|
310
|
+
await eventEmitter(15);
|
|
311
|
+
},
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
await run(app);
|
|
315
|
+
|
|
316
|
+
// Verify both handlers executed for first event (value=5)
|
|
317
|
+
expect(
|
|
318
|
+
eventHandlerExecutions.filter((e) => e === "high-priority-executed")
|
|
319
|
+
).toHaveLength(2);
|
|
320
|
+
expect(
|
|
321
|
+
eventHandlerExecutions.filter((e) => e === "low-priority-executed")
|
|
322
|
+
).toHaveLength(1);
|
|
323
|
+
|
|
324
|
+
// Verify propagation was stopped for second event (value=15)
|
|
325
|
+
expect(
|
|
326
|
+
eventHandlerExecutions.filter((e) => e === "propagation-stopped")
|
|
327
|
+
).toHaveLength(1);
|
|
328
|
+
|
|
329
|
+
// The low priority handler should NOT have run for the second event due to stopped propagation
|
|
330
|
+
// So it should only appear once (from the first event where propagation was not stopped)
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it("should support global event listeners with both global and local middleware", async () => {
|
|
334
|
+
const middlewareExecutions: string[] = [];
|
|
335
|
+
const eventHandlerExecutions: string[] = [];
|
|
336
|
+
|
|
337
|
+
// Custom event to emit
|
|
338
|
+
const testEvent = defineEvent<{ message: string }>({
|
|
339
|
+
id: "test.globalMiddlewareEvent",
|
|
340
|
+
meta: {
|
|
341
|
+
title: "Global Middleware Test Event",
|
|
342
|
+
description: "Test event for global middleware verification",
|
|
343
|
+
tags: ["test", "global"],
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// Global middleware that should be applied everywhere
|
|
348
|
+
const globalMiddleware = defineMiddleware({
|
|
349
|
+
id: "global.middleware",
|
|
350
|
+
run: async ({ next, task }) => {
|
|
351
|
+
const taskId = task?.definition?.id || "unknown";
|
|
352
|
+
middlewareExecutions.push(`global-middleware-before:${String(taskId)}`);
|
|
353
|
+
const result = await next(task?.input);
|
|
354
|
+
middlewareExecutions.push(`global-middleware-after:${String(taskId)}`);
|
|
355
|
+
return result;
|
|
356
|
+
},
|
|
357
|
+
}).everywhere(); // Make it global
|
|
358
|
+
|
|
359
|
+
// Local middleware specific to certain tasks
|
|
360
|
+
const localMiddleware = defineMiddleware({
|
|
361
|
+
id: "local.middleware",
|
|
362
|
+
run: async ({ next, task }) => {
|
|
363
|
+
const taskId = task?.definition?.id || "unknown";
|
|
364
|
+
middlewareExecutions.push(`local-middleware-before:${String(taskId)}`);
|
|
365
|
+
const result = await next(task?.input);
|
|
366
|
+
middlewareExecutions.push(`local-middleware-after:${String(taskId)}`);
|
|
367
|
+
return result;
|
|
368
|
+
},
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
// Global event listener task with local middleware
|
|
372
|
+
const globalEventHandler = defineTask({
|
|
373
|
+
id: "global.middleware.event.handler",
|
|
374
|
+
on: "*", // Global listener
|
|
375
|
+
middleware: [localMiddleware], // Local middleware
|
|
376
|
+
run: async (event) => {
|
|
377
|
+
if (event && event.id) {
|
|
378
|
+
eventHandlerExecutions.push(`global-handler:${event.id.toString()}`);
|
|
379
|
+
if (event.id === testEvent.id) {
|
|
380
|
+
expect(event.meta.title).toBe("Global Middleware Test Event");
|
|
381
|
+
expect(event.data.message).toBe("Hello from middleware test");
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// Specific event listener task with local middleware
|
|
388
|
+
const specificEventHandler = defineTask({
|
|
389
|
+
id: "specific.middleware.event.handler",
|
|
390
|
+
on: testEvent,
|
|
391
|
+
middleware: [localMiddleware], // Local middleware
|
|
392
|
+
run: async (event) => {
|
|
393
|
+
if (event && event.id) {
|
|
394
|
+
eventHandlerExecutions.push(
|
|
395
|
+
`specific-handler:${event.id.toString()}`
|
|
396
|
+
);
|
|
397
|
+
expect(event.meta.title).toBe("Global Middleware Test Event");
|
|
398
|
+
expect(event.data.message).toBe("Hello from middleware test");
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
// Task that emits the test event
|
|
404
|
+
const eventEmitter = defineTask({
|
|
405
|
+
id: "middleware.event.emitter",
|
|
406
|
+
dependencies: { testEvent },
|
|
407
|
+
middleware: [localMiddleware], // This task also has local middleware
|
|
408
|
+
run: async (_, { testEvent }) => {
|
|
409
|
+
await testEvent({ message: "Hello from middleware test" });
|
|
410
|
+
return "Event emitted";
|
|
411
|
+
},
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
const app = defineResource({
|
|
415
|
+
id: "app",
|
|
416
|
+
register: [
|
|
417
|
+
globalMiddleware, // Register global middleware
|
|
418
|
+
localMiddleware,
|
|
419
|
+
testEvent,
|
|
420
|
+
globalEventHandler,
|
|
421
|
+
specificEventHandler,
|
|
422
|
+
eventEmitter,
|
|
423
|
+
],
|
|
424
|
+
dependencies: { eventEmitter },
|
|
425
|
+
async init(_, { eventEmitter }) {
|
|
426
|
+
await eventEmitter();
|
|
427
|
+
},
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
await run(app);
|
|
431
|
+
|
|
432
|
+
// Verify global middleware was called for global event listener
|
|
433
|
+
expect(middlewareExecutions).toContain(
|
|
434
|
+
"global-middleware-before:global.middleware.event.handler"
|
|
435
|
+
);
|
|
436
|
+
expect(middlewareExecutions).toContain(
|
|
437
|
+
"global-middleware-after:global.middleware.event.handler"
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
// Verify local middleware was called for global event listener
|
|
441
|
+
expect(middlewareExecutions).toContain(
|
|
442
|
+
"local-middleware-before:global.middleware.event.handler"
|
|
443
|
+
);
|
|
444
|
+
expect(middlewareExecutions).toContain(
|
|
445
|
+
"local-middleware-after:global.middleware.event.handler"
|
|
446
|
+
);
|
|
447
|
+
|
|
448
|
+
// Verify global middleware was called for specific event listener
|
|
449
|
+
expect(middlewareExecutions).toContain(
|
|
450
|
+
"global-middleware-before:specific.middleware.event.handler"
|
|
451
|
+
);
|
|
452
|
+
expect(middlewareExecutions).toContain(
|
|
453
|
+
"global-middleware-after:specific.middleware.event.handler"
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
// Verify local middleware was called for specific event listener
|
|
457
|
+
expect(middlewareExecutions).toContain(
|
|
458
|
+
"local-middleware-before:specific.middleware.event.handler"
|
|
459
|
+
);
|
|
460
|
+
expect(middlewareExecutions).toContain(
|
|
461
|
+
"local-middleware-after:specific.middleware.event.handler"
|
|
462
|
+
);
|
|
463
|
+
|
|
464
|
+
// Verify global middleware was called for event emitter task
|
|
465
|
+
expect(middlewareExecutions).toContain(
|
|
466
|
+
"global-middleware-before:middleware.event.emitter"
|
|
467
|
+
);
|
|
468
|
+
expect(middlewareExecutions).toContain(
|
|
469
|
+
"global-middleware-after:middleware.event.emitter"
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
// Verify local middleware was called for event emitter task
|
|
473
|
+
expect(middlewareExecutions).toContain(
|
|
474
|
+
"local-middleware-before:middleware.event.emitter"
|
|
475
|
+
);
|
|
476
|
+
expect(middlewareExecutions).toContain(
|
|
477
|
+
"local-middleware-after:middleware.event.emitter"
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
// Verify event handlers were executed
|
|
481
|
+
expect(eventHandlerExecutions).toContain(
|
|
482
|
+
"global-handler:test.globalMiddlewareEvent"
|
|
483
|
+
);
|
|
484
|
+
expect(eventHandlerExecutions).toContain(
|
|
485
|
+
"specific-handler:test.globalMiddlewareEvent"
|
|
486
|
+
);
|
|
487
|
+
|
|
488
|
+
// Verify global listeners also handle other events (like global events themselves)
|
|
489
|
+
expect(
|
|
490
|
+
eventHandlerExecutions.some(
|
|
491
|
+
(exec) =>
|
|
492
|
+
exec.includes("global-handler:") && exec.includes("beforeInit")
|
|
493
|
+
)
|
|
494
|
+
).toBe(true);
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
it("should support defineEvent without any config", async () => {
|
|
498
|
+
const eventHandlerExecutions: string[] = [];
|
|
499
|
+
|
|
500
|
+
// Define event with minimal config (just id)
|
|
501
|
+
const simpleEvent = defineEvent();
|
|
502
|
+
|
|
503
|
+
// Event listener for the simple event
|
|
504
|
+
const simpleEventHandler = defineTask({
|
|
505
|
+
id: "simple.event.handler",
|
|
506
|
+
on: simpleEvent,
|
|
507
|
+
run: async (event) => {
|
|
508
|
+
if (event && event.id) {
|
|
509
|
+
eventHandlerExecutions.push(`simple-handler:${event.id.toString()}`);
|
|
510
|
+
// Event should exist but meta might be minimal/undefined
|
|
511
|
+
expect(event.id).toBe(simpleEvent.id);
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
// Task that emits the simple event
|
|
517
|
+
const eventEmitter = defineTask({
|
|
518
|
+
id: "simple.event.emitter",
|
|
519
|
+
dependencies: { simpleEvent },
|
|
520
|
+
run: async (_, { simpleEvent }) => {
|
|
521
|
+
await simpleEvent();
|
|
522
|
+
return "Simple event emitted";
|
|
523
|
+
},
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
const app = defineResource({
|
|
527
|
+
id: "app",
|
|
528
|
+
register: [simpleEvent, simpleEventHandler, eventEmitter],
|
|
529
|
+
dependencies: { eventEmitter },
|
|
530
|
+
async init(_, { eventEmitter }) {
|
|
531
|
+
await eventEmitter();
|
|
532
|
+
},
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
await run(app);
|
|
536
|
+
|
|
537
|
+
// Verify the simple event handler was executed
|
|
538
|
+
expect(eventHandlerExecutions).toContain(
|
|
539
|
+
"simple-handler:Symbol(__tests__.globalEvents.test.event)"
|
|
540
|
+
);
|
|
541
|
+
});
|
|
124
542
|
});
|
package/src/define.ts
CHANGED
|
@@ -179,12 +179,13 @@ export function defineIndex<
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
export function defineEvent<TPayload = void>(
|
|
182
|
-
config
|
|
182
|
+
config?: IEventDefinition<TPayload>
|
|
183
183
|
): IEvent<TPayload> {
|
|
184
184
|
const callerFilePath = getCallerFile();
|
|
185
|
+
const eventConfig = config || {};
|
|
185
186
|
return {
|
|
186
|
-
...
|
|
187
|
-
id:
|
|
187
|
+
...eventConfig,
|
|
188
|
+
id: eventConfig.id || generateCallerIdFromFile(callerFilePath, "event"),
|
|
188
189
|
[symbols.filePath]: callerFilePath,
|
|
189
190
|
[symbolEvent]: true, // This is a workaround
|
|
190
191
|
};
|
package/src/defs.ts
CHANGED
|
@@ -309,6 +309,18 @@ export interface IEventEmission<TPayload = any> {
|
|
|
309
309
|
* The source of the event. This can be useful for debugging.
|
|
310
310
|
*/
|
|
311
311
|
source: string | symbol;
|
|
312
|
+
/**
|
|
313
|
+
* Metadata associated with the event definition.
|
|
314
|
+
*/
|
|
315
|
+
meta: IEventMeta;
|
|
316
|
+
/**
|
|
317
|
+
* Stops propagation to remaining event listeners.
|
|
318
|
+
*/
|
|
319
|
+
stopPropagation(): void;
|
|
320
|
+
/**
|
|
321
|
+
* Returns true if propagation has been stopped.
|
|
322
|
+
*/
|
|
323
|
+
isPropagationStopped(): boolean;
|
|
312
324
|
}
|
|
313
325
|
|
|
314
326
|
export interface IMiddlewareDefinition<
|
|
@@ -112,14 +112,25 @@ export class EventManager {
|
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
let propagationStopped = false;
|
|
116
|
+
|
|
115
117
|
const event: IEventEmission = {
|
|
116
118
|
id: eventDefinition.id,
|
|
117
119
|
data,
|
|
118
120
|
timestamp: new Date(),
|
|
119
121
|
source,
|
|
122
|
+
meta: eventDefinition.meta || {},
|
|
123
|
+
stopPropagation: () => {
|
|
124
|
+
propagationStopped = true;
|
|
125
|
+
},
|
|
126
|
+
isPropagationStopped: () => propagationStopped,
|
|
120
127
|
};
|
|
121
128
|
|
|
122
129
|
for (const listener of allListeners) {
|
|
130
|
+
if (propagationStopped) {
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
|
|
123
134
|
if (!listener.filter || listener.filter(event)) {
|
|
124
135
|
await listener.handler(event);
|
|
125
136
|
}
|