@peerbit/time 2.0.8 → 2.1.0-2f92713

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.
@@ -0,0 +1,24 @@
1
+ export declare const debounceFixedInterval: <T extends (...args: any[]) => any | Promise<any>>(fn: T, delay: number | (() => number), options?: {
2
+ onError?: (error: Error) => void;
3
+ leading?: boolean;
4
+ }) => {
5
+ call: (...args: Parameters<T>) => Promise<void>;
6
+ close: () => void;
7
+ };
8
+ export declare const debounceAccumulator: <K, T, V>(fn: (args: V) => any, create: () => {
9
+ delete: (key: K) => void;
10
+ add: (value: T) => void;
11
+ size: () => number;
12
+ value: V;
13
+ has: (key: K) => boolean;
14
+ }, delay: number | (() => number), options?: {
15
+ leading?: boolean;
16
+ }) => {
17
+ add: (value: T) => Promise<void>;
18
+ delete: (key: K) => void;
19
+ size: () => number;
20
+ invoke: () => Promise<void>;
21
+ close: () => void;
22
+ has: (key: K) => boolean;
23
+ };
24
+ //# sourceMappingURL=aggregators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregators.d.ts","sourceRoot":"","sources":["../../src/aggregators.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,GACjC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,EAEhD,IAAI,CAAC,EACL,OAAO,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,EAC9B,UAAU;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,KAC/D;IAAE,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,IAAI,CAAA;CAsFtE,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAC1C,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,GAAG,EACpB,QAAQ,MAAM;IACb,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAC;IACzB,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,MAAM,CAAC;IACnB,KAAK,EAAE,CAAC,CAAC;IACT,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC;CACzB,EACD,OAAO,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,EAC9B,UAAU;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE;iBAiBjB,CAAC,KAAG,OAAO,CAAC,IAAI,CAAC;kBAKhB,CAAC;;;;eAMJ,CAAC;CAEb,CAAC"}
@@ -0,0 +1,110 @@
1
+ export const debounceFixedInterval = (fn, delay, options) => {
2
+ // A debounce function that waits for the delay after the async function finishes
3
+ // before invoking the function again, and returns a promise that resolves when the invocation is done.
4
+ let delayFn = typeof delay === "number" ? () => delay : delay;
5
+ const onError = options?.onError ||
6
+ ((error) => {
7
+ throw error;
8
+ });
9
+ // When leading is true, the first call is immediate. Otherwise, it's deferred.
10
+ const leading = options?.leading !== undefined ? options.leading : true;
11
+ let timeout = null;
12
+ let lastArgs = null;
13
+ let lastThis;
14
+ let pendingCall = false;
15
+ let isRunning = false;
16
+ // Array of resolvers for the promises returned by each debounced call.
17
+ let waitingResolvers = [];
18
+ // Track when the last invocation finished.
19
+ let lastInvokeTime = null;
20
+ const invoke = async () => {
21
+ timeout = null;
22
+ if (!lastArgs) {
23
+ return;
24
+ }
25
+ const args = lastArgs;
26
+ lastArgs = null;
27
+ pendingCall = false;
28
+ isRunning = true;
29
+ try {
30
+ await Promise.resolve(fn.apply(lastThis, args));
31
+ }
32
+ catch (error) {
33
+ onError(error);
34
+ }
35
+ finally {
36
+ isRunning = false;
37
+ lastInvokeTime = Date.now();
38
+ // Resolve all waiting promises.
39
+ waitingResolvers.forEach((resolve) => resolve());
40
+ waitingResolvers = [];
41
+ // If calls came in during the invocation, schedule the next run.
42
+ if (pendingCall) {
43
+ const timeSinceInvoke = Date.now() - (lastInvokeTime || 0);
44
+ const delayRemaining = Math.max(delayFn() - timeSinceInvoke, 0);
45
+ timeout = setTimeout(invoke, delayRemaining);
46
+ }
47
+ }
48
+ };
49
+ const debounced = (...args) => {
50
+ lastArgs = args;
51
+ lastThis = this;
52
+ pendingCall = true;
53
+ // Create a new promise that will resolve when the associated invocation completes.
54
+ const p = new Promise((resolve) => {
55
+ waitingResolvers.push(resolve);
56
+ });
57
+ const now = Date.now();
58
+ if (!isRunning && !timeout) {
59
+ if (leading) {
60
+ // If leading is enabled, trigger immediately if it's the very first call
61
+ // or if enough time has passed since the last invocation.
62
+ if (lastInvokeTime === null || now - lastInvokeTime >= delayFn()) {
63
+ invoke();
64
+ }
65
+ else {
66
+ const delayRemaining = delayFn() - (now - lastInvokeTime);
67
+ timeout = setTimeout(invoke, delayRemaining);
68
+ }
69
+ }
70
+ else {
71
+ // If not leading, always schedule a trailing invocation.
72
+ timeout = setTimeout(invoke, delayFn());
73
+ }
74
+ }
75
+ return p;
76
+ };
77
+ return {
78
+ call: debounced,
79
+ close: () => {
80
+ isRunning = false;
81
+ if (timeout !== null) {
82
+ clearTimeout(timeout);
83
+ }
84
+ },
85
+ };
86
+ };
87
+ export const debounceAccumulator = (fn, create, delay, options) => {
88
+ let accumulator = create();
89
+ const invoke = async () => {
90
+ const toSend = accumulator.value;
91
+ accumulator = create();
92
+ await fn(toSend);
93
+ };
94
+ const { call: debounced, close } = debounceFixedInterval(invoke, delay, options);
95
+ return {
96
+ add: (value) => {
97
+ accumulator.add(value);
98
+ // Return a promise that resolves when the debounced (accumulated) call is executed.
99
+ return debounced();
100
+ },
101
+ delete: (key) => {
102
+ accumulator.delete(key);
103
+ },
104
+ size: () => accumulator.size(),
105
+ invoke,
106
+ close: () => close(),
107
+ has: (key) => accumulator.has(key),
108
+ };
109
+ };
110
+ //# sourceMappingURL=aggregators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregators.js","sourceRoot":"","sources":["../../src/aggregators.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { hrtime } from "./hrtime.js";
2
+ export * from "./aggregators.js";
2
3
  export * from "./wait.js";
3
4
  export * from "./metrics.js";
4
5
  export { hrtime };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,CAAC"}
package/dist/src/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { hrtime } from "./hrtime.js";
2
+ export * from "./aggregators.js";
2
3
  export * from "./wait.js";
3
4
  export * from "./metrics.js";
4
5
  export { hrtime };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"wait.d.ts","sourceRoot":"","sources":["../../src/wait.ts"],"names":[],"mappings":"AAAA,qBAAa,YAAa,SAAQ,KAAK;CAAG;AAE1C,qBAAa,UAAW,SAAQ,KAAK;CAAG;AACxC,eAAO,MAAM,KAAK,OAAc,MAAM,YAAY;IAAE,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,kBAYzE,CAAC;AASF,eAAO,MAAM,OAAO,GAAU,CAAC,MAC1B,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,YACf;IACR,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB,KACC,OAAO,CAAC,CAAC,GAAG,SAAS,CAiCvB,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,CAAC,MAClC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,YACf;IACR,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB,KACC,OAAO,CAAC,CAAC,CAyCX,CAAC"}
1
+ {"version":3,"file":"wait.d.ts","sourceRoot":"","sources":["../../src/wait.ts"],"names":[],"mappings":"AAAA,qBAAa,YAAa,SAAQ,KAAK;CAAG;AAE1C,qBAAa,UAAW,SAAQ,KAAK;CAAG;AACxC,eAAO,MAAM,KAAK,GAAU,IAAI,MAAM,EAAE,UAAU;IAAE,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,kBAYzE,CAAC;AASF,eAAO,MAAM,OAAO,GAAU,CAAC,EAC9B,IAAI,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACxB,UAAS;IACR,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACqB,KAC5C,OAAO,CAAC,CAAC,GAAG,SAAS,CAiCvB,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,CAAC,EACtC,IAAI,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACxB,UAAS;IACR,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACoB,KAC3C,OAAO,CAAC,CAAC,CAyCX,CAAC"}
package/package.json CHANGED
@@ -1,62 +1,62 @@
1
1
  {
2
- "name": "@peerbit/time",
3
- "version": "2.0.8",
4
- "description": "Utility functions for time",
5
- "type": "module",
6
- "sideEffects": false,
7
- "types": "./dist/src/index.d.ts",
8
- "typesVersions": {
9
- "*": {
10
- "*": [
11
- "*",
12
- "dist/*",
13
- "dist/src/*",
14
- "dist/src/*/index"
15
- ],
16
- "src/*": [
17
- "*",
18
- "dist/*",
19
- "dist/src/*",
20
- "dist/src/*/index"
21
- ]
22
- }
23
- },
24
- "files": [
25
- "src",
26
- "dist",
27
- "!dist/test",
28
- "!**/*.tsbuildinfo"
29
- ],
30
- "exports": {
31
- ".": {
32
- "types": "./dist/src/index.d.ts",
33
- "import": "./dist/src/index.js"
34
- }
35
- },
36
- "eslintConfig": {
37
- "extends": "peerbit",
38
- "parserOptions": {
39
- "project": true,
40
- "sourceType": "module"
41
- },
42
- "ignorePatterns": [
43
- "!.aegir.js",
44
- "test/ts-use",
45
- "*.d.ts"
46
- ]
47
- },
48
- "browser": {
49
- "./dist/src/hrtime.js": "./dist/src/hrtime.browser.js"
50
- },
51
- "publishConfig": {
52
- "access": "public"
53
- },
54
- "scripts": {
55
- "clean": "aegir clean",
56
- "build": "aegir build --no-bundle",
57
- "test": "aegir test",
58
- "lint": "aegir lint"
59
- },
60
- "author": "dao.xyz",
61
- "license": "MIT"
2
+ "name": "@peerbit/time",
3
+ "version": "2.1.0-2f92713",
4
+ "description": "Utility functions for time",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "types": "./dist/src/index.d.ts",
8
+ "typesVersions": {
9
+ "*": {
10
+ "*": [
11
+ "*",
12
+ "dist/*",
13
+ "dist/src/*",
14
+ "dist/src/*/index"
15
+ ],
16
+ "src/*": [
17
+ "*",
18
+ "dist/*",
19
+ "dist/src/*",
20
+ "dist/src/*/index"
21
+ ]
22
+ }
23
+ },
24
+ "files": [
25
+ "src",
26
+ "dist",
27
+ "!dist/test",
28
+ "!**/*.tsbuildinfo"
29
+ ],
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/src/index.d.ts",
33
+ "import": "./dist/src/index.js"
34
+ }
35
+ },
36
+ "eslintConfig": {
37
+ "extends": "peerbit",
38
+ "parserOptions": {
39
+ "project": true,
40
+ "sourceType": "module"
41
+ },
42
+ "ignorePatterns": [
43
+ "!.aegir.js",
44
+ "test/ts-use",
45
+ "*.d.ts"
46
+ ]
47
+ },
48
+ "browser": {
49
+ "./dist/src/hrtime.js": "./dist/src/hrtime.browser.js"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public"
53
+ },
54
+ "scripts": {
55
+ "clean": "aegir clean",
56
+ "build": "aegir build --no-bundle",
57
+ "test": "aegir test",
58
+ "lint": "aegir lint"
59
+ },
60
+ "author": "dao.xyz",
61
+ "license": "MIT"
62
62
  }
@@ -0,0 +1,135 @@
1
+ export const debounceFixedInterval = <
2
+ T extends (...args: any[]) => any | Promise<any>,
3
+ >(
4
+ fn: T,
5
+ delay: number | (() => number),
6
+ options?: { onError?: (error: Error) => void; leading?: boolean },
7
+ ): { call: (...args: Parameters<T>) => Promise<void>; close: () => void } => {
8
+ // A debounce function that waits for the delay after the async function finishes
9
+ // before invoking the function again, and returns a promise that resolves when the invocation is done.
10
+ let delayFn: () => number = typeof delay === "number" ? () => delay : delay;
11
+ const onError =
12
+ options?.onError ||
13
+ ((error: Error) => {
14
+ throw error;
15
+ });
16
+ // When leading is true, the first call is immediate. Otherwise, it's deferred.
17
+ const leading = options?.leading !== undefined ? options.leading : true;
18
+ let timeout: NodeJS.Timeout | null = null;
19
+ let lastArgs: any[] | null = null;
20
+ let lastThis: any;
21
+ let pendingCall = false;
22
+ let isRunning = false;
23
+ // Array of resolvers for the promises returned by each debounced call.
24
+ let waitingResolvers: Array<() => void> = [];
25
+ // Track when the last invocation finished.
26
+ let lastInvokeTime: number | null = null;
27
+
28
+ const invoke = async () => {
29
+ timeout = null;
30
+ if (!lastArgs) {
31
+ return;
32
+ }
33
+ const args = lastArgs;
34
+ lastArgs = null;
35
+ pendingCall = false;
36
+ isRunning = true;
37
+ try {
38
+ await Promise.resolve(fn.apply(lastThis, args));
39
+ } catch (error) {
40
+ onError(error as Error);
41
+ } finally {
42
+ isRunning = false;
43
+ lastInvokeTime = Date.now();
44
+ // Resolve all waiting promises.
45
+ waitingResolvers.forEach((resolve) => resolve());
46
+ waitingResolvers = [];
47
+ // If calls came in during the invocation, schedule the next run.
48
+ if (pendingCall) {
49
+ const timeSinceInvoke = Date.now() - (lastInvokeTime || 0);
50
+ const delayRemaining = Math.max(delayFn() - timeSinceInvoke, 0);
51
+ timeout = setTimeout(invoke, delayRemaining);
52
+ }
53
+ }
54
+ };
55
+
56
+ const debounced = (...args: Parameters<T>): Promise<void> => {
57
+ lastArgs = args;
58
+ lastThis = this;
59
+ pendingCall = true;
60
+ // Create a new promise that will resolve when the associated invocation completes.
61
+ const p = new Promise<void>((resolve) => {
62
+ waitingResolvers.push(resolve);
63
+ });
64
+
65
+ const now = Date.now();
66
+ if (!isRunning && !timeout) {
67
+ if (leading) {
68
+ // If leading is enabled, trigger immediately if it's the very first call
69
+ // or if enough time has passed since the last invocation.
70
+ if (lastInvokeTime === null || now - lastInvokeTime >= delayFn()) {
71
+ invoke();
72
+ } else {
73
+ const delayRemaining = delayFn() - (now - lastInvokeTime);
74
+ timeout = setTimeout(invoke, delayRemaining);
75
+ }
76
+ } else {
77
+ // If not leading, always schedule a trailing invocation.
78
+ timeout = setTimeout(invoke, delayFn());
79
+ }
80
+ }
81
+ return p;
82
+ };
83
+
84
+ return {
85
+ call: debounced,
86
+ close: () => {
87
+ isRunning = false;
88
+ if (timeout !== null) {
89
+ clearTimeout(timeout);
90
+ }
91
+ },
92
+ };
93
+ };
94
+
95
+ export const debounceAccumulator = <K, T, V>(
96
+ fn: (args: V) => any,
97
+ create: () => {
98
+ delete: (key: K) => void;
99
+ add: (value: T) => void;
100
+ size: () => number;
101
+ value: V;
102
+ has: (key: K) => boolean;
103
+ },
104
+ delay: number | (() => number),
105
+ options?: { leading?: boolean },
106
+ ) => {
107
+ let accumulator = create();
108
+
109
+ const invoke = async () => {
110
+ const toSend = accumulator.value;
111
+ accumulator = create();
112
+ await fn(toSend);
113
+ };
114
+
115
+ const { call: debounced, close } = debounceFixedInterval(
116
+ invoke,
117
+ delay,
118
+ options,
119
+ );
120
+
121
+ return {
122
+ add: (value: T): Promise<void> => {
123
+ accumulator.add(value);
124
+ // Return a promise that resolves when the debounced (accumulated) call is executed.
125
+ return debounced();
126
+ },
127
+ delete: (key: K) => {
128
+ accumulator.delete(key);
129
+ },
130
+ size: () => accumulator.size(),
131
+ invoke,
132
+ close: () => close(),
133
+ has: (key: K) => accumulator.has(key),
134
+ };
135
+ };
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { hrtime } from "./hrtime.js";
2
2
 
3
+ export * from "./aggregators.js";
3
4
  export * from "./wait.js";
4
5
  export * from "./metrics.js";
5
6
  export { hrtime };