@expressive/mvc 0.2.6 → 0.4.1

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
@@ -59,7 +59,7 @@ function suspend(source, key) {
59
59
  const release = source.addListener(forKey => {
60
60
  if (forKey == key)
61
61
  return () => {
62
- if (source.state[key] !== undefined) {
62
+ if (source.state.get(key) !== undefined) {
63
63
  release();
64
64
  resolve();
65
65
  }
@@ -140,240 +140,37 @@ function createValueEffect(callback) {
140
140
  };
141
141
  }
142
142
 
143
- const UPDATE = new WeakMap();
144
- function applyUpdate(subject, keys) {
145
- UPDATE.set(subject, keys);
146
- return () => {
147
- setTimeout(() => {
148
- UPDATE.delete(subject);
149
- }, 0);
150
- };
151
- }
152
- function getUpdate(subject) {
153
- return UPDATE.get(subject);
154
- }
155
-
156
- const CONTROL = Symbol("CONTROL");
157
- const WHY = Symbol("UPDATE");
158
- const LOCAL = Symbol("LOCAL");
159
- const STATE = Symbol("STATE");
160
- class Model {
161
- constructor() {
162
- define(this, CONTROL, new Controller(this));
163
- define(this, "get", this);
164
- define(this, "is", this);
165
- defineLazy(this, "set", () => {
166
- const controller = control(this);
167
- const assign = (key, value) => {
168
- controller.update(key, value);
169
- };
170
- for (const key of getOwnPropertyNames(controller.proxy))
171
- define(assign, key, controller.ref(key));
172
- return assign;
173
- });
174
- }
175
- get [STATE]() {
176
- return this[CONTROL].state;
177
- }
178
- get [WHY]() {
179
- return UPDATE.get(this);
180
- }
181
- on(select, handler, squash, once) {
182
- return control(this, control => {
183
- if (typeof select == "function")
184
- return control.addListener(select);
185
- const selection = typeof select == "string" ? [select] :
186
- !select.length ? getOwnPropertyNames(control.state) :
187
- select;
188
- ensure(control, selection);
189
- const callback = squash
190
- ? () => {
191
- handler.call(this, getUpdate(this));
192
- }
193
- : () => {
194
- getUpdate(this)
195
- .filter(k => selection.includes(k))
196
- .forEach(k => {
197
- handler.call(this, control.state[k], k);
198
- });
199
- };
200
- const onEvent = once
201
- ? () => {
202
- remove();
203
- callback();
204
- }
205
- : callback;
206
- const remove = control.addListener(key => {
207
- if (selection.includes(key))
208
- return onEvent;
209
- });
210
- return remove;
211
- });
212
- }
213
- once(select, callback, squash) {
214
- if (callback)
215
- return this.on(select, callback, squash, true);
216
- return new Promise(resolve => {
217
- this.on(select, resolve, true, true);
218
- });
143
+ function ensure(subject, cb) {
144
+ let control = subject[CONTROL];
145
+ if (!control) {
146
+ control = new Controller(subject);
147
+ define(subject, CONTROL, control);
219
148
  }
220
- effect(callback, select) {
221
- const effect = createEffect(callback);
222
- return control(this, control => {
223
- let busy = false;
224
- let inject = this.is;
225
- const invoke = () => {
226
- if (busy)
227
- return;
228
- const output = mayRetry(() => {
229
- effect.call(inject, inject);
230
- });
231
- if (output instanceof Promise) {
232
- output.finally(() => busy = false);
233
- busy = true;
234
- }
235
- };
236
- if (!select) {
237
- const sub = new Subscriber(control, () => invoke);
238
- inject = sub.proxy;
239
- invoke();
240
- return sub.commit();
241
- }
242
- invoke();
243
- if (!select.length) {
244
- control.onDestroy.add(invoke);
245
- return () => {
246
- control.onDestroy.delete(invoke);
247
- };
248
- }
249
- return control.addListener(key => {
250
- if (select.includes(key))
251
- return invoke;
149
+ if (!control.state) {
150
+ const { waiting } = control;
151
+ if (cb) {
152
+ let done;
153
+ waiting.add(() => {
154
+ done = cb(control);
252
155
  });
253
- });
254
- }
255
- // TODO: account for exotic properties
256
- import(source, select) {
257
- const { subject } = control(this);
258
- if (!select)
259
- select = getOwnPropertyNames(subject);
260
- for (const key of select)
261
- if (key in source)
262
- this[key] = source[key];
263
- }
264
- export(subset) {
265
- const { state } = control(this);
266
- const output = {};
267
- if (!subset)
268
- subset = getOwnPropertyNames(state);
269
- for (const key of subset)
270
- output[key] = state[key];
271
- return output;
272
- }
273
- update(arg, tag) {
274
- const target = control(this);
275
- if (typeof arg == "string") {
276
- target.update(arg);
277
- if (1 in arguments && arg in this) {
278
- const method = this[arg];
279
- if (typeof method == "function")
280
- if (typeof tag != "boolean")
281
- method.call(this, tag);
282
- else if (tag)
283
- method.call(this);
284
- }
285
- arg = undefined;
156
+ return () => done && done();
286
157
  }
287
- return target.requestUpdate(arg);
288
- }
289
- /**
290
- * Mark this instance for garbage-collection and send `willDestroy` event to all listeners.
291
- */
292
- destroy() {
293
- control(this).stop();
294
- }
295
- toString() {
296
- return this.constructor.name;
297
- }
298
- /**
299
- * Creates a new instance of this controller.
300
- *
301
- * Beyond `new this(...)`, method will activate managed-state.
302
- *
303
- * @param args - arguments sent to constructor
304
- */
305
- static create(...args) {
306
- const instance = new this(...args);
307
- control(instance);
308
- return instance;
309
- }
310
- /**
311
- * Static equivalent of `x instanceof this`.
312
- *
313
- * Will determine if provided class is a subtype of this one.
314
- */
315
- static isTypeof(maybe) {
316
- return (typeof maybe == "function" &&
317
- maybe.prototype instanceof this);
318
- }
319
- }
320
-
321
- class Subscriber {
322
- constructor(target, onUpdate) {
323
- this.onUpdate = onUpdate;
324
- this.active = false;
325
- this.dependant = new Set();
326
- this.watch = {};
327
- const parent = target instanceof Controller
328
- ? target : control(target);
329
- const subject = parent.subject;
330
- const proxy = create(parent.proxy);
331
- let reset;
332
- define(proxy, LOCAL, this);
333
- defineProperty(this, "proxy", {
334
- configurable: true,
335
- get() {
336
- if (reset)
337
- setTimeout(reset, 0);
338
- return proxy;
339
- }
340
- });
341
- const release = parent.addListener(key => {
342
- const handler = this.watch[key];
343
- if (!handler || !this.active)
344
- return;
345
- if (typeof handler == "function")
346
- handler();
347
- const notify = this.onUpdate(key, parent);
348
- const getWhy = () => {
349
- const update = getUpdate(subject);
350
- const applicable = update.filter(k => k in this.watch);
351
- reset = applyUpdate(proxy, applicable);
352
- };
353
- if (notify) {
354
- parent.requestUpdate(getWhy);
355
- parent.requestUpdate(notify);
356
- }
357
- });
358
- this.commit = () => {
359
- this.active = true;
360
- this.dependant.forEach(x => x.commit());
361
- return this.release;
362
- };
363
- this.release = () => {
364
- this.dependant.forEach(x => x.release());
365
- release();
366
- };
158
+ control.state = new Map();
159
+ for (const key in subject)
160
+ control.add(key);
161
+ const callback = Array.from(waiting);
162
+ waiting.clear();
163
+ for (const cb of callback)
164
+ cb();
367
165
  }
166
+ return cb ? cb(control) : control;
368
167
  }
369
168
 
370
169
  const Oops$a = issues({
371
170
  BadSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
372
171
  PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
373
- Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
374
- Early: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
172
+ Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
375
173
  });
376
- const INIT = new WeakSet();
377
174
  const INFO = new WeakMap();
378
175
  const USED = new WeakMap();
379
176
  const KEYS = new WeakMap();
@@ -381,8 +178,8 @@ function from(source, arg1, arg2) {
381
178
  return apply(function from(key) {
382
179
  const parent = this;
383
180
  const { subject, state } = this;
181
+ const required = arg2 === true || arg1 === true;
384
182
  let getSource;
385
- let required = arg2 === true || arg1 === true;
386
183
  if (typeof arg1 == "boolean")
387
184
  arg1 = undefined;
388
185
  // Easy mistake, using a peer, will always be unresolved.
@@ -390,7 +187,7 @@ function from(source, arg1, arg2) {
390
187
  throw Oops$a.PeerNotAllowed(subject, key);
391
188
  // replace source controller in-case it is different
392
189
  if (typeof source == "object")
393
- getSource = () => control(source);
190
+ getSource = () => ensure(source);
394
191
  // specifically an arrow function (getter factory)
395
192
  else if (!source.prototype) {
396
193
  arg1 = source.call(subject, key);
@@ -399,21 +196,20 @@ function from(source, arg1, arg2) {
399
196
  // Regular function is too ambiguous so not allowed.
400
197
  else
401
198
  throw Oops$a.BadSource(subject, key, source);
402
- let sub;
403
199
  const setter = arg1;
404
200
  const info = { key, parent, priority: 1 };
201
+ let sub;
405
202
  let register = USED.get(parent);
406
- if (!register) {
407
- register = new Map();
408
- USED.set(parent, register);
409
- }
203
+ if (!register)
204
+ USED.set(parent, register = new Map());
205
+ state.set(key, undefined);
410
206
  register.set(key, info);
411
207
  function compute(initial) {
412
208
  try {
413
209
  return setter.call(sub.proxy, sub.proxy);
414
210
  }
415
211
  catch (err) {
416
- Oops$a.Failed(subject, key, !!initial).warn();
212
+ Oops$a.Failed(subject, key, initial).warn();
417
213
  throw err;
418
214
  }
419
215
  }
@@ -426,16 +222,17 @@ function from(source, arg1, arg2) {
426
222
  console.error(e);
427
223
  }
428
224
  finally {
429
- if (state[key] !== value) {
430
- parent.update(key, value);
225
+ if (state.get(key) !== value) {
226
+ parent.state.set(key, value);
227
+ parent.update(key);
431
228
  return value;
432
229
  }
433
230
  }
434
231
  }
435
232
  function defer(_key, from) {
436
- let pending = KEYS.get(from.frame);
233
+ let pending = KEYS.get(from);
437
234
  if (!pending)
438
- KEYS.set(from.frame, pending = []);
235
+ KEYS.set(from, pending = []);
439
236
  if (info.parent !== from)
440
237
  update();
441
238
  else {
@@ -443,179 +240,356 @@ function from(source, arg1, arg2) {
443
240
  pending.splice(after + 1, 0, update);
444
241
  }
445
242
  }
446
- function create(early) {
447
- sub = new Subscriber(getSource(), defer);
448
- defineProperty(state, key, {
449
- value: undefined,
450
- writable: true
451
- });
243
+ function create() {
244
+ const control = getSource();
245
+ sub = control.subscribe(defer);
452
246
  try {
453
- return state[key] = compute(true);
247
+ const value = compute(true);
248
+ state.set(key, value);
249
+ return value;
454
250
  }
455
251
  catch (e) {
456
- if (early)
457
- Oops$a.Early(key).warn();
458
252
  throw e;
459
253
  }
460
254
  finally {
461
255
  sub.commit();
462
- for (const key in sub.watch) {
256
+ for (const key of control.state.keys()) {
463
257
  const peer = register.get(key);
464
258
  if (peer && peer.priority >= info.priority)
465
259
  info.priority = peer.priority + 1;
466
260
  }
467
261
  }
468
262
  }
469
- INIT.add(create);
470
263
  INFO.set(update, info);
471
- defineProperty(state, key, {
472
- get: create,
473
- configurable: true,
474
- enumerable: true
475
- });
476
264
  return () => {
477
- const value = parent.state[key];
265
+ const value = sub ? state.get(key) : create();
478
266
  if (value === undefined && required)
479
267
  throw suspend(this, key);
480
268
  return value;
481
269
  };
482
270
  });
483
271
  }
484
- function ensure(on, keys) {
485
- for (const key of keys) {
486
- const desc = getOwnPropertyDescriptor(on.state, key);
487
- const getter = desc && desc.get;
488
- if (INIT.has(getter))
489
- getter(true);
490
- }
491
- }
492
- function flush(frame) {
493
- const pending = KEYS.get(frame);
272
+ function flush(control) {
273
+ const pending = KEYS.get(control);
494
274
  if (!pending)
495
275
  return;
496
276
  while (pending.length) {
497
277
  const compute = pending.shift();
498
278
  const { key } = INFO.get(compute);
499
- if (!frame.has(key))
279
+ if (!control.frame.has(key))
500
280
  compute();
501
281
  }
502
- KEYS.delete(frame);
282
+ KEYS.delete(control);
503
283
  }
504
284
 
505
- const Oops$9 = issues({
506
- StrictUpdate: () => `Strict update() did not find pending updates.`,
507
- NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
508
- });
509
- const PENDING = new Map();
510
- const READY = new WeakSet();
285
+ class Subscriber {
286
+ constructor(parent, onUpdate) {
287
+ this.onUpdate = onUpdate;
288
+ this.active = false;
289
+ this.dependant = new Set();
290
+ const proxy = create(parent.subject);
291
+ const using = new Map();
292
+ define(proxy, LOCAL, this);
293
+ defineProperty(this, "proxy", {
294
+ configurable: true,
295
+ get() {
296
+ if (UPDATE.has(proxy))
297
+ setTimeout(() => UPDATE.delete(proxy), 0);
298
+ return proxy;
299
+ }
300
+ });
301
+ const release = parent.addListener(key => {
302
+ if (!this.active || !using.has(key))
303
+ return;
304
+ const handler = using.get(key);
305
+ if (typeof handler == "function")
306
+ if (handler() !== true)
307
+ return;
308
+ const notify = this.onUpdate(key, parent);
309
+ const getWhy = () => {
310
+ const update = getUpdate(parent.subject);
311
+ const applicable = update.filter(k => using.has(k));
312
+ UPDATE.set(proxy, applicable);
313
+ };
314
+ if (notify) {
315
+ parent.waiting.add(getWhy);
316
+ parent.waiting.add(notify);
317
+ }
318
+ });
319
+ this.commit = () => {
320
+ this.active = true;
321
+ this.dependant.forEach(x => x.commit());
322
+ return this.release;
323
+ };
324
+ this.release = () => {
325
+ this.dependant.forEach(x => x.release());
326
+ release();
327
+ };
328
+ this.add = (key, value) => {
329
+ if (value)
330
+ using.set(key, value);
331
+ else if (!using.has(key))
332
+ using.set(key, true);
333
+ };
334
+ }
335
+ }
336
+
337
+ const UPDATE = new WeakMap();
338
+ function getUpdate(subject) {
339
+ return UPDATE.get(subject);
340
+ }
511
341
  class Controller {
512
342
  constructor(subject) {
513
343
  this.subject = subject;
514
- this.state = {};
515
344
  this.frame = new Set();
516
- this.onDestroy = new Set();
517
345
  this.waiting = new Set();
518
346
  this.followers = new Set();
519
- this.proxy = Object.create(subject);
520
- }
521
- start() {
522
- READY.add(this);
523
- for (const key in this.subject) {
524
- const { value } = getOwnPropertyDescriptor(this.subject, key);
525
- if (typeof value == "function")
526
- continue;
527
- if (typeof value == "symbol") {
528
- const instruction = PENDING.get(value);
529
- if (instruction)
530
- instruction.call(this, key, this);
531
- continue;
347
+ }
348
+ subscribe(callback) {
349
+ return new Subscriber(this, callback);
350
+ }
351
+ add(key) {
352
+ const { subject, state } = this;
353
+ const { value } = getOwnPropertyDescriptor(subject, key);
354
+ if (typeof value == "function")
355
+ return;
356
+ if (typeof value == "symbol") {
357
+ const instruction = PENDING.get(value);
358
+ if (instruction)
359
+ instruction.call(this, key, this);
360
+ return;
361
+ }
362
+ state.set(key, value);
363
+ defineProperty(subject, key, {
364
+ enumerable: false,
365
+ set: this.ref(key),
366
+ get() {
367
+ const local = this[LOCAL];
368
+ if (local)
369
+ local.add(key);
370
+ return state.get(key);
532
371
  }
533
- this.manage(key, value);
372
+ });
373
+ }
374
+ addListener(listener) {
375
+ this.followers.add(listener);
376
+ return () => {
377
+ this.followers.delete(listener);
378
+ };
379
+ }
380
+ ref(key, handler) {
381
+ const { subject, state } = this;
382
+ return (value) => {
383
+ if (state.get(key) == value)
384
+ return;
385
+ if (handler)
386
+ switch (handler.call(subject, value)) {
387
+ case true:
388
+ this.update(key);
389
+ case false:
390
+ return;
391
+ }
392
+ state.set(key, value);
393
+ this.update(key);
394
+ };
395
+ }
396
+ update(key) {
397
+ const { followers, frame, subject, waiting } = this;
398
+ if (frame.has(key))
399
+ return;
400
+ else if (!frame.size)
401
+ setTimeout(() => {
402
+ flush(this);
403
+ const callback = Array.from(waiting);
404
+ const keys = Array.from(frame);
405
+ frame.clear();
406
+ waiting.clear();
407
+ UPDATE.set(subject, keys);
408
+ setTimeout(() => {
409
+ UPDATE.delete(subject);
410
+ }, 0);
411
+ for (const cb of callback)
412
+ try {
413
+ cb();
414
+ }
415
+ catch (err) {
416
+ console.error(err);
417
+ }
418
+ }, 0);
419
+ frame.add(key);
420
+ for (const callback of followers) {
421
+ const event = callback(key, this);
422
+ if (typeof event == "function")
423
+ waiting.add(event);
534
424
  }
535
- this.flush();
536
425
  }
537
- stop() {
426
+ clear() {
427
+ const listeners = [...this.followers];
538
428
  this.followers.clear();
539
- this.onDestroy.forEach(x => x());
429
+ listeners.forEach(x => x(null, this));
540
430
  }
541
- manage(key, value) {
542
- const { state } = this;
543
- const set = this.ref(key);
544
- state[key] = value;
545
- defineProperty(this.subject, key, {
546
- enumerable: false,
547
- get: () => state[key],
548
- set
431
+ }
432
+
433
+ const Oops$9 = issues({
434
+ Timeout: (keys, timeout) => `No update for [${keys}] within ${timeout}.`,
435
+ StrictUpdate: () => `Strict update() did not find pending updates.`,
436
+ NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
437
+ });
438
+ const CONTROL = Symbol("CONTROL");
439
+ const WHY = Symbol("UPDATE");
440
+ const LOCAL = Symbol("LOCAL");
441
+ const STATE = Symbol("STATE");
442
+ class Model {
443
+ constructor() {
444
+ define(this, CONTROL, new Controller(this));
445
+ define(this, "get", this);
446
+ define(this, "is", this);
447
+ defineLazy(this, "set", () => {
448
+ const controller = ensure(this);
449
+ const assign = (key, value) => {
450
+ controller.state.set(key, value);
451
+ controller.update(key);
452
+ };
453
+ for (const key of controller.state.keys())
454
+ define(assign, key, controller.ref(key));
455
+ return assign;
456
+ });
457
+ }
458
+ get [STATE]() {
459
+ return this.export();
460
+ }
461
+ get [WHY]() {
462
+ return UPDATE.get(this);
463
+ }
464
+ on(select, handler, squash, once) {
465
+ return ensure(this, control => {
466
+ if (typeof select == "function")
467
+ return control.addListener(select);
468
+ const keys = typeof select == "string" ? [select] :
469
+ select.length ? select : [...control.state.keys()];
470
+ for (const key of keys)
471
+ try {
472
+ void this[key];
473
+ }
474
+ catch (e) { }
475
+ const callback = squash
476
+ ? () => {
477
+ handler.call(this, getUpdate(this));
478
+ }
479
+ : () => {
480
+ getUpdate(this)
481
+ .filter(k => keys.includes(k))
482
+ .forEach(k => {
483
+ handler.call(this, control.state.get(k), k);
484
+ });
485
+ };
486
+ const onEvent = once
487
+ ? () => {
488
+ remove();
489
+ callback();
490
+ }
491
+ : callback;
492
+ const remove = control.addListener(key => {
493
+ if (keys.includes(key))
494
+ return onEvent;
495
+ });
496
+ return remove;
549
497
  });
550
- defineProperty(this.proxy, key, {
551
- enumerable: false,
552
- get() {
553
- const local = this[LOCAL];
554
- if (local && !local.watch[key])
555
- local.watch[key] = true;
556
- return state[key];
557
- },
558
- set
498
+ }
499
+ once(select, argument, squash) {
500
+ if (typeof argument == "function")
501
+ return this.on(select, argument, squash, true);
502
+ if (typeof select == "string")
503
+ select = [select];
504
+ return new Promise((resolve, reject) => {
505
+ const invoke = (key) => {
506
+ if (!key) {
507
+ clear();
508
+ reject(Oops$9.Timeout(select, typeof argument == "number"
509
+ ? `${argument}ms`
510
+ : `lifetime of ${this}`));
511
+ }
512
+ else if (select.includes(key)) {
513
+ clear();
514
+ return resolve;
515
+ }
516
+ };
517
+ const clear = ensure(this, x => {
518
+ for (const key of select)
519
+ try {
520
+ void this[key];
521
+ }
522
+ catch (e) { }
523
+ return x.addListener(invoke);
524
+ });
525
+ if (typeof argument == "number")
526
+ setTimeout(invoke, argument);
559
527
  });
560
528
  }
561
- ref(key, handler) {
562
- const { state, subject } = this;
563
- return (value) => {
564
- if (state[key] == value)
565
- return;
566
- if (handler)
567
- switch (handler.call(subject, value, state)) {
568
- case true:
569
- this.update(key);
570
- case false:
571
- return;
529
+ effect(callback, select) {
530
+ const effect = createEffect(callback);
531
+ return ensure(this, control => {
532
+ let busy = false;
533
+ let inject = this.is;
534
+ const invoke = () => {
535
+ if (busy)
536
+ return;
537
+ const output = mayRetry(() => {
538
+ effect.call(inject, inject);
539
+ });
540
+ if (output instanceof Promise) {
541
+ output.finally(() => busy = false);
542
+ busy = true;
572
543
  }
573
- this.update(key, value);
574
- };
544
+ };
545
+ if (!select) {
546
+ const sub = control.subscribe(() => invoke);
547
+ inject = sub.proxy;
548
+ invoke();
549
+ return sub.commit();
550
+ }
551
+ invoke();
552
+ return control.addListener(key => {
553
+ if (key === null) {
554
+ if (!select.length)
555
+ invoke();
556
+ }
557
+ else if (select.includes(key))
558
+ return invoke;
559
+ });
560
+ });
575
561
  }
576
- addListener(listener) {
577
- this.followers.add(listener);
578
- return () => {
579
- this.followers.delete(listener);
580
- };
562
+ // TODO: account for exotic properties
563
+ import(source, select) {
564
+ const { subject } = ensure(this);
565
+ if (!select)
566
+ select = getOwnPropertyNames(subject);
567
+ for (const key of select)
568
+ if (key in source)
569
+ this[key] = source[key];
581
570
  }
582
- update(key, value) {
583
- const { frame } = this;
584
- if (1 in arguments)
585
- this.state[key] = value;
586
- if (!frame.size)
587
- setTimeout(() => {
588
- flush(frame);
589
- this.flush();
590
- }, 0);
591
- else if (frame.has(key))
592
- return;
593
- frame.add(key);
594
- for (const callback of this.followers) {
595
- const event = callback(key, this);
596
- if (typeof event == "function")
597
- this.waiting.add(event);
598
- }
571
+ export(subset) {
572
+ const { state } = ensure(this);
573
+ const output = {};
574
+ const keys = subset || state.keys();
575
+ for (const key of keys)
576
+ output[key] = state.get(key);
577
+ return output;
599
578
  }
600
- flush() {
601
- const waiting = Array.from(this.waiting);
602
- const keys = Array.from(this.frame);
603
- this.frame.clear();
604
- this.waiting.clear();
605
- applyUpdate(this.subject, keys)();
606
- for (const callback of waiting)
607
- try {
608
- callback();
609
- }
610
- catch (err) {
611
- console.error(err);
579
+ update(arg, tag) {
580
+ const target = ensure(this);
581
+ const { frame, waiting } = target;
582
+ if (typeof arg == "string") {
583
+ target.update(arg);
584
+ if (1 in arguments && arg in this) {
585
+ const method = this[arg];
586
+ if (typeof method == "function")
587
+ if (typeof tag != "boolean")
588
+ method.call(this, tag);
589
+ else if (tag)
590
+ method.call(this);
612
591
  }
613
- }
614
- requestUpdate(arg) {
615
- const { frame, subject, waiting } = this;
616
- if (typeof arg == "function") {
617
- waiting.add(arg);
618
- return;
592
+ arg = undefined;
619
593
  }
620
594
  if (!frame.size && arg === true)
621
595
  return Promise.reject(Oops$9.StrictUpdate());
@@ -625,37 +599,51 @@ class Controller {
625
599
  throw Oops$9.NoChaining();
626
600
  if (frame.size || arg !== false)
627
601
  waiting.add(() => {
628
- callback(getUpdate(subject));
602
+ callback(getUpdate(this));
629
603
  });
630
604
  else
631
605
  callback(false);
632
606
  }
633
607
  };
634
608
  }
635
- }
636
- function control(subject, cb) {
637
- let control = subject[CONTROL];
638
- if (!control) {
639
- control = new Controller(subject);
640
- define(subject, CONTROL, control);
609
+ /**
610
+ * Mark this instance for garbage-collection and send `willDestroy` event to all listeners.
611
+ */
612
+ destroy() {
613
+ ensure(this).clear();
641
614
  }
642
- const ready = READY.has(control);
643
- if (!ready) {
644
- if (cb) {
645
- let done;
646
- control.requestUpdate(() => done = cb(control));
647
- return () => done && done();
648
- }
649
- control.start();
615
+ toString() {
616
+ return this.constructor.name;
617
+ }
618
+ /**
619
+ * Creates a new instance of this controller.
620
+ *
621
+ * Beyond `new this(...)`, method will activate managed-state.
622
+ *
623
+ * @param args - arguments sent to constructor
624
+ */
625
+ static create(...args) {
626
+ const instance = new this(...args);
627
+ ensure(instance);
628
+ return instance;
629
+ }
630
+ /**
631
+ * Static equivalent of `x instanceof this`.
632
+ *
633
+ * Will determine if provided class is a subtype of this one.
634
+ */
635
+ static isTypeof(maybe) {
636
+ return (typeof maybe == "function" &&
637
+ maybe.prototype instanceof this);
650
638
  }
651
- return cb ? cb(control) : control;
652
639
  }
653
640
 
641
+ const PENDING = new Map();
654
642
  function apply(fn, label) {
655
643
  const name = label || fn.name || "pending";
656
644
  const placeholder = Symbol(`${name} instruction`);
657
645
  function setup(key) {
658
- const { proxy, state, subject } = this;
646
+ const { subject, state } = this;
659
647
  const control = this;
660
648
  PENDING.delete(placeholder);
661
649
  delete subject[key];
@@ -669,67 +657,56 @@ function apply(fn, label) {
669
657
  return false;
670
658
  }
671
659
  if ("recursive" in output && output.recursive)
672
- output = Object.assign(Object.assign({}, output), { get: recursive(this, key) });
660
+ output = Object.assign(Object.assign({}, output), { get: getRecursive(key, this) });
673
661
  const desc = output;
674
662
  if ("value" in desc)
675
- state[key] = desc.value;
663
+ state.set(key, desc.value);
676
664
  const { get: onGet, set: onSet, enumerable, suspense } = desc;
677
- let set = onSet === false
678
- ? undefined
679
- : this.ref(key, onSet);
665
+ const set = onSet !== false
666
+ ? this.ref(key, onSet)
667
+ : undefined;
680
668
  function get() {
681
- if (!(key in state) && suspense)
669
+ if (!state.has(key) && suspense)
682
670
  throw suspend(control, key);
683
671
  const local = this[LOCAL];
684
- if (local && !(key in local.watch))
685
- local.watch[key] = true;
686
- const value = state[key];
687
- if (!onGet)
688
- return value;
689
- return local
690
- ? onGet(value, local)
691
- : onGet(value);
672
+ if (local)
673
+ local.add(key);
674
+ return onGet
675
+ ? onGet(local)
676
+ : state.get(key);
692
677
  }
693
- for (const x of [subject, proxy])
694
- defineProperty(x, key, { enumerable, get, set });
678
+ defineProperty(subject, key, { enumerable, get, set });
695
679
  }
696
680
  PENDING.set(placeholder, setup);
697
681
  return placeholder;
698
682
  }
699
- function recursive(source, key) {
700
- return forSubscriber((parent, context) => {
701
- let child;
702
- function init() {
703
- if (child) {
704
- child.release();
705
- parent.dependant.delete(child);
706
- context.set(parent, undefined);
707
- child = undefined;
708
- }
709
- const value = source.state[key];
710
- if (value && CONTROL in value) {
711
- child = new Subscriber(value, parent.onUpdate);
712
- if (parent.active)
713
- child.commit();
714
- parent.dependant.add(child);
715
- context.set(parent, child.proxy);
716
- }
717
- }
718
- init();
719
- parent.watch[key] = init;
720
- });
721
- }
722
- function forSubscriber(fn) {
683
+ function getRecursive(key, from) {
723
684
  const context = new WeakMap();
724
- return (value, local) => {
685
+ const { state } = from;
686
+ return (local) => {
725
687
  if (!local)
726
- return value;
688
+ return state.get(key);
727
689
  if (!context.has(local)) {
728
- const output = fn(local, context);
729
- if (output) {
730
- context.set(local, output);
731
- return output;
732
- }
690
+ let child;
691
+ const init = () => {
692
+ if (child) {
693
+ child.release();
694
+ local.dependant.delete(child);
695
+ context.set(local, undefined);
696
+ child = undefined;
697
+ }
698
+ const value = state.get(key);
699
+ if (value && CONTROL in value) {
700
+ child = ensure(value).subscribe(local.onUpdate);
701
+ if (local.active)
702
+ child.commit();
703
+ local.dependant.add(child);
704
+ context.set(local, child.proxy);
705
+ }
706
+ return true;
707
+ };
708
+ init();
709
+ local.add(key, init);
733
710
  }
734
711
  return context.get(local);
735
712
  };
@@ -754,7 +731,7 @@ function act(task) {
754
731
  this.update(key);
755
732
  }
756
733
  });
757
- this.state[key] = undefined;
734
+ this.state.set(key, undefined);
758
735
  defineProperty(invoke, "active", {
759
736
  get: () => pending
760
737
  });
@@ -775,7 +752,7 @@ class Managed extends Array {
775
752
  };
776
753
  }
777
754
  push(...items) {
778
- const length = this.length;
755
+ const { length } = this;
779
756
  const end = super.push(...items);
780
757
  this.update(length, end);
781
758
  return end;
@@ -786,64 +763,65 @@ class Managed extends Array {
786
763
  return end;
787
764
  }
788
765
  splice(start, deleteCount, ...rest) {
789
- this.update(start, deleteCount !== rest.length ? Infinity : deleteCount);
766
+ const end = deleteCount !== rest.length ? Infinity : deleteCount;
767
+ this.update(start, end);
790
768
  return super.splice(start, deleteCount, ...rest);
791
769
  }
792
770
  }
793
771
  function array() {
794
772
  return apply(function array(key) {
773
+ const context = new WeakMap();
795
774
  const array = new Managed(() => this.update(key));
796
- const access = forSubscriber(context => {
797
- const local = Object.create(array);
798
- const update = context.onUpdate(key, this);
775
+ const getLocal = (context) => {
776
+ const proxy = Object.create(array);
799
777
  let rangeA = 0;
800
778
  let rangeB = 0;
801
- function onUpdate() {
779
+ const onUpdate = () => {
802
780
  const [lastA, lastB] = array.lastUpdate;
803
781
  if (rangeA <= lastB && rangeB >= lastA)
804
- return update;
805
- }
806
- function listen(eventA, eventB) {
782
+ return true;
783
+ };
784
+ const listen = (eventA, eventB) => {
807
785
  if (context.active)
808
786
  return;
809
- context.watch[key] = onUpdate;
787
+ context.add(key, onUpdate);
810
788
  rangeA = Math.min(rangeA, eventA);
811
789
  rangeB = Math.max(rangeB, eventB);
812
- }
813
- local[Symbol.iterator] = () => {
790
+ };
791
+ proxy[Symbol.iterator] = () => {
814
792
  listen(0, Infinity);
815
793
  return array[Symbol.iterator]();
816
794
  };
817
- return local;
818
- });
795
+ return proxy;
796
+ };
819
797
  return {
820
- get: access,
798
+ value: array,
821
799
  set: false,
822
- value: array
800
+ get: (local) => {
801
+ if (!local)
802
+ return this.state.get(key);
803
+ if (context.has(local))
804
+ return context.get(local);
805
+ const output = getLocal(local);
806
+ context.set(local, output);
807
+ return output;
808
+ }
823
809
  };
824
810
  });
825
811
  }
826
812
 
827
- function ref(arg) {
813
+ function ref(callback) {
828
814
  return apply(function ref(key) {
829
- let value = {};
830
- if (typeof arg == "object") {
831
- const source = control(arg);
832
- for (const key in source.state)
833
- defineLazy(value, key, createRef.bind(source, key));
834
- }
835
- else
836
- value = createRef.call(this, key, arg);
837
- return { value, explicit: true };
838
- });
839
- }
840
- function createRef(key, cb) {
841
- const refObjectFunction = this.ref(key, cb && createValueEffect(cb));
842
- defineProperty(refObjectFunction, "current", {
843
- set: refObjectFunction,
844
- get: () => this.state[key]
815
+ const value = this.ref(key, callback && createValueEffect(callback));
816
+ defineProperty(value, "current", {
817
+ set: value,
818
+ get: () => this.state.get(key)
819
+ });
820
+ return {
821
+ value,
822
+ explicit: true
823
+ };
845
824
  });
846
- return refObjectFunction;
847
825
  }
848
826
 
849
827
  const Oops$7 = issues({
@@ -851,65 +829,64 @@ const Oops$7 = issues({
851
829
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
852
830
  Failed: (model, key) => `Generating initial value for ${model}.${key} failed.`
853
831
  });
854
- function set(factory, argument) {
832
+ function put(factory, argument) {
855
833
  return apply(function set(key) {
856
834
  const { subject, state } = this;
857
835
  const required = argument === true || argument === undefined;
858
836
  let set;
859
837
  let get;
860
- let suspense;
861
- if (factory === undefined)
862
- suspense = true;
863
- else {
864
- let pending;
865
- let error;
866
- const init = () => {
867
- const output = typeof factory == "function" ?
868
- mayRetry(() => factory.call(subject, key, subject)) :
869
- factory;
870
- if (output instanceof Promise) {
871
- pending = output
872
- .catch(err => error = err)
873
- .then(val => state[key] = val)
874
- .finally(() => {
875
- pending = undefined;
876
- this.update(key);
877
- });
878
- return;
879
- }
880
- return state[key] = output;
881
- };
882
- const suspend = () => {
883
- if (required === false)
884
- return undefined;
885
- const issue = Oops$7.NotReady(subject, key);
886
- Object.assign(pending, {
887
- message: issue.message,
888
- stack: issue.stack
838
+ let pending;
839
+ let error;
840
+ const init = () => {
841
+ const output = typeof factory == "function" ?
842
+ mayRetry(() => factory.call(subject, key, subject)) :
843
+ factory;
844
+ if (output instanceof Promise) {
845
+ pending = output
846
+ .catch(err => error = err)
847
+ .then(val => {
848
+ state.set(key, val);
849
+ return val;
850
+ })
851
+ .finally(() => {
852
+ pending = undefined;
853
+ this.update(key);
889
854
  });
890
- throw pending;
891
- };
892
- if (required)
893
- try {
894
- init();
895
- }
896
- catch (err) {
897
- Oops$7.Failed(subject, key).warn();
898
- throw err;
899
- }
900
- get = () => {
901
- if (pending)
902
- return suspend();
903
- if (error)
904
- throw error;
905
- if (key in state)
906
- return state[key];
907
- let output = init();
908
- return pending
909
- ? suspend()
910
- : output;
911
- };
912
- }
855
+ return;
856
+ }
857
+ state.set(key, output);
858
+ return output;
859
+ };
860
+ const suspend = () => {
861
+ if (required === false)
862
+ return undefined;
863
+ const issue = Oops$7.NotReady(subject, key);
864
+ Object.assign(pending, {
865
+ message: issue.message,
866
+ stack: issue.stack
867
+ });
868
+ throw pending;
869
+ };
870
+ if (required)
871
+ try {
872
+ init();
873
+ }
874
+ catch (err) {
875
+ Oops$7.Failed(subject, key).warn();
876
+ throw err;
877
+ }
878
+ get = () => {
879
+ if (pending)
880
+ return suspend();
881
+ if (error)
882
+ throw error;
883
+ if (state.has(key))
884
+ return state.get(key);
885
+ let output = init();
886
+ return pending
887
+ ? suspend()
888
+ : output;
889
+ };
913
890
  if (typeof argument == "function")
914
891
  set = createValueEffect(argument);
915
892
  else
@@ -919,8 +896,24 @@ function set(factory, argument) {
919
896
  };
920
897
  return {
921
898
  set,
922
- get,
923
- suspense
899
+ get
900
+ };
901
+ });
902
+ }
903
+
904
+ function set(value, argument) {
905
+ if (!(1 in arguments)) {
906
+ argument = value;
907
+ value = undefined;
908
+ }
909
+ return apply(function set(key) {
910
+ if (value !== undefined)
911
+ this.state.set(key, value);
912
+ return {
913
+ suspense: true,
914
+ set: typeof argument == "function"
915
+ ? createValueEffect(argument)
916
+ : undefined
924
917
  };
925
918
  });
926
919
  }
@@ -945,35 +938,224 @@ function parent(Expects, required) {
945
938
  });
946
939
  }
947
940
 
941
+ const ANY$1 = Symbol("any");
942
+ function managedMap(control, property, initial) {
943
+ const lastUpdate = new Set();
944
+ const context = new WeakMap();
945
+ const assoc = new WeakMap();
946
+ let managed;
947
+ let value;
948
+ function reset() {
949
+ lastUpdate.clear();
950
+ }
951
+ function emit(key) {
952
+ lastUpdate.add(key);
953
+ control.update(property);
954
+ control.waiting.add(reset);
955
+ }
956
+ function setValue(next, initial) {
957
+ value = next;
958
+ managed = create(next);
959
+ control.state.set(property, next);
960
+ if (!initial)
961
+ emit(ANY$1);
962
+ const watch = (key, on) => {
963
+ const local = assoc.get(on);
964
+ if (local)
965
+ local(key);
966
+ };
967
+ managed.set = (k, v) => {
968
+ emit(k);
969
+ return value.set(k, v);
970
+ };
971
+ managed.delete = (k) => {
972
+ emit(k);
973
+ return value.delete(k);
974
+ };
975
+ managed.clear = () => {
976
+ emit(ANY$1);
977
+ value.clear();
978
+ };
979
+ managed.get = function (key) {
980
+ watch(key, this);
981
+ return value.get(key);
982
+ };
983
+ managed.has = function (key) {
984
+ watch(key, this);
985
+ return value.has(key);
986
+ };
987
+ managed.values = function () {
988
+ watch(ANY$1, this);
989
+ return value.values();
990
+ };
991
+ managed.keys = function () {
992
+ watch(ANY$1, this);
993
+ return value.keys();
994
+ };
995
+ managed.entries = function () {
996
+ watch(ANY$1, this);
997
+ return value.entries();
998
+ };
999
+ managed[Symbol.iterator] = function () {
1000
+ watch(ANY$1, this);
1001
+ return value[Symbol.iterator]();
1002
+ };
1003
+ defineProperty(managed, "size", {
1004
+ get() {
1005
+ watch(ANY$1, this);
1006
+ return value.size;
1007
+ }
1008
+ });
1009
+ }
1010
+ function getValue(local) {
1011
+ if (!local)
1012
+ return managed;
1013
+ if (context.has(local))
1014
+ return context.get(local);
1015
+ const proxy = Object.create(managed);
1016
+ const using = new Set();
1017
+ context.set(local, proxy);
1018
+ assoc.set(proxy, (key) => {
1019
+ if (!local.active)
1020
+ using.add(key);
1021
+ });
1022
+ local.add(property, () => {
1023
+ if (using.has(ANY$1) || lastUpdate.has(ANY$1) && using.size)
1024
+ return true;
1025
+ for (const key of lastUpdate)
1026
+ if (using.has(key))
1027
+ return true;
1028
+ });
1029
+ return proxy;
1030
+ }
1031
+ setValue(initial, true);
1032
+ return {
1033
+ set: setValue,
1034
+ get: getValue
1035
+ };
1036
+ }
1037
+
1038
+ const ANY = Symbol("any");
1039
+ function managedSet(control, property, initial) {
1040
+ const lastUpdate = new Set();
1041
+ const context = new WeakMap();
1042
+ const assoc = new WeakMap();
1043
+ let managed;
1044
+ let value;
1045
+ function reset() {
1046
+ lastUpdate.clear();
1047
+ }
1048
+ function emit(key) {
1049
+ lastUpdate.add(key);
1050
+ control.update(property);
1051
+ control.waiting.add(reset);
1052
+ }
1053
+ function setValue(next, initial) {
1054
+ value = next;
1055
+ managed = create(next);
1056
+ control.state.set(property, next);
1057
+ if (!initial)
1058
+ emit(ANY);
1059
+ const watch = (key, on) => {
1060
+ const local = assoc.get(on);
1061
+ if (local)
1062
+ local(key);
1063
+ };
1064
+ managed.add = (k) => {
1065
+ emit(k);
1066
+ return value.add(k);
1067
+ };
1068
+ managed.delete = (k) => {
1069
+ emit(k);
1070
+ return value.delete(k);
1071
+ };
1072
+ managed.clear = () => {
1073
+ emit(ANY);
1074
+ value.clear();
1075
+ };
1076
+ managed.has = function (key) {
1077
+ watch(key, this);
1078
+ return value.has(key);
1079
+ };
1080
+ managed.values = function () {
1081
+ watch(ANY, this);
1082
+ return value.values();
1083
+ };
1084
+ managed.keys = function () {
1085
+ watch(ANY, this);
1086
+ return value.keys();
1087
+ };
1088
+ managed.entries = function () {
1089
+ watch(ANY, this);
1090
+ return value.entries();
1091
+ };
1092
+ managed[Symbol.iterator] = function () {
1093
+ watch(ANY, this);
1094
+ return value[Symbol.iterator]();
1095
+ };
1096
+ defineProperty(managed, "size", {
1097
+ get() {
1098
+ watch(ANY, this);
1099
+ return value.size;
1100
+ }
1101
+ });
1102
+ }
1103
+ function getValue(local) {
1104
+ if (!local)
1105
+ return managed;
1106
+ if (context.has(local))
1107
+ return context.get(local);
1108
+ const proxy = Object.create(managed);
1109
+ const using = new Set();
1110
+ context.set(local, proxy);
1111
+ assoc.set(proxy, (key) => {
1112
+ if (!local.active)
1113
+ using.add(key);
1114
+ });
1115
+ local.add(property, () => {
1116
+ if (using.has(ANY) || lastUpdate.has(ANY) && using.size)
1117
+ return true;
1118
+ for (const key of lastUpdate)
1119
+ if (using.has(key))
1120
+ return true;
1121
+ });
1122
+ return proxy;
1123
+ }
1124
+ setValue(initial, true);
1125
+ return {
1126
+ set: setValue,
1127
+ get: getValue
1128
+ };
1129
+ }
1130
+
948
1131
  const Oops$5 = issues({
949
1132
  BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
950
1133
  });
951
1134
  function use$1(input, argument) {
952
1135
  return apply(function use(key) {
953
- const { subject } = this;
954
- const onUpdate = (next) => {
955
- this.state[key] = next;
1136
+ const { state, subject } = this;
1137
+ if (typeof input === "function")
1138
+ input = Model.isTypeof(input)
1139
+ ? new input()
1140
+ : input();
1141
+ else if (input && typeof input !== "object")
1142
+ throw Oops$5.BadArgument(typeof input);
1143
+ if (input instanceof Map)
1144
+ return managedMap(this, key, input);
1145
+ if (input instanceof Set)
1146
+ return managedSet(this, key, input);
1147
+ function onUpdate(next) {
1148
+ state.set(key, next);
956
1149
  if (next) {
957
1150
  Parent.set(next, subject);
958
- control(next);
1151
+ ensure(next);
959
1152
  }
960
1153
  if (typeof argument == "function")
961
1154
  argument(next);
962
1155
  return true;
963
- };
964
- if (input) {
965
- const value = Model.isTypeof(input)
966
- ? new input() :
967
- typeof input === "object"
968
- ? input :
969
- typeof input === "function"
970
- ? input()
971
- : null;
972
- if (value === null)
973
- throw Oops$5.BadArgument(typeof input);
974
- if (value)
975
- onUpdate(value);
976
1156
  }
1157
+ if (input)
1158
+ onUpdate(input);
977
1159
  return {
978
1160
  set: onUpdate,
979
1161
  recursive: true
@@ -1085,7 +1267,8 @@ function tap(type, argument) {
1085
1267
  }
1086
1268
  else if (!instance && argument)
1087
1269
  throw Oops$3.AmbientRequired(type.name, subject, key);
1088
- this.update(key, instance);
1270
+ this.state.set(key, instance);
1271
+ this.update(key);
1089
1272
  });
1090
1273
  return {
1091
1274
  recursive: true,
@@ -1130,7 +1313,7 @@ function useModel(source, arg, arg2) {
1130
1313
  new source() :
1131
1314
  source() :
1132
1315
  source;
1133
- control(instance);
1316
+ ensure(instance);
1134
1317
  if (typeof cb == "function")
1135
1318
  cb(instance);
1136
1319
  return instance;
@@ -1148,7 +1331,7 @@ function useModel(source, arg, arg2) {
1148
1331
  return instance;
1149
1332
  }
1150
1333
  else {
1151
- const local = use(refresh => (new Subscriber(instance, () => refresh)));
1334
+ const local = use(refresh => (ensure(instance).subscribe(() => refresh)));
1152
1335
  if (typeof arg == "object") {
1153
1336
  local.active = false;
1154
1337
  if (typeof arg2 !== "object")
@@ -1174,7 +1357,7 @@ function useModel(source, arg, arg2) {
1174
1357
 
1175
1358
  function useFrom(target, compute, suspend) {
1176
1359
  const local = use(refresh => {
1177
- const sub = new Subscriber(target, () => update);
1360
+ const sub = ensure(target).subscribe(() => update);
1178
1361
  const spy = sub.proxy;
1179
1362
  let value = compute.call(spy, spy);
1180
1363
  let update;
@@ -1226,23 +1409,14 @@ function useTap(source, path, expect) {
1226
1409
  }, [])();
1227
1410
  if (typeof path == "function")
1228
1411
  return useFrom(instance, path, expect);
1229
- const local = use(refresh => {
1230
- const parent = control(instance);
1231
- const sub = new Subscriber(parent, () => refresh);
1232
- if (typeof path == "string") {
1233
- const source = sub.proxy;
1234
- defineProperty(sub, "proxy", {
1235
- get() {
1236
- const value = source[path];
1237
- if (value === undefined && expect)
1238
- throw suspend(parent, path);
1239
- return value;
1240
- }
1241
- });
1242
- }
1243
- return sub;
1244
- });
1412
+ const local = use(refresh => (ensure(instance).subscribe(() => refresh)));
1245
1413
  React__default["default"].useLayoutEffect(local.commit, []);
1414
+ if (typeof path !== "undefined") {
1415
+ const value = local.proxy[path];
1416
+ if (value === undefined && expect)
1417
+ throw suspend(ensure(instance), path);
1418
+ return value;
1419
+ }
1246
1420
  return local.proxy;
1247
1421
  }
1248
1422
 
@@ -1263,7 +1437,7 @@ class MVC extends Model {
1263
1437
  static new(arg) {
1264
1438
  const instance = React__default["default"].useMemo(() => {
1265
1439
  const instance = new this();
1266
- control(instance);
1440
+ ensure(instance);
1267
1441
  if (typeof arg == "function")
1268
1442
  arg(instance);
1269
1443
  else if (arg)
@@ -1348,7 +1522,7 @@ function useAppliedProps(within, props) {
1348
1522
  const targets = within.local;
1349
1523
  return function integrate(props) {
1350
1524
  for (const [key, value] of entries(props))
1351
- if (["of", "for", "children"].indexOf(key) < 0)
1525
+ if (!["of", "for", "children"].includes(key))
1352
1526
  for (const into of targets)
1353
1527
  if (into && key in into)
1354
1528
  into[key] = value;
@@ -1360,7 +1534,7 @@ function RenderFunction(props) {
1360
1534
  const hook = use(refresh => {
1361
1535
  const targets = props.context.local;
1362
1536
  if (targets.length == 1)
1363
- return new Subscriber(targets[0], () => refresh);
1537
+ return ensure(targets[0]).subscribe(() => refresh);
1364
1538
  return {};
1365
1539
  });
1366
1540
  if (hook.commit)
@@ -1426,6 +1600,7 @@ exports.array = array;
1426
1600
  exports["default"] = MVC;
1427
1601
  exports.from = from;
1428
1602
  exports.parent = parent;
1603
+ exports.put = put;
1429
1604
  exports.ref = ref;
1430
1605
  exports.set = set;
1431
1606
  exports.tap = tap;