@expressive/mvc 1.0.0-beta.41 → 1.0.0-beta.44

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/lib/index.esm.js CHANGED
@@ -17,7 +17,7 @@ function issues(register) {
17
17
  return Library;
18
18
  }
19
19
 
20
- const Oops$d = issues({
20
+ const Oops$c = issues({
21
21
  BadEffectCallback: () => `Callback for effect-callback may only return a function.`
22
22
  });
23
23
  const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
@@ -34,9 +34,6 @@ function defineLazy(object, property, init) {
34
34
  }
35
35
  });
36
36
  }
37
- function setAlias(func, displayName) {
38
- assign(func, { displayName });
39
- }
40
37
  function createEffect(callback) {
41
38
  let unSet;
42
39
  return function (value) {
@@ -46,7 +43,7 @@ function createEffect(callback) {
46
43
  if (unSet instanceof Promise)
47
44
  unSet = undefined;
48
45
  if (unSet && typeof unSet !== "function")
49
- throw Oops$d.BadEffectCallback();
46
+ throw Oops$c.BadEffectCallback();
50
47
  };
51
48
  }
52
49
  function createValueEffect(callback) {
@@ -62,8 +59,28 @@ function createValueEffect(callback) {
62
59
  if (typeof out == "function")
63
60
  unSet = out;
64
61
  else
65
- throw Oops$d.BadEffectCallback();
62
+ throw Oops$c.BadEffectCallback();
63
+ };
64
+ }
65
+ function suspenseBoundary(fn) {
66
+ const retry = (err) => {
67
+ if (err instanceof Promise)
68
+ return err.then(compute);
69
+ else
70
+ throw err;
66
71
  };
72
+ const compute = () => {
73
+ try {
74
+ const output = fn();
75
+ return output instanceof Promise
76
+ ? output.catch(retry)
77
+ : output;
78
+ }
79
+ catch (err) {
80
+ return retry(err);
81
+ }
82
+ };
83
+ return compute();
67
84
  }
68
85
 
69
86
  const UPDATE = new WeakMap();
@@ -76,8 +93,215 @@ function applyUpdate(subject, keys) {
76
93
  };
77
94
  }
78
95
 
79
- const Oops$c = issues({
80
- StrictUpdate: (expected) => `Strict update() did ${expected ? "not " : ""}find pending updates.`,
96
+ class Subscriber {
97
+ constructor(target, onUpdate) {
98
+ this.onUpdate = onUpdate;
99
+ this.active = false;
100
+ this.dependant = new Set();
101
+ this.watch = {};
102
+ const parent = target instanceof Controller
103
+ ? target : control(target);
104
+ const proxy = create(parent.proxy);
105
+ let reset;
106
+ define(proxy, LOCAL, this);
107
+ defineProperty(this, "proxy", {
108
+ configurable: true,
109
+ get() {
110
+ if (reset)
111
+ setTimeout(reset, 0);
112
+ return proxy;
113
+ }
114
+ });
115
+ const release = parent.addListener(key => {
116
+ const handler = this.watch[key];
117
+ if (!handler || !this.active)
118
+ return;
119
+ if (typeof handler == "function")
120
+ handler();
121
+ const notify = this.onUpdate(key, parent);
122
+ const getWhy = (keys) => {
123
+ reset = applyUpdate(proxy, keys.filter(k => k in this.watch));
124
+ };
125
+ if (notify) {
126
+ parent.requestUpdate(getWhy);
127
+ parent.requestUpdate(notify);
128
+ }
129
+ });
130
+ this.commit = () => {
131
+ this.active = true;
132
+ this.dependant.forEach(x => x.commit());
133
+ return this.release;
134
+ };
135
+ this.release = () => {
136
+ this.dependant.forEach(x => x.release());
137
+ release();
138
+ };
139
+ }
140
+ }
141
+
142
+ const Oops$b = issues({
143
+ ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
144
+ });
145
+ function suspend(source, key) {
146
+ const error = Oops$b.ValueNotReady(source.subject, key);
147
+ const promise = new Promise(resolve => {
148
+ const release = source.addListener(forKey => {
149
+ if (forKey == key)
150
+ return () => {
151
+ if (source.state[key] !== undefined) {
152
+ release();
153
+ resolve();
154
+ }
155
+ };
156
+ });
157
+ });
158
+ return Object.assign(promise, {
159
+ toString: () => String(error),
160
+ name: "Suspense",
161
+ message: error.message,
162
+ stack: error.stack
163
+ });
164
+ }
165
+
166
+ const Oops$a = issues({
167
+ BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
168
+ PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
169
+ ComputeFailed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
170
+ ComputedEarly: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
171
+ });
172
+ const INIT = new WeakSet();
173
+ const INFO = new WeakMap();
174
+ const USED = new WeakMap();
175
+ const KEYS = new WeakMap();
176
+ function from(source, arg1, arg2) {
177
+ return apply(function from(key) {
178
+ const parent = this;
179
+ const { subject, state } = this;
180
+ let getSource;
181
+ let required = arg2 === true || arg1 === true;
182
+ if (typeof arg1 == "boolean")
183
+ arg1 = undefined;
184
+ // Easy mistake, using a peer, will always be unresolved.
185
+ if (typeof source == "symbol")
186
+ throw Oops$a.PeerNotAllowed(subject, key);
187
+ // replace source controller in-case it is different
188
+ if (typeof source == "object")
189
+ getSource = () => control(source);
190
+ // specifically an arrow function (getter factory)
191
+ else if (!source.prototype) {
192
+ arg1 = source.call(subject, key);
193
+ getSource = () => this;
194
+ }
195
+ // Regular function is too ambiguous so not allowed.
196
+ else
197
+ throw Oops$a.BadComputedSource(subject, key, source);
198
+ let sub;
199
+ const setter = arg1;
200
+ const info = { key, parent, priority: 1 };
201
+ let register = USED.get(parent);
202
+ if (!register) {
203
+ register = new Map();
204
+ USED.set(parent, register);
205
+ }
206
+ register.set(key, info);
207
+ function compute(initial) {
208
+ try {
209
+ return setter.call(sub.proxy, sub.proxy);
210
+ }
211
+ catch (err) {
212
+ Oops$a.ComputeFailed(subject, key, !!initial).warn();
213
+ throw err;
214
+ }
215
+ }
216
+ function update() {
217
+ let value;
218
+ try {
219
+ value = compute(false);
220
+ }
221
+ catch (e) {
222
+ console.error(e);
223
+ }
224
+ finally {
225
+ if (state[key] !== value) {
226
+ parent.update(key, value);
227
+ return value;
228
+ }
229
+ }
230
+ }
231
+ function defer(_key, from) {
232
+ let pending = KEYS.get(from);
233
+ if (!pending)
234
+ KEYS.set(from, pending = []);
235
+ if (info.parent !== from)
236
+ update();
237
+ else {
238
+ const after = pending.findIndex(peer => (info.priority > INFO.get(peer).priority));
239
+ pending.splice(after + 1, 0, update);
240
+ }
241
+ }
242
+ function create(early) {
243
+ sub = new Subscriber(getSource(), defer);
244
+ defineProperty(state, key, {
245
+ value: undefined,
246
+ writable: true
247
+ });
248
+ try {
249
+ return state[key] = compute(true);
250
+ }
251
+ catch (e) {
252
+ if (early)
253
+ Oops$a.ComputedEarly(key).warn();
254
+ throw e;
255
+ }
256
+ finally {
257
+ sub.commit();
258
+ for (const key in sub.watch) {
259
+ const peer = register.get(key);
260
+ if (peer && peer.priority >= info.priority)
261
+ info.priority = peer.priority + 1;
262
+ }
263
+ }
264
+ }
265
+ INIT.add(create);
266
+ INFO.set(update, info);
267
+ defineProperty(state, key, {
268
+ get: create,
269
+ configurable: true,
270
+ enumerable: true
271
+ });
272
+ return () => {
273
+ const value = parent.state[key];
274
+ if (value === undefined && required)
275
+ throw suspend(this, key);
276
+ return value;
277
+ };
278
+ });
279
+ }
280
+ function ensure(on, keys) {
281
+ for (const key of keys) {
282
+ const desc = getOwnPropertyDescriptor(on.state, key);
283
+ const getter = desc && desc.get;
284
+ if (INIT.has(getter))
285
+ getter(true);
286
+ }
287
+ }
288
+ function flush(on) {
289
+ const handled = on.frame;
290
+ const pending = KEYS.get(on);
291
+ if (!pending)
292
+ return;
293
+ while (pending.length) {
294
+ const why = [...handled];
295
+ const compute = pending.shift();
296
+ const { key } = INFO.get(compute);
297
+ if (!handled.has(key))
298
+ compute(why);
299
+ }
300
+ KEYS.delete(on);
301
+ }
302
+
303
+ const Oops$9 = issues({
304
+ StrictUpdate: () => `Strict update() did not find pending updates.`,
81
305
  NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
82
306
  });
83
307
  const READY = new WeakSet();
@@ -107,7 +331,9 @@ class Controller {
107
331
  return;
108
332
  let onGet;
109
333
  let onSet;
334
+ let set;
110
335
  let enumerable;
336
+ let suspense;
111
337
  const instruction = Pending.get(entry);
112
338
  if (instruction) {
113
339
  Pending.delete(entry);
@@ -120,33 +346,35 @@ class Controller {
120
346
  state[key] = desc.value;
121
347
  onSet = desc.set;
122
348
  onGet = desc.get;
349
+ suspense = desc.suspense;
123
350
  enumerable = desc.enumerable;
124
351
  }
125
352
  }
126
353
  else
127
354
  state[key] = entry;
128
- const set = onSet !== false
129
- ? this.ref(key, onSet)
130
- : undefined;
131
- function get() {
132
- const local = this[LOCAL];
355
+ if (onSet !== false)
356
+ set = this.ref(key, onSet);
357
+ const get = (local) => {
358
+ if (!(key in state) && suspense)
359
+ throw suspend(this, key);
133
360
  const value = state[key];
134
- if (local && !local.watch[key])
135
- local.watch[key] = true;
136
- return onGet ? onGet(value, local) : value;
137
- }
138
- setAlias(get, `tap ${key}`);
361
+ if (onGet)
362
+ return local
363
+ ? onGet(value, local)
364
+ : onGet(value);
365
+ return value;
366
+ };
139
367
  defineProperty(subject, key, {
140
- enumerable,
141
- set,
142
- get: onGet
143
- ? () => onGet(state[key])
144
- : () => state[key]
368
+ enumerable, set, get
145
369
  });
146
370
  defineProperty(proxy, key, {
147
- enumerable,
148
- set,
149
- get
371
+ enumerable, set,
372
+ get() {
373
+ const local = this[LOCAL];
374
+ if (local && !local.watch[key])
375
+ local.watch[key] = true;
376
+ return get(local);
377
+ }
150
378
  });
151
379
  }
152
380
  ref(key, handler) {
@@ -206,17 +434,17 @@ class Controller {
206
434
  this.waiting.add(arg);
207
435
  return;
208
436
  }
209
- if (typeof arg == "boolean" && arg !== this.frame.size > 0)
210
- return Promise.reject(Oops$c.StrictUpdate(arg));
437
+ if (arg === true && this.frame.size < 1)
438
+ return Promise.reject(Oops$9.StrictUpdate());
211
439
  return {
212
440
  then: (callback) => {
213
441
  if (callback)
214
- if (this.frame.size)
442
+ if (this.frame.size || arg !== false)
215
443
  this.waiting.add(callback);
216
444
  else
217
445
  callback(false);
218
446
  else
219
- throw Oops$c.NoChaining();
447
+ throw Oops$9.NoChaining();
220
448
  }
221
449
  };
222
450
  }
@@ -245,164 +473,6 @@ function control(subject, cb) {
245
473
  return cb(control);
246
474
  }
247
475
 
248
- class Subscriber {
249
- constructor(target, onUpdate) {
250
- this.onUpdate = onUpdate;
251
- this.active = false;
252
- this.dependant = new Set();
253
- this.watch = {};
254
- const parent = target instanceof Controller
255
- ? target : control(target);
256
- const proxy = create(parent.proxy);
257
- let reset;
258
- define(proxy, LOCAL, this);
259
- defineProperty(this, "proxy", {
260
- configurable: true,
261
- get() {
262
- if (reset)
263
- setTimeout(reset, 0);
264
- return proxy;
265
- }
266
- });
267
- const release = parent.addListener(key => {
268
- const handler = this.watch[key];
269
- if (!handler || !this.active)
270
- return;
271
- if (typeof handler == "function")
272
- handler();
273
- const notify = this.onUpdate(key, parent);
274
- const getWhy = (keys) => {
275
- reset = applyUpdate(proxy, keys.filter(k => k in this.watch));
276
- };
277
- if (notify) {
278
- parent.requestUpdate(getWhy);
279
- parent.requestUpdate(notify);
280
- }
281
- });
282
- this.commit = () => {
283
- this.active = true;
284
- this.dependant.forEach(x => x.commit());
285
- return this.release;
286
- };
287
- this.release = () => {
288
- this.dependant.forEach(x => x.release());
289
- release();
290
- };
291
- }
292
- }
293
-
294
- const Oops$b = issues({
295
- ComputeFailed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
296
- ComputedEarly: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
297
- });
298
- const INIT = new WeakSet();
299
- const INFO = new WeakMap();
300
- const USED = new WeakMap();
301
- const KEYS = new WeakMap();
302
- function prepare(parent, key, source, setter, getter) {
303
- let sub;
304
- const { state, subject } = parent;
305
- const info = { key, parent, priority: 1 };
306
- let register = USED.get(parent);
307
- if (!register) {
308
- register = new Map();
309
- USED.set(parent, register);
310
- }
311
- register.set(key, info);
312
- function compute(initial) {
313
- try {
314
- return setter.call(sub.proxy, sub.proxy);
315
- }
316
- catch (err) {
317
- Oops$b.ComputeFailed(subject, key, !!initial).warn();
318
- throw err;
319
- }
320
- }
321
- function update() {
322
- let value;
323
- try {
324
- value = compute(false);
325
- }
326
- catch (e) {
327
- console.error(e);
328
- }
329
- finally {
330
- if (state[key] !== value) {
331
- parent.update(key, value);
332
- return value;
333
- }
334
- }
335
- }
336
- function defer(_key, from) {
337
- let pending = KEYS.get(from);
338
- if (!pending)
339
- KEYS.set(from, pending = []);
340
- if (info.parent !== from)
341
- update();
342
- else {
343
- const after = pending.findIndex(peer => (info.priority > INFO.get(peer).priority));
344
- pending.splice(after + 1, 0, update);
345
- }
346
- }
347
- function create(early) {
348
- sub = new Subscriber(source(), defer);
349
- defineProperty(state, key, {
350
- value: undefined,
351
- writable: true
352
- });
353
- try {
354
- return state[key] = compute(true);
355
- }
356
- catch (e) {
357
- if (early)
358
- Oops$b.ComputedEarly(key).warn();
359
- throw e;
360
- }
361
- finally {
362
- sub.commit();
363
- for (const key in sub.watch) {
364
- const peer = register.get(key);
365
- if (peer && peer.priority >= info.priority)
366
- info.priority = peer.priority + 1;
367
- }
368
- }
369
- }
370
- setAlias(update, `try ${key}`);
371
- setAlias(create, `new ${key}`);
372
- setAlias(setter, `run ${key}`);
373
- INIT.add(create);
374
- INFO.set(update, info);
375
- defineProperty(state, key, {
376
- get: create,
377
- configurable: true,
378
- enumerable: true
379
- });
380
- if (getter)
381
- return () => getter(parent, key);
382
- }
383
- function ensure(on, keys) {
384
- for (const key of keys) {
385
- const desc = getOwnPropertyDescriptor(on.state, key);
386
- const getter = desc && desc.get;
387
- if (INIT.has(getter))
388
- getter(true);
389
- }
390
- }
391
- function flush(on) {
392
- const handled = on.frame;
393
- const pending = KEYS.get(on);
394
- if (!pending)
395
- return;
396
- while (pending.length) {
397
- const why = [...handled];
398
- const compute = pending.shift();
399
- const { key } = INFO.get(compute);
400
- if (!handled.has(key))
401
- compute(why);
402
- }
403
- KEYS.delete(on);
404
- }
405
-
406
476
  const CONTROL = Symbol("CONTROL");
407
477
  const WHY = Symbol("UPDATE");
408
478
  const LOCAL = Symbol("LOCAL");
@@ -552,17 +622,21 @@ function apply(fn, label) {
552
622
  const placeholder = Symbol(`${name} instruction`);
553
623
  function setup(key) {
554
624
  let output = fn.call(this, key, this);
555
- if (typeof output == "function")
556
- return { get: output };
557
- if (typeof output !== "object")
558
- return output || undefined;
559
- if ("explicit" in output && output.explicit) {
560
- defineProperty(this.subject, key, output);
561
- return false;
625
+ switch (typeof output) {
626
+ case "function":
627
+ return { get: output };
628
+ case "object": {
629
+ if ("explicit" in output && output.explicit) {
630
+ defineProperty(this.subject, key, output);
631
+ return false;
632
+ }
633
+ if ("recursive" in output && output.recursive)
634
+ return Object.assign(Object.assign({}, output), { get: recursive(this, key) });
635
+ }
636
+ case "boolean":
637
+ return output;
562
638
  }
563
- if ("recursive" in output)
564
- output = Object.assign(Object.assign({}, output), { get: recursive(this, key) });
565
- return output;
639
+ return;
566
640
  }
567
641
  Pending.set(placeholder, setup);
568
642
  return placeholder;
@@ -599,7 +673,7 @@ function recursive(source, key) {
599
673
  };
600
674
  }
601
675
 
602
- const Oops$a = issues({
676
+ const Oops$8 = issues({
603
677
  DuplicateAction: (key) => `Invoked action ${key} but one is already active.`
604
678
  });
605
679
  function act(task) {
@@ -607,7 +681,7 @@ function act(task) {
607
681
  let pending = false;
608
682
  const invoke = (...args) => {
609
683
  if (pending)
610
- return Promise.reject(Oops$a.DuplicateAction(key));
684
+ return Promise.reject(Oops$8.DuplicateAction(key));
611
685
  pending = true;
612
686
  this.update(key);
613
687
  return new Promise(res => {
@@ -618,7 +692,6 @@ function act(task) {
618
692
  });
619
693
  };
620
694
  this.state[key] = undefined;
621
- setAlias(invoke, `run ${key}`);
622
695
  defineProperty(invoke, "active", {
623
696
  get: () => pending
624
697
  });
@@ -629,107 +702,6 @@ function act(task) {
629
702
  });
630
703
  }
631
704
 
632
- const Oops$9 = issues({
633
- ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
634
- });
635
- /**
636
- * Get value, suspend instead if undefined.
637
- *
638
- * Throws suspense promise also interpretable as an error.
639
- * React could handle it but other contexts probably not.
640
- */
641
- function pendingValue(via, key) {
642
- const value = via.state[key];
643
- if (value === undefined)
644
- throw suspend(via, key);
645
- return value;
646
- }
647
- function pendingFactory(via, key, fn) {
648
- const { subject, state } = via;
649
- let waiting;
650
- let error;
651
- return () => {
652
- if (waiting)
653
- throw waiting;
654
- if (error)
655
- throw error;
656
- if (key in state)
657
- return state[key];
658
- let output;
659
- try {
660
- output = fn.call(subject, key, subject);
661
- }
662
- catch (err) {
663
- throw error = err;
664
- }
665
- if (output instanceof Promise) {
666
- const issue = Oops$9.ValueNotReady(subject, key);
667
- output
668
- .catch(err => error = err)
669
- .then(out => state[key] = out)
670
- .finally(() => waiting = undefined);
671
- throw waiting = Object.assign(output, {
672
- message: issue.message,
673
- stack: issue.stack
674
- });
675
- }
676
- else {
677
- return state[key] = output;
678
- }
679
- };
680
- }
681
- function suspend(source, key) {
682
- const error = Oops$9.ValueNotReady(source.subject, key);
683
- const promise = new Promise(resolve => {
684
- const release = source.addListener(forKey => {
685
- if (forKey == key)
686
- return () => {
687
- if (source.state[key] !== undefined) {
688
- release();
689
- resolve();
690
- }
691
- };
692
- });
693
- });
694
- return Object.assign(promise, {
695
- toString: () => String(error),
696
- name: "Suspense",
697
- message: error.message,
698
- stack: error.stack
699
- });
700
- }
701
-
702
- const Oops$8 = issues({
703
- BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
704
- PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`
705
- });
706
- function from(source, setter, arg) {
707
- return apply(function from(key) {
708
- const { subject } = this;
709
- let getSource;
710
- let getter;
711
- if (arg === true || setter === true)
712
- getter = pendingValue;
713
- if (typeof setter == "boolean")
714
- setter = undefined;
715
- // Easy mistake, using a peer, will always be unresolved.
716
- if (typeof source == "symbol")
717
- throw Oops$8.PeerNotAllowed(subject, key);
718
- // replace source controller in-case it is different
719
- if (typeof source == "object")
720
- getSource = () => control(source);
721
- // specifically an arrow function (getter factory)
722
- else if (!source.prototype) {
723
- setter = source.call(subject, key);
724
- getSource = () => this;
725
- }
726
- // Regular function is too ambiguous so not allowed.
727
- else
728
- throw Oops$8.BadComputedSource(subject, key, source);
729
- return prepare(this, key, getSource, setter, getter);
730
- });
731
- }
732
-
733
705
  function ref(arg) {
734
706
  return apply(function ref(key) {
735
707
  let value = {};
@@ -755,32 +727,21 @@ function createRef(key, cb) {
755
727
  const Oops$7 = issues({
756
728
  NonOptional: (Parent, key) => `Property ${Parent}.${key} is marked as required.`,
757
729
  BadFactory: () => `Set instruction can only accept a factory or undefined.`,
730
+ ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
758
731
  FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`
759
732
  });
760
733
  function set(factory, argument) {
761
734
  return apply(function set(key) {
762
735
  let set;
763
736
  let get;
737
+ let suspense;
764
738
  const required = argument === true || argument === undefined;
765
739
  if (factory === undefined)
766
- get = () => pendingValue(this, key);
767
- else if (typeof factory !== "function")
740
+ suspense = true;
741
+ else if (typeof factory === "function")
742
+ get = pendingFactory(this, key, factory, required);
743
+ else
768
744
  throw Oops$7.BadFactory();
769
- else {
770
- get = pendingFactory(this, key, factory);
771
- if (required)
772
- try {
773
- get();
774
- }
775
- catch (err) {
776
- if (err instanceof Promise)
777
- ;
778
- else {
779
- Oops$7.FactoryFailed(this.subject, key).warn();
780
- throw err;
781
- }
782
- }
783
- }
784
745
  if (typeof argument == "function")
785
746
  set = createValueEffect(argument);
786
747
  else
@@ -788,8 +749,63 @@ function set(factory, argument) {
788
749
  if (value === undefined && required)
789
750
  throw Oops$7.NonOptional(this.subject, key);
790
751
  };
791
- return { set, get };
752
+ return {
753
+ set,
754
+ get,
755
+ suspense
756
+ };
792
757
  });
758
+ }
759
+ function pendingFactory(parent, key, fn, required) {
760
+ const { subject, state } = parent;
761
+ let pending;
762
+ let error;
763
+ const init = () => {
764
+ const output = suspenseBoundary(() => {
765
+ return fn.call(subject, key, subject);
766
+ });
767
+ if (output instanceof Promise) {
768
+ pending = output
769
+ .catch(err => error = err)
770
+ .then(val => state[key] = val)
771
+ .finally(() => {
772
+ pending = undefined;
773
+ parent.update(key);
774
+ });
775
+ return;
776
+ }
777
+ return state[key] = output;
778
+ };
779
+ const suspend = () => {
780
+ if (required === false)
781
+ return undefined;
782
+ const issue = Oops$7.ValueNotReady(subject, key);
783
+ Object.assign(pending, {
784
+ message: issue.message,
785
+ stack: issue.stack
786
+ });
787
+ throw pending;
788
+ };
789
+ if (required)
790
+ try {
791
+ init();
792
+ }
793
+ catch (err) {
794
+ Oops$7.FactoryFailed(subject, key).warn();
795
+ throw err;
796
+ }
797
+ return () => {
798
+ if (pending)
799
+ return suspend();
800
+ if (error)
801
+ throw error;
802
+ if (key in state)
803
+ return state[key];
804
+ let output = init();
805
+ return pending
806
+ ? suspend()
807
+ : output;
808
+ };
793
809
  }
794
810
 
795
811
  const Parent = new WeakMap();
@@ -932,24 +948,26 @@ const ContextWasUsed = new WeakMap();
932
948
  function tap(type, argument) {
933
949
  return apply(function tap(key) {
934
950
  if ("set" in type)
935
- this.state[key] = type.get();
936
- else {
937
- const { subject } = this;
938
- if ("set" in subject.constructor)
939
- throw Oops$3.CantAttachGlobal(subject, type.name);
940
- getPending(subject).push(context => {
941
- let instance = context.get(type);
942
- if (typeof argument == "function") {
943
- if (argument(instance) === false)
944
- instance = undefined;
945
- }
946
- else if (!instance && argument)
947
- throw Oops$3.AmbientRequired(type.name, subject, key);
948
- this.update(key, instance);
949
- });
950
- }
951
+ return {
952
+ recursive: true,
953
+ value: type.get()
954
+ };
955
+ const { subject } = this;
956
+ if ("set" in subject.constructor)
957
+ throw Oops$3.CantAttachGlobal(subject, type.name);
958
+ getPending(subject).push(context => {
959
+ let instance = context.get(type);
960
+ if (typeof argument == "function") {
961
+ if (argument(instance) === false)
962
+ instance = undefined;
963
+ }
964
+ else if (!instance && argument)
965
+ throw Oops$3.AmbientRequired(type.name, subject, key);
966
+ this.update(key, instance);
967
+ });
951
968
  return {
952
- recursive: true
969
+ recursive: true,
970
+ suspense: true
953
971
  };
954
972
  });
955
973
  }
@@ -1121,7 +1139,7 @@ class MVC extends Model {
1121
1139
  return useTap(this, key, expect);
1122
1140
  }
1123
1141
  static new(arg) {
1124
- return React.useMemo(() => {
1142
+ const instance = React.useMemo(() => {
1125
1143
  const instance = new this();
1126
1144
  control(instance);
1127
1145
  if (typeof arg == "function")
@@ -1133,6 +1151,8 @@ class MVC extends Model {
1133
1151
  });
1134
1152
  return instance;
1135
1153
  }, []);
1154
+ usePeerContext(instance.get);
1155
+ return instance;
1136
1156
  }
1137
1157
  static use(a, b) {
1138
1158
  const instance = useModel(this, a, b);
@@ -1245,7 +1265,7 @@ class Global extends MVC {
1245
1265
  static set(updates) {
1246
1266
  const instance = Active.get(this) || this.create();
1247
1267
  instance.import(updates);
1248
- return instance.update();
1268
+ return instance.update(false);
1249
1269
  }
1250
1270
  static get(arg) {
1251
1271
  const instance = Active.get(this);