@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.
Files changed (52) hide show
  1. package/.vscode/settings.json +5 -0
  2. package/CHANGELOG.md +10 -0
  3. package/README.md +8 -2
  4. package/dist/abi.d.ts +111 -0
  5. package/dist/abi.js +571 -0
  6. package/dist/address.d.ts +2 -0
  7. package/dist/address.js +24 -0
  8. package/dist/api.d.ts +31 -0
  9. package/dist/api.js +260 -0
  10. package/dist/app.d.ts +101 -0
  11. package/dist/app.js +2077 -0
  12. package/dist/availability.d.ts +23 -0
  13. package/dist/availability.js +133 -0
  14. package/dist/cli.d.ts +5 -0
  15. package/dist/cli.js +41 -0
  16. package/dist/const.d.ts +34 -0
  17. package/dist/const.js +162 -0
  18. package/dist/date.d.ts +5 -0
  19. package/dist/date.js +56 -0
  20. package/dist/deploy.d.ts +75 -0
  21. package/dist/deploy.js +587 -0
  22. package/dist/dynamodb.d.ts +16 -0
  23. package/dist/dynamodb.js +479 -0
  24. package/dist/env.d.ts +6 -0
  25. package/dist/env.js +26 -0
  26. package/dist/goalert.d.ts +19 -0
  27. package/dist/goalert.js +43 -0
  28. package/dist/graphql.d.ts +6 -0
  29. package/dist/graphql.js +35 -0
  30. package/dist/indexer.d.ts +69 -0
  31. package/dist/indexer.js +1099 -0
  32. package/dist/log.d.ts +13 -0
  33. package/dist/log.js +63 -0
  34. package/dist/object-hash.d.ts +1 -0
  35. package/dist/object-hash.js +61 -0
  36. package/dist/por.d.ts +37 -0
  37. package/dist/por.js +120 -0
  38. package/dist/s3.d.ts +20 -0
  39. package/dist/s3.js +122 -0
  40. package/dist/search.d.ts +5 -0
  41. package/dist/search.js +105 -0
  42. package/dist/selector.d.ts +17 -0
  43. package/dist/selector.js +44 -0
  44. package/dist/slack.d.ts +14 -0
  45. package/dist/slack.js +29 -0
  46. package/dist/util.d.ts +4 -0
  47. package/dist/util.js +27 -0
  48. package/examples/api.ts +0 -0
  49. package/examples/indexer.ts +0 -0
  50. package/examples/mode-indexer.ts +0 -0
  51. package/package.json +1 -1
  52. 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
+ };
@@ -0,0 +1,5 @@
1
+ type ElasticSearchRecord = {
2
+ [key: string]: unknown;
3
+ };
4
+ export declare function sendToSearch(indexPrefix: string, record: ElasticSearchRecord, throws?: boolean): Promise<void>;
5
+ export {};
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 };
@@ -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
+ };
@@ -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
@@ -0,0 +1,4 @@
1
+ declare function range(startAt: number, endAt: number, step: number): [number, number][];
2
+ declare function arrayGroup<T>(array: T[], groupSize: number): T[][];
3
+ declare function fillRange(start: number, end: number): number[];
4
+ export { arrayGroup, range, fillRange };
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
+ };