@pumped-fn/lite 2.1.0 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -87,7 +87,7 @@ function getAtomsForTag(tag$1) {
87
87
  return live;
88
88
  }
89
89
  function tag(options) {
90
- const key = Symbol.for(`@pumped-fn/lite/tag/${options.label}`);
90
+ const key = Symbol(`@pumped-fn/lite/tag/${options.label}`);
91
91
  const hasDefault = "default" in options;
92
92
  const defaultValue = hasDefault ? options.default : void 0;
93
93
  const parse = options.parse;
@@ -424,12 +424,14 @@ function isResource(value) {
424
424
  //#endregion
425
425
  //#region src/service.ts
426
426
  function service(config) {
427
- return {
427
+ const atomInstance = {
428
428
  [atomSymbol]: true,
429
429
  factory: config.factory,
430
430
  deps: config.deps,
431
431
  tags: config.tags
432
432
  };
433
+ if (config.tags?.length) registerAtomToTags(atomInstance, config.tags);
434
+ return atomInstance;
433
435
  }
434
436
 
435
437
  //#endregion
@@ -445,7 +447,7 @@ function getResourceKey(resource$1) {
445
447
  return key;
446
448
  }
447
449
  const inflightResources = /* @__PURE__ */ new WeakMap();
448
- const resolvingResources = /* @__PURE__ */ new Set();
450
+ const resolvingResourcesMap = /* @__PURE__ */ new WeakMap();
449
451
  var ContextDataImpl = class {
450
452
  map = /* @__PURE__ */ new Map();
451
453
  constructor(parentData) {
@@ -470,6 +472,10 @@ var ContextDataImpl = class {
470
472
  if (this.map.has(key)) return this.map.get(key);
471
473
  return this.parentData?.seek(key);
472
474
  }
475
+ seekHas(key) {
476
+ if (this.map.has(key)) return true;
477
+ return this.parentData?.seekHas(key) ?? false;
478
+ }
473
479
  getTag(tag$1) {
474
480
  return this.map.get(tag$1.key);
475
481
  }
@@ -515,6 +521,16 @@ var SelectHandleImpl = class {
515
521
  return this.currentValue;
516
522
  }
517
523
  subscribe(listener) {
524
+ if (!this.ctrlUnsub) {
525
+ this.currentValue = this.selector(this.ctrl.get());
526
+ this.ctrlUnsub = this.ctrl.on("resolved", () => {
527
+ const nextValue = this.selector(this.ctrl.get());
528
+ if (!this.eq(this.currentValue, nextValue)) {
529
+ this.currentValue = nextValue;
530
+ this.notifyListeners();
531
+ }
532
+ });
533
+ }
518
534
  this.listeners.add(listener);
519
535
  return () => {
520
536
  this.listeners.delete(listener);
@@ -522,12 +538,15 @@ var SelectHandleImpl = class {
522
538
  };
523
539
  }
524
540
  notifyListeners() {
525
- for (const listener of this.listeners) listener();
541
+ for (const listener of [...this.listeners]) listener();
542
+ }
543
+ dispose() {
544
+ this.listeners.clear();
545
+ this.cleanup();
526
546
  }
527
547
  cleanup() {
528
548
  this.ctrlUnsub?.();
529
549
  this.ctrlUnsub = null;
530
- this.listeners.clear();
531
550
  }
532
551
  };
533
552
  var ControllerImpl = class {
@@ -576,11 +595,15 @@ var ScopeImpl = class {
576
595
  invalidationScheduled = false;
577
596
  invalidationChain = null;
578
597
  chainPromise = null;
598
+ chainError = null;
579
599
  initialized = false;
600
+ disposed = false;
580
601
  controllers = /* @__PURE__ */ new Map();
581
602
  gcOptions;
582
603
  extensions;
583
604
  tags;
605
+ resolveExts;
606
+ execExts;
584
607
  ready;
585
608
  scheduleInvalidation(atom$1) {
586
609
  const entry = this.cache.get(atom$1);
@@ -593,16 +616,22 @@ var ScopeImpl = class {
593
616
  if (!this.chainPromise) {
594
617
  this.invalidationChain = /* @__PURE__ */ new Set();
595
618
  this.invalidationScheduled = true;
596
- this.chainPromise = new Promise((resolve, reject) => {
597
- queueMicrotask(() => {
598
- this.processInvalidationChain().then(resolve).catch(reject);
619
+ this.chainError = null;
620
+ this.chainPromise = (async () => {
621
+ await new Promise((resolve) => {
622
+ queueMicrotask(resolve);
599
623
  });
600
- });
624
+ try {
625
+ await this.processInvalidationChain();
626
+ } catch (error) {
627
+ if (this.chainError === null) this.chainError = error;
628
+ }
629
+ })();
601
630
  }
602
631
  }
603
632
  async processInvalidationChain() {
604
633
  try {
605
- while (this.invalidationQueue.size > 0) {
634
+ while (this.invalidationQueue.size > 0 && !this.disposed) {
606
635
  const atom$1 = this.invalidationQueue.values().next().value;
607
636
  this.invalidationQueue.delete(atom$1);
608
637
  if (this.invalidationChain.has(atom$1)) {
@@ -623,6 +652,8 @@ var ScopeImpl = class {
623
652
  constructor(options) {
624
653
  this.extensions = options?.extensions ?? [];
625
654
  this.tags = options?.tags ?? [];
655
+ this.resolveExts = this.extensions.filter((e) => e.wrapResolve);
656
+ this.execExts = this.extensions.filter((e) => e.wrapExec);
626
657
  for (const p of options?.presets ?? []) this.presets.set(p.target, p.value);
627
658
  this.gcOptions = {
628
659
  enabled: options?.gc?.enabled ?? true,
@@ -715,21 +746,21 @@ var ScopeImpl = class {
715
746
  const entry = this.cache.get(atom$1);
716
747
  if (!entry) return;
717
748
  const eventListeners = entry.listeners.get(event);
718
- if (eventListeners) for (const listener of eventListeners) listener();
749
+ if (eventListeners?.size) for (const listener of [...eventListeners]) listener();
719
750
  const allListeners = entry.listeners.get("*");
720
- if (allListeners) for (const listener of allListeners) listener();
751
+ if (allListeners?.size) for (const listener of [...allListeners]) listener();
721
752
  }
722
753
  notifyAllListeners(atom$1) {
723
754
  const entry = this.cache.get(atom$1);
724
755
  if (!entry) return;
725
756
  const allListeners = entry.listeners.get("*");
726
- if (allListeners) for (const listener of allListeners) listener();
757
+ if (allListeners?.size) for (const listener of [...allListeners]) listener();
727
758
  }
728
759
  emitStateChange(state, atom$1) {
729
760
  const stateMap = this.stateListeners.get(state);
730
761
  if (stateMap) {
731
762
  const listeners = stateMap.get(atom$1);
732
- if (listeners) for (const listener of listeners) listener();
763
+ if (listeners?.size) for (const listener of [...listeners]) listener();
733
764
  }
734
765
  }
735
766
  on(event, atom$1, listener) {
@@ -755,14 +786,15 @@ var ScopeImpl = class {
755
786
  };
756
787
  }
757
788
  async resolve(atom$1) {
789
+ if (this.disposed) throw new Error("Scope is disposed");
758
790
  if (!this.initialized) await this.ready;
759
791
  const entry = this.cache.get(atom$1);
760
792
  if (entry?.state === "resolved") return entry.value;
761
793
  const pendingPromise = this.pending.get(atom$1);
762
794
  if (pendingPromise) return pendingPromise;
763
795
  if (this.resolving.has(atom$1)) throw new Error("Circular dependency detected");
764
- const presetValue = this.presets.get(atom$1);
765
- if (presetValue !== void 0) {
796
+ if (this.presets.has(atom$1)) {
797
+ const presetValue = this.presets.get(atom$1);
766
798
  if (isAtom(presetValue)) return this.resolve(presetValue);
767
799
  const newEntry = this.getOrCreateEntry(atom$1);
768
800
  newEntry.state = "resolved";
@@ -785,7 +817,9 @@ var ScopeImpl = class {
785
817
  async doResolve(atom$1) {
786
818
  const entry = this.getOrCreateEntry(atom$1);
787
819
  if (!(entry.state === "resolving")) {
788
- for (let i = entry.cleanups.length - 1; i >= 0; i--) await entry.cleanups[i]?.();
820
+ for (let i = entry.cleanups.length - 1; i >= 0; i--) try {
821
+ await entry.cleanups[i]?.();
822
+ } catch {}
789
823
  entry.cleanups = [];
790
824
  entry.state = "resolving";
791
825
  this.emitStateChange("resolving", atom$1);
@@ -805,7 +839,7 @@ var ScopeImpl = class {
805
839
  };
806
840
  const factory = atom$1.factory;
807
841
  const doResolve = async () => {
808
- if (atom$1.deps && Object.keys(atom$1.deps).length > 0) return factory(ctx, resolvedDeps);
842
+ if (atom$1.deps) return factory(ctx, resolvedDeps);
809
843
  else return factory(ctx);
810
844
  };
811
845
  try {
@@ -841,88 +875,103 @@ var ScopeImpl = class {
841
875
  entry.pendingInvalidate = false;
842
876
  this.invalidationChain?.delete(atom$1);
843
877
  this.scheduleInvalidation(atom$1);
844
- }
878
+ } else if (entry.pendingSet && "value" in entry.pendingSet) {
879
+ this.invalidationChain?.delete(atom$1);
880
+ this.scheduleInvalidation(atom$1);
881
+ } else entry.pendingSet = void 0;
845
882
  throw entry.error;
846
883
  }
847
884
  }
848
885
  async applyResolveExtensions(event, doResolve) {
849
886
  let next = doResolve;
850
- for (let i = this.extensions.length - 1; i >= 0; i--) {
851
- const ext = this.extensions[i];
852
- if (ext?.wrapResolve) {
853
- const currentNext = next;
854
- next = ext.wrapResolve.bind(ext, currentNext, event);
855
- }
887
+ for (let i = this.resolveExts.length - 1; i >= 0; i--) {
888
+ const ext = this.resolveExts[i];
889
+ const currentNext = next;
890
+ next = ext.wrapResolve.bind(ext, currentNext, event);
856
891
  }
857
892
  return next();
858
893
  }
859
894
  async resolveDeps(deps, ctx, dependentAtom) {
860
895
  if (!deps) return {};
861
896
  const result = {};
862
- for (const [key, dep] of Object.entries(deps)) if (isAtom(dep)) {
863
- result[key] = await this.resolve(dep);
864
- if (dependentAtom) {
865
- const depEntry = this.getEntry(dep);
866
- if (depEntry) depEntry.dependents.add(dependentAtom);
867
- }
868
- } else if (isControllerDep(dep)) {
869
- if (dep.watch) {
870
- if (!dependentAtom) throw new Error("controller({ watch: true }) is only supported in atom dependencies");
871
- if (!dep.resolve) throw new Error("controller({ watch: true }) requires resolve: true");
872
- }
873
- const ctrl = this.controller(dep.atom);
874
- if (dep.resolve) await ctrl.resolve();
875
- result[key] = ctrl;
876
- if (dependentAtom) {
877
- const depEntry = this.getEntry(dep.atom);
878
- if (depEntry) depEntry.dependents.add(dependentAtom);
879
- }
880
- if (dep.watch) {
881
- const eq = dep.eq ?? Object.is;
882
- let prev = ctrl.get();
883
- const unsub = this.on("resolved", dep.atom, () => {
884
- const next = ctrl.get();
885
- if (!eq(prev, next)) {
886
- prev = next;
887
- this.scheduleInvalidation(dependentAtom);
897
+ const parallel = [];
898
+ const deferredResources = [];
899
+ for (const key in deps) {
900
+ const dep = deps[key];
901
+ if (isAtom(dep)) parallel.push(this.resolve(dep).then((value) => {
902
+ result[key] = value;
903
+ if (dependentAtom) {
904
+ const depEntry = this.getEntry(dep);
905
+ if (depEntry) depEntry.dependents.add(dependentAtom);
906
+ }
907
+ }));
908
+ else if (isControllerDep(dep)) {
909
+ if (dep.watch) {
910
+ if (!dependentAtom) throw new Error("controller({ watch: true }) is only supported in atom dependencies");
911
+ if (!dep.resolve) throw new Error("controller({ watch: true }) requires resolve: true");
912
+ }
913
+ const ctrl = this.controller(dep.atom);
914
+ if (dep.resolve) parallel.push(ctrl.resolve().then(() => {
915
+ result[key] = ctrl;
916
+ if (dependentAtom) {
917
+ const depEntry = this.getEntry(dep.atom);
918
+ if (depEntry) depEntry.dependents.add(dependentAtom);
919
+ }
920
+ if (dep.watch) {
921
+ const eq = dep.eq ?? Object.is;
922
+ let prev = ctrl.get();
923
+ const unsub = this.on("resolved", dep.atom, () => {
924
+ const next = ctrl.get();
925
+ if (!eq(prev, next)) {
926
+ prev = next;
927
+ this.scheduleInvalidation(dependentAtom);
928
+ }
929
+ });
930
+ const depEntry = this.getEntry(dependentAtom);
931
+ if (depEntry) depEntry.cleanups.push(unsub);
932
+ else unsub();
933
+ }
934
+ }));
935
+ else {
936
+ result[key] = ctrl;
937
+ if (dependentAtom) {
938
+ const depEntry = this.getEntry(dep.atom);
939
+ if (depEntry) depEntry.dependents.add(dependentAtom);
888
940
  }
889
- });
890
- const depEntry = this.getEntry(dependentAtom);
891
- if (depEntry) depEntry.cleanups.push(unsub);
892
- else unsub();
893
- }
894
- } else if (tagExecutorSymbol in dep) {
895
- const tagExecutor = dep;
896
- switch (tagExecutor.mode) {
897
- case "required": {
898
- const value = ctx ? ctx.data.seekTag(tagExecutor.tag) : tagExecutor.tag.find(this.tags);
899
- if (value !== void 0) result[key] = value;
900
- else if (tagExecutor.tag.hasDefault) result[key] = tagExecutor.tag.defaultValue;
901
- else throw new Error(`Tag "${tagExecutor.tag.label}" not found`);
902
- break;
903
941
  }
904
- case "optional":
905
- result[key] = (ctx ? ctx.data.seekTag(tagExecutor.tag) : tagExecutor.tag.find(this.tags)) ?? tagExecutor.tag.defaultValue;
906
- break;
907
- case "all":
908
- result[key] = ctx ? this.collectFromHierarchy(ctx, tagExecutor.tag) : tagExecutor.tag.collect(this.tags);
909
- break;
910
- }
911
- } else if (isResource(dep)) {
942
+ } else if (tagExecutorSymbol in dep) {
943
+ const tagExecutor = dep;
944
+ switch (tagExecutor.mode) {
945
+ case "required": {
946
+ const value = ctx ? ctx.data.seekTag(tagExecutor.tag) : tagExecutor.tag.find(this.tags);
947
+ if (value !== void 0) result[key] = value;
948
+ else if (tagExecutor.tag.hasDefault) result[key] = tagExecutor.tag.defaultValue;
949
+ else throw new Error(`Tag "${tagExecutor.tag.label}" not found`);
950
+ break;
951
+ }
952
+ case "optional":
953
+ result[key] = (ctx ? ctx.data.seekTag(tagExecutor.tag) : tagExecutor.tag.find(this.tags)) ?? tagExecutor.tag.defaultValue;
954
+ break;
955
+ case "all":
956
+ result[key] = ctx ? this.collectFromHierarchy(ctx, tagExecutor.tag) : tagExecutor.tag.collect(this.tags);
957
+ break;
958
+ }
959
+ } else if (isResource(dep)) deferredResources.push([key, dep]);
960
+ }
961
+ if (parallel.length === 1) await parallel[0];
962
+ else if (parallel.length > 1) await Promise.all(parallel);
963
+ for (const [key, resource$1] of deferredResources) {
912
964
  if (!ctx) throw new Error("Resource deps require an ExecutionContext");
913
- const resource$1 = dep;
914
965
  const resourceKey = getResourceKey(resource$1);
915
966
  const storeCtx = ctx.parent ?? ctx;
916
967
  if (storeCtx.data.has(resourceKey)) {
917
968
  result[key] = storeCtx.data.get(resourceKey);
918
969
  continue;
919
970
  }
920
- const existingSeek = ctx.data.seek(resourceKey);
921
- if (existingSeek !== void 0 || ctx.data.has(resourceKey)) {
922
- result[key] = existingSeek;
971
+ if (ctx.data.seekHas(resourceKey)) {
972
+ result[key] = ctx.data.seek(resourceKey);
923
973
  continue;
924
974
  }
925
- if (resolvingResources.has(resourceKey)) throw new Error(`Circular resource dependency detected: ${resource$1.name ?? "anonymous"}`);
926
975
  let flights = inflightResources.get(storeCtx.data);
927
976
  if (!flights) {
928
977
  flights = /* @__PURE__ */ new Map();
@@ -933,8 +982,14 @@ var ScopeImpl = class {
933
982
  result[key] = await inflight;
934
983
  continue;
935
984
  }
985
+ let localResolvingResources = resolvingResourcesMap.get(storeCtx.data);
986
+ if (!localResolvingResources) {
987
+ localResolvingResources = /* @__PURE__ */ new Set();
988
+ resolvingResourcesMap.set(storeCtx.data, localResolvingResources);
989
+ }
990
+ if (localResolvingResources.has(resourceKey)) throw new Error(`Circular resource dependency detected: ${resource$1.name ?? "anonymous"}`);
936
991
  const resolve = async () => {
937
- resolvingResources.add(resourceKey);
992
+ localResolvingResources.add(resourceKey);
938
993
  try {
939
994
  const resourceDeps = await this.resolveDeps(resource$1.deps, ctx);
940
995
  const event = {
@@ -944,14 +999,14 @@ var ScopeImpl = class {
944
999
  };
945
1000
  const doResolve = async () => {
946
1001
  const factory = resource$1.factory;
947
- if (resource$1.deps && Object.keys(resource$1.deps).length > 0) return factory(storeCtx, resourceDeps);
1002
+ if (resource$1.deps) return factory(storeCtx, resourceDeps);
948
1003
  return factory(storeCtx);
949
1004
  };
950
1005
  const value = await this.applyResolveExtensions(event, doResolve);
951
1006
  storeCtx.data.set(resourceKey, value);
952
1007
  return value;
953
1008
  } finally {
954
- resolvingResources.delete(resourceKey);
1009
+ localResolvingResources.delete(resourceKey);
955
1010
  }
956
1011
  };
957
1012
  const promise = resolve();
@@ -975,6 +1030,7 @@ var ScopeImpl = class {
975
1030
  return results;
976
1031
  }
977
1032
  controller(atom$1, options) {
1033
+ if (this.disposed) throw new Error("Scope is disposed");
978
1034
  let ctrl = this.controllers.get(atom$1);
979
1035
  if (!ctrl) {
980
1036
  ctrl = new ControllerImpl(atom$1, this);
@@ -984,7 +1040,7 @@ var ScopeImpl = class {
984
1040
  return ctrl;
985
1041
  }
986
1042
  select(atom$1, selector, options) {
987
- return new SelectHandleImpl(this.controller(atom$1), selector, options?.eq ?? ((a, b) => a === b));
1043
+ return new SelectHandleImpl(this.controller(atom$1), selector, options?.eq ?? Object.is);
988
1044
  }
989
1045
  getFlowPreset(flow$1) {
990
1046
  return this.presets.get(flow$1);
@@ -1028,10 +1084,27 @@ var ScopeImpl = class {
1028
1084
  const previousValue = entry.value;
1029
1085
  const pendingSet = entry.pendingSet;
1030
1086
  entry.pendingSet = void 0;
1031
- for (let i = entry.cleanups.length - 1; i >= 0; i--) {
1032
- const cleanup = entry.cleanups[i];
1033
- if (cleanup) await cleanup();
1087
+ if (pendingSet) {
1088
+ entry.state = "resolving";
1089
+ entry.value = previousValue;
1090
+ entry.error = void 0;
1091
+ entry.pendingInvalidate = false;
1092
+ this.pending.delete(atom$1);
1093
+ this.resolving.delete(atom$1);
1094
+ this.emitStateChange("resolving", atom$1);
1095
+ this.notifyListeners(atom$1, "resolving");
1096
+ if ("value" in pendingSet) entry.value = pendingSet.value;
1097
+ else entry.value = pendingSet.fn(previousValue);
1098
+ entry.state = "resolved";
1099
+ entry.hasValue = true;
1100
+ this.emitStateChange("resolved", atom$1);
1101
+ this.notifyListeners(atom$1, "resolved");
1102
+ this.invalidationChain?.delete(atom$1);
1103
+ return;
1034
1104
  }
1105
+ for (let i = entry.cleanups.length - 1; i >= 0; i--) try {
1106
+ await entry.cleanups[i]?.();
1107
+ } catch {}
1035
1108
  entry.cleanups = [];
1036
1109
  entry.state = "resolving";
1037
1110
  entry.value = previousValue;
@@ -1041,16 +1114,11 @@ var ScopeImpl = class {
1041
1114
  this.resolving.delete(atom$1);
1042
1115
  this.emitStateChange("resolving", atom$1);
1043
1116
  this.notifyListeners(atom$1, "resolving");
1044
- if (pendingSet) {
1045
- if ("value" in pendingSet) entry.value = pendingSet.value;
1046
- else entry.value = pendingSet.fn(previousValue);
1047
- entry.state = "resolved";
1048
- entry.hasValue = true;
1049
- this.emitStateChange("resolved", atom$1);
1050
- this.notifyListeners(atom$1, "resolved");
1051
- return;
1117
+ try {
1118
+ await this.resolve(atom$1);
1119
+ } catch (e) {
1120
+ if (!entry.pendingSet && !entry.pendingInvalidate) throw e;
1052
1121
  }
1053
- await this.resolve(atom$1);
1054
1122
  }
1055
1123
  async release(atom$1) {
1056
1124
  const entry = this.cache.get(atom$1);
@@ -1059,14 +1127,33 @@ var ScopeImpl = class {
1059
1127
  clearTimeout(entry.gcScheduled);
1060
1128
  entry.gcScheduled = null;
1061
1129
  }
1062
- for (let i = entry.cleanups.length - 1; i >= 0; i--) {
1063
- const cleanup = entry.cleanups[i];
1064
- if (cleanup) await cleanup();
1130
+ for (let i = entry.cleanups.length - 1; i >= 0; i--) try {
1131
+ await entry.cleanups[i]?.();
1132
+ } catch {}
1133
+ if (atom$1.deps) for (const dep of Object.values(atom$1.deps)) {
1134
+ const depAtom = isAtom(dep) ? dep : isControllerDep(dep) ? dep.atom : null;
1135
+ if (!depAtom) continue;
1136
+ const depEntry = this.cache.get(depAtom);
1137
+ if (depEntry) {
1138
+ depEntry.dependents.delete(atom$1);
1139
+ this.maybeScheduleGC(depAtom);
1140
+ }
1065
1141
  }
1066
1142
  this.cache.delete(atom$1);
1067
1143
  this.controllers.delete(atom$1);
1144
+ for (const [state, stateMap] of this.stateListeners) {
1145
+ stateMap.delete(atom$1);
1146
+ if (stateMap.size === 0) this.stateListeners.delete(state);
1147
+ }
1068
1148
  }
1069
1149
  async dispose() {
1150
+ if (this.chainPromise) try {
1151
+ await this.chainPromise;
1152
+ } catch {}
1153
+ this.disposed = true;
1154
+ this.invalidationQueue.clear();
1155
+ this.invalidationChain = null;
1156
+ this.chainPromise = null;
1070
1157
  for (const ext of this.extensions) if (ext.dispose) await ext.dispose(this);
1071
1158
  for (const entry of this.cache.values()) if (entry.gcScheduled) {
1072
1159
  clearTimeout(entry.gcScheduled);
@@ -1077,8 +1164,14 @@ var ScopeImpl = class {
1077
1164
  }
1078
1165
  async flush() {
1079
1166
  if (this.chainPromise) await this.chainPromise;
1167
+ if (this.chainError !== null) {
1168
+ const error = this.chainError;
1169
+ this.chainError = null;
1170
+ throw error;
1171
+ }
1080
1172
  }
1081
1173
  createContext(options) {
1174
+ if (this.disposed) throw new Error("Scope is disposed");
1082
1175
  const ctx = new ExecutionContextImpl(this, options);
1083
1176
  for (const tagged of options?.tags ?? []) ctx.data.set(tagged.key, tagged.value);
1084
1177
  for (const tagged of this.tags) if (!ctx.data.has(tagged.key)) ctx.data.set(tagged.key, tagged.value);
@@ -1172,7 +1265,7 @@ var ExecutionContextImpl = class ExecutionContextImpl {
1172
1265
  const resolvedDeps = await this.scope.resolveDeps(flow$1.deps, this);
1173
1266
  const factory = flow$1.factory;
1174
1267
  const doExec = async () => {
1175
- if (flow$1.deps && Object.keys(flow$1.deps).length > 0) return factory(this, resolvedDeps);
1268
+ if (flow$1.deps) return factory(this, resolvedDeps);
1176
1269
  else return factory(this);
1177
1270
  };
1178
1271
  return this.applyExecExtensions(flow$1, doExec);
@@ -1188,12 +1281,10 @@ var ExecutionContextImpl = class ExecutionContextImpl {
1188
1281
  }
1189
1282
  async applyExecExtensions(target, doExec) {
1190
1283
  let next = doExec;
1191
- for (let i = this.scope.extensions.length - 1; i >= 0; i--) {
1192
- const ext = this.scope.extensions[i];
1193
- if (ext?.wrapExec) {
1194
- const currentNext = next;
1195
- next = ext.wrapExec.bind(ext, currentNext, target, this);
1196
- }
1284
+ for (let i = this.scope.execExts.length - 1; i >= 0; i--) {
1285
+ const ext = this.scope.execExts[i];
1286
+ const currentNext = next;
1287
+ next = ext.wrapExec.bind(ext, currentNext, target, this);
1197
1288
  }
1198
1289
  return next();
1199
1290
  }
@@ -1203,10 +1294,9 @@ var ExecutionContextImpl = class ExecutionContextImpl {
1203
1294
  async close(result = { ok: true }) {
1204
1295
  if (this.closed) return;
1205
1296
  this.closed = true;
1206
- for (let i = this.cleanups.length - 1; i >= 0; i--) {
1207
- const cleanup = this.cleanups[i];
1208
- if (cleanup) await cleanup(result);
1209
- }
1297
+ for (let i = this.cleanups.length - 1; i >= 0; i--) try {
1298
+ await this.cleanups[i]?.(result);
1299
+ } catch {}
1210
1300
  }
1211
1301
  };
1212
1302
  /**