doxum 0.1.33 → 0.1.35

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.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_transform = require("./transform-CSPGdBe5.cjs");
2
+ const require_transform = require("./transform-D45KWMzj.cjs");
3
3
  const require_record = require("./record-ChYUi8PP.cjs");
4
4
  const require_driver = require("./driver-CN3dGxQI.cjs");
5
5
  //#region core/src/schema/model.ts
@@ -2775,6 +2775,12 @@ const isExternalSource = (source) => {
2775
2775
  return (candidate.kind === "value" || candidate.kind === "collection") && typeof candidate.current === "function" && typeof candidate.revision === "function" && typeof candidate.subscribe === "function";
2776
2776
  };
2777
2777
  //#endregion
2778
+ //#region core/src/projection/keyed/entries.ts
2779
+ /** Shared entry boundary; membership and duplicate policy belong to each operation. */
2780
+ function assertKeyedEntry(entry, name) {
2781
+ if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[0] !== "string") throw new TypeError(`${name} entries must be [string key, value] tuples.`);
2782
+ }
2783
+ //#endregion
2778
2784
  //#region core/src/projection/keyed/flat-map.ts
2779
2785
  function createKeyedFlatMap(source, dependenciesOrSelect, selectOrEquality, maybeEquality) {
2780
2786
  const name = "derive.keyed.flatMap";
@@ -2821,7 +2827,7 @@ function createKeyedFlatMap(source, dependenciesOrSelect, selectOrEquality, mayb
2821
2827
  if (!Array.isArray(entries)) throw new TypeError(`${name} selector must return an array of entries.`);
2822
2828
  const keys = [];
2823
2829
  for (const entry of entries) {
2824
- if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[0] !== "string") throw new TypeError(`${name} entries must be [string key, value] tuples.`);
2830
+ assertKeyedEntry(entry, name);
2825
2831
  const [key, child] = entry;
2826
2832
  const owner = ownerByOutput.get(key);
2827
2833
  if (proposals.has(key) || owner !== void 0 && !replaced.has(owner)) throw new TypeError(`${name} duplicate key ${JSON.stringify(key)}.`);
@@ -2908,6 +2914,25 @@ const assertCollectionSources = (sources, expected) => {
2908
2914
  if (sources.length !== expected) throw new Error("derive.keyed.merge resolved an invalid dependency count.");
2909
2915
  for (const source of sources) if (source.kind !== "collection") throw new Error("derive.keyed.merge requires collection inputs.");
2910
2916
  };
2917
+ /** Complete ordered result reconciliation, without retaining a second member/value cache. */
2918
+ const stageKeyedSnapshot = (values, output, keyOf, valueOf, name) => {
2919
+ const seen = /* @__PURE__ */ new Set();
2920
+ const order = new Array(values.length);
2921
+ const previous = output.previous.ids();
2922
+ require_transform.profile.collectionView.idsScanned(values.length + previous.length);
2923
+ for (let index = 0; index < values.length; index++) {
2924
+ const value = values[index];
2925
+ const key = keyOf(value);
2926
+ require_transform.assertSynchronous(key);
2927
+ if (typeof key !== "string") throw new TypeError(`${name} key selector must return a string.`);
2928
+ if (seen.has(key)) throw new TypeError(`${name} duplicate key ${JSON.stringify(key)}.`);
2929
+ seen.add(key);
2930
+ order[index] = key;
2931
+ output.output.set(key, valueOf(value));
2932
+ }
2933
+ for (const key of previous) if (!seen.has(key)) output.output.remove(key);
2934
+ output.output.order(order);
2935
+ };
2911
2936
  function createKeyedFrom(source, keyOf, equality) {
2912
2937
  if (typeof keyOf !== "function") throw new TypeError("derive.keyed.from requires a key selector.");
2913
2938
  const outputEquality = assertEquality(equality, "derive.keyed.from");
@@ -2937,25 +2962,38 @@ function createKeyedFrom(source, keyOf, equality) {
2937
2962
  values = scalar.value;
2938
2963
  }
2939
2964
  if (!values) throw new Error("derive.keyed.from has no source values.");
2940
- const seen = /* @__PURE__ */ new Set();
2941
- const order = new Array(values.length);
2942
- for (let index = 0; index < values.length; index++) {
2943
- const value = values[index];
2944
- const key = keyOf(value);
2945
- require_transform.assertSynchronous(key);
2946
- if (typeof key !== "string") throw new TypeError("derive.keyed.from key selector must return a string.");
2947
- if (seen.has(key)) throw new TypeError(`derive.keyed.from duplicate key ${JSON.stringify(key)}.`);
2948
- seen.add(key);
2949
- order[index] = key;
2950
- output.output.set(key, value);
2951
- }
2952
- for (const previousKey of output.previous.ids()) if (!seen.has(previousKey)) output.output.remove(previousKey);
2953
- output.output.order(order);
2965
+ stageKeyedSnapshot(values, output, keyOf, (value) => value, "derive.keyed.from");
2954
2966
  } }),
2955
2967
  name: "derive.keyed.from"
2956
2968
  });
2957
2969
  return projection;
2958
2970
  }
2971
+ function createKeyedFromEntries(dependencies, compute, equality) {
2972
+ const name = "derive.keyed.fromEntries";
2973
+ const compiled = require_transform.compileProjectionDependencies(dependencies, name);
2974
+ if (typeof compute !== "function") throw new TypeError(`${name} requires a compute callback.`);
2975
+ const outputEquality = assertEquality(equality, name);
2976
+ const [projection] = require_transform.defineProcessor({
2977
+ dependencies: compiled.projections,
2978
+ outputs: [{
2979
+ kind: "collection",
2980
+ equality: outputEquality
2981
+ }],
2982
+ name,
2983
+ create: () => ({ evaluate: (evaluation) => {
2984
+ const output = evaluation.outputs[0];
2985
+ if (output.kind !== "collection") throw new Error(`${name} requires a collection output.`);
2986
+ const entries = compute(require_transform.snapshotProjectionValues(compiled.names, evaluation.sources));
2987
+ require_transform.assertSynchronous(entries);
2988
+ if (!Array.isArray(entries)) throw new TypeError(`${name} compute must return an array of entries.`);
2989
+ stageKeyedSnapshot(entries, output, (entry) => {
2990
+ assertKeyedEntry(entry, name);
2991
+ return entry[0];
2992
+ }, (entry) => entry[1], name);
2993
+ } })
2994
+ });
2995
+ return projection;
2996
+ }
2959
2997
  function createKeyedMerge(sources, options) {
2960
2998
  if (!Array.isArray(sources)) throw new TypeError("derive.keyed.merge sources must be an array of keyed projections.");
2961
2999
  const capturedSources = require_transform.snapshotArray(sources);
@@ -3584,6 +3622,7 @@ const keyedDerive = Object.assign(createKeyedDerive, {
3584
3622
  entries: createKeyedEntries,
3585
3623
  get: createKeyedGet,
3586
3624
  from: createKeyedFrom,
3625
+ fromEntries: createKeyedFromEntries,
3587
3626
  merge: createKeyedMerge,
3588
3627
  groupBy: createKeyedGroupBy,
3589
3628
  flatMap: createKeyedFlatMap,
@@ -3607,9 +3646,7 @@ function createValueDerive(dependencies, compute, equality = Object.is) {
3607
3646
  create: () => ({ evaluate: (evaluation) => {
3608
3647
  const output = evaluation.outputs[0];
3609
3648
  if (output.kind !== "value") throw new Error("derive requires a value output.");
3610
- const values = Object.create(null);
3611
- for (let index = 0; index < names.length; index++) values[names[index]] = require_transform.snapshotDependencyValue(evaluation.sources[index]);
3612
- const next = compute(Object.freeze(values));
3649
+ const next = compute(require_transform.snapshotProjectionValues(names, evaluation.sources));
3613
3650
  require_transform.assertSynchronous(next);
3614
3651
  output.output.set(next);
3615
3652
  } })
@@ -3618,6 +3655,104 @@ function createValueDerive(dependencies, compute, equality = Object.is) {
3618
3655
  }
3619
3656
  const derive = Object.assign(createValueDerive, { keyed: keyedDerive });
3620
3657
  //#endregion
3658
+ //#region core/src/projection/collection/changes.ts
3659
+ /** Net transitions for one consumer's unconsumed interval; bounded by touched keys. */
3660
+ const createCollectionChanges = () => {
3661
+ let first;
3662
+ let beforeOrder = [];
3663
+ let afterOrder = [];
3664
+ let cached;
3665
+ let valid = false;
3666
+ let transitions;
3667
+ const merge = (change) => {
3668
+ const write = (key, before, after) => {
3669
+ const previous = transitions.get(key);
3670
+ const initial = previous?.before ?? before;
3671
+ if (initial.present === after.present && (!initial.present || after.present && Object.is(initial.value, after.value))) transitions.delete(key);
3672
+ else if (previous) previous.after = after;
3673
+ else transitions.set(key, {
3674
+ before,
3675
+ after
3676
+ });
3677
+ };
3678
+ for (const entry of change.added) write(entry.key, { present: false }, {
3679
+ present: true,
3680
+ value: entry.after
3681
+ });
3682
+ for (const entry of change.updated) write(entry.key, {
3683
+ present: true,
3684
+ value: entry.before
3685
+ }, {
3686
+ present: true,
3687
+ value: entry.after
3688
+ });
3689
+ for (const entry of change.removed) write(entry.key, {
3690
+ present: true,
3691
+ value: entry.before
3692
+ }, { present: false });
3693
+ };
3694
+ return {
3695
+ add(change, before, after) {
3696
+ valid = false;
3697
+ afterOrder = after;
3698
+ if (!first) {
3699
+ first = change;
3700
+ beforeOrder = before;
3701
+ return;
3702
+ }
3703
+ if (first.kind === "reset") return;
3704
+ if (change.kind === "reset") {
3705
+ first = change;
3706
+ transitions = void 0;
3707
+ return;
3708
+ }
3709
+ if (!transitions) {
3710
+ transitions = /* @__PURE__ */ new Map();
3711
+ merge(first);
3712
+ }
3713
+ merge(change);
3714
+ },
3715
+ current() {
3716
+ if (!transitions) return first;
3717
+ if (valid) return cached;
3718
+ const added = [];
3719
+ const updated = [];
3720
+ const removed = [];
3721
+ for (const [key, { before, after }] of transitions) if (!before.present) {
3722
+ if (after.present) added.push({
3723
+ key,
3724
+ after: after.value
3725
+ });
3726
+ } else if (!after.present) removed.push({
3727
+ key,
3728
+ before: before.value
3729
+ });
3730
+ else if (!Object.is(before.value, after.value)) updated.push({
3731
+ key,
3732
+ before: before.value,
3733
+ after: after.value
3734
+ });
3735
+ cached = require_transform.createCollectionChange({
3736
+ added,
3737
+ updated,
3738
+ removed,
3739
+ beforeOrder,
3740
+ afterOrder
3741
+ });
3742
+ valid = true;
3743
+ return cached;
3744
+ },
3745
+ reset: () => first?.kind === "reset",
3746
+ clear() {
3747
+ first = void 0;
3748
+ cached = void 0;
3749
+ valid = false;
3750
+ transitions = void 0;
3751
+ beforeOrder = afterOrder = [];
3752
+ }
3753
+ };
3754
+ };
3755
+ //#endregion
3621
3756
  //#region core/src/projection/collection/index.ts
3622
3757
  const height = (node) => node?.height ?? 0;
3623
3758
  const node = (key, value, left, right) => {
@@ -3712,7 +3847,7 @@ var PersistentKeyedIndex = class PersistentKeyedIndex {
3712
3847
  const createCollectionState = (initial) => {
3713
3848
  const values = new Map(initial);
3714
3849
  let ids = Object.freeze([...values.keys()]);
3715
- let index = values.size ? PersistentKeyedIndex.from(values) : PersistentKeyedIndex.empty();
3850
+ let index;
3716
3851
  return {
3717
3852
  get: (key) => values.get(key),
3718
3853
  has: (key) => values.has(key),
@@ -3720,7 +3855,7 @@ const createCollectionState = (initial) => {
3720
3855
  size: () => values.size,
3721
3856
  ids: () => ids,
3722
3857
  read: (check) => {
3723
- const snapshotIndex = index;
3858
+ const snapshotIndex = index ??= PersistentKeyedIndex.from(values);
3724
3859
  const snapshotIds = ids;
3725
3860
  return Object.freeze({
3726
3861
  get: (key) => {
@@ -3741,9 +3876,9 @@ const createCollectionState = (initial) => {
3741
3876
  if (reset) {
3742
3877
  values.clear();
3743
3878
  for (const [key, entry] of staged) if (entry.present) values.set(key, entry.value);
3744
- index = PersistentKeyedIndex.from(values);
3879
+ if (index) index = PersistentKeyedIndex.from(values);
3745
3880
  } else for (const [key, entry] of staged) {
3746
- index = entry.present ? index.set(key, entry.value) : index.remove(key);
3881
+ if (index) index = entry.present ? index.set(key, entry.value) : index.remove(key);
3747
3882
  if (entry.present) values.set(key, entry.value);
3748
3883
  else values.delete(key);
3749
3884
  }
@@ -3752,17 +3887,17 @@ const createCollectionState = (initial) => {
3752
3887
  release: () => {
3753
3888
  values.clear();
3754
3889
  ids = Object.freeze([]);
3755
- index = PersistentKeyedIndex.empty();
3890
+ index = void 0;
3756
3891
  }
3757
3892
  };
3758
3893
  };
3759
3894
  //#endregion
3760
3895
  //#region core/src/projection/output/collection.ts
3761
- /** Owns staged keyed intent, exact transitions and published collection state. */
3896
+ /** Owns staged keyed intent, exact transitions and current collection state. */
3762
3897
  const createCollectionOutput = (binding) => {
3763
- const published = createCollectionState();
3898
+ const currentState = createCollectionState();
3764
3899
  const staged = /* @__PURE__ */ new Map();
3765
- let nextIds = published.ids();
3900
+ let nextIds = currentState.ids();
3766
3901
  let change;
3767
3902
  let initialized = false;
3768
3903
  let reset = false;
@@ -3770,23 +3905,26 @@ const createCollectionOutput = (binding) => {
3770
3905
  let explicitOrder;
3771
3906
  let cleared = false;
3772
3907
  const listeners = /* @__PURE__ */ new Set();
3773
- const consumers = /* @__PURE__ */ new Set();
3774
- const hasNext = (key) => staged.has(key) ? staged.get(key).present : !cleared && published.has(key);
3908
+ const consumers = /* @__PURE__ */ new Map();
3909
+ const notifications = createCollectionChanges();
3910
+ const observers = /* @__PURE__ */ new Set();
3911
+ let baseline;
3912
+ const hasNext = (key) => staged.has(key) ? staged.get(key).present : !cleared && currentState.has(key);
3775
3913
  const getNext = (key) => {
3776
3914
  const entry = staged.get(key);
3777
- return entry ? entry.present ? entry.value : void 0 : cleared ? void 0 : published.get(key);
3915
+ return entry ? entry.present ? entry.value : void 0 : cleared ? void 0 : currentState.get(key);
3778
3916
  };
3779
3917
  const deriveIds = () => {
3780
3918
  const result = [];
3781
3919
  if (!cleared) {
3782
- for (const key of published.ids()) if (hasNext(key)) result.push(key);
3920
+ for (const key of currentState.ids()) if (hasNext(key)) result.push(key);
3783
3921
  }
3784
- for (const [key, entry] of staged) if (entry.present && (cleared || !published.has(key))) result.push(key);
3922
+ for (const [key, entry] of staged) if (entry.present && (cleared || !currentState.has(key))) result.push(key);
3785
3923
  return result;
3786
3924
  };
3787
3925
  const begin = (active, initialize) => {
3788
3926
  staged.clear();
3789
- nextIds = published.ids();
3927
+ nextIds = currentState.ids();
3790
3928
  change = void 0;
3791
3929
  explicitOrder = void 0;
3792
3930
  cleared = initialize;
@@ -3794,15 +3932,15 @@ const createCollectionOutput = (binding) => {
3794
3932
  const read = (next) => ({
3795
3933
  get: (key) => {
3796
3934
  require_transform.assertScope(active);
3797
- return next ? getNext(key) : published.get(key);
3935
+ return next ? getNext(key) : currentState.get(key);
3798
3936
  },
3799
3937
  has: (key) => {
3800
3938
  require_transform.assertScope(active);
3801
- return next ? hasNext(key) : published.has(key);
3939
+ return next ? hasNext(key) : currentState.has(key);
3802
3940
  },
3803
3941
  ids: () => {
3804
3942
  require_transform.assertScope(active);
3805
- if (!next) return published.ids();
3943
+ if (!next) return currentState.ids();
3806
3944
  if (explicitOrder) return explicitOrder;
3807
3945
  return Object.freeze(deriveIds());
3808
3946
  }
@@ -3832,15 +3970,28 @@ const createCollectionOutput = (binding) => {
3832
3970
  };
3833
3971
  const seal = (nextReset, isEqual) => {
3834
3972
  if (cleared) {
3835
- for (const key of published.keys()) if (!staged.has(key)) staged.set(key, { present: false });
3973
+ for (const key of currentState.keys()) if (!staged.has(key)) staged.set(key, { present: false });
3836
3974
  }
3837
3975
  require_transform.profile.projection("touchedKeys", staged.size);
3838
3976
  const addedEntries = [];
3839
3977
  const updatedEntries = [];
3840
3978
  const removedEntries = [];
3841
- for (const [key, entry] of staged) {
3842
- const existed = published.has(key);
3979
+ for (const [key, original] of staged) {
3980
+ let entry = original;
3981
+ const existed = currentState.has(key);
3843
3982
  if (entry.present) {
3983
+ if (baseline?.has(key) && (!existed || !Object.is(currentState.get(key), baseline.get(key)))) {
3984
+ const before = baseline.get(key);
3985
+ const equivalent = isEqual(before, entry.value);
3986
+ require_transform.assertSynchronous(equivalent);
3987
+ if (equivalent) {
3988
+ entry = {
3989
+ present: true,
3990
+ value: before
3991
+ };
3992
+ staged.set(key, entry);
3993
+ }
3994
+ }
3844
3995
  if (!existed) {
3845
3996
  addedEntries.push({
3846
3997
  key,
@@ -3848,7 +3999,7 @@ const createCollectionOutput = (binding) => {
3848
3999
  });
3849
4000
  continue;
3850
4001
  }
3851
- const before = published.get(key);
4002
+ const before = currentState.get(key);
3852
4003
  const equal = isEqual(before, entry.value);
3853
4004
  require_transform.assertSynchronous(equal);
3854
4005
  if (!equal) updatedEntries.push({
@@ -3865,13 +4016,13 @@ const createCollectionOutput = (binding) => {
3865
4016
  }
3866
4017
  if (existed) removedEntries.push({
3867
4018
  key,
3868
- before: published.get(key)
4019
+ before: currentState.get(key)
3869
4020
  });
3870
4021
  else staged.delete(key);
3871
4022
  }
3872
- const ids = published.ids();
4023
+ const ids = currentState.ids();
3873
4024
  if (explicitOrder) {
3874
- const expectedLength = published.size() + addedEntries.length - removedEntries.length;
4025
+ const expectedLength = currentState.size() + addedEntries.length - removedEntries.length;
3875
4026
  const seen = /* @__PURE__ */ new Set();
3876
4027
  for (const key of explicitOrder) {
3877
4028
  if (seen.has(key) || !hasNext(key)) throw new TypeError("Projection order must contain every key exactly once.");
@@ -3880,7 +4031,7 @@ const createCollectionOutput = (binding) => {
3880
4031
  if (seen.size !== expectedLength) throw new TypeError("Projection order must contain every key exactly once.");
3881
4032
  nextIds = require_transform.sameArray(ids, explicitOrder) ? ids : explicitOrder;
3882
4033
  } else if (addedEntries.length || removedEntries.length) {
3883
- const order = new Array(published.size() + addedEntries.length - removedEntries.length);
4034
+ const order = new Array(currentState.size() + addedEntries.length - removedEntries.length);
3884
4035
  let index = 0;
3885
4036
  for (const key of ids) if (hasNext(key)) order[index++] = key;
3886
4037
  for (const entry of addedEntries) order[index++] = entry.key;
@@ -3897,7 +4048,7 @@ const createCollectionOutput = (binding) => {
3897
4048
  reset = nextReset;
3898
4049
  return change !== void 0;
3899
4050
  };
3900
- const context = (active, cause) => Object.freeze({
4051
+ const context = (active, cause, consumer) => Object.freeze({
3901
4052
  kind: "collection",
3902
4053
  read: {
3903
4054
  get: (key) => {
@@ -3913,9 +4064,9 @@ const createCollectionOutput = (binding) => {
3913
4064
  return nextIds;
3914
4065
  }
3915
4066
  },
3916
- change,
4067
+ change: consumer ? consumers.get(consumer)?.current() : change,
3917
4068
  revision,
3918
- reset,
4069
+ reset: consumer ? consumers.get(consumer)?.reset() ?? false : reset,
3919
4070
  cause
3920
4071
  });
3921
4072
  return {
@@ -3925,35 +4076,59 @@ const createCollectionOutput = (binding) => {
3925
4076
  },
3926
4077
  begin,
3927
4078
  seal,
3928
- context: (active) => context(active, binding.cause()),
3929
- current: () => published.read(binding.check),
4079
+ context: (active, consumer) => context(active, binding.cause(), consumer),
4080
+ acknowledge: (consumer) => consumers.get(consumer)?.clear(),
4081
+ pending: (consumer) => consumers.get(consumer)?.current() !== void 0,
4082
+ baseline: () => baseline ?? currentState.read(binding.check),
4083
+ current: () => currentState.read(binding.check),
3930
4084
  revision: () => revision,
3931
- reset: () => reset,
4085
+ reset: (consumer) => consumer ? consumers.get(consumer)?.reset() ?? false : reset,
3932
4086
  publish: () => {
3933
- if (change) published.install(staged, nextIds, change.kind === "reset");
3934
- if (change && initialized) revision++;
4087
+ if (change) {
4088
+ if (initialized) {
4089
+ baseline ??= currentState.read(() => void 0);
4090
+ notifications.add(change, currentState.ids(), nextIds);
4091
+ for (const pending of consumers.values()) pending.add(change, currentState.ids(), nextIds);
4092
+ revision++;
4093
+ }
4094
+ currentState.install(staged, nextIds, change.kind === "reset");
4095
+ }
3935
4096
  initialized = true;
3936
4097
  },
3937
- emit: (call) => {
3938
- Array.from(listeners).forEach((listener) => call(listener, change));
4098
+ emit: (call, force) => {
4099
+ const net = notifications.current();
4100
+ for (const listener of [...observers]) call(listener, net);
4101
+ if (net || force) for (const listener of [...listeners]) call(listener, net);
4102
+ },
4103
+ finish: () => {
4104
+ baseline = void 0;
4105
+ notifications.clear();
4106
+ },
4107
+ observe: (listener) => {
4108
+ binding.check();
4109
+ observers.add(listener);
4110
+ return () => observers.delete(listener);
3939
4111
  },
3940
4112
  hasConsumers: () => consumers.size > 0,
3941
- forEachConsumer: (run) => consumers.forEach(run),
3942
- attachConsumer: (consumer) => consumers.add(consumer),
4113
+ forEachConsumer: (run) => consumers.forEach((_pending, consumer) => run(consumer)),
4114
+ attachConsumer: (consumer) => consumers.set(consumer, createCollectionChanges()),
3943
4115
  detachConsumer: (consumer) => consumers.delete(consumer),
3944
4116
  clear: () => {
3945
4117
  staged.clear();
3946
- nextIds = published.ids();
4118
+ nextIds = currentState.ids();
3947
4119
  change = void 0;
3948
4120
  reset = false;
3949
4121
  explicitOrder = void 0;
3950
4122
  cleared = false;
3951
4123
  },
3952
4124
  release: () => {
3953
- published.release();
4125
+ currentState.release();
3954
4126
  staged.clear();
3955
4127
  listeners.clear();
3956
4128
  consumers.clear();
4129
+ observers.clear();
4130
+ baseline = void 0;
4131
+ notifications.clear();
3957
4132
  nextIds = Object.freeze([]);
3958
4133
  change = void 0;
3959
4134
  initialized = false;
@@ -3972,7 +4147,7 @@ const createCollectionOutput = (binding) => {
3972
4147
  //#endregion
3973
4148
  //#region core/src/projection/output/value.ts
3974
4149
  const unset = Symbol("projection-value-unset");
3975
- /** Owns staged and published state for one scalar Projection output. */
4150
+ /** Owns staged and current state for one scalar Projection output. */
3976
4151
  const createValueOutput = (binding) => {
3977
4152
  let value;
3978
4153
  let staged = unset;
@@ -3982,7 +4157,10 @@ const createValueOutput = (binding) => {
3982
4157
  let changed = false;
3983
4158
  let reset = false;
3984
4159
  const listeners = /* @__PURE__ */ new Set();
3985
- const consumers = /* @__PURE__ */ new Set();
4160
+ const consumers = /* @__PURE__ */ new Map();
4161
+ const observers = /* @__PURE__ */ new Set();
4162
+ let baseline = unset;
4163
+ let resetRevision = -1;
3986
4164
  const begin = (active, initialize) => {
3987
4165
  staged = unset;
3988
4166
  next = value;
@@ -4009,7 +4187,12 @@ const createValueOutput = (binding) => {
4009
4187
  next = value;
4010
4188
  return false;
4011
4189
  }
4012
- const candidate = staged;
4190
+ let candidate = staged;
4191
+ if (baseline !== unset && !Object.is(value, baseline)) {
4192
+ const equivalent = isEqual(baseline, candidate);
4193
+ require_transform.assertSynchronous(equivalent);
4194
+ if (equivalent) candidate = baseline;
4195
+ }
4013
4196
  const equal = initialized ? isEqual(value, candidate) : false;
4014
4197
  require_transform.assertSynchronous(equal);
4015
4198
  changed = !equal;
@@ -4024,13 +4207,13 @@ const createValueOutput = (binding) => {
4024
4207
  },
4025
4208
  begin,
4026
4209
  seal,
4027
- context: (active) => {
4210
+ context: (active, consumer) => {
4028
4211
  require_transform.assertScope(active);
4029
4212
  return Object.freeze({
4030
4213
  kind: "value",
4031
4214
  value: next,
4032
4215
  revision,
4033
- reset,
4216
+ reset: consumer ? (consumers.get(consumer)?.revision ?? -1) < resetRevision : reset,
4034
4217
  cause: binding.cause()
4035
4218
  });
4036
4219
  },
@@ -4039,19 +4222,48 @@ const createValueOutput = (binding) => {
4039
4222
  return value;
4040
4223
  },
4041
4224
  revision: () => revision,
4042
- reset: () => reset,
4043
- publish: () => {
4044
- if (changed && initialized) revision++;
4225
+ reset: (consumer) => consumer ? (consumers.get(consumer)?.revision ?? -1) < resetRevision : reset,
4226
+ acknowledge: (consumer) => {
4227
+ if (consumers.has(consumer)) consumers.set(consumer, {
4228
+ revision,
4229
+ value
4230
+ });
4231
+ },
4232
+ pending: (consumer) => {
4233
+ const previous = consumers.get(consumer);
4234
+ return !previous || previous.revision < resetRevision || !Object.is(previous.value, value);
4235
+ },
4236
+ baseline: () => baseline === unset ? value : baseline,
4237
+ publish: (forceReset) => {
4238
+ if (initialized && (changed || forceReset)) {
4239
+ if (baseline === unset) baseline = value;
4240
+ revision++;
4241
+ if (reset) resetRevision = revision;
4242
+ }
4045
4243
  if (changed) value = next;
4046
4244
  initialized = true;
4047
4245
  },
4048
- emit: (call) => {
4049
- require_transform.profile.materialized.notification();
4050
- Array.from(listeners).forEach((listener) => call(listener, void 0));
4246
+ emit: (call, force) => {
4247
+ for (const listener of [...observers]) call(listener, void 0);
4248
+ if (force || baseline !== unset && !Object.is(baseline, value)) {
4249
+ require_transform.profile.materialized.notification();
4250
+ for (const listener of [...listeners]) call(listener, void 0);
4251
+ }
4252
+ },
4253
+ finish: () => {
4254
+ baseline = unset;
4255
+ },
4256
+ observe: (listener) => {
4257
+ binding.check();
4258
+ observers.add(listener);
4259
+ return () => observers.delete(listener);
4051
4260
  },
4052
4261
  hasConsumers: () => consumers.size > 0,
4053
- forEachConsumer: (run) => consumers.forEach(run),
4054
- attachConsumer: (consumer) => consumers.add(consumer),
4262
+ forEachConsumer: (run) => consumers.forEach((_revision, consumer) => run(consumer)),
4263
+ attachConsumer: (consumer) => consumers.set(consumer, {
4264
+ revision,
4265
+ value
4266
+ }),
4055
4267
  detachConsumer: (consumer) => consumers.delete(consumer),
4056
4268
  clear: () => {
4057
4269
  staged = unset;
@@ -4062,6 +4274,8 @@ const createValueOutput = (binding) => {
4062
4274
  release: () => {
4063
4275
  listeners.clear();
4064
4276
  consumers.clear();
4277
+ observers.clear();
4278
+ baseline = unset;
4065
4279
  staged = unset;
4066
4280
  value = next = void 0;
4067
4281
  initialized = false;
@@ -4132,7 +4346,7 @@ const createProcessor = (scheduler, definition, dependencies) => {
4132
4346
  let active = true;
4133
4347
  try {
4134
4348
  const scopeActive = () => active;
4135
- const sources = Object.freeze(dependencies.map((output) => output.context(scopeActive)));
4349
+ const sources = Object.freeze(dependencies.map((output) => output.context(scopeActive, processor)));
4136
4350
  const outputs = begin(scopeActive, reset);
4137
4351
  if (recreate && instance) {
4138
4352
  instance.release?.();
@@ -4146,16 +4360,17 @@ const createProcessor = (scheduler, definition, dependencies) => {
4146
4360
  sources,
4147
4361
  outputs
4148
4362
  }));
4149
- return seal(reset);
4363
+ const changed = seal(reset);
4364
+ dependencies.forEach((output) => output.acknowledge(processor));
4365
+ return changed;
4150
4366
  } finally {
4151
4367
  active = false;
4152
4368
  }
4153
4369
  };
4154
- const order = scheduler.order();
4370
+ const id = scheduler.nextId();
4155
4371
  processor = {
4156
4372
  kind: "processor",
4157
- order,
4158
- name: definition.name ? `${definition.name} (${order})` : `projection-${order}`,
4373
+ name: definition.name ? `${definition.name} (${id})` : `projection-${id}`,
4159
4374
  dependencies: Object.freeze([...dependencies]),
4160
4375
  outputs: Object.freeze(bound.map((entry) => entry.state)),
4161
4376
  fault: void 0,
@@ -4282,7 +4497,9 @@ const createSelectorReadable = (source, selector, equality = Object.is) => {
4282
4497
  let initialized = false;
4283
4498
  let value;
4284
4499
  let selectedRevision = 0;
4500
+ let notified;
4285
4501
  let sourceRevision = -1;
4502
+ let notificationRevision = -1;
4286
4503
  let selection = Object.freeze({
4287
4504
  keys: /* @__PURE__ */ new Set(),
4288
4505
  all: true,
@@ -4318,8 +4535,9 @@ const createSelectorReadable = (source, selector, equality = Object.is) => {
4318
4535
  });
4319
4536
  const changed = !initialized || !equality(value, next);
4320
4537
  if (changed) {
4538
+ const candidate = unsubscribeSource && equality(notified, next) ? notified : next;
4321
4539
  if (initialized) selectedRevision++;
4322
- value = next;
4540
+ value = candidate;
4323
4541
  }
4324
4542
  selection = nextSelection;
4325
4543
  initialized = true;
@@ -4329,31 +4547,44 @@ const createSelectorReadable = (source, selector, equality = Object.is) => {
4329
4547
  };
4330
4548
  const ensureCurrent = () => {
4331
4549
  const revision = source.revision();
4332
- if (!initialized || !unsubscribeSource && sourceRevision !== revision) evaluate();
4333
- return value;
4334
- };
4335
- const onProjectionChange = (incoming) => {
4336
- let change = incoming;
4337
- if (!change && previousCollection) {
4550
+ if (!initialized) evaluate();
4551
+ else if (sourceRevision !== revision) {
4338
4552
  const current = source.current();
4339
- if (isMapLike(current)) {
4340
- change = require_transform.diffCollection(previousCollection, current);
4341
- previousCollection = current;
4342
- if (!change) {
4343
- sourceRevision = source.revision();
4344
- return;
4553
+ let affected = true;
4554
+ if (previousCollection && isMapLike(current) && !selection.all) {
4555
+ affected = selection.structure && !require_transform.iterableMatchesArray(current.keys(), [...previousCollection.keys()]);
4556
+ if (!affected) {
4557
+ for (const key of selection.keys) if (previousCollection.has(key) !== current.has(key) || !Object.is(previousCollection.get(key), current.get(key))) {
4558
+ affected = true;
4559
+ break;
4560
+ }
4345
4561
  }
4346
- } else previousCollection = void 0;
4562
+ }
4563
+ if (affected) evaluate();
4564
+ else {
4565
+ sourceRevision = revision;
4566
+ updateCollectionSnapshot(current);
4567
+ }
4347
4568
  }
4348
- if (!selectionAffects(selection, change)) {
4569
+ return value;
4570
+ };
4571
+ const onProjectionChange = (incoming) => {
4572
+ if (sourceRevision === notificationRevision && sourceRevision !== source.revision() && incoming && !selectionAffects(selection, incoming)) {
4349
4573
  sourceRevision = source.revision();
4350
4574
  updateCollectionSnapshot();
4351
- return;
4575
+ } else ensureCurrent();
4576
+ notificationRevision = sourceRevision;
4577
+ if (!equality(notified, value)) {
4578
+ notified = value;
4579
+ notifyProjectionListeners(listeners, "Projection selector listeners failed.");
4352
4580
  }
4353
- if (evaluate()) notifyProjectionListeners(listeners, "Projection selector listeners failed.");
4354
4581
  };
4355
4582
  const installSource = () => {
4356
- if (!unsubscribeSource) unsubscribeSource = source.subscribe(onProjectionChange);
4583
+ if (!unsubscribeSource) {
4584
+ notified = value;
4585
+ notificationRevision = sourceRevision;
4586
+ unsubscribeSource = source.observe(onProjectionChange);
4587
+ }
4357
4588
  };
4358
4589
  return Object.freeze({
4359
4590
  current: ensureCurrent,
@@ -4735,13 +4966,12 @@ const createValueBoundary = (scheduler, name, initial, equality, prepare, clearS
4735
4966
  active = false;
4736
4967
  }
4737
4968
  },
4738
- publish: state.publish,
4969
+ publish: () => state.publish(pendingReset),
4739
4970
  clear: () => {
4740
4971
  const failed = boundary.fault !== void 0;
4741
4972
  state.clear();
4742
4973
  pendingReset = false;
4743
4974
  pendingCause = void 0;
4744
- contextCause = void 0;
4745
4975
  recovering = false;
4746
4976
  clearSource(failed);
4747
4977
  },
@@ -4797,6 +5027,7 @@ const createValueBoundary = (scheduler, name, initial, equality, prepare, clearS
4797
5027
  return {
4798
5028
  producer: boundary,
4799
5029
  output,
5030
+ baseline: state.baseline,
4800
5031
  mark,
4801
5032
  fail,
4802
5033
  detach: (next) => {
@@ -4816,7 +5047,7 @@ const stageCollectionRead = (state, read, active, options) => {
4816
5047
  }
4817
5048
  evaluation.output.order(ids);
4818
5049
  } else {
4819
- const previous = state.current();
5050
+ const previous = evaluation.previous;
4820
5051
  let currentIds;
4821
5052
  const ids = () => currentIds ??= read.ids();
4822
5053
  if (options.candidates) for (const key of options.candidates) if (read.has(key)) {
@@ -4897,7 +5128,6 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSo
4897
5128
  state.clear();
4898
5129
  pendingReset = false;
4899
5130
  pendingCause = void 0;
4900
- contextCause = void 0;
4901
5131
  recovering = false;
4902
5132
  fullScan = false;
4903
5133
  orderMayChange = false;
@@ -4950,7 +5180,11 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSo
4950
5180
  fullScan ||= metadata.fullScan ?? false;
4951
5181
  orderMayChange ||= metadata.orderMayChange ?? false;
4952
5182
  if (metadata.candidates) for (const key of metadata.candidates) candidates.add(key);
4953
- if (boundary.fault) recovering = true;
5183
+ if (boundary.fault) {
5184
+ recovering = true;
5185
+ fullScan = true;
5186
+ orderMayChange = true;
5187
+ }
4954
5188
  scheduler.capture(boundary);
4955
5189
  };
4956
5190
  const fail = (cause) => {
@@ -4961,6 +5195,7 @@ const createCollectionBoundary = (scheduler, name, readLatest, equality, clearSo
4961
5195
  return {
4962
5196
  producer: boundary,
4963
5197
  output,
5198
+ baseline: state.baseline,
4964
5199
  mark,
4965
5200
  fail,
4966
5201
  detach: (next) => {
@@ -5510,13 +5745,12 @@ const materializeInputSource = (scheduler, definition) => {
5510
5745
  ...boundary,
5511
5746
  input: {
5512
5747
  kind: "value",
5513
- read: () => latest,
5514
5748
  set(value) {
5515
5749
  const next = scheduler.acceptInput(() => {
5516
5750
  if (equal(latest, value)) return latest;
5517
5751
  if (source.equality === Object.is) return value;
5518
- const published = boundary.output.current();
5519
- return !Object.is(latest, published) && equal(published, value) ? published : value;
5752
+ const baseline = boundary.baseline();
5753
+ return !Object.is(latest, baseline) && equal(baseline, value) ? baseline : value;
5520
5754
  });
5521
5755
  if (Object.is(latest, next)) return;
5522
5756
  latest = next;
@@ -5527,7 +5761,6 @@ const materializeInputSource = (scheduler, definition) => {
5527
5761
  };
5528
5762
  }
5529
5763
  const values = createCollectionState(source.initial);
5530
- let view;
5531
5764
  const latest = {
5532
5765
  get: values.get,
5533
5766
  has: values.has,
@@ -5536,17 +5769,11 @@ const materializeInputSource = (scheduler, definition) => {
5536
5769
  const boundary = createCollectionBoundary(scheduler, "projection collection input", () => latest, Object.is, () => void 0);
5537
5770
  boundary.detach(() => {
5538
5771
  values.release();
5539
- view = void 0;
5540
5772
  });
5541
- const check = () => {
5542
- scheduler.assertActive();
5543
- if (boundary.producer.disposed) throw new require_transform.ProjectionDisposedError();
5544
- };
5545
5773
  return {
5546
5774
  ...boundary,
5547
5775
  input: {
5548
5776
  kind: "collection",
5549
- read: () => view ??= require_transform.collectionView(values.read(check)),
5550
5777
  update(run) {
5551
5778
  const accepted = scheduler.acceptInput(() => {
5552
5779
  const staged = /* @__PURE__ */ new Map();
@@ -5593,7 +5820,7 @@ const materializeInputSource = (scheduler, definition) => {
5593
5820
  } finally {
5594
5821
  active = false;
5595
5822
  }
5596
- const published = source.equality === Object.is ? void 0 : boundary.output.current();
5823
+ const baseline = source.equality === Object.is ? void 0 : boundary.baseline();
5597
5824
  for (const [key, entry] of staged) {
5598
5825
  const existed = values.has(key);
5599
5826
  if (!entry.present) {
@@ -5603,8 +5830,8 @@ const materializeInputSource = (scheduler, definition) => {
5603
5830
  const previous = values.get(key);
5604
5831
  let next = entry.value;
5605
5832
  if (existed && equal(previous, next)) next = previous;
5606
- else if (published?.has(key)) {
5607
- const before = published.get(key);
5833
+ else if (baseline?.has(key)) {
5834
+ const before = baseline.get(key);
5608
5835
  if ((!existed || !Object.is(previous, before)) && equal(before, next)) next = before;
5609
5836
  }
5610
5837
  if (existed && Object.is(previous, next)) staged.delete(key);
@@ -5629,7 +5856,6 @@ const materializeInputSource = (scheduler, definition) => {
5629
5856
  });
5630
5857
  if (!accepted.staged.size && !accepted.structural) return;
5631
5858
  values.install(accepted.staged, accepted.order, false);
5632
- view = void 0;
5633
5859
  boundary.mark({
5634
5860
  candidates: accepted.staged.keys(),
5635
5861
  orderMayChange: accepted.structural
@@ -5682,6 +5908,11 @@ const createProjectionItems = (source, checkOwner) => {
5682
5908
  const waiting = /* @__PURE__ */ new Map();
5683
5909
  let keysValue = Object.freeze([...source.current().keys()]);
5684
5910
  let keysRevision = 0;
5911
+ let notifiedKeys = keysValue;
5912
+ let settledRevision = source.revision();
5913
+ let keysSourceRevision = settledRevision;
5914
+ const pendingKeys = /* @__PURE__ */ new Set();
5915
+ const changedStates = /* @__PURE__ */ new Set();
5685
5916
  const keyListeners = /* @__PURE__ */ new Set();
5686
5917
  const check = () => {
5687
5918
  if (disposed) throw new require_transform.ProjectionDisposedError();
@@ -5717,7 +5948,7 @@ const createProjectionItems = (source, checkOwner) => {
5717
5948
  }
5718
5949
  state.value = value;
5719
5950
  state.revision++;
5720
- notify(state.listeners);
5951
+ changedStates.add(state);
5721
5952
  };
5722
5953
  const attachActive = (state, value) => {
5723
5954
  if (state.ended) return;
@@ -5760,10 +5991,12 @@ const createProjectionItems = (source, checkOwner) => {
5760
5991
  if (extra) for (const state of extra) publishState(state, value);
5761
5992
  };
5762
5993
  const updateKeys = (current) => {
5994
+ const revision = source.revision();
5995
+ if (keysSourceRevision === revision) return;
5996
+ keysSourceRevision = revision;
5763
5997
  if (require_transform.iterableMatchesArray(current.keys(), keysValue)) return;
5764
- keysValue = Object.freeze([...current.keys()]);
5998
+ keysValue = require_transform.iterableMatchesArray(current.keys(), notifiedKeys) ? notifiedKeys : Object.freeze([...current.keys()]);
5765
5999
  keysRevision++;
5766
- notify(keyListeners);
5767
6000
  };
5768
6001
  const createItem = (key, initial) => {
5769
6002
  const state = {
@@ -5772,12 +6005,15 @@ const createProjectionItems = (source, checkOwner) => {
5772
6005
  tracked: initial !== void 0,
5773
6006
  ended: false,
5774
6007
  value: initial?.value,
6008
+ notified: initial?.value,
5775
6009
  revision: 0
5776
6010
  };
5777
6011
  const ensureObserved = () => {
5778
- if (state.ended || state.tracked) return;
6012
+ if (state.ended) return;
5779
6013
  const current = source.current();
5780
- if (current.has(key)) attachActive(state, current.get(key));
6014
+ if (source.revision() !== settledRevision) pendingKeys.add(key);
6015
+ if (!state.tracked && current.has(key)) attachActive(state, current.get(key));
6016
+ else if (state.tracked) publishState(state, current.get(key));
5781
6017
  };
5782
6018
  state.readable = Object.freeze({
5783
6019
  current: () => {
@@ -5812,25 +6048,45 @@ const createProjectionItems = (source, checkOwner) => {
5812
6048
  const onChange = (change) => {
5813
6049
  check();
5814
6050
  const current = source.current();
5815
- if (!change || change.kind === "reset") {
5816
- reconcile(current);
5817
- flushNotifications();
5818
- return;
6051
+ if (change?.kind === "reset") reconcile(current);
6052
+ else {
6053
+ if (change) {
6054
+ for (const entry of change.removed) terminateKey(entry.key);
6055
+ for (const entry of change.added) activateWaiting(entry.key, entry.after);
6056
+ for (const entry of change.updated) updateKey(entry.key, entry.after);
6057
+ if (change.added.length || change.removed.length || change.order) updateKeys(current);
6058
+ }
6059
+ for (const key of pendingKeys) if (!current.has(key)) terminateKey(key);
6060
+ else {
6061
+ updateKey(key, current.get(key));
6062
+ activateWaiting(key, current.get(key));
6063
+ }
6064
+ }
6065
+ pendingKeys.clear();
6066
+ settledRevision = source.revision();
6067
+ for (const state of changedStates) if (!Object.is(state.notified, state.value)) {
6068
+ state.notified = state.value;
6069
+ notify(state.listeners);
6070
+ }
6071
+ changedStates.clear();
6072
+ if (keysValue !== notifiedKeys) updateKeys(current);
6073
+ else keysSourceRevision = settledRevision;
6074
+ if (keysValue !== notifiedKeys) {
6075
+ notifiedKeys = keysValue;
6076
+ notify(keyListeners);
5819
6077
  }
5820
- for (const entry of change.removed) terminateKey(entry.key);
5821
- for (const entry of change.added) activateWaiting(entry.key, entry.after);
5822
- for (const entry of change.updated) updateKey(entry.key, entry.after);
5823
- if (change.added.length || change.removed.length || change.order) updateKeys(current);
5824
6078
  flushNotifications();
5825
6079
  };
5826
- const stop = source.subscribe(onChange);
6080
+ const stop = source.observe(onChange);
5827
6081
  const keys = Object.freeze({
5828
6082
  current: () => {
5829
6083
  check();
6084
+ updateKeys(source.current());
5830
6085
  return keysValue;
5831
6086
  },
5832
6087
  revision: () => {
5833
6088
  check();
6089
+ updateKeys(source.current());
5834
6090
  return keysRevision;
5835
6091
  },
5836
6092
  subscribe: (listener) => {
@@ -5844,11 +6100,12 @@ const createProjectionItems = (source, checkOwner) => {
5844
6100
  keys,
5845
6101
  get: (key) => {
5846
6102
  check();
6103
+ const current = source.current();
6104
+ if (source.revision() !== settledRevision) pendingKeys.add(key);
5847
6105
  const canonical = active.get(key);
5848
6106
  if (canonical) return canonical.readable;
5849
6107
  const pending = waiting.get(key)?.values().next().value;
5850
6108
  if (pending) return pending.readable;
5851
- const current = source.current();
5852
6109
  if (current.has(key)) {
5853
6110
  const state = createItem(key, {
5854
6111
  present: true,
@@ -5874,6 +6131,8 @@ const createProjectionItems = (source, checkOwner) => {
5874
6131
  followers.clear();
5875
6132
  waiting.clear();
5876
6133
  notifications.length = 0;
6134
+ pendingKeys.clear();
6135
+ changedStates.clear();
5877
6136
  }
5878
6137
  };
5879
6138
  };
@@ -5934,6 +6193,7 @@ const createProjectionRuntime = (options) => {
5934
6193
  } else {
5935
6194
  if (definition.owner === void 0 && definition.dependencies.some((dependency) => require_transform.producerOf(dependency).owner !== void 0)) throw new TypeError("A root projection cannot depend on a scoped projection.");
5936
6195
  const dependencies = definition.dependencies.map((dependency) => resolveOutput(dependency, requester));
6196
+ dependencies.forEach((output) => scheduler.ensureCurrent(output));
5937
6197
  const processor = createProcessor(scheduler, definition, Object.freeze(dependencies));
5938
6198
  result = Object.freeze({
5939
6199
  record: processor,
@@ -5957,6 +6217,7 @@ const createProjectionRuntime = (options) => {
5957
6217
  if (output.owner.fault) throw output.owner.fault;
5958
6218
  };
5959
6219
  const publicCurrent = (output) => {
6220
+ scheduler.ensureCurrent(output);
5960
6221
  assertOutput(output);
5961
6222
  const current = output.current();
5962
6223
  const revision = output.revision();
@@ -5988,10 +6249,12 @@ const createProjectionRuntime = (options) => {
5988
6249
  kind: output.kind,
5989
6250
  current: () => readProjection(projection, requester),
5990
6251
  revision: () => {
6252
+ scheduler.ensureCurrent(output);
5991
6253
  assertOutput(output);
5992
6254
  return output.revision();
5993
6255
  },
5994
- subscribe: output.subscribe
6256
+ subscribe: output.subscribe,
6257
+ observe: output.observe
5995
6258
  });
5996
6259
  };
5997
6260
  const projectionItems = (projection, requester) => {
@@ -6002,6 +6265,7 @@ const createProjectionRuntime = (options) => {
6002
6265
  if (existing) return existing.items;
6003
6266
  const controller = createProjectionItems(readableSource(projection, requester), () => {
6004
6267
  if (requester && !requester.active) throw new require_transform.ProjectionDisposedError();
6268
+ scheduler.ensureCurrent(output);
6005
6269
  assertOutput(output);
6006
6270
  });
6007
6271
  registry.set(output, controller);
@@ -6036,18 +6300,7 @@ const createProjectionRuntime = (options) => {
6036
6300
  function update(target, valueOrRun) {
6037
6301
  updateInput(target, valueOrRun);
6038
6302
  }
6039
- const batch = (run, options, requester) => scheduler.batch(() => {
6040
- let active = true;
6041
- const read = (target) => {
6042
- require_transform.assertScope(() => active);
6043
- return inputAccess(target, requester).read();
6044
- };
6045
- try {
6046
- return run(read);
6047
- } finally {
6048
- active = false;
6049
- }
6050
- }, options);
6303
+ const batch = (run, options) => scheduler.batch(run, options);
6051
6304
  const disposeScope = (state) => {
6052
6305
  if (!state.active) return;
6053
6306
  scheduler.assertIdle();
@@ -6139,7 +6392,7 @@ const createProjectionRuntime = (options) => {
6139
6392
  }
6140
6393
  function scopeBatch(run, options) {
6141
6394
  assertActive();
6142
- return batch(run, options, state);
6395
+ return batch(run, options);
6143
6396
  }
6144
6397
  return Object.freeze({
6145
6398
  own,