uneventful 0.0.3 → 0.0.4

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/dist/mod.d.ts CHANGED
@@ -222,539 +222,159 @@ declare class CancelError extends Error {
222
222
  }
223
223
 
224
224
  /**
225
- * The result type returned from calls to {@link Each}.next()
225
+ * A backpressure controller: returns true if downstream is ready to accept
226
+ * data.
226
227
  *
227
- * @category Types and Interfaces
228
- */
229
- type EachResult<T> = {
230
- /** The value provided by the source being iterated */
231
- item: T;
232
- /**
233
- * A suspend callback that must be `yield`-ed before the next call to the
234
- * iterator's .next() method. (That is, you must `yield next` it exactly once
235
- * per loop pass. See {@link each}() for more details.)
236
- */
237
- next: Suspend<void>;
238
- };
239
- /**
240
- * The iterable returned by `yield *` {@link each}()
228
+ * @param cb (optional) - a callback to run when the downstream consumer wishes
229
+ * to resume event production (i.e., when a sink calls
230
+ * {@link Throttle.resume}()). The callback is automatically unregistered when
231
+ * invoked, so the producer must re-register it after each call if it wishes to
232
+ * keep being called.
241
233
  *
242
234
  * @category Types and Interfaces
243
235
  */
244
- type Each<T> = IterableIterator<EachResult<T>>;
245
- /**
246
- * Asynchronously iterate over an event source
247
- *
248
- * Usage:
249
- *
250
- * ```ts
251
- * for (const {item: event, next} of yield *each(mouseMove)) {
252
- * console.log(event.clientX, event.clientY);
253
- * yield next; // required exactly once per iteration, even/w continue!
254
- * }
255
- * ```
256
- *
257
- * each(eventSource) yield-returns an iterator of `{item, next}` pairs. The
258
- * item is the data supplied by the event source, and `next` is a
259
- * {@link Suspend}\<void\> that advances the iterator to the next item. It
260
- * *must* be yielded exactly once per loop iteration. If you use `continue` to
261
- * shortcut the loop body, you must `yield next` *before* doing so.
262
- *
263
- * The for-loop will end if the source ends, errors, or is canceled. The source
264
- * is paused while the loop body is running, and resumed when the `yield next`
265
- * happens. If events arrive anyway (e.g. because the source doesn't support
266
- * pausing), they will be ignored unless you pipe the source through the
267
- * {@link slack}() operator to provide a buffer. If the for-loop is exited
268
- * early for any reason (or the iterator's `.return()` is called), the source is
269
- * unsubscribed and the iteration ended.
270
- *
271
- * @category Stream Consumers
272
- */
273
- declare function each<T>(src: Source<T>): Yielding<Each<T>>;
236
+ type Backpressure = (cb?: () => any) => boolean;
274
237
  /**
275
- * An object that can be waited on with `yield *until()`.
238
+ * Create a backpressure control function for the given connection
276
239
  *
277
- * @category Types and Interfaces
240
+ * @category Stream Producers
278
241
  */
279
- type Waitable<T> = UntilMethod<T> | Source<T> | Promise<T> | PromiseLike<T>;
242
+ declare function backpressure(inlet?: Inlet): Backpressure;
280
243
  /**
281
- * An object that can be waited on with `yield *until()`, by calling its
282
- * "uneventful.until" method.
244
+ * Control backpressure for listening streams. This interface is the API
245
+ * internal to the implementation of {@link backpressure}(). Unless you're
246
+ * implementing a backpressurable stream yourself, see the {@link Throttle}
247
+ * interface instead.
283
248
  *
284
249
  * @category Types and Interfaces
285
250
  */
286
- interface UntilMethod<T> {
287
- "uneventful.until"(): Yielding<T>;
251
+ interface Inlet {
252
+ /** Is the main connection open? (i.e. is the creating job not closed yet?) */
253
+ isOpen(): boolean;
254
+ /** Is the conduit currently ready to receive data? */
255
+ isReady(): boolean;
256
+ /**
257
+ * Register a callback to produce more data when the inlet is resumed
258
+ * (The callback is unregistered if the supplied job ends.)
259
+ */
260
+ onReady(cb: () => any, job: Job): this;
288
261
  }
289
262
  /**
290
- * Wait for and return next value (or error) from a data source when processed
291
- * with `yield *` within a {@link Job}.
292
- *
293
- * @param source A {@link Waitable} data source, which can be any of:
294
- * - A {@link Signal} (in which case the job will resume when the value is
295
- * truthy - perhaps immediately!)
296
- * - A {@link Source}
297
- * - A promise, or promise-like object with a `.then()` method
298
- * - An object with an `"uneventful.until"` method returning a {@link Yielding}
299
- * (in which case the result will be the the result of that method)
263
+ * Control backpressure for listening streams
300
264
  *
301
- * @returns a Yieldable that when processed with `yield *` in a job, will return
302
- * the triggered event, promise resolution, or signal value. An error is thrown
303
- * if the promise rejects or the event stream throws or closes early, or the
304
- * signal throws.
265
+ * Obtain instances via {@link throttle}(), then pass them into the appropriate
266
+ * stream-consuming API. (e.g. {@link connect}).
305
267
  *
306
- * @category Scheduling
268
+ * @category Types and Interfaces
307
269
  */
308
- declare function until<T>(source: Waitable<T>): Yielding<T>;
270
+ interface Throttle extends Inlet {
271
+ /** Set inlet status to "paused". */
272
+ pause(): void;
273
+ /**
274
+ * Un-pause, and iterate backpressure-able sources' onReady callbacks to
275
+ * resume sending immediately. (i.e., synchronously!)
276
+ */
277
+ resume(): void;
278
+ }
309
279
  /**
310
- * Run a {@link restarting}() callback for each value produced by a source.
311
- *
312
- * With each event that occurs, any previous callback run is cleaned up before
313
- * the new one begins. (And the last run is cleaned up when the connection or
314
- * job ends.)
315
- *
316
- * This function is almost the exact opposite of {@link each}(), in that the
317
- * stream is never paused (unless you do so manually via a throttle or inlet),
318
- * and if the "loop body" (callback job) is still running when a new value
319
- * arrives, forEach() restarts the job instead of dropping the value.
320
- *
321
- * @param src An event source (i.e. a {@link Producer} or {@link Signal})
322
- * @param sink A callback that receives values from the source
323
- * @param inlet An optional throttle or inlet that will be used to pause the
324
- * source (if it's a signal or supports backpressure)
325
- * @returns a {@link Connection} that can be used to detect the stream
326
- * end/error, or ended to close it early.
280
+ * A Connection is a job that returns void when the connected stream ends
281
+ * itself. If the stream doesn't end itself (e.g. it's an event listener), the
282
+ * job will never return, and only end with a cancel or throw.
327
283
  *
328
- * @category Stream Consumers
284
+ * @category Types and Interfaces
329
285
  */
330
- declare function forEach<T>(src: Source<T>, sink: Sink<T>, inlet?: Inlet): Connection;
286
+ type Connection = Job<void>;
331
287
  /**
332
- * When called without a source, return a callback suitable for use w/{@link pipe}().
333
- * e.g.:
334
- *
335
- * ```ts
336
- * pipe(someSource, ..., forEach(v => { doSomething(v); }), optionalInlet));
337
- * ```
288
+ * A Source is a function that can be called to arrange for data to be
289
+ * produced and sent to a {@link Sink} function for consumption, until the
290
+ * associated {@link Connection} is closed (either by the source or the sink,
291
+ * e.g. if the sink doesn't want more data or the source has no more to send).
338
292
  *
339
- */
340
- declare function forEach<T>(sink: Sink<T>, inlet?: Inlet): (src: Source<T>) => Connection;
341
-
342
- /**
343
- * Error indicating a rule has attempted to write a value it indirectly
344
- * depends on, or which has already been read by another rule in the current
345
- * batch. (Also thrown when a cached function attempts to write a value at all,
346
- * directly or inidirectly.)
293
+ * If the source is a backpressurable stream, it can use the (optional) supplied
294
+ * inlet (usually a {@link throttle}()) to rate-limit its output.
347
295
  *
348
- * @category Errors
349
- */
350
- declare class WriteConflict extends Error {
351
- }
352
- /**
353
- * Error indicating a rule has attempted to write a value it directly depends
354
- * on, or a cached function has called itself, directly or indirectly.
296
+ * A producer function *must* return the special {@link IsStream} value, so
297
+ * TypeScript can tell what functions are usable as sources. (Otherwise any
298
+ * void function with no arguments would appear to be usable as a source!)
355
299
  *
356
- * @category Errors
300
+ * @category Types and Interfaces
357
301
  */
358
- declare class CircularDependency extends Error {
302
+ interface Source<T> {
303
+ /** Subscribe sink to receive values */
304
+ (sink: Sink<T>, conn?: Connection, inlet?: Throttle | Inlet): typeof IsStream;
359
305
  }
360
306
  /**
361
- * A queue for rules to run during a particular kind of period, such as
362
- * microtasks or animation frames. (Can only be obtained or created via
363
- * {@link RuleScheduler.for}().)
307
+ * An uneventful stream is either a {@link Source} or a {@link SignalSource}.
308
+ * (Signals actually implement the {@link Source} interface as an overload, but
309
+ * TypeScript gets confused about that sometimes, so we generally declare our
310
+ * stream *inputs* as `Stream<T>` and our stream *outputs* as {@link Source}, so
311
+ * that TypeScript knows what's what.
364
312
  *
365
- * @category Signals
313
+ * @category Types and Interfaces
366
314
  */
367
- declare class RuleScheduler {
368
- /**
369
- * Run all pending rules on this scheduler.
370
- *
371
- * This is a bound method
372
- *
373
- * (Note: "pending" rules are ones with at least one changed ancestor
374
- * dependency; this doesn't mean they will actually *do* anything,
375
- * since intermediate cached() function results might end up unchanged.)
376
- */
377
- flush: () => void;
378
- /**
379
- * Create an {@link RuleScheduler} from a callback-taking function, that
380
- * you can then use to make rules that run in a specific time frame.
381
- *
382
- * ```ts
383
- * // frame.rule will now create rules that run during animation fames
384
- * const animate = RuleScheduler.for(requestAnimationFrame).rule;
385
- *
386
- * animate(() => {
387
- * // ... do stuff in an animation frame when signals used here change
388
- * })
389
- * ```
390
- *
391
- * Returns the default scheduler if no arguments are given. If called with
392
- * the same function more than once, it returns the same scheduler instance.
393
- *
394
- * @param scheduleFn A single-argument scheduling function (like
395
- * requestAnimationFrame, setImmediate, or queueMicrotask). The scheduler
396
- * will call it from time to time with a single callback. The scheduling
397
- * function should then arrange for that callback to be invoked *once* at
398
- * some future point, when it is the desired time for all pending rules on
399
- * that scheduler to run.
400
- */
401
- static for(scheduleFn?: (cb: () => unknown) => unknown): RuleScheduler;
402
- protected constructor(_scheduleFn?: (cb: () => unknown) => unknown);
403
- /**
404
- * @inheritdoc rule tied to a specific scheduler. See {@link rule} for
405
- * more details.
406
- *
407
- * @remarks The rule will only run during its matching
408
- * {@link RuleScheduler.flush}().
409
- *
410
- * This is a bound method, so you can use it independently of the scheduler
411
- * it came from.
412
- */
413
- rule: (fn: (stop: DisposeFn) => OptionalCleanup) => DisposeFn;
414
- }
315
+ type Stream<T> = Source<T> | SignalSource<T>;
415
316
  /**
416
- * Subscribe a function to run every time certain values change.
417
- *
418
- * @remarks
419
- * The function is run asynchronously, first after being created, then again
420
- * after there are changes in any of the values or cached functions it read
421
- * during its previous run.
422
- *
423
- * The created subscription is tied to the currently-active job (which may be
424
- * another rule). So when that job is ended or restarted, the rule will be
425
- * terminated automatically. You can also terminate it early by calling the
426
- * "stop" function that is both passed to the rule function and returned by
427
- * `rule()`.
428
- *
429
- * Note: this function will throw an error if called without an active job. If
430
- * you need a standalone rule, use {@link detached}.run to wrap the
431
- * call to rule.
432
- *
433
- * @param fn The function that will be run each time its dependencies change.
434
- * The function will be run in a restarted job each time, with any resources
435
- * used by the previous run being cleaned up. The function is passed a single
436
- * argument: a function that can be called to terminate the rule. The function
437
- * should return a cleanup function or void.
317
+ * The call signatures implemented by signals. (They can be used as sources, or
318
+ * called with no arguments to return a value.)
438
319
  *
439
- * @returns A function that can be called to terminate the rule.
320
+ * This type is needed because TypeScript won't infer the overloads of
321
+ * {@link Signal} correctly otherwise. (Specifically, it won't allow it to be
322
+ * used as a zero-agument function.)
440
323
  *
441
- * @category Signals
442
- */
443
- declare const rule: (fn: (stop: DisposeFn) => OptionalCleanup) => DisposeFn;
324
+ * @category Types and Interfaces
325
+ */
326
+ type SignalSource<T> = Source<T> & {
327
+ /** A signal object can be called to get its current value */
328
+ (): T;
329
+ };
444
330
  /**
445
- * Synchronously run pending rules from the default scheduler.
446
- *
447
- * @remarks Equivalent to calling
448
- * {@link RuleScheduler.for}(defer).{@link RuleScheduler.flush flush}().
449
- *
450
- * Note that you should normally only need to call this when you need
451
- * side-effects to occur within a specific synchronous timeframe, e.g. if
452
- * rules need to be able to cancel a synchronous event or continue an
453
- * IndexedDB transaction. (You can also define rules to run in a specific
454
- * timeframe by creating a {@link RuleScheduler} for them, via
455
- * {@link RuleScheduler.for}.)
331
+ * A specially-typed string used to verify that a function supports uneventful's
332
+ * streaming protocol. Return it from a function to implement the
333
+ * {@link Source} type.
456
334
  *
457
- * @category Signals
335
+ * @category Types and Interfaces
458
336
  */
459
- declare const runRules: () => void;
460
-
337
+ declare const IsStream: "uneventful/is-stream";
461
338
  /**
462
- * A function that can be called to get a value.
463
- *
464
- * (This interface is needed because TypeScript won't infer type of
465
- * {@link Signal} correctly otherwise, specifically it won't see it as a zero-agument function.)
339
+ * A `Sink` is a function that receives data from a {@link Stream}.
466
340
  *
467
341
  * @category Types and Interfaces
468
342
  */
469
- type Returns<T> = () => T;
470
- interface Signal<T> extends Producer<T>, Returns<T> {
471
- /**
472
- * A signal object implements the {@link Producer} interface, even if it's
473
- * not directly recognized as one by TypeScript.
474
- */
475
- (sink: Sink<T>, conn?: Connection, inlet?: Inlet): typeof IsStream;
476
- /** A signal object can be called to get its current value */
477
- (): T;
478
- }
343
+ type Sink<T> = (val: T) => void;
479
344
  /**
480
- * An observable value, as a zero-argument callable with extra methods.
481
- *
482
- * Note: this class is not directly instantiable - use {@link cached}() or call
483
- * {@link readonly |.readonly()} on an existing signal instead.
345
+ * A `Transformer` is a function that takes one stream and returns another,
346
+ * possibly one that produces data of a different type. Most operator functions
347
+ * return a transformer, allowing them to be combined via {@link pipe}().
484
348
  *
485
349
  * @category Types and Interfaces
486
350
  */
487
- declare class Signal<T> extends Function implements UntilMethod<T> {
488
- /** The current value */
489
- get value(): T;
490
- /** The current value */
491
- valueOf(): T;
492
- /** The current value, as a string */
493
- toString(): string;
494
- /** The current value */
495
- toJSON(): T;
496
- /** Get the signal's current value, without adding the signal as a dependency */
497
- peek(): T;
498
- /** Get a read-only version of this signal */
499
- readonly(): Signal<T>;
500
- /** New writable signal with a custom setter */
501
- withSet(set: (v: T) => unknown): Writable<T>;
502
- "uneventful.until"(): Yielding<T>;
503
- protected constructor();
504
- }
505
- interface Writable<T> {
506
- /** Set the current value. (Note: this is a bound method so it can be used as a callback.) */
507
- set(val: T): void;
508
- }
351
+ type Transformer<T, V = T> = (input: Stream<T>) => Source<V>;
509
352
  /**
510
- * A {@link Signal} with a {@link Writable.set | .set()} method and writable
511
- * {@link Writable.value | .value} property.
353
+ * Subscribe a sink to a stream, returning a nested job. (Shorthand for
354
+ * {@link getJob}().{@link Job.connect connect}(...).)
512
355
  *
513
- * Note: this class is not directly instantiable - use {@link value}() or call
514
- * {@link Signal.withSet | .withSet()} on an existing signal instead.
356
+ * @param src An event source or signal
357
+ * @param sink A callback that will receive the events
358
+ * @param inlet Optional - a {@link throttle}() to control backpressure
515
359
  *
516
- * @category Types and Interfaces
517
- */
518
- declare class Writable<T> extends Signal<T> {
519
- get value(): T;
520
- set value(val: T);
521
- readonly(): Signal<T>;
522
- }
523
- /**
524
- * Create a {@link Writable} signal with the given inital value
360
+ * @returns A job that can be aborted to end the subscription, and which will
361
+ * end naturally (with a void return or error) if the stream ends itself.
525
362
  *
526
- * @category Signals
363
+ * @category Stream Consumers
527
364
  */
528
- declare function value<T>(val?: T): Writable<T>;
365
+ declare function connect<T>(src: Stream<T>, sink: Sink<T>, inlet?: Throttle | Inlet): Connection;
529
366
  /**
530
- * Create a cached version of a function. The returned callable is also a
531
- * {@link Signal}.
367
+ * Create a backpressure controller for a stream. Pass it to one or more
368
+ * sources you're connecting to, and if they support backpressure they'll
369
+ * respond when you call its .pause() and .resume() methods.
532
370
  *
533
- * Note: If the supplied function has a non-zero `.length` (i.e., it explicitly
534
- * takes arguments), it is assumed to be a {@link Producer}, and the second
535
- * calling signature below will apply, even if TypeScript doesn't see it that
536
- * way!)
371
+ * @param job - Optional: a job that controls readiness. (The throttle will
372
+ * pause indefinitely when the job ends.) Defaults to the currently-active job,
373
+ * but unlike most such defaults, it won't throw if no job is active.
537
374
  *
538
- * @category Signals
375
+ * @category Stream Consumers
539
376
  */
540
- declare function cached<T>(compute: () => T): Signal<T>;
541
- /**
542
- * If the supplied function has a non-zero `.length` (i.e., it explicitly takes
543
- * arguments), it is assumed to be a {@link Producer}, and the second argument is
544
- * a default value for the created signal to use as default value until the
545
- * source produces a value.
546
- *
547
- * The source will be subscribed *only* while the signal is subscribed as a
548
- * stream, or observed (directly or indirectly) by a rule. While subscribed,
549
- * the signal will update itself with the most recent value produced by the
550
- * source, triggering rules or events as appropriate if the value changes. When
551
- * the signal is once again unobserved, it will revert to the supplied inital
552
- * value.
553
- *
554
- * @param source A {@link Producer} providing data which will become this signal's value
555
- * @param initVal The value to use when the signal is unobserved or waiting for the
556
- * first item from the source.
557
- */
558
- declare function cached<T>(source: Producer<T>, initVal?: T): Signal<T>;
559
- declare function cached<T extends Signal<any>>(signal: T): T;
560
- /**
561
- * Call a function without creating a dependency on any signals it reads. (Like
562
- * {@link Signal.peek}, but for any function with any arguments.)
563
- *
564
- * You can also pass in any arguments the function takes, and the function's
565
- * return value is returned.
566
- *
567
- * @returns The result of calling `fn(..args)`
568
- *
569
- * @category Signals
570
- */
571
- declare function noDeps<F extends PlainFunction>(fn: F, ...args: Parameters<F>): ReturnType<F>;
572
- /**
573
- * Arrange for the current signal or rule to recalculate on demand
574
- *
575
- * This lets you interop with systems that have a way to query a value and
576
- * subscribe to changes to it, but not directly produce a signal. (Such as
577
- * querying the DOM state and using a MutationObserver.)
578
- *
579
- * By calling this with a {@link Producer} or {@link RecalcSource}, you arrange
580
- * for it to be subscribed, if and when the call occurs in a rule or a cached
581
- * function that's in use by a rule (directly or indirectly). When the source
582
- * emits a value, the signal machinery will invalidate the caching of the
583
- * function or rule, forcing a recalculation and subsequent rule reruns, if
584
- * applicable.
585
- *
586
- * Note: you should generally only call the 1-argument version of this function
587
- * with "static" sources - i.e. ones that won't change on every call. Otherwise,
588
- * you will end up creating new signals each time, subscribing and unsubscribing
589
- * on every call to recalcWhen().
590
- *
591
- * If the source needs to reference some object, it's best to use the 2-argument
592
- * version (i.e. `changesWhen(someObj, factory)`, where `factory` is a function
593
- * that takes `someObj` and returns a suitable {@link RecalcSource}.)
594
- *
595
- * @remarks
596
- * recalcWhen is specifically designed so that using it does not pull in any
597
- * part of Uneventful's signals framework, in the event a program doesn't
598
- * already use it. This means you can use it in library code to provide signal
599
- * compatibility, without adding bundle bloat to code that doesn't use signals.
600
- *
601
- * @category Signals
602
- */
603
- declare function recalcWhen(src: RecalcSource): void;
604
- /**
605
- * Two-argument variant of recalcWhen
606
- *
607
- * In certain circumstances, you may wish to use recalcWhen with a source
608
- * related to some object. You could call recalcWhen with a closure, but that
609
- * would create and discard signals on every call. So this 2-argument version
610
- * lets you avoid that by allowing the use of an arbitrary object as a key,
611
- * along with a factory function to turn the key into a {@link RecalcSource}.
612
- *
613
- * @param key an object to be used as a key
614
- *
615
- * @param factory a function that will be called with the key to obtain a
616
- * {@link RecalcSource}. Note that this factory function must also be a static
617
- * function, not a closure, or the same memory thrash issue will occur.
618
- */
619
- declare function recalcWhen<T extends WeakKey>(key: T, factory: (key: T) => RecalcSource): void;
620
-
621
- /**
622
- * A backpressure controller: returns true if downstream is ready to accept
623
- * data.
624
- *
625
- * @param cb (optional) - a callback to run when the downstream consumer wishes
626
- * to resume event production (i.e., when a sink calls
627
- * {@link Throttle.resume}()). The callback is automatically unregistered when
628
- * invoked, so the producer must re-register it after each call if it wishes to
629
- * keep being called.
630
- *
631
- * @category Types and Interfaces
632
- */
633
- type Backpressure = (cb?: () => any) => boolean;
634
- /**
635
- * Create a backpressure control function for the given connection
636
- *
637
- * @category Stream Producers
638
- */
639
- declare function backpressure(inlet?: Inlet): Backpressure;
640
- /**
641
- * Control backpressure for listening streams. This interface is the API
642
- * internal to the implementation of {@link backpressure}(). Unless you're
643
- * implementing a backpressurable stream yourself, see the {@link Throttle}
644
- * interface instead.
645
- *
646
- * @category Types and Interfaces
647
- */
648
- interface Inlet {
649
- /** Is the main connection open? (i.e. is the creating job not closed yet?) */
650
- isOpen(): boolean;
651
- /** Is the conduit currently ready to receive data? */
652
- isReady(): boolean;
653
- /**
654
- * Register a callback to produce more data when the inlet is resumed
655
- * (The callback is unregistered if the supplied job ends.)
656
- */
657
- onReady(cb: () => any, job: Job): this;
658
- }
659
- /**
660
- * Control backpressure for listening streams
661
- *
662
- * Obtain instances via {@link throttle}(), then pass them into the appropriate
663
- * stream-consuming API. (e.g. {@link connect}).
664
- *
665
- * @category Types and Interfaces
666
- */
667
- interface Throttle extends Inlet {
668
- /** Set inlet status to "paused". */
669
- pause(): void;
670
- /**
671
- * Un-pause, and iterate backpressure-able sources' onReady callbacks to
672
- * resume sending immediately. (i.e., synchronously!)
673
- */
674
- resume(): void;
675
- }
676
- /**
677
- * A Connection is a job that returns void when the connected stream ends
678
- * itself. If the stream doesn't end itself (e.g. it's an event listener), the
679
- * job will never return, and only end with a cancel or throw.
680
- *
681
- * @category Types and Interfaces
682
- */
683
- type Connection = Job<void>;
684
- /**
685
- * A Producer is a function that can be called to arrange for data to be
686
- * produced and sent to a {@link Sink} function for consumption, until the
687
- * associated {@link Connection} is closed (either by the source or the sink,
688
- * e.g. if the sink doesn't want more data or the source has no more to send).
689
- *
690
- * If the source is a backpressurable stream, it can use the (optional) supplied
691
- * inlet (usually a {@link throttle}()) to rate-limit its output.
692
- *
693
- * A producer function *must* return the special {@link IsStream} value, so
694
- * TypeScript can tell what functions are usable as sources. (Otherwise any
695
- * void function with no arguments would appear to be usable as a source!)
696
- *
697
- * @category Types and Interfaces
698
- */
699
- type Producer<T> = (sink: Sink<T>, conn?: Connection, inlet?: Throttle | Inlet) => typeof IsStream;
700
- /**
701
- * A Source is either a {@link Producer} or a {@link Signal}. (Signals actually
702
- * implement the {@link Producer} interface as an overload, but TypeScript gets
703
- * confused about that sometimes, so we generally declare our stream *inputs* as
704
- * `Source<T>` and our stream *outputs* as {@link Producer}, so that TypeScript
705
- * knows what's what.
706
- *
707
- * @category Types and Interfaces
708
- */
709
- type Source<T> = Producer<T> | Signal<T>;
710
- /**
711
- * A specially-typed string used to verify that a function supports uneventful's
712
- * streaming protocol. Return it from a function to implement the
713
- * {@link Source} type.
714
- *
715
- * @category Types and Interfaces
716
- */
717
- declare const IsStream: "uneventful/is-stream";
718
- /**
719
- * A `Sink` is a function that receives data from a {@link Source}.
720
- *
721
- * @category Types and Interfaces
722
- */
723
- type Sink<T> = (val: T) => void;
724
- /**
725
- * A `Transformer` is a function that takes one source and returns another,
726
- * possibly one that produces data of a different type. Most operator functions
727
- * return a transformer, allowing them to be combined via {@link pipe}().
728
- *
729
- * @category Types and Interfaces
730
- */
731
- type Transformer<T, V = T> = (input: Source<T>) => Producer<V>;
732
- /**
733
- * Subscribe a sink to a source, returning a nested job. (Shorthand for
734
- * {@link getJob}().{@link Job.connect connect}(...).)
735
- *
736
- * @param src An event source or finite data stream
737
- * @param sink A callback that will receive the events
738
- * @param inlet Optional - a {@link throttle}() to control backpressure
739
- *
740
- * @returns A job that can be aborted to end the subscription, and which will
741
- * end naturally (with a void return or error) if the stream ends itself.
742
- *
743
- * @category Stream Consumers
744
- */
745
- declare function connect<T>(src: Source<T>, sink: Sink<T>, inlet?: Throttle | Inlet): Connection;
746
- /**
747
- * Create a backpressure controller for a stream. Pass it to one or more
748
- * sources you're connecting to, and if they support backpressure they'll
749
- * respond when you call its .pause() and .resume() methods.
750
- *
751
- * @param job - Optional: a job that controls readiness. (The throttle will
752
- * pause indefinitely when the job ends.) Defaults to the currently-active job,
753
- * but unlike most such defaults, it won't throw if no job is active.
754
- *
755
- * @category Stream Consumers
756
- */
757
- declare function throttle(job?: Job): Throttle;
377
+ declare function throttle(job?: Job): Throttle;
758
378
  /**
759
379
  * Pipe a stream (or anything else) through a series of single-argument
760
380
  * functions/operators
@@ -1010,7 +630,7 @@ interface Job<T = any> extends Yielding<T>, Promise<T> {
1010
630
  * In order to ensure that all such "child" jobs, resources, and activities
1011
631
  * are marked as canceled *before* any side effects (such as events,
1012
632
  * callbacks or I/O operations) can occur, Uneventful prioritizes *all*
1013
- * release callbacks to run before *any* other callbacks of any kind. since
633
+ * release callbacks to run before *any* other callbacks of any kind. Since
1014
634
  * release callbacks are used for child jobs, this means that the entire job
1015
635
  * subtree is notified immediately of cancellation, before any other actions
1016
636
  * are taken. This ensures that no "stray" operations can continue, unaware
@@ -1054,15 +674,15 @@ interface Job<T = any> extends Yielding<T>, Promise<T> {
1054
674
  * This is basically shorthand for `start<void>(job => void src(sink, job,
1055
675
  * inlet))` -- i.e. a quick way to subscribe to a finite and/or pausable stream.
1056
676
  *
1057
- * @param src An event source or finite data stream
1058
- * @param sink A callback that will receive the events
677
+ * @param src An event source or signal
678
+ * @param sink A callback that will receive the events or values
1059
679
  * @param inlet Optional - a {@link throttle}() to control backpressure
1060
680
  * @returns A job that can be aborted to end the subscription, and which will
1061
681
  * end naturally (with a void return or error) if the stream ends itself.
1062
682
  *
1063
683
  * @category Execution Control
1064
684
  */
1065
- connect<T>(src: Source<T>, sink: Sink<T>, inlet?: Throttle | Inlet): Connection;
685
+ connect<T>(src: Stream<T>, sink: Sink<T>, inlet?: Throttle | Inlet): Connection;
1066
686
  /**
1067
687
  * Invoke a function with this job as the active one, so that calling the
1068
688
  * global {@link must} function will add cleanup callbacks to it,
@@ -1089,7 +709,7 @@ interface Job<T = any> extends Yielding<T>, Promise<T> {
1089
709
  * though TypeScript will act as if they are present at compile time. This
1090
710
  * is because the only way to copy all overloads of a function signature is
1091
711
  * to copy the exact type (as TypeScript has no way to generically say,
1092
- * "this a function with all the same overloads, but none of the
712
+ * "this is a function with all the same overloads, but none of the
1093
713
  * properties").
1094
714
  *
1095
715
  * @category Execution Control
@@ -1255,192 +875,782 @@ interface Job<T = any> extends Yielding<T>, Promise<T> {
1255
875
  /**
1256
876
  * A pausable computation that ultimately produces a value of type T.
1257
877
  *
1258
- * An item of this type can be used to either create a job of type T, or awaited
1259
- * in a job via `yield *` to obtain the value.
878
+ * An item of this type can be used to either create a job of type T, or awaited
879
+ * in a job via `yield *` to obtain the value.
880
+ *
881
+ * Any generator function that ultimately returns a value, implicitly returns a
882
+ * Yielding of that type, but it's best to *explicitly* declare this so that
883
+ * TypeScript can properly type check your yield expressions. (e.g. `function
884
+ * *(): Yielding<number> {}` for a generator function that ultimately returns a
885
+ * number.)
886
+ *
887
+ * Generator functions implementing this type should only ever `yield *` to
888
+ * things that are of Yielding type, such as a {@link Job}, {@link to}() or
889
+ * other generators declared Yielding.
890
+ *
891
+ * @yields {@link Suspend}\<any>
892
+ * @returns T
893
+ *
894
+ *
895
+ * @category Types and Interfaces
896
+ */
897
+ type Yielding<T> = {
898
+ /**
899
+ * An iterator suitable for use with `yield *` (in a job generator) to
900
+ * obtain a result.
901
+ *
902
+ * @category Obtaining Results
903
+ */
904
+ [Symbol.iterator](): JobIterator<T>;
905
+ };
906
+ /**
907
+ * An iterator yielding {@link Suspend} callbacks. (An implementation detail of
908
+ * the {@link Yielding} type.)
909
+ *
910
+ * @category Types and Interfaces
911
+ */
912
+ type JobIterator<T> = Generator<Suspend<any>, T, any>;
913
+ /**
914
+ * An asynchronous operation that can be waited on by a {@link Job}.
915
+ *
916
+ * When a {@link JobIterator} yields a Suspend, the job invokes it with a
917
+ * {@link Request}. The Suspend function should arrange for the request to be
918
+ * settled (via {@link resolve} or {@link reject}).
919
+ *
920
+ * Note: If the request is not settled, **the job will be suspended until
921
+ * cancelled by outside forces**. (Such as its enclosing job ending, or
922
+ * explicit throw()/return() calls on the job instance.)
923
+ *
924
+ * Also note that any subjobs the Suspend function creates (or cleanup callbacks
925
+ * it registers) **will not be cleaned up until the *calling* job ends**. So
926
+ * any resources that won't be needed once the job is resumed should be
927
+ * explicitly disposed of -- in which case you should probably just `yield *` to
928
+ * a {@link start}(), instead of yielding a Suspend!
929
+ *
930
+ * @category Types and Interfaces
931
+ */
932
+ type Suspend<T> = (request: Request<T>) => void;
933
+ /**
934
+ * A request for a value (or error) to be returned asynchronously.
935
+ *
936
+ * A request is like the inverse of a Promise: instead of waiting for it to
937
+ * settle, you settle it by passing it to {@link resolve}() or {@link reject}().
938
+ * Like a promise, it can only be settled once: resolving or rejecting it after
939
+ * it's already resolved or rejected has no effect.
940
+ *
941
+ * Settling a request will cause the requesting job (or other code) to resume
942
+ * immediately, running up to its next suspension or termination. (Unless it's
943
+ * settled while the requesting job is already on the call stack, in which case
944
+ * the job will be resumed later.)
945
+ *
946
+ * (Note: do not call a Request directly, unless you want your code to maybe
947
+ * break in future. Use resolve or reject (or {@link resolver}() or
948
+ * {@link rejecter}()), as 1) they'll shield you from future changes to this
949
+ * protocol and 2) they have better type checking anyway.)
950
+ *
951
+ * @category Types and Interfaces
952
+ */
953
+ interface Request<T> {
954
+ (op: "next", val: T, err?: any): void;
955
+ (op: "throw", val: undefined | null, err: any): void;
956
+ (op: "next" | "throw", val?: T | undefined | null, err?: any): void;
957
+ }
958
+ /**
959
+ * A subscribable function used to trigger signal recalculations
960
+ *
961
+ * It must accept a callback, and should arrange (via {@link must}()) to
962
+ * unsubscribe when its calling job ends. Once subscribed, it should
963
+ * invoke the callback to trigger recalculation of the signal(s) that
964
+ * were targeted via {@link recalcWhen}.
965
+ *
966
+ * @category Types and Interfaces
967
+ */
968
+ type RecalcSource = ((cb: () => void) => unknown);
969
+
970
+ /**
971
+ * Is the given value a function?
972
+ *
973
+ * @category Types and Interfaces
974
+ */
975
+ declare function isFunction(f: any): f is Function;
976
+ /**
977
+ * Return the currently-active Job, or throw an error if none is active.
978
+ *
979
+ * (You can check if a job is active first using {@link isJobActive}().)
980
+ *
981
+ * @category Jobs
982
+ */
983
+ declare function getJob<T = unknown>(): Job<T>;
984
+ /**
985
+ * Obtain a native promise for a job
986
+ *
987
+ * While jobs have the same interface as native promises, there are occasionally
988
+ * reasons to just use one directly. (Like when Uneventful uses this function
989
+ * to implement jobs' promise methods!)
990
+ *
991
+ * @param job Optional: the job to get a native promise for. If none is given,
992
+ * the active job is used.
993
+ *
994
+ * @returns A {@link Promise} that resolves or rejects according to whether the
995
+ * job returns or throws. If the job is canceled, the promise is rejected with
996
+ * a {@link CancelError}.
997
+ *
998
+ * @category Jobs
999
+ */
1000
+ declare function nativePromise<T>(job?: Job<T>): Promise<T>;
1001
+ /**
1002
+ * Return a new {@link Job}. If *either* a parent parameter or stop function
1003
+ * are given, the new job is linked to the parent.
1004
+ *
1005
+ * @param parent The parent job to which the new job should be attached.
1006
+ * Defaults to the currently-active job if none given (assuming a stop
1007
+ * parameter is provided).
1008
+ *
1009
+ * @param stop The function to call to destroy the nested job. Defaults to the
1010
+ * {@link Job.end} method of the new job if none is given (assuming a parent
1011
+ * parameter is provided).
1012
+ *
1013
+ * @returns A new job. The job is linked/nested if any arguments are given,
1014
+ * or a detached (parentless) job otherwise.
1015
+ *
1016
+ * @category Jobs
1017
+ */
1018
+ declare const makeJob: <T, R = unknown>(parent?: Job<R>, stop?: CleanupFn<R>) => Job<T>;
1019
+ /**
1020
+ * A special {@link Job} with no parents, that can be used to create standalone
1021
+ * jobs. detached.start() returns a new detached job, detached.run() can be
1022
+ * used to run code that expects to create a child job, and detached.bind() can
1023
+ * wrap a function to work without a parent job.
1024
+ *
1025
+ * (Note that in all cases, a child job of `detached` *must* be stopped
1026
+ * explicitly, or it may "run" forever, never running its cleanup callbacks.)
1027
+ *
1028
+ * The detached job has a few special features and limitations:
1029
+ *
1030
+ * - It can't be ended, thrown, return()ed, etc. -- you'll get an error
1031
+ *
1032
+ * - It can't have any cleanup functions added: no do, must, onError, etc., and
1033
+ * thus also can't have any native promise, abort signal, etc. used. You can
1034
+ * call its release() method, but nothing will actually be registered and the
1035
+ * returned callback is a no-op.
1036
+ *
1037
+ * - Unhandled errors from jobs without parents (and errors from *any* job's
1038
+ * cleanup functions) are sent to the detached job for handling. This means
1039
+ * whatever you set as the detached job's .{@link Job.asyncCatch asyncCatch}()
1040
+ * handler will receive them. (Its default is Promise.reject, causing an
1041
+ * unhandled promise rejection.)
1042
+ *
1043
+ * @category Jobs
1044
+ */
1045
+ declare const detached: Job<unknown>;
1046
+
1047
+ /**
1048
+ * Convert a (possible) promise to something you can `yield *to()` in a job
1049
+ *
1050
+ * Much like `await valueOrPromiseLike` in an async function, using `yield
1051
+ * *to(valueOrPromiseLike)` in a {@link Job}'s generator function will return
1052
+ * the value or the result of the promise/promise-like object.
1053
+ *
1054
+ * @category Scheduling
1055
+ */
1056
+ declare function to<T>(p: Promise<T> | PromiseLike<T> | T): Yielding<T>;
1057
+ /**
1058
+ * Pause the job for the specified time in ms, e.g. `yield *sleep(1000)` to wait
1059
+ * one second.
1060
+ *
1061
+ * @category Scheduling
1062
+ */
1063
+ declare function sleep(ms: number): Yielding<void>;
1064
+
1065
+ /**
1066
+ * The result type returned from calls to {@link Each}.next()
1067
+ *
1068
+ * @category Types and Interfaces
1069
+ */
1070
+ type EachResult<T> = {
1071
+ /** The value provided by the source being iterated */
1072
+ item: T;
1073
+ /**
1074
+ * A suspend callback that must be `yield`-ed before the next call to the
1075
+ * iterator's .next() method. (That is, you must `yield next` it exactly once
1076
+ * per loop pass. See {@link each}() for more details.)
1077
+ */
1078
+ next: Suspend<void>;
1079
+ };
1080
+ /**
1081
+ * The iterable returned by `yield *` {@link each}()
1082
+ *
1083
+ * @category Types and Interfaces
1084
+ */
1085
+ type Each<T> = IterableIterator<EachResult<T>>;
1086
+ /**
1087
+ * Asynchronously iterate over an event source
1088
+ *
1089
+ * Usage:
1090
+ *
1091
+ * ```ts
1092
+ * for (const {item: event, next} of yield *each(mouseMove)) {
1093
+ * console.log(event.clientX, event.clientY);
1094
+ * yield next; // required exactly once per iteration, even/w continue!
1095
+ * }
1096
+ * ```
1097
+ *
1098
+ * each(eventSource) yield-returns an iterator of `{item, next}` pairs. The
1099
+ * item is the data supplied by the event source, and `next` is a
1100
+ * {@link Suspend}\<void\> that advances the iterator to the next item. It
1101
+ * *must* be yielded exactly once per loop iteration. If you use `continue` to
1102
+ * shortcut the loop body, you must `yield next` *before* doing so.
1103
+ *
1104
+ * The for-loop will end if the source ends, errors, or is canceled. The source
1105
+ * is paused while the loop body is running, and resumed when the `yield next`
1106
+ * happens. If events arrive anyway (e.g. because the source doesn't support
1107
+ * pausing), they will be ignored unless you pipe the source through the
1108
+ * {@link slack}() operator to provide a buffer. If the for-loop is exited
1109
+ * early for any reason (or the iterator's `.return()` is called), the source is
1110
+ * unsubscribed and the iteration ended.
1111
+ *
1112
+ * @category Stream Consumers
1113
+ */
1114
+ declare function each<T>(src: Stream<T>): Yielding<Each<T>>;
1115
+ /**
1116
+ * An object that can be waited on with `yield *until()`, by calling its
1117
+ * "uneventful.until" method. (This mostly exists to allow Signals to optimize
1118
+ * their until() implementation, but is also open for extensions.)
1119
+ *
1120
+ * @category Types and Interfaces
1121
+ */
1122
+ interface UntilMethod<T> {
1123
+ /** Return an async op to resume once a truthy value is available */
1124
+ "uneventful.until"(): Yielding<T>;
1125
+ }
1126
+ /**
1127
+ * An object that can be waited on with `yield *next()`, by calling its
1128
+ * "uneventful.next" method. (This mostly exists to allow Signals to optimize
1129
+ * their next() implementation, but is also open for extensions.)
1130
+ *
1131
+ * @category Types and Interfaces
1132
+ */
1133
+ interface NextMethod<T> {
1134
+ /** Return an async op to resume with the "next" (i.e. not current) value produced */
1135
+ "uneventful.next"(): Yielding<T>;
1136
+ }
1137
+ /**
1138
+ * Wait for and return the next truthy value (or error) from a data source (when
1139
+ * processed with `yield *` within a {@link Job}).
1140
+ *
1141
+ * This differs from {@link next}() in that it waits for the next "truthy" value
1142
+ * (i.e., not null, false, zero, empty string, etc.), and when used with signals
1143
+ * or a signal-using function, it can resume *immediately* if the result is
1144
+ * already truthy. (It also supports zero-argument signal-using functions,
1145
+ * automatically wrapping them with {@link cached}(), as the common use case for
1146
+ * until() is to wait for an arbitrary condition to be satisfied.)
1147
+ *
1148
+ * @param source The source to wait on, which can be:
1149
+ * - An object with an `"uneventful.until"` method returning a {@link Yielding}
1150
+ * (in which case the result will be the the result of calling that method)
1151
+ * - A {@link Signal}, or a zero-argument function returning a value based on
1152
+ * signals (in which case the job resumes as soon as the result is truthy,
1153
+ * perhaps immediately)
1154
+ * - A {@link Source} (in which case the job resumes on the next truthy value
1155
+ * it produces
1156
+ *
1157
+ * (Note: if the supplied source is a function with a non-zero `.length`, it is
1158
+ * assumed to be a {@link Source}.)
1159
+ *
1160
+ * @returns a Yieldable that when processed with `yield *` in a job, will return
1161
+ * the triggered event, or signal value. An error is thrown if event stream
1162
+ * throws or closes early, or the signal throws.
1163
+ *
1164
+ * @category Signals
1165
+ * @category Scheduling
1166
+ */
1167
+ declare function until<T>(source: UntilMethod<T> | Stream<T> | (() => T)): Yielding<T>;
1168
+ /**
1169
+ * Wait for and return the next value (or error) from a data source (when
1170
+ * processed with `yield *` within a {@link Job}).
1171
+ *
1172
+ * This differs from {@link until}() in that it waits for the *next* value
1173
+ * (truthy or not!), and it never resumes immediately for signals, but instead
1174
+ * waits for the signal to *change*. (Also, it does not support zero-argument
1175
+ * functions, unless you wrap them with {@link cached}() first.)
1176
+ *
1177
+ * @param source The source to wait on, which can be:
1178
+ * - An object with an `"uneventful.next"` method returning a {@link Yielding}
1179
+ * (in which case the result will be the the result of calling that method)
1180
+ * - A {@link Signal} or {@link Source} (in which case the job resumes on the
1181
+ * next value it produces)
1182
+ *
1183
+ * (Note: if the supplied source is a function with a non-zero `.length`, it is
1184
+ * assumed to be a {@link Source}.)
1185
+ *
1186
+ * @returns a Yieldable that when processed with `yield *` in a job, will return
1187
+ * the triggered event, or signal value. An error is thrown if event stream
1188
+ * throws or closes early, or the signal throws.
1189
+ *
1190
+ * @category Stream Consumers
1191
+ * @category Scheduling
1192
+ */
1193
+ declare function next<T>(source: NextMethod<T> | Stream<T>): Yielding<T>;
1194
+ /**
1195
+ * Run a {@link restarting}() callback for each value produced by a source.
1196
+ *
1197
+ * With each event that occurs, any previous callback run is cleaned up before
1198
+ * the new one begins. (And the last run is cleaned up when the connection or
1199
+ * job ends.)
1200
+ *
1201
+ * This function is almost the exact opposite of {@link each}(), in that the
1202
+ * stream is never paused (unless you do so manually via a throttle or inlet),
1203
+ * and if the "loop body" (callback job) is still running when a new value
1204
+ * arrives, forEach() restarts the job instead of dropping the value.
1205
+ *
1206
+ * @param src An event source (i.e. a {@link Source} or {@link Signal})
1207
+ * @param sink A callback that receives values from the source
1208
+ * @param inlet An optional throttle or inlet that will be used to pause the
1209
+ * source (if it's a signal or supports backpressure)
1210
+ * @returns a {@link Connection} that can be used to detect the stream
1211
+ * end/error, or ended to close it early.
1212
+ *
1213
+ * @category Stream Consumers
1214
+ */
1215
+ declare function forEach<T>(src: Stream<T>, sink: Sink<T>, inlet?: Inlet): Connection;
1216
+ /**
1217
+ * When called without a source, return a callback suitable for use w/{@link pipe}().
1218
+ * e.g.:
1219
+ *
1220
+ * ```ts
1221
+ * pipe(someSource, ..., forEach(v => { doSomething(v); }), optionalInlet));
1222
+ * ```
1223
+ *
1224
+ */
1225
+ declare function forEach<T>(sink: Sink<T>, inlet?: Inlet): (src: Stream<T>) => Connection;
1226
+
1227
+ /**
1228
+ * A decorator function that supports both TC39 and "legacy" decorator protocols
1229
+ *
1230
+ * @template F the type of method this decorator can decorate. If the method
1231
+ * doesn't conform to this type, compile-time type checks will fail.
1232
+ *
1233
+ * @category Types and Interfaces
1234
+ */
1235
+ type GenericMethodDecorator<F extends AnyFunction> = {
1236
+ /** TC39 Method Decorator @hidden */
1237
+ (fn: F, ctx?: {
1238
+ kind: "method";
1239
+ }): F;
1240
+ /** Legacy Method Decorator @hidden */
1241
+ (proto: object, name: string | symbol, desc?: {
1242
+ value?: F;
1243
+ }): void;
1244
+ };
1245
+ /**
1246
+ * The interface provided by {@link rule}, and other {@link rule.factory}()
1247
+ * functions.
1248
+ *
1249
+ * @category Types and Interfaces
1250
+ */
1251
+ interface RuleFactory {
1252
+ /**
1253
+ * @inheritdoc rule factory tied to a specific scheduler. See {@link rule} for
1254
+ * more details.
1255
+ */
1256
+ (fn: (stop: DisposeFn) => OptionalCleanup): DisposeFn;
1257
+ /**
1258
+ * Stop the currently-executing rule, or throw an error if no rule is
1259
+ * currently running.
1260
+ */
1261
+ stop(): void;
1262
+ /**
1263
+ * Observe a condition and apply an action.
1264
+ *
1265
+ * This is roughly equivalent to `rule(() => { if (condition()) return
1266
+ * action(); })`, except that the rule is *only* rerun if the `action`'s
1267
+ * dependencies change, *or* the truthiness of `condition()` changes. It
1268
+ * will *not* be re-run if only the dependencies of `condition()` have
1269
+ * changed, without affecting its truthiness.
1270
+ *
1271
+ * This behavior can be important for rules that nest other rules, have
1272
+ * cleanups, fire off tasks, etc., as it may be wasteful to constantly tear
1273
+ * them down and set them back up if the enabling condition is a calculation
1274
+ * with frequently-changing dependencies.
1275
+ */
1276
+ if(condition: () => any, action: () => OptionalCleanup): DisposeFn;
1277
+ /**
1278
+ * Decorate a method to behave as a rule, e.g.
1279
+ *
1280
+ * ```ts
1281
+ * const animate = rule.factory(requestAnimationFrame);
1282
+ *
1283
+ * class Draggable {
1284
+ * ⁣@animate.method
1285
+ * trackPosition(handleTop: number, handleLeft: number) {
1286
+ * const {clientX, clientY} = lastMouseEvent();
1287
+ * this.element.style.top = `${clientY - handleTop}px`;
1288
+ * this.element.style.left = `${clientX - handleLeft}px`;
1289
+ * }
1290
+ * }
1291
+ *
1292
+ * // Start running the method in an animation frame for every change to
1293
+ * // lastMouseEvent, until the current job ends:
1294
+ * someDraggable.trackPosition(top, left);
1295
+ * ```
1296
+ *
1297
+ * Each time it's (explicitly) called, the decorated method will start a new
1298
+ * rule, which will repeatedly run the method body (with the original
1299
+ * arguments and `this`) whenever its dependencies change, according to the
1300
+ * schedule defined by the rule factory. (So e.g. `@rule.method` will
1301
+ * update on the microtask after a change, etc.)
1302
+ *
1303
+ * The decorated method will always return a {@link DisposeFn} to let you
1304
+ * explicitly stop the rule before the current job end. But if the original
1305
+ * method body doesn't return a dispose function of its own, TypeScript will
1306
+ * consider the method to return void, unless you explicitly declare its
1307
+ * return type to be `DisposeFn | void`.
1308
+ *
1309
+ * Also note that since rule methods can accept arbitrary parameters, they
1310
+ * do not receive a `stop` parameter, and must therefore use {@link
1311
+ * RuleFactory.stop rule.stop}() if they wish to terminate themselves.
1312
+ */
1313
+ readonly method: GenericMethodDecorator<(...args: any[]) => OptionalCleanup>;
1314
+ /**
1315
+ * Return a rule factory for the given scheduling function, that you can
1316
+ * then use to make rules that run in a specific time frame.
1317
+ *
1318
+ * ```ts
1319
+ * // `animate` will now create rules that run during animation fames
1320
+ * const animate = rule.factory(requestAnimationFrame);
1321
+ *
1322
+ * animate(() => {
1323
+ * // ... do stuff in an animation frame when signals used here change
1324
+ * })
1325
+ * ```
1326
+ *
1327
+ * (In addition to being callable, the returned function is also a
1328
+ * {@link RuleFactory}, and thus has a `.method` decorator, `.if()` method,
1329
+ * and so on.)
1330
+ *
1331
+ * @param scheduleFn A single-argument scheduling function (such as
1332
+ * requestAnimationFrame, setImmediate, or queueMicrotask). The rule
1333
+ * scheduler will call it from time to time with a single callback. The
1334
+ * scheduling function should then arrange for that callback to be invoked
1335
+ * *once* at some future point, when it is the desired time for all pending
1336
+ * rules on that scheduler to run.
1337
+ *
1338
+ * @returns A {@link RuleFactory}, like {@link rule}. If called with the
1339
+ * same scheduling function more than once, it returns the same factory.
1340
+ *
1341
+ */
1342
+ factory(scheduleFn: (cb: () => unknown) => unknown): RuleFactory;
1343
+ }
1344
+ /**
1345
+ * Subscribe a function to run every time certain values change.
1346
+ *
1347
+ * The function is run asynchronously, first after being created, then again
1348
+ * after there are changes in any of the values or cached functions it read
1349
+ * during its previous run.
1350
+ *
1351
+ * The created subscription is tied to the currently-active job (which may be
1352
+ * another rule). So when that job is ended or restarted, the rule will be
1353
+ * terminated automatically. You can also terminate it early by calling the
1354
+ * "stop" function that is both passed to the rule function and returned by
1355
+ * `rule()`.
1356
+ *
1357
+ * Note: this function will throw an error if called without an active job. If
1358
+ * you need a standalone rule, use {@link detached}.run to wrap the
1359
+ * call to rule.
1360
+ *
1361
+ * @param fn The function that will be run each time its dependencies change.
1362
+ * The function will be run in a restarted job each time, with any resources
1363
+ * used by the previous run being cleaned up. The function is passed a single
1364
+ * argument: a function that can be called to terminate the rule. The function
1365
+ * should return a cleanup function or void.
1366
+ *
1367
+ * @returns A function that can be called to terminate the rule.
1368
+ *
1369
+ * @category Signals
1370
+ */
1371
+ declare const rule: ((action: (stop: DisposeFn) => OptionalCleanup) => DisposeFn) & RuleFactory;
1372
+ /**
1373
+ * Synchronously run any pending rules tied to a specific schedule.
1260
1374
  *
1261
- * Any generator function that ultimately returns a value, implicitly returns a
1262
- * Yielding of that type, but it's best to *explicitly* declare this so that
1263
- * TypeScript can properly type check your yield expressions. (e.g. `function
1264
- * *(): Yielding<number> {}` for a generator function that ultimately returns a
1265
- * number.)
1375
+ * (Note: "pending" rules are ones with at least one changed ancestor
1376
+ * dependency; this doesn't mean they will actually *do* anything, since
1377
+ * intermediate cached() function results might end up unchanged.)
1266
1378
  *
1267
- * Generator functions implementing this type should only ever `yield *` to
1268
- * things that are of Yielding type, such as a {@link Job}, {@link to}() or
1269
- * other generators declared Yielding.
1379
+ * You should normally only need to call this when you need to *force*
1380
+ * side-effects to occur within a specific *synchronous* timeframe, e.g. if
1381
+ * rules need to be able to cancel a synchronous event or continue an IndexedDB
1382
+ * transaction. (Otherwise, this is really only useful for testing.)
1270
1383
  *
1271
- * @yields {@link Suspend}\<any>
1272
- * @returns T
1384
+ * @param scheduleFn The scheduler used to create the rule factory you wish to
1385
+ * run pending rules for. If not given, the default {@link rule}() factory is
1386
+ * targeted.
1273
1387
  *
1388
+ * @category Signals
1389
+ */
1390
+ declare function runRules(scheduleFn?: (cb: () => unknown) => unknown): void;
1391
+
1392
+ /**
1393
+ * Error indicating a rule has attempted to write a value it indirectly
1394
+ * depends on, or which has already been read by another rule in the current
1395
+ * batch. (Also thrown when a cached function attempts to write a value at all,
1396
+ * directly or inidirectly.)
1274
1397
  *
1275
- * @category Types and Interfaces
1398
+ * @category Errors
1276
1399
  */
1277
- type Yielding<T> = {
1278
- /**
1279
- * An iterator suitable for use with `yield *` (in a job generator) to
1280
- * obtain a result.
1281
- *
1282
- * @category Obtaining Results
1283
- */
1284
- [Symbol.iterator](): JobIterator<T>;
1285
- };
1400
+ declare class WriteConflict extends Error {
1401
+ }
1286
1402
  /**
1287
- * An iterator yielding {@link Suspend} callbacks. (An implementation detail of
1288
- * the {@link Yielding} type.)
1403
+ * Error indicating a rule has attempted to write a value it directly depends
1404
+ * on, or a cached function has called itself, directly or indirectly.
1289
1405
  *
1290
- * @category Types and Interfaces
1406
+ * @category Errors
1291
1407
  */
1292
- type JobIterator<T> = Generator<Suspend<any>, T, any>;
1408
+ declare class CircularDependency extends Error {
1409
+ }
1410
+
1293
1411
  /**
1294
- * An asynchronous operation that can be waited on by a {@link Job}.
1412
+ * An observable value, as a zero-argument callable with extra methods.
1295
1413
  *
1296
- * When a {@link JobIterator} yields a Suspend, the job invokes it with a
1297
- * {@link Request}. The Suspend function should arrange for the request to be
1298
- * settled (via {@link resolve} or {@link reject}).
1414
+ * In addition to being callable, signals also offer a `.value` getter, and
1415
+ * implement the standard JS methods `.toString()`, `.valueOf()`, and
1416
+ * `.toJSON()` in such a way that they reflect the signal's contents rather than
1417
+ * the signal itself.
1299
1418
  *
1300
- * Note: If the request is not settled, **the job will be suspended until
1301
- * cancelled by outside forces**. (Such as its enclosing job ending, or
1302
- * explicit throw()/return() calls on the job instance.)
1419
+ * Signals also implement the {@link Source} interface, and can thus be
1420
+ * subscribed to. Subscribers receive the current value first, and then any
1421
+ * changes thereafter. They can be waited on by {@link until}(), in which case
1422
+ * the calling job resumes when the signal's value is truthy.
1303
1423
  *
1304
- * Also note that any subjobs the Suspend function creates (or cleanup callbacks
1305
- * it registers) **will not be cleaned up until the *calling* job ends**. So
1306
- * any resources that won't be needed once the job is resumed should be
1307
- * explicitly disposed of -- in which case you should probably just `yield *` to
1308
- * a {@link start}(), instead of yielding a Suspend!
1424
+ * You can also transform a signal to a {@link Writable} by calling its
1425
+ * .{@link Signal.withSet withSet}() method, or create a writable value using
1426
+ * {@link value}().
1309
1427
  *
1310
1428
  * @category Types and Interfaces
1311
1429
  */
1312
- type Suspend<T> = (request: Request<T>) => void;
1430
+ interface Signal<T> extends SignalSource<T>, UntilMethod<T> {
1431
+ /**
1432
+ * The current value
1433
+ *
1434
+ * @category Reading
1435
+ */
1436
+ readonly value: T;
1437
+ /** Current value @hidden */
1438
+ valueOf(): T;
1439
+ /** Current value as a string @hidden */
1440
+ toString(): string;
1441
+ /** The current value @hidden */
1442
+ toJSON(): T;
1443
+ /**
1444
+ * Get the signal's current value, without adding the signal as a dependency
1445
+ *
1446
+ * (This is exactly equivalent to calling {@link peek}(signal), and exists
1447
+ * here mainly for interop with other signal frameworks.)
1448
+ *
1449
+ * @category Reading */
1450
+ peek(): T;
1451
+ /** Get a read-only version of this signal @category Reading */
1452
+ asReadonly(): Signal<T>;
1453
+ /** New writable signal with a custom setter @category Writing */
1454
+ withSet(set: (v: T) => unknown): Writable<T>;
1455
+ /** @hidden */
1456
+ "uneventful.until"(): Yielding<T>;
1457
+ }
1313
1458
  /**
1314
- * A request for a value (or error) to be returned asynchronously.
1315
- *
1316
- * A request is like the inverse of a Promise: instead of waiting for it to
1317
- * settle, you settle it by passing it to {@link resolve}() or {@link reject}().
1318
- * Like a promise, it can only be settled once: resolving or rejecting it after
1319
- * it's already resolved or rejected has no effect.
1320
- *
1321
- * Settling a request will cause the requesting job (or other code) to resume
1322
- * immediately, running up to its next suspension or termination. (Unless it's
1323
- * settled while the requesting job is already on the call stack, in which case
1324
- * the job will be resumed later.)
1325
- *
1326
- * (Note: do not call a Request directly, unless you want your code to maybe
1327
- * break in future. Use resolve or reject (or {@link resolver}() or
1328
- * {@link rejecter}()), as 1) they'll shield you from future changes to this
1329
- * protocol and 2) they have better type checking anyway.)
1459
+ * A {@link Signal} with a {@link Writable.set | .set()} method and writable
1460
+ * {@link Writable.value | .value} property.
1330
1461
  *
1331
1462
  * @category Types and Interfaces
1332
1463
  */
1333
- interface Request<T> {
1334
- (op: "next", val: T, err?: any): void;
1335
- (op: "throw", val: undefined | null, err: any): void;
1336
- (op: "next" | "throw", val?: T | undefined | null, err?: any): void;
1464
+ interface Writable<T> extends Signal<T> {
1465
+ /**
1466
+ * Set the current value. (Note: this is a bound method so it can be used
1467
+ * as a callback.)
1468
+ *
1469
+ * @category Writing
1470
+ */
1471
+ readonly set: (val: T) => void;
1472
+ get value(): T;
1473
+ /** Set the current value */
1474
+ set value(val: T);
1337
1475
  }
1338
1476
  /**
1339
- * A subscribable function used to trigger signal recalculations
1477
+ * A writable signal that can be set to either a value or an expression.
1340
1478
  *
1341
- * It must accept a callback, and should arrange (via {@link must}()) to
1342
- * unsubscribe when its calling job ends. Once subscribed, it should
1343
- * invoke the callback to trigger recalculation of the signal(s) that
1344
- * were targeted via {@link recalcWhen}.
1479
+ * Like a spreadsheet cell, a configurable signal can contain either a value or
1480
+ * a formula. If you .set() a value or change the .value property of the
1481
+ * signal, the formula is cleared. Conversely, if you set a formula with
1482
+ * .setf(), then the value is calculated using that formula from then on, until
1483
+ * another formula is set, or the value is changed directly again.
1345
1484
  *
1346
1485
  * @category Types and Interfaces
1347
1486
  */
1348
- type RecalcSource = ((cb: () => void) => unknown);
1349
-
1487
+ interface Configurable<T> extends Writable<T> {
1488
+ /**
1489
+ * Set a formula that will be used to calculate the signal's value. If it
1490
+ * uses the value of other signals, this signal's value will be recalculated
1491
+ * when they change.
1492
+ *
1493
+ * @category Writing
1494
+ */
1495
+ setf(expr: () => T): this;
1496
+ }
1350
1497
  /**
1351
- * Is the given value a function?
1498
+ * Create a {@link Configurable} signal with the given inital value
1352
1499
  *
1353
- * @category Types and Interfaces
1500
+ * @category Signals
1354
1501
  */
1355
- declare function isFunction(f: any): f is Function;
1502
+ declare function value<T>(val?: T): Configurable<T>;
1356
1503
  /**
1357
- * Return the currently-active Job, or throw an error if none is active.
1504
+ * Create a cached version of a function. The returned callable is also a
1505
+ * {@link Signal}.
1358
1506
  *
1359
- * (You can check if a job is active first using {@link isJobActive}().)
1507
+ * Note: If the supplied function has a non-zero `.length` (i.e., it explicitly
1508
+ * takes arguments), it is assumed to be a {@link Source}, and the second
1509
+ * calling signature below will apply, even if TypeScript doesn't see it that
1510
+ * way!)
1360
1511
  *
1361
- * @category Jobs
1512
+ * @category Signals
1362
1513
  */
1363
- declare function getJob<T = unknown>(): Job<T>;
1514
+ declare function cached<T>(compute: () => T): Signal<T>;
1364
1515
  /**
1365
- * Obtain a native promise for a job
1366
- *
1367
- * While jobs have the same interface as native promises, there are occasionally
1368
- * reasons to just use one directly. (Like when Uneventful uses this function
1369
- * to implement jobs' promise methods!)
1516
+ * If the supplied function has a non-zero `.length` (i.e., it explicitly takes
1517
+ * arguments), it is assumed to be a {@link Source}, and the second argument is
1518
+ * a default value for the created signal to use as default value until the
1519
+ * source produces a value.
1370
1520
  *
1371
- * @param job Optional: the job to get a native promise for. If none is given,
1372
- * the active job is used.
1521
+ * The source will be subscribed *only* while the signal is subscribed as a
1522
+ * stream, or observed (directly or indirectly) by a rule. While subscribed,
1523
+ * the signal will update itself with the most recent value produced by the
1524
+ * source, triggering rules or events as appropriate if the value changes. When
1525
+ * the signal is once again unobserved (or if the source ends without an error),
1526
+ * its value will revert to the supplied default.
1373
1527
  *
1374
- * @returns A {@link Promise} that resolves or rejects according to whether the
1375
- * job returns or throws. If the job is canceled, the promise is rejected with
1376
- * a {@link CancelError}.
1528
+ * If the source ends *with* an error, however, then the cached function will
1529
+ * throw that error whenever called, until/unless it becomes unobserved again.
1530
+ * (And thus reverts to the default value once more.)
1377
1531
  *
1378
- * @category Jobs
1532
+ * @param source A {@link Source} providing data which will become this signal's
1533
+ * value
1534
+ * @param defaultVal The value to use when the signal is unobserved or waiting for
1535
+ * the first item from the source.
1379
1536
  */
1380
- declare function nativePromise<T>(job?: Job<T>): Promise<T>;
1537
+ declare function cached<T>(source: Source<T>, defaultVal?: T): Signal<T>;
1538
+ declare function cached<T extends Signal<any>>(signal: T): T;
1381
1539
  /**
1382
- * Return a new {@link Job}. If *either* a parent parameter or stop function
1383
- * are given, the new job is linked to the parent.
1540
+ * Call a function without creating a dependency on any signals it reads. (Like
1541
+ * {@link Signal.peek}, but for any function with any arguments.)
1384
1542
  *
1385
- * @param parent The parent job to which the new job should be attached.
1386
- * Defaults to the currently-active job if none given (assuming a stop
1387
- * parameter is provided).
1543
+ * You can also pass in any arguments the function takes, and the function's
1544
+ * return value is returned.
1388
1545
  *
1389
- * @param stop The function to call to destroy the nested job. Defaults to the
1390
- * {@link Job.end} method of the new job if none is given (assuming a parent
1391
- * parameter is provided).
1546
+ * (Note: Typed overloads are not supported: TypeScript will use the function's
1547
+ * *last* overload for argument-typing purposes. If you need to call a function
1548
+ * with a specific overload, wrap the function with {@link action}() instead, and
1549
+ * then TypeScript will be able to detect which overload you're using.)
1392
1550
  *
1393
- * @returns A new job. The job is linked/nested if any arguments are given,
1394
- * or a detached (parentless) job otherwise.
1551
+ * @returns The result of calling `fn(..args)`
1395
1552
  *
1396
- * @category Jobs
1553
+ * @category Signals
1397
1554
  */
1398
- declare const makeJob: <T, R = unknown>(parent?: Job<R>, stop?: CleanupFn<R>) => Job<T>;
1555
+ declare function peek<F extends PlainFunction>(fn: F, ...args: Parameters<F>): ReturnType<F>;
1399
1556
  /**
1400
- * A special {@link Job} with no parents, that can be used to create standalone
1401
- * jobs. detached.start() returns a new detached job, detached.run() can be
1402
- * used to run code that expects to create a child job, and detached.bind() can
1403
- * wrap a function to work without a parent job.
1557
+ * Arrange for the current signal or rule to recalculate on demand
1404
1558
  *
1405
- * (Note that in all cases, a child job of `detached` *must* be stopped
1406
- * explicitly, or it may "run" forever, never running its cleanup callbacks.)
1559
+ * This lets you interop with systems that have a way to query a value and
1560
+ * subscribe to changes to it, but not directly produce a signal. (Such as
1561
+ * querying the DOM state and using a MutationObserver.)
1407
1562
  *
1408
- * The detached job has a few special features and limitations:
1563
+ * By calling this with a {@link Source} or {@link RecalcSource}, you arrange
1564
+ * for it to be subscribed, if and when the call occurs in a rule or a cached
1565
+ * function that's in use by a rule (directly or indirectly). When the source
1566
+ * emits a value, the signal machinery will invalidate the caching of the
1567
+ * function or rule, forcing a recalculation and subsequent rule reruns, if
1568
+ * applicable.
1409
1569
  *
1410
- * - It can't be ended, thrown, return()ed, etc. -- you'll get an error
1570
+ * Note: you should generally only call the 1-argument version of this function
1571
+ * with "static" sources - i.e. ones that won't change on every call. Otherwise,
1572
+ * you will end up creating new signals each time, subscribing and unsubscribing
1573
+ * on every call to recalcWhen().
1411
1574
  *
1412
- * - It can't have any cleanup functions added: no do, must, onError, etc., and
1413
- * thus also can't have any native promise, abort signal, etc. used. You can
1414
- * call its release() method, but nothing will actually be registered and the
1415
- * returned callback is a no-op.
1575
+ * If the source needs to reference some object, it's best to use the 2-argument
1576
+ * version (i.e. `recalcWhen(someObj, factory)`, where `factory` is a function
1577
+ * that takes `someObj` and returns a suitable {@link RecalcSource}.)
1416
1578
  *
1417
- * - Unhandled errors from jobs without parents (and errors from *any* job's
1418
- * cleanup functions) are sent to the detached job for handling. This means
1419
- * whatever you set as the detached job's .{@link Job.asyncCatch asyncCatch}()
1420
- * handler will receive them. (Its default is Promise.reject, causing an
1421
- * unhandled promise rejection.)
1579
+ * @remarks
1580
+ * recalcWhen is specifically designed so that using it does not pull in any
1581
+ * part of Uneventful's signals framework, in the event a program doesn't
1582
+ * already use it. This means you can use it in library code to provide signal
1583
+ * compatibility, without adding bundle bloat to code that doesn't use signals.
1422
1584
  *
1423
- * @category Jobs
1585
+ * @category Signals
1424
1586
  */
1425
- declare const detached: Job<unknown>;
1426
-
1587
+ declare function recalcWhen(src: RecalcSource): void;
1427
1588
  /**
1428
- * Convert a promise to something you can `yield *to()` in a job
1589
+ * Two-argument variant of recalcWhen
1429
1590
  *
1430
- * Much like `await valueOrPromiseLike` in an async function, using `yield
1431
- * *to(valueOrPromiseLike)` in a {@link Job}'s generator function will return
1432
- * the value or the result of the promise/promise-like object.
1591
+ * In certain circumstances, you may wish to use recalcWhen with a source
1592
+ * related to some object. You could call recalcWhen with a closure, but that
1593
+ * would create and discard signals on every call. So this 2-argument version
1594
+ * lets you avoid that by allowing the use of an arbitrary object as a key,
1595
+ * along with a factory function to turn the key into a {@link RecalcSource}.
1433
1596
  *
1434
- * @category Scheduling
1597
+ * @param key an object to be used as a key
1598
+ *
1599
+ * @param factory a function that will be called with the key to obtain a
1600
+ * {@link RecalcSource}. (Note that this factory function must also be a static
1601
+ * function, not a closure, or the same memory thrash issue will occur!)
1435
1602
  */
1436
- declare function to<T>(p: Promise<T> | PromiseLike<T> | T): Yielding<T>;
1603
+ declare function recalcWhen<T extends WeakKey>(key: T, factory: (key: T) => RecalcSource): void;
1437
1604
  /**
1438
- * Pause the job for the specified time in ms, e.g. `yield *sleep(1000)` to wait
1439
- * one second.
1605
+ * Wrap a function (or decorate a method) so that signals it reads are not added
1606
+ * as dependencies to the current rule (if any). (Basically, it's shorthand for
1607
+ * wrapping the function or method body in a giant call to {@link peek}().)
1440
1608
  *
1441
- * @category Scheduling
1609
+ * So, instead of writing an action function like this:
1610
+ *
1611
+ * ```ts
1612
+ * function outer(arg1, arg2) {
1613
+ * return peek(() => {
1614
+ * // reactive values used here will not be added to the running rule
1615
+ * })
1616
+ * }
1617
+ * ```
1618
+ * you can just write this:
1619
+ * ```ts
1620
+ * const outer = action((arg1, arg2) => {
1621
+ * // reactive values used here will not be added to the running rule
1622
+ * });
1623
+ * ```
1624
+ * or this:
1625
+ * ```ts
1626
+ * class Something {
1627
+ * ⁣⁣@action // auto-detects TC39 or legacy decorators
1628
+ * someMethod(arg1) {
1629
+ * // reactive values used here will not be added to the running rule
1630
+ * }
1631
+ * }
1632
+ * ```
1633
+ *
1634
+ * @param fn The function to wrap. It can take any arguments or return value,
1635
+ * and overloads are supported. However, any non-standard properties the
1636
+ * function may have had will *not* be present on the wrapped function, even if
1637
+ * TypeScript will act as if they are!
1638
+ *
1639
+ * @returns A wrapped version of the function that passes through its arguments
1640
+ * to the original function, while running with dependency tracking suppressed
1641
+ * (as with {@link peek}()).
1642
+ *
1643
+ * @category Signals
1442
1644
  */
1443
- declare function sleep(ms: number): Yielding<void>;
1645
+ declare function action<F extends AnyFunction>(fn: F): F;
1646
+ /** @hidden TC39 Decorator protocol */
1647
+ declare function action<F extends AnyFunction>(fn: F, ctx: {
1648
+ kind: "method";
1649
+ }): F;
1650
+ /** @hidden Legacy Decorator protocol */
1651
+ declare function action<F extends AnyFunction, D extends {
1652
+ value?: F;
1653
+ }>(clsOrProto: any, name: string | symbol, desc: D): D;
1444
1654
 
1445
1655
  /**
1446
1656
  * A function that emits events, with a .source they're emitted from
@@ -1453,7 +1663,7 @@ interface Emitter<T> {
1453
1663
  /** Call the emitter to emit events on its .source */
1454
1664
  (val: T): void;
1455
1665
  /** An event source that receives the events */
1456
- source: Producer<T>;
1666
+ source: Source<T>;
1457
1667
  /** Close all current subscribers' connections */
1458
1668
  end: () => void;
1459
1669
  /** Close all current subscribers' connections with an error */
@@ -1476,7 +1686,7 @@ declare function emitter<T>(): Emitter<T>;
1476
1686
  *
1477
1687
  * @category Stream Producers
1478
1688
  */
1479
- declare function empty(): Producer<never>;
1689
+ declare function empty(): Source<never>;
1480
1690
  /**
1481
1691
  * Convert an async iterable to an event source
1482
1692
  *
@@ -1486,7 +1696,7 @@ declare function empty(): Producer<never>;
1486
1696
  *
1487
1697
  * @category Stream Producers
1488
1698
  */
1489
- declare function fromAsyncIterable<T>(iterable: AsyncIterable<T>): Producer<T>;
1699
+ declare function fromAsyncIterable<T>(iterable: AsyncIterable<T>): Source<T>;
1490
1700
  /**
1491
1701
  * Create an event source from an element, window, or other event target
1492
1702
  *
@@ -1502,10 +1712,10 @@ declare function fromAsyncIterable<T>(iterable: AsyncIterable<T>): Producer<T>;
1502
1712
  *
1503
1713
  * @category Stream Producers
1504
1714
  */
1505
- declare function fromDomEvent<T extends HTMLElement, K extends keyof HTMLElementEventMap>(target: T, type: K, options?: boolean | AddEventListenerOptions): Producer<HTMLElementEventMap[K]>;
1506
- declare function fromDomEvent<T extends Window, K extends keyof WindowEventMap>(target: T, type: K, options?: boolean | AddEventListenerOptions): Producer<WindowEventMap[K]>;
1507
- declare function fromDomEvent<T extends Document, K extends keyof DocumentEventMap>(target: T, type: K, options?: boolean | AddEventListenerOptions): Producer<DocumentEventMap[K]>;
1508
- declare function fromDomEvent<T extends Event>(target: EventTarget, type: string, options?: boolean | AddEventListenerOptions): Producer<T>;
1715
+ declare function fromDomEvent<T extends HTMLElement, K extends keyof HTMLElementEventMap>(target: T, type: K, options?: boolean | AddEventListenerOptions): Source<HTMLElementEventMap[K]>;
1716
+ declare function fromDomEvent<T extends Window, K extends keyof WindowEventMap>(target: T, type: K, options?: boolean | AddEventListenerOptions): Source<WindowEventMap[K]>;
1717
+ declare function fromDomEvent<T extends Document, K extends keyof DocumentEventMap>(target: T, type: K, options?: boolean | AddEventListenerOptions): Source<DocumentEventMap[K]>;
1718
+ declare function fromDomEvent<T extends Event>(target: EventTarget, type: string, options?: boolean | AddEventListenerOptions): Source<T>;
1509
1719
  /**
1510
1720
  * Convert an iterable to a synchronous event source
1511
1721
  *
@@ -1515,7 +1725,7 @@ declare function fromDomEvent<T extends Event>(target: EventTarget, type: string
1515
1725
  *
1516
1726
  * @category Stream Producers
1517
1727
  */
1518
- declare function fromIterable<T>(iterable: Iterable<T>): Producer<T>;
1728
+ declare function fromIterable<T>(iterable: Iterable<T>): Source<T>;
1519
1729
  /**
1520
1730
  * Convert a Promise to an event source
1521
1731
  *
@@ -1527,7 +1737,7 @@ declare function fromIterable<T>(iterable: Iterable<T>): Producer<T>;
1527
1737
  *
1528
1738
  * @category Stream Producers
1529
1739
  */
1530
- declare function fromPromise<T>(promise: Promise<T> | PromiseLike<T> | T): Producer<T>;
1740
+ declare function fromPromise<T>(promise: Promise<T> | PromiseLike<T> | T): Source<T>;
1531
1741
  /**
1532
1742
  * Create an event source from an arbitrary subscribe/unsubscribe function
1533
1743
  *
@@ -1541,20 +1751,20 @@ declare function fromPromise<T>(promise: Promise<T> | PromiseLike<T> | T): Produ
1541
1751
  *
1542
1752
  * @category Stream Producers
1543
1753
  */
1544
- declare function fromSubscribe<T>(subscribe: (cb: (val: T) => void) => DisposeFn): Producer<T>;
1754
+ declare function fromSubscribe<T>(subscribe: (cb: (val: T) => void) => DisposeFn): Source<T>;
1545
1755
  /**
1546
1756
  * Create a source that emits a single given value
1547
1757
  *
1548
1758
  * @category Stream Producers
1549
1759
  */
1550
- declare function fromValue<T>(val: T): Producer<T>;
1760
+ declare function fromValue<T>(val: T): Source<T>;
1551
1761
  /**
1552
1762
  * Create an event source that issues a number every `ms` milliseconds (starting
1553
1763
  * with 0 after the first interval passes).
1554
1764
  *
1555
1765
  * @category Stream Producers
1556
1766
  */
1557
- declare function interval(ms: number): Producer<number>;
1767
+ declare function interval(ms: number): Source<number>;
1558
1768
  /**
1559
1769
  * Create a dynamic source that is created each time it's subscribed
1560
1770
  *
@@ -1565,7 +1775,7 @@ declare function interval(ms: number): Producer<number>;
1565
1775
  *
1566
1776
  * @category Stream Producers
1567
1777
  */
1568
- declare function lazy<T>(factory: () => Source<T>): Producer<T>;
1778
+ declare function lazy<T>(factory: () => Stream<T>): Source<T>;
1569
1779
  /**
1570
1780
  * An {@link Emitter} with a ready() method, that only supports a single active
1571
1781
  * subscriber. (Useful for testing stream operators and sinks.)
@@ -1590,7 +1800,7 @@ declare function mockSource<T>(): MockSource<T>;
1590
1800
  *
1591
1801
  * @category Stream Producers
1592
1802
  */
1593
- declare function never(): Producer<never>;
1803
+ declare function never(): Source<never>;
1594
1804
  /**
1595
1805
  * Wrap a source to allow multiple subscribers to the same underlying stream
1596
1806
  *
@@ -1612,7 +1822,7 @@ declare function never(): Producer<never>;
1612
1822
  *
1613
1823
  * @category Stream Operators
1614
1824
  */
1615
- declare function share<T>(source: Source<T>): Producer<T>;
1825
+ declare function share<T>(source: Stream<T>): Source<T>;
1616
1826
 
1617
1827
  /**
1618
1828
  * Output multiple streams' contents in order (from an array/iterable of stream
@@ -1627,7 +1837,7 @@ declare function share<T>(source: Source<T>): Producer<T>;
1627
1837
  *
1628
1838
  * @category Stream Operators
1629
1839
  */
1630
- declare function concat<T>(sources: Source<T>[] | Iterable<Source<T>>): Producer<T>;
1840
+ declare function concat<T>(sources: Stream<T>[] | Iterable<Stream<T>>): Source<T>;
1631
1841
  /**
1632
1842
  * Flatten a source of sources by emitting their contents in series
1633
1843
  *
@@ -1641,7 +1851,7 @@ declare function concat<T>(sources: Source<T>[] | Iterable<Source<T>>): Producer
1641
1851
  *
1642
1852
  * @category Stream Operators
1643
1853
  */
1644
- declare function concatAll<T>(sources: Source<Source<T>>): Producer<T>;
1854
+ declare function concatAll<T>(sources: Stream<Stream<T>>): Source<T>;
1645
1855
  /**
1646
1856
  * Map each value of a stream to a substream, then concatenate the resulting
1647
1857
  * substreams
@@ -1653,7 +1863,7 @@ declare function concatAll<T>(sources: Source<Source<T>>): Producer<T>;
1653
1863
  *
1654
1864
  * @category Stream Operators
1655
1865
  */
1656
- declare function concatMap<T, R>(mapper: (v: T, idx: number) => Source<R>): Transformer<T, R>;
1866
+ declare function concatMap<T, R>(mapper: (v: T, idx: number) => Stream<R>): Transformer<T, R>;
1657
1867
  /**
1658
1868
  * Create a subset of a stream, based on a filter function (like Array.filter)
1659
1869
  *
@@ -1686,7 +1896,7 @@ declare function map<T, R>(mapper: (v: T, idx: number) => R): Transformer<T, R>;
1686
1896
  *
1687
1897
  * @category Stream Operators
1688
1898
  */
1689
- declare function merge<T>(sources: Source<T>[] | Iterable<Source<T>>): Producer<T>;
1899
+ declare function merge<T>(sources: Stream<T>[] | Iterable<Stream<T>>): Source<T>;
1690
1900
  /**
1691
1901
  * Create an event source by merging sources from a stream of event sources
1692
1902
  *
@@ -1695,7 +1905,7 @@ declare function merge<T>(sources: Source<T>[] | Iterable<Source<T>>): Producer<
1695
1905
  *
1696
1906
  * @category Stream Operators
1697
1907
  */
1698
- declare function mergeAll<T>(sources: Source<Source<T>>): Producer<T>;
1908
+ declare function mergeAll<T>(sources: Stream<Stream<T>>): Source<T>;
1699
1909
  /**
1700
1910
  * Create an event source by merging sources created by mapping events to sources
1701
1911
  *
@@ -1706,7 +1916,7 @@ declare function mergeAll<T>(sources: Source<Source<T>>): Producer<T>;
1706
1916
  *
1707
1917
  * @category Stream Operators
1708
1918
  */
1709
- declare function mergeMap<T, R>(mapper: (v: T, idx: number) => Source<R>): Transformer<T, R>;
1919
+ declare function mergeMap<T, R>(mapper: (v: T, idx: number) => Stream<R>): Transformer<T, R>;
1710
1920
  /**
1711
1921
  * Skip the first N items from a source
1712
1922
  *
@@ -1723,7 +1933,7 @@ declare function skip<T>(n: number): Transformer<T>;
1723
1933
  *
1724
1934
  * @category Stream Operators
1725
1935
  */
1726
- declare function skipUntil<T>(notifier: Source<any>): Transformer<T>;
1936
+ declare function skipUntil<T>(notifier: Stream<any>): Transformer<T>;
1727
1937
  /**
1728
1938
  * Skip items from a stream until a given condition is false, then output all
1729
1939
  * remaining items. The condition function is not called again once it returns
@@ -1765,7 +1975,7 @@ declare function slack<T>(size: number, dropped?: Sink<T>): Transformer<T>;
1765
1975
  *
1766
1976
  * @category Stream Operators
1767
1977
  */
1768
- declare function switchAll<T>(sources: Source<Source<T>>): Producer<T>;
1978
+ declare function switchAll<T>(sources: Stream<Stream<T>>): Source<T>;
1769
1979
  /**
1770
1980
  * Map each value of a stream to a substream, then output the resulting
1771
1981
  * substreams until a new value arrives.
@@ -1777,7 +1987,7 @@ declare function switchAll<T>(sources: Source<Source<T>>): Producer<T>;
1777
1987
  *
1778
1988
  * @category Stream Operators
1779
1989
  */
1780
- declare function switchMap<T, R>(mapper: (v: T, idx: number) => Source<R>): Transformer<T, R>;
1990
+ declare function switchMap<T, R>(mapper: (v: T, idx: number) => Stream<R>): Transformer<T, R>;
1781
1991
  /**
1782
1992
  * Take the first N items from a source
1783
1993
  *
@@ -1794,7 +2004,7 @@ declare function take<T>(n: number): Transformer<T>;
1794
2004
  *
1795
2005
  * @category Stream Operators
1796
2006
  */
1797
- declare function takeUntil<T>(notifier: Source<any>): Transformer<T>;
2007
+ declare function takeUntil<T>(notifier: Stream<any>): Transformer<T>;
1798
2008
  /**
1799
2009
  * Take items from a stream until a given condition is false, then close the
1800
2010
  * output. The condition function is not called again after it returns false.
@@ -1932,5 +2142,68 @@ declare function abortSignal(job?: Job): AbortSignal;
1932
2142
  */
1933
2143
  declare function restarting<F extends AnyFunction>(task: F): F;
1934
2144
  declare function restarting(): (task: () => OptionalCleanup<never>) => void;
2145
+ /**
2146
+ * Wrap an argument-taking function so it will run in (and returns) a new Job
2147
+ * when called.
2148
+ *
2149
+ * This lets you avoid the common pattern of needing to write your functions or
2150
+ * methods like this:
2151
+ *
2152
+ * ```ts
2153
+ * function outer(arg1, arg2) {
2154
+ * return start(function*() {
2155
+ * // ...
2156
+ * })
2157
+ * }
2158
+ * ```
2159
+ * and instead write them like this:
2160
+ * ```ts
2161
+ * const outer = task(function *(arg1, arg2) {
2162
+ * // ...
2163
+ * });
2164
+ * ```
2165
+ * or this:
2166
+ * ```ts
2167
+ * class Something {
2168
+ * ⁣⁣@task // auto-detects TC39 or legacy decorators
2169
+ * *someMethod(arg1): Yielding<SomeResultType> {
2170
+ * // ...
2171
+ * }
2172
+ * }
2173
+ * ```
2174
+ *
2175
+ * Important: if the wrapped function or method has overloads, the resulting
2176
+ * function type will be based on the **last** overload, because TypeScript (at
2177
+ * least as of 5.x) is still not very good at dealing with higher order
2178
+ * generics, especially if overloads are involved.
2179
+ *
2180
+ * Also note that TypeScript doesn't allow decorators to change the calling
2181
+ * signature or return type of a method, so even though the above method will
2182
+ * return a {@link Job}, TypeScript will only see it as a {@link Yielding}.
2183
+ *
2184
+ * This is fine if all you're going to do is `yield *` it to wait for the
2185
+ * result, but if you need to use any job-specific methods on it, you'll have to
2186
+ * pass it through {@link start} to have TypeScript treat it as an actual job.
2187
+ * (Luckily, start() has a fast path to return the original job if it's passed a
2188
+ * job, so you won't actually create a new job by doing this.)
2189
+ *
2190
+ * @param fn The function to wrap. A function returning a generator or
2191
+ * promise-like object (i.e., a {@link StartObj}).
2192
+ *
2193
+ * @returns A wrapped version of the function that passes through its arguments
2194
+ * to the original function, while running it in a new job. (The wrapper also
2195
+ * returns the job.)
2196
+ *
2197
+ * @category Jobs
2198
+ */
2199
+ declare function task<T, A extends any[], C>(fn: (this: C, ...args: A) => StartObj<T>): (this: C, ...args: A) => Job<T>;
2200
+ /** @hidden TC39 Decorator protocol */
2201
+ declare function task<T, A extends any[], C>(fn: (this: C, ...args: A) => StartObj<T>, ctx: {
2202
+ kind: "method";
2203
+ }): (this: C, ...args: A) => Job<T>;
2204
+ /** @hidden Legacy Decorator protocol */
2205
+ declare function task<T, A extends any[], C, D extends {
2206
+ value?: (this: C, ...args: A) => StartObj<T>;
2207
+ }>(clsOrProto: any, name: string | symbol, desc: D): D;
1935
2208
 
1936
- export { type AnyFunction, type AsyncStart, type Backpressure, CancelError, CancelResult, CircularDependency, type CleanupFn, type Connection, type DisposeFn, type Each, type EachResult, type Emitter, ErrorResult, type HandledError, type Inlet, IsStream, type Job, type JobIterator, type JobResult, type MockSource, type Nothing, type OptionalCleanup, type PlainFunction, type Producer, type RecalcSource, type Request, type Returns, RuleScheduler, Signal, type Sink, type Source, type StartFn, type StartObj, type Suspend, type SyncStart, type Throttle, type Transformer, type UnhandledError, type UntilMethod, ValueResult, type Waitable, Writable, WriteConflict, type Yielding, abortSignal, backpressure, cached, compose, concat, concatAll, concatMap, connect, defer, detached, each, emitter, empty, filter, forEach, fromAsyncIterable, fromDomEvent, fromIterable, fromPromise, fromSubscribe, fromValue, fulfillPromise, getJob, getResult, interval, into, isCancel, isError, isFunction, isHandled, isJobActive, isUnhandled, isValue, lazy, makeJob, map, markHandled, merge, mergeAll, mergeMap, mockSource, must, nativePromise, never, noDeps, noop, pipe, propagateResult, recalcWhen, reject, rejecter, resolve, resolver, restarting, rule, runRules, share, skip, skipUntil, skipWhile, slack, sleep, start, switchAll, switchMap, take, takeUntil, takeWhile, throttle, timeout, to, until, value };
2209
+ export { type AnyFunction, type AsyncStart, type Backpressure, CancelError, CancelResult, CircularDependency, type CleanupFn, type Configurable, type Connection, type DisposeFn, type Each, type EachResult, type Emitter, ErrorResult, type GenericMethodDecorator, type HandledError, type Inlet, IsStream, type Job, type JobIterator, type JobResult, type MockSource, type NextMethod, type Nothing, type OptionalCleanup, type PlainFunction, type RecalcSource, type Request, type RuleFactory, type Signal, type SignalSource, type Sink, type Source, type StartFn, type StartObj, type Stream, type Suspend, type SyncStart, type Throttle, type Transformer, type UnhandledError, type UntilMethod, ValueResult, type Writable, WriteConflict, type Yielding, abortSignal, action, backpressure, cached, compose, concat, concatAll, concatMap, connect, defer, detached, each, emitter, empty, filter, forEach, fromAsyncIterable, fromDomEvent, fromIterable, fromPromise, fromSubscribe, fromValue, fulfillPromise, getJob, getResult, interval, into, isCancel, isError, isFunction, isHandled, isJobActive, isUnhandled, isValue, lazy, makeJob, map, markHandled, merge, mergeAll, mergeMap, mockSource, must, nativePromise, never, next, noop, peek, pipe, propagateResult, recalcWhen, reject, rejecter, resolve, resolver, restarting, rule, runRules, share, skip, skipUntil, skipWhile, slack, sleep, start, switchAll, switchMap, take, takeUntil, takeWhile, task, throttle, timeout, to, until, value };