@bluelibs/runner 4.8.5 → 4.9.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 (173) hide show
  1. package/AI.md +8 -0
  2. package/README.md +39 -4
  3. package/dist/browser/index.cjs +596 -428
  4. package/dist/browser/index.cjs.map +1 -1
  5. package/dist/browser/index.d.mts +2221 -0
  6. package/dist/browser/index.d.ts +2221 -0
  7. package/dist/browser/index.mjs +596 -428
  8. package/dist/browser/index.mjs.map +1 -1
  9. package/dist/edge/index.cjs +596 -428
  10. package/dist/edge/index.cjs.map +1 -1
  11. package/dist/edge/index.d.mts +2221 -0
  12. package/dist/edge/index.d.ts +2221 -0
  13. package/dist/edge/index.mjs +596 -428
  14. package/dist/edge/index.mjs.map +1 -1
  15. package/dist/node/node.cjs +638 -447
  16. package/dist/node/node.cjs.map +1 -1
  17. package/dist/node/node.d.mts +2472 -0
  18. package/dist/node/node.d.ts +2425 -55
  19. package/dist/node/node.mjs +638 -447
  20. package/dist/node/node.mjs.map +1 -1
  21. package/dist/universal/index.cjs +594 -428
  22. package/dist/universal/index.cjs.map +1 -1
  23. package/dist/universal/index.d.mts +2221 -0
  24. package/dist/universal/index.d.ts +2221 -0
  25. package/dist/universal/index.mjs +594 -428
  26. package/dist/universal/index.mjs.map +1 -1
  27. package/package.json +5 -5
  28. package/dist/define.d.ts +0 -9
  29. package/dist/definers/builders/asyncContext.d.ts +0 -11
  30. package/dist/definers/builders/core.d.ts +0 -30
  31. package/dist/definers/builders/error.d.ts +0 -13
  32. package/dist/definers/builders/event.d.ts +0 -12
  33. package/dist/definers/builders/hook.d.ts +0 -20
  34. package/dist/definers/builders/middleware.d.ts +0 -39
  35. package/dist/definers/builders/resource.d.ts +0 -40
  36. package/dist/definers/builders/tag.d.ts +0 -10
  37. package/dist/definers/builders/task.d.ts +0 -37
  38. package/dist/definers/builders/task.phantom.d.ts +0 -27
  39. package/dist/definers/builders/utils.d.ts +0 -4
  40. package/dist/definers/defineAsyncContext.d.ts +0 -15
  41. package/dist/definers/defineError.d.ts +0 -26
  42. package/dist/definers/defineEvent.d.ts +0 -2
  43. package/dist/definers/defineHook.d.ts +0 -6
  44. package/dist/definers/defineOverride.d.ts +0 -17
  45. package/dist/definers/defineResource.d.ts +0 -2
  46. package/dist/definers/defineResourceMiddleware.d.ts +0 -2
  47. package/dist/definers/defineTag.d.ts +0 -12
  48. package/dist/definers/defineTask.d.ts +0 -18
  49. package/dist/definers/defineTaskMiddleware.d.ts +0 -2
  50. package/dist/definers/tools.d.ts +0 -53
  51. package/dist/defs.d.ts +0 -31
  52. package/dist/errors.d.ts +0 -62
  53. package/dist/globals/debug.d.ts +0 -10
  54. package/dist/globals/globalEvents.d.ts +0 -8
  55. package/dist/globals/globalMiddleware.d.ts +0 -31
  56. package/dist/globals/globalResources.d.ts +0 -41
  57. package/dist/globals/globalTags.d.ts +0 -11
  58. package/dist/globals/middleware/cache.middleware.d.ts +0 -27
  59. package/dist/globals/middleware/requireContext.middleware.d.ts +0 -6
  60. package/dist/globals/middleware/retry.middleware.d.ts +0 -21
  61. package/dist/globals/middleware/timeout.middleware.d.ts +0 -9
  62. package/dist/globals/middleware/tunnel.middleware.d.ts +0 -2
  63. package/dist/globals/resources/debug/debug.resource.d.ts +0 -7
  64. package/dist/globals/resources/debug/debug.tag.d.ts +0 -2
  65. package/dist/globals/resources/debug/debugConfig.resource.d.ts +0 -22
  66. package/dist/globals/resources/debug/executionTracker.middleware.d.ts +0 -50
  67. package/dist/globals/resources/debug/globalEvent.hook.d.ts +0 -27
  68. package/dist/globals/resources/debug/hook.hook.d.ts +0 -30
  69. package/dist/globals/resources/debug/index.d.ts +0 -6
  70. package/dist/globals/resources/debug/middleware.hook.d.ts +0 -30
  71. package/dist/globals/resources/debug/types.d.ts +0 -25
  72. package/dist/globals/resources/debug/utils.d.ts +0 -2
  73. package/dist/globals/resources/httpClientFactory.resource.d.ts +0 -28
  74. package/dist/globals/resources/queue.resource.d.ts +0 -10
  75. package/dist/globals/resources/tunnel/ejson-extensions.d.ts +0 -1
  76. package/dist/globals/resources/tunnel/error-utils.d.ts +0 -1
  77. package/dist/globals/resources/tunnel/plan.d.ts +0 -19
  78. package/dist/globals/resources/tunnel/protocol.d.ts +0 -47
  79. package/dist/globals/resources/tunnel/serializer.d.ts +0 -9
  80. package/dist/globals/resources/tunnel/tunnel.policy.tag.d.ts +0 -18
  81. package/dist/globals/resources/tunnel/tunnel.tag.d.ts +0 -2
  82. package/dist/globals/resources/tunnel/types.d.ts +0 -42
  83. package/dist/globals/tunnels/index.d.ts +0 -23
  84. package/dist/globals/types.d.ts +0 -4
  85. package/dist/http-client.d.ts +0 -25
  86. package/dist/http-fetch-tunnel.resource.d.ts +0 -11
  87. package/dist/index.d.ts +0 -117
  88. package/dist/models/DependencyProcessor.d.ts +0 -48
  89. package/dist/models/EventManager.d.ts +0 -153
  90. package/dist/models/LogPrinter.d.ts +0 -55
  91. package/dist/models/Logger.d.ts +0 -85
  92. package/dist/models/MiddlewareManager.d.ts +0 -75
  93. package/dist/models/OverrideManager.d.ts +0 -13
  94. package/dist/models/Queue.d.ts +0 -26
  95. package/dist/models/ResourceInitializer.d.ts +0 -20
  96. package/dist/models/RunResult.d.ts +0 -35
  97. package/dist/models/Semaphore.d.ts +0 -61
  98. package/dist/models/Store.d.ts +0 -73
  99. package/dist/models/StoreRegistry.d.ts +0 -49
  100. package/dist/models/StoreValidator.d.ts +0 -8
  101. package/dist/models/TaskRunner.d.ts +0 -27
  102. package/dist/models/UnhandledError.d.ts +0 -11
  103. package/dist/models/index.d.ts +0 -11
  104. package/dist/models/middleware/InterceptorRegistry.d.ts +0 -56
  105. package/dist/models/middleware/MiddlewareResolver.d.ts +0 -31
  106. package/dist/models/middleware/ResourceMiddlewareComposer.d.ts +0 -34
  107. package/dist/models/middleware/TaskMiddlewareComposer.d.ts +0 -43
  108. package/dist/models/middleware/ValidationHelper.d.ts +0 -20
  109. package/dist/models/middleware/index.d.ts +0 -6
  110. package/dist/models/middleware/types.d.ts +0 -10
  111. package/dist/models/utils/findCircularDependencies.d.ts +0 -16
  112. package/dist/models/utils/safeStringify.d.ts +0 -3
  113. package/dist/node/exposure/allowList.d.ts +0 -3
  114. package/dist/node/exposure/authenticator.d.ts +0 -6
  115. package/dist/node/exposure/cors.d.ts +0 -4
  116. package/dist/node/exposure/createNodeExposure.d.ts +0 -2
  117. package/dist/node/exposure/exposureServer.d.ts +0 -18
  118. package/dist/node/exposure/httpResponse.d.ts +0 -10
  119. package/dist/node/exposure/logging.d.ts +0 -4
  120. package/dist/node/exposure/multipart.d.ts +0 -27
  121. package/dist/node/exposure/requestBody.d.ts +0 -11
  122. package/dist/node/exposure/requestContext.d.ts +0 -17
  123. package/dist/node/exposure/requestHandlers.d.ts +0 -24
  124. package/dist/node/exposure/resourceTypes.d.ts +0 -60
  125. package/dist/node/exposure/router.d.ts +0 -17
  126. package/dist/node/exposure/serverLifecycle.d.ts +0 -13
  127. package/dist/node/exposure/types.d.ts +0 -31
  128. package/dist/node/exposure/utils.d.ts +0 -17
  129. package/dist/node/exposure.resource.d.ts +0 -12
  130. package/dist/node/files.d.ts +0 -9
  131. package/dist/node/http-mixed-client.d.ts +0 -30
  132. package/dist/node/http-smart-client.model.d.ts +0 -24
  133. package/dist/node/index.d.ts +0 -1
  134. package/dist/node/inputFile.model.d.ts +0 -22
  135. package/dist/node/inputFile.utils.d.ts +0 -14
  136. package/dist/node/platform/createFile.d.ts +0 -9
  137. package/dist/node/resources/http-mixed-client.factory.resource.d.ts +0 -17
  138. package/dist/node/resources/http-smart-client.factory.resource.d.ts +0 -16
  139. package/dist/node/tunnel.allowlist.d.ts +0 -7
  140. package/dist/node/upload/manifest.d.ts +0 -22
  141. package/dist/platform/adapters/browser.d.ts +0 -14
  142. package/dist/platform/adapters/edge.d.ts +0 -5
  143. package/dist/platform/adapters/node-als.d.ts +0 -1
  144. package/dist/platform/adapters/node.d.ts +0 -15
  145. package/dist/platform/adapters/universal-generic.d.ts +0 -14
  146. package/dist/platform/adapters/universal.d.ts +0 -17
  147. package/dist/platform/createFile.d.ts +0 -10
  148. package/dist/platform/createWebFile.d.ts +0 -11
  149. package/dist/platform/factory.d.ts +0 -2
  150. package/dist/platform/index.d.ts +0 -27
  151. package/dist/platform/types.d.ts +0 -29
  152. package/dist/processHooks.d.ts +0 -2
  153. package/dist/run.d.ts +0 -14
  154. package/dist/testing.d.ts +0 -25
  155. package/dist/tools/getCallerFile.d.ts +0 -1
  156. package/dist/tunnels/buildUniversalManifest.d.ts +0 -24
  157. package/dist/types/asyncContext.d.ts +0 -39
  158. package/dist/types/contracts.d.ts +0 -63
  159. package/dist/types/error.d.ts +0 -34
  160. package/dist/types/event.d.ts +0 -74
  161. package/dist/types/hook.d.ts +0 -23
  162. package/dist/types/inputFile.d.ts +0 -34
  163. package/dist/types/meta.d.ts +0 -18
  164. package/dist/types/resource.d.ts +0 -87
  165. package/dist/types/resourceMiddleware.d.ts +0 -47
  166. package/dist/types/runner.d.ts +0 -68
  167. package/dist/types/storeTypes.d.ts +0 -40
  168. package/dist/types/symbols.d.ts +0 -32
  169. package/dist/types/tag.d.ts +0 -46
  170. package/dist/types/task.d.ts +0 -54
  171. package/dist/types/taskMiddleware.d.ts +0 -48
  172. package/dist/types/utilities.d.ts +0 -113
  173. package/dist/utils/detectRunnerMode.d.ts +0 -9
@@ -171,78 +171,87 @@ var cacheMiddleware = defineTaskMiddleware({
171
171
  }
172
172
  });
173
173
 
174
- // src/tools/getCallerFile.ts
175
- function getCallerFile() {
176
- const originalFunc = Error.prepareStackTrace;
177
- try {
178
- const err = new Error();
179
- let callerfile;
180
- let currentfile;
181
- Error.prepareStackTrace = (err2, stack2) => stack2;
182
- const stack = err.stack;
183
- stack.shift();
184
- currentfile = stack.shift()?.getFileName?.();
185
- callerfile = stack.shift()?.getFileName?.();
186
- return callerfile;
187
- } finally {
188
- Error.prepareStackTrace = originalFunc;
189
- }
174
+ // src/platform/adapters/node-als.ts
175
+ async function loadAsyncLocalStorageClass() {
176
+ const mod = __require("async_hooks");
177
+ return mod.AsyncLocalStorage;
190
178
  }
191
- __name(getCallerFile, "getCallerFile");
179
+ __name(loadAsyncLocalStorageClass, "loadAsyncLocalStorageClass");
192
180
 
193
- // src/definers/defineTask.ts
194
- function defineTask(taskConfig) {
195
- const filePath = getCallerFile();
196
- const id2 = taskConfig.id;
197
- return {
198
- [symbolTask]: true,
199
- [symbolFilePath]: filePath,
200
- id: id2,
201
- dependencies: taskConfig.dependencies || {},
202
- middleware: taskConfig.middleware || [],
203
- run: taskConfig.run,
204
- inputSchema: taskConfig.inputSchema,
205
- resultSchema: taskConfig.resultSchema,
206
- meta: taskConfig.meta || {},
207
- tags: taskConfig.tags || [],
208
- // autorun,
209
- optional() {
210
- return {
211
- inner: this,
212
- [symbolOptionalDependency]: true
213
- };
214
- }
215
- };
216
- }
217
- __name(defineTask, "defineTask");
218
- defineTask.phantom = (taskConfig) => {
219
- const taskDef = defineTask({
220
- ...taskConfig,
221
- run: /* @__PURE__ */ __name(async (input) => {
222
- return void 0;
223
- }, "run")
224
- });
225
- taskDef[symbolPhantomTask] = true;
226
- return taskDef;
181
+ // src/platform/adapters/node.ts
182
+ var NodePlatformAdapter = class {
183
+ constructor() {
184
+ this.id = "node";
185
+ this.setTimeout = globalThis.setTimeout;
186
+ this.clearTimeout = globalThis.clearTimeout;
187
+ }
188
+ static {
189
+ __name(this, "NodePlatformAdapter");
190
+ }
191
+ async init() {
192
+ this.alsClass = await loadAsyncLocalStorageClass();
193
+ }
194
+ onUncaughtException(handler) {
195
+ process.on("uncaughtException", handler);
196
+ return () => process.off("uncaughtException", handler);
197
+ }
198
+ onUnhandledRejection(handler) {
199
+ const h = /* @__PURE__ */ __name((reason) => handler(reason), "h");
200
+ process.on("unhandledRejection", h);
201
+ return () => process.off("unhandledRejection", h);
202
+ }
203
+ onShutdownSignal(handler) {
204
+ process.on("SIGINT", handler);
205
+ process.on("SIGTERM", handler);
206
+ return () => {
207
+ process.off("SIGINT", handler);
208
+ process.off("SIGTERM", handler);
209
+ };
210
+ }
211
+ exit(code) {
212
+ process.exit(code);
213
+ }
214
+ getEnv(key) {
215
+ return process.env[key];
216
+ }
217
+ hasAsyncLocalStorage() {
218
+ return true;
219
+ }
220
+ createAsyncLocalStorage() {
221
+ let instance;
222
+ const ensure = /* @__PURE__ */ __name(() => {
223
+ if (!this.alsClass) {
224
+ let als;
225
+ const forceNoop = typeof process !== "undefined" && !!process.env?.RUNNER_FORCE_NOOP_ALS;
226
+ if (!forceNoop) {
227
+ try {
228
+ const mod = __require("async_hooks");
229
+ als = mod?.AsyncLocalStorage;
230
+ } catch (_) {
231
+ als = void 0;
232
+ }
233
+ }
234
+ this.alsClass = als ? als : class NoopAsyncLocalStorage {
235
+ static {
236
+ __name(this, "NoopAsyncLocalStorage");
237
+ }
238
+ getStore() {
239
+ return void 0;
240
+ }
241
+ run(_store, callback) {
242
+ return callback();
243
+ }
244
+ };
245
+ }
246
+ return instance ??= new this.alsClass();
247
+ }, "ensure");
248
+ return {
249
+ getStore: /* @__PURE__ */ __name(() => ensure().getStore(), "getStore"),
250
+ run: /* @__PURE__ */ __name((store2, callback) => ensure().run(store2, callback), "run")
251
+ };
252
+ }
227
253
  };
228
254
 
229
- // src/definers/defineHook.ts
230
- function defineHook(hookDef) {
231
- const filePath = getCallerFile();
232
- return {
233
- [symbolHook]: true,
234
- [symbolFilePath]: filePath,
235
- id: hookDef.id,
236
- dependencies: hookDef.dependencies || {},
237
- on: hookDef.on,
238
- order: hookDef.order,
239
- run: hookDef.run,
240
- meta: hookDef.meta || {},
241
- tags: hookDef.tags || []
242
- };
243
- }
244
- __name(defineHook, "defineHook");
245
-
246
255
  // src/errors.ts
247
256
  var errors_exports = {};
248
257
  __export(errors_exports, {
@@ -338,13 +347,18 @@ function makeErrorBuilder(state) {
338
347
  const next = clone(state, { format: fn });
339
348
  return makeErrorBuilder(next);
340
349
  },
350
+ meta(m) {
351
+ const next = clone(state, { meta: m });
352
+ return makeErrorBuilder(next);
353
+ },
341
354
  build() {
342
355
  return defineError({
343
356
  id: state.id,
344
357
  serialize: state.serialize,
345
358
  parse: state.parse,
346
359
  dataSchema: state.dataSchema,
347
- format: state.format
360
+ format: state.format,
361
+ meta: state.meta
348
362
  });
349
363
  }
350
364
  };
@@ -356,93 +370,101 @@ function errorBuilder(id2) {
356
370
  id: id2,
357
371
  serialize: void 0,
358
372
  parse: void 0,
359
- dataSchema: void 0
373
+ dataSchema: void 0,
374
+ meta: {}
360
375
  });
361
376
  return makeErrorBuilder(initial);
362
377
  }
363
378
  __name(errorBuilder, "errorBuilder");
364
379
  var error = errorBuilder;
365
380
 
366
- // src/platform/adapters/node-als.ts
367
- async function loadAsyncLocalStorageClass() {
368
- const mod = __require("async_hooks");
369
- return mod.AsyncLocalStorage;
370
- }
371
- __name(loadAsyncLocalStorageClass, "loadAsyncLocalStorageClass");
372
-
373
- // src/platform/adapters/node.ts
374
- var NodePlatformAdapter = class {
375
- constructor() {
376
- this.id = "node";
377
- this.setTimeout = globalThis.setTimeout;
378
- this.clearTimeout = globalThis.clearTimeout;
379
- }
380
- static {
381
- __name(this, "NodePlatformAdapter");
382
- }
383
- async init() {
384
- this.alsClass = await loadAsyncLocalStorageClass();
385
- }
386
- onUncaughtException(handler) {
387
- process.on("uncaughtException", handler);
388
- return () => process.off("uncaughtException", handler);
389
- }
390
- onUnhandledRejection(handler) {
391
- const h = /* @__PURE__ */ __name((reason) => handler(reason), "h");
392
- process.on("unhandledRejection", h);
393
- return () => process.off("unhandledRejection", h);
394
- }
395
- onShutdownSignal(handler) {
396
- process.on("SIGINT", handler);
397
- process.on("SIGTERM", handler);
398
- return () => {
399
- process.off("SIGINT", handler);
400
- process.off("SIGTERM", handler);
401
- };
402
- }
403
- exit(code) {
404
- process.exit(code);
405
- }
406
- getEnv(key) {
407
- return process.env[key];
408
- }
409
- hasAsyncLocalStorage() {
410
- return true;
411
- }
412
- createAsyncLocalStorage() {
413
- let instance;
414
- const ensure = /* @__PURE__ */ __name(() => {
415
- if (!this.alsClass) {
416
- let als;
417
- const forceNoop = typeof process !== "undefined" && !!process.env?.RUNNER_FORCE_NOOP_ALS;
418
- if (!forceNoop) {
419
- try {
420
- const mod = __require("async_hooks");
421
- als = mod?.AsyncLocalStorage;
422
- } catch (_) {
423
- als = void 0;
424
- }
425
- }
426
- this.alsClass = als ? als : class NoopAsyncLocalStorage {
427
- static {
428
- __name(this, "NoopAsyncLocalStorage");
429
- }
430
- getStore() {
431
- return void 0;
432
- }
433
- run(_store, callback) {
434
- return callback();
435
- }
436
- };
437
- }
438
- return instance ??= new this.alsClass();
439
- }, "ensure");
440
- return {
441
- getStore: /* @__PURE__ */ __name(() => ensure().getStore(), "getStore"),
442
- run: /* @__PURE__ */ __name((store2, callback) => ensure().run(store2, callback), "run")
443
- };
381
+ // src/errors.ts
382
+ var duplicateRegistrationError = error("runner.errors.duplicateRegistration").format(
383
+ ({ type, id: id2 }) => `${type} "${id2.toString()}" already registered. You might have used the same 'id' in two different components or you may have registered the same element twice.`
384
+ ).build();
385
+ var dependencyNotFoundError = error("runner.errors.dependencyNotFound").format(
386
+ ({ key }) => `Dependency ${key.toString()} not found. Did you forget to register it through a resource?`
387
+ ).build();
388
+ var unknownItemTypeError = error(
389
+ "runner.errors.unknownItemType"
390
+ ).format(
391
+ ({ item }) => `Unknown item type: ${String(
392
+ item
393
+ )}. Please ensure you are not using different versions of '@bluelibs/runner'`
394
+ ).build();
395
+ var contextError = error(
396
+ "runner.errors.context"
397
+ ).format(({ details }) => details ?? "Context error").build();
398
+ var circularDependenciesError = error("runner.errors.circularDependencies").format(({ cycles }) => {
399
+ const cycleDetails = cycles.map((cycle) => ` \u2022 ${cycle}`).join("\n");
400
+ const hasMiddleware = cycles.some((cycle) => cycle.includes("middleware"));
401
+ let guidance = "\n\nTo resolve circular dependencies:";
402
+ guidance += "\n \u2022 Consider refactoring to reduce coupling between components";
403
+ guidance += "\n \u2022 Extract shared dependencies into separate resources";
404
+ if (hasMiddleware) {
405
+ guidance += "\n \u2022 For middleware: you can filter out tasks/resources using everywhere(fn)";
406
+ guidance += "\n \u2022 Consider using events for communication instead of direct dependencies";
444
407
  }
445
- };
408
+ return `Circular dependencies detected:
409
+ ${cycleDetails}${guidance}`;
410
+ }).build();
411
+ var eventNotFoundError = error(
412
+ "runner.errors.eventNotFound"
413
+ ).format(
414
+ ({ id: id2 }) => `Event "${id2.toString()}" not found. Did you forget to register it?`
415
+ ).build();
416
+ var resourceNotFoundError = error(
417
+ "runner.errors.resourceNotFound"
418
+ ).format(
419
+ ({ id: id2 }) => `Resource "${id2.toString()}" not found. Did you forget to register it or are you using the correct id?`
420
+ ).build();
421
+ var middlewareNotRegisteredError = error("runner.errors.middlewareNotRegistered").format(
422
+ ({ type, source, middlewareId }) => `Middleware inside ${type} "${source}" depends on "${middlewareId}" but it's not registered. Did you forget to register it?`
423
+ ).build();
424
+ var tagNotFoundError = error(
425
+ "runner.errors.tagNotFound"
426
+ ).format(
427
+ ({ id: id2 }) => `Tag "${id2}" not registered. Did you forget to register it inside a resource?`
428
+ ).build();
429
+ var lockedError = error(
430
+ "runner.errors.locked"
431
+ ).format(
432
+ ({ what }) => `Cannot modify the ${what.toString()} when it is locked.`
433
+ ).build();
434
+ var storeAlreadyInitializedError = error(
435
+ "runner.errors.storeAlreadyInitialized"
436
+ ).format(() => "Store already initialized. Cannot reinitialize.").build();
437
+ var validationError = error("runner.errors.validation").format(({ subject, id: id2, originalError }) => {
438
+ const errorMessage = originalError instanceof Error ? originalError.message : String(originalError);
439
+ return `${subject} validation failed for ${id2.toString()}: ${errorMessage}`;
440
+ }).build();
441
+ var eventCycleError = error("runner.errors.eventCycle").format(({ path }) => {
442
+ const chain = path.map((p) => `${p.id}\u2190${p.source}`).join(" -> ");
443
+ return `Event emission cycle detected:
444
+ ${chain}
445
+
446
+ Break the cycle by changing hook logic (avoid mutual emits) or gate with conditions/tags.`;
447
+ }).build();
448
+ var eventEmissionCycleError = error("runner.errors.eventEmissionCycle").format(({ cycles }) => {
449
+ const list = cycles.map((c) => ` \u2022 ${c}`).join("\n");
450
+ return `Event emission cycles detected between hooks and events:
451
+ ${list}
452
+
453
+ This was detected at compile time (dry-run). Break the cycle by avoiding mutual emits between hooks or scoping hooks using tags.`;
454
+ }).build();
455
+ var platformUnsupportedFunctionError = error("runner.errors.platformUnsupportedFunction").format(
456
+ ({ functionName }) => `Platform function not supported in this environment: ${functionName}. Detected platform: ${detectEnvironment()}.`
457
+ ).build();
458
+ var cancellationError = error(
459
+ "runner.errors.cancellation"
460
+ ).format(({ reason }) => reason || "Operation cancelled").build();
461
+ var tunnelOwnershipConflictError = error("runner.errors.tunnelOwnershipConflict").format(
462
+ ({ taskId, currentOwnerId, attemptedOwnerId }) => `Task "${taskId}" is already tunneled by resource "${currentOwnerId}". Resource "${attemptedOwnerId}" cannot tunnel it again. Ensure each task is owned by a single tunnel client.`
463
+ ).build();
464
+ function isCancellationError(err) {
465
+ return cancellationError.is(err);
466
+ }
467
+ __name(isCancellationError, "isCancellationError");
446
468
 
447
469
  // src/platform/adapters/browser.ts
448
470
  var BrowserPlatformAdapter = class {
@@ -751,6 +773,12 @@ function setPlatform(adapter) {
751
773
  adapter.id;
752
774
  }
753
775
  __name(setPlatform, "setPlatform");
776
+ function isNode() {
777
+ {
778
+ return false;
779
+ }
780
+ }
781
+ __name(isNode, "isNode");
754
782
  var PlatformAdapter = class {
755
783
  constructor(env) {
756
784
  this.setTimeout = globalThis.setTimeout;
@@ -804,93 +832,79 @@ var PlatformAdapter = class {
804
832
  }
805
833
  };
806
834
 
807
- // src/errors.ts
808
- var duplicateRegistrationError = error("runner.errors.duplicateRegistration").format(
809
- ({ type, id: id2 }) => `${type} "${id2.toString()}" already registered. You might have used the same 'id' in two different components or you may have registered the same element twice.`
810
- ).build();
811
- var dependencyNotFoundError = error("runner.errors.dependencyNotFound").format(
812
- ({ key }) => `Dependency ${key.toString()} not found. Did you forget to register it through a resource?`
813
- ).build();
814
- var unknownItemTypeError = error(
815
- "runner.errors.unknownItemType"
816
- ).format(
817
- ({ item }) => `Unknown item type: ${String(
818
- item
819
- )}. Please ensure you are not using different versions of '@bluelibs/runner'`
820
- ).build();
821
- var contextError = error(
822
- "runner.errors.context"
823
- ).format(({ details }) => details ?? "Context error").build();
824
- var circularDependenciesError = error("runner.errors.circularDependencies").format(({ cycles }) => {
825
- const cycleDetails = cycles.map((cycle) => ` \u2022 ${cycle}`).join("\n");
826
- const hasMiddleware = cycles.some((cycle) => cycle.includes("middleware"));
827
- let guidance = "\n\nTo resolve circular dependencies:";
828
- guidance += "\n \u2022 Consider refactoring to reduce coupling between components";
829
- guidance += "\n \u2022 Extract shared dependencies into separate resources";
830
- if (hasMiddleware) {
831
- guidance += "\n \u2022 For middleware: you can filter out tasks/resources using everywhere(fn)";
832
- guidance += "\n \u2022 Consider using events for communication instead of direct dependencies";
835
+ // src/tools/getCallerFile.ts
836
+ function getCallerFile() {
837
+ const originalPrepare = Error.prepareStackTrace;
838
+ try {
839
+ if (isNode()) {
840
+ const err = new Error();
841
+ Error.prepareStackTrace = (_err, stack2) => stack2;
842
+ const stack = err.stack;
843
+ stack.shift();
844
+ stack.shift();
845
+ const candidate = stack.shift();
846
+ const file = candidate?.getFileName?.();
847
+ return file;
848
+ }
849
+ return "unknown";
850
+ } finally {
851
+ Error.prepareStackTrace = originalPrepare;
833
852
  }
834
- return `Circular dependencies detected:
835
- ${cycleDetails}${guidance}`;
836
- }).build();
837
- var eventNotFoundError = error(
838
- "runner.errors.eventNotFound"
839
- ).format(
840
- ({ id: id2 }) => `Event "${id2.toString()}" not found. Did you forget to register it?`
841
- ).build();
842
- var resourceNotFoundError = error(
843
- "runner.errors.resourceNotFound"
844
- ).format(
845
- ({ id: id2 }) => `Resource "${id2.toString()}" not found. Did you forget to register it or are you using the correct id?`
846
- ).build();
847
- var middlewareNotRegisteredError = error("runner.errors.middlewareNotRegistered").format(
848
- ({ type, source, middlewareId }) => `Middleware inside ${type} "${source}" depends on "${middlewareId}" but it's not registered. Did you forget to register it?`
849
- ).build();
850
- var tagNotFoundError = error(
851
- "runner.errors.tagNotFound"
852
- ).format(
853
- ({ id: id2 }) => `Tag "${id2}" not registered. Did you forget to register it inside a resource?`
854
- ).build();
855
- var lockedError = error(
856
- "runner.errors.locked"
857
- ).format(
858
- ({ what }) => `Cannot modify the ${what.toString()} when it is locked.`
859
- ).build();
860
- var storeAlreadyInitializedError = error(
861
- "runner.errors.storeAlreadyInitialized"
862
- ).format(() => "Store already initialized. Cannot reinitialize.").build();
863
- var validationError = error("runner.errors.validation").format(({ subject, id: id2, originalError }) => {
864
- const errorMessage = originalError instanceof Error ? originalError.message : String(originalError);
865
- return `${subject} validation failed for ${id2.toString()}: ${errorMessage}`;
866
- }).build();
867
- var eventCycleError = error("runner.errors.eventCycle").format(({ path }) => {
868
- const chain = path.map((p) => `${p.id}\u2190${p.source}`).join(" -> ");
869
- return `Event emission cycle detected:
870
- ${chain}
853
+ }
854
+ __name(getCallerFile, "getCallerFile");
871
855
 
872
- Break the cycle by changing hook logic (avoid mutual emits) or gate with conditions/tags.`;
873
- }).build();
874
- var eventEmissionCycleError = error("runner.errors.eventEmissionCycle").format(({ cycles }) => {
875
- const list = cycles.map((c) => ` \u2022 ${c}`).join("\n");
876
- return `Event emission cycles detected between hooks and events:
877
- ${list}
856
+ // src/definers/defineTask.ts
857
+ function defineTask(taskConfig) {
858
+ const filePath = getCallerFile();
859
+ const id2 = taskConfig.id;
860
+ return {
861
+ [symbolTask]: true,
862
+ [symbolFilePath]: filePath,
863
+ id: id2,
864
+ dependencies: taskConfig.dependencies || {},
865
+ middleware: taskConfig.middleware || [],
866
+ run: taskConfig.run,
867
+ inputSchema: taskConfig.inputSchema,
868
+ resultSchema: taskConfig.resultSchema,
869
+ meta: taskConfig.meta || {},
870
+ tags: taskConfig.tags || [],
871
+ // autorun,
872
+ optional() {
873
+ return {
874
+ inner: this,
875
+ [symbolOptionalDependency]: true
876
+ };
877
+ }
878
+ };
879
+ }
880
+ __name(defineTask, "defineTask");
881
+ defineTask.phantom = (taskConfig) => {
882
+ const taskDef = defineTask({
883
+ ...taskConfig,
884
+ run: /* @__PURE__ */ __name(async (input) => {
885
+ return void 0;
886
+ }, "run")
887
+ });
888
+ taskDef[symbolPhantomTask] = true;
889
+ return taskDef;
890
+ };
878
891
 
879
- This was detected at compile time (dry-run). Break the cycle by avoiding mutual emits between hooks or scoping hooks using tags.`;
880
- }).build();
881
- var platformUnsupportedFunctionError = error("runner.errors.platformUnsupportedFunction").format(
882
- ({ functionName }) => `Platform function not supported in this environment: ${functionName}. Detected platform: ${detectEnvironment()}.`
883
- ).build();
884
- var cancellationError = error(
885
- "runner.errors.cancellation"
886
- ).format(({ reason }) => reason || "Operation cancelled").build();
887
- var tunnelOwnershipConflictError = error("runner.errors.tunnelOwnershipConflict").format(
888
- ({ taskId, currentOwnerId, attemptedOwnerId }) => `Task "${taskId}" is already tunneled by resource "${currentOwnerId}". Resource "${attemptedOwnerId}" cannot tunnel it again. Ensure each task is owned by a single tunnel client.`
889
- ).build();
890
- function isCancellationError(err) {
891
- return cancellationError.is(err);
892
+ // src/definers/defineHook.ts
893
+ function defineHook(hookDef) {
894
+ const filePath = getCallerFile();
895
+ return {
896
+ [symbolHook]: true,
897
+ [symbolFilePath]: filePath,
898
+ id: hookDef.id,
899
+ dependencies: hookDef.dependencies || {},
900
+ on: hookDef.on,
901
+ order: hookDef.order,
902
+ run: hookDef.run,
903
+ meta: hookDef.meta || {},
904
+ tags: hookDef.tags || []
905
+ };
892
906
  }
893
- __name(isCancellationError, "isCancellationError");
907
+ __name(defineHook, "defineHook");
894
908
 
895
909
  // src/definers/defineResource.ts
896
910
  function defineResource(constConfig) {
@@ -951,6 +965,7 @@ function defineEvent(config) {
951
965
  [symbolEvent]: true,
952
966
  // This is a workaround
953
967
  tags: eventConfig.tags || [],
968
+ parallel: eventConfig.parallel,
954
969
  optional() {
955
970
  return {
956
971
  inner: this,
@@ -3481,30 +3496,279 @@ var DependencyProcessor = class {
3481
3496
  }
3482
3497
  };
3483
3498
 
3484
- // src/models/EventManager.ts
3499
+ // src/models/event/types.ts
3485
3500
  var HandlerOptionsDefaults = { order: 0 };
3486
- var EventManager = class {
3487
- constructor(options) {
3488
- // Core storage for event listeners
3501
+
3502
+ // src/models/event/ListenerRegistry.ts
3503
+ var ListenerRegistry = class {
3504
+ constructor(isExcludedFromGlobal) {
3489
3505
  this.listeners = /* @__PURE__ */ new Map();
3490
3506
  this.globalListeners = [];
3491
- // Caching system for merged listeners to improve performance
3492
3507
  this.cachedMergedListeners = /* @__PURE__ */ new Map();
3493
- this.globalListenersCacheValid = true;
3494
- // Interceptors storage
3508
+ this._globalListenersCacheValid = true;
3509
+ this.isExcludedFromGlobal = isExcludedFromGlobal ?? ((event2) => globalTags.excludeFromGlobalHooks.exists(event2));
3510
+ }
3511
+ static {
3512
+ __name(this, "ListenerRegistry");
3513
+ }
3514
+ get globalListenersCacheValid() {
3515
+ return this._globalListenersCacheValid;
3516
+ }
3517
+ addListener(eventId, newListener) {
3518
+ const listeners = this.listeners.get(eventId);
3519
+ if (listeners) {
3520
+ this.insertListener(listeners, newListener);
3521
+ } else {
3522
+ this.listeners.set(eventId, [newListener]);
3523
+ }
3524
+ this.invalidateCache(eventId);
3525
+ }
3526
+ addGlobalListener(newListener) {
3527
+ this.insertListener(this.globalListeners, newListener);
3528
+ this.invalidateCache();
3529
+ }
3530
+ getListenersForEmit(eventDefinition) {
3531
+ const excludeGlobal = this.isExcludedFromGlobal(eventDefinition);
3532
+ if (excludeGlobal) {
3533
+ return this.listeners.get(eventDefinition.id) || [];
3534
+ }
3535
+ return this.getCachedMergedListeners(eventDefinition.id);
3536
+ }
3537
+ hasListeners(eventDefinition) {
3538
+ const eventListeners = this.listeners.get(eventDefinition.id) || [];
3539
+ if (eventListeners.length > 0) {
3540
+ return true;
3541
+ }
3542
+ if (this.globalListeners.length === 0) {
3543
+ return false;
3544
+ }
3545
+ return !this.isExcludedFromGlobal(eventDefinition);
3546
+ }
3547
+ /**
3548
+ * Cached merge between event-specific and global listeners.
3549
+ * Exposed for backward compatibility with existing tests.
3550
+ */
3551
+ getCachedMergedListeners(eventId) {
3552
+ if (!this._globalListenersCacheValid) {
3553
+ this.cachedMergedListeners.clear();
3554
+ this._globalListenersCacheValid = true;
3555
+ }
3556
+ let cached = this.cachedMergedListeners.get(eventId);
3557
+ if (!cached) {
3558
+ const eventListeners = this.listeners.get(eventId) || [];
3559
+ if (eventListeners.length === 0 && this.globalListeners.length === 0) {
3560
+ cached = [];
3561
+ } else if (eventListeners.length === 0) {
3562
+ cached = this.globalListeners;
3563
+ } else if (this.globalListeners.length === 0) {
3564
+ cached = eventListeners;
3565
+ } else {
3566
+ cached = this.mergeSortedListeners(eventListeners, this.globalListeners);
3567
+ }
3568
+ this.cachedMergedListeners.set(eventId, cached);
3569
+ }
3570
+ return cached;
3571
+ }
3572
+ invalidateCache(eventId) {
3573
+ if (eventId) {
3574
+ this.cachedMergedListeners.delete(eventId);
3575
+ } else {
3576
+ this._globalListenersCacheValid = false;
3577
+ }
3578
+ }
3579
+ mergeSortedListeners(a, b) {
3580
+ const result = [];
3581
+ let i = 0;
3582
+ let j = 0;
3583
+ while (i < a.length && j < b.length) {
3584
+ if (a[i].order <= b[j].order) {
3585
+ result.push(a[i++]);
3586
+ } else {
3587
+ result.push(b[j++]);
3588
+ }
3589
+ }
3590
+ while (i < a.length) result.push(a[i++]);
3591
+ while (j < b.length) result.push(b[j++]);
3592
+ return result;
3593
+ }
3594
+ insertListener(listeners, newListener) {
3595
+ let low = 0;
3596
+ let high = listeners.length;
3597
+ while (low < high) {
3598
+ const mid = low + high >>> 1;
3599
+ if (listeners[mid].order < newListener.order) {
3600
+ low = mid + 1;
3601
+ } else {
3602
+ high = mid;
3603
+ }
3604
+ }
3605
+ listeners.splice(low, 0, newListener);
3606
+ }
3607
+ };
3608
+ function createListener(newListener) {
3609
+ return {
3610
+ handler: newListener.handler,
3611
+ order: newListener.order ?? HandlerOptionsDefaults.order,
3612
+ filter: newListener.filter,
3613
+ id: newListener.id,
3614
+ isGlobal: newListener.isGlobal ?? false
3615
+ };
3616
+ }
3617
+ __name(createListener, "createListener");
3618
+
3619
+ // src/models/event/InterceptorPipeline.ts
3620
+ function composeInterceptors(interceptors, base) {
3621
+ return interceptors.slice().reverse().reduce(
3622
+ (next, interceptor) => (...args) => interceptor(next, ...args),
3623
+ base
3624
+ );
3625
+ }
3626
+ __name(composeInterceptors, "composeInterceptors");
3627
+
3628
+ // src/models/event/EmissionExecutor.ts
3629
+ async function executeSequentially({
3630
+ listeners,
3631
+ event: event2,
3632
+ isPropagationStopped
3633
+ }) {
3634
+ for (const listener of listeners) {
3635
+ if (isPropagationStopped()) {
3636
+ break;
3637
+ }
3638
+ if (shouldExecuteListener(listener, event2)) {
3639
+ await listener.handler(event2);
3640
+ }
3641
+ }
3642
+ }
3643
+ __name(executeSequentially, "executeSequentially");
3644
+ async function executeInParallel({
3645
+ listeners,
3646
+ event: event2
3647
+ }) {
3648
+ if (listeners.length === 0 || event2.isPropagationStopped()) {
3649
+ return;
3650
+ }
3651
+ let currentOrder = listeners[0].order;
3652
+ let currentBatch = [];
3653
+ const executeBatch = /* @__PURE__ */ __name(async (batch) => {
3654
+ const results = await Promise.allSettled(
3655
+ batch.map(async (listener) => {
3656
+ if (shouldExecuteListener(listener, event2)) {
3657
+ await listener.handler(event2);
3658
+ }
3659
+ })
3660
+ );
3661
+ const errors = results.map((result, index) => ({ result, listener: batch[index] })).filter(
3662
+ (r2) => r2.result.status === "rejected"
3663
+ ).map(({ result, listener }) => {
3664
+ const reason = result.reason;
3665
+ const errObj = reason && typeof reason === "object" ? reason : new Error(String(reason));
3666
+ if (errObj.listenerId === void 0) {
3667
+ errObj.listenerId = listener.id;
3668
+ }
3669
+ if (errObj.listenerOrder === void 0) {
3670
+ errObj.listenerOrder = listener.order;
3671
+ }
3672
+ return errObj;
3673
+ });
3674
+ if (errors.length > 0) {
3675
+ if (errors.length === 1) {
3676
+ throw errors[0];
3677
+ }
3678
+ const aggregateError = new Error(
3679
+ `${errors.length} listeners failed in parallel batch`
3680
+ );
3681
+ aggregateError.errors = errors;
3682
+ aggregateError.name = "AggregateError";
3683
+ throw aggregateError;
3684
+ }
3685
+ }, "executeBatch");
3686
+ for (const listener of listeners) {
3687
+ if (listener.order !== currentOrder) {
3688
+ await executeBatch(currentBatch);
3689
+ currentBatch = [];
3690
+ currentOrder = listener.order;
3691
+ if (event2.isPropagationStopped()) {
3692
+ break;
3693
+ }
3694
+ }
3695
+ currentBatch.push(listener);
3696
+ }
3697
+ if (currentBatch.length > 0 && !event2.isPropagationStopped()) {
3698
+ await executeBatch(currentBatch);
3699
+ }
3700
+ }
3701
+ __name(executeInParallel, "executeInParallel");
3702
+ function shouldExecuteListener(listener, event2) {
3703
+ if (listener.id && listener.id === event2.source) {
3704
+ return false;
3705
+ }
3706
+ return !listener.filter || listener.filter(event2);
3707
+ }
3708
+ __name(shouldExecuteListener, "shouldExecuteListener");
3709
+
3710
+ // src/models/event/CycleContext.ts
3711
+ var CycleContext = class {
3712
+ static {
3713
+ __name(this, "CycleContext");
3714
+ }
3715
+ constructor(runtimeCycleDetection) {
3716
+ const platform3 = getPlatform();
3717
+ if (platform3.hasAsyncLocalStorage() && runtimeCycleDetection) {
3718
+ this.emissionStack = platform3.createAsyncLocalStorage();
3719
+ this.currentHookIdContext = platform3.createAsyncLocalStorage();
3720
+ this.isEnabled = true;
3721
+ } else {
3722
+ this.emissionStack = null;
3723
+ this.currentHookIdContext = null;
3724
+ this.isEnabled = false;
3725
+ }
3726
+ }
3727
+ runEmission(frame, source, processEmission) {
3728
+ if (!this.isEnabled || !this.emissionStack || !this.currentHookIdContext) {
3729
+ return processEmission();
3730
+ }
3731
+ const currentStack = this.emissionStack.getStore();
3732
+ if (currentStack) {
3733
+ const cycleStart = currentStack.findIndex(
3734
+ (f) => f.id === frame.id
3735
+ );
3736
+ if (cycleStart !== -1) {
3737
+ const top = currentStack[currentStack.length - 1];
3738
+ const currentHookId = this.currentHookIdContext.getStore();
3739
+ const safeReEmitBySameHook = top.id === frame.id && currentHookId && currentHookId === source;
3740
+ if (!safeReEmitBySameHook) {
3741
+ eventCycleError.throw({
3742
+ path: [...currentStack.slice(cycleStart), frame]
3743
+ });
3744
+ }
3745
+ }
3746
+ }
3747
+ const nextStack = currentStack ? [...currentStack, frame] : [frame];
3748
+ return this.emissionStack.run(nextStack, processEmission);
3749
+ }
3750
+ runHook(hookId, execute) {
3751
+ if (!this.isEnabled || !this.currentHookIdContext) {
3752
+ return execute();
3753
+ }
3754
+ return this.currentHookIdContext.run(hookId, execute);
3755
+ }
3756
+ };
3757
+
3758
+ // src/models/EventManager.ts
3759
+ var EventManager = class {
3760
+ constructor(options) {
3761
+ // Interceptors storage (tests access these directly)
3495
3762
  this.emissionInterceptors = [];
3496
3763
  this.hookInterceptors = [];
3497
3764
  // Locking mechanism to prevent modifications after initialization
3498
3765
  this.#isLocked = false;
3499
3766
  this.runtimeCycleDetection = options?.runtimeCycleDetection ?? true;
3500
- if (getPlatform().hasAsyncLocalStorage() && this.runtimeCycleDetection) {
3501
- this.emissionStack = getPlatform().createAsyncLocalStorage();
3502
- this.currentHookIdContext = getPlatform().createAsyncLocalStorage();
3503
- } else {
3504
- this.runtimeCycleDetection = false;
3505
- this.emissionStack = null;
3506
- this.currentHookIdContext = null;
3507
- }
3767
+ this.registry = new ListenerRegistry();
3768
+ this.cycleContext = new CycleContext(this.runtimeCycleDetection);
3769
+ this.listeners = this.registry.listeners;
3770
+ this.globalListeners = this.registry.globalListeners;
3771
+ this.cachedMergedListeners = this.registry.cachedMergedListeners;
3508
3772
  }
3509
3773
  static {
3510
3774
  __name(this, "EventManager");
@@ -3545,8 +3809,7 @@ var EventManager = class {
3545
3809
  }
3546
3810
  const frame = { id: eventDefinition.id, source };
3547
3811
  const processEmission = /* @__PURE__ */ __name(async () => {
3548
- const excludeFromGlobal = globalTags.excludeFromGlobalHooks.exists(eventDefinition);
3549
- const allListeners = excludeFromGlobal ? this.listeners.get(eventDefinition.id) || [] : this.getCachedMergedListeners(eventDefinition.id);
3812
+ const allListeners = this.registry.getListenersForEmit(eventDefinition);
3550
3813
  let propagationStopped = false;
3551
3814
  const event2 = {
3552
3815
  id: eventDefinition.id,
@@ -3564,49 +3827,23 @@ var EventManager = class {
3564
3827
  if (allListeners.length === 0) {
3565
3828
  return;
3566
3829
  }
3567
- this.isExcludedFromGlobal(eventToEmit);
3568
- for (const listener of allListeners) {
3569
- if (propagationStopped) {
3570
- break;
3571
- }
3572
- if (listener.id && listener.id === eventToEmit.source) {
3573
- continue;
3574
- }
3575
- if (!listener.filter || listener.filter(eventToEmit)) {
3576
- await listener.handler(eventToEmit);
3577
- }
3830
+ if (eventDefinition.parallel) {
3831
+ await executeInParallel({ listeners: allListeners, event: eventToEmit });
3832
+ } else {
3833
+ await executeSequentially({
3834
+ listeners: allListeners,
3835
+ event: eventToEmit,
3836
+ isPropagationStopped: /* @__PURE__ */ __name(() => propagationStopped, "isPropagationStopped")
3837
+ });
3578
3838
  }
3579
3839
  }, "baseEmit");
3580
- let emitWithInterceptors = baseEmit;
3581
- const reversedInterceptors = [...this.emissionInterceptors].reverse();
3582
- for (const interceptor of reversedInterceptors) {
3583
- const nextFunction = emitWithInterceptors;
3584
- emitWithInterceptors = /* @__PURE__ */ __name(async (eventToEmit) => interceptor(nextFunction, eventToEmit), "emitWithInterceptors");
3585
- }
3840
+ const emitWithInterceptors = composeInterceptors(
3841
+ this.emissionInterceptors,
3842
+ baseEmit
3843
+ );
3586
3844
  await emitWithInterceptors(event2);
3587
3845
  }, "processEmission");
3588
- if (this.runtimeCycleDetection && this.emissionStack && this.currentHookIdContext) {
3589
- const currentStack = this.emissionStack.getStore();
3590
- if (currentStack) {
3591
- const cycleStart = currentStack.findIndex(
3592
- (f) => f.id === frame.id
3593
- );
3594
- if (cycleStart !== -1) {
3595
- const top = currentStack[currentStack.length - 1];
3596
- const currentHookId = this.currentHookIdContext.getStore();
3597
- const safeReEmitBySameHook = top.id === frame.id && currentHookId && currentHookId === source;
3598
- if (!safeReEmitBySameHook) {
3599
- eventCycleError.throw({
3600
- path: [...currentStack.slice(cycleStart), frame]
3601
- });
3602
- }
3603
- }
3604
- }
3605
- const nextStack = currentStack ? [...currentStack, frame] : [frame];
3606
- await this.emissionStack.run(nextStack, processEmission);
3607
- } else {
3608
- await processEmission();
3609
- }
3846
+ await this.cycleContext.runEmission(frame, source, processEmission);
3610
3847
  }
3611
3848
  /**
3612
3849
  * Registers an event listener for specific event(s).
@@ -3618,24 +3855,18 @@ var EventManager = class {
3618
3855
  */
3619
3856
  addListener(event2, handler, options = HandlerOptionsDefaults) {
3620
3857
  this.checkLock();
3621
- const newListener = {
3858
+ const newListener = createListener({
3622
3859
  handler,
3623
- order: options.order || 0,
3860
+ order: options.order,
3624
3861
  filter: options.filter,
3625
3862
  id: options.id,
3626
3863
  isGlobal: false
3627
- };
3864
+ });
3628
3865
  if (Array.isArray(event2)) {
3629
3866
  event2.forEach((id2) => this.addListener(id2, handler, options));
3630
3867
  } else {
3631
3868
  const eventId = event2.id;
3632
- const listeners = this.listeners.get(eventId);
3633
- if (listeners) {
3634
- this.insertListener(listeners, newListener);
3635
- } else {
3636
- this.listeners.set(eventId, [newListener]);
3637
- }
3638
- this.invalidateCache(eventId);
3869
+ this.registry.addListener(eventId, newListener);
3639
3870
  }
3640
3871
  }
3641
3872
  /**
@@ -3647,15 +3878,14 @@ var EventManager = class {
3647
3878
  */
3648
3879
  addGlobalListener(handler, options = HandlerOptionsDefaults) {
3649
3880
  this.checkLock();
3650
- const newListener = {
3881
+ const newListener = createListener({
3651
3882
  handler,
3652
- order: options.order || 0,
3883
+ order: options.order,
3653
3884
  filter: options.filter,
3654
3885
  id: options.id,
3655
3886
  isGlobal: true
3656
- };
3657
- this.insertListener(this.globalListeners, newListener);
3658
- this.invalidateCache();
3887
+ });
3888
+ this.registry.addGlobalListener(newListener);
3659
3889
  }
3660
3890
  /**
3661
3891
  * Checks if there are any listeners registered for the given event
@@ -3664,15 +3894,7 @@ var EventManager = class {
3664
3894
  * @returns true if listeners exist, false otherwise
3665
3895
  */
3666
3896
  hasListeners(eventDefinition) {
3667
- const eventListeners = this.listeners.get(eventDefinition.id) || [];
3668
- if (eventListeners.length > 0) {
3669
- return true;
3670
- }
3671
- if (this.globalListeners.length === 0) {
3672
- return false;
3673
- }
3674
- const isExcludedFromGlobal = globalTags.excludeFromGlobalHooks.exists(eventDefinition);
3675
- return !isExcludedFromGlobal;
3897
+ return this.registry.hasListeners(eventDefinition);
3676
3898
  }
3677
3899
  /**
3678
3900
  * Adds an interceptor for all event emissions
@@ -3717,20 +3939,14 @@ var EventManager = class {
3717
3939
  throw err;
3718
3940
  }
3719
3941
  }, "baseExecute");
3720
- let executeWithInterceptors = baseExecute;
3721
- const reversedInterceptors = [...this.hookInterceptors].reverse();
3722
- for (const interceptor of reversedInterceptors) {
3723
- const nextFunction = executeWithInterceptors;
3724
- executeWithInterceptors = /* @__PURE__ */ __name(async (hookToExecute, eventForHook) => interceptor(nextFunction, hookToExecute, eventForHook), "executeWithInterceptors");
3725
- }
3726
- if (this.runtimeCycleDetection) {
3727
- return await this.currentHookIdContext?.run(
3728
- hook2.id,
3729
- async () => await executeWithInterceptors(hook2, event2)
3730
- );
3731
- } else {
3732
- return await executeWithInterceptors(hook2, event2);
3733
- }
3942
+ const executeWithInterceptors = composeInterceptors(
3943
+ this.hookInterceptors,
3944
+ baseExecute
3945
+ );
3946
+ return this.cycleContext.isEnabled ? await this.cycleContext.runHook(
3947
+ hook2.id,
3948
+ () => executeWithInterceptors(hook2, event2)
3949
+ ) : await executeWithInterceptors(hook2, event2);
3734
3950
  }
3735
3951
  // ==================== PRIVATE METHODS ====================
3736
3952
  /**
@@ -3741,102 +3957,12 @@ var EventManager = class {
3741
3957
  lockedError.throw({ what: "EventManager" });
3742
3958
  }
3743
3959
  }
3744
- /**
3745
- * Merges two sorted arrays of listeners while maintaining order.
3746
- * Used to combine event-specific listeners with global listeners.
3747
- *
3748
- * @param a - First array of listeners
3749
- * @param b - Second array of listeners
3750
- * @returns Merged and sorted array of listeners
3751
- */
3752
- mergeSortedListeners(a, b) {
3753
- const result = [];
3754
- let i = 0, j = 0;
3755
- while (i < a.length && j < b.length) {
3756
- if (a[i].order <= b[j].order) {
3757
- result.push(a[i++]);
3758
- } else {
3759
- result.push(b[j++]);
3760
- }
3761
- }
3762
- while (i < a.length) result.push(a[i++]);
3763
- while (j < b.length) result.push(b[j++]);
3764
- return result;
3765
- }
3766
- /**
3767
- * Inserts a new listener into a sorted array using binary search.
3768
- * Maintains order based on listener priority.
3769
- *
3770
- * @param listeners - Array to insert into
3771
- * @param newListener - Listener to insert
3772
- */
3773
- insertListener(listeners, newListener) {
3774
- let low = 0;
3775
- let high = listeners.length;
3776
- while (low < high) {
3777
- const mid = low + high >>> 1;
3778
- if (listeners[mid].order < newListener.order) {
3779
- low = mid + 1;
3780
- } else {
3781
- high = mid;
3782
- }
3783
- }
3784
- listeners.splice(low, 0, newListener);
3785
- }
3786
- /**
3787
- * Returns true if the given emission carries the tag that marks
3788
- * it as excluded from global ("*") listeners.
3789
- *
3790
- * @param event - The event emission to check
3791
- * @returns true if event should exclude global listeners
3792
- */
3793
- isExcludedFromGlobal(event2) {
3794
- return globalTags.excludeFromGlobalHooks.exists(event2);
3795
- }
3796
3960
  /**
3797
3961
  * Retrieves cached merged listeners for an event, or creates them if not cached.
3798
- * Combines event-specific listeners with global listeners and sorts them by priority.
3799
- *
3800
- * @param eventId - The event ID to get listeners for
3801
- * @returns Array of merged listeners sorted by priority
3962
+ * Kept for backward compatibility (tests spy on this).
3802
3963
  */
3803
3964
  getCachedMergedListeners(eventId) {
3804
- if (!this.globalListenersCacheValid) {
3805
- this.cachedMergedListeners.clear();
3806
- this.globalListenersCacheValid = true;
3807
- }
3808
- let cached = this.cachedMergedListeners.get(eventId);
3809
- if (!cached) {
3810
- const eventListeners = this.listeners.get(eventId) || [];
3811
- if (eventListeners.length === 0 && this.globalListeners.length === 0) {
3812
- cached = [];
3813
- } else if (eventListeners.length === 0) {
3814
- cached = this.globalListeners;
3815
- } else if (this.globalListeners.length === 0) {
3816
- cached = eventListeners;
3817
- } else {
3818
- cached = this.mergeSortedListeners(
3819
- eventListeners,
3820
- this.globalListeners
3821
- );
3822
- }
3823
- this.cachedMergedListeners.set(eventId, cached);
3824
- }
3825
- return cached;
3826
- }
3827
- /**
3828
- * Invalidates the cached merged listeners.
3829
- * If eventId is provided, only invalidates cache for that specific event.
3830
- * Otherwise, invalidates the global cache.
3831
- *
3832
- * @param eventId - Optional specific event ID to invalidate
3833
- */
3834
- invalidateCache(eventId) {
3835
- if (eventId) {
3836
- this.cachedMergedListeners.delete(eventId);
3837
- } else {
3838
- this.globalListenersCacheValid = false;
3839
- }
3965
+ return this.registry.getCachedMergedListeners(eventId);
3840
3966
  }
3841
3967
  };
3842
3968
 
@@ -5526,15 +5652,19 @@ function makeResourceBuilder(state) {
5526
5652
  meta: state.meta,
5527
5653
  overrides: state.overrides
5528
5654
  };
5529
- return defineResource(definition);
5655
+ const resource2 = defineResource(definition);
5656
+ resource2[symbolFilePath] = state.filePath;
5657
+ return resource2;
5530
5658
  }
5531
5659
  };
5532
5660
  return builder;
5533
5661
  }
5534
5662
  __name(makeResourceBuilder, "makeResourceBuilder");
5535
5663
  function resourceBuilder(id2) {
5664
+ const filePath = getCallerFile();
5536
5665
  const initial = Object.freeze({
5537
5666
  id: id2,
5667
+ filePath,
5538
5668
  dependencies: void 0,
5539
5669
  register: void 0,
5540
5670
  middleware: [],
@@ -5648,6 +5778,7 @@ function makePhantomTaskBuilder(state) {
5648
5778
  meta: state.meta,
5649
5779
  tags: state.tags
5650
5780
  });
5781
+ built[symbolFilePath] = state.filePath;
5651
5782
  return built;
5652
5783
  }
5653
5784
  };
@@ -5655,8 +5786,10 @@ function makePhantomTaskBuilder(state) {
5655
5786
  }
5656
5787
  __name(makePhantomTaskBuilder, "makePhantomTaskBuilder");
5657
5788
  function phantomTaskBuilder(id2) {
5789
+ const filePath = getCallerFile();
5658
5790
  const initial = Object.freeze({
5659
5791
  id: id2,
5792
+ filePath,
5660
5793
  dependencies: {},
5661
5794
  middleware: [],
5662
5795
  meta: {},
@@ -5723,17 +5856,21 @@ function makeTaskBuilder(state) {
5723
5856
  return makeTaskBuilder(next);
5724
5857
  },
5725
5858
  build() {
5726
- return defineTask({
5859
+ const task2 = defineTask({
5727
5860
  ...state
5728
5861
  });
5862
+ task2[symbolFilePath] = state.filePath;
5863
+ return task2;
5729
5864
  }
5730
5865
  };
5731
5866
  return builder;
5732
5867
  }
5733
5868
  __name(makeTaskBuilder, "makeTaskBuilder");
5734
5869
  function taskBuilder(id2) {
5870
+ const filePath = getCallerFile();
5735
5871
  const initial = Object.freeze({
5736
5872
  id: id2,
5873
+ filePath,
5737
5874
  dependencies: {},
5738
5875
  middleware: [],
5739
5876
  meta: {},
@@ -5771,21 +5908,30 @@ function makeEventBuilder(state) {
5771
5908
  const next = clone5(state, { meta: m });
5772
5909
  return makeEventBuilder(next);
5773
5910
  },
5911
+ parallel(enabled = true) {
5912
+ const next = clone5(state, { parallel: enabled });
5913
+ return makeEventBuilder(next);
5914
+ },
5774
5915
  build() {
5775
- return defineEvent({
5916
+ const event2 = defineEvent({
5776
5917
  ...state
5777
5918
  });
5919
+ event2[symbolFilePath] = state.filePath;
5920
+ return event2;
5778
5921
  }
5779
5922
  };
5780
5923
  return b;
5781
5924
  }
5782
5925
  __name(makeEventBuilder, "makeEventBuilder");
5783
5926
  function eventBuilder(id2) {
5927
+ const filePath = getCallerFile();
5784
5928
  const initial = Object.freeze({
5785
5929
  id: id2,
5930
+ filePath,
5786
5931
  meta: {},
5787
5932
  payloadSchema: void 0,
5788
- tags: []
5933
+ tags: [],
5934
+ parallel: void 0
5789
5935
  });
5790
5936
  return makeEventBuilder(initial);
5791
5937
  }
@@ -5861,17 +6007,21 @@ function makeHookBuilder(state) {
5861
6007
  return makeHookBuilder(next);
5862
6008
  },
5863
6009
  build() {
5864
- return defineHook({
6010
+ const hook2 = defineHook({
5865
6011
  ...state
5866
6012
  });
6013
+ hook2[symbolFilePath] = state.filePath;
6014
+ return hook2;
5867
6015
  }
5868
6016
  };
5869
6017
  return b;
5870
6018
  }
5871
6019
  __name(makeHookBuilder, "makeHookBuilder");
5872
6020
  function hookBuilder(id2) {
6021
+ const filePath = getCallerFile();
5873
6022
  const initial = Object.freeze({
5874
6023
  id: id2,
6024
+ filePath,
5875
6025
  dependencies: {},
5876
6026
  on: "*",
5877
6027
  order: void 0,
@@ -5954,17 +6104,21 @@ function makeTaskMiddlewareBuilder(state) {
5954
6104
  return makeTaskMiddlewareBuilder(next);
5955
6105
  },
5956
6106
  build() {
5957
- return defineTaskMiddleware({
6107
+ const middleware = defineTaskMiddleware({
5958
6108
  ...state
5959
6109
  });
6110
+ middleware[symbolFilePath] = state.filePath;
6111
+ return middleware;
5960
6112
  }
5961
6113
  };
5962
6114
  return b;
5963
6115
  }
5964
6116
  __name(makeTaskMiddlewareBuilder, "makeTaskMiddlewareBuilder");
5965
6117
  function taskMiddlewareBuilder(id2) {
6118
+ const filePath = getCallerFile();
5966
6119
  const initial = Object.freeze({
5967
6120
  id: id2,
6121
+ filePath,
5968
6122
  dependencies: {},
5969
6123
  configSchema: void 0,
5970
6124
  run: void 0,
@@ -6044,17 +6198,21 @@ function makeResourceMiddlewareBuilder(state) {
6044
6198
  return makeResourceMiddlewareBuilder(next);
6045
6199
  },
6046
6200
  build() {
6047
- return defineResourceMiddleware({
6201
+ const middleware = defineResourceMiddleware({
6048
6202
  ...state
6049
6203
  });
6204
+ middleware[symbolFilePath] = state.filePath;
6205
+ return middleware;
6050
6206
  }
6051
6207
  };
6052
6208
  return b;
6053
6209
  }
6054
6210
  __name(makeResourceMiddlewareBuilder, "makeResourceMiddlewareBuilder");
6055
6211
  function resourceMiddlewareBuilder(id2) {
6212
+ const filePath = getCallerFile();
6056
6213
  const initial = Object.freeze({
6057
6214
  id: id2,
6215
+ filePath,
6058
6216
  dependencies: {},
6059
6217
  configSchema: void 0,
6060
6218
  run: void 0,
@@ -6093,21 +6251,25 @@ function makeTagBuilder(state) {
6093
6251
  );
6094
6252
  },
6095
6253
  build() {
6096
- return defineTag({
6254
+ const tag2 = defineTag({
6097
6255
  id: state.id,
6098
6256
  meta: state.meta,
6099
6257
  configSchema: state.configSchema,
6100
6258
  config: state.config
6101
6259
  });
6260
+ tag2[symbolFilePath] = state.filePath;
6261
+ return tag2;
6102
6262
  }
6103
6263
  };
6104
6264
  return b;
6105
6265
  }
6106
6266
  __name(makeTagBuilder, "makeTagBuilder");
6107
6267
  function tagBuilder(id2) {
6268
+ const filePath = getCallerFile();
6108
6269
  const initial = Object.freeze(
6109
6270
  {
6110
6271
  id: id2,
6272
+ filePath,
6111
6273
  meta: {},
6112
6274
  configSchema: void 0,
6113
6275
  config: void 0
@@ -6138,12 +6300,17 @@ function makeAsyncContextBuilder(state) {
6138
6300
  const next = clone8(state, { configSchema: schema });
6139
6301
  return makeAsyncContextBuilder(next);
6140
6302
  },
6303
+ meta(m) {
6304
+ const next = clone8(state, { meta: m });
6305
+ return makeAsyncContextBuilder(next);
6306
+ },
6141
6307
  build() {
6142
6308
  const def = {
6143
6309
  id: state.id,
6144
6310
  serialize: state.serialize,
6145
6311
  parse: state.parse,
6146
- configSchema: state.configSchema
6312
+ configSchema: state.configSchema,
6313
+ meta: state.meta
6147
6314
  };
6148
6315
  return defineAsyncContext(def);
6149
6316
  }
@@ -6156,7 +6323,8 @@ function asyncContextBuilder(id2) {
6156
6323
  id: id2,
6157
6324
  serialize: void 0,
6158
6325
  parse: void 0,
6159
- configSchema: void 0
6326
+ configSchema: void 0,
6327
+ meta: {}
6160
6328
  });
6161
6329
  return makeAsyncContextBuilder(initial);
6162
6330
  }