@blac/react 2.1.1 → 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.
@@ -16,6 +16,4 @@
16
16
  */
17
17
  export declare function buildTrackedProxy<T extends object>(instance: T, trackedStateRef: {
18
18
  current: unknown;
19
- }, onDepHandle?: (handle: object) => unknown): {
20
- proxy: T;
21
- };
19
+ }, onDepHandle?: (handle: object) => unknown): T;
@@ -16,6 +16,4 @@
16
16
  */
17
17
  export declare function buildTrackedProxy<T extends object>(instance: T, trackedStateRef: {
18
18
  current: unknown;
19
- }, onDepHandle?: (handle: object) => unknown): {
20
- proxy: T;
21
- };
19
+ }, onDepHandle?: (handle: object) => unknown): T;
@@ -13,13 +13,21 @@ import { type PathSet } from '@dirtytalk/structural';
13
13
  export declare class DepSession {
14
14
  private readonly consumerId;
15
15
  private readonly onChange;
16
- private readonly entries;
17
- private readonly subs;
18
- private lastReconciled;
19
- private readonly refId;
16
+ private primary;
17
+ private primaryPaths;
18
+ private entries;
19
+ private subs;
20
+ private reconciled;
21
+ private lastPrimary;
22
+ private lastPrimaryPaths;
23
+ private lastEntries;
24
+ private disarms;
20
25
  constructor(consumerId: string, onChange: () => void);
26
+ private get refId();
21
27
  begin(primary: StateContainer, paths: PathSet): void;
22
- record(dep: StateContainer, paths: PathSet, Type: StateContainerConstructor, key: string, args: unknown): void;
28
+ record(dep: StateContainer, paths: PathSet, Type: StateContainerConstructor, key: string, args: unknown, disarm: () => void): void;
29
+ /** Stops every dep tracked this render from recording further reads. */
30
+ disarm(): void;
23
31
  /** Forces the next `reconcile` to run in full. */
24
32
  invalidate(): void;
25
33
  isUnchanged(): boolean;
@@ -13,13 +13,21 @@ import { type PathSet } from '@dirtytalk/structural';
13
13
  export declare class DepSession {
14
14
  private readonly consumerId;
15
15
  private readonly onChange;
16
- private readonly entries;
17
- private readonly subs;
18
- private lastReconciled;
19
- private readonly refId;
16
+ private primary;
17
+ private primaryPaths;
18
+ private entries;
19
+ private subs;
20
+ private reconciled;
21
+ private lastPrimary;
22
+ private lastPrimaryPaths;
23
+ private lastEntries;
24
+ private disarms;
20
25
  constructor(consumerId: string, onChange: () => void);
26
+ private get refId();
21
27
  begin(primary: StateContainer, paths: PathSet): void;
22
- record(dep: StateContainer, paths: PathSet, Type: StateContainerConstructor, key: string, args: unknown): void;
28
+ record(dep: StateContainer, paths: PathSet, Type: StateContainerConstructor, key: string, args: unknown, disarm: () => void): void;
29
+ /** Stops every dep tracked this render from recording further reads. */
30
+ disarm(): void;
23
31
  /** Forces the next `reconcile` to run in full. */
24
32
  invalidate(): void;
25
33
  isUnchanged(): boolean;
package/dist/index.cjs CHANGED
@@ -77,6 +77,44 @@ function collectGetters(proto) {
77
77
  gettersByProto.set(proto, getters);
78
78
  return getters;
79
79
  }
80
+ var BlocHandler = class {
81
+ constructor(getters, tracksState, trackedStateRef, onDepHandle) {
82
+ this.getters = getters;
83
+ this.tracksState = tracksState;
84
+ this.trackedStateRef = trackedStateRef;
85
+ this.onDepHandle = onDepHandle;
86
+ this.boundMethods = void 0;
87
+ }
88
+ get(target, key) {
89
+ const getter = this.getters.get(key);
90
+ if (getter !== void 0) {
91
+ const tracked = this.trackedStateRef.current;
92
+ return this.wrapDepHandle(tracked == null || !this.tracksState ? getter.call(target) : target[_blac_core_internal.WITH_TRACKED_STATE](tracked, getter, this.onDepHandle));
93
+ }
94
+ const value = Reflect.get(target, key, target);
95
+ if (typeof value === "function") {
96
+ const fn = value;
97
+ this.boundMethods ??= /* @__PURE__ */ new Map();
98
+ let cached = this.boundMethods.get(key);
99
+ if (cached === void 0 || cached.fn !== fn) {
100
+ cached = {
101
+ fn,
102
+ bound: fn.bind(target)
103
+ };
104
+ this.boundMethods.set(key, cached);
105
+ }
106
+ return this.wrapDepHandle(cached.bound);
107
+ }
108
+ return this.wrapDepHandle(value);
109
+ }
110
+ set(target, key, value) {
111
+ return Reflect.set(target, key, value, target);
112
+ }
113
+ wrapDepHandle(value) {
114
+ if (this.onDepHandle !== void 0 && (typeof value === "function" || typeof value === "object") && value !== null && value[_blac_core_internal.DEP_BRAND] !== void 0) return this.onDepHandle(value);
115
+ return value;
116
+ }
117
+ };
80
118
  /**
81
119
  * Build a per-consumer proxy for a bloc instance.
82
120
  *
@@ -94,68 +132,12 @@ function collectGetters(proto) {
94
132
  * Must cache wrappers per handle to avoid re-allocation.
95
133
  */
96
134
  function buildTrackedProxy(instance, trackedStateRef, onDepHandle) {
97
- const getters = collectGetters(Object.getPrototypeOf(instance));
98
- const tracksState = supportsTrackedState(instance);
99
- const boundMethods = /* @__PURE__ */ new Map();
100
- const wrapDepHandle = (value) => {
101
- if (onDepHandle !== void 0 && (typeof value === "function" || typeof value === "object") && value !== null && value[_blac_core_internal.DEP_BRAND] !== void 0) return onDepHandle(value);
102
- return value;
103
- };
104
- return { proxy: new Proxy(instance, {
105
- get(target, key) {
106
- const getter = getters.get(key);
107
- if (getter !== void 0) {
108
- const tracked = trackedStateRef.current;
109
- return wrapDepHandle(tracked == null || !tracksState ? getter.call(target) : target[_blac_core_internal.WITH_TRACKED_STATE](tracked, getter, onDepHandle));
110
- }
111
- const value = Reflect.get(target, key, target);
112
- if (typeof value === "function") {
113
- const fn = value;
114
- let cached = boundMethods.get(key);
115
- if (cached === void 0 || cached.fn !== fn) {
116
- cached = {
117
- fn,
118
- bound: fn.bind(target)
119
- };
120
- boundMethods.set(key, cached);
121
- }
122
- return wrapDepHandle(cached.bound);
123
- }
124
- return wrapDepHandle(value);
125
- },
126
- set(target, key, value) {
127
- return Reflect.set(target, key, value, target);
128
- }
129
- }) };
130
- }
131
- //#endregion
132
- //#region src/expandWithAncestors.ts
133
- /**
134
- * Add an ancestor-watch id for every ancestor of every tracked leaf, so a
135
- * `patch` that replaces a parent atomically (e.g. the array `items`) wakes a
136
- * consumer that read a child (`items.length`).
137
- *
138
- * Ancestor-watch ids only match marks the source emits for atomic
139
- * replacements, never a plain-object pulse-up: `{'user.email'}` does not wake
140
- * when a sibling `user.name` changes. The `''` root is never added; a root
141
- * change already marks `ALL_PATHS`.
142
- *
143
- * Returns `paths` itself when no leaf has an ancestor.
144
- */
145
- function expandWithAncestors(paths, interner) {
146
- if (paths === _dirtytalk_structural.ALL_PATHS) return _dirtytalk_structural.ALL_PATHS;
147
- const leafPaths = paths;
148
- let expanded;
149
- for (const id of leafPaths) {
150
- const watch = interner.ancestorWatchIds(id);
151
- if (watch.length === 0) continue;
152
- expanded ??= new Set(leafPaths);
153
- for (let i = 0; i < watch.length; i++) expanded.add(watch[i]);
154
- }
155
- return expanded ?? paths;
135
+ const handler = new BlocHandler(collectGetters(Object.getPrototypeOf(instance)), supportsTrackedState(instance), trackedStateRef, onDepHandle);
136
+ return new Proxy(instance, handler);
156
137
  }
157
138
  //#endregion
158
139
  //#region src/depSession.ts
140
+ const NO_PATHS$1 = (0, _dirtytalk_structural.emptyPathSet)();
159
141
  /**
160
142
  * The containers one `useBloc` consumer reads during a render: its primary
161
143
  * bloc plus every dep reached through `this.<handle>.track()`.
@@ -169,61 +151,91 @@ var DepSession = class {
169
151
  constructor(consumerId, onChange) {
170
152
  this.consumerId = consumerId;
171
153
  this.onChange = onChange;
172
- this.entries = /* @__PURE__ */ new Map();
173
- this.subs = /* @__PURE__ */ new Map();
174
- this.lastReconciled = null;
175
- this.refId = `useBloc@${consumerId}:dep`;
154
+ this.primary = null;
155
+ this.primaryPaths = NO_PATHS$1;
156
+ this.entries = null;
157
+ this.subs = null;
158
+ this.reconciled = false;
159
+ this.lastPrimary = null;
160
+ this.lastPrimaryPaths = NO_PATHS$1;
161
+ this.lastEntries = null;
162
+ this.disarms = null;
163
+ }
164
+ get refId() {
165
+ return `useBloc@${this.consumerId}:dep`;
176
166
  }
177
167
  begin(primary, paths) {
178
- this.entries.clear();
179
- this.entries.set(primary, {
180
- kind: "primary",
181
- paths
182
- });
168
+ this.entries?.clear();
169
+ if (this.disarms !== null) this.disarms.length = 0;
170
+ this.primary = primary;
171
+ this.primaryPaths = paths;
183
172
  }
184
- record(dep, paths, Type, key, args) {
185
- const existing = this.entries.get(dep);
173
+ record(dep, paths, Type, key, args, disarm) {
174
+ (this.disarms ??= []).push(disarm);
175
+ if (dep === this.primary) {
176
+ this.primaryPaths = unionPaths(this.primaryPaths, paths);
177
+ return;
178
+ }
179
+ const entries = this.entries ??= /* @__PURE__ */ new Map();
180
+ const existing = entries.get(dep);
186
181
  if (existing !== void 0) existing.paths = unionPaths(existing.paths, paths);
187
- else this.entries.set(dep, {
188
- kind: "dep",
182
+ else entries.set(dep, {
189
183
  paths,
190
184
  Type,
191
185
  key,
192
186
  args
193
187
  });
194
188
  }
189
+ /** Stops every dep tracked this render from recording further reads. */
190
+ disarm() {
191
+ const disarms = this.disarms;
192
+ if (disarms === null) return;
193
+ for (const disarm of disarms) disarm();
194
+ disarms.length = 0;
195
+ }
195
196
  /** Forces the next `reconcile` to run in full. */
196
197
  invalidate() {
197
- this.lastReconciled = null;
198
+ this.reconciled = false;
198
199
  }
199
200
  isUnchanged() {
200
- const last = this.lastReconciled;
201
- if (last === null || last.size !== this.entries.size) return false;
202
- for (const [container, entry] of this.entries) {
201
+ if (!this.reconciled || this.lastPrimary !== this.primary || !(0, _dirtytalk_structural.pathSetEquals)(this.lastPrimaryPaths, this.primaryPaths)) return false;
202
+ const last = this.lastEntries;
203
+ const entries = this.entries;
204
+ if ((last?.size ?? 0) !== (entries?.size ?? 0)) return false;
205
+ if (last === null || entries === null) return true;
206
+ for (const [container, entry] of entries) {
203
207
  const prev = last.get(container);
204
208
  if (prev === void 0 || !sameEntry(prev, entry)) return false;
205
209
  }
206
210
  return true;
207
211
  }
208
212
  reconcile(registry) {
209
- const { consumerId, refId, subs, entries } = this;
210
- for (const [dep, sub] of subs) if (!entries.has(dep)) {
211
- this.drop(dep, sub);
212
- subs.delete(dep);
213
+ const { consumerId } = this;
214
+ const entries = this.entries;
215
+ this.reconciled = true;
216
+ this.lastPrimary = this.primary;
217
+ this.lastPrimaryPaths = this.primaryPaths;
218
+ this.lastEntries = entries === null || entries.size === 0 ? null : new Map(entries);
219
+ const subs = this.subs;
220
+ if (subs !== null) {
221
+ for (const [dep, sub] of subs) if (entries?.has(dep) !== true) {
222
+ this.drop(dep, sub);
223
+ subs.delete(dep);
224
+ }
213
225
  }
226
+ if (entries === null) return;
214
227
  for (const [dep, entry] of entries) {
215
- if (entry.kind === "primary") continue;
216
228
  if (dep.$blac.disposed) {
217
229
  this.onChange();
218
230
  continue;
219
231
  }
220
- const interest = expandWithAncestors(entry.paths, dep.interner);
221
232
  dep.registerConsumerPaths(consumerId, entry.paths);
222
- const existing = subs.get(dep);
233
+ const existing = subs?.get(dep);
223
234
  if (existing) {
224
- existing.interestRef.current = interest;
235
+ existing.subscription.setInterest(entry.paths);
225
236
  continue;
226
237
  }
238
+ const refId = this.refId;
227
239
  if (registry.acquire(entry.Type, entry.key, {
228
240
  canCreate: true,
229
241
  countRef: true,
@@ -234,33 +246,32 @@ var DepSession = class {
234
246
  this.onChange();
235
247
  continue;
236
248
  }
237
- const interestRef = { current: interest };
238
- const unsubscribe = dep.channel.subscribe(() => interestRef.current, this.onChange);
239
- subs.set(dep, {
240
- unsubscribe,
241
- interestRef,
249
+ const subscription = dep.subscribePaths(this.onChange);
250
+ subscription.setInterest(entry.paths);
251
+ (this.subs ??= /* @__PURE__ */ new Map()).set(dep, {
252
+ subscription,
242
253
  registry,
243
254
  Type: entry.Type,
244
255
  key: entry.key
245
256
  });
246
257
  }
247
- this.lastReconciled = new Map(entries);
248
258
  }
249
259
  dispose() {
250
- for (const [dep, sub] of this.subs) this.drop(dep, sub);
251
- this.subs.clear();
252
- this.lastReconciled = null;
260
+ const subs = this.subs;
261
+ if (subs !== null) {
262
+ for (const [dep, sub] of subs) this.drop(dep, sub);
263
+ subs.clear();
264
+ }
265
+ this.reconciled = false;
253
266
  }
254
267
  drop(dep, sub) {
255
- sub.unsubscribe();
268
+ sub.subscription.unsubscribe();
256
269
  dep.unregisterConsumer(this.consumerId);
257
270
  sub.registry.release(sub.Type, sub.key, false, this.refId);
258
271
  }
259
272
  };
260
273
  function sameEntry(a, b) {
261
- if (a.kind !== b.kind || !(0, _dirtytalk_structural.pathSetEquals)(a.paths, b.paths)) return false;
262
- if (a.kind === "primary" || b.kind === "primary") return true;
263
- return a.key === b.key && Object.is(a.args, b.args);
274
+ return (0, _dirtytalk_structural.pathSetEquals)(a.paths, b.paths) && a.key === b.key && Object.is(a.args, b.args);
264
275
  }
265
276
  function unionPaths(a, b) {
266
277
  if (a === _dirtytalk_structural.ALL_PATHS || b === _dirtytalk_structural.ALL_PATHS) return _dirtytalk_structural.ALL_PATHS;
@@ -306,11 +317,11 @@ function makeDepWrapper(handle, registry, session, tracked, onDepHandle) {
306
317
  const ref = { current: result.value };
307
318
  cache = {
308
319
  ref,
309
- proxy: buildTrackedProxy(dep, ref, onDepHandle).proxy
320
+ proxy: buildTrackedProxy(dep, ref, onDepHandle)
310
321
  };
311
322
  perDep.set(dep, cache);
312
323
  } else cache.ref.current = result.value;
313
- session.record(dep, result.paths, brand.Type, key, args);
324
+ session.record(dep, result.paths, brand.Type, key, args, result.disarm);
314
325
  return [result.value, cache.proxy];
315
326
  }
316
327
  };
@@ -379,7 +390,6 @@ function useBloc(BlocClass, options) {
379
390
  const registry = require_RegistryProvider.useRegistry();
380
391
  const consumerRef = (0, react.useRef)(null);
381
392
  const consumer = consumerRef.current ??= createConsumer();
382
- const consumerId = consumer.id;
383
393
  consumer.select = options?.select;
384
394
  consumer.onMount = options?.onMount;
385
395
  consumer.onUnmount = options?.onUnmount;
@@ -387,94 +397,18 @@ function useBloc(BlocClass, options) {
387
397
  consumer.providerArgs = useProvidedArgs(BlocClass);
388
398
  const effectiveArgs = resolveEffectiveArgs(consumer);
389
399
  const instanceKey = registry.resolveKey(BlocClass, void 0, effectiveArgs);
390
- const rebindNonce = consumer.rebindNonce;
391
- const { bloc, trackedBloc } = (0, react.useMemo)(() => {
392
- const instance = registry.acquire(BlocClass, instanceKey, {
393
- canCreate: true,
394
- countRef: false,
395
- args: effectiveArgs,
396
- sweepIfUnowned: true
397
- });
398
- const depWrappers = /* @__PURE__ */ new Map();
399
- const onDepHandle = (handle) => {
400
- const cached = depWrappers.get(handle);
401
- if (cached !== void 0) return cached;
402
- const wrapper = makeDepWrapper(handle, registry, consumer.deps, consumer.tracked, onDepHandle);
403
- depWrappers.set(handle, wrapper);
404
- return wrapper;
405
- };
406
- const { proxy } = buildTrackedProxy(instance, consumer.tracked, onDepHandle);
407
- return {
408
- bloc: instance,
409
- trackedBloc: proxy
410
- };
411
- }, [
412
- BlocClass,
413
- instanceKey,
414
- rebindNonce,
415
- registry
416
- ]);
417
- consumer.container = bloc;
418
- (0, react.useSyncExternalStore)((0, react.useMemo)(() => (onStoreChange) => {
419
- consumer.notify = onStoreChange;
420
- const container = consumer.container;
421
- const unsubscribe = container.channel.subscribe(() => consumer.interest, () => {
422
- if (consumer.isSelectMode) {
423
- const select = consumer.select;
424
- if (select) {
425
- const next = select(container.state, container);
426
- const prev = consumer.selection;
427
- if (prev !== null && shallowArrayEqual(prev, next)) return;
428
- consumer.selection = next;
429
- }
430
- }
431
- consumer.bump();
432
- });
433
- container.registerConsumerPaths(consumerId, consumer.paths);
434
- return () => {
435
- consumer.notify = noop;
436
- unsubscribe();
437
- container.unregisterConsumer(consumerId);
438
- };
439
- }, [
440
- BlocClass,
441
- instanceKey,
442
- consumerId,
443
- rebindNonce,
444
- registry
445
- ]), consumer.getSnapshot, consumer.getServerSnapshot);
446
- (0, react.useLayoutEffect)(() => {
447
- const live = registry.acquire(BlocClass, instanceKey, {
448
- canCreate: true,
449
- countRef: true,
450
- refId: consumer.primaryRefId,
451
- args: resolveEffectiveArgs(consumer)
452
- });
453
- consumer.ownedBloc = live;
454
- consumer.onMount?.(live);
455
- if (live !== bloc) {
456
- consumer.rebindNonce++;
457
- consumer.bump();
458
- }
459
- return () => {
460
- consumer.onUnmount?.(consumer.ownedBloc ?? bloc);
461
- registry.release(BlocClass, instanceKey, false, consumer.primaryRefId);
462
- };
463
- }, [
464
- BlocClass,
465
- instanceKey,
466
- consumerId,
467
- registry
468
- ]);
400
+ if (consumer.BlocClass !== BlocClass || consumer.instanceKey !== instanceKey || consumer.registry !== registry || consumer.boundNonce !== consumer.rebindNonce) bind(consumer, BlocClass, instanceKey, registry, effectiveArgs);
401
+ (0, react.useSyncExternalStore)(consumer.subscribe, consumer.getSnapshot, consumer.getSnapshot);
469
402
  const container = consumer.container;
470
403
  const rawState = container.state;
404
+ consumer.renderedState = rawState;
471
405
  const select = consumer.select;
472
406
  consumer.isSelectMode = select !== void 0;
473
407
  let state;
474
408
  if (select !== void 0) {
475
409
  state = rawState;
476
- consumer.selection = select(rawState, bloc);
477
- consumer.interest = _dirtytalk_structural.ALL_PATHS;
410
+ consumer.selection = select(rawState, container);
411
+ setInterest(consumer, _dirtytalk_structural.ALL_PATHS);
478
412
  } else {
479
413
  const tracked = (0, _dirtytalk_structural.trackRender)(rawState, container.interner, consumer.proxyCache ??= new _dirtytalk_structural.ProxyCache());
480
414
  state = tracked.value;
@@ -483,34 +417,27 @@ function useBloc(BlocClass, options) {
483
417
  consumer.disarm = tracked.disarm;
484
418
  consumer.deps.begin(container, tracked.paths);
485
419
  }
486
- (0, react.useLayoutEffect)(() => {
487
- consumer.tracked.current = null;
488
- const disarm = consumer.disarm;
489
- if (disarm !== null) {
490
- consumer.disarm = null;
491
- disarm();
492
- }
493
- const deps = consumer.deps;
494
- if (consumer.isSelectMode) {
495
- deps.invalidate();
496
- return;
497
- }
498
- if (deps.isUnchanged()) return;
499
- const primary = consumer.container;
500
- primary.registerConsumerPaths(consumerId, consumer.paths);
501
- consumer.interest = expandWithAncestors(consumer.paths, primary.interner);
502
- deps.reconcile(registry);
503
- });
504
- (0, react.useEffect)(() => () => consumer.deps.dispose(), [consumerId]);
505
- return [state, trackedBloc];
420
+ (0, react.useLayoutEffect)(consumer.commit);
421
+ (0, react.useLayoutEffect)(consumer.mount, NO_DEPS);
422
+ return [state, consumer.trackedBloc];
506
423
  }
507
424
  const noop = () => {};
425
+ const NO_PATHS = (0, _dirtytalk_structural.emptyPathSet)();
426
+ const NO_DEPS = [];
508
427
  function createConsumer() {
509
428
  const id = `useBloc-${nextConsumerId++}`;
510
429
  const consumer = {
511
430
  id,
512
431
  primaryRefId: `useBloc@${id}`,
432
+ BlocClass: null,
433
+ instanceKey: "",
434
+ registry: null,
513
435
  container: null,
436
+ trackedBloc: null,
437
+ subscribe: null,
438
+ boundNonce: 0,
439
+ rebindNonce: 0,
440
+ renderedState: void 0,
514
441
  version: 0,
515
442
  notify: noop,
516
443
  bump: () => {
@@ -518,12 +445,17 @@ function createConsumer() {
518
445
  consumer.notify();
519
446
  },
520
447
  getSnapshot: () => consumer.version,
521
- getServerSnapshot: () => consumer.version,
522
- interest: (0, _dirtytalk_structural.emptyPathSet)(),
523
- paths: (0, _dirtytalk_structural.emptyPathSet)(),
448
+ onChange: () => onChange(consumer),
449
+ unsubscribe: () => unsubscribe(consumer),
450
+ commit: () => commit(consumer),
451
+ mount: () => teardown,
452
+ interest: NO_PATHS,
453
+ subscription: null,
454
+ subscribedTo: null,
455
+ paths: NO_PATHS,
524
456
  isSelectMode: false,
525
457
  selection: null,
526
- deps: new DepSession(id, () => consumer.bump()),
458
+ deps: null,
527
459
  select: void 0,
528
460
  onMount: void 0,
529
461
  onUnmount: void 0,
@@ -532,11 +464,125 @@ function createConsumer() {
532
464
  tracked: { current: null },
533
465
  disarm: null,
534
466
  proxyCache: null,
535
- rebindNonce: 0,
467
+ ownedClass: null,
468
+ ownedKey: "",
469
+ ownedRegistry: null,
536
470
  ownedBloc: null
537
471
  };
472
+ const teardown = () => {
473
+ release(consumer);
474
+ consumer.deps.dispose();
475
+ };
476
+ consumer.deps = new DepSession(id, consumer.bump);
538
477
  return consumer;
539
478
  }
479
+ function bind(consumer, BlocClass, instanceKey, registry, args) {
480
+ const instance = registry.acquire(BlocClass, instanceKey, {
481
+ canCreate: true,
482
+ countRef: false,
483
+ args,
484
+ sweepIfUnowned: true
485
+ });
486
+ let depWrappers;
487
+ const onDepHandle = (handle) => {
488
+ depWrappers ??= /* @__PURE__ */ new Map();
489
+ const cached = depWrappers.get(handle);
490
+ if (cached !== void 0) return cached;
491
+ const wrapper = makeDepWrapper(handle, registry, consumer.deps, consumer.tracked, onDepHandle);
492
+ depWrappers.set(handle, wrapper);
493
+ return wrapper;
494
+ };
495
+ consumer.BlocClass = BlocClass;
496
+ consumer.instanceKey = instanceKey;
497
+ consumer.registry = registry;
498
+ consumer.boundNonce = consumer.rebindNonce;
499
+ consumer.container = instance;
500
+ consumer.trackedBloc = buildTrackedProxy(instance, consumer.tracked, onDepHandle);
501
+ consumer.subscribe = (onStoreChange) => subscribe(consumer, onStoreChange);
502
+ }
503
+ function subscribe(consumer, onStoreChange) {
504
+ consumer.notify = onStoreChange;
505
+ const container = consumer.container;
506
+ const subscription = container.subscribePaths(consumer.onChange);
507
+ subscription.setInterest(consumer.interest);
508
+ consumer.subscription = subscription;
509
+ consumer.subscribedTo = container;
510
+ container.registerConsumerPaths(consumer.id, consumer.paths);
511
+ return consumer.unsubscribe;
512
+ }
513
+ function unsubscribe(consumer) {
514
+ consumer.notify = noop;
515
+ consumer.subscription?.unsubscribe();
516
+ consumer.subscription = null;
517
+ consumer.subscribedTo?.unregisterConsumer(consumer.id);
518
+ consumer.subscribedTo = null;
519
+ }
520
+ function onChange(consumer) {
521
+ if (consumer.isSelectMode) {
522
+ const select = consumer.select;
523
+ const container = consumer.subscribedTo;
524
+ if (select && container !== null) {
525
+ const next = select(container.state, container);
526
+ const prev = consumer.selection;
527
+ if (prev !== null && shallowArrayEqual(prev, next)) return;
528
+ consumer.selection = next;
529
+ }
530
+ }
531
+ consumer.bump();
532
+ }
533
+ function claim(consumer) {
534
+ const { BlocClass, instanceKey, registry } = consumer;
535
+ if (consumer.ownedClass === BlocClass && consumer.ownedKey === instanceKey && consumer.ownedRegistry === registry) return;
536
+ release(consumer);
537
+ const live = registry.acquire(BlocClass, instanceKey, {
538
+ canCreate: true,
539
+ countRef: true,
540
+ refId: consumer.primaryRefId,
541
+ args: resolveEffectiveArgs(consumer)
542
+ });
543
+ consumer.ownedClass = BlocClass;
544
+ consumer.ownedKey = instanceKey;
545
+ consumer.ownedRegistry = registry;
546
+ consumer.ownedBloc = live;
547
+ consumer.onMount?.(live);
548
+ if (live !== consumer.container) {
549
+ consumer.rebindNonce++;
550
+ consumer.bump();
551
+ }
552
+ }
553
+ function release(consumer) {
554
+ const { ownedClass, ownedRegistry } = consumer;
555
+ if (ownedClass === null || ownedRegistry === null) return;
556
+ consumer.onUnmount?.(consumer.ownedBloc);
557
+ consumer.ownedClass = null;
558
+ consumer.ownedRegistry = null;
559
+ ownedRegistry.release(ownedClass, consumer.ownedKey, false, consumer.primaryRefId);
560
+ }
561
+ function commit(consumer) {
562
+ claim(consumer);
563
+ consumer.tracked.current = null;
564
+ const disarm = consumer.disarm;
565
+ if (disarm !== null) {
566
+ consumer.disarm = null;
567
+ disarm();
568
+ }
569
+ const deps = consumer.deps;
570
+ deps.disarm();
571
+ if (consumer.isSelectMode) {
572
+ deps.invalidate();
573
+ return;
574
+ }
575
+ const primary = consumer.container;
576
+ if (primary.state !== consumer.renderedState) consumer.bump();
577
+ if (deps.isUnchanged()) return;
578
+ primary.registerConsumerPaths(consumer.id, consumer.paths);
579
+ setInterest(consumer, consumer.paths);
580
+ deps.reconcile(consumer.registry);
581
+ }
582
+ const setInterest = (consumer, interest) => {
583
+ consumer.interest = interest;
584
+ consumer.subscription?.setInterest(interest);
585
+ };
540
586
  const resolveEffectiveArgs = (consumer) => consumer.ownArgs !== void 0 ? consumer.ownArgs : consumer.providerArgs;
541
587
  const shallowArrayEqual = (a, b) => {
542
588
  if (a === b) return true;