@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
@@ -551,6 +551,13 @@ function parseMaybeJsonResponse(res, serializer2) {
551
551
  }
552
552
  return Promise.resolve(res);
553
553
  }
554
+ function rethrowTyped(registry, error2) {
555
+ if (registry && error2 && error2.id && error2.data) {
556
+ const helper = registry.get(String(error2.id));
557
+ if (helper) helper.throw(error2.data);
558
+ }
559
+ throw error2;
560
+ }
554
561
  function createHttpSmartClient(cfg) {
555
562
  const baseUrl = cfg.baseUrl.replace(/\/$/, "");
556
563
  if (!baseUrl) throw new Error("createHttpSmartClient requires baseUrl");
@@ -567,28 +574,42 @@ function createHttpSmartClient(cfg) {
567
574
  const manifestText = serializer2.stringify({
568
575
  input: manifest.input
569
576
  });
570
- const { res } = await postMultipart(
571
- cfg,
572
- url,
573
- manifestText,
574
- manifest.files
575
- );
576
- const maybe = await parseMaybeJsonResponse(
577
- res,
578
- serializer2
579
- );
580
- if (isReadable(maybe)) return maybe;
581
- return assertOkEnvelope(maybe, {
577
+ try {
578
+ const { res } = await postMultipart(
579
+ cfg,
580
+ url,
581
+ manifestText,
582
+ manifest.files
583
+ );
584
+ const maybe = await parseMaybeJsonResponse(
585
+ res,
586
+ serializer2
587
+ );
588
+ if (isReadable(maybe)) return maybe;
589
+ return assertOkEnvelope(maybe, {
590
+ fallbackMessage: "Tunnel task error"
591
+ });
592
+ } catch (error2) {
593
+ rethrowTyped(cfg.errorRegistry, error2);
594
+ }
595
+ }
596
+ try {
597
+ const r2 = await postJson(cfg, url, { input });
598
+ return assertOkEnvelope(r2, {
582
599
  fallbackMessage: "Tunnel task error"
583
600
  });
601
+ } catch (error2) {
602
+ rethrowTyped(cfg.errorRegistry, error2);
584
603
  }
585
- const r2 = await postJson(cfg, url, { input });
586
- return assertOkEnvelope(r2, { fallbackMessage: "Tunnel task error" });
587
604
  },
588
605
  async event(id2, payload) {
589
606
  const url = `${baseUrl}/event/${encodeURIComponent(id2)}`;
590
- const r2 = await postJson(cfg, url, { payload });
591
- assertOkEnvelope(r2, { fallbackMessage: "Tunnel event error" });
607
+ try {
608
+ const r2 = await postJson(cfg, url, { payload });
609
+ assertOkEnvelope(r2, { fallbackMessage: "Tunnel event error" });
610
+ } catch (error2) {
611
+ rethrowTyped(cfg.errorRegistry, error2);
612
+ }
592
613
  }
593
614
  };
594
615
  }
@@ -606,6 +627,7 @@ var init_http_smart_client_model = __esm({
606
627
  __name(postMultipart, "postMultipart");
607
628
  __name(postOctetStream, "postOctetStream");
608
629
  __name(parseMaybeJsonResponse, "parseMaybeJsonResponse");
630
+ __name(rethrowTyped, "rethrowTyped");
609
631
  __name(createHttpSmartClient, "createHttpSmartClient");
610
632
  }
611
633
  });
@@ -652,7 +674,8 @@ function createHttpMixedClient(cfg) {
652
674
  timeoutMs: cfg.timeoutMs,
653
675
  serializer: cfg.serializer,
654
676
  onRequest: cfg.onRequest,
655
- contexts: cfg.contexts
677
+ contexts: cfg.contexts,
678
+ errorRegistry: cfg.errorRegistry
656
679
  });
657
680
  return {
658
681
  async task(id2, input) {
@@ -832,78 +855,87 @@ var cacheMiddleware = defineTaskMiddleware({
832
855
  }
833
856
  });
834
857
 
835
- // src/tools/getCallerFile.ts
836
- function getCallerFile() {
837
- const originalFunc = Error.prepareStackTrace;
838
- try {
839
- const err = new Error();
840
- let callerfile;
841
- let currentfile;
842
- Error.prepareStackTrace = (err2, stack2) => stack2;
843
- const stack = err.stack;
844
- stack.shift();
845
- currentfile = stack.shift()?.getFileName?.();
846
- callerfile = stack.shift()?.getFileName?.();
847
- return callerfile;
848
- } finally {
849
- Error.prepareStackTrace = originalFunc;
850
- }
858
+ // src/platform/adapters/node-als.ts
859
+ async function loadAsyncLocalStorageClass() {
860
+ const mod = __require("async_hooks");
861
+ return mod.AsyncLocalStorage;
851
862
  }
852
- __name(getCallerFile, "getCallerFile");
863
+ __name(loadAsyncLocalStorageClass, "loadAsyncLocalStorageClass");
853
864
 
854
- // src/definers/defineTask.ts
855
- function defineTask(taskConfig) {
856
- const filePath = getCallerFile();
857
- const id2 = taskConfig.id;
858
- return {
859
- [symbolTask]: true,
860
- [symbolFilePath]: filePath,
861
- id: id2,
862
- dependencies: taskConfig.dependencies || {},
863
- middleware: taskConfig.middleware || [],
864
- run: taskConfig.run,
865
- inputSchema: taskConfig.inputSchema,
866
- resultSchema: taskConfig.resultSchema,
867
- meta: taskConfig.meta || {},
868
- tags: taskConfig.tags || [],
869
- // autorun,
870
- optional() {
871
- return {
872
- inner: this,
873
- [symbolOptionalDependency]: true
874
- };
875
- }
876
- };
877
- }
878
- __name(defineTask, "defineTask");
879
- defineTask.phantom = (taskConfig) => {
880
- const taskDef = defineTask({
881
- ...taskConfig,
882
- run: /* @__PURE__ */ __name(async (input) => {
883
- return void 0;
884
- }, "run")
885
- });
886
- taskDef[symbolPhantomTask] = true;
887
- return taskDef;
865
+ // src/platform/adapters/node.ts
866
+ var NodePlatformAdapter = class {
867
+ constructor() {
868
+ this.id = "node";
869
+ this.setTimeout = globalThis.setTimeout;
870
+ this.clearTimeout = globalThis.clearTimeout;
871
+ }
872
+ static {
873
+ __name(this, "NodePlatformAdapter");
874
+ }
875
+ async init() {
876
+ this.alsClass = await loadAsyncLocalStorageClass();
877
+ }
878
+ onUncaughtException(handler) {
879
+ process.on("uncaughtException", handler);
880
+ return () => process.off("uncaughtException", handler);
881
+ }
882
+ onUnhandledRejection(handler) {
883
+ const h = /* @__PURE__ */ __name((reason) => handler(reason), "h");
884
+ process.on("unhandledRejection", h);
885
+ return () => process.off("unhandledRejection", h);
886
+ }
887
+ onShutdownSignal(handler) {
888
+ process.on("SIGINT", handler);
889
+ process.on("SIGTERM", handler);
890
+ return () => {
891
+ process.off("SIGINT", handler);
892
+ process.off("SIGTERM", handler);
893
+ };
894
+ }
895
+ exit(code) {
896
+ process.exit(code);
897
+ }
898
+ getEnv(key) {
899
+ return process.env[key];
900
+ }
901
+ hasAsyncLocalStorage() {
902
+ return true;
903
+ }
904
+ createAsyncLocalStorage() {
905
+ let instance;
906
+ const ensure = /* @__PURE__ */ __name(() => {
907
+ if (!this.alsClass) {
908
+ let als;
909
+ const forceNoop = typeof process !== "undefined" && !!process.env?.RUNNER_FORCE_NOOP_ALS;
910
+ if (!forceNoop) {
911
+ try {
912
+ const mod = __require("async_hooks");
913
+ als = mod?.AsyncLocalStorage;
914
+ } catch (_) {
915
+ als = void 0;
916
+ }
917
+ }
918
+ this.alsClass = als ? als : class NoopAsyncLocalStorage {
919
+ static {
920
+ __name(this, "NoopAsyncLocalStorage");
921
+ }
922
+ getStore() {
923
+ return void 0;
924
+ }
925
+ run(_store, callback) {
926
+ return callback();
927
+ }
928
+ };
929
+ }
930
+ return instance ??= new this.alsClass();
931
+ }, "ensure");
932
+ return {
933
+ getStore: /* @__PURE__ */ __name(() => ensure().getStore(), "getStore"),
934
+ run: /* @__PURE__ */ __name((store2, callback) => ensure().run(store2, callback), "run")
935
+ };
936
+ }
888
937
  };
889
938
 
890
- // src/definers/defineHook.ts
891
- function defineHook(hookDef) {
892
- const filePath = getCallerFile();
893
- return {
894
- [symbolHook]: true,
895
- [symbolFilePath]: filePath,
896
- id: hookDef.id,
897
- dependencies: hookDef.dependencies || {},
898
- on: hookDef.on,
899
- order: hookDef.order,
900
- run: hookDef.run,
901
- meta: hookDef.meta || {},
902
- tags: hookDef.tags || []
903
- };
904
- }
905
- __name(defineHook, "defineHook");
906
-
907
939
  // src/errors.ts
908
940
  var errors_exports = {};
909
941
  __export(errors_exports, {
@@ -999,13 +1031,18 @@ function makeErrorBuilder(state) {
999
1031
  const next = clone(state, { format: fn });
1000
1032
  return makeErrorBuilder(next);
1001
1033
  },
1034
+ meta(m) {
1035
+ const next = clone(state, { meta: m });
1036
+ return makeErrorBuilder(next);
1037
+ },
1002
1038
  build() {
1003
1039
  return defineError({
1004
1040
  id: state.id,
1005
1041
  serialize: state.serialize,
1006
1042
  parse: state.parse,
1007
1043
  dataSchema: state.dataSchema,
1008
- format: state.format
1044
+ format: state.format,
1045
+ meta: state.meta
1009
1046
  });
1010
1047
  }
1011
1048
  };
@@ -1017,93 +1054,101 @@ function errorBuilder(id2) {
1017
1054
  id: id2,
1018
1055
  serialize: void 0,
1019
1056
  parse: void 0,
1020
- dataSchema: void 0
1057
+ dataSchema: void 0,
1058
+ meta: {}
1021
1059
  });
1022
1060
  return makeErrorBuilder(initial);
1023
1061
  }
1024
1062
  __name(errorBuilder, "errorBuilder");
1025
1063
  var error = errorBuilder;
1026
1064
 
1027
- // src/platform/adapters/node-als.ts
1028
- async function loadAsyncLocalStorageClass() {
1029
- const mod = __require("async_hooks");
1030
- return mod.AsyncLocalStorage;
1031
- }
1032
- __name(loadAsyncLocalStorageClass, "loadAsyncLocalStorageClass");
1033
-
1034
- // src/platform/adapters/node.ts
1035
- var NodePlatformAdapter = class {
1036
- constructor() {
1037
- this.id = "node";
1038
- this.setTimeout = globalThis.setTimeout;
1039
- this.clearTimeout = globalThis.clearTimeout;
1040
- }
1041
- static {
1042
- __name(this, "NodePlatformAdapter");
1043
- }
1044
- async init() {
1045
- this.alsClass = await loadAsyncLocalStorageClass();
1046
- }
1047
- onUncaughtException(handler) {
1048
- process.on("uncaughtException", handler);
1049
- return () => process.off("uncaughtException", handler);
1050
- }
1051
- onUnhandledRejection(handler) {
1052
- const h = /* @__PURE__ */ __name((reason) => handler(reason), "h");
1053
- process.on("unhandledRejection", h);
1054
- return () => process.off("unhandledRejection", h);
1055
- }
1056
- onShutdownSignal(handler) {
1057
- process.on("SIGINT", handler);
1058
- process.on("SIGTERM", handler);
1059
- return () => {
1060
- process.off("SIGINT", handler);
1061
- process.off("SIGTERM", handler);
1062
- };
1063
- }
1064
- exit(code) {
1065
- process.exit(code);
1066
- }
1067
- getEnv(key) {
1068
- return process.env[key];
1069
- }
1070
- hasAsyncLocalStorage() {
1071
- return true;
1072
- }
1073
- createAsyncLocalStorage() {
1074
- let instance;
1075
- const ensure = /* @__PURE__ */ __name(() => {
1076
- if (!this.alsClass) {
1077
- let als;
1078
- const forceNoop = typeof process !== "undefined" && !!process.env?.RUNNER_FORCE_NOOP_ALS;
1079
- if (!forceNoop) {
1080
- try {
1081
- const mod = __require("async_hooks");
1082
- als = mod?.AsyncLocalStorage;
1083
- } catch (_) {
1084
- als = void 0;
1085
- }
1086
- }
1087
- this.alsClass = als ? als : class NoopAsyncLocalStorage {
1088
- static {
1089
- __name(this, "NoopAsyncLocalStorage");
1090
- }
1091
- getStore() {
1092
- return void 0;
1093
- }
1094
- run(_store, callback) {
1095
- return callback();
1096
- }
1097
- };
1098
- }
1099
- return instance ??= new this.alsClass();
1100
- }, "ensure");
1101
- return {
1102
- getStore: /* @__PURE__ */ __name(() => ensure().getStore(), "getStore"),
1103
- run: /* @__PURE__ */ __name((store2, callback) => ensure().run(store2, callback), "run")
1104
- };
1065
+ // src/errors.ts
1066
+ var duplicateRegistrationError = error("runner.errors.duplicateRegistration").format(
1067
+ ({ 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.`
1068
+ ).build();
1069
+ var dependencyNotFoundError = error("runner.errors.dependencyNotFound").format(
1070
+ ({ key }) => `Dependency ${key.toString()} not found. Did you forget to register it through a resource?`
1071
+ ).build();
1072
+ var unknownItemTypeError = error(
1073
+ "runner.errors.unknownItemType"
1074
+ ).format(
1075
+ ({ item }) => `Unknown item type: ${String(
1076
+ item
1077
+ )}. Please ensure you are not using different versions of '@bluelibs/runner'`
1078
+ ).build();
1079
+ var contextError = error(
1080
+ "runner.errors.context"
1081
+ ).format(({ details }) => details ?? "Context error").build();
1082
+ var circularDependenciesError = error("runner.errors.circularDependencies").format(({ cycles }) => {
1083
+ const cycleDetails = cycles.map((cycle) => ` \u2022 ${cycle}`).join("\n");
1084
+ const hasMiddleware = cycles.some((cycle) => cycle.includes("middleware"));
1085
+ let guidance = "\n\nTo resolve circular dependencies:";
1086
+ guidance += "\n \u2022 Consider refactoring to reduce coupling between components";
1087
+ guidance += "\n \u2022 Extract shared dependencies into separate resources";
1088
+ if (hasMiddleware) {
1089
+ guidance += "\n \u2022 For middleware: you can filter out tasks/resources using everywhere(fn)";
1090
+ guidance += "\n \u2022 Consider using events for communication instead of direct dependencies";
1105
1091
  }
1106
- };
1092
+ return `Circular dependencies detected:
1093
+ ${cycleDetails}${guidance}`;
1094
+ }).build();
1095
+ var eventNotFoundError = error(
1096
+ "runner.errors.eventNotFound"
1097
+ ).format(
1098
+ ({ id: id2 }) => `Event "${id2.toString()}" not found. Did you forget to register it?`
1099
+ ).build();
1100
+ var resourceNotFoundError = error(
1101
+ "runner.errors.resourceNotFound"
1102
+ ).format(
1103
+ ({ id: id2 }) => `Resource "${id2.toString()}" not found. Did you forget to register it or are you using the correct id?`
1104
+ ).build();
1105
+ var middlewareNotRegisteredError = error("runner.errors.middlewareNotRegistered").format(
1106
+ ({ type, source, middlewareId }) => `Middleware inside ${type} "${source}" depends on "${middlewareId}" but it's not registered. Did you forget to register it?`
1107
+ ).build();
1108
+ var tagNotFoundError = error(
1109
+ "runner.errors.tagNotFound"
1110
+ ).format(
1111
+ ({ id: id2 }) => `Tag "${id2}" not registered. Did you forget to register it inside a resource?`
1112
+ ).build();
1113
+ var lockedError = error(
1114
+ "runner.errors.locked"
1115
+ ).format(
1116
+ ({ what }) => `Cannot modify the ${what.toString()} when it is locked.`
1117
+ ).build();
1118
+ var storeAlreadyInitializedError = error(
1119
+ "runner.errors.storeAlreadyInitialized"
1120
+ ).format(() => "Store already initialized. Cannot reinitialize.").build();
1121
+ var validationError = error("runner.errors.validation").format(({ subject, id: id2, originalError }) => {
1122
+ const errorMessage2 = originalError instanceof Error ? originalError.message : String(originalError);
1123
+ return `${subject} validation failed for ${id2.toString()}: ${errorMessage2}`;
1124
+ }).build();
1125
+ var eventCycleError = error("runner.errors.eventCycle").format(({ path: path3 }) => {
1126
+ const chain = path3.map((p) => `${p.id}\u2190${p.source}`).join(" -> ");
1127
+ return `Event emission cycle detected:
1128
+ ${chain}
1129
+
1130
+ Break the cycle by changing hook logic (avoid mutual emits) or gate with conditions/tags.`;
1131
+ }).build();
1132
+ var eventEmissionCycleError = error("runner.errors.eventEmissionCycle").format(({ cycles }) => {
1133
+ const list = cycles.map((c) => ` \u2022 ${c}`).join("\n");
1134
+ return `Event emission cycles detected between hooks and events:
1135
+ ${list}
1136
+
1137
+ This was detected at compile time (dry-run). Break the cycle by avoiding mutual emits between hooks or scoping hooks using tags.`;
1138
+ }).build();
1139
+ var platformUnsupportedFunctionError = error("runner.errors.platformUnsupportedFunction").format(
1140
+ ({ functionName }) => `Platform function not supported in this environment: ${functionName}. Detected platform: ${detectEnvironment()}.`
1141
+ ).build();
1142
+ var cancellationError = error(
1143
+ "runner.errors.cancellation"
1144
+ ).format(({ reason }) => reason || "Operation cancelled").build();
1145
+ var tunnelOwnershipConflictError = error("runner.errors.tunnelOwnershipConflict").format(
1146
+ ({ 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.`
1147
+ ).build();
1148
+ function isCancellationError(err) {
1149
+ return cancellationError.is(err);
1150
+ }
1151
+ __name(isCancellationError, "isCancellationError");
1107
1152
 
1108
1153
  // src/platform/adapters/browser.ts
1109
1154
  var BrowserPlatformAdapter = class {
@@ -1412,6 +1457,12 @@ function setPlatform(adapter) {
1412
1457
  adapter.id;
1413
1458
  }
1414
1459
  __name(setPlatform, "setPlatform");
1460
+ function isNode() {
1461
+ {
1462
+ return true;
1463
+ }
1464
+ }
1465
+ __name(isNode, "isNode");
1415
1466
  var PlatformAdapter = class {
1416
1467
  constructor(env) {
1417
1468
  this.setTimeout = globalThis.setTimeout;
@@ -1465,93 +1516,79 @@ var PlatformAdapter = class {
1465
1516
  }
1466
1517
  };
1467
1518
 
1468
- // src/errors.ts
1469
- var duplicateRegistrationError = error("runner.errors.duplicateRegistration").format(
1470
- ({ 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.`
1471
- ).build();
1472
- var dependencyNotFoundError = error("runner.errors.dependencyNotFound").format(
1473
- ({ key }) => `Dependency ${key.toString()} not found. Did you forget to register it through a resource?`
1474
- ).build();
1475
- var unknownItemTypeError = error(
1476
- "runner.errors.unknownItemType"
1477
- ).format(
1478
- ({ item }) => `Unknown item type: ${String(
1479
- item
1480
- )}. Please ensure you are not using different versions of '@bluelibs/runner'`
1481
- ).build();
1482
- var contextError = error(
1483
- "runner.errors.context"
1484
- ).format(({ details }) => details ?? "Context error").build();
1485
- var circularDependenciesError = error("runner.errors.circularDependencies").format(({ cycles }) => {
1486
- const cycleDetails = cycles.map((cycle) => ` \u2022 ${cycle}`).join("\n");
1487
- const hasMiddleware = cycles.some((cycle) => cycle.includes("middleware"));
1488
- let guidance = "\n\nTo resolve circular dependencies:";
1489
- guidance += "\n \u2022 Consider refactoring to reduce coupling between components";
1490
- guidance += "\n \u2022 Extract shared dependencies into separate resources";
1491
- if (hasMiddleware) {
1492
- guidance += "\n \u2022 For middleware: you can filter out tasks/resources using everywhere(fn)";
1493
- guidance += "\n \u2022 Consider using events for communication instead of direct dependencies";
1519
+ // src/tools/getCallerFile.ts
1520
+ function getCallerFile() {
1521
+ const originalPrepare = Error.prepareStackTrace;
1522
+ try {
1523
+ if (isNode()) {
1524
+ const err = new Error();
1525
+ Error.prepareStackTrace = (_err, stack2) => stack2;
1526
+ const stack = err.stack;
1527
+ stack.shift();
1528
+ stack.shift();
1529
+ const candidate = stack.shift();
1530
+ const file = candidate?.getFileName?.();
1531
+ return file;
1532
+ }
1533
+ return "unknown";
1534
+ } finally {
1535
+ Error.prepareStackTrace = originalPrepare;
1494
1536
  }
1495
- return `Circular dependencies detected:
1496
- ${cycleDetails}${guidance}`;
1497
- }).build();
1498
- var eventNotFoundError = error(
1499
- "runner.errors.eventNotFound"
1500
- ).format(
1501
- ({ id: id2 }) => `Event "${id2.toString()}" not found. Did you forget to register it?`
1502
- ).build();
1503
- var resourceNotFoundError = error(
1504
- "runner.errors.resourceNotFound"
1505
- ).format(
1506
- ({ id: id2 }) => `Resource "${id2.toString()}" not found. Did you forget to register it or are you using the correct id?`
1507
- ).build();
1508
- var middlewareNotRegisteredError = error("runner.errors.middlewareNotRegistered").format(
1509
- ({ type, source, middlewareId }) => `Middleware inside ${type} "${source}" depends on "${middlewareId}" but it's not registered. Did you forget to register it?`
1510
- ).build();
1511
- var tagNotFoundError = error(
1512
- "runner.errors.tagNotFound"
1513
- ).format(
1514
- ({ id: id2 }) => `Tag "${id2}" not registered. Did you forget to register it inside a resource?`
1515
- ).build();
1516
- var lockedError = error(
1517
- "runner.errors.locked"
1518
- ).format(
1519
- ({ what }) => `Cannot modify the ${what.toString()} when it is locked.`
1520
- ).build();
1521
- var storeAlreadyInitializedError = error(
1522
- "runner.errors.storeAlreadyInitialized"
1523
- ).format(() => "Store already initialized. Cannot reinitialize.").build();
1524
- var validationError = error("runner.errors.validation").format(({ subject, id: id2, originalError }) => {
1525
- const errorMessage2 = originalError instanceof Error ? originalError.message : String(originalError);
1526
- return `${subject} validation failed for ${id2.toString()}: ${errorMessage2}`;
1527
- }).build();
1528
- var eventCycleError = error("runner.errors.eventCycle").format(({ path: path3 }) => {
1529
- const chain = path3.map((p) => `${p.id}\u2190${p.source}`).join(" -> ");
1530
- return `Event emission cycle detected:
1531
- ${chain}
1537
+ }
1538
+ __name(getCallerFile, "getCallerFile");
1532
1539
 
1533
- Break the cycle by changing hook logic (avoid mutual emits) or gate with conditions/tags.`;
1534
- }).build();
1535
- var eventEmissionCycleError = error("runner.errors.eventEmissionCycle").format(({ cycles }) => {
1536
- const list = cycles.map((c) => ` \u2022 ${c}`).join("\n");
1537
- return `Event emission cycles detected between hooks and events:
1538
- ${list}
1540
+ // src/definers/defineTask.ts
1541
+ function defineTask(taskConfig) {
1542
+ const filePath = getCallerFile();
1543
+ const id2 = taskConfig.id;
1544
+ return {
1545
+ [symbolTask]: true,
1546
+ [symbolFilePath]: filePath,
1547
+ id: id2,
1548
+ dependencies: taskConfig.dependencies || {},
1549
+ middleware: taskConfig.middleware || [],
1550
+ run: taskConfig.run,
1551
+ inputSchema: taskConfig.inputSchema,
1552
+ resultSchema: taskConfig.resultSchema,
1553
+ meta: taskConfig.meta || {},
1554
+ tags: taskConfig.tags || [],
1555
+ // autorun,
1556
+ optional() {
1557
+ return {
1558
+ inner: this,
1559
+ [symbolOptionalDependency]: true
1560
+ };
1561
+ }
1562
+ };
1563
+ }
1564
+ __name(defineTask, "defineTask");
1565
+ defineTask.phantom = (taskConfig) => {
1566
+ const taskDef = defineTask({
1567
+ ...taskConfig,
1568
+ run: /* @__PURE__ */ __name(async (input) => {
1569
+ return void 0;
1570
+ }, "run")
1571
+ });
1572
+ taskDef[symbolPhantomTask] = true;
1573
+ return taskDef;
1574
+ };
1539
1575
 
1540
- This was detected at compile time (dry-run). Break the cycle by avoiding mutual emits between hooks or scoping hooks using tags.`;
1541
- }).build();
1542
- var platformUnsupportedFunctionError = error("runner.errors.platformUnsupportedFunction").format(
1543
- ({ functionName }) => `Platform function not supported in this environment: ${functionName}. Detected platform: ${detectEnvironment()}.`
1544
- ).build();
1545
- var cancellationError = error(
1546
- "runner.errors.cancellation"
1547
- ).format(({ reason }) => reason || "Operation cancelled").build();
1548
- var tunnelOwnershipConflictError = error("runner.errors.tunnelOwnershipConflict").format(
1549
- ({ 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.`
1550
- ).build();
1551
- function isCancellationError(err) {
1552
- return cancellationError.is(err);
1576
+ // src/definers/defineHook.ts
1577
+ function defineHook(hookDef) {
1578
+ const filePath = getCallerFile();
1579
+ return {
1580
+ [symbolHook]: true,
1581
+ [symbolFilePath]: filePath,
1582
+ id: hookDef.id,
1583
+ dependencies: hookDef.dependencies || {},
1584
+ on: hookDef.on,
1585
+ order: hookDef.order,
1586
+ run: hookDef.run,
1587
+ meta: hookDef.meta || {},
1588
+ tags: hookDef.tags || []
1589
+ };
1553
1590
  }
1554
- __name(isCancellationError, "isCancellationError");
1591
+ __name(defineHook, "defineHook");
1555
1592
 
1556
1593
  // src/definers/defineResource.ts
1557
1594
  function defineResource(constConfig) {
@@ -1612,6 +1649,7 @@ function defineEvent(config) {
1612
1649
  [symbolEvent]: true,
1613
1650
  // This is a workaround
1614
1651
  tags: eventConfig.tags || [],
1652
+ parallel: eventConfig.parallel,
1615
1653
  optional() {
1616
1654
  return {
1617
1655
  inner: this,
@@ -3978,30 +4016,279 @@ var DependencyProcessor = class {
3978
4016
  }
3979
4017
  };
3980
4018
 
3981
- // src/models/EventManager.ts
4019
+ // src/models/event/types.ts
3982
4020
  var HandlerOptionsDefaults = { order: 0 };
3983
- var EventManager = class {
3984
- constructor(options) {
3985
- // Core storage for event listeners
4021
+
4022
+ // src/models/event/ListenerRegistry.ts
4023
+ var ListenerRegistry = class {
4024
+ constructor(isExcludedFromGlobal) {
3986
4025
  this.listeners = /* @__PURE__ */ new Map();
3987
4026
  this.globalListeners = [];
3988
- // Caching system for merged listeners to improve performance
3989
4027
  this.cachedMergedListeners = /* @__PURE__ */ new Map();
3990
- this.globalListenersCacheValid = true;
3991
- // Interceptors storage
4028
+ this._globalListenersCacheValid = true;
4029
+ this.isExcludedFromGlobal = isExcludedFromGlobal ?? ((event2) => globalTags.excludeFromGlobalHooks.exists(event2));
4030
+ }
4031
+ static {
4032
+ __name(this, "ListenerRegistry");
4033
+ }
4034
+ get globalListenersCacheValid() {
4035
+ return this._globalListenersCacheValid;
4036
+ }
4037
+ addListener(eventId, newListener) {
4038
+ const listeners = this.listeners.get(eventId);
4039
+ if (listeners) {
4040
+ this.insertListener(listeners, newListener);
4041
+ } else {
4042
+ this.listeners.set(eventId, [newListener]);
4043
+ }
4044
+ this.invalidateCache(eventId);
4045
+ }
4046
+ addGlobalListener(newListener) {
4047
+ this.insertListener(this.globalListeners, newListener);
4048
+ this.invalidateCache();
4049
+ }
4050
+ getListenersForEmit(eventDefinition) {
4051
+ const excludeGlobal = this.isExcludedFromGlobal(eventDefinition);
4052
+ if (excludeGlobal) {
4053
+ return this.listeners.get(eventDefinition.id) || [];
4054
+ }
4055
+ return this.getCachedMergedListeners(eventDefinition.id);
4056
+ }
4057
+ hasListeners(eventDefinition) {
4058
+ const eventListeners = this.listeners.get(eventDefinition.id) || [];
4059
+ if (eventListeners.length > 0) {
4060
+ return true;
4061
+ }
4062
+ if (this.globalListeners.length === 0) {
4063
+ return false;
4064
+ }
4065
+ return !this.isExcludedFromGlobal(eventDefinition);
4066
+ }
4067
+ /**
4068
+ * Cached merge between event-specific and global listeners.
4069
+ * Exposed for backward compatibility with existing tests.
4070
+ */
4071
+ getCachedMergedListeners(eventId) {
4072
+ if (!this._globalListenersCacheValid) {
4073
+ this.cachedMergedListeners.clear();
4074
+ this._globalListenersCacheValid = true;
4075
+ }
4076
+ let cached = this.cachedMergedListeners.get(eventId);
4077
+ if (!cached) {
4078
+ const eventListeners = this.listeners.get(eventId) || [];
4079
+ if (eventListeners.length === 0 && this.globalListeners.length === 0) {
4080
+ cached = [];
4081
+ } else if (eventListeners.length === 0) {
4082
+ cached = this.globalListeners;
4083
+ } else if (this.globalListeners.length === 0) {
4084
+ cached = eventListeners;
4085
+ } else {
4086
+ cached = this.mergeSortedListeners(eventListeners, this.globalListeners);
4087
+ }
4088
+ this.cachedMergedListeners.set(eventId, cached);
4089
+ }
4090
+ return cached;
4091
+ }
4092
+ invalidateCache(eventId) {
4093
+ if (eventId) {
4094
+ this.cachedMergedListeners.delete(eventId);
4095
+ } else {
4096
+ this._globalListenersCacheValid = false;
4097
+ }
4098
+ }
4099
+ mergeSortedListeners(a, b) {
4100
+ const result = [];
4101
+ let i = 0;
4102
+ let j = 0;
4103
+ while (i < a.length && j < b.length) {
4104
+ if (a[i].order <= b[j].order) {
4105
+ result.push(a[i++]);
4106
+ } else {
4107
+ result.push(b[j++]);
4108
+ }
4109
+ }
4110
+ while (i < a.length) result.push(a[i++]);
4111
+ while (j < b.length) result.push(b[j++]);
4112
+ return result;
4113
+ }
4114
+ insertListener(listeners, newListener) {
4115
+ let low = 0;
4116
+ let high = listeners.length;
4117
+ while (low < high) {
4118
+ const mid = low + high >>> 1;
4119
+ if (listeners[mid].order < newListener.order) {
4120
+ low = mid + 1;
4121
+ } else {
4122
+ high = mid;
4123
+ }
4124
+ }
4125
+ listeners.splice(low, 0, newListener);
4126
+ }
4127
+ };
4128
+ function createListener(newListener) {
4129
+ return {
4130
+ handler: newListener.handler,
4131
+ order: newListener.order ?? HandlerOptionsDefaults.order,
4132
+ filter: newListener.filter,
4133
+ id: newListener.id,
4134
+ isGlobal: newListener.isGlobal ?? false
4135
+ };
4136
+ }
4137
+ __name(createListener, "createListener");
4138
+
4139
+ // src/models/event/InterceptorPipeline.ts
4140
+ function composeInterceptors(interceptors, base) {
4141
+ return interceptors.slice().reverse().reduce(
4142
+ (next, interceptor) => (...args) => interceptor(next, ...args),
4143
+ base
4144
+ );
4145
+ }
4146
+ __name(composeInterceptors, "composeInterceptors");
4147
+
4148
+ // src/models/event/EmissionExecutor.ts
4149
+ async function executeSequentially({
4150
+ listeners,
4151
+ event: event2,
4152
+ isPropagationStopped
4153
+ }) {
4154
+ for (const listener of listeners) {
4155
+ if (isPropagationStopped()) {
4156
+ break;
4157
+ }
4158
+ if (shouldExecuteListener(listener, event2)) {
4159
+ await listener.handler(event2);
4160
+ }
4161
+ }
4162
+ }
4163
+ __name(executeSequentially, "executeSequentially");
4164
+ async function executeInParallel({
4165
+ listeners,
4166
+ event: event2
4167
+ }) {
4168
+ if (listeners.length === 0 || event2.isPropagationStopped()) {
4169
+ return;
4170
+ }
4171
+ let currentOrder = listeners[0].order;
4172
+ let currentBatch = [];
4173
+ const executeBatch = /* @__PURE__ */ __name(async (batch) => {
4174
+ const results = await Promise.allSettled(
4175
+ batch.map(async (listener) => {
4176
+ if (shouldExecuteListener(listener, event2)) {
4177
+ await listener.handler(event2);
4178
+ }
4179
+ })
4180
+ );
4181
+ const errors = results.map((result, index) => ({ result, listener: batch[index] })).filter(
4182
+ (r2) => r2.result.status === "rejected"
4183
+ ).map(({ result, listener }) => {
4184
+ const reason = result.reason;
4185
+ const errObj = reason && typeof reason === "object" ? reason : new Error(String(reason));
4186
+ if (errObj.listenerId === void 0) {
4187
+ errObj.listenerId = listener.id;
4188
+ }
4189
+ if (errObj.listenerOrder === void 0) {
4190
+ errObj.listenerOrder = listener.order;
4191
+ }
4192
+ return errObj;
4193
+ });
4194
+ if (errors.length > 0) {
4195
+ if (errors.length === 1) {
4196
+ throw errors[0];
4197
+ }
4198
+ const aggregateError = new Error(
4199
+ `${errors.length} listeners failed in parallel batch`
4200
+ );
4201
+ aggregateError.errors = errors;
4202
+ aggregateError.name = "AggregateError";
4203
+ throw aggregateError;
4204
+ }
4205
+ }, "executeBatch");
4206
+ for (const listener of listeners) {
4207
+ if (listener.order !== currentOrder) {
4208
+ await executeBatch(currentBatch);
4209
+ currentBatch = [];
4210
+ currentOrder = listener.order;
4211
+ if (event2.isPropagationStopped()) {
4212
+ break;
4213
+ }
4214
+ }
4215
+ currentBatch.push(listener);
4216
+ }
4217
+ if (currentBatch.length > 0 && !event2.isPropagationStopped()) {
4218
+ await executeBatch(currentBatch);
4219
+ }
4220
+ }
4221
+ __name(executeInParallel, "executeInParallel");
4222
+ function shouldExecuteListener(listener, event2) {
4223
+ if (listener.id && listener.id === event2.source) {
4224
+ return false;
4225
+ }
4226
+ return !listener.filter || listener.filter(event2);
4227
+ }
4228
+ __name(shouldExecuteListener, "shouldExecuteListener");
4229
+
4230
+ // src/models/event/CycleContext.ts
4231
+ var CycleContext = class {
4232
+ static {
4233
+ __name(this, "CycleContext");
4234
+ }
4235
+ constructor(runtimeCycleDetection) {
4236
+ const platform3 = getPlatform();
4237
+ if (platform3.hasAsyncLocalStorage() && runtimeCycleDetection) {
4238
+ this.emissionStack = platform3.createAsyncLocalStorage();
4239
+ this.currentHookIdContext = platform3.createAsyncLocalStorage();
4240
+ this.isEnabled = true;
4241
+ } else {
4242
+ this.emissionStack = null;
4243
+ this.currentHookIdContext = null;
4244
+ this.isEnabled = false;
4245
+ }
4246
+ }
4247
+ runEmission(frame, source, processEmission) {
4248
+ if (!this.isEnabled || !this.emissionStack || !this.currentHookIdContext) {
4249
+ return processEmission();
4250
+ }
4251
+ const currentStack = this.emissionStack.getStore();
4252
+ if (currentStack) {
4253
+ const cycleStart = currentStack.findIndex(
4254
+ (f) => f.id === frame.id
4255
+ );
4256
+ if (cycleStart !== -1) {
4257
+ const top = currentStack[currentStack.length - 1];
4258
+ const currentHookId = this.currentHookIdContext.getStore();
4259
+ const safeReEmitBySameHook = top.id === frame.id && currentHookId && currentHookId === source;
4260
+ if (!safeReEmitBySameHook) {
4261
+ eventCycleError.throw({
4262
+ path: [...currentStack.slice(cycleStart), frame]
4263
+ });
4264
+ }
4265
+ }
4266
+ }
4267
+ const nextStack = currentStack ? [...currentStack, frame] : [frame];
4268
+ return this.emissionStack.run(nextStack, processEmission);
4269
+ }
4270
+ runHook(hookId, execute) {
4271
+ if (!this.isEnabled || !this.currentHookIdContext) {
4272
+ return execute();
4273
+ }
4274
+ return this.currentHookIdContext.run(hookId, execute);
4275
+ }
4276
+ };
4277
+
4278
+ // src/models/EventManager.ts
4279
+ var EventManager = class {
4280
+ constructor(options) {
4281
+ // Interceptors storage (tests access these directly)
3992
4282
  this.emissionInterceptors = [];
3993
4283
  this.hookInterceptors = [];
3994
4284
  // Locking mechanism to prevent modifications after initialization
3995
4285
  this.#isLocked = false;
3996
4286
  this.runtimeCycleDetection = options?.runtimeCycleDetection ?? true;
3997
- if (getPlatform().hasAsyncLocalStorage() && this.runtimeCycleDetection) {
3998
- this.emissionStack = getPlatform().createAsyncLocalStorage();
3999
- this.currentHookIdContext = getPlatform().createAsyncLocalStorage();
4000
- } else {
4001
- this.runtimeCycleDetection = false;
4002
- this.emissionStack = null;
4003
- this.currentHookIdContext = null;
4004
- }
4287
+ this.registry = new ListenerRegistry();
4288
+ this.cycleContext = new CycleContext(this.runtimeCycleDetection);
4289
+ this.listeners = this.registry.listeners;
4290
+ this.globalListeners = this.registry.globalListeners;
4291
+ this.cachedMergedListeners = this.registry.cachedMergedListeners;
4005
4292
  }
4006
4293
  static {
4007
4294
  __name(this, "EventManager");
@@ -4042,8 +4329,7 @@ var EventManager = class {
4042
4329
  }
4043
4330
  const frame = { id: eventDefinition.id, source };
4044
4331
  const processEmission = /* @__PURE__ */ __name(async () => {
4045
- const excludeFromGlobal = globalTags.excludeFromGlobalHooks.exists(eventDefinition);
4046
- const allListeners = excludeFromGlobal ? this.listeners.get(eventDefinition.id) || [] : this.getCachedMergedListeners(eventDefinition.id);
4332
+ const allListeners = this.registry.getListenersForEmit(eventDefinition);
4047
4333
  let propagationStopped = false;
4048
4334
  const event2 = {
4049
4335
  id: eventDefinition.id,
@@ -4061,49 +4347,23 @@ var EventManager = class {
4061
4347
  if (allListeners.length === 0) {
4062
4348
  return;
4063
4349
  }
4064
- this.isExcludedFromGlobal(eventToEmit);
4065
- for (const listener of allListeners) {
4066
- if (propagationStopped) {
4067
- break;
4068
- }
4069
- if (listener.id && listener.id === eventToEmit.source) {
4070
- continue;
4071
- }
4072
- if (!listener.filter || listener.filter(eventToEmit)) {
4073
- await listener.handler(eventToEmit);
4074
- }
4350
+ if (eventDefinition.parallel) {
4351
+ await executeInParallel({ listeners: allListeners, event: eventToEmit });
4352
+ } else {
4353
+ await executeSequentially({
4354
+ listeners: allListeners,
4355
+ event: eventToEmit,
4356
+ isPropagationStopped: /* @__PURE__ */ __name(() => propagationStopped, "isPropagationStopped")
4357
+ });
4075
4358
  }
4076
4359
  }, "baseEmit");
4077
- let emitWithInterceptors = baseEmit;
4078
- const reversedInterceptors = [...this.emissionInterceptors].reverse();
4079
- for (const interceptor of reversedInterceptors) {
4080
- const nextFunction = emitWithInterceptors;
4081
- emitWithInterceptors = /* @__PURE__ */ __name(async (eventToEmit) => interceptor(nextFunction, eventToEmit), "emitWithInterceptors");
4082
- }
4360
+ const emitWithInterceptors = composeInterceptors(
4361
+ this.emissionInterceptors,
4362
+ baseEmit
4363
+ );
4083
4364
  await emitWithInterceptors(event2);
4084
4365
  }, "processEmission");
4085
- if (this.runtimeCycleDetection && this.emissionStack && this.currentHookIdContext) {
4086
- const currentStack = this.emissionStack.getStore();
4087
- if (currentStack) {
4088
- const cycleStart = currentStack.findIndex(
4089
- (f) => f.id === frame.id
4090
- );
4091
- if (cycleStart !== -1) {
4092
- const top = currentStack[currentStack.length - 1];
4093
- const currentHookId = this.currentHookIdContext.getStore();
4094
- const safeReEmitBySameHook = top.id === frame.id && currentHookId && currentHookId === source;
4095
- if (!safeReEmitBySameHook) {
4096
- eventCycleError.throw({
4097
- path: [...currentStack.slice(cycleStart), frame]
4098
- });
4099
- }
4100
- }
4101
- }
4102
- const nextStack = currentStack ? [...currentStack, frame] : [frame];
4103
- await this.emissionStack.run(nextStack, processEmission);
4104
- } else {
4105
- await processEmission();
4106
- }
4366
+ await this.cycleContext.runEmission(frame, source, processEmission);
4107
4367
  }
4108
4368
  /**
4109
4369
  * Registers an event listener for specific event(s).
@@ -4115,24 +4375,18 @@ var EventManager = class {
4115
4375
  */
4116
4376
  addListener(event2, handler, options = HandlerOptionsDefaults) {
4117
4377
  this.checkLock();
4118
- const newListener = {
4378
+ const newListener = createListener({
4119
4379
  handler,
4120
- order: options.order || 0,
4380
+ order: options.order,
4121
4381
  filter: options.filter,
4122
4382
  id: options.id,
4123
4383
  isGlobal: false
4124
- };
4384
+ });
4125
4385
  if (Array.isArray(event2)) {
4126
4386
  event2.forEach((id2) => this.addListener(id2, handler, options));
4127
4387
  } else {
4128
4388
  const eventId = event2.id;
4129
- const listeners = this.listeners.get(eventId);
4130
- if (listeners) {
4131
- this.insertListener(listeners, newListener);
4132
- } else {
4133
- this.listeners.set(eventId, [newListener]);
4134
- }
4135
- this.invalidateCache(eventId);
4389
+ this.registry.addListener(eventId, newListener);
4136
4390
  }
4137
4391
  }
4138
4392
  /**
@@ -4144,15 +4398,14 @@ var EventManager = class {
4144
4398
  */
4145
4399
  addGlobalListener(handler, options = HandlerOptionsDefaults) {
4146
4400
  this.checkLock();
4147
- const newListener = {
4401
+ const newListener = createListener({
4148
4402
  handler,
4149
- order: options.order || 0,
4403
+ order: options.order,
4150
4404
  filter: options.filter,
4151
4405
  id: options.id,
4152
4406
  isGlobal: true
4153
- };
4154
- this.insertListener(this.globalListeners, newListener);
4155
- this.invalidateCache();
4407
+ });
4408
+ this.registry.addGlobalListener(newListener);
4156
4409
  }
4157
4410
  /**
4158
4411
  * Checks if there are any listeners registered for the given event
@@ -4161,15 +4414,7 @@ var EventManager = class {
4161
4414
  * @returns true if listeners exist, false otherwise
4162
4415
  */
4163
4416
  hasListeners(eventDefinition) {
4164
- const eventListeners = this.listeners.get(eventDefinition.id) || [];
4165
- if (eventListeners.length > 0) {
4166
- return true;
4167
- }
4168
- if (this.globalListeners.length === 0) {
4169
- return false;
4170
- }
4171
- const isExcludedFromGlobal = globalTags.excludeFromGlobalHooks.exists(eventDefinition);
4172
- return !isExcludedFromGlobal;
4417
+ return this.registry.hasListeners(eventDefinition);
4173
4418
  }
4174
4419
  /**
4175
4420
  * Adds an interceptor for all event emissions
@@ -4214,20 +4459,14 @@ var EventManager = class {
4214
4459
  throw err;
4215
4460
  }
4216
4461
  }, "baseExecute");
4217
- let executeWithInterceptors = baseExecute;
4218
- const reversedInterceptors = [...this.hookInterceptors].reverse();
4219
- for (const interceptor of reversedInterceptors) {
4220
- const nextFunction = executeWithInterceptors;
4221
- executeWithInterceptors = /* @__PURE__ */ __name(async (hookToExecute, eventForHook) => interceptor(nextFunction, hookToExecute, eventForHook), "executeWithInterceptors");
4222
- }
4223
- if (this.runtimeCycleDetection) {
4224
- return await this.currentHookIdContext?.run(
4225
- hook2.id,
4226
- async () => await executeWithInterceptors(hook2, event2)
4227
- );
4228
- } else {
4229
- return await executeWithInterceptors(hook2, event2);
4230
- }
4462
+ const executeWithInterceptors = composeInterceptors(
4463
+ this.hookInterceptors,
4464
+ baseExecute
4465
+ );
4466
+ return this.cycleContext.isEnabled ? await this.cycleContext.runHook(
4467
+ hook2.id,
4468
+ () => executeWithInterceptors(hook2, event2)
4469
+ ) : await executeWithInterceptors(hook2, event2);
4231
4470
  }
4232
4471
  // ==================== PRIVATE METHODS ====================
4233
4472
  /**
@@ -4238,102 +4477,12 @@ var EventManager = class {
4238
4477
  lockedError.throw({ what: "EventManager" });
4239
4478
  }
4240
4479
  }
4241
- /**
4242
- * Merges two sorted arrays of listeners while maintaining order.
4243
- * Used to combine event-specific listeners with global listeners.
4244
- *
4245
- * @param a - First array of listeners
4246
- * @param b - Second array of listeners
4247
- * @returns Merged and sorted array of listeners
4248
- */
4249
- mergeSortedListeners(a, b) {
4250
- const result = [];
4251
- let i = 0, j = 0;
4252
- while (i < a.length && j < b.length) {
4253
- if (a[i].order <= b[j].order) {
4254
- result.push(a[i++]);
4255
- } else {
4256
- result.push(b[j++]);
4257
- }
4258
- }
4259
- while (i < a.length) result.push(a[i++]);
4260
- while (j < b.length) result.push(b[j++]);
4261
- return result;
4262
- }
4263
- /**
4264
- * Inserts a new listener into a sorted array using binary search.
4265
- * Maintains order based on listener priority.
4266
- *
4267
- * @param listeners - Array to insert into
4268
- * @param newListener - Listener to insert
4269
- */
4270
- insertListener(listeners, newListener) {
4271
- let low = 0;
4272
- let high = listeners.length;
4273
- while (low < high) {
4274
- const mid = low + high >>> 1;
4275
- if (listeners[mid].order < newListener.order) {
4276
- low = mid + 1;
4277
- } else {
4278
- high = mid;
4279
- }
4280
- }
4281
- listeners.splice(low, 0, newListener);
4282
- }
4283
- /**
4284
- * Returns true if the given emission carries the tag that marks
4285
- * it as excluded from global ("*") listeners.
4286
- *
4287
- * @param event - The event emission to check
4288
- * @returns true if event should exclude global listeners
4289
- */
4290
- isExcludedFromGlobal(event2) {
4291
- return globalTags.excludeFromGlobalHooks.exists(event2);
4292
- }
4293
4480
  /**
4294
4481
  * Retrieves cached merged listeners for an event, or creates them if not cached.
4295
- * Combines event-specific listeners with global listeners and sorts them by priority.
4296
- *
4297
- * @param eventId - The event ID to get listeners for
4298
- * @returns Array of merged listeners sorted by priority
4482
+ * Kept for backward compatibility (tests spy on this).
4299
4483
  */
4300
4484
  getCachedMergedListeners(eventId) {
4301
- if (!this.globalListenersCacheValid) {
4302
- this.cachedMergedListeners.clear();
4303
- this.globalListenersCacheValid = true;
4304
- }
4305
- let cached = this.cachedMergedListeners.get(eventId);
4306
- if (!cached) {
4307
- const eventListeners = this.listeners.get(eventId) || [];
4308
- if (eventListeners.length === 0 && this.globalListeners.length === 0) {
4309
- cached = [];
4310
- } else if (eventListeners.length === 0) {
4311
- cached = this.globalListeners;
4312
- } else if (this.globalListeners.length === 0) {
4313
- cached = eventListeners;
4314
- } else {
4315
- cached = this.mergeSortedListeners(
4316
- eventListeners,
4317
- this.globalListeners
4318
- );
4319
- }
4320
- this.cachedMergedListeners.set(eventId, cached);
4321
- }
4322
- return cached;
4323
- }
4324
- /**
4325
- * Invalidates the cached merged listeners.
4326
- * If eventId is provided, only invalidates cache for that specific event.
4327
- * Otherwise, invalidates the global cache.
4328
- *
4329
- * @param eventId - Optional specific event ID to invalidate
4330
- */
4331
- invalidateCache(eventId) {
4332
- if (eventId) {
4333
- this.cachedMergedListeners.delete(eventId);
4334
- } else {
4335
- this.globalListenersCacheValid = false;
4336
- }
4485
+ return this.registry.getCachedMergedListeners(eventId);
4337
4486
  }
4338
4487
  };
4339
4488
 
@@ -6024,15 +6173,19 @@ function makeResourceBuilder(state) {
6024
6173
  meta: state.meta,
6025
6174
  overrides: state.overrides
6026
6175
  };
6027
- return defineResource(definition);
6176
+ const resource2 = defineResource(definition);
6177
+ resource2[symbolFilePath] = state.filePath;
6178
+ return resource2;
6028
6179
  }
6029
6180
  };
6030
6181
  return builder;
6031
6182
  }
6032
6183
  __name(makeResourceBuilder, "makeResourceBuilder");
6033
6184
  function resourceBuilder(id2) {
6185
+ const filePath = getCallerFile();
6034
6186
  const initial = Object.freeze({
6035
6187
  id: id2,
6188
+ filePath,
6036
6189
  dependencies: void 0,
6037
6190
  register: void 0,
6038
6191
  middleware: [],
@@ -6146,6 +6299,7 @@ function makePhantomTaskBuilder(state) {
6146
6299
  meta: state.meta,
6147
6300
  tags: state.tags
6148
6301
  });
6302
+ built[symbolFilePath] = state.filePath;
6149
6303
  return built;
6150
6304
  }
6151
6305
  };
@@ -6153,8 +6307,10 @@ function makePhantomTaskBuilder(state) {
6153
6307
  }
6154
6308
  __name(makePhantomTaskBuilder, "makePhantomTaskBuilder");
6155
6309
  function phantomTaskBuilder(id2) {
6310
+ const filePath = getCallerFile();
6156
6311
  const initial = Object.freeze({
6157
6312
  id: id2,
6313
+ filePath,
6158
6314
  dependencies: {},
6159
6315
  middleware: [],
6160
6316
  meta: {},
@@ -6221,17 +6377,21 @@ function makeTaskBuilder(state) {
6221
6377
  return makeTaskBuilder(next);
6222
6378
  },
6223
6379
  build() {
6224
- return defineTask({
6380
+ const task2 = defineTask({
6225
6381
  ...state
6226
6382
  });
6383
+ task2[symbolFilePath] = state.filePath;
6384
+ return task2;
6227
6385
  }
6228
6386
  };
6229
6387
  return builder;
6230
6388
  }
6231
6389
  __name(makeTaskBuilder, "makeTaskBuilder");
6232
6390
  function taskBuilder(id2) {
6391
+ const filePath = getCallerFile();
6233
6392
  const initial = Object.freeze({
6234
6393
  id: id2,
6394
+ filePath,
6235
6395
  dependencies: {},
6236
6396
  middleware: [],
6237
6397
  meta: {},
@@ -6269,21 +6429,30 @@ function makeEventBuilder(state) {
6269
6429
  const next = clone5(state, { meta: m });
6270
6430
  return makeEventBuilder(next);
6271
6431
  },
6432
+ parallel(enabled = true) {
6433
+ const next = clone5(state, { parallel: enabled });
6434
+ return makeEventBuilder(next);
6435
+ },
6272
6436
  build() {
6273
- return defineEvent({
6437
+ const event2 = defineEvent({
6274
6438
  ...state
6275
6439
  });
6440
+ event2[symbolFilePath] = state.filePath;
6441
+ return event2;
6276
6442
  }
6277
6443
  };
6278
6444
  return b;
6279
6445
  }
6280
6446
  __name(makeEventBuilder, "makeEventBuilder");
6281
6447
  function eventBuilder(id2) {
6448
+ const filePath = getCallerFile();
6282
6449
  const initial = Object.freeze({
6283
6450
  id: id2,
6451
+ filePath,
6284
6452
  meta: {},
6285
6453
  payloadSchema: void 0,
6286
- tags: []
6454
+ tags: [],
6455
+ parallel: void 0
6287
6456
  });
6288
6457
  return makeEventBuilder(initial);
6289
6458
  }
@@ -6359,17 +6528,21 @@ function makeHookBuilder(state) {
6359
6528
  return makeHookBuilder(next);
6360
6529
  },
6361
6530
  build() {
6362
- return defineHook({
6531
+ const hook2 = defineHook({
6363
6532
  ...state
6364
6533
  });
6534
+ hook2[symbolFilePath] = state.filePath;
6535
+ return hook2;
6365
6536
  }
6366
6537
  };
6367
6538
  return b;
6368
6539
  }
6369
6540
  __name(makeHookBuilder, "makeHookBuilder");
6370
6541
  function hookBuilder(id2) {
6542
+ const filePath = getCallerFile();
6371
6543
  const initial = Object.freeze({
6372
6544
  id: id2,
6545
+ filePath,
6373
6546
  dependencies: {},
6374
6547
  on: "*",
6375
6548
  order: void 0,
@@ -6452,17 +6625,21 @@ function makeTaskMiddlewareBuilder(state) {
6452
6625
  return makeTaskMiddlewareBuilder(next);
6453
6626
  },
6454
6627
  build() {
6455
- return defineTaskMiddleware({
6628
+ const middleware = defineTaskMiddleware({
6456
6629
  ...state
6457
6630
  });
6631
+ middleware[symbolFilePath] = state.filePath;
6632
+ return middleware;
6458
6633
  }
6459
6634
  };
6460
6635
  return b;
6461
6636
  }
6462
6637
  __name(makeTaskMiddlewareBuilder, "makeTaskMiddlewareBuilder");
6463
6638
  function taskMiddlewareBuilder(id2) {
6639
+ const filePath = getCallerFile();
6464
6640
  const initial = Object.freeze({
6465
6641
  id: id2,
6642
+ filePath,
6466
6643
  dependencies: {},
6467
6644
  configSchema: void 0,
6468
6645
  run: void 0,
@@ -6542,17 +6719,21 @@ function makeResourceMiddlewareBuilder(state) {
6542
6719
  return makeResourceMiddlewareBuilder(next);
6543
6720
  },
6544
6721
  build() {
6545
- return defineResourceMiddleware({
6722
+ const middleware = defineResourceMiddleware({
6546
6723
  ...state
6547
6724
  });
6725
+ middleware[symbolFilePath] = state.filePath;
6726
+ return middleware;
6548
6727
  }
6549
6728
  };
6550
6729
  return b;
6551
6730
  }
6552
6731
  __name(makeResourceMiddlewareBuilder, "makeResourceMiddlewareBuilder");
6553
6732
  function resourceMiddlewareBuilder(id2) {
6733
+ const filePath = getCallerFile();
6554
6734
  const initial = Object.freeze({
6555
6735
  id: id2,
6736
+ filePath,
6556
6737
  dependencies: {},
6557
6738
  configSchema: void 0,
6558
6739
  run: void 0,
@@ -6591,21 +6772,25 @@ function makeTagBuilder(state) {
6591
6772
  );
6592
6773
  },
6593
6774
  build() {
6594
- return defineTag({
6775
+ const tag2 = defineTag({
6595
6776
  id: state.id,
6596
6777
  meta: state.meta,
6597
6778
  configSchema: state.configSchema,
6598
6779
  config: state.config
6599
6780
  });
6781
+ tag2[symbolFilePath] = state.filePath;
6782
+ return tag2;
6600
6783
  }
6601
6784
  };
6602
6785
  return b;
6603
6786
  }
6604
6787
  __name(makeTagBuilder, "makeTagBuilder");
6605
6788
  function tagBuilder(id2) {
6789
+ const filePath = getCallerFile();
6606
6790
  const initial = Object.freeze(
6607
6791
  {
6608
6792
  id: id2,
6793
+ filePath,
6609
6794
  meta: {},
6610
6795
  configSchema: void 0,
6611
6796
  config: void 0
@@ -6636,12 +6821,17 @@ function makeAsyncContextBuilder(state) {
6636
6821
  const next = clone8(state, { configSchema: schema });
6637
6822
  return makeAsyncContextBuilder(next);
6638
6823
  },
6824
+ meta(m) {
6825
+ const next = clone8(state, { meta: m });
6826
+ return makeAsyncContextBuilder(next);
6827
+ },
6639
6828
  build() {
6640
6829
  const def = {
6641
6830
  id: state.id,
6642
6831
  serialize: state.serialize,
6643
6832
  parse: state.parse,
6644
- configSchema: state.configSchema
6833
+ configSchema: state.configSchema,
6834
+ meta: state.meta
6645
6835
  };
6646
6836
  return defineAsyncContext(def);
6647
6837
  }
@@ -6654,7 +6844,8 @@ function asyncContextBuilder(id2) {
6654
6844
  id: id2,
6655
6845
  serialize: void 0,
6656
6846
  parse: void 0,
6657
- configSchema: void 0
6847
+ configSchema: void 0,
6848
+ meta: {}
6658
6849
  });
6659
6850
  return makeAsyncContextBuilder(initial);
6660
6851
  }
@@ -7045,7 +7236,7 @@ function createAllowListGuard(store2) {
7045
7236
  return null;
7046
7237
  }
7047
7238
  if (!list.taskIds.has(id2)) {
7048
- return jsonErrorResponse(404, `Task ${id2} not exposed`, "NOT_EXPOSED");
7239
+ return jsonErrorResponse(403, `Task ${id2} not exposed`, "FORBIDDEN");
7049
7240
  }
7050
7241
  return null;
7051
7242
  },
@@ -7055,7 +7246,7 @@ function createAllowListGuard(store2) {
7055
7246
  return null;
7056
7247
  }
7057
7248
  if (!list.eventIds.has(id2)) {
7058
- return jsonErrorResponse(404, `Event ${id2} not exposed`, "NOT_EXPOSED");
7249
+ return jsonErrorResponse(403, `Event ${id2} not exposed`, "FORBIDDEN");
7059
7250
  }
7060
7251
  return null;
7061
7252
  }