@duplojs/utils 1.6.0 → 1.6.2
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/common/asserts.cjs +12 -0
- package/dist/common/asserts.d.ts +26 -0
- package/dist/common/asserts.mjs +12 -1
- package/dist/common/callThen.cjs +14 -0
- package/dist/common/callThen.d.ts +35 -0
- package/dist/common/callThen.mjs +12 -0
- package/dist/common/index.d.ts +2 -0
- package/dist/common/queue.cjs +90 -0
- package/dist/common/queue.d.ts +46 -0
- package/dist/common/queue.mjs +87 -0
- package/dist/flow/calledByNext.cjs +13 -0
- package/dist/flow/calledByNext.d.ts +47 -0
- package/dist/flow/calledByNext.mjs +11 -0
- package/dist/flow/debounce.cjs +16 -0
- package/dist/flow/debounce.d.ts +63 -0
- package/dist/flow/debounce.mjs +14 -0
- package/dist/flow/exec.cjs +101 -0
- package/dist/flow/exec.d.ts +4 -3
- package/dist/flow/exec.mjs +101 -0
- package/dist/flow/index.cjs +28 -0
- package/dist/flow/index.d.ts +5 -0
- package/dist/flow/index.mjs +10 -1
- package/dist/flow/initializer.d.ts +3 -3
- package/dist/flow/queue.cjs +19 -0
- package/dist/flow/queue.d.ts +47 -0
- package/dist/flow/queue.mjs +17 -0
- package/dist/flow/run.cjs +118 -0
- package/dist/flow/run.d.ts +6 -4
- package/dist/flow/run.mjs +113 -1
- package/dist/flow/theFlow/calledByNext.cjs +11 -0
- package/dist/flow/theFlow/calledByNext.d.ts +5 -0
- package/dist/flow/theFlow/calledByNext.mjs +8 -0
- package/dist/flow/theFlow/debounce.cjs +11 -0
- package/dist/flow/theFlow/debounce.d.ts +9 -0
- package/dist/flow/theFlow/debounce.mjs +8 -0
- package/dist/flow/theFlow/index.d.ts +11 -3
- package/dist/flow/theFlow/queue.cjs +11 -0
- package/dist/flow/theFlow/queue.d.ts +9 -0
- package/dist/flow/theFlow/queue.mjs +8 -0
- package/dist/flow/theFlow/throttling.cjs +11 -0
- package/dist/flow/theFlow/throttling.d.ts +10 -0
- package/dist/flow/theFlow/throttling.mjs +8 -0
- package/dist/flow/throttling.cjs +27 -0
- package/dist/flow/throttling.d.ts +60 -0
- package/dist/flow/throttling.mjs +25 -0
- package/dist/flow/toFunction.cjs +15 -0
- package/dist/flow/toFunction.d.ts +56 -0
- package/dist/flow/toFunction.mjs +13 -0
- package/dist/index.cjs +6 -0
- package/dist/index.mjs +3 -1
- package/dist/metadata.json +99 -0
- package/dist/object/types/getPropsWithValue.d.ts +1 -1
- package/dist/object/types/getPropsWithValueExtends.d.ts +1 -1
- package/package.json +1 -1
package/dist/flow/exec.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type SimplifyTopLevel, type IsEqual, type IsExtends, type Or } from "../common";
|
|
2
|
-
import { type TheFlowGenerator, type TheFlow, type TheFlowFunction, type FlowInput, type WrapFlow, type Exit, type Break, type Injection, type Step, type FlowDependencies } from "./theFlow";
|
|
2
|
+
import { type TheFlowGenerator, type TheFlow, type TheFlowFunction, type FlowInput, type WrapFlow, type Exit, type Break, type Injection, type Step, type FlowDependencies, type Throttling, type Debounce } from "./theFlow";
|
|
3
|
+
import { type Defer } from "./theFlow/defer";
|
|
3
4
|
import { type Finalizer } from "./theFlow/finalizer";
|
|
4
5
|
type ComputeExecParams<GenericInput extends unknown, GenericDependencies extends Record<string, unknown>> = SimplifyTopLevel<(Or<[
|
|
5
6
|
IsEqual<GenericInput, unknown>,
|
|
@@ -13,7 +14,7 @@ type ComputeExecParams<GenericInput extends unknown, GenericDependencies extends
|
|
|
13
14
|
dependencies?: GenericDependencies;
|
|
14
15
|
}>;
|
|
15
16
|
export type ExecResult<GenericFlow extends TheFlow> = GenericFlow extends TheFlow<infer InferredFunction> ? InferredFunction extends TheFlowFunction<any, infer InferredGenerator> ? InferredGenerator extends TheFlowGenerator<infer InferredOutput, infer InferredEffect> ? [
|
|
16
|
-
((InferredEffect extends Break<infer InferredValue> ? InferredValue : never) | InferredOutput),
|
|
17
|
+
((InferredEffect extends Break<infer InferredValue> ? InferredValue : InferredEffect extends Throttling<infer InferredValue> ? InferredValue : InferredEffect extends Debounce<infer InferredValue> ? InferredValue : never) | InferredOutput),
|
|
17
18
|
Extract<InferredEffect, Exit | Injection | Finalizer | Step>
|
|
18
19
|
] extends [
|
|
19
20
|
infer InferredOutput,
|
|
@@ -79,5 +80,5 @@ export type ExecResult<GenericFlow extends TheFlow> = GenericFlow extends TheFlo
|
|
|
79
80
|
* @namespace F
|
|
80
81
|
*
|
|
81
82
|
*/
|
|
82
|
-
export declare function exec<GenericFlow extends (TheFlowFunction | TheFlow | TheFlowGenerator), GenericWrapFlow extends WrapFlow<GenericFlow>, const GenericParams extends ComputeExecParams<FlowInput<GenericWrapFlow>, FlowDependencies<GenericWrapFlow>>>(theFlow: GenericFlow, ...[params]: ({} extends GenericParams ? [params?: GenericParams] : [params: GenericParams])): ExecResult<WrapFlow<GenericFlow>>;
|
|
83
|
+
export declare function exec<GenericFlow extends (TheFlowFunction<any, TheFlowGenerator<unknown, Injection | Step | Exit | Break | Defer | Finalizer>> | TheFlow | TheFlowGenerator<unknown, Injection | Step | Exit | Break | Defer | Finalizer>), GenericWrapFlow extends WrapFlow<GenericFlow>, const GenericParams extends ComputeExecParams<FlowInput<GenericWrapFlow>, FlowDependencies<GenericWrapFlow>>>(theFlow: GenericFlow, ...[params]: ({} extends GenericParams ? [params?: GenericParams] : [params: GenericParams])): ExecResult<WrapFlow<GenericFlow>>;
|
|
83
84
|
export {};
|
package/dist/flow/exec.mjs
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import { theFlowKind } from './theFlow/index.mjs';
|
|
2
2
|
import { deferKind } from './theFlow/defer.mjs';
|
|
3
3
|
import { finalizerKind } from './theFlow/finalizer.mjs';
|
|
4
|
+
import { throttlingLastTimeWeakStore, throttlingResumerWeakStore, calledByNextFunctionWeakStore, queuesWeakStore, debounceTimeoutIdWeakStore, debounceResumerWeakStore } from './run.mjs';
|
|
4
5
|
import { justExec } from '../common/justExec.mjs';
|
|
5
6
|
import { breakKind } from './theFlow/break.mjs';
|
|
6
7
|
import { exitKind } from './theFlow/exit.mjs';
|
|
7
8
|
import { stepKind } from './theFlow/step.mjs';
|
|
8
9
|
import { injectionKind } from './theFlow/injection.mjs';
|
|
9
10
|
import { dependenceHandlerKind } from './theFlow/dependence.mjs';
|
|
11
|
+
import { throttlingKind } from './theFlow/throttling.mjs';
|
|
12
|
+
import { createExternalPromise } from '../common/externalPromise.mjs';
|
|
13
|
+
import { calledByNextKind } from './theFlow/calledByNext.mjs';
|
|
14
|
+
import { queueKind } from './theFlow/queue.mjs';
|
|
15
|
+
import { createQueue } from '../common/queue.mjs';
|
|
16
|
+
import { debounceKind } from './theFlow/debounce.mjs';
|
|
10
17
|
import { forward } from '../common/forward.mjs';
|
|
11
18
|
|
|
12
19
|
/**
|
|
@@ -15,6 +22,10 @@ import { forward } from '../common/forward.mjs';
|
|
|
15
22
|
function exec(theFlow, ...[params]) {
|
|
16
23
|
let result = undefined;
|
|
17
24
|
let deferFunctions = undefined;
|
|
25
|
+
let alreadyUseThrottling = undefined;
|
|
26
|
+
let alreadyUseDebounce = undefined;
|
|
27
|
+
let alreadyUseCalledByNext = undefined;
|
|
28
|
+
let alreadyUseQueue = undefined;
|
|
18
29
|
const generator = justExec(() => {
|
|
19
30
|
if (Symbol.asyncIterator in theFlow || Symbol.iterator in theFlow) {
|
|
20
31
|
return forward(theFlow);
|
|
@@ -62,10 +73,90 @@ function exec(theFlow, ...[params]) {
|
|
|
62
73
|
injectionProperties.inject(params.dependencies[dependenceName]);
|
|
63
74
|
}
|
|
64
75
|
}
|
|
76
|
+
else if (throttlingKind.has(result.value)) {
|
|
77
|
+
if (alreadyUseThrottling) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
alreadyUseThrottling = true;
|
|
81
|
+
const { time, keepLast, returnValue } = throttlingKind.getValue(result.value);
|
|
82
|
+
const lastTime = throttlingLastTimeWeakStore.get(theFlow);
|
|
83
|
+
const now = Date.now();
|
|
84
|
+
throttlingLastTimeWeakStore.set(theFlow, now);
|
|
85
|
+
if (typeof lastTime === "number" && (lastTime + time) > now) {
|
|
86
|
+
if (keepLast === true) {
|
|
87
|
+
const resumer = throttlingResumerWeakStore.get(theFlow);
|
|
88
|
+
resumer?.(false);
|
|
89
|
+
const externalPromise = createExternalPromise();
|
|
90
|
+
throttlingResumerWeakStore.set(theFlow, externalPromise.resolve);
|
|
91
|
+
if (await externalPromise.promise) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
result = await generator.return(returnValue);
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
else if (keepLast === true) {
|
|
99
|
+
setTimeout(() => {
|
|
100
|
+
const resumer = throttlingResumerWeakStore.get(theFlow);
|
|
101
|
+
resumer?.(true);
|
|
102
|
+
}, time);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else if (calledByNextKind.has(result.value)) {
|
|
106
|
+
if (alreadyUseCalledByNext) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
alreadyUseCalledByNext = calledByNextKind.getValue(result.value);
|
|
110
|
+
const lastFunction = calledByNextFunctionWeakStore.get(theFlow);
|
|
111
|
+
const lastResult = lastFunction?.();
|
|
112
|
+
if (lastResult instanceof Promise) {
|
|
113
|
+
await lastResult;
|
|
114
|
+
}
|
|
115
|
+
calledByNextFunctionWeakStore.set(theFlow, alreadyUseCalledByNext);
|
|
116
|
+
}
|
|
117
|
+
else if (queueKind.has(result.value)) {
|
|
118
|
+
if (alreadyUseQueue) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const { concurrency, injectResolver } = queueKind.getValue(result.value);
|
|
122
|
+
let queue = queuesWeakStore.get(theFlow);
|
|
123
|
+
if (queue === undefined) {
|
|
124
|
+
queue = createQueue({ concurrency });
|
|
125
|
+
queuesWeakStore.set(theFlow, queue);
|
|
126
|
+
}
|
|
127
|
+
alreadyUseQueue = await queue.addExternal();
|
|
128
|
+
injectResolver(alreadyUseQueue);
|
|
129
|
+
}
|
|
130
|
+
else if (debounceKind.has(result.value)) {
|
|
131
|
+
if (alreadyUseDebounce) {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
alreadyUseDebounce = true;
|
|
135
|
+
const { time, returnValue } = debounceKind.getValue(result.value);
|
|
136
|
+
const lastTimeout = debounceTimeoutIdWeakStore.get(theFlow);
|
|
137
|
+
clearTimeout(lastTimeout);
|
|
138
|
+
const lastResumer = debounceResumerWeakStore.get(theFlow);
|
|
139
|
+
lastResumer?.(false);
|
|
140
|
+
const externalPromise = createExternalPromise();
|
|
141
|
+
debounceTimeoutIdWeakStore.set(theFlow, setTimeout(() => void externalPromise.resolve(true), time));
|
|
142
|
+
debounceResumerWeakStore.set(theFlow, externalPromise.resolve);
|
|
143
|
+
if (await externalPromise.promise) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
result = await generator.return(returnValue);
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
65
149
|
} while (true);
|
|
66
150
|
return result.value;
|
|
67
151
|
}
|
|
68
152
|
finally {
|
|
153
|
+
if (alreadyUseCalledByNext
|
|
154
|
+
&& calledByNextFunctionWeakStore.get(theFlow) === alreadyUseCalledByNext) {
|
|
155
|
+
calledByNextFunctionWeakStore.delete(theFlow);
|
|
156
|
+
}
|
|
157
|
+
if (alreadyUseQueue) {
|
|
158
|
+
alreadyUseQueue();
|
|
159
|
+
}
|
|
69
160
|
await generator.return(undefined);
|
|
70
161
|
if (deferFunctions) {
|
|
71
162
|
await Promise.all(deferFunctions.map(justExec));
|
|
@@ -108,6 +199,16 @@ function exec(theFlow, ...[params]) {
|
|
|
108
199
|
injectionProperties.inject(params.dependencies[dependenceName]);
|
|
109
200
|
}
|
|
110
201
|
}
|
|
202
|
+
else if (throttlingKind.has(result.value)) {
|
|
203
|
+
const { time, returnValue } = throttlingKind.getValue(result.value);
|
|
204
|
+
const lastTime = throttlingLastTimeWeakStore.get(theFlow);
|
|
205
|
+
const now = Date.now();
|
|
206
|
+
throttlingLastTimeWeakStore.set(theFlow, now);
|
|
207
|
+
if (typeof lastTime === "number" && (lastTime + time) > now) {
|
|
208
|
+
result = generator.return(returnValue);
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
111
212
|
} while (true);
|
|
112
213
|
return result.value;
|
|
113
214
|
}
|
package/dist/flow/index.cjs
CHANGED
|
@@ -11,6 +11,11 @@ var inject = require('./inject.cjs');
|
|
|
11
11
|
var step$1 = require('./step.cjs');
|
|
12
12
|
var initializer = require('./initializer.cjs');
|
|
13
13
|
var kind = require('./kind.cjs');
|
|
14
|
+
var calledByNext$1 = require('./calledByNext.cjs');
|
|
15
|
+
var queue$1 = require('./queue.cjs');
|
|
16
|
+
var throttling$1 = require('./throttling.cjs');
|
|
17
|
+
var toFunction = require('./toFunction.cjs');
|
|
18
|
+
var debounce$1 = require('./debounce.cjs');
|
|
14
19
|
var step = require('./theFlow/step.cjs');
|
|
15
20
|
var exit = require('./theFlow/exit.cjs');
|
|
16
21
|
var _break = require('./theFlow/break.cjs');
|
|
@@ -18,11 +23,21 @@ var injection = require('./theFlow/injection.cjs');
|
|
|
18
23
|
var defer = require('./theFlow/defer.cjs');
|
|
19
24
|
var finalizer = require('./theFlow/finalizer.cjs');
|
|
20
25
|
var dependence = require('./theFlow/dependence.cjs');
|
|
26
|
+
var throttling = require('./theFlow/throttling.cjs');
|
|
27
|
+
var calledByNext = require('./theFlow/calledByNext.cjs');
|
|
28
|
+
var queue = require('./theFlow/queue.cjs');
|
|
29
|
+
var debounce = require('./theFlow/debounce.cjs');
|
|
21
30
|
|
|
22
31
|
|
|
23
32
|
|
|
24
33
|
exports.MissingDependenceError = run.MissingDependenceError;
|
|
34
|
+
exports.calledByNextFunctionWeakStore = run.calledByNextFunctionWeakStore;
|
|
35
|
+
exports.debounceResumerWeakStore = run.debounceResumerWeakStore;
|
|
36
|
+
exports.debounceTimeoutIdWeakStore = run.debounceTimeoutIdWeakStore;
|
|
37
|
+
exports.queuesWeakStore = run.queuesWeakStore;
|
|
25
38
|
exports.run = run.run;
|
|
39
|
+
exports.throttlingLastTimeWeakStore = run.throttlingLastTimeWeakStore;
|
|
40
|
+
exports.throttlingResumerWeakStore = run.throttlingResumerWeakStore;
|
|
26
41
|
exports.create = index.create;
|
|
27
42
|
exports.theFlowKind = index.theFlowKind;
|
|
28
43
|
exports.breakIf = breakIf.breakIf;
|
|
@@ -34,6 +49,11 @@ exports.inject = inject.inject;
|
|
|
34
49
|
exports.step = step$1.step;
|
|
35
50
|
exports.createInitializer = initializer.createInitializer;
|
|
36
51
|
exports.createFlowKind = kind.createFlowKind;
|
|
52
|
+
exports.calledByNext = calledByNext$1.calledByNext;
|
|
53
|
+
exports.queue = queue$1.queue;
|
|
54
|
+
exports.throttling = throttling$1.throttling;
|
|
55
|
+
exports.toFunction = toFunction.toFunction;
|
|
56
|
+
exports.debounce = debounce$1.debounce;
|
|
37
57
|
exports.createStep = step.createStep;
|
|
38
58
|
exports.stepKind = step.stepKind;
|
|
39
59
|
exports.createExit = exit.createExit;
|
|
@@ -48,3 +68,11 @@ exports.createFinalizer = finalizer.createFinalizer;
|
|
|
48
68
|
exports.finalizerKind = finalizer.finalizerKind;
|
|
49
69
|
exports.createDependence = dependence.createDependence;
|
|
50
70
|
exports.dependenceHandlerKind = dependence.dependenceHandlerKind;
|
|
71
|
+
exports.createThrottling = throttling.createThrottling;
|
|
72
|
+
exports.throttlingKind = throttling.throttlingKind;
|
|
73
|
+
exports.calledByNextKind = calledByNext.calledByNextKind;
|
|
74
|
+
exports.createCalledByNext = calledByNext.createCalledByNext;
|
|
75
|
+
exports.createQueue = queue.createQueue;
|
|
76
|
+
exports.queueKind = queue.queueKind;
|
|
77
|
+
exports.createDebounce = debounce.createDebounce;
|
|
78
|
+
exports.debounceKind = debounce.debounceKind;
|
package/dist/flow/index.d.ts
CHANGED
|
@@ -10,3 +10,8 @@ export * from "./inject";
|
|
|
10
10
|
export * from "./step";
|
|
11
11
|
export * from "./initializer";
|
|
12
12
|
export * from "./kind";
|
|
13
|
+
export * from "./calledByNext";
|
|
14
|
+
export * from "./queue";
|
|
15
|
+
export * from "./throttling";
|
|
16
|
+
export * from "./toFunction";
|
|
17
|
+
export * from "./debounce";
|
package/dist/flow/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { MissingDependenceError, run } from './run.mjs';
|
|
1
|
+
export { MissingDependenceError, calledByNextFunctionWeakStore, debounceResumerWeakStore, debounceTimeoutIdWeakStore, queuesWeakStore, run, throttlingLastTimeWeakStore, throttlingResumerWeakStore } from './run.mjs';
|
|
2
2
|
export { create, theFlowKind } from './theFlow/index.mjs';
|
|
3
3
|
export { breakIf } from './breakIf.mjs';
|
|
4
4
|
export { defer } from './defer.mjs';
|
|
@@ -9,6 +9,11 @@ export { inject } from './inject.mjs';
|
|
|
9
9
|
export { step } from './step.mjs';
|
|
10
10
|
export { createInitializer } from './initializer.mjs';
|
|
11
11
|
export { createFlowKind } from './kind.mjs';
|
|
12
|
+
export { calledByNext } from './calledByNext.mjs';
|
|
13
|
+
export { queue } from './queue.mjs';
|
|
14
|
+
export { throttling } from './throttling.mjs';
|
|
15
|
+
export { toFunction } from './toFunction.mjs';
|
|
16
|
+
export { debounce } from './debounce.mjs';
|
|
12
17
|
export { createStep, stepKind } from './theFlow/step.mjs';
|
|
13
18
|
export { createExit, exitKind } from './theFlow/exit.mjs';
|
|
14
19
|
export { breakKind, createBreak } from './theFlow/break.mjs';
|
|
@@ -16,3 +21,7 @@ export { createInjection, injectionKind } from './theFlow/injection.mjs';
|
|
|
16
21
|
export { createDefer, deferKind } from './theFlow/defer.mjs';
|
|
17
22
|
export { createFinalizer, finalizerKind } from './theFlow/finalizer.mjs';
|
|
18
23
|
export { createDependence, dependenceHandlerKind } from './theFlow/dependence.mjs';
|
|
24
|
+
export { createThrottling, throttlingKind } from './theFlow/throttling.mjs';
|
|
25
|
+
export { calledByNextKind, createCalledByNext } from './theFlow/calledByNext.mjs';
|
|
26
|
+
export { createQueue, queueKind } from './theFlow/queue.mjs';
|
|
27
|
+
export { createDebounce, debounceKind } from './theFlow/debounce.mjs';
|
|
@@ -21,7 +21,7 @@ export type Initializer<GenericArgs extends unknown[], GenericOutput extends unk
|
|
|
21
21
|
* The returned initializer can then be executed inside `F.run(...)` like any other flow generator.
|
|
22
22
|
*
|
|
23
23
|
* ```ts
|
|
24
|
-
* const userInitializer = createInitializer(
|
|
24
|
+
* const userInitializer = F.createInitializer(
|
|
25
25
|
* (name: string) => ({ name }),
|
|
26
26
|
* { defer: (user) => void console.log(`close:${user.name}`) },
|
|
27
27
|
* );
|
|
@@ -33,7 +33,7 @@ export type Initializer<GenericArgs extends unknown[], GenericOutput extends unk
|
|
|
33
33
|
* ); // { name: "Ada" }
|
|
34
34
|
*
|
|
35
35
|
* const finalizerLogs: string[] = [];
|
|
36
|
-
* const tokenInitializer = createInitializer(
|
|
36
|
+
* const tokenInitializer = F.createInitializer(
|
|
37
37
|
* (id: number) => `token-${id}`,
|
|
38
38
|
* { finalizer: (token) => finalizerLogs.push(token) },
|
|
39
39
|
* );
|
|
@@ -44,7 +44,7 @@ export type Initializer<GenericArgs extends unknown[], GenericOutput extends unk
|
|
|
44
44
|
* },
|
|
45
45
|
* ); // "token-42"
|
|
46
46
|
*
|
|
47
|
-
* const asyncInitializer = createInitializer(
|
|
47
|
+
* const asyncInitializer = F.createInitializer(
|
|
48
48
|
* (name: string) => Promise.resolve({
|
|
49
49
|
* name,
|
|
50
50
|
* ready: true,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var queue$1 = require('./theFlow/queue.cjs');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* {@include flow/queue/index.md}
|
|
7
|
+
*/
|
|
8
|
+
async function* queue(params) {
|
|
9
|
+
let resolver = undefined;
|
|
10
|
+
yield queue$1.createQueue({
|
|
11
|
+
concurrency: params?.concurrency ?? 1,
|
|
12
|
+
injectResolver: (injectResolver) => {
|
|
13
|
+
resolver = injectResolver;
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
return resolver;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
exports.queue = queue;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type OnlyLiteralNumber } from "../common";
|
|
2
|
+
/**
|
|
3
|
+
* Reserves execution through the async flow queue and returns a resolver that releases the reserved slot.
|
|
4
|
+
*
|
|
5
|
+
* **Supported call styles:**
|
|
6
|
+
* - Classic: `queue()` -> yields a queue effect with concurrency `1`
|
|
7
|
+
* - Classic with options: `queue({ concurrency })` -> yields a queue effect with the provided concurrency
|
|
8
|
+
*
|
|
9
|
+
* `queue` is an async flow helper consumed by the runner.
|
|
10
|
+
* It asks the runner to serialize or limit concurrent executions of the same flow.
|
|
11
|
+
* When the slot is granted, the helper returns a `release` function that should be called once the protected section is finished.
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* const saveFlow = F.create(
|
|
15
|
+
* async function *(name: string) {
|
|
16
|
+
* const release = yield *F.queue({
|
|
17
|
+
* concurrency: 1,
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* try {
|
|
21
|
+
* return await Promise.resolve(`saved:${name}` as const);
|
|
22
|
+
* } finally {
|
|
23
|
+
* release();
|
|
24
|
+
* }
|
|
25
|
+
* },
|
|
26
|
+
* );
|
|
27
|
+
* const saveUser = F.toFunction(saveFlow);
|
|
28
|
+
*
|
|
29
|
+
* await saveUser("alice"); // Promise<"saved:alice">
|
|
30
|
+
*
|
|
31
|
+
* await saveUser("bob"); // Promise<"saved:bob">
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* - `queue` is meaningful only in asynchronous flows handled by `F.run(...)`
|
|
36
|
+
* - Reuse the same flow reference to share the same queue across runs
|
|
37
|
+
* - If the same flow execution yields `queue(...)` multiple times, only the first yielded effect is applied by the runner
|
|
38
|
+
*
|
|
39
|
+
* @see [`F.run`](https://utils.duplojs.dev/en/v1/api/flow/run) For queue-aware execution
|
|
40
|
+
* @see https://utils.duplojs.dev/en/v1/api/flow/queue
|
|
41
|
+
*
|
|
42
|
+
* @namespace F
|
|
43
|
+
*
|
|
44
|
+
*/
|
|
45
|
+
export declare function queue<GenericConcurrency extends number>(params?: {
|
|
46
|
+
concurrency?: GenericConcurrency & OnlyLiteralNumber<GenericConcurrency>;
|
|
47
|
+
}): AsyncGenerator<import("./theFlow").Queue, () => void, unknown>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createQueue } from './theFlow/queue.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* {@include flow/queue/index.md}
|
|
5
|
+
*/
|
|
6
|
+
async function* queue(params) {
|
|
7
|
+
let resolver = undefined;
|
|
8
|
+
yield createQueue({
|
|
9
|
+
concurrency: params?.concurrency ?? 1,
|
|
10
|
+
injectResolver: (injectResolver) => {
|
|
11
|
+
resolver = injectResolver;
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
return resolver;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { queue };
|
package/dist/flow/run.cjs
CHANGED
|
@@ -9,6 +9,12 @@ var _break = require('./theFlow/break.cjs');
|
|
|
9
9
|
var exit = require('./theFlow/exit.cjs');
|
|
10
10
|
var step = require('./theFlow/step.cjs');
|
|
11
11
|
var injection = require('./theFlow/injection.cjs');
|
|
12
|
+
var throttling = require('./theFlow/throttling.cjs');
|
|
13
|
+
var externalPromise = require('../common/externalPromise.cjs');
|
|
14
|
+
var calledByNext = require('./theFlow/calledByNext.cjs');
|
|
15
|
+
var queue = require('./theFlow/queue.cjs');
|
|
16
|
+
var queue$1 = require('../common/queue.cjs');
|
|
17
|
+
var debounce = require('./theFlow/debounce.cjs');
|
|
12
18
|
var justExec = require('../common/justExec.cjs');
|
|
13
19
|
var kind = require('../common/kind.cjs');
|
|
14
20
|
|
|
@@ -19,6 +25,18 @@ class MissingDependenceError extends kind.kindHeritage("missing-dependence-error
|
|
|
19
25
|
this.dependenceHandler = dependenceHandler;
|
|
20
26
|
}
|
|
21
27
|
}
|
|
28
|
+
/** @internal */
|
|
29
|
+
const throttlingLastTimeWeakStore = new WeakMap();
|
|
30
|
+
/** @internal */
|
|
31
|
+
const throttlingResumerWeakStore = new WeakMap();
|
|
32
|
+
/** @internal */
|
|
33
|
+
const debounceTimeoutIdWeakStore = new WeakMap();
|
|
34
|
+
/** @internal */
|
|
35
|
+
const debounceResumerWeakStore = new WeakMap();
|
|
36
|
+
/** @internal */
|
|
37
|
+
const calledByNextFunctionWeakStore = new WeakMap();
|
|
38
|
+
/** @internal */
|
|
39
|
+
const queuesWeakStore = new WeakMap();
|
|
22
40
|
/**
|
|
23
41
|
* {@include flow/run/index.md}
|
|
24
42
|
*/
|
|
@@ -26,6 +44,10 @@ function run(theFlow, ...[params]) {
|
|
|
26
44
|
let result = undefined;
|
|
27
45
|
let deferFunctions = undefined;
|
|
28
46
|
let steps = undefined;
|
|
47
|
+
let alreadyUseThrottling = undefined;
|
|
48
|
+
let alreadyUseDebounce = undefined;
|
|
49
|
+
let alreadyUseCalledByNext = undefined;
|
|
50
|
+
let alreadyUseQueue = undefined;
|
|
29
51
|
const generator = typeof theFlow === "function"
|
|
30
52
|
? theFlow(params?.input)
|
|
31
53
|
: index.theFlowKind.getValue(theFlow).run(params?.input);
|
|
@@ -67,6 +89,79 @@ function run(theFlow, ...[params]) {
|
|
|
67
89
|
}
|
|
68
90
|
injectionProperties.inject(params.dependencies[dependenceName]);
|
|
69
91
|
}
|
|
92
|
+
else if (throttling.throttlingKind.has(result.value)) {
|
|
93
|
+
if (alreadyUseThrottling) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
alreadyUseThrottling = true;
|
|
97
|
+
const { time, keepLast, returnValue } = throttling.throttlingKind.getValue(result.value);
|
|
98
|
+
const lastTime = throttlingLastTimeWeakStore.get(theFlow);
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
throttlingLastTimeWeakStore.set(theFlow, now);
|
|
101
|
+
if (typeof lastTime === "number" && (lastTime + time) > now) {
|
|
102
|
+
if (keepLast === true) {
|
|
103
|
+
const resumer = throttlingResumerWeakStore.get(theFlow);
|
|
104
|
+
resumer?.(false);
|
|
105
|
+
const externalPromise$1 = externalPromise.createExternalPromise();
|
|
106
|
+
throttlingResumerWeakStore.set(theFlow, externalPromise$1.resolve);
|
|
107
|
+
if (await externalPromise$1.promise) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
result = await generator.return(returnValue);
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
else if (keepLast === true) {
|
|
115
|
+
setTimeout(() => {
|
|
116
|
+
const resumer = throttlingResumerWeakStore.get(theFlow);
|
|
117
|
+
resumer?.(true);
|
|
118
|
+
}, time);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else if (calledByNext.calledByNextKind.has(result.value)) {
|
|
122
|
+
if (alreadyUseCalledByNext) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
alreadyUseCalledByNext = calledByNext.calledByNextKind.getValue(result.value);
|
|
126
|
+
const lastFunction = calledByNextFunctionWeakStore.get(theFlow);
|
|
127
|
+
const lastResult = lastFunction?.();
|
|
128
|
+
if (lastResult instanceof Promise) {
|
|
129
|
+
await lastResult;
|
|
130
|
+
}
|
|
131
|
+
calledByNextFunctionWeakStore.set(theFlow, alreadyUseCalledByNext);
|
|
132
|
+
}
|
|
133
|
+
else if (queue.queueKind.has(result.value)) {
|
|
134
|
+
if (alreadyUseQueue) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const { concurrency, injectResolver } = queue.queueKind.getValue(result.value);
|
|
138
|
+
let queue$2 = queuesWeakStore.get(theFlow);
|
|
139
|
+
if (queue$2 === undefined) {
|
|
140
|
+
queue$2 = queue$1.createQueue({ concurrency });
|
|
141
|
+
queuesWeakStore.set(theFlow, queue$2);
|
|
142
|
+
}
|
|
143
|
+
alreadyUseQueue = await queue$2.addExternal();
|
|
144
|
+
injectResolver(alreadyUseQueue);
|
|
145
|
+
}
|
|
146
|
+
else if (debounce.debounceKind.has(result.value)) {
|
|
147
|
+
if (alreadyUseDebounce) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
alreadyUseDebounce = true;
|
|
151
|
+
const { time, returnValue } = debounce.debounceKind.getValue(result.value);
|
|
152
|
+
const lastTimeout = debounceTimeoutIdWeakStore.get(theFlow);
|
|
153
|
+
clearTimeout(lastTimeout);
|
|
154
|
+
const lastResumer = debounceResumerWeakStore.get(theFlow);
|
|
155
|
+
lastResumer?.(false);
|
|
156
|
+
const externalPromise$1 = externalPromise.createExternalPromise();
|
|
157
|
+
debounceTimeoutIdWeakStore.set(theFlow, setTimeout(() => void externalPromise$1.resolve(true), time));
|
|
158
|
+
debounceResumerWeakStore.set(theFlow, externalPromise$1.resolve);
|
|
159
|
+
if (await externalPromise$1.promise) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
result = await generator.return(returnValue);
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
70
165
|
} while (true);
|
|
71
166
|
return params?.includeDetails === true
|
|
72
167
|
? {
|
|
@@ -76,6 +171,13 @@ function run(theFlow, ...[params]) {
|
|
|
76
171
|
: result.value;
|
|
77
172
|
}
|
|
78
173
|
finally {
|
|
174
|
+
if (alreadyUseCalledByNext
|
|
175
|
+
&& calledByNextFunctionWeakStore.get(theFlow) === alreadyUseCalledByNext) {
|
|
176
|
+
calledByNextFunctionWeakStore.delete(theFlow);
|
|
177
|
+
}
|
|
178
|
+
if (alreadyUseQueue) {
|
|
179
|
+
alreadyUseQueue();
|
|
180
|
+
}
|
|
79
181
|
await generator.return(undefined);
|
|
80
182
|
if (deferFunctions) {
|
|
81
183
|
await Promise.all(deferFunctions.map(justExec.justExec));
|
|
@@ -119,6 +221,16 @@ function run(theFlow, ...[params]) {
|
|
|
119
221
|
}
|
|
120
222
|
injectionProperties.inject(params.dependencies[dependenceName]);
|
|
121
223
|
}
|
|
224
|
+
else if (throttling.throttlingKind.has(result.value)) {
|
|
225
|
+
const { time, returnValue } = throttling.throttlingKind.getValue(result.value);
|
|
226
|
+
const lastTime = throttlingLastTimeWeakStore.get(theFlow);
|
|
227
|
+
const now = Date.now();
|
|
228
|
+
throttlingLastTimeWeakStore.set(theFlow, now);
|
|
229
|
+
if (typeof lastTime === "number" && (lastTime + time) > now) {
|
|
230
|
+
result = generator.return(returnValue);
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
122
234
|
} while (true);
|
|
123
235
|
return (params?.includeDetails === true
|
|
124
236
|
? {
|
|
@@ -136,4 +248,10 @@ function run(theFlow, ...[params]) {
|
|
|
136
248
|
}
|
|
137
249
|
|
|
138
250
|
exports.MissingDependenceError = MissingDependenceError;
|
|
251
|
+
exports.calledByNextFunctionWeakStore = calledByNextFunctionWeakStore;
|
|
252
|
+
exports.debounceResumerWeakStore = debounceResumerWeakStore;
|
|
253
|
+
exports.debounceTimeoutIdWeakStore = debounceTimeoutIdWeakStore;
|
|
254
|
+
exports.queuesWeakStore = queuesWeakStore;
|
|
139
255
|
exports.run = run;
|
|
256
|
+
exports.throttlingLastTimeWeakStore = throttlingLastTimeWeakStore;
|
|
257
|
+
exports.throttlingResumerWeakStore = throttlingResumerWeakStore;
|
package/dist/flow/run.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type SimplifyTopLevel, type IsEqual, type IsExtends, type Or } from "../common";
|
|
2
|
-
import { type TheFlow, type TheFlowFunction, type FlowInput, type WrapFlow, type TheFlowGenerator, type Exit, type Break, type Step, type FlowDependencies, type DependenceHandler, type ExtractFlowGenerator } from "./theFlow";
|
|
3
|
-
|
|
2
|
+
import { type TheFlow, type TheFlowFunction, type FlowInput, type WrapFlow, type TheFlowGenerator, type Exit, type Break, type Step, type FlowDependencies, type DependenceHandler, type ExtractFlowGenerator, type Throttling, type Injection, type Debounce } from "./theFlow";
|
|
3
|
+
import { type Defer } from "./theFlow/defer";
|
|
4
|
+
import { type Finalizer } from "./theFlow/finalizer";
|
|
5
|
+
type ComputeRunParams<GenericInput extends unknown = unknown, GenericDependencies extends Record<string, unknown> = Record<string, unknown>> = SimplifyTopLevel<(Or<[
|
|
4
6
|
IsEqual<GenericInput, unknown>,
|
|
5
7
|
IsEqual<GenericInput, never>,
|
|
6
8
|
IsExtends<GenericInput, undefined>
|
|
@@ -19,7 +21,7 @@ export interface FlowDetails<GenericValue extends unknown, GenericStepName exten
|
|
|
19
21
|
result: GenericValue;
|
|
20
22
|
steps: GenericStepName[];
|
|
21
23
|
}
|
|
22
|
-
export type RunResult<GenericFlow extends TheFlow, GenericIncludeDetails extends boolean = false> = (GenericFlow extends TheFlow<infer InferredFunction> ? InferredFunction extends TheFlowFunction<any, infer InferredGenerator> ? InferredGenerator extends TheFlowGenerator<infer InferredOutput, infer InferredEffect> ? ((InferredEffect extends Exit<infer InferredValue> ? InferredValue : InferredEffect extends Break<infer InferredValue> ? InferredValue : never) | InferredOutput) extends infer InferredResult ? IsEqual<GenericIncludeDetails, true> extends true ? FlowDetails<InferredResult, InferredEffect extends Step<infer InferredName> ? InferredName : never> : InferredResult : never : never : never : never) extends infer InferredResult ? ExtractFlowGenerator<GenericFlow> extends AsyncGenerator ? Promise<InferredResult> : InferredResult : never;
|
|
24
|
+
export type RunResult<GenericFlow extends TheFlow, GenericIncludeDetails extends boolean = false> = (GenericFlow extends TheFlow<infer InferredFunction> ? InferredFunction extends TheFlowFunction<any, infer InferredGenerator> ? InferredGenerator extends TheFlowGenerator<infer InferredOutput, infer InferredEffect> ? ((InferredEffect extends Exit<infer InferredValue> ? InferredValue : InferredEffect extends Break<infer InferredValue> ? InferredValue : InferredEffect extends Throttling<infer InferredValue> ? InferredValue : InferredEffect extends Debounce<infer InferredValue> ? InferredValue : never) | InferredOutput) extends infer InferredResult ? IsEqual<GenericIncludeDetails, true> extends true ? FlowDetails<InferredResult, InferredEffect extends Step<infer InferredName> ? InferredName : never> : InferredResult : never : never : never : never) extends infer InferredResult ? ExtractFlowGenerator<GenericFlow> extends AsyncGenerator ? Promise<InferredResult> : InferredResult : never;
|
|
23
25
|
declare const MissingDependenceError_base: new (params: {
|
|
24
26
|
"@DuplojsUtilsFlow/missing-dependence-error"?: unknown;
|
|
25
27
|
}, parentParams: readonly [message?: string | undefined, options?: ErrorOptions | undefined]) => Error & import("../common").Kind<import("../common").KindDefinition<"missing-dependence-error", unknown>, unknown> & import("../common").Kind<import("../common").KindDefinition<"@DuplojsUtilsFlow/missing-dependence-error", unknown>, unknown>;
|
|
@@ -76,5 +78,5 @@ export declare class MissingDependenceError extends MissingDependenceError_base
|
|
|
76
78
|
* @namespace F
|
|
77
79
|
*
|
|
78
80
|
*/
|
|
79
|
-
export declare function run<GenericFlow extends (TheFlowFunction | TheFlow), GenericWrapFlow extends WrapFlow<GenericFlow>, const GenericParams extends ComputeRunParams<FlowInput<GenericWrapFlow>, FlowDependencies<GenericWrapFlow>>>(theFlow: GenericFlow, ...[params]: ({} extends GenericParams ? [params?: GenericParams] : [params: GenericParams])): RunResult<GenericWrapFlow, IsEqual<GenericParams["includeDetails"], true>>;
|
|
81
|
+
export declare function run<GenericFlow extends (TheFlowFunction<any, TheFlowGenerator<unknown, Injection | Step | Exit | Break | Defer | Finalizer>> | TheFlow), GenericWrapFlow extends WrapFlow<GenericFlow>, const GenericParams extends ComputeRunParams<FlowInput<GenericWrapFlow>, FlowDependencies<GenericWrapFlow>>>(theFlow: GenericFlow, ...[params]: ({} extends GenericParams ? [params?: GenericParams] : [params: GenericParams])): RunResult<GenericWrapFlow, IsEqual<GenericParams["includeDetails"], true>>;
|
|
80
82
|
export {};
|