shelving 1.195.0 → 1.196.0
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/api/provider/DebugAPIProvider.d.ts +4 -2
- package/api/provider/DebugAPIProvider.js +23 -17
- package/package.json +1 -1
- package/store/PayloadFetchStore.d.ts +2 -1
- package/store/PayloadFetchStore.js +12 -2
- package/util/async.d.ts +8 -0
- package/util/async.js +15 -0
- package/util/sequence.js +10 -7
|
@@ -2,7 +2,9 @@ import type { AnyCaller } from "../../util/function.js";
|
|
|
2
2
|
import type { RequestOptions } from "../../util/http.js";
|
|
3
3
|
import type { Endpoint } from "../endpoint/Endpoint.js";
|
|
4
4
|
import { ThroughAPIProvider } from "./ThroughAPIProvider.js";
|
|
5
|
-
/** Provider that logs
|
|
5
|
+
/** Provider that logs operations to the console. */
|
|
6
6
|
export declare class DebugAPIProvider<P, R> extends ThroughAPIProvider<P, R> {
|
|
7
|
-
|
|
7
|
+
getRequest<PP extends P, RR extends R>(endpoint: Endpoint<PP, RR>, payload: PP, options?: RequestOptions, caller?: AnyCaller): Request;
|
|
8
|
+
fetch(request: Request): Promise<Response>;
|
|
9
|
+
parseResponse<PP extends P, RR extends R>(endpoint: Endpoint<PP, RR>, response: Response, caller?: AnyCaller): Promise<RR>;
|
|
8
10
|
}
|
|
@@ -1,37 +1,43 @@
|
|
|
1
1
|
import { debugFullRequest, debugFullResponse } from "../../util/debug.js";
|
|
2
2
|
import { ThroughAPIProvider } from "./ThroughAPIProvider.js";
|
|
3
|
-
/** Provider that logs
|
|
3
|
+
/** Provider that logs operations to the console. */
|
|
4
4
|
export class DebugAPIProvider extends ThroughAPIProvider {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
getRequest(endpoint, payload, options, caller = this.getRequest) {
|
|
6
|
+
const url = this.url.toString();
|
|
7
|
+
const ep = endpoint.toString();
|
|
8
8
|
try {
|
|
9
|
-
request =
|
|
9
|
+
const request = super.getRequest(endpoint, payload, options, caller);
|
|
10
|
+
console.debug("✔ REQUEST", url, ep, payload);
|
|
11
|
+
return request;
|
|
10
12
|
}
|
|
11
13
|
catch (reason) {
|
|
12
|
-
console.error("✘
|
|
14
|
+
console.error("✘ REQUEST", url, ep, payload, reason);
|
|
13
15
|
throw reason;
|
|
14
16
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
let response;
|
|
17
|
+
}
|
|
18
|
+
async fetch(request) {
|
|
19
|
+
const url = this.url.toString();
|
|
19
20
|
try {
|
|
20
|
-
|
|
21
|
+
console.error("→ FETCH", url, await debugFullRequest(request));
|
|
22
|
+
const response = await super.fetch(request);
|
|
23
|
+
console.error("← FETCH", url, await debugFullResponse(response));
|
|
24
|
+
return response;
|
|
21
25
|
}
|
|
22
26
|
catch (reason) {
|
|
23
|
-
console.error("✘ FETCH",
|
|
27
|
+
console.error("✘ FETCH", url, reason);
|
|
24
28
|
throw reason;
|
|
25
29
|
}
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
}
|
|
31
|
+
async parseResponse(endpoint, response, caller = this.parseResponse) {
|
|
32
|
+
const url = this.url.toString();
|
|
33
|
+
const ep = endpoint.toString();
|
|
28
34
|
try {
|
|
29
|
-
const result = await
|
|
30
|
-
console.debug("✔
|
|
35
|
+
const result = await super.parseResponse(endpoint, response, caller);
|
|
36
|
+
console.debug("✔ RESPONSE", url, ep, result);
|
|
31
37
|
return result;
|
|
32
38
|
}
|
|
33
39
|
catch (reason) {
|
|
34
|
-
console.error("✘
|
|
40
|
+
console.error("✘ RESPONSE", url, ep, reason);
|
|
35
41
|
throw reason;
|
|
36
42
|
}
|
|
37
43
|
}
|
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@ export type PayloadFetchCallback<P, R> = (payload: P, signal: AbortSignal) => R
|
|
|
8
8
|
* @param payload The initial payload for the store.
|
|
9
9
|
* @param value The initial value for the store, or `NONE` if it does not have one yet.
|
|
10
10
|
* @param callback An optional callback that, if set, will be called with the current payload when the `fetch()` method is invoked to fetch the next value.
|
|
11
|
+
* @param debounce Delay in milliseconds before the fetch is triggered after a payload change. `busy` becomes `true` immediately; the actual fetch waits for the debounce period to expire. If the payload changes again before the delay expires the previous fetch is cancelled and the timer resets.
|
|
11
12
|
*/
|
|
12
13
|
export declare class PayloadFetchStore<P, R> extends FetchStore<R> {
|
|
13
14
|
/**
|
|
@@ -15,6 +16,6 @@ export declare class PayloadFetchStore<P, R> extends FetchStore<R> {
|
|
|
15
16
|
* - New payloads can be set using `this.payload.value`
|
|
16
17
|
*/
|
|
17
18
|
readonly payload: Store<P>;
|
|
18
|
-
constructor(payload: P, value: R | typeof NONE, callback?: PayloadFetchCallback<P, R
|
|
19
|
+
constructor(payload: P, value: R | typeof NONE, callback?: PayloadFetchCallback<P, R>, debounce?: number);
|
|
19
20
|
[Symbol.asyncDispose](): Promise<void>;
|
|
20
21
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { awaitAbort, getDelay } from "../util/async.js";
|
|
1
2
|
import { awaitDispose } from "../util/dispose.js";
|
|
2
3
|
import { FetchStore } from "./FetchStore.js";
|
|
3
4
|
import { Store } from "./Store.js";
|
|
@@ -7,6 +8,7 @@ import { Store } from "./Store.js";
|
|
|
7
8
|
* @param payload The initial payload for the store.
|
|
8
9
|
* @param value The initial value for the store, or `NONE` if it does not have one yet.
|
|
9
10
|
* @param callback An optional callback that, if set, will be called with the current payload when the `fetch()` method is invoked to fetch the next value.
|
|
11
|
+
* @param debounce Delay in milliseconds before the fetch is triggered after a payload change. `busy` becomes `true` immediately; the actual fetch waits for the debounce period to expire. If the payload changes again before the delay expires the previous fetch is cancelled and the timer resets.
|
|
10
12
|
*/
|
|
11
13
|
export class PayloadFetchStore extends FetchStore {
|
|
12
14
|
/**
|
|
@@ -15,9 +17,17 @@ export class PayloadFetchStore extends FetchStore {
|
|
|
15
17
|
*/
|
|
16
18
|
payload;
|
|
17
19
|
// Override to save initial payload and callback.
|
|
18
|
-
constructor(payload, value, callback) {
|
|
20
|
+
constructor(payload, value, callback, debounce = 0) {
|
|
19
21
|
const payloadStore = new Store(payload);
|
|
20
|
-
|
|
22
|
+
const fetch = callback &&
|
|
23
|
+
(debounce > 0
|
|
24
|
+
? async (signal) => {
|
|
25
|
+
const snap = payloadStore.value;
|
|
26
|
+
await Promise.race([getDelay(debounce), awaitAbort(signal)]);
|
|
27
|
+
return callback(snap, signal);
|
|
28
|
+
}
|
|
29
|
+
: (signal) => callback(payloadStore.value, signal));
|
|
30
|
+
super(value, fetch);
|
|
21
31
|
this.payload = payloadStore;
|
|
22
32
|
void _iterate(this);
|
|
23
33
|
}
|
package/util/async.d.ts
CHANGED
|
@@ -62,3 +62,11 @@ export type Deferred<T = unknown> = {
|
|
|
62
62
|
export declare function getDeferred<T = void>(): Deferred<T>;
|
|
63
63
|
/** Get a promise that automatically resolves after a delay. */
|
|
64
64
|
export declare function getDelay(ms: number): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Get a promise that rejects with the signal's reason when an `AbortSignal` fires.
|
|
67
|
+
* - Rejects immediately if the signal is already aborted.
|
|
68
|
+
* - Use with `Promise.race()` to cancel a concurrent operation when a signal fires.
|
|
69
|
+
*
|
|
70
|
+
* @example await Promise.race([getDelay(300), awaitAbort(signal)]);
|
|
71
|
+
*/
|
|
72
|
+
export declare function awaitAbort(signal: AbortSignal): Promise<never>;
|
package/util/async.js
CHANGED
|
@@ -110,3 +110,18 @@ export function getDeferred() {
|
|
|
110
110
|
export function getDelay(ms) {
|
|
111
111
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
112
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Get a promise that rejects with the signal's reason when an `AbortSignal` fires.
|
|
115
|
+
* - Rejects immediately if the signal is already aborted.
|
|
116
|
+
* - Use with `Promise.race()` to cancel a concurrent operation when a signal fires.
|
|
117
|
+
*
|
|
118
|
+
* @example await Promise.race([getDelay(300), awaitAbort(signal)]);
|
|
119
|
+
*/
|
|
120
|
+
export function awaitAbort(signal) {
|
|
121
|
+
return new Promise((_, reject) => {
|
|
122
|
+
if (signal.aborted)
|
|
123
|
+
reject(signal.reason);
|
|
124
|
+
else
|
|
125
|
+
signal.addEventListener("abort", () => reject(signal.reason), { once: true });
|
|
126
|
+
});
|
|
127
|
+
}
|
package/util/sequence.js
CHANGED
|
@@ -2,8 +2,12 @@ import { UnexpectedError } from "../error/UnexpectedError.js";
|
|
|
2
2
|
import { getDeferred, getDelay } from "./async.js";
|
|
3
3
|
import { ABORT } from "./constants.js";
|
|
4
4
|
/** Turn a `Promise<R>` into an `IteratorAbortResult<R>` */
|
|
5
|
-
|
|
6
|
-
return
|
|
5
|
+
function _awaitAbortResult(value) {
|
|
6
|
+
return value.then(_getAbortResult);
|
|
7
|
+
}
|
|
8
|
+
/** Turn a result `R` into an `IteratorAbortResult<R>` */
|
|
9
|
+
function _getAbortResult(value) {
|
|
10
|
+
return { done: ABORT, value };
|
|
7
11
|
}
|
|
8
12
|
/** Call an iterator's `return()` method (if it exists) with an initial value, and return the `value` it returns. */
|
|
9
13
|
async function _iteratorReturn(iterator, initial, caller) {
|
|
@@ -26,13 +30,12 @@ export function isSequence(value) {
|
|
|
26
30
|
/** Infinite sequence that yields until a `SIGNAL` is received. */
|
|
27
31
|
export async function* repeatUntil(source, ...signals) {
|
|
28
32
|
const iterator = source[Symbol.asyncIterator]();
|
|
33
|
+
const aborts = signals.map(_awaitAbortResult);
|
|
29
34
|
let n;
|
|
30
35
|
while (true) {
|
|
31
36
|
try {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
...signals.map(_awaitAbort),
|
|
35
|
-
]);
|
|
37
|
+
const next = iterator.next(n);
|
|
38
|
+
const { done, value } = await (aborts.length ? Promise.race([next, ...aborts]) : next);
|
|
36
39
|
if (done) {
|
|
37
40
|
// For aborts, tell the iterator we're no longer using it.
|
|
38
41
|
if (done === ABORT)
|
|
@@ -81,7 +84,7 @@ export async function* callSequence(sequence, callback) {
|
|
|
81
84
|
export function runSequence(sequence, onNext, onError, onReturn) {
|
|
82
85
|
const { promise, resolve } = getDeferred();
|
|
83
86
|
void _runSequenceIterator(sequence[Symbol.asyncIterator](), promise, onNext, onError, onReturn);
|
|
84
|
-
return (value) => resolve(
|
|
87
|
+
return (value) => resolve(_getAbortResult(value));
|
|
85
88
|
}
|
|
86
89
|
async function _runSequenceIterator(iterator, stopped, onNext, onError, onReturn) {
|
|
87
90
|
let n;
|