@expressive/mvc 0.87.0 → 0.89.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +19 -19
  2. package/dist/component.d.ts +28 -16
  3. package/dist/component.js +53 -72
  4. package/dist/component.js.map +1 -1
  5. package/dist/context.d.ts +28 -26
  6. package/dist/context.js +45 -27
  7. package/dist/context.js.map +1 -1
  8. package/dist/dispatch.d.ts +6 -1
  9. package/dist/dispatch.js +14 -6
  10. package/dist/dispatch.js.map +1 -1
  11. package/dist/field/def.d.ts +3 -3
  12. package/dist/field/def.js +7 -7
  13. package/dist/field/def.js.map +1 -1
  14. package/dist/field/get.d.ts +16 -16
  15. package/dist/field/get.js +21 -5
  16. package/dist/field/get.js.map +1 -1
  17. package/dist/field/has.d.ts +8 -8
  18. package/dist/field/has.js +3 -3
  19. package/dist/field/has.js.map +1 -1
  20. package/dist/field/map.d.ts +2 -2
  21. package/dist/field/map.js +2 -2
  22. package/dist/field/map.js.map +1 -1
  23. package/dist/field/ref.d.ts +8 -8
  24. package/dist/field/ref.js +3 -3
  25. package/dist/field/ref.js.map +1 -1
  26. package/dist/field/set.js +1 -1
  27. package/dist/field/set.js.map +1 -1
  28. package/dist/hot.d.ts +5 -8
  29. package/dist/hot.js +126 -18
  30. package/dist/hot.js.map +1 -1
  31. package/dist/index.d.ts +2 -3
  32. package/dist/index.js +4 -5
  33. package/dist/index.js.map +1 -1
  34. package/dist/jsx-dev-runtime.d.ts +1 -2
  35. package/dist/jsx-dev-runtime.js +1 -1
  36. package/dist/jsx-runtime.d.ts +77 -4
  37. package/dist/jsx-runtime.js +67 -2
  38. package/dist/jsx-runtime.js.map +1 -0
  39. package/dist/observable.d.ts +7 -4
  40. package/dist/observable.js +94 -27
  41. package/dist/observable.js.map +1 -1
  42. package/dist/state.d.ts +154 -112
  43. package/dist/state.js +115 -192
  44. package/dist/state.js.map +1 -1
  45. package/package.json +7 -5
  46. package/dist/_virtual/_rolldown/runtime.js +0 -18
  47. package/dist/caught.d.ts +0 -5237
  48. package/dist/caught.js +0 -64
  49. package/dist/caught.js.map +0 -1
  50. package/dist/runtime.d.ts +0 -72
  51. package/dist/runtime.js +0 -70
  52. package/dist/runtime.js.map +0 -1
package/dist/state.js CHANGED
@@ -1,6 +1,6 @@
1
- import { Caught } from "./caught.js";
1
+ import { REPORT } from "./dispatch.js";
2
2
  import { capture, event, listener, observer, queued, touch, watch } from "./observable.js";
3
- import { Context, join } from "./context.js";
3
+ import { Context, host, join } from "./context.js";
4
4
 
5
5
  //#region src/state.ts
6
6
  const define = Object.defineProperty;
@@ -8,7 +8,7 @@ const define = Object.defineProperty;
8
8
  const ID = /* @__PURE__ */ new WeakMap();
9
9
  /** Internal state assigned to states. */
10
10
  const STORE = /* @__PURE__ */ new WeakMap();
11
- /** States under construction - added on `new`, removed when activated or released.
11
+ /** Models under construction - added on `new`, removed when activated or released.
12
12
  * Also carries work to run at the deadline, which `def` uses to bound its registry. */
13
13
  const PENDING = /* @__PURE__ */ new Set();
14
14
  const SETUP = /* @__PURE__ */ new WeakMap();
@@ -22,35 +22,31 @@ const METHODS = /* @__PURE__ */ new WeakMap();
22
22
  const GETTERS = /* @__PURE__ */ new WeakMap();
23
23
  /** Replacement for a getter captured by live computed properties, for hot patching. */
24
24
  const LATEST = /* @__PURE__ */ new WeakMap();
25
- /** Method implementations replaced by a hot patch. */
26
- const PAST = /* @__PURE__ */ new WeakSet();
27
- /** Live instances, tracked once hot patching is enabled. */
28
- let LIVE;
29
- /** Bootstrapped subclasses of each class, tracked once hot patching is enabled. */
30
- const SUBCLASSES = /* @__PURE__ */ new WeakMap();
31
25
  /** Event every observer treats as watched, forcing a refresh after a hot patch. */
32
26
  const REFRESH = Symbol.for("@expressive/mvc.refresh");
33
27
  /** Stale flags for compute closures awaiting refresh on next access. */
34
28
  const STALE = /* @__PURE__ */ new WeakSet();
35
29
  /** Whether the deadline which drains `PENDING` is already queued for this tick. */
36
30
  let QUEUED = false;
37
- /** Global list each loaded copy of this module adds its `State` to, on first construction. */
31
+ /** Global list each loaded copy of this module adds its `Model` to, on first construction. */
38
32
  const COPIES = Symbol.for("@expressive/mvc");
39
33
  let ANNOUNCED = false;
40
- /** Adopters for managed properties which have held a child State. */
34
+ /** Adopters for managed properties which have held a child Model. */
41
35
  const ADOPT = /* @__PURE__ */ new WeakMap();
42
36
  const CHILDREN = /* @__PURE__ */ new WeakMap();
43
- var State = class State {
37
+ const OWNS = /* @__PURE__ */ new WeakMap();
38
+ const OWNED = /* @__PURE__ */ new WeakMap();
39
+ var Model = class Model {
44
40
  /**
45
41
  * Whether an instance activated with no enclosing context registers itself
46
42
  * to the process-global root, where `get()` can resolve it from anywhere.
47
43
  * `false` (the default) keeps a context-less instance fully functional but
48
44
  * private - not injectable, though it can still read declared globals. Opt in
49
- * with `static readonly global = true`; a resolver (see {@link State.Global})
45
+ * with `static readonly global = true`; a resolver (see {@link Model.Global})
50
46
  * makes the choice conditional. It must be declared per class - a subclass
51
47
  * that would inherit a global without its own declaration throws on
52
- * activation, so an accidental global (a forgotten `Provider`, an extended
53
- * global) cannot leak into the shared root.
48
+ * activation, so an accidental global (a forgotten `<Component for>`, an
49
+ * extended global) cannot leak into the shared root.
54
50
  */
55
51
  static global = false;
56
52
  constructor(...args) {
@@ -60,7 +56,8 @@ var State = class State {
60
56
  get(arg1, arg2, arg3) {
61
57
  const self = this.is;
62
58
  if (arg1 === void 0) return values(self);
63
- if (State.is(arg1)) return Context.get(self).get(arg1, arg2, arg3, self);
59
+ if (arg1 === Model) return typeof arg2 == "function" ? owned(self, arg2) : observed(this, arg1, owner(self, arg2));
60
+ if (Model.is(arg1)) return observed(this, arg1, Context.get(self).get(arg1, arg2, arg3, self));
64
61
  if (typeof arg1 == "function") return watch(self, unbind(arg1));
65
62
  if (typeof arg2 == "function") return callback(self, arg2, arg1);
66
63
  if (arg1 === null) return observer(self) === null;
@@ -78,7 +75,7 @@ var State = class State {
78
75
  return queued(self);
79
76
  }
80
77
  /**
81
- * Iterate over managed properties in this instance of State.
78
+ * Iterate over managed properties in this instance of Model.
82
79
  * Yeilds the key and current value for each property.
83
80
  */
84
81
  [Symbol.iterator]() {
@@ -105,30 +102,23 @@ var State = class State {
105
102
  static is(maybe) {
106
103
  return maybe === this || typeof maybe == "function" && maybe.prototype instanceof this;
107
104
  }
108
- /**
109
- * Register a lifecycle handler for this State and its subclasses.
110
- *
111
- * A bare function is per-instance setup run in the `prepare` phase (sugar for
112
- * `{ before }`); if it returns a function, that runs when the instance is
113
- * destroyed. Pass a {@link State.On} object to hook by cadence - `type`
114
- * (per-class, at bootstrap), `before` (per-instance, before `new()`), and
115
- * `after` (per-instance, at the `new()` slot).
116
- *
117
- * @returns Function to remove the handler.
118
- */
119
105
  static on(handler) {
106
+ if (typeof handler == "function") handler = { setup: handler };
120
107
  let setup = SETUP.get(this);
121
108
  if (!setup) SETUP.set(this, setup = /* @__PURE__ */ new Set());
122
109
  setup.add(handler);
123
110
  return () => setup.delete(handler);
124
111
  }
125
112
  };
126
- define(State.prototype, "toString", { value() {
113
+ define(Model.prototype, "toString", { value() {
127
114
  return ID.get(this.is);
128
115
  } });
129
- define(State, "toString", { value() {
116
+ define(Model, "toString", { value() {
130
117
  return this.name;
131
118
  } });
119
+ function observed(from, key, value) {
120
+ return value instanceof Model ? touch(from, key, value) : value;
121
+ }
132
122
  /** Register a user OnEvent callback, preserving `this` and `source`. */
133
123
  function callback(self, cb, select) {
134
124
  return listener(self, (key) => cb.call(self, key, self), select);
@@ -139,15 +129,14 @@ function callback(self, cb, select) {
139
129
  **/
140
130
  function init(state, ...args) {
141
131
  const T = state.constructor;
142
- if (T === State) throw new Error("Cannot create base State.");
132
+ if (T === Model) throw new Error("Cannot create base Model.");
143
133
  if (!ANNOUNCED) {
144
134
  ANNOUNCED = true;
145
- (globalThis[COPIES] ||= []).push(State);
135
+ (globalThis[COPIES] ||= []).push(Model);
146
136
  }
147
137
  const { before, after } = bootstrap(T);
148
138
  ID.set(state, `${T}-${uid()}`);
149
139
  STORE.set(state, {});
150
- LIVE?.add(new WeakRef(state));
151
140
  function observe() {
152
141
  for (const key in state) {
153
142
  const desc = Object.getOwnPropertyDescriptor(state, key) || {};
@@ -162,13 +151,20 @@ function init(state, ...args) {
162
151
  const g = type.global;
163
152
  if (!(typeof g == "function" ? g(state) : g)) return;
164
153
  if (!Object.prototype.hasOwnProperty.call(type, "global")) throw new Error(`${state} would register as a global by inheritance alone - re-declare \`static global\` on ${type.name} (\`true\` to keep it, \`false\` to opt out).`);
154
+ for (let T = type; T !== Model; T = Object.getPrototypeOf(T)) {
155
+ const found = Context.root.get(T, false);
156
+ if (found && (T === type || found.constructor === T)) throw new Error(`Cannot register ${state} as a global - ${found} already exists in root. Destroy the existing instance first, or provide additional ones via explicit context.`);
157
+ }
165
158
  return Context.root.add(state);
166
159
  }
167
160
  listener(state, (key) => {
168
161
  const rest = trailing(state);
169
162
  PENDING.delete(state);
170
163
  if (key === null) return null;
171
- parent(state, null);
164
+ if (!PARENT.has(state)) parent(state, host(state) || null);
165
+ const above = PARENT.get(state);
166
+ const owns = above && (OWNS.get(above) || OWNS.set(above, /* @__PURE__ */ new Set()).get(above));
167
+ if (owns) listener(state, () => void owns.delete(state), null);
172
168
  const queue = [
173
169
  ...before,
174
170
  observe,
@@ -181,12 +177,16 @@ function init(state, ...args) {
181
177
  for (let i = 0; i < queue.length; i++) {
182
178
  const arg = queue[i];
183
179
  const out = typeof arg == "function" ? arg.call(state, state) : arg;
184
- if (out instanceof Promise) out.catch((err) => report(new Caught.Init(state, err)));
180
+ if (out instanceof Promise) out.catch((err) => report("setup", state, err));
185
181
  else if (Array.isArray(out)) queue.splice(i + 1, 0, ...out);
186
182
  else if (typeof out == "function") listener(state, out, null);
187
183
  else if (typeof out == "object") assign(state, out, true);
188
184
  }
189
185
  });
186
+ if (owns) {
187
+ owns.add(state);
188
+ OWNED.get(above)?.forEach((cb) => cb(state));
189
+ }
190
190
  let end = rest.length;
191
191
  while (end-- > 0 && PENDING.has(rest[end]));
192
192
  for (let i = 0; i < end; i++) PENDING.delete(rest[i]);
@@ -197,7 +197,7 @@ function init(state, ...args) {
197
197
  queueMicrotask(() => {
198
198
  QUEUED = false;
199
199
  for (const item of PENDING) if (typeof item == "function") item();
200
- else report(new Caught.Inactive(item));
200
+ else report("unused", item, /* @__PURE__ */ new Error(`${item} was constructed but never activated.`));
201
201
  PENDING.clear();
202
202
  });
203
203
  }
@@ -216,7 +216,7 @@ function unmanaged(state, key, value) {
216
216
  /**
217
217
  * Apply instructions and inherited event listeners. Ensure class metadata is ready.
218
218
  *
219
- * @param T - State class to bootstrap.
219
+ * @param T - Model class to bootstrap.
220
220
  * @return Array of init functions to run on instance, in order of class hierarchy.
221
221
  */
222
222
  function bootstrap(T) {
@@ -228,29 +228,22 @@ function bootstrap(T) {
228
228
  let getters = /* @__PURE__ */ new Map();
229
229
  while (true) {
230
230
  chain.unshift(T);
231
- if (T === State) break;
231
+ if (T === Model) break;
232
232
  T = Object.getPrototypeOf(T);
233
233
  }
234
234
  for (const type of chain) {
235
- for (const handler of SETUP.get(type) || []) if (typeof handler == "function") before.add(handler);
236
- else {
237
- if (handler.before) before.add(handler.before);
238
- if (handler.after) after.add(handler.after);
235
+ for (const handler of SETUP.get(type) || []) {
236
+ if (handler.setup) before.add(handler.setup);
237
+ if (handler.ready) after.add(handler.ready);
239
238
  if (handler.type) onType.add(handler.type);
240
239
  }
241
- if (type === State) continue;
240
+ if (type === Model) continue;
242
241
  if (METHODS.has(type)) {
243
242
  keys = METHODS.get(type);
244
243
  getters = GETTERS.get(type);
245
244
  continue;
246
245
  }
247
246
  for (const setupType of onType) setupType(type);
248
- if (LIVE) {
249
- const parent = Object.getPrototypeOf(type);
250
- let children = SUBCLASSES.get(parent);
251
- if (!children) SUBCLASSES.set(parent, children = /* @__PURE__ */ new Set());
252
- children.add(type);
253
- }
254
247
  METHODS.set(type, keys = new Map(keys));
255
248
  GETTERS.set(type, getters = new Map(getters));
256
249
  classify(type, keys, getters);
@@ -295,6 +288,7 @@ function classify(type, keys, getters) {
295
288
  writable: true,
296
289
  configurable: true
297
290
  });
291
+ for (const handler of stages(is.constructor, "method")) handler.call(is, key, bound, is);
298
292
  return bound;
299
293
  }
300
294
  UNBIND.set(bind, value);
@@ -305,6 +299,12 @@ function classify(type, keys, getters) {
305
299
  });
306
300
  }
307
301
  }
302
+ /** Handlers of one stage along the class chain - ancestor first, in registration order, each once. */
303
+ function stages(T, key) {
304
+ const found = T === Model ? /* @__PURE__ */ new Set() : stages(Object.getPrototypeOf(T), key);
305
+ for (const handler of SETUP.get(T) || []) if (handler[key]) found.add(handler[key]);
306
+ return found;
307
+ }
308
308
  /**
309
309
  * Install a reactive computed property on a state instance, derived from a prototype
310
310
  * getter or an arity-bearing `set` factory.
@@ -317,6 +317,8 @@ function compute(getter, key) {
317
317
  const store = STORE.get(this);
318
318
  let reset;
319
319
  let isAsync;
320
+ let suspended = false;
321
+ let waiting;
320
322
  let proxy;
321
323
  const connect = () => {
322
324
  reset = watch(this, (current) => {
@@ -332,15 +334,27 @@ function compute(getter, key) {
332
334
  };
333
335
  const run = (initial) => {
334
336
  let next;
337
+ waiting = void 0;
335
338
  try {
336
339
  next = latest(getter).call(proxy, proxy);
337
340
  } catch (err) {
338
- if (initial) {
341
+ if (err instanceof Promise) {
342
+ if (initial) {
343
+ suspended = true;
344
+ throw err;
345
+ }
346
+ const retry = () => {
347
+ if (waiting === err && observer(this) !== null) run();
348
+ };
349
+ waiting = err;
350
+ err.then(retry, retry);
351
+ if (suspended) return;
352
+ } else if (initial) {
339
353
  console.warn(`An exception was thrown while initializing ${this}.${key}.`);
340
354
  throw err;
341
- }
342
- if (!(err instanceof Promise)) report(new Caught.Getter(this, key, err));
355
+ } else report("getter", this, err, key);
343
356
  }
357
+ suspended = false;
344
358
  update(this, key, next, !isAsync);
345
359
  };
346
360
  apply(this, key, {
@@ -353,7 +367,7 @@ function compute(getter, key) {
353
367
  isAsync = true;
354
368
  }
355
369
  if (STALE.delete(run)) run();
356
- return access(this, key, !proxy);
370
+ return access(this, key, suspended);
357
371
  }
358
372
  }, true);
359
373
  }
@@ -362,7 +376,7 @@ function compute(getter, key) {
362
376
  * If the property already is managed, config will only accept value.
363
377
  * If the property does not exist, it will be created and made reactive.
364
378
  *
365
- * @param state - State to apply property to.
379
+ * @param state - Model to apply property to.
366
380
  * @param key - Property to define or update.
367
381
  * @param config - Descriptor config with value, get, set, enumerable, and/or destroy.
368
382
  * @param silent - If an update does occur, listeners will not be refreshed automatically.
@@ -420,7 +434,7 @@ function child(state) {
420
434
  listener(state, reset, null);
421
435
  return (value) => {
422
436
  reset();
423
- if (!(value instanceof State)) return;
437
+ if (!(value instanceof Model)) return;
424
438
  if (parent(value, state)) {
425
439
  const remove = join(state, value);
426
440
  cleanup = () => {
@@ -435,18 +449,18 @@ function child(state) {
435
449
  };
436
450
  }
437
451
  /**
438
- * Pending States constructed after this one - in a parent, the products of
452
+ * Pending Models constructed after this one - in a parent, the products of
439
453
  * its own initializers, until the last one it kept.
440
454
  */
441
455
  function trailing(state) {
442
456
  const rest = [];
443
457
  let seen = false;
444
458
  for (const item of PENDING) if (!seen) seen = item === state;
445
- else if (item instanceof State) rest.push(item);
459
+ else if (item instanceof Model) rest.push(item);
446
460
  return rest;
447
461
  }
448
462
  /**
449
- * Report States adopted by a parent - those already held, then each one
463
+ * Report Models adopted by a parent - those already held, then each one
450
464
  * claimed later. Returns a callback to stop watching.
451
465
  */
452
466
  function children(state, callback) {
@@ -454,13 +468,33 @@ function children(state, callback) {
454
468
  const keys = ADOPT.get(state);
455
469
  if (keys) for (const key of keys.keys()) {
456
470
  const value = store[key];
457
- if (value instanceof State) callback(value);
471
+ if (value instanceof Model) callback(value);
458
472
  }
459
473
  let set = CHILDREN.get(state);
460
474
  if (!set) CHILDREN.set(state, set = /* @__PURE__ */ new Set());
461
475
  set.add(callback);
462
476
  return () => set.delete(callback);
463
477
  }
478
+ function owner(state, required) {
479
+ const found = PARENT.get(state);
480
+ if (found || required === false) return found || void 0;
481
+ throw new Error(`${state} has no owner.`);
482
+ }
483
+ /**
484
+ * Report Models owned by this one - those active now, then each one as it
485
+ * activates. A function returned by `callback` runs when that Model is destroyed.
486
+ */
487
+ function owned(state, callback) {
488
+ function each(child) {
489
+ const done = callback(child);
490
+ if (typeof done == "function") listener(child, () => void done(), null);
491
+ }
492
+ OWNS.get(state)?.forEach(each);
493
+ let set = OWNED.get(state);
494
+ if (!set) OWNED.set(state, set = /* @__PURE__ */ new Set());
495
+ set.add(each);
496
+ return () => void set.delete(each);
497
+ }
464
498
  /** Currently accumulating export. Stores real values of placeholder properties such as ref() or child states. */
465
499
  let EXPORT;
466
500
  function values(state) {
@@ -524,15 +558,16 @@ function assign(state, data, silent) {
524
558
  *
525
559
  * This is used internally to update properties, but can also be used to update properties which are not managed by state, or to update values without triggering setters.
526
560
  *
527
- * A destroyed state reports the write - thrown to the writer unless a `catch` handler takes it - and returns `false`; `silent` skips both, and dispatch.
561
+ * A destroyed state stores the write without dispatch, reports it unless `silent`, and returns `false`.
528
562
  */
529
563
  function update(state, key, value, silent, own) {
564
+ const store = STORE.get(state);
565
+ if (value instanceof Model) value = value.is;
530
566
  if (observer(state) === null) {
531
- if (!silent) report(new Caught.Destroyed(state, String(key)), true);
567
+ if (!silent) report("dead", state, /* @__PURE__ */ new Error(`Tried to update ${state}.${String(key)} but state is destroyed.`), String(key));
568
+ store[key] = value;
532
569
  return false;
533
570
  }
534
- const store = STORE.get(state);
535
- if (value instanceof State) value = value.is;
536
571
  if (key in store && value === store[key]) return false;
537
572
  store[key] = value;
538
573
  if (!silent) event(state, key);
@@ -540,55 +575,38 @@ function update(state, key, value, silent, own) {
540
575
  return true;
541
576
  }
542
577
  /**
543
- * Pass a caught error along `catch` handlers - most-derived class first, last registered
544
- * first - until one returns nothing. Passed off the end, a warning logs and anything
545
- * else is thrown - to the caller when `sync`, else uncaught. So is a handler's throw,
546
- * and one wrapping an error a handler already threw escapes that error unreported.
578
+ * Pass an error along `catch` handlers - most-derived class first, last registered
579
+ * first, one on several classes once at the outermost - until one returns nothing. Passed off
580
+ * the end, a destroyed write outputs nothing, `unused` warns, anything else escapes uncaught;
581
+ * so does a handler's throw.
547
582
  */
548
- function report(caught, sync) {
549
- const handlers = /* @__PURE__ */ new Set();
550
- let error = caught;
551
- if (caught.cause instanceof Caught) return escape(caught.cause);
552
- for (let T = caught.state.constructor;; T = Object.getPrototypeOf(T)) {
553
- for (const handler of [...SETUP.get(T) || []].reverse()) if (typeof handler == "object" && handler.catch) handlers.add(handler.catch);
554
- if (T === State) break;
555
- }
583
+ function report(kind, owner, error, key) {
584
+ const state = owner instanceof Model ? owner : owner && PARENT.get(owner);
585
+ if (!state) return REPORT.error(error);
556
586
  try {
557
- for (const handler of handlers) if (!(error = handler.call(caught.state, error))) return;
587
+ for (const handler of [...stages(state.constructor, "catch")].reverse()) if ((error = handler.call(state, error, kind, key)) === void 0) return;
588
+ if (kind == "unused") console.warn(error);
589
+ else if (kind != "dead") REPORT.error(error);
558
590
  } catch (err) {
559
- if (sync) throw err;
560
- return escape(err);
591
+ REPORT.error(err);
561
592
  }
562
- if (error.warning) console.warn(error);
563
- else if (sync) throw error;
564
- else escape(error);
565
- }
566
- function escape(err) {
567
- queueMicrotask(() => {
568
- throw err;
569
- });
570
- }
571
- /** Error thrown by a handler replaying in dispatch, attributed to the State which queued it. */
572
- function fault(err, owner) {
573
- const state = owner instanceof State ? owner : owner && PARENT.get(owner);
574
- if (state) report(new Caught.Effect(state, err));
575
- else escape(err);
576
593
  }
594
+ REPORT.as = report;
577
595
  /**
578
596
  * Hand a value stored by an owning writer to that property's adopter,
579
- * creating one the first time a State is stored there. A property which has
580
- * held a State keeps its adopter, so a later non-State value releases the
597
+ * creating one the first time a Model is stored there. A property which has
598
+ * held a Model keeps its adopter, so a later non-Model value releases the
581
599
  * previous child.
582
600
  */
583
601
  function adopt(state, key, value) {
584
602
  let keys = ADOPT.get(state);
585
603
  if (!keys) {
586
- if (!(value instanceof State)) return;
604
+ if (!(value instanceof Model)) return;
587
605
  ADOPT.set(state, keys = /* @__PURE__ */ new Map());
588
606
  }
589
607
  let claim = keys.get(key);
590
608
  if (!claim) {
591
- if (!(value instanceof State)) return;
609
+ if (!(value instanceof Model)) return;
592
610
  keys.set(key, claim = child(state));
593
611
  }
594
612
  claim(value);
@@ -598,101 +616,6 @@ function latest(getter) {
598
616
  for (let next; next = LATEST.get(getter);) getter = next;
599
617
  return getter;
600
618
  }
601
- /** Begin tracking live instances, so a hot patch can reach them. */
602
- function track() {
603
- LIVE ||= /* @__PURE__ */ new Set();
604
- }
605
- /**
606
- * Move the members of `next` onto `prev`, which keeps its identity. Returns the
607
- * live instances of `prev`, each needing a refresh.
608
- */
609
- function patch(prev, next, own) {
610
- const proto = prev.prototype;
611
- const incoming = Object.getOwnPropertyDescriptors(next.prototype);
612
- const keys = METHODS.get(prev);
613
- const getters = GETTERS.get(prev);
614
- const methods = /* @__PURE__ */ new Map();
615
- const knownKeys = new Set(keys?.keys());
616
- const knownGetters = new Set(getters?.keys());
617
- let setup = SETUP.get(prev);
618
- for (const handler of own) setup.delete(handler);
619
- for (const handler of handlers(next)) {
620
- if (!setup) SETUP.set(prev, setup = /* @__PURE__ */ new Set());
621
- setup.add(handler);
622
- }
623
- for (const key of Reflect.ownKeys(next)) {
624
- if (key == "prototype" || key == "length" || key == "name") continue;
625
- if (Object.getOwnPropertyDescriptor(prev, key)?.configurable !== false) define(prev, key, Object.getOwnPropertyDescriptor(next, key));
626
- }
627
- const removed = /* @__PURE__ */ new Set();
628
- for (const key of Object.getOwnPropertyNames(proto)) if (key != "constructor" && !(key in incoming)) {
629
- const bind = keys?.get(key);
630
- if (bind && Object.getOwnPropertyDescriptor(proto, key).get === bind) {
631
- PAST.add(UNBIND.get(bind));
632
- keys.delete(key);
633
- }
634
- removed.add(key);
635
- Reflect.deleteProperty(proto, key);
636
- getters?.delete(key);
637
- }
638
- for (const [key, desc] of Object.entries(incoming)) {
639
- if (key == "constructor") continue;
640
- const current = Object.getOwnPropertyDescriptor(proto, key);
641
- if (typeof desc.value == "function") methods.set(key, desc.value);
642
- if (current?.configurable === false) {
643
- if (current.writable) proto[key] = desc.value;
644
- continue;
645
- }
646
- if (current?.get && keys?.get(key) === current.get) PAST.add(UNBIND.get(current.get));
647
- const getter = getters?.get(key);
648
- if (getter) LATEST.set(getter, desc.get);
649
- define(proto, key, {
650
- ...desc,
651
- configurable: true
652
- });
653
- }
654
- if (keys) {
655
- for (let T = prev;; T = Object.getPrototypeOf(T)) {
656
- for (const handler of SETUP.get(T) || []) if (typeof handler == "object" && handler.type) handler.type(prev);
657
- if (T === State) break;
658
- }
659
- classify(prev, keys, getters);
660
- }
661
- const live = [];
662
- for (const ref of LIVE) {
663
- const state = ref.deref();
664
- if (!state) LIVE.delete(ref);
665
- else if (state instanceof prev) live.push(state);
666
- }
667
- const descendants = new Set([prev, ...live.map((state) => state.constructor)]);
668
- for (const type of descendants) for (const child of SUBCLASSES.get(type) || []) descendants.add(child);
669
- descendants.delete(prev);
670
- for (const type of descendants) {
671
- const inherit = METHODS.get(type);
672
- const computed = GETTERS.get(type);
673
- for (const [key, bind] of keys) if (!knownKeys.has(key) && !inherit.has(key)) inherit.set(key, bind);
674
- for (const [key, get] of getters) if (!knownGetters.has(key) && !computed.has(key)) computed.set(key, get);
675
- for (const key of removed) if (!(key in type.prototype)) {
676
- inherit.delete(key);
677
- computed.delete(key);
678
- }
679
- }
680
- for (const state of live) {
681
- for (const [key, value] of methods) {
682
- const desc = Object.getOwnPropertyDescriptor(state, key);
683
- if (!desc) continue;
684
- if (desc.set) desc.set.call(state, value);
685
- else if (PAST.has(UNBIND.get(desc.value))) delete state[key];
686
- }
687
- for (const key of removed) if (PAST.has(UNBIND.get(Object.getOwnPropertyDescriptor(state, key)?.value))) delete state[key];
688
- for (const [key, get] of GETTERS.get(state.constructor)) if (!knownGetters.has(key) && get === getters.get(key)) compute.call(state, get, key);
689
- }
690
- return live;
691
- }
692
- /** Lifecycle handlers registered on a class itself. */
693
- function handlers(type) {
694
- return [...SETUP.get(type) || []];
695
- }
696
619
  /** Random alphanumberic of length 6; always starts with a letter. */
697
620
  function uid() {
698
621
  return (.278 + Math.random() * .722).toString(36).substring(2, 8).toUpperCase();
@@ -708,5 +631,5 @@ function parent(child, value) {
708
631
  }
709
632
 
710
633
  //#endregion
711
- export { PENDING, STORE, State, access, apply, children, compute, event, fault, handlers, parent, patch, track, trailing, uid, unbind, update };
634
+ export { GETTERS, LATEST, METHODS, Model, PENDING, SETUP, STORE, UNBIND, access, adopt, apply, children, classify, compute, event, owned, parent, trailing, uid, unbind, update };
712
635
  //# sourceMappingURL=state.js.map