@raf-query/core 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/CHANGELOG.md +7 -1
- package/README.md +109 -39
- package/dist/all-keyed.d.mts +18 -0
- package/dist/all-keyed.mjs +19 -0
- package/dist/cast.mjs +10 -0
- package/dist/client.d.mts +99 -0
- package/dist/client.mjs +234 -0
- package/dist/hydration.d.mts +50 -0
- package/dist/hydration.mjs +50 -0
- package/dist/index.d.mts +7 -4
- package/dist/index.mjs +7 -5
- package/dist/key.d.mts +18 -0
- package/dist/key.mjs +36 -0
- package/dist/notify.mjs +21 -0
- package/dist/options.d.mts +111 -0
- package/dist/options.mjs +35 -0
- package/dist/query.d.mts +77 -0
- package/dist/query.mjs +394 -0
- package/dist/thenable.mjs +37 -0
- package/package.json +1 -1
package/dist/query.mjs
ADDED
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import { scheduleNotify } from "./notify.mjs";
|
|
2
|
+
import { fulfilled, pending } from "./thenable.mjs";
|
|
3
|
+
import { Cause, Effect, Exit, Predicate, Schedule } from "effect";
|
|
4
|
+
//#region src/query.ts
|
|
5
|
+
/** Thrown into a request's awaiters when the cache is cleared mid-request. */
|
|
6
|
+
var CancelledError = class extends Error {
|
|
7
|
+
constructor() {
|
|
8
|
+
super("The query was cancelled");
|
|
9
|
+
this.name = "CancelledError";
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const noop = () => {};
|
|
13
|
+
const identity = (value) => value;
|
|
14
|
+
const defaultObserver = {};
|
|
15
|
+
function isEffectResult(result) {
|
|
16
|
+
return Effect.isEffect(result);
|
|
17
|
+
}
|
|
18
|
+
function isInfiniteData(data) {
|
|
19
|
+
return Predicate.hasProperty(data, "pages") && Predicate.hasProperty(data, "pageParams") && Array.isArray(data.pages) && Array.isArray(data.pageParams);
|
|
20
|
+
}
|
|
21
|
+
function shouldRetry(retry, failureCount, error) {
|
|
22
|
+
if (Predicate.isBoolean(retry)) return retry;
|
|
23
|
+
if (Predicate.isNumber(retry)) return failureCount <= retry;
|
|
24
|
+
return retry(failureCount, error);
|
|
25
|
+
}
|
|
26
|
+
function nextPageParam(options, data) {
|
|
27
|
+
if (data.pages.length === 0) return;
|
|
28
|
+
return options.getNextPageParam(data.pages.at(-1), data.pages, data.pageParams.at(-1), data.pageParams);
|
|
29
|
+
}
|
|
30
|
+
function previousPageParam(options, data) {
|
|
31
|
+
if (data.pages.length === 0 || !options.getPreviousPageParam) return;
|
|
32
|
+
return options.getPreviousPageParam(data.pages[0], data.pages, data.pageParams[0], data.pageParams);
|
|
33
|
+
}
|
|
34
|
+
function addPage(data, page, pageParam, direction, maxPages) {
|
|
35
|
+
const forward = direction === "forward";
|
|
36
|
+
const pages = forward ? [...data.pages, page] : [page, ...data.pages];
|
|
37
|
+
const pageParams = forward ? [...data.pageParams, pageParam] : [pageParam, ...data.pageParams];
|
|
38
|
+
if (maxPages === void 0 || pages.length <= maxPages) return {
|
|
39
|
+
pageParams,
|
|
40
|
+
pages
|
|
41
|
+
};
|
|
42
|
+
return forward ? {
|
|
43
|
+
pageParams: pageParams.slice(-maxPages),
|
|
44
|
+
pages: pages.slice(-maxPages)
|
|
45
|
+
} : {
|
|
46
|
+
pageParams: pageParams.slice(0, maxPages),
|
|
47
|
+
pages: pages.slice(0, maxPages)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
var QueryEntry = class {
|
|
51
|
+
hash;
|
|
52
|
+
key;
|
|
53
|
+
#errorShown = false;
|
|
54
|
+
#errorShownTimer;
|
|
55
|
+
#gcTimer;
|
|
56
|
+
#handle;
|
|
57
|
+
#host;
|
|
58
|
+
#inFlight;
|
|
59
|
+
#listeners = /* @__PURE__ */ new Map();
|
|
60
|
+
#options;
|
|
61
|
+
#pending;
|
|
62
|
+
#staleTimer;
|
|
63
|
+
#state;
|
|
64
|
+
constructor(host, key, hash) {
|
|
65
|
+
this.#host = host;
|
|
66
|
+
this.key = key;
|
|
67
|
+
this.hash = hash;
|
|
68
|
+
this.#handle = {
|
|
69
|
+
input: void 0,
|
|
70
|
+
key
|
|
71
|
+
};
|
|
72
|
+
this.#pending = pending();
|
|
73
|
+
this.#state = {
|
|
74
|
+
data: void 0,
|
|
75
|
+
error: null,
|
|
76
|
+
failureCount: 0,
|
|
77
|
+
fetchDirection: void 0,
|
|
78
|
+
hasData: false,
|
|
79
|
+
isFetching: false,
|
|
80
|
+
isInvalidated: false,
|
|
81
|
+
isStale: true,
|
|
82
|
+
promise: this.#pending.promise,
|
|
83
|
+
status: "pending",
|
|
84
|
+
updatedAt: 0
|
|
85
|
+
};
|
|
86
|
+
this.#scheduleGc();
|
|
87
|
+
}
|
|
88
|
+
get handle() {
|
|
89
|
+
return this.#handle;
|
|
90
|
+
}
|
|
91
|
+
get options() {
|
|
92
|
+
return this.#options;
|
|
93
|
+
}
|
|
94
|
+
/** Readers are subscribed; `invalidate` and focus refetch only what is read. */
|
|
95
|
+
get isObserved() {
|
|
96
|
+
return this.#listeners.size > 0;
|
|
97
|
+
}
|
|
98
|
+
getState = () => this.#state;
|
|
99
|
+
/** Staleness as of now; `getState().isStale` is only refreshed for read entries. */
|
|
100
|
+
isStaleNow = () => this.#computeStale(this.#state);
|
|
101
|
+
subscribe = (listener, observer = defaultObserver) => {
|
|
102
|
+
this.#listeners.set(listener, observer);
|
|
103
|
+
this.#clearGc();
|
|
104
|
+
this.#scheduleStale();
|
|
105
|
+
return () => {
|
|
106
|
+
this.#listeners.delete(listener);
|
|
107
|
+
if (this.#listeners.size === 0) {
|
|
108
|
+
clearTimeout(this.#staleTimer);
|
|
109
|
+
this.#scheduleGc();
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
/** Attach the options and input of the latest factory call. */
|
|
114
|
+
setOptions(options, input) {
|
|
115
|
+
this.#options = options;
|
|
116
|
+
if (this.#handle.input !== input) this.#handle = {
|
|
117
|
+
input,
|
|
118
|
+
key: this.key
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
read = () => {
|
|
122
|
+
const state = this.#state;
|
|
123
|
+
if (!state.hasData && !state.isFetching) {
|
|
124
|
+
if (state.status !== "error" || this.#errorShown) this.fetch().catch(noop);
|
|
125
|
+
else this.#markErrorShown();
|
|
126
|
+
}
|
|
127
|
+
return this.#state.promise;
|
|
128
|
+
};
|
|
129
|
+
fetch = (request = {}) => {
|
|
130
|
+
const options = this.#options;
|
|
131
|
+
const inFlight = this.#inFlight;
|
|
132
|
+
if (inFlight && !(request.restart && options)) {
|
|
133
|
+
if (request.direction) {
|
|
134
|
+
const next = () => this.fetch(request);
|
|
135
|
+
return inFlight.deferred.promise.then(next, next);
|
|
136
|
+
}
|
|
137
|
+
return inFlight.deferred.promise;
|
|
138
|
+
}
|
|
139
|
+
if (!options) return this.#state.promise;
|
|
140
|
+
inFlight?.controller.abort();
|
|
141
|
+
return this.#start(this.#request(options, request), request.direction);
|
|
142
|
+
};
|
|
143
|
+
refetch = () => this.fetch().then(noop, noop);
|
|
144
|
+
fetchNextPage = () => this.fetch({ direction: "forward" }).then(noop, noop);
|
|
145
|
+
fetchPreviousPage = () => this.fetch({ direction: "backward" }).then(noop, noop);
|
|
146
|
+
hasNextPage = () => {
|
|
147
|
+
const options = this.#options;
|
|
148
|
+
const data = this.#state.data;
|
|
149
|
+
return options?.kind === "infinite" && isInfiniteData(data) && nextPageParam(options, data) != null;
|
|
150
|
+
};
|
|
151
|
+
hasPreviousPage = () => {
|
|
152
|
+
const options = this.#options;
|
|
153
|
+
const data = this.#state.data;
|
|
154
|
+
return options?.kind === "infinite" && isInfiniteData(data) && previousPageParam(options, data) != null;
|
|
155
|
+
};
|
|
156
|
+
invalidate = () => {
|
|
157
|
+
this.#set({ isInvalidated: true });
|
|
158
|
+
if (!this.isObserved || !this.#options) return Promise.resolve();
|
|
159
|
+
return this.fetch({ restart: true }).then(noop, noop);
|
|
160
|
+
};
|
|
161
|
+
/** Write data directly, as if a request had returned it. */
|
|
162
|
+
setData(data, updatedAt = Date.now()) {
|
|
163
|
+
this.#succeed(data, updatedAt);
|
|
164
|
+
}
|
|
165
|
+
/** Adopt a request started elsewhere (the server's, during hydration). */
|
|
166
|
+
resume(promise) {
|
|
167
|
+
if (this.#state.hasData || this.#inFlight) return;
|
|
168
|
+
this.#start(Effect.tryPromise({
|
|
169
|
+
catch: identity,
|
|
170
|
+
try: () => Promise.resolve(promise)
|
|
171
|
+
}), void 0).catch(noop);
|
|
172
|
+
}
|
|
173
|
+
/** Refetch a read, stale entry whose readers want it on this event. */
|
|
174
|
+
onWindowEvent(event) {
|
|
175
|
+
const option = event === "focus" ? "refetchOnWindowFocus" : "refetchOnReconnect";
|
|
176
|
+
const fallback = this.#behavior(option) ?? true;
|
|
177
|
+
if ([...this.#listeners.values()].some((observer) => observer[option] ?? fallback) && this.#computeStale(this.#state)) this.fetch().catch(noop);
|
|
178
|
+
}
|
|
179
|
+
/** Stop timers and abort the in-flight request; the entry is leaving the cache. */
|
|
180
|
+
destroy() {
|
|
181
|
+
clearTimeout(this.#gcTimer);
|
|
182
|
+
clearTimeout(this.#staleTimer);
|
|
183
|
+
clearTimeout(this.#errorShownTimer);
|
|
184
|
+
const inFlight = this.#inFlight;
|
|
185
|
+
this.#inFlight = void 0;
|
|
186
|
+
if (inFlight) {
|
|
187
|
+
inFlight.controller.abort();
|
|
188
|
+
inFlight.deferred.reject(new CancelledError());
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
#behavior(name) {
|
|
192
|
+
return this.#options?.[name] ?? this.#host.defaults[name];
|
|
193
|
+
}
|
|
194
|
+
#computeStale(state) {
|
|
195
|
+
if (state.isInvalidated || !state.hasData) return true;
|
|
196
|
+
const staleTime = this.#behavior("staleTime") ?? 0;
|
|
197
|
+
return Date.now() - state.updatedAt >= staleTime;
|
|
198
|
+
}
|
|
199
|
+
#set(patch) {
|
|
200
|
+
const next = {
|
|
201
|
+
...this.#state,
|
|
202
|
+
...patch
|
|
203
|
+
};
|
|
204
|
+
this.#state = {
|
|
205
|
+
...next,
|
|
206
|
+
isStale: this.#computeStale(next)
|
|
207
|
+
};
|
|
208
|
+
for (const listener of this.#listeners.keys()) scheduleNotify(listener);
|
|
209
|
+
this.#host.changed(this);
|
|
210
|
+
this.#scheduleStale();
|
|
211
|
+
}
|
|
212
|
+
#start(request, direction) {
|
|
213
|
+
const deferred = this.#inFlight?.deferred ?? pending();
|
|
214
|
+
const run = {
|
|
215
|
+
controller: new AbortController(),
|
|
216
|
+
deferred
|
|
217
|
+
};
|
|
218
|
+
this.#inFlight = run;
|
|
219
|
+
this.#clearGc();
|
|
220
|
+
if (!this.#state.hasData && this.#state.status === "error") {
|
|
221
|
+
this.#pending = pending();
|
|
222
|
+
this.#set({
|
|
223
|
+
error: null,
|
|
224
|
+
failureCount: 0,
|
|
225
|
+
fetchDirection: direction,
|
|
226
|
+
isFetching: true,
|
|
227
|
+
promise: this.#pending.promise,
|
|
228
|
+
status: "pending"
|
|
229
|
+
});
|
|
230
|
+
} else this.#set({
|
|
231
|
+
failureCount: 0,
|
|
232
|
+
fetchDirection: direction,
|
|
233
|
+
isFetching: true
|
|
234
|
+
});
|
|
235
|
+
Effect.runPromiseExit(request, { signal: run.controller.signal }).then((exit) => this.#settle(run, exit), noop);
|
|
236
|
+
return deferred.promise;
|
|
237
|
+
}
|
|
238
|
+
#settle(run, exit) {
|
|
239
|
+
if (this.#inFlight !== run) return;
|
|
240
|
+
this.#inFlight = void 0;
|
|
241
|
+
if (Exit.isSuccess(exit)) {
|
|
242
|
+
this.#succeed(exit.value, Date.now());
|
|
243
|
+
run.deferred.resolve(exit.value);
|
|
244
|
+
} else if (Cause.hasInterruptsOnly(exit.cause)) {
|
|
245
|
+
this.#set({
|
|
246
|
+
fetchDirection: void 0,
|
|
247
|
+
isFetching: false
|
|
248
|
+
});
|
|
249
|
+
run.deferred.reject(new CancelledError());
|
|
250
|
+
} else {
|
|
251
|
+
const error = Cause.squash(exit.cause);
|
|
252
|
+
this.#fail(error);
|
|
253
|
+
run.deferred.reject(error);
|
|
254
|
+
}
|
|
255
|
+
this.#scheduleGc();
|
|
256
|
+
}
|
|
257
|
+
#succeed(data, updatedAt) {
|
|
258
|
+
const firstLoad = this.#pending;
|
|
259
|
+
this.#pending = void 0;
|
|
260
|
+
firstLoad?.resolve(data);
|
|
261
|
+
this.#set({
|
|
262
|
+
data,
|
|
263
|
+
error: null,
|
|
264
|
+
failureCount: 0,
|
|
265
|
+
fetchDirection: void 0,
|
|
266
|
+
hasData: true,
|
|
267
|
+
isFetching: false,
|
|
268
|
+
isInvalidated: false,
|
|
269
|
+
promise: firstLoad ? firstLoad.promise : fulfilled(data),
|
|
270
|
+
status: "success",
|
|
271
|
+
updatedAt
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
#fail(error) {
|
|
275
|
+
this.#host.reportError(error, this);
|
|
276
|
+
if (!this.#state.hasData) {
|
|
277
|
+
const firstLoad = this.#pending;
|
|
278
|
+
this.#pending = void 0;
|
|
279
|
+
firstLoad?.reject(error);
|
|
280
|
+
this.#errorShown = false;
|
|
281
|
+
}
|
|
282
|
+
this.#set({
|
|
283
|
+
error,
|
|
284
|
+
fetchDirection: void 0,
|
|
285
|
+
isFetching: false,
|
|
286
|
+
status: "error"
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* A failed first load rejects its promise, so the reader throws to an error
|
|
291
|
+
* boundary. Every read in that same task (React retries a throwing render
|
|
292
|
+
* once, StrictMode renders twice) gets the rejection too; a read in a later
|
|
293
|
+
* task — the boundary was reset — starts a new request.
|
|
294
|
+
*/
|
|
295
|
+
#markErrorShown() {
|
|
296
|
+
if (this.#errorShownTimer !== void 0) return;
|
|
297
|
+
this.#errorShownTimer = setTimeout(() => {
|
|
298
|
+
this.#errorShownTimer = void 0;
|
|
299
|
+
this.#errorShown = true;
|
|
300
|
+
}, 0);
|
|
301
|
+
}
|
|
302
|
+
#request(options, request) {
|
|
303
|
+
if (options.kind === "query") return this.#attempt((signal) => options.queryFn({
|
|
304
|
+
queryKey: options.queryKey,
|
|
305
|
+
signal
|
|
306
|
+
}));
|
|
307
|
+
return this.#pagedRequest(options, request);
|
|
308
|
+
}
|
|
309
|
+
#pagedRequest(options, request) {
|
|
310
|
+
const current = isInfiniteData(this.#state.data) ? this.#state.data : void 0;
|
|
311
|
+
const fetchPage = (pageParam, direction) => this.#attempt((signal) => options.queryFn({
|
|
312
|
+
direction,
|
|
313
|
+
pageParam,
|
|
314
|
+
queryKey: options.queryKey,
|
|
315
|
+
signal
|
|
316
|
+
}));
|
|
317
|
+
return Effect.gen(function* () {
|
|
318
|
+
if (request.direction && current) {
|
|
319
|
+
const pageParam = request.direction === "forward" ? nextPageParam(options, current) : previousPageParam(options, current);
|
|
320
|
+
if (pageParam == null) return current;
|
|
321
|
+
const page = yield* fetchPage(pageParam, request.direction);
|
|
322
|
+
return addPage(current, page, pageParam, request.direction, options.maxPages);
|
|
323
|
+
}
|
|
324
|
+
const count = Math.max(request.pages ?? 1, current?.pages.length ?? 0);
|
|
325
|
+
let data = {
|
|
326
|
+
pageParams: [],
|
|
327
|
+
pages: []
|
|
328
|
+
};
|
|
329
|
+
let pageParam = current && current.pageParams.length > 0 ? current.pageParams[0] : options.initialPageParam;
|
|
330
|
+
for (let index = 0; index < count; index++) {
|
|
331
|
+
if (index > 0) {
|
|
332
|
+
const next = nextPageParam(options, data);
|
|
333
|
+
if (next == null) break;
|
|
334
|
+
pageParam = next;
|
|
335
|
+
}
|
|
336
|
+
const page = yield* fetchPage(pageParam, "forward");
|
|
337
|
+
data = addPage(data, page, pageParam, "forward", options.maxPages);
|
|
338
|
+
}
|
|
339
|
+
return data;
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
/** One request: run the `queryFn` with a fresh signal, retrying per policy. */
|
|
343
|
+
#attempt(call) {
|
|
344
|
+
const once = Effect.suspend(() => {
|
|
345
|
+
const controller = new AbortController();
|
|
346
|
+
return Effect.try({
|
|
347
|
+
catch: identity,
|
|
348
|
+
try: () => call(controller.signal)
|
|
349
|
+
}).pipe(Effect.flatMap((result) => isEffectResult(result) ? result : Effect.tryPromise({
|
|
350
|
+
catch: identity,
|
|
351
|
+
try: () => Promise.resolve(result)
|
|
352
|
+
})), Effect.onInterrupt(() => Effect.sync(() => controller.abort())));
|
|
353
|
+
});
|
|
354
|
+
return this.#withRetry(once);
|
|
355
|
+
}
|
|
356
|
+
#withRetry(once) {
|
|
357
|
+
const retry = this.#behavior("retry") ?? (this.#host.isServer ? 0 : 3);
|
|
358
|
+
const countFailure = Effect.sync(() => this.#set({ failureCount: this.#state.failureCount + 1 }));
|
|
359
|
+
const counted = once.pipe(Effect.tapError(() => countFailure));
|
|
360
|
+
if (Schedule.isSchedule(retry)) return Effect.retry(counted, retry);
|
|
361
|
+
const retryDelay = this.#behavior("retryDelay");
|
|
362
|
+
const delayFor = (failureCount, error) => {
|
|
363
|
+
if (retryDelay === void 0) return Math.min(1e3 * 2 ** (failureCount - 1), 3e4);
|
|
364
|
+
return Predicate.isNumber(retryDelay) ? retryDelay : retryDelay(failureCount, error);
|
|
365
|
+
};
|
|
366
|
+
const attempt = counted.pipe(Effect.catch((error) => {
|
|
367
|
+
const failureCount = this.#state.failureCount;
|
|
368
|
+
if (!shouldRetry(retry, failureCount, error)) return Effect.fail(error);
|
|
369
|
+
return Effect.sleep(delayFor(failureCount, error)).pipe(Effect.andThen(Effect.suspend(() => attempt)));
|
|
370
|
+
}));
|
|
371
|
+
return attempt;
|
|
372
|
+
}
|
|
373
|
+
#clearGc() {
|
|
374
|
+
clearTimeout(this.#gcTimer);
|
|
375
|
+
this.#gcTimer = void 0;
|
|
376
|
+
}
|
|
377
|
+
#scheduleGc() {
|
|
378
|
+
this.#clearGc();
|
|
379
|
+
if (this.isObserved || this.#inFlight) return;
|
|
380
|
+
const gcTime = this.#behavior("gcTime") ?? (this.#host.isServer ? Infinity : 3e5);
|
|
381
|
+
if (Number.isFinite(gcTime)) this.#gcTimer = setTimeout(() => this.#host.remove(this), gcTime);
|
|
382
|
+
}
|
|
383
|
+
#scheduleStale() {
|
|
384
|
+
clearTimeout(this.#staleTimer);
|
|
385
|
+
const state = this.#state;
|
|
386
|
+
if (this.#host.isServer || !this.isObserved || state.isStale) return;
|
|
387
|
+
const staleTime = this.#behavior("staleTime") ?? 0;
|
|
388
|
+
if (!Number.isFinite(staleTime)) return;
|
|
389
|
+
const remaining = state.updatedAt + staleTime - Date.now();
|
|
390
|
+
this.#staleTimer = setTimeout(() => this.#set({}), Math.max(remaining, 0) + 1);
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
//#endregion
|
|
394
|
+
export { CancelledError, QueryEntry, isInfiniteData, nextPageParam, previousPageParam };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region src/thenable.ts
|
|
2
|
+
/**
|
|
3
|
+
* Promises that React's `use()` can read synchronously. React checks
|
|
4
|
+
* `status` / `value` / `reason` on a thenable before suspending, so a
|
|
5
|
+
* settled one renders without a fallback.
|
|
6
|
+
*/
|
|
7
|
+
const noop = () => {};
|
|
8
|
+
function fulfilled(value) {
|
|
9
|
+
return Object.assign(Promise.resolve(value), {
|
|
10
|
+
status: "fulfilled",
|
|
11
|
+
value
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function pending() {
|
|
15
|
+
const deferred = Promise.withResolvers();
|
|
16
|
+
const promise = Object.assign(deferred.promise, { status: "pending" });
|
|
17
|
+
promise.catch(noop);
|
|
18
|
+
return {
|
|
19
|
+
promise,
|
|
20
|
+
reject(reason) {
|
|
21
|
+
Object.assign(promise, {
|
|
22
|
+
reason,
|
|
23
|
+
status: "rejected"
|
|
24
|
+
});
|
|
25
|
+
deferred.reject(reason);
|
|
26
|
+
},
|
|
27
|
+
resolve(value) {
|
|
28
|
+
Object.assign(promise, {
|
|
29
|
+
status: "fulfilled",
|
|
30
|
+
value
|
|
31
|
+
});
|
|
32
|
+
deferred.resolve(value);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { fulfilled, pending };
|