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