@certik/skynet 0.25.0 → 0.25.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/.vscode/settings.json +5 -0
- package/CHANGELOG.md +10 -0
- package/README.md +8 -2
- package/dist/abi.d.ts +111 -0
- package/dist/abi.js +571 -0
- package/dist/address.d.ts +2 -0
- package/dist/address.js +24 -0
- package/dist/api.d.ts +31 -0
- package/dist/api.js +260 -0
- package/dist/app.d.ts +101 -0
- package/dist/app.js +2077 -0
- package/dist/availability.d.ts +23 -0
- package/dist/availability.js +133 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +41 -0
- package/dist/const.d.ts +34 -0
- package/dist/const.js +162 -0
- package/dist/date.d.ts +5 -0
- package/dist/date.js +56 -0
- package/dist/deploy.d.ts +75 -0
- package/dist/deploy.js +587 -0
- package/dist/dynamodb.d.ts +16 -0
- package/dist/dynamodb.js +479 -0
- package/dist/env.d.ts +6 -0
- package/dist/env.js +26 -0
- package/dist/goalert.d.ts +19 -0
- package/dist/goalert.js +43 -0
- package/dist/graphql.d.ts +6 -0
- package/dist/graphql.js +35 -0
- package/dist/indexer.d.ts +69 -0
- package/dist/indexer.js +1099 -0
- package/dist/log.d.ts +13 -0
- package/dist/log.js +63 -0
- package/dist/object-hash.d.ts +1 -0
- package/dist/object-hash.js +61 -0
- package/dist/por.d.ts +37 -0
- package/dist/por.js +120 -0
- package/dist/s3.d.ts +20 -0
- package/dist/s3.js +122 -0
- package/dist/search.d.ts +5 -0
- package/dist/search.js +105 -0
- package/dist/selector.d.ts +17 -0
- package/dist/selector.js +44 -0
- package/dist/slack.d.ts +14 -0
- package/dist/slack.js +29 -0
- package/dist/util.d.ts +4 -0
- package/dist/util.js +27 -0
- package/examples/api.ts +0 -0
- package/examples/indexer.ts +0 -0
- package/examples/mode-indexer.ts +0 -0
- package/package.json +1 -1
- package/src/deploy.ts +1 -1
package/dist/log.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
declare function print(o: unknown): string;
|
|
2
|
+
declare function getLine(params: unknown[]): string;
|
|
3
|
+
declare const inline: {
|
|
4
|
+
debug: (...args: unknown[]) => void;
|
|
5
|
+
log: (...args: unknown[]) => void;
|
|
6
|
+
error: (...args: unknown[]) => void;
|
|
7
|
+
};
|
|
8
|
+
declare const logger: {
|
|
9
|
+
debug: (...args: unknown[]) => void;
|
|
10
|
+
log: (...args: unknown[]) => void;
|
|
11
|
+
error: (...args: unknown[]) => void;
|
|
12
|
+
};
|
|
13
|
+
export { print, getLine, inline, logger };
|
package/dist/log.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// src/log.ts
|
|
2
|
+
function isObject(a) {
|
|
3
|
+
return !!a && a.constructor === Object;
|
|
4
|
+
}
|
|
5
|
+
function print(o) {
|
|
6
|
+
if (Array.isArray(o)) {
|
|
7
|
+
return `[${o.map(print).join(", ")}]`;
|
|
8
|
+
}
|
|
9
|
+
if (isObject(o)) {
|
|
10
|
+
return `{${Object.keys(o).map((k) => `${k}: ${o[k]}`).join(", ")}}`;
|
|
11
|
+
}
|
|
12
|
+
return `${o}`;
|
|
13
|
+
}
|
|
14
|
+
function getLine(params) {
|
|
15
|
+
let line = "";
|
|
16
|
+
for (let i = 0, l = params.length;i < l; i++) {
|
|
17
|
+
line += `${print(params[i])} `.replace(/\n/gm, "\t");
|
|
18
|
+
}
|
|
19
|
+
return line.trim();
|
|
20
|
+
}
|
|
21
|
+
function timestamp() {
|
|
22
|
+
return new Date().toISOString();
|
|
23
|
+
}
|
|
24
|
+
var inline = {
|
|
25
|
+
debug: function(...args) {
|
|
26
|
+
if (true) {
|
|
27
|
+
console.log(`${timestamp()} ${getLine(args)}`);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
log: function(...args) {
|
|
31
|
+
if (true) {
|
|
32
|
+
console.log(`${timestamp()} ${getLine(args)}`);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
error: function(...args) {
|
|
36
|
+
if (true) {
|
|
37
|
+
console.error(`${timestamp()} ${getLine(args)}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var logger = {
|
|
42
|
+
debug: function(...args) {
|
|
43
|
+
if (true) {
|
|
44
|
+
console.log(`[${timestamp()}]`, ...args);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
log: function(...args) {
|
|
48
|
+
if (true) {
|
|
49
|
+
console.log(`[${timestamp()}]`, ...args);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
error: function(...args) {
|
|
53
|
+
if (true) {
|
|
54
|
+
console.error(`[${timestamp()}]`, ...args);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
export {
|
|
59
|
+
print,
|
|
60
|
+
logger,
|
|
61
|
+
inline,
|
|
62
|
+
getLine
|
|
63
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getHash(obj: unknown): string;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// src/object-hash.ts
|
|
2
|
+
import xh from "@node-rs/xxhash";
|
|
3
|
+
function getHash(obj) {
|
|
4
|
+
const xxh3 = xh.xxh3.Xxh3.withSeed();
|
|
5
|
+
hash(obj, xxh3);
|
|
6
|
+
return xxh3.digest().toString(16);
|
|
7
|
+
}
|
|
8
|
+
function hash(obj, xxh3) {
|
|
9
|
+
if (obj === null) {
|
|
10
|
+
xxh3.update("null");
|
|
11
|
+
} else if (obj === undefined) {
|
|
12
|
+
xxh3.update("undefined");
|
|
13
|
+
} else if (typeof obj === "string") {
|
|
14
|
+
xxh3.update(obj);
|
|
15
|
+
} else if (typeof obj === "number") {
|
|
16
|
+
xxh3.update(obj.toString());
|
|
17
|
+
} else if (typeof obj === "boolean") {
|
|
18
|
+
xxh3.update(obj.toString());
|
|
19
|
+
} else if (typeof obj === "bigint") {
|
|
20
|
+
xxh3.update(obj.toString());
|
|
21
|
+
} else if (obj instanceof Date) {
|
|
22
|
+
xxh3.update(obj.toISOString());
|
|
23
|
+
} else if (Array.isArray(obj)) {
|
|
24
|
+
arrayHash(obj, xxh3);
|
|
25
|
+
} else if (obj instanceof Set) {
|
|
26
|
+
setHash(obj, xxh3);
|
|
27
|
+
} else if (obj instanceof Map) {
|
|
28
|
+
mapHash(obj, xxh3);
|
|
29
|
+
} else if (typeof obj === "object") {
|
|
30
|
+
objectHash(obj, xxh3);
|
|
31
|
+
} else {
|
|
32
|
+
throw new Error(`Unsupported type: ${obj}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function arrayHash(array, xxh3) {
|
|
36
|
+
xxh3.update("[");
|
|
37
|
+
for (const obj of array) {
|
|
38
|
+
hash(obj, xxh3);
|
|
39
|
+
}
|
|
40
|
+
xxh3.update("]");
|
|
41
|
+
}
|
|
42
|
+
function setHash(_set, _xxh3) {
|
|
43
|
+
throw new Error("Set hashing not implemented");
|
|
44
|
+
}
|
|
45
|
+
function mapHash(map, xxh3) {
|
|
46
|
+
const array = Array.from(map.entries()).sort(([aKey], [bKey]) => aKey.localeCompare(bKey));
|
|
47
|
+
for (const [key, value] of array) {
|
|
48
|
+
hash(key, xxh3);
|
|
49
|
+
hash(value, xxh3);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function objectHash(obj, xxh3) {
|
|
53
|
+
const array = Object.entries(obj).sort(([aKey], [bKey]) => aKey.localeCompare(bKey));
|
|
54
|
+
for (const [key, value] of array) {
|
|
55
|
+
hash(key, xxh3);
|
|
56
|
+
hash(value, xxh3);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export {
|
|
60
|
+
getHash
|
|
61
|
+
};
|
package/dist/por.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface UserLiability {
|
|
2
|
+
userHash: string;
|
|
3
|
+
balance: number;
|
|
4
|
+
token?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface MerkleProof {
|
|
7
|
+
userHash: string;
|
|
8
|
+
balance: number;
|
|
9
|
+
token?: string;
|
|
10
|
+
proof: string[];
|
|
11
|
+
positions: ("left" | "right")[];
|
|
12
|
+
rootHash: string;
|
|
13
|
+
leafIndex: number;
|
|
14
|
+
hashFunction?: (data: string) => string;
|
|
15
|
+
}
|
|
16
|
+
export interface MerkleNode {
|
|
17
|
+
hash: string;
|
|
18
|
+
left?: MerkleNode;
|
|
19
|
+
right?: MerkleNode;
|
|
20
|
+
data?: UserLiability;
|
|
21
|
+
}
|
|
22
|
+
export declare class MerkleTreePoR {
|
|
23
|
+
private leaves;
|
|
24
|
+
private tree;
|
|
25
|
+
private userMap;
|
|
26
|
+
private userData;
|
|
27
|
+
private hashFunction;
|
|
28
|
+
constructor(users: UserLiability[], hashFunction?: (data: string) => string);
|
|
29
|
+
private static defaultSHA256Hash;
|
|
30
|
+
private defaultSHA256Hash;
|
|
31
|
+
private hash;
|
|
32
|
+
private createLeafHash;
|
|
33
|
+
private buildTree;
|
|
34
|
+
getRootHash(): string;
|
|
35
|
+
generateProof(userHash: string, token?: string): MerkleProof;
|
|
36
|
+
static verifyProof(merkleProof: MerkleProof): boolean;
|
|
37
|
+
}
|
package/dist/por.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/por.ts
|
|
3
|
+
var {CryptoHasher } = globalThis.Bun;
|
|
4
|
+
|
|
5
|
+
class MerkleTreePoR {
|
|
6
|
+
leaves = [];
|
|
7
|
+
tree = [];
|
|
8
|
+
userMap = new Map;
|
|
9
|
+
userData = [];
|
|
10
|
+
hashFunction;
|
|
11
|
+
constructor(users, hashFunction) {
|
|
12
|
+
this.userData = [...users];
|
|
13
|
+
this.hashFunction = hashFunction || this.defaultSHA256Hash;
|
|
14
|
+
this.buildTree();
|
|
15
|
+
}
|
|
16
|
+
static defaultSHA256Hash(data) {
|
|
17
|
+
const hasher = new CryptoHasher("sha256");
|
|
18
|
+
hasher.update(data);
|
|
19
|
+
return hasher.digest("hex");
|
|
20
|
+
}
|
|
21
|
+
defaultSHA256Hash(data) {
|
|
22
|
+
return MerkleTreePoR.defaultSHA256Hash(data);
|
|
23
|
+
}
|
|
24
|
+
hash(data) {
|
|
25
|
+
return this.hashFunction(data);
|
|
26
|
+
}
|
|
27
|
+
createLeafHash(user) {
|
|
28
|
+
const leafData = `${user.userHash}:${user.balance}:${user.token || ""}`;
|
|
29
|
+
return this.hash(leafData);
|
|
30
|
+
}
|
|
31
|
+
buildTree() {
|
|
32
|
+
if (this.userData.length === 0) {
|
|
33
|
+
throw new Error("Cannot build tree with empty user data");
|
|
34
|
+
}
|
|
35
|
+
this.leaves = this.userData.map((user, index) => {
|
|
36
|
+
const leafHash = this.createLeafHash(user);
|
|
37
|
+
this.userMap.set(`${user.userHash}:${user.token || ""}`, index);
|
|
38
|
+
return leafHash;
|
|
39
|
+
});
|
|
40
|
+
let currentLevel = this.leaves;
|
|
41
|
+
this.tree.push(currentLevel.map((hash) => ({ hash })));
|
|
42
|
+
while (currentLevel.length > 1) {
|
|
43
|
+
const nextLevel = [];
|
|
44
|
+
const nextLevelNodes = [];
|
|
45
|
+
for (let i = 0;i < currentLevel.length; i += 2) {
|
|
46
|
+
const left = currentLevel[i];
|
|
47
|
+
const right = i + 1 < currentLevel.length ? currentLevel[i + 1] : left;
|
|
48
|
+
const parentHash = this.hash(left + right);
|
|
49
|
+
nextLevel.push(parentHash);
|
|
50
|
+
const leftNode = this.tree[this.tree.length - 1][i];
|
|
51
|
+
const rightNode = i + 1 < currentLevel.length ? this.tree[this.tree.length - 1][i + 1] : leftNode;
|
|
52
|
+
nextLevelNodes.push({
|
|
53
|
+
hash: parentHash,
|
|
54
|
+
left: leftNode,
|
|
55
|
+
right: rightNode
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
currentLevel = nextLevel;
|
|
59
|
+
this.tree.push(nextLevelNodes);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
getRootHash() {
|
|
63
|
+
if (this.tree.length === 0) {
|
|
64
|
+
throw new Error("Merkle tree not built");
|
|
65
|
+
}
|
|
66
|
+
return this.tree[this.tree.length - 1][0].hash;
|
|
67
|
+
}
|
|
68
|
+
generateProof(userHash, token) {
|
|
69
|
+
const key = `${userHash}:${token || ""}`;
|
|
70
|
+
const leafIndex = this.userMap.get(key);
|
|
71
|
+
if (leafIndex === undefined) {
|
|
72
|
+
throw new Error(`${userHash} not found in merkle tree for token ${token}`);
|
|
73
|
+
}
|
|
74
|
+
const user = this.userData[leafIndex];
|
|
75
|
+
const proof = [];
|
|
76
|
+
const positions = [];
|
|
77
|
+
let currentIndex = leafIndex;
|
|
78
|
+
for (let level = 0;level < this.tree.length - 1; level++) {
|
|
79
|
+
const currentLevelSize = this.tree[level].length;
|
|
80
|
+
const isRightNode = currentIndex % 2 === 1;
|
|
81
|
+
const siblingIndex = isRightNode ? currentIndex - 1 : currentIndex + 1;
|
|
82
|
+
if (siblingIndex < currentLevelSize) {
|
|
83
|
+
proof.push(this.tree[level][siblingIndex].hash);
|
|
84
|
+
positions.push(isRightNode ? "left" : "right");
|
|
85
|
+
} else {
|
|
86
|
+
proof.push(this.tree[level][currentIndex].hash);
|
|
87
|
+
positions.push(isRightNode ? "left" : "right");
|
|
88
|
+
}
|
|
89
|
+
currentIndex = Math.floor(currentIndex / 2);
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
userHash: user.userHash,
|
|
93
|
+
balance: user.balance,
|
|
94
|
+
token: user.token,
|
|
95
|
+
proof,
|
|
96
|
+
positions,
|
|
97
|
+
rootHash: this.getRootHash(),
|
|
98
|
+
leafIndex,
|
|
99
|
+
hashFunction: this.hashFunction !== this.defaultSHA256Hash ? this.hashFunction : undefined
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
static verifyProof(merkleProof) {
|
|
103
|
+
const leafData = `${merkleProof.userHash}:${merkleProof.balance}:${merkleProof.token || ""}`;
|
|
104
|
+
const hashFunction = merkleProof.hashFunction || MerkleTreePoR.defaultSHA256Hash;
|
|
105
|
+
let currentHash = hashFunction(leafData);
|
|
106
|
+
for (let i = 0;i < merkleProof.proof.length; i++) {
|
|
107
|
+
const siblingHash = merkleProof.proof[i];
|
|
108
|
+
const position = merkleProof.positions[i];
|
|
109
|
+
if (position === "left") {
|
|
110
|
+
currentHash = hashFunction(siblingHash + currentHash);
|
|
111
|
+
} else {
|
|
112
|
+
currentHash = hashFunction(currentHash + siblingHash);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return currentHash === merkleProof.rootHash;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export {
|
|
119
|
+
MerkleTreePoR
|
|
120
|
+
};
|
package/dist/s3.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { S3Client, ObjectCannedACL } from "@aws-sdk/client-s3";
|
|
2
|
+
declare function getS3(forceNew?: boolean): S3Client;
|
|
3
|
+
declare function readFile(bucketName: string, key: string, verbose?: boolean): Promise<string | null | undefined>;
|
|
4
|
+
declare function hasFile(bucketName: string, key: string): Promise<boolean>;
|
|
5
|
+
declare function getFileSize(bucketName: string, key: string): Promise<number | undefined>;
|
|
6
|
+
declare function writeFile(bucketName: string, key: string, body: string, options?: {
|
|
7
|
+
verbose?: boolean;
|
|
8
|
+
skipIfExists?: boolean;
|
|
9
|
+
acl?: ObjectCannedACL;
|
|
10
|
+
contentType?: string;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
declare function deleteFile(bucketName: string, key: string, verbose?: boolean): Promise<null | undefined>;
|
|
13
|
+
declare function listKeys(bucketName: string, prefix?: string, continuationToken?: string): Promise<{
|
|
14
|
+
keys: never[];
|
|
15
|
+
continuationToken?: undefined;
|
|
16
|
+
} | {
|
|
17
|
+
keys: (string | undefined)[];
|
|
18
|
+
continuationToken: string | undefined;
|
|
19
|
+
} | null>;
|
|
20
|
+
export { getS3, hasFile, readFile, writeFile, deleteFile, getFileSize, listKeys };
|
package/dist/s3.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// src/s3.ts
|
|
2
|
+
import {
|
|
3
|
+
S3Client,
|
|
4
|
+
GetObjectCommand,
|
|
5
|
+
HeadObjectCommand,
|
|
6
|
+
PutObjectCommand,
|
|
7
|
+
DeleteObjectCommand,
|
|
8
|
+
ListObjectsV2Command,
|
|
9
|
+
NotFound,
|
|
10
|
+
NoSuchKey
|
|
11
|
+
} from "@aws-sdk/client-s3";
|
|
12
|
+
var _s3Client;
|
|
13
|
+
function getS3(forceNew = false) {
|
|
14
|
+
if (!_s3Client || forceNew) {
|
|
15
|
+
_s3Client = new S3Client;
|
|
16
|
+
}
|
|
17
|
+
return _s3Client;
|
|
18
|
+
}
|
|
19
|
+
async function readFile(bucketName, key, verbose = false) {
|
|
20
|
+
const s3 = getS3();
|
|
21
|
+
const params = { Bucket: bucketName, Key: key };
|
|
22
|
+
try {
|
|
23
|
+
const result = await s3.send(new GetObjectCommand(params));
|
|
24
|
+
return result.Body?.transformToString();
|
|
25
|
+
} catch (error) {
|
|
26
|
+
if (error instanceof NoSuchKey) {
|
|
27
|
+
if (verbose) {
|
|
28
|
+
console.log("no such bucket or key", bucketName, key);
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function hasFile(bucketName, key) {
|
|
36
|
+
const s3 = getS3();
|
|
37
|
+
try {
|
|
38
|
+
await s3.send(new HeadObjectCommand({ Bucket: bucketName, Key: key }));
|
|
39
|
+
return true;
|
|
40
|
+
} catch (headErr) {
|
|
41
|
+
if (headErr instanceof NotFound) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
throw headErr;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function getFileSize(bucketName, key) {
|
|
48
|
+
const s3 = getS3();
|
|
49
|
+
const result = await s3.send(new HeadObjectCommand({
|
|
50
|
+
Bucket: bucketName,
|
|
51
|
+
Key: key
|
|
52
|
+
}));
|
|
53
|
+
return result.ContentLength;
|
|
54
|
+
}
|
|
55
|
+
async function writeFile(bucketName, key, body, options = {}) {
|
|
56
|
+
const s3 = getS3();
|
|
57
|
+
if (options.skipIfExists) {
|
|
58
|
+
if (await hasFile(bucketName, key)) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const verbose = options.verbose || false;
|
|
63
|
+
const params = { Bucket: bucketName, Key: key, Body: body };
|
|
64
|
+
if (options.acl) {
|
|
65
|
+
params.ACL = options.acl;
|
|
66
|
+
}
|
|
67
|
+
if (options.contentType) {
|
|
68
|
+
params.ContentType = options.contentType;
|
|
69
|
+
}
|
|
70
|
+
if (verbose) {
|
|
71
|
+
console.log("uploading", key);
|
|
72
|
+
}
|
|
73
|
+
await s3.send(new PutObjectCommand(params));
|
|
74
|
+
}
|
|
75
|
+
async function deleteFile(bucketName, key, verbose = false) {
|
|
76
|
+
const s3 = getS3();
|
|
77
|
+
const params = { Bucket: bucketName, Key: key };
|
|
78
|
+
try {
|
|
79
|
+
await s3.send(new DeleteObjectCommand(params));
|
|
80
|
+
} catch (error) {
|
|
81
|
+
if (error instanceof NoSuchKey) {
|
|
82
|
+
if (verbose) {
|
|
83
|
+
console.log("no such bucket or key", bucketName, key);
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async function listKeys(bucketName, prefix, continuationToken) {
|
|
91
|
+
const s3 = getS3();
|
|
92
|
+
const params = {
|
|
93
|
+
Bucket: bucketName,
|
|
94
|
+
Prefix: prefix,
|
|
95
|
+
ContinuationToken: continuationToken
|
|
96
|
+
};
|
|
97
|
+
let data;
|
|
98
|
+
try {
|
|
99
|
+
data = await s3.send(new ListObjectsV2Command(params));
|
|
100
|
+
} catch (err) {
|
|
101
|
+
if (err instanceof Error && "statusCode" in err && err.statusCode === 400) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
throw `unable to list keys with prefix ${prefix}: ${err}`;
|
|
105
|
+
}
|
|
106
|
+
if (!data.Contents) {
|
|
107
|
+
return { keys: [] };
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
keys: data.Contents.map(({ Key }) => Key),
|
|
111
|
+
continuationToken: data.IsTruncated ? data.NextContinuationToken : undefined
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export {
|
|
115
|
+
writeFile,
|
|
116
|
+
readFile,
|
|
117
|
+
listKeys,
|
|
118
|
+
hasFile,
|
|
119
|
+
getS3,
|
|
120
|
+
getFileSize,
|
|
121
|
+
deleteFile
|
|
122
|
+
};
|
package/dist/search.d.ts
ADDED
package/dist/search.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// src/env.ts
|
|
2
|
+
function ensureAndGet(envName, defaultValue) {
|
|
3
|
+
return process.env[envName] || defaultValue;
|
|
4
|
+
}
|
|
5
|
+
function getEnvironment() {
|
|
6
|
+
return ensureAndGet("SKYNET_ENVIRONMENT", "dev");
|
|
7
|
+
}
|
|
8
|
+
function getEnvOrThrow(envName) {
|
|
9
|
+
if (!process.env[envName]) {
|
|
10
|
+
throw new Error(`Must set environment variable ${envName}`);
|
|
11
|
+
}
|
|
12
|
+
return process.env[envName];
|
|
13
|
+
}
|
|
14
|
+
function isProduction() {
|
|
15
|
+
return getEnvironment() === "prd";
|
|
16
|
+
}
|
|
17
|
+
function isDev() {
|
|
18
|
+
return getEnvironment() === "dev";
|
|
19
|
+
}
|
|
20
|
+
// src/log.ts
|
|
21
|
+
function isObject(a) {
|
|
22
|
+
return !!a && a.constructor === Object;
|
|
23
|
+
}
|
|
24
|
+
function print(o) {
|
|
25
|
+
if (Array.isArray(o)) {
|
|
26
|
+
return `[${o.map(print).join(", ")}]`;
|
|
27
|
+
}
|
|
28
|
+
if (isObject(o)) {
|
|
29
|
+
return `{${Object.keys(o).map((k) => `${k}: ${o[k]}`).join(", ")}}`;
|
|
30
|
+
}
|
|
31
|
+
return `${o}`;
|
|
32
|
+
}
|
|
33
|
+
function getLine(params) {
|
|
34
|
+
let line = "";
|
|
35
|
+
for (let i = 0, l = params.length;i < l; i++) {
|
|
36
|
+
line += `${print(params[i])} `.replace(/\n/gm, "\t");
|
|
37
|
+
}
|
|
38
|
+
return line.trim();
|
|
39
|
+
}
|
|
40
|
+
function timestamp() {
|
|
41
|
+
return new Date().toISOString();
|
|
42
|
+
}
|
|
43
|
+
var inline = {
|
|
44
|
+
debug: function(...args) {
|
|
45
|
+
if (true) {
|
|
46
|
+
console.log(`${timestamp()} ${getLine(args)}`);
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
log: function(...args) {
|
|
50
|
+
if (true) {
|
|
51
|
+
console.log(`${timestamp()} ${getLine(args)}`);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
error: function(...args) {
|
|
55
|
+
if (true) {
|
|
56
|
+
console.error(`${timestamp()} ${getLine(args)}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var logger = {
|
|
61
|
+
debug: function(...args) {
|
|
62
|
+
if (true) {
|
|
63
|
+
console.log(`[${timestamp()}]`, ...args);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
log: function(...args) {
|
|
67
|
+
if (true) {
|
|
68
|
+
console.log(`[${timestamp()}]`, ...args);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
error: function(...args) {
|
|
72
|
+
if (true) {
|
|
73
|
+
console.error(`[${timestamp()}]`, ...args);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
// src/search.ts
|
|
78
|
+
import { Client, HttpConnection } from "@elastic/elasticsearch";
|
|
79
|
+
import osModule from "os";
|
|
80
|
+
async function sendToSearch(indexPrefix, record, throws = false) {
|
|
81
|
+
if (!process.env["SKYNET_ELASTICSEARCH_CLOUD_ID"] || !process.env["SKYNET_ELASTICSEARCH_API_KEY"]) {
|
|
82
|
+
throw new Error("SKYNET_ELASTICSEARCH_CLOUD_ID or SKYNET_ELASTICSEARCH_API_KEY is not set");
|
|
83
|
+
}
|
|
84
|
+
const client = new Client({
|
|
85
|
+
cloud: { id: process.env["SKYNET_ELASTICSEARCH_CLOUD_ID"] },
|
|
86
|
+
auth: { apiKey: process.env["SKYNET_ELASTICSEARCH_API_KEY"] },
|
|
87
|
+
Connection: HttpConnection
|
|
88
|
+
});
|
|
89
|
+
const now = new Date;
|
|
90
|
+
const indexName = [indexPrefix, isProduction() ? "prod" : "dev", now.toISOString().slice(0, 7)].join("-");
|
|
91
|
+
try {
|
|
92
|
+
await client.index({
|
|
93
|
+
index: indexName,
|
|
94
|
+
document: { instance: osModule.hostname(), timestamp: now, record }
|
|
95
|
+
});
|
|
96
|
+
} catch (err) {
|
|
97
|
+
inline.error(err);
|
|
98
|
+
if (throws) {
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export {
|
|
104
|
+
sendToSearch
|
|
105
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Flag, Result } from "meow";
|
|
2
|
+
type StringFlag = Flag<"string", string> | Flag<"string", string[], true>;
|
|
3
|
+
type BooleanFlag = Flag<"boolean", boolean> | Flag<"boolean", boolean[], true>;
|
|
4
|
+
type NumberFlag = Flag<"number", number> | Flag<"number", number[], true>;
|
|
5
|
+
type AnyFlag = StringFlag | BooleanFlag | NumberFlag;
|
|
6
|
+
export type Selector = Record<string, AnyFlag & {
|
|
7
|
+
desc?: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
optional?: boolean;
|
|
10
|
+
aliases?: string[];
|
|
11
|
+
}>;
|
|
12
|
+
export type SelectorFlags<TSelector extends Selector> = Result<TSelector>["flags"];
|
|
13
|
+
declare function getSelectorDesc(selector: Selector): string;
|
|
14
|
+
declare function getSelectorFlags<TSelector extends Selector>(selector: Selector): TSelector;
|
|
15
|
+
declare function toSelectorString<TSelector extends Selector>(selectorFlags: SelectorFlags<TSelector>, delim?: string): string;
|
|
16
|
+
declare function getJobName<TSelector extends Selector>(name: string, selectorFlags: SelectorFlags<TSelector>, mode?: string): string;
|
|
17
|
+
export { getJobName, getSelectorDesc, getSelectorFlags, toSelectorString };
|
package/dist/selector.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// src/selector.ts
|
|
2
|
+
function getSelectorDesc(selector) {
|
|
3
|
+
return Object.keys(selector).map((name) => {
|
|
4
|
+
return ` --${name.padEnd(14)}${selector[name].desc || selector[name].description || ""}`;
|
|
5
|
+
}).join(`
|
|
6
|
+
`);
|
|
7
|
+
}
|
|
8
|
+
function getSelectorFlags(selector) {
|
|
9
|
+
return Object.keys(selector).reduce((acc, name) => {
|
|
10
|
+
const flag = {
|
|
11
|
+
type: selector[name].type || "string",
|
|
12
|
+
...selector[name]
|
|
13
|
+
};
|
|
14
|
+
if (!selector[name].optional && selector[name].isRequired !== false) {
|
|
15
|
+
flag.isRequired = true;
|
|
16
|
+
}
|
|
17
|
+
return { ...acc, [name]: flag };
|
|
18
|
+
}, {});
|
|
19
|
+
}
|
|
20
|
+
function toSelectorString(selectorFlags, delim = ",") {
|
|
21
|
+
return Object.keys(selectorFlags).sort().map((flag) => {
|
|
22
|
+
return `${flag}=${selectorFlags[flag]}`;
|
|
23
|
+
}).join(delim);
|
|
24
|
+
}
|
|
25
|
+
function normalizeSelectorValue(v) {
|
|
26
|
+
return v.replace(/[^A-Za-z0-9]+/g, "-");
|
|
27
|
+
}
|
|
28
|
+
function getJobName(name, selectorFlags, mode) {
|
|
29
|
+
const selectorNamePart = Object.keys(selectorFlags).sort().map((name2) => selectorFlags[name2]).join("-");
|
|
30
|
+
let jobName = name;
|
|
31
|
+
if (mode) {
|
|
32
|
+
jobName += `-${mode}`;
|
|
33
|
+
}
|
|
34
|
+
if (selectorNamePart.length > 0) {
|
|
35
|
+
jobName += `-${normalizeSelectorValue(selectorNamePart)}`;
|
|
36
|
+
}
|
|
37
|
+
return jobName;
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
toSelectorString,
|
|
41
|
+
getSelectorFlags,
|
|
42
|
+
getSelectorDesc,
|
|
43
|
+
getJobName
|
|
44
|
+
};
|
package/dist/slack.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ChatPostMessageArguments } from "@slack/web-api";
|
|
2
|
+
declare function postMessageToConversation({ conversationId, message, token, verbose, }: {
|
|
3
|
+
conversationId: string;
|
|
4
|
+
message: string;
|
|
5
|
+
token?: string;
|
|
6
|
+
verbose?: boolean;
|
|
7
|
+
} | {
|
|
8
|
+
conversationId?: undefined;
|
|
9
|
+
message: ChatPostMessageArguments;
|
|
10
|
+
token?: string;
|
|
11
|
+
verbose?: boolean;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
export { postMessageToConversation };
|
|
14
|
+
export type { ChatPostMessageArguments };
|
package/dist/slack.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// src/slack.ts
|
|
2
|
+
import { WebClient } from "@slack/web-api";
|
|
3
|
+
function getClient(token) {
|
|
4
|
+
return new WebClient(token);
|
|
5
|
+
}
|
|
6
|
+
async function postMessageToConversation({
|
|
7
|
+
conversationId,
|
|
8
|
+
message,
|
|
9
|
+
token,
|
|
10
|
+
verbose
|
|
11
|
+
}) {
|
|
12
|
+
if (!token) {
|
|
13
|
+
throw new Error("missing slack token");
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const client = getClient(token);
|
|
17
|
+
const post = typeof conversationId === "string" ? { channel: conversationId, text: message } : message;
|
|
18
|
+
if (verbose) {
|
|
19
|
+
console.log(`posting to slack:`, JSON.stringify(post, null, 2));
|
|
20
|
+
}
|
|
21
|
+
await client.chat.postMessage(post);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error("failed to post slack message", error);
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
postMessageToConversation
|
|
29
|
+
};
|
package/dist/util.d.ts
ADDED
package/dist/util.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/util.ts
|
|
2
|
+
function range(startAt, endAt, step) {
|
|
3
|
+
const arr = [];
|
|
4
|
+
for (let i = startAt;i <= endAt; i += step) {
|
|
5
|
+
arr.push([i, Math.min(endAt, i + step - 1)]);
|
|
6
|
+
}
|
|
7
|
+
return arr;
|
|
8
|
+
}
|
|
9
|
+
function arrayGroup(array, groupSize) {
|
|
10
|
+
const groups = [];
|
|
11
|
+
for (let i = 0;i < array.length; i += groupSize) {
|
|
12
|
+
groups.push(array.slice(i, i + groupSize));
|
|
13
|
+
}
|
|
14
|
+
return groups;
|
|
15
|
+
}
|
|
16
|
+
function fillRange(start, end) {
|
|
17
|
+
const result = [];
|
|
18
|
+
for (let i = start;i <= end; i++) {
|
|
19
|
+
result.push(i);
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
range,
|
|
25
|
+
fillRange,
|
|
26
|
+
arrayGroup
|
|
27
|
+
};
|