doxum 0.1.32 → 0.1.33

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.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as ownProjections, C as snapshotDependencyValue, D as defineProcessor, E as snapshotCollectionView, M as projectionRef, N as profile, O as defineSource, S as compileProjectionDependencies, T as mapRead, _ as createCollectionChange, a as createKeyedDependencyRuntime, b as sameArray, c as assertScope, d as ProjectionDisposedError, f as ProjectionError, g as collectionHasStructuralChange, h as collectionChangeTouchesKey, i as compileKeyedDependencies, j as producerOf, k as isProjection, l as assertSynchronous, m as collectionChangeIntersects, n as keyedAbsent, o as outputKind, r as assertKeyedProjection, s as createKeyRelation, t as createKeyedTransform, u as createScheduler, v as diffCollection, w as collectionView, x as snapshotArray, y as iterableMatchesArray } from "./transform-gOtqcdHe.js";
1
+ import { A as isProjection, C as compileProjectionDependencies, D as snapshotCollectionView, E as mapRead, M as producerOf, N as projectionRef, O as defineProcessor, P as profile, S as collectKeyedInvalidation, T as collectionView, _ as assertScope, a as collectionChangeTouchesKey, b as ProjectionDisposedError, c as diffCollection, d as createKeyedDependencyRuntime, f as outputKind, g as snapshotArray, h as sameArray, i as collectionChangeIntersects, j as ownProjections, k as defineSource, l as assertKeyedProjection, m as iterableMatchesArray, n as keyedAbsent, o as collectionHasStructuralChange, p as createKeyRelation, s as createCollectionChange, t as createKeyedTransform, u as compileKeyedDependencies, v as assertSynchronous, w as snapshotDependencyValue, x as ProjectionError, y as createScheduler } from "./transform-A9Lx5R2l.js";
2
2
  import { n as isPlainObject, r as isRecord, t as installOwn } from "./record-B2yRhYsc.js";
3
3
  import { c as AddressIndex, d as invalidValue, f as children, g as validate, h as parent, i as contextOf, l as MutationRejected, m as is, o as decodeChanges, p as contains$1, r as bindContext, s as sealChanges, t as assertRuntimeWritable, u as fail } from "./driver-B7RR-VfX.js";
4
4
  //#region core/src/schema/model.ts
@@ -2774,6 +2774,108 @@ const isExternalSource = (source) => {
2774
2774
  return (candidate.kind === "value" || candidate.kind === "collection") && typeof candidate.current === "function" && typeof candidate.revision === "function" && typeof candidate.subscribe === "function";
2775
2775
  };
2776
2776
  //#endregion
2777
+ //#region core/src/projection/keyed/flat-map.ts
2778
+ function createKeyedFlatMap(source, dependenciesOrSelect, selectOrEquality, maybeEquality) {
2779
+ const name = "derive.keyed.flatMap";
2780
+ assertKeyedProjection(source, `${name} source`);
2781
+ const specs = typeof dependenciesOrSelect === "function" ? void 0 : dependenciesOrSelect;
2782
+ const select = specs === void 0 ? dependenciesOrSelect : selectOrEquality;
2783
+ const equality = specs === void 0 ? selectOrEquality : maybeEquality;
2784
+ if (typeof select !== "function") throw new TypeError(`${name} requires a selector.`);
2785
+ if (equality !== void 0 && typeof equality !== "function") throw new TypeError(`${name} equality must be a function.`);
2786
+ const compiled = compileKeyedDependencies(source, specs, name);
2787
+ const [projection] = defineProcessor({
2788
+ dependencies: compiled.projections,
2789
+ outputs: [{
2790
+ kind: "collection",
2791
+ equality: equality ?? Object.is
2792
+ }],
2793
+ name,
2794
+ create: () => {
2795
+ const dependencies = createKeyedDependencyRuntime(compiled);
2796
+ const childrenByParent = /* @__PURE__ */ new Map();
2797
+ const ownerByOutput = /* @__PURE__ */ new Map();
2798
+ return {
2799
+ evaluate: (evaluation) => {
2800
+ const driver = evaluation.sources[0];
2801
+ const output = evaluation.outputs[0];
2802
+ if (driver.kind !== "collection" || output.kind !== "collection") throw new Error(`${name} requires collection input and output.`);
2803
+ const plan = collectKeyedInvalidation(driver, evaluation.sources, dependencies, evaluation.reset);
2804
+ dependencies.prepare(evaluation.sources, plan.rebuild);
2805
+ if (plan.rebuild) {
2806
+ dependencies.clearBindings();
2807
+ childrenByParent.clear();
2808
+ ownerByOutput.clear();
2809
+ }
2810
+ const replaced = new Set(plan.keys);
2811
+ for (const entry of plan.removed) replaced.add(entry.key);
2812
+ const proposals = /* @__PURE__ */ new Map();
2813
+ const segments = /* @__PURE__ */ new Map();
2814
+ let orderDirty = plan.structural;
2815
+ for (const parent of replaced) {
2816
+ if (!driver.read.has(parent)) continue;
2817
+ const value = driver.read.get(parent);
2818
+ const entries = select(value, parent, dependencies.resolve(value, parent, evaluation.sources));
2819
+ assertSynchronous(entries);
2820
+ if (!Array.isArray(entries)) throw new TypeError(`${name} selector must return an array of entries.`);
2821
+ const keys = [];
2822
+ for (const entry of entries) {
2823
+ if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[0] !== "string") throw new TypeError(`${name} entries must be [string key, value] tuples.`);
2824
+ const [key, child] = entry;
2825
+ const owner = ownerByOutput.get(key);
2826
+ if (proposals.has(key) || owner !== void 0 && !replaced.has(owner)) throw new TypeError(`${name} duplicate key ${JSON.stringify(key)}.`);
2827
+ proposals.set(key, {
2828
+ parent,
2829
+ value: child
2830
+ });
2831
+ keys.push(key);
2832
+ }
2833
+ const previous = childrenByParent.get(parent);
2834
+ const unchanged = previous ? sameArray(previous, keys) : keys.length === 0;
2835
+ if (!unchanged) orderDirty = true;
2836
+ if (keys.length) segments.set(parent, unchanged && previous ? previous : Object.freeze(keys));
2837
+ }
2838
+ if (plan.rebuild) {
2839
+ if (!evaluation.reset) {
2840
+ for (const key of output.previous.ids()) if (!proposals.has(key)) output.output.remove(key);
2841
+ }
2842
+ } else for (const parent of replaced) {
2843
+ const previous = childrenByParent.get(parent);
2844
+ if (previous) for (const key of previous) {
2845
+ if (!proposals.has(key)) output.output.remove(key);
2846
+ ownerByOutput.delete(key);
2847
+ }
2848
+ childrenByParent.delete(parent);
2849
+ }
2850
+ for (const entry of plan.removed) dependencies.remove(entry.key);
2851
+ for (const [parent, keys] of segments) childrenByParent.set(parent, keys);
2852
+ for (const [key, entry] of proposals) {
2853
+ ownerByOutput.set(key, entry.parent);
2854
+ output.output.set(key, entry.value);
2855
+ }
2856
+ if (orderDirty) {
2857
+ const order = [];
2858
+ const parents = driver.read.ids();
2859
+ for (const parent of parents) {
2860
+ const keys = childrenByParent.get(parent);
2861
+ if (keys) for (const key of keys) order.push(key);
2862
+ }
2863
+ profile.collectionView.idsScanned(parents.length + order.length);
2864
+ output.output.order(order);
2865
+ }
2866
+ dependencies.remember(evaluation.sources);
2867
+ },
2868
+ release: () => {
2869
+ childrenByParent.clear();
2870
+ ownerByOutput.clear();
2871
+ dependencies.release();
2872
+ }
2873
+ };
2874
+ }
2875
+ });
2876
+ return projection;
2877
+ }
2878
+ //#endregion
2777
2879
  //#region core/src/projection/keyed/composition.ts
2778
2880
  const assertEquality = (equality, role) => {
2779
2881
  if (equality !== void 0 && typeof equality !== "function") throw new TypeError(`${role} equality must be a function.`);
@@ -3440,44 +3542,26 @@ function createKeyedGroupBy(source, dependenciesOrSelector, maybeSelector) {
3440
3542
  const driver = evaluation.sources[0];
3441
3543
  const output = evaluation.outputs[0];
3442
3544
  if (driver.kind !== "collection" || output.kind !== "collection") throw new Error("derive.keyed.groupBy requires collection input and output.");
3443
- dependencies.prepare(evaluation.sources, evaluation.reset);
3444
- if (evaluation.reset) {
3545
+ const invalidation = collectKeyedInvalidation(driver, evaluation.sources, dependencies, evaluation.reset);
3546
+ dependencies.prepare(evaluation.sources, invalidation.rebuild);
3547
+ if (invalidation.rebuild) {
3445
3548
  rebuild(driver, evaluation.sources, output);
3446
3549
  dependencies.remember(evaluation.sources);
3447
3550
  return;
3448
3551
  }
3449
- const dirty = /* @__PURE__ */ new Set();
3450
3552
  const affected = /* @__PURE__ */ new Set();
3451
- let all = false;
3452
- let structural = false;
3453
- let orderDirty = false;
3454
- if (dependencies.driverChanged(driver)) {
3455
- const change = driver.change;
3456
- if (!change || change.kind === "reset") {
3457
- rebuild(driver, evaluation.sources, output);
3458
- dependencies.remember(evaluation.sources);
3459
- return;
3460
- } else {
3461
- for (const entry of change.removed) {
3462
- const changed = removeSourceKey(entry.key, affected);
3463
- orderDirty ||= changed;
3464
- dependencies.remove(entry.key);
3465
- dirty.delete(entry.key);
3466
- }
3467
- for (const entry of change.added) dirty.add(entry.key);
3468
- for (const entry of change.updated) dirty.add(entry.key);
3469
- structural = Boolean(change.added.length || change.removed.length || change.order);
3470
- orderDirty ||= structural;
3471
- if (structural) refreshOrderIndex(driver);
3472
- }
3553
+ let orderDirty = invalidation.structural;
3554
+ for (const entry of invalidation.removed) {
3555
+ const changed = removeSourceKey(entry.key, affected);
3556
+ orderDirty ||= changed;
3557
+ dependencies.remove(entry.key);
3473
3558
  }
3474
- all ||= dependencies.collectInvalidated(evaluation.sources, dirty);
3475
- if (all) for (const key of driver.read.ids()) dirty.add(key);
3476
- for (const key of dirty) {
3559
+ if (invalidation.structural) refreshOrderIndex(driver);
3560
+ for (const key of invalidation.keys) {
3477
3561
  const changed = selectGroups(driver, evaluation.sources, key, affected);
3478
3562
  orderDirty ||= changed;
3479
3563
  }
3480
- if (structural) markAllGroups(output, affected);
3564
+ if (invalidation.structural) markAllGroups(output, affected);
3481
3565
  publishAffected(affected, output, orderDirty);
3482
3566
  dependencies.remember(evaluation.sources);
3483
3567
  },
@@ -3501,6 +3585,7 @@ const keyedDerive = Object.assign(createKeyedDerive, {
3501
3585
  from: createKeyedFrom,
3502
3586
  merge: createKeyedMerge,
3503
3587
  groupBy: createKeyedGroupBy,
3588
+ flatMap: createKeyedFlatMap,
3504
3589
  singleton: createKeyedSingleton,
3505
3590
  subset: createKeyedSubset,
3506
3591
  filter: createKeyedFilter,
@@ -3622,11 +3707,11 @@ var PersistentKeyedIndex = class PersistentKeyedIndex {
3622
3707
  }
3623
3708
  };
3624
3709
  //#endregion
3625
- //#region core/src/projection/output/collection.ts
3626
- const createPublishedCollection = () => {
3627
- const values = /* @__PURE__ */ new Map();
3628
- let ids = Object.freeze([]);
3629
- let index = PersistentKeyedIndex.empty();
3710
+ //#region core/src/projection/collection/state.ts
3711
+ const createCollectionState = (initial) => {
3712
+ const values = new Map(initial);
3713
+ let ids = Object.freeze([...values.keys()]);
3714
+ let index = values.size ? PersistentKeyedIndex.from(values) : PersistentKeyedIndex.empty();
3630
3715
  return {
3631
3716
  get: (key) => values.get(key),
3632
3717
  has: (key) => values.has(key),
@@ -3651,7 +3736,7 @@ const createPublishedCollection = () => {
3651
3736
  }
3652
3737
  });
3653
3738
  },
3654
- publish: (staged, nextIds, reset) => {
3739
+ install: (staged, nextIds, reset) => {
3655
3740
  if (reset) {
3656
3741
  values.clear();
3657
3742
  for (const [key, entry] of staged) if (entry.present) values.set(key, entry.value);
@@ -3670,9 +3755,11 @@ const createPublishedCollection = () => {
3670
3755
  }
3671
3756
  };
3672
3757
  };
3758
+ //#endregion
3759
+ //#region core/src/projection/output/collection.ts
3673
3760
  /** Owns staged keyed intent, exact transitions and published collection state. */
3674
3761
  const createCollectionOutput = (binding) => {
3675
- const published = createPublishedCollection();
3762
+ const published = createCollectionState();
3676
3763
  const staged = /* @__PURE__ */ new Map();
3677
3764
  let nextIds = published.ids();
3678
3765
  let change;
@@ -3761,12 +3848,18 @@ const createCollectionOutput = (binding) => {
3761
3848
  continue;
3762
3849
  }
3763
3850
  const before = published.get(key);
3764
- if (!isEqual(before, entry.value)) updatedEntries.push({
3851
+ const equal = isEqual(before, entry.value);
3852
+ assertSynchronous(equal);
3853
+ if (!equal) updatedEntries.push({
3765
3854
  key,
3766
3855
  before,
3767
3856
  after: entry.value
3768
3857
  });
3769
- else if (!nextReset) staged.delete(key);
3858
+ else if (nextReset) staged.set(key, {
3859
+ present: true,
3860
+ value: before
3861
+ });
3862
+ else staged.delete(key);
3770
3863
  continue;
3771
3864
  }
3772
3865
  if (existed) removedEntries.push({
@@ -3836,7 +3929,7 @@ const createCollectionOutput = (binding) => {
3836
3929
  revision: () => revision,
3837
3930
  reset: () => reset,
3838
3931
  publish: () => {
3839
- if (change) published.publish(staged, nextIds, change.kind === "reset");
3932
+ if (change) published.install(staged, nextIds, change.kind === "reset");
3840
3933
  if (change && initialized) revision++;
3841
3934
  initialized = true;
3842
3935
  },
@@ -3916,7 +4009,9 @@ const createValueOutput = (binding) => {
3916
4009
  return false;
3917
4010
  }
3918
4011
  const candidate = staged;
3919
- changed = !initialized || !isEqual(value, candidate);
4012
+ const equal = initialized ? isEqual(value, candidate) : false;
4013
+ assertSynchronous(equal);
4014
+ changed = !equal;
3920
4015
  next = changed ? candidate : value;
3921
4016
  reset = nextReset;
3922
4017
  return changed;
@@ -5398,101 +5493,145 @@ const createExternalSourceRegistry = (scheduler, documents) => {
5398
5493
  //#region core/src/projection/source/input.ts
5399
5494
  const materializeInputSource = (scheduler, definition) => {
5400
5495
  const source = definition.source;
5496
+ if (source.kind !== "value-input" && source.kind !== "collection-input") throw new Error("Invalid projection input source.");
5497
+ const equal = (previous, next) => {
5498
+ const result = source.equality(previous, next);
5499
+ assertSynchronous(result);
5500
+ return result;
5501
+ };
5401
5502
  if (source.kind === "value-input") {
5402
5503
  let latest = source.initial;
5403
- const boundary = createValueBoundary(scheduler, "projection input", source.initial, source.equality, () => latest, () => void 0);
5504
+ const boundary = createValueBoundary(scheduler, "projection input", source.initial, Object.is, () => latest, () => void 0);
5505
+ boundary.detach(() => {
5506
+ latest = void 0;
5507
+ });
5404
5508
  return {
5405
5509
  ...boundary,
5406
- write: {
5510
+ input: {
5407
5511
  kind: "value",
5512
+ read: () => latest,
5408
5513
  set(value) {
5409
- scheduler.assertIdle();
5410
- latest = value;
5514
+ const next = scheduler.acceptInput(() => {
5515
+ if (equal(latest, value)) return latest;
5516
+ if (source.equality === Object.is) return value;
5517
+ const published = boundary.output.current();
5518
+ return !Object.is(latest, published) && equal(published, value) ? published : value;
5519
+ });
5520
+ if (Object.is(latest, next)) return;
5521
+ latest = next;
5411
5522
  boundary.mark();
5412
5523
  scheduler.run();
5413
5524
  }
5414
5525
  }
5415
5526
  };
5416
5527
  }
5417
- if (source.kind !== "collection-input") throw new Error("Invalid projection input source.");
5418
- const values = new Map(source.initial);
5419
- const boundary = createCollectionBoundary(scheduler, "projection collection input", () => mapRead(values), definition.output.equality, () => void 0);
5528
+ const values = createCollectionState(source.initial);
5529
+ let view;
5530
+ const latest = {
5531
+ get: values.get,
5532
+ has: values.has,
5533
+ ids: values.ids
5534
+ };
5535
+ const boundary = createCollectionBoundary(scheduler, "projection collection input", () => latest, Object.is, () => void 0);
5536
+ boundary.detach(() => {
5537
+ values.release();
5538
+ view = void 0;
5539
+ });
5540
+ const check = () => {
5541
+ scheduler.assertActive();
5542
+ if (boundary.producer.disposed) throw new ProjectionDisposedError();
5543
+ };
5420
5544
  return {
5421
5545
  ...boundary,
5422
- write: {
5546
+ input: {
5423
5547
  kind: "collection",
5548
+ read: () => view ??= collectionView(values.read(check)),
5424
5549
  update(run) {
5425
- scheduler.assertIdle();
5426
- const staged = /* @__PURE__ */ new Map();
5427
- const operations = [];
5428
- let structural = false;
5429
- let active = true;
5430
- const draft = Object.freeze({
5431
- get: (key) => {
5432
- assertScope(() => active);
5433
- const entry = staged.get(key);
5434
- return entry ? entry.present ? entry.value : void 0 : values.get(key);
5435
- },
5436
- has: (key) => {
5437
- assertScope(() => active);
5550
+ const accepted = scheduler.acceptInput(() => {
5551
+ const staged = /* @__PURE__ */ new Map();
5552
+ const appended = /* @__PURE__ */ new Set();
5553
+ let structural = false;
5554
+ let active = true;
5555
+ const has = (key) => {
5438
5556
  const entry = staged.get(key);
5439
5557
  return entry ? entry.present : values.has(key);
5440
- },
5441
- set: (key, value) => {
5442
- assertScope(() => active);
5443
- if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
5444
- const previous = staged.get(key);
5445
- structural ||= previous ? !previous.present : !values.has(key);
5446
- staged.set(key, {
5447
- present: true,
5448
- value
5449
- });
5450
- operations.push({
5451
- kind: "set",
5452
- key,
5453
- value
5454
- });
5455
- },
5456
- remove: (key) => {
5457
- assertScope(() => active);
5458
- if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
5459
- const previous = staged.get(key);
5460
- const present = previous ? previous.present : values.has(key);
5461
- structural ||= present;
5462
- staged.set(key, { present: false });
5463
- if (present) operations.push({
5464
- kind: "remove",
5465
- key
5466
- });
5558
+ };
5559
+ const draft = Object.freeze({
5560
+ get: (key) => {
5561
+ assertScope(() => active);
5562
+ const entry = staged.get(key);
5563
+ return entry ? entry.present ? entry.value : void 0 : values.get(key);
5564
+ },
5565
+ has: (key) => {
5566
+ assertScope(() => active);
5567
+ return has(key);
5568
+ },
5569
+ set: (key, value) => {
5570
+ assertScope(() => active);
5571
+ if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
5572
+ if (!has(key)) {
5573
+ appended.add(key);
5574
+ structural = true;
5575
+ }
5576
+ staged.set(key, {
5577
+ present: true,
5578
+ value
5579
+ });
5580
+ },
5581
+ remove: (key) => {
5582
+ assertScope(() => active);
5583
+ if (typeof key !== "string") throw new TypeError("Projection keys must be strings.");
5584
+ if (!has(key)) return;
5585
+ appended.delete(key);
5586
+ structural = true;
5587
+ staged.set(key, { present: false });
5588
+ }
5589
+ });
5590
+ try {
5591
+ assertSynchronous(run(draft));
5592
+ } finally {
5593
+ active = false;
5467
5594
  }
5468
- });
5469
- try {
5470
- assertSynchronous(run(draft));
5471
- } finally {
5472
- active = false;
5473
- }
5474
- if (!operations.length) return;
5475
- const candidates = /* @__PURE__ */ new Set();
5476
- const retained = /* @__PURE__ */ new Map();
5477
- for (const [key, entry] of staged) {
5478
- const existed = values.has(key);
5479
- if (entry.present) {
5480
- if (!existed) {
5481
- candidates.add(key);
5595
+ const published = source.equality === Object.is ? void 0 : boundary.output.current();
5596
+ for (const [key, entry] of staged) {
5597
+ const existed = values.has(key);
5598
+ if (!entry.present) {
5599
+ if (!existed) staged.delete(key);
5482
5600
  continue;
5483
5601
  }
5484
5602
  const previous = values.get(key);
5485
- if (source.equality(previous, entry.value)) retained.set(key, previous);
5486
- else candidates.add(key);
5487
- } else if (existed) candidates.add(key);
5488
- }
5489
- if (!candidates.size && !structural) return;
5490
- for (const operation of operations) if (operation.kind === "set") values.set(operation.key, operation.value);
5491
- else values.delete(operation.key);
5492
- for (const [key, value] of retained) if (values.has(key)) values.set(key, value);
5603
+ let next = entry.value;
5604
+ if (existed && equal(previous, next)) next = previous;
5605
+ else if (published?.has(key)) {
5606
+ const before = published.get(key);
5607
+ if ((!existed || !Object.is(previous, before)) && equal(before, next)) next = before;
5608
+ }
5609
+ if (existed && Object.is(previous, next)) staged.delete(key);
5610
+ else if (!Object.is(entry.value, next)) staged.set(key, {
5611
+ present: true,
5612
+ value: next
5613
+ });
5614
+ }
5615
+ const beforeOrder = values.ids();
5616
+ let order = beforeOrder;
5617
+ if (structural) {
5618
+ const next = [];
5619
+ for (const key of beforeOrder) if (has(key) && !appended.has(key)) next.push(key);
5620
+ for (const key of appended) next.push(key);
5621
+ if (!sameArray(beforeOrder, next)) order = Object.freeze(next);
5622
+ }
5623
+ return {
5624
+ staged,
5625
+ order,
5626
+ structural: order !== beforeOrder
5627
+ };
5628
+ });
5629
+ if (!accepted.staged.size && !accepted.structural) return;
5630
+ values.install(accepted.staged, accepted.order, false);
5631
+ view = void 0;
5493
5632
  boundary.mark({
5494
- candidates,
5495
- orderMayChange: structural
5633
+ candidates: accepted.staged.keys(),
5634
+ orderMayChange: accepted.structural
5496
5635
  });
5497
5636
  scheduler.run();
5498
5637
  }
@@ -5789,7 +5928,7 @@ const createProjectionRuntime = (options) => {
5789
5928
  result = Object.freeze({
5790
5929
  record: source.producer,
5791
5930
  outputs: Object.freeze([source.output]),
5792
- ...source.write ? { write: source.write } : {}
5931
+ ...source.input ? { input: source.input } : {}
5793
5932
  });
5794
5933
  } else {
5795
5934
  if (definition.owner === void 0 && definition.dependencies.some((dependency) => producerOf(dependency).owner !== void 0)) throw new TypeError("A root projection cannot depend on a scoped projection.");
@@ -5874,16 +6013,18 @@ const createProjectionRuntime = (options) => {
5874
6013
  function selectProjection(projection, selector, equality) {
5875
6014
  return makeReadable(projection, selector, equality);
5876
6015
  }
5877
- const inputWrite = (target, requester) => {
6016
+ const inputAccess = (target, requester) => {
6017
+ scheduler.assertIdle();
6018
+ if (requester && !requester.active) throw new ProjectionDisposedError();
5878
6019
  const ref = projectionRef(target);
5879
6020
  if (ref.output !== 0 || ref.producer.kind !== "source") throw new TypeError("Projection is not an input.");
5880
6021
  if (ref.producer.source.kind !== "value-input" && ref.producer.source.kind !== "collection-input") throw new TypeError("Projection is not an input.");
5881
- const write = materializeProducer(ref.producer, requester).write;
5882
- if (!write) throw new TypeError("Projection input is not writable.");
5883
- return write;
6022
+ const access = materializeProducer(ref.producer, requester).input;
6023
+ if (!access) throw new TypeError("Projection input is not writable.");
6024
+ return access;
5884
6025
  };
5885
6026
  const updateInput = (target, valueOrRun, requester) => {
5886
- const write = inputWrite(target, requester);
6027
+ const write = inputAccess(target, requester);
5887
6028
  if (write.kind === "value") {
5888
6029
  write.set(valueOrRun);
5889
6030
  return;
@@ -5894,7 +6035,18 @@ const createProjectionRuntime = (options) => {
5894
6035
  function update(target, valueOrRun) {
5895
6036
  updateInput(target, valueOrRun);
5896
6037
  }
5897
- const batch = (run, options) => scheduler.batch(run, options);
6038
+ const batch = (run, options, requester) => scheduler.batch(() => {
6039
+ let active = true;
6040
+ const read = (target) => {
6041
+ assertScope(() => active);
6042
+ return inputAccess(target, requester).read();
6043
+ };
6044
+ try {
6045
+ return run(read);
6046
+ } finally {
6047
+ active = false;
6048
+ }
6049
+ }, options);
5898
6050
  const disposeScope = (state) => {
5899
6051
  if (!state.active) return;
5900
6052
  scheduler.assertIdle();
@@ -5986,7 +6138,7 @@ const createProjectionRuntime = (options) => {
5986
6138
  }
5987
6139
  function scopeBatch(run, options) {
5988
6140
  assertActive();
5989
- return batch(run, options);
6141
+ return batch(run, options, state);
5990
6142
  }
5991
6143
  return Object.freeze({
5992
6144
  own,