@bluelibs/runner 2.2.4 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/README.md +1409 -935
  2. package/dist/common.types.d.ts +20 -0
  3. package/dist/common.types.js +4 -0
  4. package/dist/common.types.js.map +1 -0
  5. package/dist/context.d.ts +34 -0
  6. package/dist/context.js +58 -0
  7. package/dist/context.js.map +1 -0
  8. package/dist/define.d.ts +24 -5
  9. package/dist/define.js +89 -20
  10. package/dist/define.js.map +1 -1
  11. package/dist/defs.d.ts +109 -73
  12. package/dist/defs.js +12 -2
  13. package/dist/defs.js.map +1 -1
  14. package/dist/errors.d.ts +5 -5
  15. package/dist/errors.js +6 -5
  16. package/dist/errors.js.map +1 -1
  17. package/dist/event.types.d.ts +18 -0
  18. package/dist/event.types.js +4 -0
  19. package/dist/event.types.js.map +1 -0
  20. package/dist/examples/registrator-example.d.ts +122 -0
  21. package/dist/examples/registrator-example.js +147 -0
  22. package/dist/examples/registrator-example.js.map +1 -0
  23. package/dist/globals/globalEvents.d.ts +41 -0
  24. package/dist/globals/globalEvents.js +94 -0
  25. package/dist/globals/globalEvents.js.map +1 -0
  26. package/dist/globals/globalMiddleware.d.ts +23 -0
  27. package/dist/globals/globalMiddleware.js +15 -0
  28. package/dist/globals/globalMiddleware.js.map +1 -0
  29. package/dist/globals/globalResources.d.ts +27 -0
  30. package/dist/globals/globalResources.js +47 -0
  31. package/dist/globals/globalResources.js.map +1 -0
  32. package/dist/globals/middleware/cache.middleware.d.ts +34 -0
  33. package/dist/globals/middleware/cache.middleware.js +85 -0
  34. package/dist/globals/middleware/cache.middleware.js.map +1 -0
  35. package/dist/globals/middleware/requireContext.middleware.d.ts +6 -0
  36. package/dist/globals/middleware/requireContext.middleware.js +25 -0
  37. package/dist/globals/middleware/requireContext.middleware.js.map +1 -0
  38. package/dist/globals/middleware/retry.middleware.d.ts +20 -0
  39. package/dist/globals/middleware/retry.middleware.js +34 -0
  40. package/dist/globals/middleware/retry.middleware.js.map +1 -0
  41. package/dist/globals/resources/queue.resource.d.ts +7 -0
  42. package/dist/globals/resources/queue.resource.js +31 -0
  43. package/dist/globals/resources/queue.resource.js.map +1 -0
  44. package/dist/index.d.ts +54 -18
  45. package/dist/index.js +14 -9
  46. package/dist/index.js.map +1 -1
  47. package/dist/middleware.types.d.ts +40 -0
  48. package/dist/middleware.types.js +4 -0
  49. package/dist/middleware.types.js.map +1 -0
  50. package/dist/models/DependencyProcessor.d.ts +6 -5
  51. package/dist/models/DependencyProcessor.js +13 -15
  52. package/dist/models/DependencyProcessor.js.map +1 -1
  53. package/dist/models/EventManager.d.ts +9 -4
  54. package/dist/models/EventManager.js +44 -2
  55. package/dist/models/EventManager.js.map +1 -1
  56. package/dist/models/Logger.d.ts +30 -13
  57. package/dist/models/Logger.js +132 -54
  58. package/dist/models/Logger.js.map +1 -1
  59. package/dist/models/OverrideManager.d.ts +13 -0
  60. package/dist/models/OverrideManager.js +70 -0
  61. package/dist/models/OverrideManager.js.map +1 -0
  62. package/dist/models/Queue.d.ts +25 -0
  63. package/dist/models/Queue.js +54 -0
  64. package/dist/models/Queue.js.map +1 -0
  65. package/dist/models/ResourceInitializer.d.ts +5 -2
  66. package/dist/models/ResourceInitializer.js +22 -14
  67. package/dist/models/ResourceInitializer.js.map +1 -1
  68. package/dist/models/Semaphore.d.ts +61 -0
  69. package/dist/models/Semaphore.js +166 -0
  70. package/dist/models/Semaphore.js.map +1 -0
  71. package/dist/models/Store.d.ts +18 -73
  72. package/dist/models/Store.js +71 -269
  73. package/dist/models/Store.js.map +1 -1
  74. package/dist/models/StoreConstants.d.ts +11 -0
  75. package/dist/models/StoreConstants.js +18 -0
  76. package/dist/models/StoreConstants.js.map +1 -0
  77. package/dist/models/StoreRegistry.d.ts +25 -0
  78. package/dist/models/StoreRegistry.js +171 -0
  79. package/dist/models/StoreRegistry.js.map +1 -0
  80. package/dist/models/StoreTypes.d.ts +21 -0
  81. package/dist/models/StoreTypes.js +3 -0
  82. package/dist/models/StoreTypes.js.map +1 -0
  83. package/dist/models/StoreValidator.d.ts +10 -0
  84. package/dist/models/StoreValidator.js +41 -0
  85. package/dist/models/StoreValidator.js.map +1 -0
  86. package/dist/models/TaskRunner.d.ts +1 -1
  87. package/dist/models/TaskRunner.js +39 -24
  88. package/dist/models/TaskRunner.js.map +1 -1
  89. package/dist/models/VarStore.d.ts +17 -0
  90. package/dist/models/VarStore.js +60 -0
  91. package/dist/models/VarStore.js.map +1 -0
  92. package/dist/models/index.d.ts +3 -0
  93. package/dist/models/index.js +3 -0
  94. package/dist/models/index.js.map +1 -1
  95. package/dist/resource.types.d.ts +31 -0
  96. package/dist/resource.types.js +3 -0
  97. package/dist/resource.types.js.map +1 -0
  98. package/dist/run.d.ts +4 -1
  99. package/dist/run.js +6 -3
  100. package/dist/run.js.map +1 -1
  101. package/dist/symbols.d.ts +24 -0
  102. package/dist/symbols.js +29 -0
  103. package/dist/symbols.js.map +1 -0
  104. package/dist/task.types.d.ts +55 -0
  105. package/dist/task.types.js +23 -0
  106. package/dist/task.types.js.map +1 -0
  107. package/dist/tools/getCallerFile.d.ts +9 -1
  108. package/dist/tools/getCallerFile.js +41 -0
  109. package/dist/tools/getCallerFile.js.map +1 -1
  110. package/dist/tools/registratorId.d.ts +4 -0
  111. package/dist/tools/registratorId.js +40 -0
  112. package/dist/tools/registratorId.js.map +1 -0
  113. package/dist/tools/simpleHash.d.ts +9 -0
  114. package/dist/tools/simpleHash.js +34 -0
  115. package/dist/tools/simpleHash.js.map +1 -0
  116. package/dist/types/base-interfaces.d.ts +18 -0
  117. package/dist/types/base-interfaces.js +6 -0
  118. package/dist/types/base-interfaces.js.map +1 -0
  119. package/dist/types/base.d.ts +13 -0
  120. package/dist/types/base.js +3 -0
  121. package/dist/types/base.js.map +1 -0
  122. package/dist/types/dependencies.d.ts +22 -0
  123. package/dist/types/dependencies.js +3 -0
  124. package/dist/types/dependencies.js.map +1 -0
  125. package/dist/types/dependency-core.d.ts +14 -0
  126. package/dist/types/dependency-core.js +5 -0
  127. package/dist/types/dependency-core.js.map +1 -0
  128. package/dist/types/events.d.ts +52 -0
  129. package/dist/types/events.js +6 -0
  130. package/dist/types/events.js.map +1 -0
  131. package/dist/types/hooks.d.ts +16 -0
  132. package/dist/types/hooks.js +5 -0
  133. package/dist/types/hooks.js.map +1 -0
  134. package/dist/types/index.d.ts +14 -0
  135. package/dist/types/index.js +27 -0
  136. package/dist/types/index.js.map +1 -0
  137. package/dist/types/meta.d.ts +13 -0
  138. package/dist/types/meta.js +5 -0
  139. package/dist/types/meta.js.map +1 -0
  140. package/dist/types/middleware.d.ts +38 -0
  141. package/dist/types/middleware.js +6 -0
  142. package/dist/types/middleware.js.map +1 -0
  143. package/dist/types/registerable.d.ts +10 -0
  144. package/dist/types/registerable.js +5 -0
  145. package/dist/types/registerable.js.map +1 -0
  146. package/dist/types/resources.d.ts +44 -0
  147. package/dist/types/resources.js +5 -0
  148. package/dist/types/resources.js.map +1 -0
  149. package/dist/types/symbols.d.ts +24 -0
  150. package/dist/types/symbols.js +30 -0
  151. package/dist/types/symbols.js.map +1 -0
  152. package/dist/types/tasks.d.ts +41 -0
  153. package/dist/types/tasks.js +5 -0
  154. package/dist/types/tasks.js.map +1 -0
  155. package/dist/types/utilities.d.ts +7 -0
  156. package/dist/types/utilities.js +5 -0
  157. package/dist/types/utilities.js.map +1 -0
  158. package/package.json +10 -6
  159. package/src/__tests__/benchmark/benchmark.test.ts +1 -1
  160. package/src/__tests__/context.test.ts +91 -0
  161. package/src/__tests__/errors.test.ts +8 -5
  162. package/src/__tests__/globalEvents.test.ts +1 -1
  163. package/src/__tests__/globals/cache.middleware.test.ts +772 -0
  164. package/src/__tests__/globals/queue.resource.test.ts +141 -0
  165. package/src/__tests__/globals/requireContext.middleware.test.ts +98 -0
  166. package/src/__tests__/globals/retry.middleware.test.ts +157 -0
  167. package/src/__tests__/index.helper.test.ts +55 -0
  168. package/src/__tests__/models/EventManager.test.ts +157 -11
  169. package/src/__tests__/models/Logger.test.ts +291 -34
  170. package/src/__tests__/models/Queue.test.ts +189 -0
  171. package/src/__tests__/models/ResourceInitializer.test.ts +8 -6
  172. package/src/__tests__/models/Semaphore.test.ts +713 -0
  173. package/src/__tests__/models/Store.test.ts +40 -0
  174. package/src/__tests__/models/TaskRunner.test.ts +86 -5
  175. package/src/__tests__/run.anonymous.test.ts +679 -0
  176. package/src/__tests__/run.middleware.test.ts +312 -12
  177. package/src/__tests__/run.overrides.test.ts +13 -10
  178. package/src/__tests__/run.test.ts +364 -13
  179. package/src/__tests__/setOutput.test.ts +244 -0
  180. package/src/__tests__/tools/getCallerFile.test.ts +124 -9
  181. package/src/__tests__/typesafety.test.ts +71 -41
  182. package/src/context.ts +86 -0
  183. package/src/define.ts +129 -34
  184. package/src/defs.ts +156 -119
  185. package/src/errors.ts +15 -10
  186. package/src/{globalEvents.ts → globals/globalEvents.ts} +13 -12
  187. package/src/globals/globalMiddleware.ts +14 -0
  188. package/src/{globalResources.ts → globals/globalResources.ts} +14 -10
  189. package/src/globals/middleware/cache.middleware.ts +115 -0
  190. package/src/globals/middleware/requireContext.middleware.ts +36 -0
  191. package/src/globals/middleware/retry.middleware.ts +56 -0
  192. package/src/globals/resources/queue.resource.ts +34 -0
  193. package/src/index.ts +9 -5
  194. package/src/models/DependencyProcessor.ts +42 -49
  195. package/src/models/EventManager.ts +64 -13
  196. package/src/models/Logger.ts +181 -64
  197. package/src/models/OverrideManager.ts +84 -0
  198. package/src/models/Queue.ts +66 -0
  199. package/src/models/ResourceInitializer.ts +40 -20
  200. package/src/models/Semaphore.ts +208 -0
  201. package/src/models/Store.ts +94 -342
  202. package/src/models/StoreConstants.ts +17 -0
  203. package/src/models/StoreRegistry.ts +228 -0
  204. package/src/models/StoreTypes.ts +46 -0
  205. package/src/models/StoreValidator.ts +43 -0
  206. package/src/models/TaskRunner.ts +54 -41
  207. package/src/models/index.ts +3 -0
  208. package/src/run.ts +7 -4
  209. package/src/tools/getCallerFile.ts +54 -2
  210. package/src/__tests__/index.ts +0 -15
  211. package/src/examples/express-mongo/index.ts +0 -1
@@ -0,0 +1,679 @@
1
+ import {
2
+ defineTask,
3
+ defineResource,
4
+ defineEvent,
5
+ defineMiddleware,
6
+ } from "../define";
7
+ import { run } from "../run";
8
+
9
+ describe("Anonymous Components", () => {
10
+ describe("Anonymous Tasks", () => {
11
+ it("should create and execute an anonymous task", async () => {
12
+ const anonymousTask = defineTask({
13
+ run: async () => "Anonymous task executed",
14
+ });
15
+
16
+ // ID should be a symbol
17
+ expect(typeof anonymousTask.id).toBe("symbol");
18
+ expect(anonymousTask.id.toString()).toContain("anonymous.test.task");
19
+
20
+ const app = defineResource({
21
+ id: "app",
22
+ register: [anonymousTask],
23
+ dependencies: { anonymousTask },
24
+ async init(_, { anonymousTask }) {
25
+ const result = await anonymousTask();
26
+ expect(result).toBe("Anonymous task executed");
27
+ },
28
+ });
29
+
30
+ await run(app);
31
+ });
32
+
33
+ it("should create anonymous task with dependencies", async () => {
34
+ const anonymousResource = defineResource({
35
+ init: async () => "Anonymous dependency",
36
+ });
37
+
38
+ const anonymousTask = defineTask({
39
+ dependencies: { anonymousResource },
40
+ run: async (_, { anonymousResource }) => {
41
+ return `Hello, ${anonymousResource}!`;
42
+ },
43
+ });
44
+
45
+ expect(typeof anonymousTask.id).toBe("symbol");
46
+ expect(typeof anonymousResource.id).toBe("symbol");
47
+
48
+ const app = defineResource({
49
+ id: "app",
50
+ register: [anonymousResource, anonymousTask],
51
+ dependencies: { anonymousTask },
52
+ async init(_, { anonymousTask }) {
53
+ const result = await anonymousTask();
54
+ expect(result).toBe("Hello, Anonymous dependency!");
55
+ },
56
+ });
57
+
58
+ await run(app);
59
+ });
60
+
61
+ it("should emit anonymous task events", async () => {
62
+ const eventHandler = jest.fn();
63
+
64
+ const anonymousTask = defineTask({
65
+ run: async () => "Task executed",
66
+ });
67
+
68
+ const eventListener = defineTask({
69
+ id: "listener",
70
+ on: anonymousTask.events.afterRun,
71
+ run: eventHandler,
72
+ });
73
+
74
+ expect(typeof anonymousTask.events.afterRun.id).toBe("symbol");
75
+ expect(anonymousTask.events.afterRun.id.toString()).toContain(
76
+ "anonymous-task.events.afterRun"
77
+ );
78
+
79
+ const app = defineResource({
80
+ id: "app",
81
+ register: [anonymousTask, eventListener],
82
+ dependencies: { anonymousTask },
83
+ async init(_, { anonymousTask }) {
84
+ await anonymousTask();
85
+ expect(eventHandler).toHaveBeenCalled();
86
+ },
87
+ });
88
+
89
+ await run(app);
90
+ });
91
+
92
+ it("should handle anonymous task with middleware", async () => {
93
+ const order: string[] = [];
94
+
95
+ const anonymousMiddleware = defineMiddleware({
96
+ run: async ({ next }) => {
97
+ order.push("middleware before");
98
+ const result = await next();
99
+ order.push("middleware after");
100
+ return result;
101
+ },
102
+ });
103
+
104
+ const anonymousTask = defineTask({
105
+ middleware: [anonymousMiddleware],
106
+ run: async () => {
107
+ order.push("task");
108
+ return "Task with middleware";
109
+ },
110
+ });
111
+
112
+ expect(typeof anonymousTask.id).toBe("symbol");
113
+ expect(typeof anonymousMiddleware.id).toBe("symbol");
114
+
115
+ const app = defineResource({
116
+ id: "app",
117
+ register: [anonymousMiddleware, anonymousTask],
118
+ dependencies: { anonymousTask },
119
+ async init(_, { anonymousTask }) {
120
+ const result = await anonymousTask();
121
+ expect(result).toBe("Task with middleware");
122
+ },
123
+ });
124
+
125
+ await run(app);
126
+
127
+ expect(order).toEqual(["middleware before", "task", "middleware after"]);
128
+ });
129
+
130
+ it("should listen to anonymous events", async () => {
131
+ const eventHandler = jest.fn();
132
+
133
+ const anonymousEvent = defineEvent<{ message: string }>({});
134
+
135
+ const eventEmitter = defineTask({
136
+ dependencies: { anonymousEvent },
137
+ run: async (_, { anonymousEvent }) => {
138
+ await anonymousEvent({ message: "Anonymous event!" });
139
+ return "Event emitted";
140
+ },
141
+ });
142
+
143
+ const eventListener = defineTask({
144
+ on: anonymousEvent,
145
+ run: eventHandler,
146
+ });
147
+
148
+ expect(typeof anonymousEvent.id).toBe("symbol");
149
+ expect(anonymousEvent.id.toString()).toContain("anonymous.test.event");
150
+
151
+ const app = defineResource({
152
+ id: "app",
153
+ register: [anonymousEvent, eventEmitter, eventListener],
154
+ dependencies: { eventEmitter },
155
+ async init(_, { eventEmitter }) {
156
+ await eventEmitter();
157
+ expect(eventHandler).toHaveBeenCalled();
158
+ },
159
+ });
160
+
161
+ await run(app);
162
+ });
163
+ });
164
+
165
+ describe("Anonymous Resources", () => {
166
+ it("should create and initialize an anonymous resource", async () => {
167
+ const anonymousResource = defineResource({
168
+ init: async () => "Anonymous resource value",
169
+ });
170
+
171
+ expect(typeof anonymousResource.id).toBe("symbol");
172
+ expect(anonymousResource.id.toString()).toContain(
173
+ "anonymous.test.resource"
174
+ );
175
+
176
+ const app = defineResource({
177
+ id: "app",
178
+ register: [anonymousResource],
179
+ dependencies: { anonymousResource },
180
+ async init(_, { anonymousResource }) {
181
+ expect(anonymousResource).toBe("Anonymous resource value");
182
+ },
183
+ });
184
+
185
+ await run(app);
186
+ });
187
+
188
+ it("should create anonymous resource with dependencies", async () => {
189
+ const dependencyResource = defineResource({
190
+ init: async () => "Dependency value",
191
+ });
192
+
193
+ const anonymousResource = defineResource({
194
+ dependencies: { dependencyResource },
195
+ init: async (_, { dependencyResource }) => {
196
+ return `Using ${dependencyResource}`;
197
+ },
198
+ });
199
+
200
+ expect(typeof anonymousResource.id).toBe("symbol");
201
+ expect(typeof dependencyResource.id).toBe("symbol");
202
+
203
+ const app = defineResource({
204
+ id: "app",
205
+ register: [dependencyResource, anonymousResource],
206
+ dependencies: { anonymousResource },
207
+ async init(_, { anonymousResource }) {
208
+ expect(anonymousResource).toBe("Using Dependency value");
209
+ },
210
+ });
211
+
212
+ await run(app);
213
+ });
214
+
215
+ it("should create anonymous resource with configuration", async () => {
216
+ const anonymousResource = defineResource({
217
+ init: async (config: { prefix: string }) =>
218
+ `${config.prefix} configured!`,
219
+ });
220
+
221
+ expect(typeof anonymousResource.id).toBe("symbol");
222
+
223
+ const app = defineResource({
224
+ id: "app",
225
+ register: [anonymousResource.with({ prefix: "Anonymous" })],
226
+ dependencies: { anonymousResource },
227
+ async init(_, { anonymousResource }) {
228
+ expect(anonymousResource).toBe("Anonymous configured!");
229
+ },
230
+ });
231
+
232
+ await run(app);
233
+ });
234
+
235
+ it("should emit anonymous resource events", async () => {
236
+ const eventHandler = jest.fn();
237
+
238
+ const anonymousResource = defineResource({
239
+ init: async () => "Resource initialized",
240
+ });
241
+
242
+ const eventListener = defineTask({
243
+ id: "listener",
244
+ on: anonymousResource.events.afterInit,
245
+ run: eventHandler,
246
+ });
247
+
248
+ expect(typeof anonymousResource.events.afterInit.id).toBe("symbol");
249
+ expect(anonymousResource.events.afterInit.id.toString()).toContain(
250
+ "anonymous-resource.events.afterInit"
251
+ );
252
+
253
+ const app = defineResource({
254
+ id: "app",
255
+ register: [anonymousResource, eventListener],
256
+ dependencies: { anonymousResource },
257
+ async init(_, { anonymousResource }) {
258
+ expect(anonymousResource).toBe("Resource initialized");
259
+ expect(eventHandler).toHaveBeenCalled();
260
+ },
261
+ });
262
+
263
+ await run(app);
264
+ });
265
+
266
+ it("should dispose anonymous resource properly", async () => {
267
+ const disposeFn = jest.fn();
268
+
269
+ const anonymousResource = defineResource({
270
+ init: async () => "Resource value",
271
+ dispose: disposeFn,
272
+ });
273
+
274
+ const app = defineResource({
275
+ id: "app",
276
+ register: [anonymousResource],
277
+ dependencies: { anonymousResource },
278
+ async init(_, { anonymousResource }) {
279
+ expect(anonymousResource).toBe("Resource value");
280
+ return anonymousResource;
281
+ },
282
+ });
283
+
284
+ const result = await run(app);
285
+ await result.dispose();
286
+
287
+ expect(disposeFn).toHaveBeenCalledWith(
288
+ "Resource value",
289
+ {},
290
+ {},
291
+ undefined
292
+ );
293
+ });
294
+
295
+ it("should work with anonymous resource without init method", async () => {
296
+ const nestedResource = defineResource({
297
+ init: async () => "Nested value",
298
+ });
299
+
300
+ const anonymousResource = defineResource({
301
+ register: [nestedResource],
302
+ });
303
+
304
+ expect(typeof anonymousResource.id).toBe("symbol");
305
+
306
+ const app = defineResource({
307
+ id: "app",
308
+ register: [anonymousResource],
309
+ dependencies: { anonymousResource },
310
+ async init(_, { anonymousResource }) {
311
+ expect(anonymousResource).toBeUndefined();
312
+ },
313
+ });
314
+
315
+ await run(app);
316
+ });
317
+ });
318
+
319
+ describe("Anonymous Events", () => {
320
+ it("should create and emit anonymous events", async () => {
321
+ const eventHandler = jest.fn();
322
+
323
+ const anonymousEvent = defineEvent<{ data: string }>({});
324
+
325
+ const emitter = defineTask({
326
+ dependencies: { anonymousEvent },
327
+ run: async (_, { anonymousEvent }) => {
328
+ await anonymousEvent({ data: "Anonymous event data" });
329
+ },
330
+ });
331
+
332
+ const listener = defineTask({
333
+ on: anonymousEvent,
334
+ run: eventHandler,
335
+ });
336
+
337
+ expect(typeof anonymousEvent.id).toBe("symbol");
338
+ expect(anonymousEvent.id.toString()).toContain("anonymous.test.event");
339
+
340
+ const app = defineResource({
341
+ id: "app",
342
+ register: [anonymousEvent, emitter, listener],
343
+ dependencies: { emitter },
344
+ async init(_, { emitter }) {
345
+ await emitter();
346
+ expect(eventHandler).toHaveBeenCalledWith(
347
+ expect.objectContaining({
348
+ data: { data: "Anonymous event data" },
349
+ }),
350
+ expect.any(Object)
351
+ );
352
+ },
353
+ });
354
+
355
+ await run(app);
356
+ });
357
+
358
+ it("should handle multiple anonymous events", async () => {
359
+ const handler1 = jest.fn();
360
+ const handler2 = jest.fn();
361
+
362
+ const anonymousEvent1 = defineEvent<{ type: string }>({});
363
+ const anonymousEvent2 = defineEvent<{ value: number }>({});
364
+
365
+ const emitter = defineTask({
366
+ dependencies: { anonymousEvent1, anonymousEvent2 },
367
+ run: async (_, { anonymousEvent1, anonymousEvent2 }) => {
368
+ await anonymousEvent1({ type: "first" });
369
+ await anonymousEvent2({ value: 42 });
370
+ },
371
+ });
372
+
373
+ const listener1 = defineTask({
374
+ on: anonymousEvent1,
375
+ run: handler1,
376
+ });
377
+
378
+ const listener2 = defineTask({
379
+ on: anonymousEvent2,
380
+ run: handler2,
381
+ });
382
+
383
+ expect(typeof anonymousEvent1.id).toBe("symbol");
384
+ expect(typeof anonymousEvent2.id).toBe("symbol");
385
+
386
+ const app = defineResource({
387
+ id: "app",
388
+ register: [
389
+ anonymousEvent1,
390
+ anonymousEvent2,
391
+ emitter,
392
+ listener1,
393
+ listener2,
394
+ ],
395
+ dependencies: { emitter },
396
+ async init(_, { emitter }) {
397
+ await emitter();
398
+ expect(handler1).toHaveBeenCalled();
399
+ expect(handler2).toHaveBeenCalled();
400
+ },
401
+ });
402
+
403
+ await run(app);
404
+ });
405
+ });
406
+
407
+ describe("Anonymous Middleware", () => {
408
+ it("should create and use anonymous middleware", async () => {
409
+ const order: string[] = [];
410
+
411
+ const anonymousMiddleware = defineMiddleware({
412
+ run: async ({ next }) => {
413
+ order.push("anonymous middleware");
414
+ return await next();
415
+ },
416
+ });
417
+
418
+ const testTask = defineTask({
419
+ id: "test.task",
420
+ middleware: [anonymousMiddleware],
421
+ run: async () => {
422
+ order.push("task execution");
423
+ return "Task result";
424
+ },
425
+ });
426
+
427
+ expect(typeof anonymousMiddleware.id).toBe("symbol");
428
+ expect(anonymousMiddleware.id.toString()).toContain(
429
+ "anonymous.test.middleware"
430
+ );
431
+
432
+ const app = defineResource({
433
+ id: "app",
434
+ register: [anonymousMiddleware, testTask],
435
+ dependencies: { testTask },
436
+ async init(_, { testTask }) {
437
+ const result = await testTask();
438
+ expect(result).toBe("Task result");
439
+ },
440
+ });
441
+
442
+ await run(app);
443
+
444
+ expect(order).toEqual(["anonymous middleware", "task execution"]);
445
+ });
446
+
447
+ it("should create anonymous middleware with dependencies", async () => {
448
+ const anonymousResource = defineResource({
449
+ init: async () => "Middleware dependency",
450
+ });
451
+
452
+ const anonymousMiddleware = defineMiddleware({
453
+ dependencies: { anonymousResource },
454
+ run: async ({ next }, { anonymousResource }) => {
455
+ const result = await next();
456
+ return `${result} - ${anonymousResource}`;
457
+ },
458
+ });
459
+
460
+ const testTask = defineTask({
461
+ id: "test.task",
462
+ middleware: [anonymousMiddleware],
463
+ run: async () => "Original result",
464
+ });
465
+
466
+ expect(typeof anonymousMiddleware.id).toBe("symbol");
467
+ expect(typeof anonymousResource.id).toBe("symbol");
468
+
469
+ const app = defineResource({
470
+ id: "app",
471
+ register: [anonymousResource, anonymousMiddleware, testTask],
472
+ dependencies: { testTask },
473
+ async init(_, { testTask }) {
474
+ const result = await testTask();
475
+ expect(result).toBe("Original result - Middleware dependency");
476
+ },
477
+ });
478
+
479
+ await run(app);
480
+ });
481
+
482
+ it("should create anonymous middleware with configuration", async () => {
483
+ const anonymousMiddleware = defineMiddleware({
484
+ run: async ({ next }, _, config: { multiplier: number }) => {
485
+ const result = await next();
486
+ return result * config.multiplier;
487
+ },
488
+ });
489
+
490
+ const testTask = defineTask({
491
+ id: "test.task",
492
+ middleware: [anonymousMiddleware.with({ multiplier: 3 })],
493
+ run: async () => 10,
494
+ });
495
+
496
+ expect(typeof anonymousMiddleware.id).toBe("symbol");
497
+
498
+ const app = defineResource({
499
+ id: "app",
500
+ register: [anonymousMiddleware, testTask],
501
+ dependencies: { testTask },
502
+ async init(_, { testTask }) {
503
+ const result = await testTask();
504
+ expect(result).toBe(30);
505
+ },
506
+ });
507
+
508
+ await run(app);
509
+ });
510
+
511
+ it("should chain multiple anonymous middleware", async () => {
512
+ const order: string[] = [];
513
+
514
+ const middleware1 = defineMiddleware({
515
+ run: async ({ next }) => {
516
+ order.push("middleware1 before");
517
+ const result = await next();
518
+ order.push("middleware1 after");
519
+ return result;
520
+ },
521
+ });
522
+
523
+ const middleware2 = defineMiddleware({
524
+ run: async ({ next }) => {
525
+ order.push("middleware2 before");
526
+ const result = await next();
527
+ order.push("middleware2 after");
528
+ return result;
529
+ },
530
+ });
531
+
532
+ const testTask = defineTask({
533
+ id: "test.task",
534
+ middleware: [middleware1, middleware2],
535
+ run: async () => {
536
+ order.push("task");
537
+ return "Task executed";
538
+ },
539
+ });
540
+
541
+ expect(typeof middleware1.id).toBe("symbol");
542
+ expect(typeof middleware2.id).toBe("symbol");
543
+
544
+ const app = defineResource({
545
+ id: "app",
546
+ register: [middleware1, middleware2, testTask],
547
+ dependencies: { testTask },
548
+ async init(_, { testTask }) {
549
+ await testTask();
550
+ },
551
+ });
552
+
553
+ await run(app);
554
+
555
+ expect(order).toEqual([
556
+ "middleware1 before",
557
+ "middleware2 before",
558
+ "task",
559
+ "middleware2 after",
560
+ "middleware1 after",
561
+ ]);
562
+ });
563
+ });
564
+
565
+ describe("Complex Anonymous Combinations", () => {
566
+ it("should work with all anonymous components together", async () => {
567
+ const results: string[] = [];
568
+
569
+ // Anonymous event
570
+ const anonymousEvent = defineEvent<{ step: string }>({});
571
+
572
+ // Anonymous resource
573
+ const anonymousResource = defineResource({
574
+ init: async () => ({ step: (name: string) => results.push(name) }),
575
+ });
576
+
577
+ // Anonymous middleware
578
+ const anonymousMiddleware = defineMiddleware({
579
+ dependencies: { anonymousResource },
580
+ run: async ({ next }, { anonymousResource }) => {
581
+ anonymousResource.step("middleware before");
582
+ const result = await next();
583
+ anonymousResource.step("middleware after");
584
+ return result;
585
+ },
586
+ });
587
+
588
+ // Anonymous task that emits event
589
+ const anonymousEmitter = defineTask({
590
+ dependencies: { anonymousEvent, anonymousResource },
591
+ middleware: [anonymousMiddleware],
592
+ run: async (_, { anonymousEvent, anonymousResource }) => {
593
+ anonymousResource.step("task execution");
594
+ await anonymousEvent({ step: "event emitted" });
595
+ return "Emitter done";
596
+ },
597
+ });
598
+
599
+ // Anonymous listener task
600
+ const anonymousListener = defineTask({
601
+ on: anonymousEvent,
602
+ dependencies: { anonymousResource },
603
+ run: async (event, { anonymousResource }) => {
604
+ anonymousResource.step(`event received: ${event.data.step}`);
605
+ },
606
+ });
607
+
608
+ // Verify all components are anonymous
609
+ expect(typeof anonymousEvent.id).toBe("symbol");
610
+ expect(typeof anonymousResource.id).toBe("symbol");
611
+ expect(typeof anonymousMiddleware.id).toBe("symbol");
612
+ expect(typeof anonymousEmitter.id).toBe("symbol");
613
+ expect(typeof anonymousListener.id).toBe("symbol");
614
+
615
+ const app = defineResource({
616
+ id: "app",
617
+ register: [
618
+ anonymousEvent,
619
+ anonymousResource,
620
+ anonymousMiddleware,
621
+ anonymousEmitter,
622
+ anonymousListener,
623
+ ],
624
+ dependencies: { anonymousEmitter },
625
+ async init(_, { anonymousEmitter }) {
626
+ const result = await anonymousEmitter();
627
+ expect(result).toBe("Emitter done");
628
+ // Wait a bit for event processing to complete
629
+ await new Promise((resolve) => setTimeout(resolve, 10));
630
+ },
631
+ });
632
+
633
+ await run(app);
634
+
635
+ expect(results).toEqual([
636
+ "middleware before",
637
+ "task execution",
638
+ "event received: event emitted",
639
+ "middleware after",
640
+ ]);
641
+ });
642
+
643
+ it("should handle error suppression with anonymous components", async () => {
644
+ const suppressMock = jest.fn();
645
+
646
+ const anonymousTask = defineTask({
647
+ run: async () => {
648
+ throw new Error("Anonymous task failed");
649
+ },
650
+ });
651
+
652
+ const anonymousErrorHandler = defineTask({
653
+ on: anonymousTask.events.onError,
654
+ run: async (event) => {
655
+ suppressMock();
656
+ event.data.suppress();
657
+ },
658
+ });
659
+
660
+ expect(typeof anonymousTask.id).toBe("symbol");
661
+ expect(typeof anonymousErrorHandler.id).toBe("symbol");
662
+
663
+ const app = defineResource({
664
+ id: "app",
665
+ register: [anonymousTask, anonymousErrorHandler],
666
+ dependencies: { anonymousTask },
667
+ async init(_, { anonymousTask }) {
668
+ const result = await anonymousTask();
669
+ expect(result).toBeUndefined();
670
+ return "App completed";
671
+ },
672
+ });
673
+
674
+ const result = await run(app);
675
+ expect(result.value).toBe("App completed");
676
+ expect(suppressMock).toHaveBeenCalled();
677
+ });
678
+ });
679
+ });