@certik/skynet 0.20.1 → 0.21.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/CHANGELOG.md +12 -0
- package/availability.ts +41 -11
- package/log.ts +22 -4
- package/object-hash.ts +66 -0
- package/package.json +5 -2
- package/web3.ts +0 -41
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.21.0
|
|
4
|
+
|
|
5
|
+
- BREAKING: Remove support for web3.js.
|
|
6
|
+
- Add `debug` log level to `log` library. They will only be printed when `NODE_ENV` is set to `development`.
|
|
7
|
+
- Hide all logs from `log` library when `NODE_ENV` is set to `test`.
|
|
8
|
+
- Add `throttle` and `memoize` to `availability` library.
|
|
9
|
+
- Add `object-hash` library for getting hash of an object. Based on xxhash algorithm.
|
|
10
|
+
|
|
11
|
+
## 0.20.2
|
|
12
|
+
|
|
13
|
+
- Make `options` in `withRetry` function optional
|
|
14
|
+
|
|
3
15
|
## 0.20.1
|
|
4
16
|
|
|
5
17
|
- Update dynamodb `scanWholeTable` types
|
package/availability.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
import pThrottle from "p-throttle";
|
|
2
|
+
import pMemoize, { type CacheStorage } from "p-memoize";
|
|
3
|
+
import type { AsyncReturnType } from "type-fest";
|
|
4
|
+
import QuickLRU from "quick-lru";
|
|
5
|
+
import { getHash } from "./object-hash";
|
|
6
|
+
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8
|
+
export declare type AnyAsyncFunction = (...arguments_: readonly any[]) => Promise<any>;
|
|
9
|
+
|
|
1
10
|
export async function wait(time: number) {
|
|
2
11
|
return new Promise((resolve) => {
|
|
3
12
|
setTimeout(resolve, time);
|
|
@@ -47,28 +56,49 @@ export async function exponentialRetry<T>(
|
|
|
47
56
|
return result;
|
|
48
57
|
}
|
|
49
58
|
|
|
50
|
-
|
|
51
|
-
export function withRetry<F extends (...args: any[]) => any>(
|
|
59
|
+
export function withRetry<F extends AnyAsyncFunction>(
|
|
52
60
|
func: F,
|
|
53
|
-
options
|
|
54
|
-
) {
|
|
55
|
-
let retries = options
|
|
56
|
-
let duration = options
|
|
57
|
-
const growFactorFinal = options
|
|
61
|
+
options?: { maxRetry?: number; initialDuration?: number; growFactor?: number },
|
|
62
|
+
): F {
|
|
63
|
+
let retries = options?.maxRetry || 3;
|
|
64
|
+
let duration = options?.initialDuration || 500;
|
|
65
|
+
const growFactorFinal = options?.growFactor || 2;
|
|
58
66
|
|
|
59
|
-
return async (...args: Parameters<F>): Promise<
|
|
67
|
+
return (async (...args: Parameters<F>): Promise<AsyncReturnType<F>> => {
|
|
60
68
|
do {
|
|
61
69
|
try {
|
|
62
70
|
return await func(...args);
|
|
63
71
|
} catch (error) {
|
|
64
72
|
retries = retries - 1;
|
|
65
|
-
if (retries
|
|
73
|
+
if (retries <= 0) {
|
|
66
74
|
throw error;
|
|
67
75
|
}
|
|
68
76
|
await wait(duration);
|
|
69
77
|
duration = duration * growFactorFinal;
|
|
70
78
|
}
|
|
71
|
-
} while (retries
|
|
79
|
+
} while (retries > 0);
|
|
72
80
|
throw new Error("unreachable");
|
|
73
|
-
};
|
|
81
|
+
}) as F;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function memoize<F extends AnyAsyncFunction>(
|
|
85
|
+
func: F,
|
|
86
|
+
options?: {
|
|
87
|
+
cache?: CacheStorage<string, AsyncReturnType<F>> | false;
|
|
88
|
+
cacheKey?: (args: Parameters<F>) => string;
|
|
89
|
+
lruMaxSize?: number;
|
|
90
|
+
},
|
|
91
|
+
) {
|
|
92
|
+
if (!options) {
|
|
93
|
+
options = {};
|
|
94
|
+
}
|
|
95
|
+
if (!options.cache) {
|
|
96
|
+
options.cache = new QuickLRU({ maxSize: options.lruMaxSize || 10000 });
|
|
97
|
+
}
|
|
98
|
+
if (!options.cacheKey) {
|
|
99
|
+
options.cacheKey = (args: Parameters<F>) => getHash(args);
|
|
100
|
+
}
|
|
101
|
+
return pMemoize<F, string>(func, options);
|
|
74
102
|
}
|
|
103
|
+
|
|
104
|
+
export { pThrottle as throttle };
|
package/log.ts
CHANGED
|
@@ -34,20 +34,38 @@ function timestamp() {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
const inline = {
|
|
37
|
+
debug: function (...args: unknown[]) {
|
|
38
|
+
if (process.env.NODE_ENV === "development") {
|
|
39
|
+
console.log(`${timestamp()} ${getLine(args)}`);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
37
42
|
log: function (...args: unknown[]) {
|
|
38
|
-
|
|
43
|
+
if (process.env.NODE_ENV !== "test") {
|
|
44
|
+
console.log(`${timestamp()} ${getLine(args)}`);
|
|
45
|
+
}
|
|
39
46
|
},
|
|
40
47
|
error: function (...args: unknown[]) {
|
|
41
|
-
|
|
48
|
+
if (process.env.NODE_ENV !== "test") {
|
|
49
|
+
console.error(`${timestamp()} ${getLine(args)}`);
|
|
50
|
+
}
|
|
42
51
|
},
|
|
43
52
|
};
|
|
44
53
|
|
|
45
54
|
const logger = {
|
|
55
|
+
debug: function (...args: unknown[]) {
|
|
56
|
+
if (process.env.NODE_ENV === "development") {
|
|
57
|
+
console.log(`[${timestamp()}]`, ...args);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
46
60
|
log: function (...args: unknown[]) {
|
|
47
|
-
|
|
61
|
+
if (process.env.NODE_ENV !== "test") {
|
|
62
|
+
console.log(`[${timestamp()}]`, ...args);
|
|
63
|
+
}
|
|
48
64
|
},
|
|
49
65
|
error: function (...args: unknown[]) {
|
|
50
|
-
|
|
66
|
+
if (process.env.NODE_ENV !== "test") {
|
|
67
|
+
console.error(`[${timestamp()}]`, ...args);
|
|
68
|
+
}
|
|
51
69
|
},
|
|
52
70
|
};
|
|
53
71
|
|
package/object-hash.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import xh from "@node-rs/xxhash";
|
|
2
|
+
|
|
3
|
+
export function getHash(obj: unknown) {
|
|
4
|
+
const xxh3 = xh.xxh3.Xxh3.withSeed();
|
|
5
|
+
hash(obj, xxh3);
|
|
6
|
+
return xxh3.digest().toString(16);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function hash(obj: unknown, xxh3: xh.xxh3.Xxh3) {
|
|
10
|
+
if (obj === null) {
|
|
11
|
+
xxh3.update("null");
|
|
12
|
+
} else if (obj === undefined) {
|
|
13
|
+
xxh3.update("undefined");
|
|
14
|
+
} else if (typeof obj === "string") {
|
|
15
|
+
xxh3.update(obj);
|
|
16
|
+
} else if (typeof obj === "number") {
|
|
17
|
+
xxh3.update(obj.toString());
|
|
18
|
+
} else if (typeof obj === "boolean") {
|
|
19
|
+
xxh3.update(obj.toString());
|
|
20
|
+
} else if (typeof obj === "bigint") {
|
|
21
|
+
xxh3.update(obj.toString());
|
|
22
|
+
} else if (obj instanceof Date) {
|
|
23
|
+
xxh3.update(obj.toISOString());
|
|
24
|
+
} else if (Array.isArray(obj)) {
|
|
25
|
+
arrayHash(obj, xxh3);
|
|
26
|
+
} else if (obj instanceof Set) {
|
|
27
|
+
setHash(obj, xxh3);
|
|
28
|
+
} else if (obj instanceof Map) {
|
|
29
|
+
mapHash(obj, xxh3);
|
|
30
|
+
} else if (typeof obj === "object") {
|
|
31
|
+
objectHash(obj, xxh3);
|
|
32
|
+
} else {
|
|
33
|
+
throw new Error(`Unsupported type: ${obj}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function arrayHash(array: unknown[], xxh3: xh.xxh3.Xxh3) {
|
|
38
|
+
xxh3.update("[");
|
|
39
|
+
for (const obj of array) {
|
|
40
|
+
hash(obj, xxh3);
|
|
41
|
+
}
|
|
42
|
+
xxh3.update("]");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
46
|
+
function setHash(_set: Set<unknown>, _xxh3: xh.xxh3.Xxh3) {
|
|
47
|
+
throw new Error("Set hashing not implemented");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function mapHash(map: Map<unknown, unknown>, xxh3: xh.xxh3.Xxh3) {
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
52
|
+
const array = Array.from(map.entries()).sort(([aKey], [bKey]) => (aKey as any).localeCompare(bKey));
|
|
53
|
+
for (const [key, value] of array) {
|
|
54
|
+
hash(key, xxh3);
|
|
55
|
+
hash(value, xxh3);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
|
+
function objectHash(obj: any, xxh3: xh.xxh3.Xxh3) {
|
|
61
|
+
const array = Object.entries(obj).sort(([aKey], [bKey]) => aKey.localeCompare(bKey));
|
|
62
|
+
for (const [key, value] of array) {
|
|
63
|
+
hash(key, xxh3);
|
|
64
|
+
hash(value, xxh3);
|
|
65
|
+
}
|
|
66
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@certik/skynet",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "Skynet Shared JS library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -21,14 +21,17 @@
|
|
|
21
21
|
"@aws-sdk/lib-dynamodb": "^3.758.0",
|
|
22
22
|
"@databricks/sql": "^1.9.0",
|
|
23
23
|
"@elastic/elasticsearch": "^8.17.1",
|
|
24
|
+
"@node-rs/xxhash": "^1.7.6",
|
|
24
25
|
"@slack/web-api": "^6.13.0",
|
|
25
26
|
"chalk": "^5.4.1",
|
|
26
27
|
"execa": "^9.5.2",
|
|
27
28
|
"express": "^4.21.2",
|
|
28
29
|
"md5": "^2.3.0",
|
|
29
30
|
"meow": "^13.2.0",
|
|
31
|
+
"p-memoize": "^7.1.1",
|
|
32
|
+
"p-throttle": "^7.0.0",
|
|
33
|
+
"quick-lru": "^7.0.0",
|
|
30
34
|
"type-fest": "^4.35.0",
|
|
31
|
-
"web3": "^4.16.0",
|
|
32
35
|
"which": "^5.0.0"
|
|
33
36
|
},
|
|
34
37
|
"devDependencies": {
|
package/web3.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { Web3 } from "web3";
|
|
2
|
-
import type { AbiFunctionFragment } from "web3";
|
|
3
|
-
import { PROTOCOLS } from "./const.ts";
|
|
4
|
-
|
|
5
|
-
function newWeb3ByProtocol(protocol: string) {
|
|
6
|
-
if (!Object.keys(PROTOCOLS).includes(protocol)) {
|
|
7
|
-
return null;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
return new Web3(PROTOCOLS[protocol].endpoint);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function normalizeCallParams<T>(params?: T) {
|
|
14
|
-
if (params === undefined) {
|
|
15
|
-
return [] as T[];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (Array.isArray(params)) {
|
|
19
|
-
return params as T[];
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return [params];
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async function singleCall<TData, TParams>(protocol: string, abi: AbiFunctionFragment, target: string, params: TParams) {
|
|
26
|
-
const web3 = newWeb3ByProtocol(protocol);
|
|
27
|
-
|
|
28
|
-
if (!web3) {
|
|
29
|
-
throw new Error(`unsupported protocol`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const contract = new web3.eth.Contract([abi], target);
|
|
33
|
-
const functionSignature = web3.eth.abi.encodeFunctionSignature(abi);
|
|
34
|
-
const method = contract.methods[functionSignature];
|
|
35
|
-
|
|
36
|
-
const result = await method(...normalizeCallParams(params)).call<TData>();
|
|
37
|
-
|
|
38
|
-
return result;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export { singleCall };
|