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