@tanstack/pacer-lite 0.2.2 → 0.3.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/README.md +21 -6
- package/dist/lite-batcher.d.ts +4 -6
- package/dist/lite-batcher.js +72 -45
- package/dist/lite-debouncer.d.ts +4 -7
- package/dist/lite-debouncer.js +58 -40
- package/dist/lite-queuer.d.ts +5 -7
- package/dist/lite-queuer.js +170 -89
- package/dist/lite-rate-limiter.d.ts +4 -7
- package/dist/lite-rate-limiter.js +89 -63
- package/dist/lite-throttler.d.ts +4 -7
- package/dist/lite-throttler.js +63 -40
- package/dist/pacer/dist/types.d.ts +2 -7
- package/package.json +13 -33
- package/dist/index.cjs +0 -17
- package/dist/index.d.cts +0 -6
- package/dist/lite-batcher.cjs +0 -176
- package/dist/lite-batcher.cjs.map +0 -1
- package/dist/lite-batcher.d.cts +0 -184
- package/dist/lite-batcher.js.map +0 -1
- package/dist/lite-debouncer.cjs +0 -126
- package/dist/lite-debouncer.cjs.map +0 -1
- package/dist/lite-debouncer.d.cts +0 -126
- package/dist/lite-debouncer.js.map +0 -1
- package/dist/lite-queuer.cjs +0 -209
- package/dist/lite-queuer.cjs.map +0 -1
- package/dist/lite-queuer.d.cts +0 -243
- package/dist/lite-queuer.js.map +0 -1
- package/dist/lite-rate-limiter.cjs +0 -150
- package/dist/lite-rate-limiter.cjs.map +0 -1
- package/dist/lite-rate-limiter.d.cts +0 -148
- package/dist/lite-rate-limiter.js.map +0 -1
- package/dist/lite-throttler.cjs +0 -128
- package/dist/lite-throttler.cjs.map +0 -1
- package/dist/lite-throttler.d.cts +0 -133
- package/dist/lite-throttler.js.map +0 -1
- package/dist/pacer/dist/types.d.cts +0 -12
- package/src/index.ts +0 -5
- package/src/lite-batcher.ts +0 -267
- package/src/lite-debouncer.ts +0 -184
- package/src/lite-queuer.ts +0 -434
- package/src/lite-rate-limiter.ts +0 -246
- package/src/lite-throttler.ts +0 -195
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { AnyFunction } from "./pacer/dist/types.js";
|
|
2
|
-
|
|
3
2
|
//#region src/lite-rate-limiter.d.ts
|
|
4
3
|
/**
|
|
5
4
|
* Options for configuring a lite rate-limited function
|
|
6
5
|
*/
|
|
7
|
-
interface LiteRateLimiterOptions<TFn extends AnyFunction = AnyFunction> {
|
|
6
|
+
export interface LiteRateLimiterOptions<TFn extends AnyFunction = AnyFunction> {
|
|
8
7
|
/**
|
|
9
8
|
* Maximum number of executions allowed within the time window.
|
|
10
9
|
*/
|
|
@@ -67,7 +66,7 @@ interface LiteRateLimiterOptions<TFn extends AnyFunction = AnyFunction> {
|
|
|
67
66
|
* }
|
|
68
67
|
* ```
|
|
69
68
|
*/
|
|
70
|
-
declare class LiteRateLimiter<TFn extends AnyFunction> {
|
|
69
|
+
export declare class LiteRateLimiter<TFn extends AnyFunction> {
|
|
71
70
|
fn: TFn;
|
|
72
71
|
options: LiteRateLimiterOptions<TFn>;
|
|
73
72
|
private executionTimes;
|
|
@@ -142,7 +141,5 @@ declare class LiteRateLimiter<TFn extends AnyFunction> {
|
|
|
142
141
|
* });
|
|
143
142
|
* ```
|
|
144
143
|
*/
|
|
145
|
-
declare function liteRateLimit<TFn extends AnyFunction>(fn: TFn, options: LiteRateLimiterOptions<TFn>): (...args: Parameters<TFn>) => boolean;
|
|
146
|
-
//#endregion
|
|
147
|
-
export { LiteRateLimiter, LiteRateLimiterOptions, liteRateLimit };
|
|
148
|
-
//# sourceMappingURL=lite-rate-limiter.d.ts.map
|
|
144
|
+
export declare function liteRateLimit<TFn extends AnyFunction>(fn: TFn, options: LiteRateLimiterOptions<TFn>): (...args: Parameters<TFn>) => boolean;
|
|
145
|
+
//#endregion
|
|
@@ -38,72 +38,99 @@
|
|
|
38
38
|
* ```
|
|
39
39
|
*/
|
|
40
40
|
var LiteRateLimiter = class {
|
|
41
|
+
fn;
|
|
42
|
+
options;
|
|
43
|
+
executionTimes = [];
|
|
44
|
+
timeoutIds = /* @__PURE__ */ new Set();
|
|
41
45
|
constructor(fn, options) {
|
|
42
46
|
this.fn = fn;
|
|
43
47
|
this.options = options;
|
|
44
|
-
this.executionTimes = [];
|
|
45
|
-
this.timeoutIds = /* @__PURE__ */ new Set();
|
|
46
|
-
this.maybeExecute = (...args) => {
|
|
47
|
-
this.cleanupOldExecutions();
|
|
48
|
-
if (this.getExecutionTimesInWindow().length < this.options.limit) {
|
|
49
|
-
this.execute(...args);
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
this.options.onReject?.(this);
|
|
53
|
-
return false;
|
|
54
|
-
};
|
|
55
|
-
this.execute = (...args) => {
|
|
56
|
-
const now = Date.now();
|
|
57
|
-
this.fn(...args);
|
|
58
|
-
this.options.onExecute?.(args, this);
|
|
59
|
-
this.executionTimes.push(now);
|
|
60
|
-
this.setCleanupTimeout(now);
|
|
61
|
-
};
|
|
62
|
-
this.getExecutionTimesInWindow = () => {
|
|
63
|
-
if (this.options.windowType === "sliding") return this.executionTimes.filter((time) => time > Date.now() - this.options.window);
|
|
64
|
-
else {
|
|
65
|
-
if (this.executionTimes.length === 0) return [];
|
|
66
|
-
const windowStart = Math.min(...this.executionTimes);
|
|
67
|
-
const windowEnd = windowStart + this.options.window;
|
|
68
|
-
if (Date.now() > windowEnd) return [];
|
|
69
|
-
return this.executionTimes.filter((time) => time >= windowStart && time <= windowEnd);
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
this.setCleanupTimeout = (executionTime) => {
|
|
73
|
-
if (this.options.windowType === "sliding" || this.timeoutIds.size === 0) {
|
|
74
|
-
const timeUntilExpiration = executionTime - Date.now() + this.options.window + 1;
|
|
75
|
-
const timeoutId = setTimeout(() => {
|
|
76
|
-
this.cleanupOldExecutions();
|
|
77
|
-
this.clearTimeout(timeoutId);
|
|
78
|
-
}, timeUntilExpiration);
|
|
79
|
-
this.timeoutIds.add(timeoutId);
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
this.clearTimeout = (timeoutId) => {
|
|
83
|
-
clearTimeout(timeoutId);
|
|
84
|
-
this.timeoutIds.delete(timeoutId);
|
|
85
|
-
};
|
|
86
|
-
this.clearTimeouts = () => {
|
|
87
|
-
this.timeoutIds.forEach((timeoutId) => clearTimeout(timeoutId));
|
|
88
|
-
this.timeoutIds.clear();
|
|
89
|
-
};
|
|
90
|
-
this.cleanupOldExecutions = () => {
|
|
91
|
-
this.executionTimes = this.getExecutionTimesInWindow();
|
|
92
|
-
};
|
|
93
|
-
this.getRemainingInWindow = () => {
|
|
94
|
-
const relevantExecutionTimes = this.getExecutionTimesInWindow();
|
|
95
|
-
return Math.max(0, this.options.limit - relevantExecutionTimes.length);
|
|
96
|
-
};
|
|
97
|
-
this.getMsUntilNextWindow = () => {
|
|
98
|
-
if (this.getRemainingInWindow() > 0) return 0;
|
|
99
|
-
return (this.executionTimes[0] ?? Infinity) + this.options.window - Date.now();
|
|
100
|
-
};
|
|
101
|
-
this.reset = () => {
|
|
102
|
-
this.executionTimes = [];
|
|
103
|
-
this.clearTimeouts();
|
|
104
|
-
};
|
|
105
48
|
if (this.options.windowType === void 0) this.options.windowType = "fixed";
|
|
106
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Attempts to execute the rate-limited function if within the configured limits.
|
|
52
|
+
* Returns true if executed, false if rejected due to rate limiting.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* const rateLimiter = new LiteRateLimiter(fn, { limit: 5, window: 1000 });
|
|
57
|
+
*
|
|
58
|
+
* // First 5 calls return true
|
|
59
|
+
* rateLimiter.maybeExecute('arg1', 'arg2'); // true
|
|
60
|
+
*
|
|
61
|
+
* // Additional calls within the window return false
|
|
62
|
+
* rateLimiter.maybeExecute('arg1', 'arg2'); // false
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
maybeExecute = (...args) => {
|
|
66
|
+
this.cleanupOldExecutions();
|
|
67
|
+
if (this.getExecutionTimesInWindow().length < this.options.limit) {
|
|
68
|
+
this.execute(...args);
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
this.options.onReject?.(this);
|
|
72
|
+
return false;
|
|
73
|
+
};
|
|
74
|
+
execute = (...args) => {
|
|
75
|
+
const now = Date.now();
|
|
76
|
+
this.fn(...args);
|
|
77
|
+
this.options.onExecute?.(args, this);
|
|
78
|
+
this.executionTimes.push(now);
|
|
79
|
+
this.setCleanupTimeout(now);
|
|
80
|
+
};
|
|
81
|
+
getExecutionTimesInWindow = () => {
|
|
82
|
+
if (this.options.windowType === "sliding") return this.executionTimes.filter((time) => time > Date.now() - this.options.window);
|
|
83
|
+
else {
|
|
84
|
+
if (this.executionTimes.length === 0) return [];
|
|
85
|
+
const windowStart = Math.min(...this.executionTimes);
|
|
86
|
+
const windowEnd = windowStart + this.options.window;
|
|
87
|
+
if (Date.now() > windowEnd) return [];
|
|
88
|
+
return this.executionTimes.filter((time) => time >= windowStart && time <= windowEnd);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
setCleanupTimeout = (executionTime) => {
|
|
92
|
+
if (this.options.windowType === "sliding" || this.timeoutIds.size === 0) {
|
|
93
|
+
const timeUntilExpiration = executionTime - Date.now() + this.options.window + 1;
|
|
94
|
+
const timeoutId = setTimeout(() => {
|
|
95
|
+
this.cleanupOldExecutions();
|
|
96
|
+
this.clearTimeout(timeoutId);
|
|
97
|
+
}, timeUntilExpiration);
|
|
98
|
+
this.timeoutIds.add(timeoutId);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
clearTimeout = (timeoutId) => {
|
|
102
|
+
clearTimeout(timeoutId);
|
|
103
|
+
this.timeoutIds.delete(timeoutId);
|
|
104
|
+
};
|
|
105
|
+
clearTimeouts = () => {
|
|
106
|
+
this.timeoutIds.forEach((timeoutId) => clearTimeout(timeoutId));
|
|
107
|
+
this.timeoutIds.clear();
|
|
108
|
+
};
|
|
109
|
+
cleanupOldExecutions = () => {
|
|
110
|
+
this.executionTimes = this.getExecutionTimesInWindow();
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Returns the number of remaining executions allowed in the current window.
|
|
114
|
+
*/
|
|
115
|
+
getRemainingInWindow = () => {
|
|
116
|
+
const relevantExecutionTimes = this.getExecutionTimesInWindow();
|
|
117
|
+
return Math.max(0, this.options.limit - relevantExecutionTimes.length);
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Returns the number of milliseconds until the next execution will be possible.
|
|
121
|
+
* Returns 0 if executions are currently allowed.
|
|
122
|
+
*/
|
|
123
|
+
getMsUntilNextWindow = () => {
|
|
124
|
+
if (this.getRemainingInWindow() > 0) return 0;
|
|
125
|
+
return (this.executionTimes[0] ?? Infinity) + this.options.window - Date.now();
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Resets the rate limiter state, clearing all execution history.
|
|
129
|
+
*/
|
|
130
|
+
reset = () => {
|
|
131
|
+
this.executionTimes = [];
|
|
132
|
+
this.clearTimeouts();
|
|
133
|
+
};
|
|
107
134
|
};
|
|
108
135
|
/**
|
|
109
136
|
* Creates a lightweight rate-limited function that will execute the provided function up to a maximum number of times within a time window.
|
|
@@ -143,5 +170,4 @@ function liteRateLimit(fn, options) {
|
|
|
143
170
|
}
|
|
144
171
|
|
|
145
172
|
//#endregion
|
|
146
|
-
export { LiteRateLimiter, liteRateLimit };
|
|
147
|
-
//# sourceMappingURL=lite-rate-limiter.js.map
|
|
173
|
+
export { LiteRateLimiter, liteRateLimit };
|
package/dist/lite-throttler.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { AnyFunction } from "./pacer/dist/types.js";
|
|
2
|
-
|
|
3
2
|
//#region src/lite-throttler.d.ts
|
|
4
3
|
/**
|
|
5
4
|
* Options for configuring a lite throttled function
|
|
6
5
|
*/
|
|
7
|
-
interface LiteThrottlerOptions<TFn extends AnyFunction = AnyFunction> {
|
|
6
|
+
export interface LiteThrottlerOptions<TFn extends AnyFunction = AnyFunction> {
|
|
8
7
|
/**
|
|
9
8
|
* Whether to execute on the leading edge of the timeout.
|
|
10
9
|
* Defaults to true.
|
|
@@ -64,7 +63,7 @@ interface LiteThrottlerOptions<TFn extends AnyFunction = AnyFunction> {
|
|
|
64
63
|
* });
|
|
65
64
|
* ```
|
|
66
65
|
*/
|
|
67
|
-
declare class LiteThrottler<TFn extends AnyFunction> {
|
|
66
|
+
export declare class LiteThrottler<TFn extends AnyFunction> {
|
|
68
67
|
fn: TFn;
|
|
69
68
|
options: LiteThrottlerOptions<TFn>;
|
|
70
69
|
private timeoutId;
|
|
@@ -127,7 +126,5 @@ declare class LiteThrottler<TFn extends AnyFunction> {
|
|
|
127
126
|
* }, { wait: 250, leading: true, trailing: false });
|
|
128
127
|
* ```
|
|
129
128
|
*/
|
|
130
|
-
declare function liteThrottle<TFn extends AnyFunction>(fn: TFn, options: LiteThrottlerOptions<TFn>): (...args: Parameters<TFn>) => void;
|
|
131
|
-
//#endregion
|
|
132
|
-
export { LiteThrottler, LiteThrottlerOptions, liteThrottle };
|
|
133
|
-
//# sourceMappingURL=lite-throttler.d.ts.map
|
|
129
|
+
export declare function liteThrottle<TFn extends AnyFunction>(fn: TFn, options: LiteThrottlerOptions<TFn>): (...args: Parameters<TFn>) => void;
|
|
130
|
+
//#endregion
|
package/dist/lite-throttler.js
CHANGED
|
@@ -40,52 +40,76 @@
|
|
|
40
40
|
* ```
|
|
41
41
|
*/
|
|
42
42
|
var LiteThrottler = class {
|
|
43
|
+
fn;
|
|
44
|
+
options;
|
|
45
|
+
timeoutId;
|
|
46
|
+
lastArgs;
|
|
47
|
+
lastExecutionTime = 0;
|
|
48
|
+
isPending = false;
|
|
43
49
|
constructor(fn, options) {
|
|
44
50
|
this.fn = fn;
|
|
45
51
|
this.options = options;
|
|
46
|
-
this.lastExecutionTime = 0;
|
|
47
|
-
this.isPending = false;
|
|
48
|
-
this.maybeExecute = (...args) => {
|
|
49
|
-
const timeSinceLastExecution = Date.now() - this.lastExecutionTime;
|
|
50
|
-
if (this.options.leading && timeSinceLastExecution >= this.options.wait) this.execute(...args);
|
|
51
|
-
else {
|
|
52
|
-
this.lastArgs = args;
|
|
53
|
-
if (!this.timeoutId && this.options.trailing) {
|
|
54
|
-
const timeoutDuration = this.options.wait - timeSinceLastExecution;
|
|
55
|
-
this.isPending = true;
|
|
56
|
-
this.timeoutId = setTimeout(() => {
|
|
57
|
-
if (this.lastArgs !== void 0) this.execute(...this.lastArgs);
|
|
58
|
-
}, timeoutDuration);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
this.execute = (...args) => {
|
|
63
|
-
this.fn(...args);
|
|
64
|
-
this.options.onExecute?.(args, this);
|
|
65
|
-
this.lastExecutionTime = Date.now();
|
|
66
|
-
this.clearTimeout();
|
|
67
|
-
this.lastArgs = void 0;
|
|
68
|
-
this.isPending = false;
|
|
69
|
-
};
|
|
70
|
-
this.flush = () => {
|
|
71
|
-
if (this.isPending && this.lastArgs) this.execute(...this.lastArgs);
|
|
72
|
-
};
|
|
73
|
-
this.cancel = () => {
|
|
74
|
-
this.clearTimeout();
|
|
75
|
-
this.lastArgs = void 0;
|
|
76
|
-
this.isPending = false;
|
|
77
|
-
};
|
|
78
|
-
this.clearTimeout = () => {
|
|
79
|
-
if (this.timeoutId) {
|
|
80
|
-
clearTimeout(this.timeoutId);
|
|
81
|
-
this.timeoutId = void 0;
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
52
|
if (this.options.leading === void 0 && this.options.trailing === void 0) {
|
|
85
53
|
this.options.leading = true;
|
|
86
54
|
this.options.trailing = true;
|
|
87
55
|
}
|
|
88
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Attempts to execute the throttled function. The execution behavior depends on the throttler options:
|
|
59
|
+
*
|
|
60
|
+
* - If enough time has passed since the last execution (>= wait period):
|
|
61
|
+
* - With leading=true: Executes immediately
|
|
62
|
+
* - With leading=false: Waits for the next trailing execution
|
|
63
|
+
*
|
|
64
|
+
* - If within the wait period:
|
|
65
|
+
* - With trailing=true: Schedules execution for end of wait period
|
|
66
|
+
* - With trailing=false: Drops the execution
|
|
67
|
+
*/
|
|
68
|
+
maybeExecute = (...args) => {
|
|
69
|
+
const timeSinceLastExecution = Date.now() - this.lastExecutionTime;
|
|
70
|
+
if (this.options.leading && timeSinceLastExecution >= this.options.wait) this.execute(...args);
|
|
71
|
+
else {
|
|
72
|
+
this.lastArgs = args;
|
|
73
|
+
if (!this.timeoutId && this.options.trailing) {
|
|
74
|
+
const timeoutDuration = this.options.wait - timeSinceLastExecution;
|
|
75
|
+
this.isPending = true;
|
|
76
|
+
this.timeoutId = setTimeout(() => {
|
|
77
|
+
if (this.lastArgs !== void 0) this.execute(...this.lastArgs);
|
|
78
|
+
}, timeoutDuration);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
execute = (...args) => {
|
|
83
|
+
this.fn(...args);
|
|
84
|
+
this.options.onExecute?.(args, this);
|
|
85
|
+
this.lastExecutionTime = Date.now();
|
|
86
|
+
this.clearTimeout();
|
|
87
|
+
this.lastArgs = void 0;
|
|
88
|
+
this.isPending = false;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Processes the current pending execution immediately.
|
|
92
|
+
* If there's a pending execution, it will be executed right away
|
|
93
|
+
* and the timeout will be cleared.
|
|
94
|
+
*/
|
|
95
|
+
flush = () => {
|
|
96
|
+
if (this.isPending && this.lastArgs) this.execute(...this.lastArgs);
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Cancels any pending trailing execution and clears internal state.
|
|
100
|
+
* If a trailing execution is scheduled, this will prevent that execution from occurring.
|
|
101
|
+
*/
|
|
102
|
+
cancel = () => {
|
|
103
|
+
this.clearTimeout();
|
|
104
|
+
this.lastArgs = void 0;
|
|
105
|
+
this.isPending = false;
|
|
106
|
+
};
|
|
107
|
+
clearTimeout = () => {
|
|
108
|
+
if (this.timeoutId) {
|
|
109
|
+
clearTimeout(this.timeoutId);
|
|
110
|
+
this.timeoutId = void 0;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
89
113
|
};
|
|
90
114
|
/**
|
|
91
115
|
* Creates a lightweight throttled function that limits how often the provided function can execute.
|
|
@@ -121,5 +145,4 @@ function liteThrottle(fn, options) {
|
|
|
121
145
|
}
|
|
122
146
|
|
|
123
147
|
//#endregion
|
|
124
|
-
export { LiteThrottler, liteThrottle };
|
|
125
|
-
//# sourceMappingURL=lite-throttler.js.map
|
|
148
|
+
export { LiteThrottler, liteThrottle };
|
|
@@ -3,10 +3,5 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Represents a function that can be called with any arguments and returns any value.
|
|
5
5
|
*/
|
|
6
|
-
type AnyFunction = (...args: Array<any>) => any;
|
|
7
|
-
|
|
8
|
-
* Represents an asynchronous function that can be called with any arguments and returns a promise.
|
|
9
|
-
*/
|
|
10
|
-
//#endregion
|
|
11
|
-
export { AnyFunction };
|
|
12
|
-
//# sourceMappingURL=types.d.ts.map
|
|
6
|
+
export type AnyFunction = (...args: Array<any>) => any;
|
|
7
|
+
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/pacer-lite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Lightweight utilities for debouncing, throttling, and more - designed for npm packages.",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,46 +23,25 @@
|
|
|
23
23
|
"minimal"
|
|
24
24
|
],
|
|
25
25
|
"type": "module",
|
|
26
|
-
"
|
|
27
|
-
"module": "./dist/index.js",
|
|
28
|
-
"types": "./dist/index.d.cts",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
29
27
|
"exports": {
|
|
30
|
-
".":
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"./lite-
|
|
35
|
-
|
|
36
|
-
"require": "./dist/lite-batcher.cjs"
|
|
37
|
-
},
|
|
38
|
-
"./lite-debouncer": {
|
|
39
|
-
"import": "./dist/lite-debouncer.js",
|
|
40
|
-
"require": "./dist/lite-debouncer.cjs"
|
|
41
|
-
},
|
|
42
|
-
"./lite-queuer": {
|
|
43
|
-
"import": "./dist/lite-queuer.js",
|
|
44
|
-
"require": "./dist/lite-queuer.cjs"
|
|
45
|
-
},
|
|
46
|
-
"./lite-rate-limiter": {
|
|
47
|
-
"import": "./dist/lite-rate-limiter.js",
|
|
48
|
-
"require": "./dist/lite-rate-limiter.cjs"
|
|
49
|
-
},
|
|
50
|
-
"./lite-throttler": {
|
|
51
|
-
"import": "./dist/lite-throttler.js",
|
|
52
|
-
"require": "./dist/lite-throttler.cjs"
|
|
53
|
-
},
|
|
28
|
+
".": "./dist/index.js",
|
|
29
|
+
"./lite-batcher": "./dist/lite-batcher.js",
|
|
30
|
+
"./lite-debouncer": "./dist/lite-debouncer.js",
|
|
31
|
+
"./lite-queuer": "./dist/lite-queuer.js",
|
|
32
|
+
"./lite-rate-limiter": "./dist/lite-rate-limiter.js",
|
|
33
|
+
"./lite-throttler": "./dist/lite-throttler.js",
|
|
54
34
|
"./package.json": "./package.json"
|
|
55
35
|
},
|
|
56
36
|
"sideEffects": false,
|
|
57
37
|
"engines": {
|
|
58
|
-
"node": ">=
|
|
38
|
+
"node": ">=20"
|
|
59
39
|
},
|
|
60
40
|
"files": [
|
|
61
|
-
"dist
|
|
62
|
-
"src"
|
|
41
|
+
"dist"
|
|
63
42
|
],
|
|
64
43
|
"devDependencies": {
|
|
65
|
-
"@tanstack/pacer": "0.
|
|
44
|
+
"@tanstack/pacer": "0.23.0"
|
|
66
45
|
},
|
|
67
46
|
"scripts": {
|
|
68
47
|
"clean": "premove ./build ./dist",
|
|
@@ -71,6 +50,7 @@
|
|
|
71
50
|
"test:lib": "vitest",
|
|
72
51
|
"test:lib:dev": "pnpm test:lib --watch",
|
|
73
52
|
"test:types": "tsc",
|
|
74
|
-
"build": "tsdown"
|
|
53
|
+
"build": "tsdown",
|
|
54
|
+
"test:build": "publint --strict && node ../../scripts/verify-package.ts"
|
|
75
55
|
}
|
|
76
56
|
}
|
package/dist/index.cjs
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
const require_lite_debouncer = require('./lite-debouncer.cjs');
|
|
3
|
-
const require_lite_throttler = require('./lite-throttler.cjs');
|
|
4
|
-
const require_lite_rate_limiter = require('./lite-rate-limiter.cjs');
|
|
5
|
-
const require_lite_queuer = require('./lite-queuer.cjs');
|
|
6
|
-
const require_lite_batcher = require('./lite-batcher.cjs');
|
|
7
|
-
|
|
8
|
-
exports.LiteBatcher = require_lite_batcher.LiteBatcher;
|
|
9
|
-
exports.LiteDebouncer = require_lite_debouncer.LiteDebouncer;
|
|
10
|
-
exports.LiteQueuer = require_lite_queuer.LiteQueuer;
|
|
11
|
-
exports.LiteRateLimiter = require_lite_rate_limiter.LiteRateLimiter;
|
|
12
|
-
exports.LiteThrottler = require_lite_throttler.LiteThrottler;
|
|
13
|
-
exports.liteBatch = require_lite_batcher.liteBatch;
|
|
14
|
-
exports.liteDebounce = require_lite_debouncer.liteDebounce;
|
|
15
|
-
exports.liteQueue = require_lite_queuer.liteQueue;
|
|
16
|
-
exports.liteRateLimit = require_lite_rate_limiter.liteRateLimit;
|
|
17
|
-
exports.liteThrottle = require_lite_throttler.liteThrottle;
|
package/dist/index.d.cts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { LiteDebouncer, LiteDebouncerOptions, liteDebounce } from "./lite-debouncer.cjs";
|
|
2
|
-
import { LiteThrottler, LiteThrottlerOptions, liteThrottle } from "./lite-throttler.cjs";
|
|
3
|
-
import { LiteRateLimiter, LiteRateLimiterOptions, liteRateLimit } from "./lite-rate-limiter.cjs";
|
|
4
|
-
import { LiteQueuer, LiteQueuerOptions, QueuePosition, liteQueue } from "./lite-queuer.cjs";
|
|
5
|
-
import { LiteBatcher, LiteBatcherOptions, liteBatch } from "./lite-batcher.cjs";
|
|
6
|
-
export { LiteBatcher, LiteBatcherOptions, LiteDebouncer, LiteDebouncerOptions, LiteQueuer, LiteQueuerOptions, LiteRateLimiter, LiteRateLimiterOptions, LiteThrottler, LiteThrottlerOptions, QueuePosition, liteBatch, liteDebounce, liteQueue, liteRateLimit, liteThrottle };
|
package/dist/lite-batcher.cjs
DELETED
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
|
|
3
|
-
//#region src/lite-batcher.ts
|
|
4
|
-
/**
|
|
5
|
-
* A lightweight class that collects items and processes them in batches.
|
|
6
|
-
*
|
|
7
|
-
* This is an alternative to the Batcher in the core @tanstack/pacer package, but is more
|
|
8
|
-
* suitable for libraries and npm packages that need minimal overhead. Unlike the core Batcher,
|
|
9
|
-
* this version does not use TanStack Store for state management, has no devtools integration,
|
|
10
|
-
* no callbacks, and provides only essential batching functionality.
|
|
11
|
-
*
|
|
12
|
-
* Batching is a technique for grouping multiple operations together to be processed as a single unit.
|
|
13
|
-
* This synchronous version is lighter weight and often all you need.
|
|
14
|
-
*
|
|
15
|
-
* The Batcher provides a flexible way to implement batching with configurable:
|
|
16
|
-
* - Maximum batch size (number of items per batch)
|
|
17
|
-
* - Time-based batching (process after X milliseconds)
|
|
18
|
-
* - Custom batch processing logic via getShouldExecute
|
|
19
|
-
*
|
|
20
|
-
* Features included:
|
|
21
|
-
* - Core batching functionality (addItem, flush, clear, cancel)
|
|
22
|
-
* - Size-based batching (maxSize)
|
|
23
|
-
* - Time-based batching (wait timeout)
|
|
24
|
-
* - Custom condition batching (getShouldExecute)
|
|
25
|
-
* - Manual processing controls
|
|
26
|
-
* - Public mutable options
|
|
27
|
-
* - Callback support for monitoring batch execution and state changes
|
|
28
|
-
*
|
|
29
|
-
* Features NOT included (compared to core Batcher):
|
|
30
|
-
* - No TanStack Store state management
|
|
31
|
-
* - No devtools integration
|
|
32
|
-
* - No complex state tracking (execution counts, etc.)
|
|
33
|
-
* - No reactive state management
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* ```ts
|
|
37
|
-
* // Basic batching
|
|
38
|
-
* const batcher = new LiteBatcher<number>(
|
|
39
|
-
* (items) => console.log('Processing batch:', items),
|
|
40
|
-
* {
|
|
41
|
-
* maxSize: 5,
|
|
42
|
-
* wait: 2000,
|
|
43
|
-
* onExecute: (batch, batcher) => {
|
|
44
|
-
* console.log('Batch executed with', batch.length, 'items');
|
|
45
|
-
* },
|
|
46
|
-
* onItemsChange: (batcher) => {
|
|
47
|
-
* console.log('Batch size changed to:', batcher.size);
|
|
48
|
-
* }
|
|
49
|
-
* }
|
|
50
|
-
* );
|
|
51
|
-
*
|
|
52
|
-
* batcher.addItem(1);
|
|
53
|
-
* batcher.addItem(2);
|
|
54
|
-
* // After 2 seconds or when 5 items are added, whichever comes first,
|
|
55
|
-
* // the batch will be processed
|
|
56
|
-
* ```
|
|
57
|
-
*
|
|
58
|
-
* @example
|
|
59
|
-
* ```ts
|
|
60
|
-
* // Custom condition batching
|
|
61
|
-
* const batcher = new LiteBatcher<Task>(
|
|
62
|
-
* (items) => processTasks(items),
|
|
63
|
-
* {
|
|
64
|
-
* getShouldExecute: (items) => items.some(task => task.urgent),
|
|
65
|
-
* maxSize: 10,
|
|
66
|
-
* }
|
|
67
|
-
* );
|
|
68
|
-
*
|
|
69
|
-
* batcher.addItem({ name: 'normal', urgent: false });
|
|
70
|
-
* batcher.addItem({ name: 'urgent', urgent: true }); // Triggers immediate processing
|
|
71
|
-
* ```
|
|
72
|
-
*/
|
|
73
|
-
var LiteBatcher = class {
|
|
74
|
-
constructor(fn, options = {}) {
|
|
75
|
-
this.fn = fn;
|
|
76
|
-
this.options = options;
|
|
77
|
-
this.items = [];
|
|
78
|
-
this.timeoutId = null;
|
|
79
|
-
this._isPending = false;
|
|
80
|
-
this.addItem = (item) => {
|
|
81
|
-
this.items.push(item);
|
|
82
|
-
this._isPending = this.options.wait !== Infinity;
|
|
83
|
-
this.options.onItemsChange?.(this);
|
|
84
|
-
if (this.items.length >= this.options.maxSize || this.options.getShouldExecute(this.items, this)) this.execute();
|
|
85
|
-
else if (this.options.wait !== Infinity) {
|
|
86
|
-
this.clearTimeout();
|
|
87
|
-
this.timeoutId = setTimeout(() => this.execute(), this.getWait());
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
this.execute = () => {
|
|
91
|
-
if (this.items.length === 0) return;
|
|
92
|
-
const batch = this.peekAllItems();
|
|
93
|
-
this.clear();
|
|
94
|
-
this.fn(batch);
|
|
95
|
-
this.options.onExecute?.(batch, this);
|
|
96
|
-
};
|
|
97
|
-
this.flush = () => {
|
|
98
|
-
this.clearTimeout();
|
|
99
|
-
this.execute();
|
|
100
|
-
};
|
|
101
|
-
this.peekAllItems = () => {
|
|
102
|
-
return [...this.items];
|
|
103
|
-
};
|
|
104
|
-
this.clearTimeout = () => {
|
|
105
|
-
if (this.timeoutId) {
|
|
106
|
-
clearTimeout(this.timeoutId);
|
|
107
|
-
this.timeoutId = null;
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
this.clear = () => {
|
|
111
|
-
const hadItems = this.items.length > 0;
|
|
112
|
-
this.items = [];
|
|
113
|
-
this._isPending = false;
|
|
114
|
-
if (hadItems) this.options.onItemsChange?.(this);
|
|
115
|
-
};
|
|
116
|
-
this.cancel = () => {
|
|
117
|
-
this.clearTimeout();
|
|
118
|
-
this._isPending = false;
|
|
119
|
-
};
|
|
120
|
-
this.options.maxSize = this.options.maxSize ?? Infinity;
|
|
121
|
-
this.options.started = this.options.started ?? true;
|
|
122
|
-
this.options.wait = this.options.wait ?? Infinity;
|
|
123
|
-
this.options.getShouldExecute = this.options.getShouldExecute ?? (() => false);
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Number of items currently in the batch
|
|
127
|
-
*/
|
|
128
|
-
get size() {
|
|
129
|
-
return this.items.length;
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Whether the batch has no items to process (items array is empty)
|
|
133
|
-
*/
|
|
134
|
-
get isEmpty() {
|
|
135
|
-
return this.items.length === 0;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Whether the batcher is waiting for the timeout to trigger batch processing
|
|
139
|
-
*/
|
|
140
|
-
get isPending() {
|
|
141
|
-
return this._isPending;
|
|
142
|
-
}
|
|
143
|
-
getWait() {
|
|
144
|
-
if (typeof this.options.wait === "function") return this.options.wait(this);
|
|
145
|
-
return this.options.wait;
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
/**
|
|
149
|
-
* Creates a batcher that processes items in batches.
|
|
150
|
-
*
|
|
151
|
-
* This is an alternative to the batch function in the core @tanstack/pacer package, but is more
|
|
152
|
-
* suitable for libraries and npm packages that need minimal overhead. Unlike the core version,
|
|
153
|
-
* this function creates a batcher with no external dependencies, devtools integration, or reactive state.
|
|
154
|
-
*
|
|
155
|
-
* @example
|
|
156
|
-
* ```ts
|
|
157
|
-
* const batchItems = liteBatch<number>(
|
|
158
|
-
* (items) => console.log('Processing:', items),
|
|
159
|
-
* {
|
|
160
|
-
* maxSize: 3,
|
|
161
|
-
* }
|
|
162
|
-
* );
|
|
163
|
-
*
|
|
164
|
-
* batchItems(1);
|
|
165
|
-
* batchItems(2);
|
|
166
|
-
* batchItems(3); // Triggers batch processing
|
|
167
|
-
* ```
|
|
168
|
-
*/
|
|
169
|
-
function liteBatch(fn, options = {}) {
|
|
170
|
-
return new LiteBatcher(fn, options).addItem;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
//#endregion
|
|
174
|
-
exports.LiteBatcher = LiteBatcher;
|
|
175
|
-
exports.liteBatch = liteBatch;
|
|
176
|
-
//# sourceMappingURL=lite-batcher.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lite-batcher.cjs","names":[],"sources":["../src/lite-batcher.ts"],"sourcesContent":["/**\n * Options for configuring a lite batcher instance\n */\nexport interface LiteBatcherOptions<TValue> {\n /**\n * Custom function to determine if a batch should be processed\n * Return true to process the batch immediately\n */\n getShouldExecute?: (\n items: Array<TValue>,\n batcher: LiteBatcher<TValue>,\n ) => boolean\n /**\n * Maximum number of items in a batch\n * @default Infinity\n */\n maxSize?: number\n /**\n * Callback fired after a batch is processed\n */\n onExecute?: (batch: Array<TValue>, batcher: LiteBatcher<TValue>) => void\n /**\n * Callback fired after items are added to the batcher\n */\n onItemsChange?: (batcher: LiteBatcher<TValue>) => void\n /**\n * Whether the batcher should start processing immediately\n * @default true\n */\n started?: boolean\n /**\n * Maximum time in milliseconds to wait before processing a batch.\n * If the wait duration has elapsed, the batch will be processed.\n * If not provided, the batch will not be triggered by a timeout.\n * @default Infinity\n */\n wait?: number | ((batcher: LiteBatcher<TValue>) => number)\n}\n\n/**\n * A lightweight class that collects items and processes them in batches.\n *\n * This is an alternative to the Batcher in the core @tanstack/pacer package, but is more\n * suitable for libraries and npm packages that need minimal overhead. Unlike the core Batcher,\n * this version does not use TanStack Store for state management, has no devtools integration,\n * no callbacks, and provides only essential batching functionality.\n *\n * Batching is a technique for grouping multiple operations together to be processed as a single unit.\n * This synchronous version is lighter weight and often all you need.\n *\n * The Batcher provides a flexible way to implement batching with configurable:\n * - Maximum batch size (number of items per batch)\n * - Time-based batching (process after X milliseconds)\n * - Custom batch processing logic via getShouldExecute\n *\n * Features included:\n * - Core batching functionality (addItem, flush, clear, cancel)\n * - Size-based batching (maxSize)\n * - Time-based batching (wait timeout)\n * - Custom condition batching (getShouldExecute)\n * - Manual processing controls\n * - Public mutable options\n * - Callback support for monitoring batch execution and state changes\n *\n * Features NOT included (compared to core Batcher):\n * - No TanStack Store state management\n * - No devtools integration\n * - No complex state tracking (execution counts, etc.)\n * - No reactive state management\n *\n * @example\n * ```ts\n * // Basic batching\n * const batcher = new LiteBatcher<number>(\n * (items) => console.log('Processing batch:', items),\n * {\n * maxSize: 5,\n * wait: 2000,\n * onExecute: (batch, batcher) => {\n * console.log('Batch executed with', batch.length, 'items');\n * },\n * onItemsChange: (batcher) => {\n * console.log('Batch size changed to:', batcher.size);\n * }\n * }\n * );\n *\n * batcher.addItem(1);\n * batcher.addItem(2);\n * // After 2 seconds or when 5 items are added, whichever comes first,\n * // the batch will be processed\n * ```\n *\n * @example\n * ```ts\n * // Custom condition batching\n * const batcher = new LiteBatcher<Task>(\n * (items) => processTasks(items),\n * {\n * getShouldExecute: (items) => items.some(task => task.urgent),\n * maxSize: 10,\n * }\n * );\n *\n * batcher.addItem({ name: 'normal', urgent: false });\n * batcher.addItem({ name: 'urgent', urgent: true }); // Triggers immediate processing\n * ```\n */\nexport class LiteBatcher<TValue> {\n private items: Array<TValue> = []\n private timeoutId: NodeJS.Timeout | null = null\n private _isPending = false\n\n constructor(\n public fn: (items: Array<TValue>) => void,\n public options: LiteBatcherOptions<TValue> = {},\n ) {\n // Set defaults\n this.options.maxSize = this.options.maxSize ?? Infinity\n this.options.started = this.options.started ?? true\n this.options.wait = this.options.wait ?? Infinity\n this.options.getShouldExecute =\n this.options.getShouldExecute ?? (() => false)\n }\n\n /**\n * Number of items currently in the batch\n */\n get size(): number {\n return this.items.length\n }\n\n /**\n * Whether the batch has no items to process (items array is empty)\n */\n get isEmpty(): boolean {\n return this.items.length === 0\n }\n\n /**\n * Whether the batcher is waiting for the timeout to trigger batch processing\n */\n get isPending(): boolean {\n return this._isPending\n }\n\n private getWait(): number {\n if (typeof this.options.wait === 'function') {\n return this.options.wait(this)\n }\n return this.options.wait!\n }\n\n /**\n * Adds an item to the batcher\n * If the batch size is reached, timeout occurs, or getShouldExecute returns true, the batch will be processed\n */\n addItem = (item: TValue): void => {\n this.items.push(item)\n this._isPending = this.options.wait !== Infinity\n this.options.onItemsChange?.(this)\n\n const shouldProcess =\n this.items.length >= this.options.maxSize! ||\n this.options.getShouldExecute!(this.items, this)\n\n if (shouldProcess) {\n this.execute()\n } else if (this.options.wait !== Infinity) {\n this.clearTimeout() // clear any pending timeout to replace it with a new one\n this.timeoutId = setTimeout(() => this.execute(), this.getWait())\n }\n }\n\n /**\n * Processes the current batch of items.\n * This method will automatically be triggered if the batcher is running and any of these conditions are met:\n * - The number of items reaches maxSize\n * - The wait duration has elapsed\n * - The getShouldExecute function returns true upon adding an item\n *\n * You can also call this method manually to process the current batch at any time.\n */\n private execute = (): void => {\n if (this.items.length === 0) {\n return\n }\n\n const batch = this.peekAllItems() // copy of the items to be processed (to prevent race conditions)\n this.clear() // Clear items before processing to prevent race conditions\n\n this.fn(batch) // EXECUTE\n this.options.onExecute?.(batch, this)\n }\n\n /**\n * Processes the current batch of items immediately\n */\n flush = (): void => {\n this.clearTimeout() // clear any pending timeout\n this.execute() // execute immediately\n }\n\n /**\n * Returns a copy of all items in the batcher\n */\n peekAllItems = (): Array<TValue> => {\n return [...this.items]\n }\n\n private clearTimeout = (): void => {\n if (this.timeoutId) {\n clearTimeout(this.timeoutId)\n this.timeoutId = null\n }\n }\n\n /**\n * Removes all items from the batcher\n */\n clear = (): void => {\n const hadItems = this.items.length > 0\n this.items = []\n this._isPending = false\n if (hadItems) {\n this.options.onItemsChange?.(this)\n }\n }\n\n /**\n * Cancels any pending execution that was scheduled.\n * Does NOT clear out the items.\n */\n cancel = (): void => {\n this.clearTimeout()\n this._isPending = false\n }\n}\n\n/**\n * Creates a batcher that processes items in batches.\n *\n * This is an alternative to the batch function in the core @tanstack/pacer package, but is more\n * suitable for libraries and npm packages that need minimal overhead. Unlike the core version,\n * this function creates a batcher with no external dependencies, devtools integration, or reactive state.\n *\n * @example\n * ```ts\n * const batchItems = liteBatch<number>(\n * (items) => console.log('Processing:', items),\n * {\n * maxSize: 3,\n * }\n * );\n *\n * batchItems(1);\n * batchItems(2);\n * batchItems(3); // Triggers batch processing\n * ```\n */\nexport function liteBatch<TValue>(\n fn: (items: Array<TValue>) => void,\n options: LiteBatcherOptions<TValue> = {},\n): (item: TValue) => void {\n const batcher = new LiteBatcher<TValue>(fn, options)\n return batcher.addItem\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4GA,IAAa,cAAb,MAAiC;CAK/B,YACE,AAAO,IACP,AAAO,UAAsC,EAAE,EAC/C;EAFO;EACA;eANsB,EAAE;mBACU;oBACtB;kBA8CV,SAAuB;GAChC,KAAK,MAAM,KAAK,KAAK;GACrB,KAAK,aAAa,KAAK,QAAQ,SAAS;GACxC,KAAK,QAAQ,gBAAgB,KAAK;GAMlC,IAHE,KAAK,MAAM,UAAU,KAAK,QAAQ,WAClC,KAAK,QAAQ,iBAAkB,KAAK,OAAO,KAAK,EAGhD,KAAK,SAAS;QACT,IAAI,KAAK,QAAQ,SAAS,UAAU;IACzC,KAAK,cAAc;IACnB,KAAK,YAAY,iBAAiB,KAAK,SAAS,EAAE,KAAK,SAAS,CAAC;;;uBAavC;GAC5B,IAAI,KAAK,MAAM,WAAW,GACxB;GAGF,MAAM,QAAQ,KAAK,cAAc;GACjC,KAAK,OAAO;GAEZ,KAAK,GAAG,MAAM;GACd,KAAK,QAAQ,YAAY,OAAO,KAAK;;qBAMnB;GAClB,KAAK,cAAc;GACnB,KAAK,SAAS;;4BAMoB;GAClC,OAAO,CAAC,GAAG,KAAK,MAAM;;4BAGW;GACjC,IAAI,KAAK,WAAW;IAClB,aAAa,KAAK,UAAU;IAC5B,KAAK,YAAY;;;qBAOD;GAClB,MAAM,WAAW,KAAK,MAAM,SAAS;GACrC,KAAK,QAAQ,EAAE;GACf,KAAK,aAAa;GAClB,IAAI,UACF,KAAK,QAAQ,gBAAgB,KAAK;;sBAQjB;GACnB,KAAK,cAAc;GACnB,KAAK,aAAa;;EArHlB,KAAK,QAAQ,UAAU,KAAK,QAAQ,WAAW;EAC/C,KAAK,QAAQ,UAAU,KAAK,QAAQ,WAAW;EAC/C,KAAK,QAAQ,OAAO,KAAK,QAAQ,QAAQ;EACzC,KAAK,QAAQ,mBACX,KAAK,QAAQ,2BAA2B;;;;;CAM5C,IAAI,OAAe;EACjB,OAAO,KAAK,MAAM;;;;;CAMpB,IAAI,UAAmB;EACrB,OAAO,KAAK,MAAM,WAAW;;;;;CAM/B,IAAI,YAAqB;EACvB,OAAO,KAAK;;CAGd,AAAQ,UAAkB;EACxB,IAAI,OAAO,KAAK,QAAQ,SAAS,YAC/B,OAAO,KAAK,QAAQ,KAAK,KAAK;EAEhC,OAAO,KAAK,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;AA8GxB,SAAgB,UACd,IACA,UAAsC,EAAE,EAChB;CAExB,OAAO,IADa,YAAoB,IAAI,QAC9B,CAAC"}
|